summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--hash.c20
-rw-r--r--test/ruby/test_env.rb16
3 files changed, 31 insertions, 11 deletions
diff --git a/ChangeLog b/ChangeLog
index eca3a3cd78..26382d4f77 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Thu Jun 26 08:28:01 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (env_select): fix memory leak and crash on Windows, make
+ keys array first instead of iterating on envrion directly.
+ [ruby-dev:48325] [Bug #9978]
+
Thu Jun 26 02:45:04 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
* eval_error.c (error_print): put a newline after an anonymous
diff --git a/hash.c b/hash.c
index 56cedf072b..bcf6b5e54b 100644
--- a/hash.c
+++ b/hash.c
@@ -3138,23 +3138,21 @@ static VALUE
env_select(VALUE ehash)
{
VALUE result;
- char **env;
+ VALUE keys;
+ long i;
RETURN_SIZED_ENUMERATOR(ehash, 0, 0, rb_env_size);
result = rb_hash_new();
- env = GET_ENVIRON(environ);
- while (*env) {
- char *s = strchr(*env, '=');
- if (s) {
- VALUE k = env_str_new(*env, s-*env);
- VALUE v = env_str_new2(s+1);
- if (RTEST(rb_yield_values(2, k, v))) {
- rb_hash_aset(result, k, v);
+ keys = env_keys();
+ for (i = 0; i < RARRAY_LEN(keys); ++i) {
+ VALUE key = RARRAY_AREF(keys, i);
+ VALUE val = rb_f_getenv(Qnil, key);
+ if (!NIL_P(val)) {
+ if (RTEST(rb_yield_values(2, key, val))) {
+ rb_hash_aset(result, key, val);
}
}
- env++;
}
- FREE_ENVIRON(environ);
return result;
}
diff --git a/test/ruby/test_env.rb b/test/ruby/test_env.rb
index ecf0608ec6..5eff01c5a2 100644
--- a/test/ruby/test_env.rb
+++ b/test/ruby/test_env.rb
@@ -517,4 +517,20 @@ class TestEnv < Test::Unit::TestCase
v = (ENV[k] = 'bar'*5000 rescue 'bar'*1500)
end;
end
+
+ def test_memory_leak_select
+ bug9978 = '[ruby-dev:48325] [Bug #9978]'
+ assert_no_memory_leak([], <<-'end;', "5_000.times {ENV.select {break}}", bug9978)
+ ENV.clear
+ k = 'FOO'
+ (ENV[k] = 'bar'*5000 rescue 'bar'*1500)
+ end;
+ end
+
+ def test_memory_crash_select
+ assert_normal_exit(<<-'end;')
+ 1000.times {ENV["FOO#{i}"] = 'bar'}
+ ENV.select {ENV.clear}
+ end;
+ end
end