summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul J. Davis <paul.joseph.davis@gmail.com>2019-12-17 11:40:24 -0600
committerPaul J. Davis <paul.joseph.davis@gmail.com>2019-12-17 13:20:47 -0600
commit43f6d96acee5d36193dde37067fc0f4acfefcce2 (patch)
tree8872e11cb1c9251519b880279e92f95cfea7600c
parent5e40111c88b0a91149573082e7057fffb2ed28cf (diff)
downloadcouchdb-fix-js-tests.tar.gz
Fix use after free of ICU collatorsfix-js-tests
During `init:restart()` we end up calling the `couch_ejson_compare` NIF's unload function which destroys all of the allocated collators. However, we don't clear the associated thread local states which leads us to a use after free issue and the ensuing segfaults. This adds checks so that threads know when their cached threadlocal collator is no longer valid.
-rw-r--r--src/couch/priv/couch_ejson_compare/couch_ejson_compare.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/src/couch/priv/couch_ejson_compare/couch_ejson_compare.c b/src/couch/priv/couch_ejson_compare/couch_ejson_compare.c
index 6d1043fa4..ad3d0cdd6 100644
--- a/src/couch/priv/couch_ejson_compare/couch_ejson_compare.c
+++ b/src/couch/priv/couch_ejson_compare/couch_ejson_compare.c
@@ -48,9 +48,11 @@ typedef struct {
} ctx_t;
static threadlocal UCollator* collator = NULL;
+static threadlocal int64_t threadEpoch = 0;
static UCollator** collators = NULL;
static int numCollators = 0;
static int numSchedulers = 0;
+static int64_t loadEpoch = 0;
static ErlNifMutex* collMutex = NULL;
static ERL_NIF_TERM less_json_nif(ErlNifEnv*, int, const ERL_NIF_TERM []);
@@ -69,7 +71,7 @@ get_collator()
{
UErrorCode status = U_ZERO_ERROR;
- if(collator != NULL) {
+ if(collator != NULL && threadEpoch == loadEpoch) {
return collator;
}
@@ -87,6 +89,8 @@ get_collator()
assert(numCollators <= numSchedulers && "Number of schedulers shrank.");
+ threadEpoch = loadEpoch;
+
return collator;
}
@@ -387,6 +391,8 @@ on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
return 2;
}
+ loadEpoch += 1;
+
collMutex = enif_mutex_create("coll_mutex");
if (collMutex == NULL) {
@@ -421,6 +427,8 @@ on_unload(ErlNifEnv* env, void* priv_data)
enif_free(collators);
}
+ numCollators = 0;
+
if (collMutex != NULL) {
enif_mutex_destroy(collMutex);
}