8000 clear dst Hash on Hash#replace. [Bug #15358] · github/ruby@a763e34 · GitHub
[go: up one dir, main page]

Skip to content

Commit a763e34

Browse files
committed
clear dst Hash on Hash#replace. [Bug #15358]
* hash.c (linear_copy): solve two issues on `Hash#replace`. (1) fix memory leak (1-1) don't allocate memory if destination already has a memory area. (1-2) free destination memory if src is NULL. (2) clear transient heap flag if src is NULL. [Bug #15358] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66091 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
1 parent 2fc56c9 commit a763e34

File tree

2 files changed

+29
-10
lines changed

2 files changed

+29
-10
lines changed

hash.c

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,7 @@ static void
493493
hash_array_set(VALUE hash, struct li_table *li)
494494
{
495495
HASH_ASSERT(RHASH_ARRAY_P(hash));
496+
HASH_ASSERT((RHASH_TRANSIENT_P(hash) && li == NULL) ? FALSE : TRUE);
496497
RHASH(hash)->as.li = li;
497498
hash_verify(hash);
498499
}
@@ -993,15 +994,17 @@ linear_copy(VALUE hash1, VALUE hash2)
993994
{
994995
li_table *old_tab = RHASH_ARRAY(hash2);
995996

996-
if (old_tab) {
997-
li_table *new_tab;
998-
new_tab = (li_table*) rb_transient_heap_alloc(hash1, sizeof(li_table));
999-
if (new_tab != NULL) {
1000-
RHASH_SET_TRANSIENT_FLAG(hash1);
1001-
}
1002-
else {
1003-
RHASH_UNSET_TRANSIENT_FLAG(hash1);
1004-
new_tab = (li_table*)ruby_xmalloc(sizeof(li_table));
997+
if (old_tab != NULL) {
998+
li_table *new_tab = RHASH_ARRAY(hash1);
999+
if (new_tab == NULL) {
1000+
new_tab = (li_table*) rb_transient_heap_alloc(hash1, sizeof(li_table));
1001+
if (new_tab != NULL) {
1002+
RHASH_SET_TRANSIENT_FLAG(hash1);
1003+
}
1004+
else {
1005+
RHASH_UNSET_TRANSIENT_FLAG(hash1);
1006+
new_tab = (li_table*)ruby_xmalloc(sizeof(li_table));
1007+
}
10051008
}
10061009
*new_tab = *old_tab;
10071010
RHASH_ARRAY_BOUND_SET(hash1, RHASH_ARRAY_BOUND(hash2));
@@ -1014,7 +1017,15 @@ linear_copy(VALUE hash1, VALUE hash2)
10141017
else {
10151018
RHASH_ARRAY_BOUND_SET(hash1, RHASH_ARRAY_BOUND(hash2));
10161019
RHASH_ARRAY_SIZE_SET(hash1, RHASH_ARRAY_SIZE(hash2));
1017-
RHASH_ARRAY_SET(hash1, old_tab);
1020+
1021+
if (RHASH_TRANSIENT_P(hash1)) {
1022+
RHASH_UNSET_TRANSIENT_FLAG(hash1);
1023+
}
1024+
else if (RHASH_ARRAY(hash1)) {
1025+
ruby_xfree(RHASH_ARRAY(hash1));
1026+
}
1027+
1028+
RHASH_ARRAY_SET(hash1, NULL);
10181029

10191030
rb_gc_writebarrier_remember(hash1);
10201031
return old_tab;

test/ruby/test_hash.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,14 @@ def test_replace_bug9230
755755
assert_predicate(h, :compare_by_identity?)
756756
end
757757

758+
def test_replace_bug15358
759+
h1 = {}
760+
h2 = {a:1,b:2,c:3,d:4,e:5}
761+
h2.replace(h1)
762+
GC.start
763+
assert(true)
764+
end
765+
758766
def test_shift
759767
h = @h.dup
760768

0 commit comments

Comments
 (0)
0