From d3d156c21ecf0a602d366209b3e2da665c3ec389 Mon Sep 17 00:00:00 2001 From: Rohit Menon Date: Thu, 1 Jul 2021 20:04:52 -0400 Subject: Add locks for ENV --- hash.c | 229 ++++++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 183 insertions(+), 46 deletions(-) (limited to 'hash.c') diff --git a/hash.c b/hash.c index 270ddfb522..e58d21587d 100644 --- a/hash.c +++ b/hash.c @@ -43,6 +43,7 @@ #include "ruby_assert.h" #include "symbol.h" #include "transient_heap.h" +#include "ruby/thread_native.h" #ifndef HASH_DEBUG #define HASH_DEBUG 0 @@ -4808,6 +4809,17 @@ extern char **environ; #define ENVNMATCH(s1, s2, n) (memcmp((s1), (s2), (n)) == 0) #endif +rb_nativethread_lock_t env_lock; + +const char* +getenv_with_lock(const char *name) +{ + rb_native_mutex_lock(&env_lock); + char *result = getenv(name); + rb_native_mutex_unlock(&env_lock); + return result; +} + static inline rb_encoding * env_encoding(void) { @@ -4906,7 +4918,7 @@ static VALUE env_delete(VALUE name) { const char *nam = env_name(name); - const char *val = getenv(nam); + const char *val = getenv_with_lock(nam); reset_by_modified_env(nam); @@ -4972,7 +4984,7 @@ rb_f_getenv(VALUE obj, VALUE name) const char *nam, *env; nam = env_name(name); - env = getenv(nam); + env = getenv_with_lock(nam); if (env) { return env_name_new(nam, env); } @@ -5018,7 +5030,7 @@ env_fetch(int argc, VALUE *argv, VALUE _) rb_warn("block supersedes default value argument"); } nam = env_name(key); - env = getenv(nam); + env = getenv_with_lock(nam); if (!env) { if (block_given) return rb_yield(key); if (argc == 1) { @@ -5054,12 +5066,14 @@ envix(const char *nam) register int i, len = strlen(nam); char **env; + rb_native_mutex_lock(&env_lock); env = GET_ENVIRON(environ); for (i = 0; env[i]; i++) { if (ENVNMATCH(env[i],nam,len) && env[i][len] == '=') break; /* memcmp must come first to avoid */ } /* potential SEGV's */ FREE_ENVIRON(environ); + rb_native_mutex_unlock(&env_lock); return i; } #endif @@ -5160,11 +5174,13 @@ ruby_setenv(const char *name, const char *value) wname[len-1] = L'='; #endif } + rb_native_mutex_lock(&env_lock); #ifndef HAVE__WPUTENV_S failed = _wputenv(wname); #else failed = _wputenv_s(wname, wvalue); #endif + rb_native_mutex_unlock(&env_lock); ALLOCV_END(buf); /* even if putenv() failed, clean up and try to delete the * variable from the system area. */ @@ -5178,6 +5194,7 @@ ruby_setenv(const char *name, const char *value) invalid_envname(name); } #elif defined(HAVE_SETENV) && defined(HAVE_UNSETENV) + rb_native_mutex_lock(&env_lock); if (value) { if (setenv(name, value, 1)) rb_sys_fail_str(rb_sprintf("setenv(%s)", name)); @@ -5190,11 +5207,13 @@ ruby_setenv(const char *name, const char *value) rb_sys_fail_str(rb_sprintf("unsetenv(%s)", name)); #endif } + rb_native_mutex_unlock(&env_lock); #elif defined __sun /* Solaris 9 (or earlier) does not have setenv(3C) and unsetenv(3C). */ /* The below code was tested on Solaris 10 by: % ./configure ac_cv_func_setenv=no ac_cv_func_unsetenv=no */ + rb_native_mutex_lock(&env_lock); size_t len, mem_size; char **env_ptr, *str, *mem_ptr; @@ -5220,6 +5239,7 @@ ruby_setenv(const char *name, const char *value) rb_sys_fail_str(rb_sprintf("putenv(%s)", name)); } } + rb_native_mutex_unlock(&env_lock); #else /* WIN32 */ size_t len; int i; @@ -5347,18 +5367,31 @@ env_keys(int raw) rb_encoding *enc = raw ? 0 : rb_locale_encoding(); ary = rb_ary_new(); + rb_native_mutex_lock(&env_lock); env = GET_ENVIRON(environ); - while (*env) { - char *s = strchr(*env, '='); + int pair_count = 0; + while(*(env+pair_count)) { + pair_count++; + } + VALUE env_pairs[pair_count]; + for(int i = 0; i < pair_count; i++) + { + const char *p = *env; + env_pairs[i] = p; + env++; + } + FREE_ENVIRON(environ); + rb_native_mutex_unlock(&env_lock); + for(int current_pair = 0; current_pair < pair_count; current_pair++) + { + const char *p = env_pairs[current_pair]; + char *s = strchr(p, '='); if (s) { - const char *p = *env; size_t l = s - p; VALUE e = raw ? rb_utf8_str_new(p, l) : env_enc_str_new(p, l, enc); rb_ary_push(ary, e); } - env++; } - FREE_ENVIRON(environ); return ary; } @@ -5387,6 +5420,7 @@ rb_env_size(VALUE ehash, VALUE args, VALUE eobj) char **env; long cnt = 0; + rb_native_mutex_lock(&env_lock); env = GET_ENVIRON(environ); for (; *env ; ++env) { if (strchr(*env, '=')) { @@ -5394,6 +5428,7 @@ rb_env_size(VALUE ehash, VALUE args, VALUE eobj) } } FREE_ENVIRON(environ); + rb_native_mutex_unlock(&env_lock); return LONG2FIX(cnt); } @@ -5435,15 +5470,29 @@ env_values(void) char **env; ary = rb_ary_new(); + rb_native_mutex_lock(&env_lock); env = GET_ENVIRON(environ); - while (*env) { - char *s = strchr(*env, '='); + int pair_count = 0; + while (*(env+pair_count)) { + pair_count++; + } + VALUE env_pairs[pair_count]; + for(int i = 0; i < pair_count; i++) + { + const char *p = *env; + env_pairs[i] = p; + env++; + } + FREE_ENVIRON(environ); + rb_native_mutex_unlock(&env_lock); + for(int current_pair = 0; current_pair < pair_count; current_pair++) + { + const char *p = env_pairs[current_pair]; + char *s = strchr(p, '='); if (s) { rb_ary_push(ary, env_str_new2(s+1)); } - env++; } - FREE_ENVIRON(environ); return ary; } @@ -5524,16 +5573,30 @@ env_each_pair(VALUE ehash) RETURN_SIZED_ENUMERATOR(ehash, 0, 0, rb_env_size); ary = rb_ary_new(); + rb_native_mutex_lock(&env_lock); env = GET_ENVIRON(environ); - while (*env) { - char *s = strchr(*env, '='); + int pair_count = 0; + while (*(env+pair_count)) { + pair_count++; + } + VALUE env_pairs[pair_count]; + for(int i = 0; i < pair_count; i++) + { + const char *p = *env; + env_pairs[i] = p; + env++; + } + FREE_ENVIRON(environ); + rb_native_mutex_unlock(&env_lock); + for(int current_pair = 0; current_pair < pair_count; current_pair++) + { + const char *p = env_pairs[current_pair]; + char *s = strchr(p, '='); if (s) { - rb_ary_push(ary, env_str_new(*env, s-*env)); + rb_ary_push(ary, env_str_new(p, s-p)); rb_ary_push(ary, env_str_new2(s+1)); } - env++; } - FREE_ENVIRON(environ); if (rb_block_pair_yield_optimizable()) { for (i=0; i"); i = rb_inspect(rb_str_new2(s+1)); rb_str_buf_append(str, i); } - env++; } - FREE_ENVIRON(environ); rb_str_buf_cat2(str, "}"); return str; @@ -5915,16 +5992,30 @@ env_to_a(VALUE _) VALUE ary; ary = rb_ary_new(); + rb_native_mutex_lock(&env_lock); env = GET_ENVIRON(environ); - while (*env) { - char *s = strchr(*env, '='); + int pair_count = 0; + while (*(env+pair_count)) { + pair_count++; + } + VALUE env_pairs[pair_count]; + for(int i = 0; i < pair_count; i++) + { + const char *p = *env; + env_pairs[i] = p; + env++; + } + FREE_ENVIRON(environ); + rb_native_mutex_unlock(&env_lock); + for(int current_pair = 0; current_pair < pair_count; current_pair++) + { + const char *p = env_pairs[current_pair]; + char *s = strchr(p, '='); if (s) { - rb_ary_push(ary, rb_assoc_new(env_str_new(*env, s-*env), + rb_ary_push(ary, rb_assoc_new(env_str_new(p, s-p), env_str_new2(s+1))); } - env++; } - FREE_ENVIRON(environ); return ary; } @@ -5958,10 +6049,12 @@ env_size(VALUE _) int i; char **env; + rb_native_mutex_lock(&env_lock); env = GET_ENVIRON(environ); for (i=0; env[i]; i++) ; FREE_ENVIRON(environ); + rb_native_mutex_unlock(&env_lock); return INT2FIX(i); } @@ -5980,12 +6073,15 @@ env_empty_p(VALUE _) { char **env; + rb_native_mutex_lock(&env_lock); env = GET_ENVIRON(environ); if (env[0] == 0) { FREE_ENVIRON(environ); + rb_native_mutex_unlock(&env_lock); return Qtrue; } FREE_ENVIRON(environ); + rb_native_mutex_unlock(&env_lock); return Qfalse; } @@ -6020,7 +6116,7 @@ env_has_key(VALUE env, VALUE key) const char *s; s = env_name(key); - return RBOOL(getenv(s)); + return RBOOL(getenv_with_lock(s)); } /* @@ -6049,7 +6145,7 @@ env_assoc(VALUE env, VALUE key) const char *s, *e; s = env_name(key); - e = getenv(s); + e = getenv_with_lock(s); if (e) return rb_assoc_new(key, env_str_new2(e)); return Qnil; } @@ -6073,6 +6169,7 @@ env_has_value(VALUE dmy, VALUE obj) obj = rb_check_string_type(obj); if (NIL_P(obj)) return Qnil; + rb_native_mutex_lock(&env_lock); env = GET_ENVIRON(environ); while (*env) { char *s = strchr(*env, '='); @@ -6080,12 +6177,14 @@ env_has_value(VALUE dmy, VALUE obj) long len = strlen(s); if (RSTRING_LEN(obj) == len && strncmp(s, RSTRING_PTR(obj), len) == 0) { FREE_ENVIRON(environ); + rb_native_mutex_unlock(&env_lock); return Qtrue; } } env++; } FREE_ENVIRON(environ); + rb_native_mutex_unlock(&env_lock); return Qfalse; } @@ -6110,20 +6209,24 @@ env_rassoc(VALUE dmy, VALUE obj) obj = rb_check_string_type(obj); if (NIL_P(obj)) return Qnil; + rb_native_mutex_lock(&env_lock); env = GET_ENVIRON(environ); while (*env) { - char *s = strchr(*env, '='); + const char *p = *env; + char *s = strchr(p, '='); if (s++) { long len = strlen(s); if (RSTRING_LEN(obj) == len && strncmp(s, RSTRING_PTR(obj), len) == 0) { - VALUE result = rb_assoc_new(rb_str_new(*env, s-*env-1), obj); - FREE_ENVIRON(environ); + FREE_ENVIRON(environ); + rb_native_mutex_unlock(&env_lock); + VALUE result = rb_assoc_new(rb_str_new(p, s-p-1), obj); return result; } } env++; } FREE_ENVIRON(environ); + rb_native_mutex_unlock(&env_lock); return Qnil; } @@ -6150,20 +6253,34 @@ env_key(VALUE dmy, VALUE value) VALUE str; SafeStringValue(value); + rb_native_mutex_lock(&env_lock); env = GET_ENVIRON(environ); - while (*env) { - char *s = strchr(*env, '='); + int pair_count = 0; + while (*(env+pair_count)) { + pair_count++; + } + VALUE env_pairs[pair_count]; + for(int i = 0; i < pair_count; i++) + { + const char *p = *env; + env_pairs[i] = p; + env++; + } + FREE_ENVIRON(environ); + rb_native_mutex_unlock(&env_lock); + for(int current_pair = 0; current_pair < pair_count; current_pair++) + { + const char *p = env_pairs[current_pair]; + char *s = strchr(p, '='); if (s++) { long len = strlen(s); if (RSTRING_LEN(value) == len && strncmp(s, RSTRING_PTR(value), len) == 0) { - str = env_str_new(*env, s-*env-1); - FREE_ENVIRON(environ); + str = env_str_new(p, s-p-1); return str; } } env++; } - FREE_ENVIRON(environ); return Qnil; } @@ -6174,16 +6291,30 @@ env_to_hash(void) VALUE hash; hash = rb_hash_new(); + rb_native_mutex_lock(&env_lock); env = GET_ENVIRON(environ); - while (*env) { - char *s = strchr(*env, '='); + int pair_count = 0; + while (*(env+pair_count)) { + pair_count++; + } + VALUE env_pairs[pair_count]; + for(int i = 0; i < pair_count; i++) + { + const char *p = *env; + env_pairs[i] = p; + env++; + } + FREE_ENVIRON(environ); + rb_native_mutex_unlock(&env_lock); + for(int current_pair = 0; current_pair < pair_count; current_pair++) + { + const char *p = env_pairs[current_pair]; + char *s = strchr(p, '='); if (s) { - rb_hash_aset(hash, env_str_new(*env, s-*env), + rb_hash_aset(hash, env_str_new(p, s-p), env_str_new2(s+1)); } - env++; } - FREE_ENVIRON(environ); return hash; } @@ -6322,17 +6453,23 @@ env_shift(VALUE _) char **env; VALUE result = Qnil; + rb_native_mutex_lock(&env_lock); env = GET_ENVIRON(environ); if (*env) { - char *s = strchr(*env, '='); + const char *p = *env; + rb_native_mutex_unlock(&env_lock); + char *s = strchr(p, '='); if (s) { - VALUE key = env_str_new(*env, s-*env); - VALUE val = env_str_new2(getenv(RSTRING_PTR(key))); + VALUE key = env_str_new(p, s-p); + VALUE val = env_str_new2(getenv_with_lock(RSTRING_PTR(key))); env_delete(key); result = rb_assoc_new(key, val); } + rb_native_mutex_lock(&env_lock); } + FREE_ENVIRON(environ); + rb_native_mutex_unlock(&env_lock); return result; } -- cgit v1.2.1