Fix segmentation fault when using jq in threads
In previous code nomem_handler in jv_alloc.c is called only once and therefore the structure is not initialized for second and following threads. This leads to segmentation fault in multi-threading environment. This patch moves initialization of nomem_handler out of the pthread_once call.
This commit is contained in:
1 parent
5300fbda58
commit
2dbae5610b
1 file changed
+26
-7
+26
-7
@@ -45,9 +45,11 @@ static void memory_exhausted() {
|
||||
#ifdef HAVE_PTHREAD_KEY_CREATE
|
||||
#include <pthread.h>
|
||||
|
||||
pthread_key_t nomem_handler_key;
|
||||
pthread_once_t mem_once = PTHREAD_ONCE_INIT;
|
||||
static pthread_key_t nomem_handler_key;
|
||||
static pthread_once_t mem_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
/* tsd_fini is called on application exit */
|
||||
/* it clears the nomem_handler allocated in the main thread */
|
||||
static void tsd_fini(void) {
|
||||
struct nomem_handler *nomem_handler;
|
||||
nomem_handler = pthread_getspecific(nomem_handler_key);
|
||||
@@ -57,8 +59,15 @@ static void tsd_fini(void) {
|
||||
}
|
||||
}
|
||||
|
||||
/* The tsd_fini_thread is a destructor set by calling */
|
||||
/* pthread_key_create(&nomem_handler_key, tsd_fini_thread) */
|
||||
/* It is called when thread ends */
|
||||
static void tsd_fini_thread(void *nomem_handler) {
|
||||
free(nomem_handler);
|
||||
}
|
||||
|
||||
static void tsd_init(void) {
|
||||
if (pthread_key_create(&nomem_handler_key, NULL) != 0) {
|
||||
if (pthread_key_create(&nomem_handler_key, tsd_fini_thread) != 0) {
|
||||
fprintf(stderr, "jq: error: cannot create thread specific key");
|
||||
abort();
|
||||
}
|
||||
@@ -66,15 +75,23 @@ static void tsd_init(void) {
|
||||
fprintf(stderr, "jq: error: cannot set an exit handler");
|
||||
abort();
|
||||
}
|
||||
struct nomem_handler *nomem_handler = calloc(1, sizeof(struct nomem_handler));
|
||||
if (pthread_setspecific(nomem_handler_key, nomem_handler) != 0) {
|
||||
fprintf(stderr, "jq: error: cannot set thread specific data");
|
||||
abort();
|
||||
}
|
||||
|
||||
static void tsd_init_nomem_handler(void)
|
||||
{
|
||||
if (pthread_getspecific(nomem_handler_key) == NULL) {
|
||||
struct nomem_handler *nomem_handler = calloc(1, sizeof(struct nomem_handler));
|
||||
if (pthread_setspecific(nomem_handler_key, nomem_handler) != 0) {
|
||||
fprintf(stderr, "jq: error: cannot set thread specific data");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void jv_nomem_handler(jv_nomem_handler_f handler, void *data) {
|
||||
pthread_once(&mem_once, tsd_init); // cannot fail
|
||||
tsd_init_nomem_handler();
|
||||
|
||||
struct nomem_handler *nomem_handler;
|
||||
|
||||
nomem_handler = pthread_getspecific(nomem_handler_key);
|
||||
@@ -91,6 +108,8 @@ static void memory_exhausted() {
|
||||
struct nomem_handler *nomem_handler;
|
||||
|
||||
pthread_once(&mem_once, tsd_init);
|
||||
tsd_init_nomem_handler();
|
||||
|
||||
nomem_handler = pthread_getspecific(nomem_handler_key);
|
||||
if (nomem_handler)
|
||||
nomem_handler->handler(nomem_handler->data); // Maybe handler() will longjmp() to safety
|
||||
|
||||
Reference in new issue
Block a user