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:
Tomas Halman authored and Nico Williams committed 2023-07-24 11:55:15 -05:00
1 parent 5300fbda58
commit 2dbae5610b
1 file changed
+26 -7
+26 -7
View File
@@ -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