diff options
author | erw7 <erw7.github@gmail.com> | 2019-10-05 00:18:24 +0900 |
---|---|---|
committer | Justin M. Keyes <justinkz@gmail.com> | 2019-10-04 08:18:24 -0700 |
commit | b4ea09cc064034f43808662c40cc1fff14284432 (patch) | |
tree | 900a91c2c074f1664db2b29fbbe1725b7ebd1b99 /src | |
parent | 77a551b6571f9a455efffeb7f43bf8235b2cbe49 (diff) | |
download | rneovim-b4ea09cc064034f43808662c40cc1fff14284432.tar.gz rneovim-b4ea09cc064034f43808662c40cc1fff14284432.tar.bz2 rneovim-b4ea09cc064034f43808662c40cc1fff14284432.zip |
Fix potential deadlock #11151
ELOG may call os_getenv and os_setenv internally. In that case, a
deadlock occurs.
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/os/env.c | 16 |
1 files changed, 10 insertions, 6 deletions
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 13853016d1..ae61e54993 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -55,6 +55,7 @@ const char *os_getenv(const char *name) return NULL; } uv_mutex_lock(&mutex); + int r = 0; if (pmap_has(cstr_t)(envmap, name) && !!(e = (char *)pmap_get(cstr_t)(envmap, name))) { if (e[0] != '\0') { @@ -67,7 +68,7 @@ const char *os_getenv(const char *name) pmap_del2(envmap, name); } e = xmalloc(size); - int r = uv_os_getenv(name, e, &size); + r = uv_os_getenv(name, e, &size); if (r == UV_ENOBUFS) { e = xrealloc(e, size); r = uv_os_getenv(name, e, &size); @@ -75,14 +76,15 @@ const char *os_getenv(const char *name) if (r != 0 || size == 0 || e[0] == '\0') { xfree(e); e = NULL; - if (r != 0 && r != UV_ENOENT && r != UV_UNKNOWN) { - ELOG("uv_os_getenv(%s) failed: %d %s", name, r, uv_err_name(r)); - } goto end; } pmap_put(cstr_t)(envmap, xstrdup(name), e); end: + // Must do this before ELOG, log.c may call os_setenv. uv_mutex_unlock(&mutex); + if (r != 0 && r != UV_ENOENT && r != UV_UNKNOWN) { + ELOG("uv_os_getenv(%s) failed: %d %s", name, r, uv_err_name(r)); + } return (e == NULL || size == 0 || e[0] == '\0') ? NULL : e; } @@ -146,10 +148,11 @@ int os_setenv(const char *name, const char *value, int overwrite) // Destroy the old map item. Do this AFTER uv_os_setenv(), because `value` // could be a previous os_getenv() result. pmap_del2(envmap, name); + // Must do this before ELOG, log.c may call os_setenv. + uv_mutex_unlock(&mutex); if (r != 0) { ELOG("uv_os_setenv(%s) failed: %d %s", name, r, uv_err_name(r)); } - uv_mutex_unlock(&mutex); return r == 0 ? 0 : -1; } @@ -163,10 +166,11 @@ int os_unsetenv(const char *name) uv_mutex_lock(&mutex); pmap_del2(envmap, name); int r = uv_os_unsetenv(name); + // Must do this before ELOG, log.c may call os_setenv. + uv_mutex_unlock(&mutex); if (r != 0) { ELOG("uv_os_unsetenv(%s) failed: %d %s", name, r, uv_err_name(r)); } - uv_mutex_unlock(&mutex); return r == 0 ? 0 : -1; } |