This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch fix-js-tests
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit b3baae5eb5446316988df6cecd62a46f2edd915c
Author: Paul J. Davis <[email protected]>
AuthorDate: Tue Dec 17 11:40:24 2019 -0600

    Fix use after free of ICU collators
    
    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.
---
 src/couch/priv/couch_ejson_compare/couch_ejson_compare.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

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 6d1043f..ad3d0cd 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);
     }

Reply via email to