summaryrefslogtreecommitdiff
path: root/test/ruby/test_weakmap.rb
AgeCommit message (Collapse)Author
2024-08-22[Backport 3.3] [Bug #20688] Fix use-after-free for WeakMap and WeakKeyMap ↵Peter Zhu
(#11439) * Add struct weakmap_entry for WeakMap entries * Refactor wmap_foreach to pass weakmap_entry * Use wmap_foreach for wmap_mark * Refactor wmap_compact to use wmap_foreach * Remove wmap_free_entry * Fix WeakMap use-after-free [Bug #20688] We cannot free the weakmap_entry before the ST_DELETE because it could hash the key which would read the weakmap_entry and would cause a use-after-free. Instead, we store the entry and free it on the next iteration. For example, the following script triggers a use-after-free in Valgrind: weakmap = ObjectSpace::WeakMap.new 10_000.times { weakmap[Object.new] = Object.new } ==25795== Invalid read of size 8 ==25795== at 0x462297: wmap_cmp (weakmap.c:165) ==25795== by 0x3A2B1C: find_table_bin_ind (st.c:930) ==25795== by 0x3A5EAA: st_general_foreach (st.c:1599) ==25795== by 0x3A5EAA: rb_st_foreach (st.c:1640) ==25795== by 0x25C991: gc_mark_children (default.c:4870) ==25795== by 0x25C991: gc_marks_wb_unprotected_objects_plane (default.c:5565) ==25795== by 0x25C991: rgengc_rememberset_mark_plane (default.c:5557) ==25795== by 0x25C991: rgengc_rememberset_mark (default.c:6233) ==25795== by 0x25C991: gc_marks_start (default.c:6057) ==25795== by 0x25C991: gc_marks (default.c:6077) ==25795== by 0x25C991: gc_start (default.c:6723) ==25795== by 0x260F96: heap_prepare (default.c:2282) ==25795== by 0x260F96: heap_next_free_page (default.c:2489) ==25795== by 0x260F96: newobj_cache_miss (default.c:2598) ==25795== by 0x26197F: newobj_alloc (default.c:2622) ==25795== by 0x26197F: rb_gc_impl_new_obj (default.c:2701) ==25795== by 0x26197F: newobj_of (gc.c:890) ==25795== by 0x26197F: rb_wb_protected_newobj_of (gc.c:917) ==25795== by 0x2DEA88: rb_class_allocate_instance (object.c:131) ==25795== by 0x2E3B18: class_call_alloc_func (object.c:2141) ==25795== by 0x2E3B18: rb_class_alloc (object.c:2113) ==25795== by 0x2E3B18: rb_class_new_instance_pass_kw (object.c:2172) ==25795== by 0x429DDC: vm_call_cfunc_with_frame_ (vm_insnhelper.c:3786) ==25795== by 0x44B08D: vm_sendish (vm_insnhelper.c:5953) ==25795== by 0x44B08D: vm_exec_core (insns.def:898) ==25795== by 0x43A7A4: rb_vm_exec (vm.c:2564) ==25795== by 0x234914: rb_ec_exec_node (eval.c:281) ==25795== Address 0x21603710 is 0 bytes inside a block of size 16 free'd ==25795== at 0x4849B2C: free (vg_replace_malloc.c:989) ==25795== by 0x249651: rb_gc_impl_free (default.c:8527) ==25795== by 0x249651: rb_gc_impl_free (default.c:8508) ==25795== by 0x249651: ruby_sized_xfree.constprop.0 (gc.c:4178) ==25795== by 0x4626EC: ruby_sized_xfree_inlined (gc.h:277) ==25795== by 0x4626EC: wmap_free_entry (weakmap.c:45) ==25795== by 0x4626EC: wmap_mark_weak_table_i (weakmap.c:61) ==25795== by 0x3A5CEF: apply_functor (st.c:1633) ==25795== by 0x3A5CEF: st_general_foreach (st.c:1543) ==25795== by 0x3A5CEF: rb_st_foreach (st.c:1640) ==25795== by 0x25C991: gc_mark_children (default.c:4870) ==25795== by 0x25C991: gc_marks_wb_unprotected_objects_plane (default.c:5565) ==25795== by 0x25C991: rgengc_rememberset_mark_plane (default.c:5557) ==25795== by 0x25C991: rgengc_rememberset_mark (default.c:6233) ==25795== by 0x25C991: gc_marks_start (default.c:6057) ==25795== by 0x25C991: gc_marks (default.c:6077) ==25795== by 0x25C991: gc_start (default.c:6723) ==25795== by 0x260F96: heap_prepare (default.c:2282) ==25795== by 0x260F96: heap_next_free_page (default.c:2489) ==25795== by 0x260F96: newobj_cache_miss (default.c:2598) ==25795== by 0x26197F: newobj_alloc (default.c:2622) ==25795== by 0x26197F: rb_gc_impl_new_obj (default.c:2701) ==25795== by 0x26197F: newobj_of (gc.c:890) ==25795== by 0x26197F: rb_wb_protected_newobj_of (gc.c:917) ==25795== by 0x2DEA88: rb_class_allocate_instance (object.c:131) ==25795== by 0x2E3B18: class_call_alloc_func (object.c:2141) ==25795== by 0x2E3B18: rb_class_alloc (object.c:2113) ==25795== by 0x2E3B18: rb_class_new_instance_pass_kw (object.c:2172) ==25795== by 0x429DDC: vm_call_cfunc_with_frame_ (vm_insnhelper.c:3786) ==25795== by 0x44B08D: vm_sendish (vm_insnhelper.c:5953) ==25795== by 0x44B08D: vm_exec_core (insns.def:898) ==25795== by 0x43A7A4: rb_vm_exec (vm.c:2564) ==25795== Block was alloc'd at ==25795== at 0x484680F: malloc (vg_replace_malloc.c:446) ==25795== by 0x25CE9E: rb_gc_impl_malloc (default.c:8542) ==25795== by 0x462A39: wmap_aset_replace (weakmap.c:423) ==25795== by 0x3A5542: rb_st_update (st.c:1487) ==25795== by 0x462B8E: wmap_aset (weakmap.c:452) ==25795== by 0x429DDC: vm_call_cfunc_with_frame_ (vm_insnhelper.c:3786) ==25795== by 0x44B08D: vm_sendish (vm_insnhelper.c:5953) ==25795== by 0x44B08D: vm_exec_core (insns.def:898) ==25795== by 0x43A7A4: rb_vm_exec (vm.c:2564) ==25795== by 0x234914: rb_ec_exec_node (eval.c:281) ==25795== by 0x2369B8: ruby_run_node (eval.c:319) ==25795== by 0x15D675: rb_main (main.c:43) ==25795== by 0x15D675: main (main.c:62) * Fix use-after-free for WeakKeyMap [Bug #20688] We cannot free the key before the ST_DELETE because it could hash the key which would read the key and would cause a use-after-free. Instead, we store the key and free it on the next iteration.
2024-05-29Skip under_gc_compact_stress on s390x (#10073)Takashi Kokubun
2023-12-12Make WeakMap safe for compaction during allocationPeter Zhu
During allocation, the table may not have been allocated yet which would crash in the st_foreach.
2023-09-06Fix crash in WeakMap during compactionPeter Zhu
WeakMap can crash during compaction because the st_insert could allocate memory.
2023-08-25Implement WeakMap using weak referencesPeter Zhu
Notes: Merged: https://github.com/ruby/ruby/pull/8113
2023-08-03Remove --disable-gems for assert_separatelyPeter Zhu
assert_separately adds --disable=gems so we don't need to add --disable-gems when calling assert_separately. Notes: Merged: https://github.com/ruby/ruby/pull/8162
2023-04-15Implement ObjectSpace::WeakMap#delete and ObjectSpace::WeakKeyMap#deleteJean Boussier
[Feature #19561] It's useful to be able to remove references from weak maps. Notes: Merged: https://github.com/ruby/ruby/pull/7629
2023-04-06Add guard to compaction test in WeakMapPeter Zhu
Some platforms don't support compaction, so we should skip this test.
2023-03-17ObjectSpace::WeakMap: clean inverse reference when an entry is re-assignedJean Boussier
[Bug #19531] ```ruby wmap[1] = "A" wmap[1] = "B" ``` In the example above, we need to remove the `"A" => 1` inverse reference so that when `"A"` is GCed the `1` key isn't deleted. Notes: Merged: https://github.com/ruby/ruby/pull/7540
2023-03-14Fix crash during compactionPeter Zhu
[Bug #19529] The fix for [Bug #19529] in commit 548086b contained a bug that crashes on the following script: ``` wm = ObjectSpace::WeakMap.new obj = Object.new 100.times do wm[Object.new] = obj GC.start end GC.compact ```
2023-03-14ObjectSpace::WeakMap: fix compaction supportJean Boussier
[Bug #19529] `rb_gc_update_tbl_refs` can't be used on `w->obj2wmap` because it's not a `VALUE -> VALUE` table, but a `VALUE -> VALUE *` table, so we need some dedicated iterator. Notes: Merged: https://github.com/ruby/ruby/pull/7518
2023-02-01[Bug #19398] Memory leak in WeakMapPeter Zhu
There's a memory leak in ObjectSpace::WeakMap due to not freeing the `struct weakmap`. It can be seen in the following script: ``` 100.times do 10000.times do ObjectSpace::WeakMap.new end # Output the Resident Set Size (memory usage, in KB) of the current Ruby process puts `ps -o rss= -p #{$$}` end ``` Notes: Merged: https://github.com/ruby/ruby/pull/7223
2022-01-16Weakmap failure is still pendingNobuyoshi Nakada
2022-01-16Remove outdated skipsNobuyoshi Nakada
Notes: Merged: https://github.com/ruby/ruby/pull/5453
2022-01-16Use pend for old TODOsNobuyoshi Nakada
Notes: Merged: https://github.com/ruby/ruby/pull/5453
2021-12-07ObjectSpace::WeakMap#inspect: check if living object [Bug #18392]Nobuyoshi Nakada
Notes: Merged: https://github.com/ruby/ruby/pull/5224
2019-08-29Allow non-finalizable objects in ObjectSpace::WeakMapJean Boussier
[feature #16035] This goes one step farther than what nobu did in [feature #13498] With this patch, special objects such as static symbols, integers, etc can be used as either key or values inside WeakMap. They simply don't have a finalizer defined on them. This is useful if you need to deduplicate value objects Notes: Merged: https://github.com/ruby/ruby/pull/2313
2019-06-23Frozen objects in WeakMapNobuyoshi Nakada
* gc.c (wmap_aset): bypass check for frozen and allow frozen object in WeakMap. [Bug #13498]
2018-03-16test_weakmap.rb: skip unstable assertionnobu
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62781 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-03-14test_weakmap.rb: fixing CI failuresnobu
* test/ruby/test_weakmap.rb (test_include?): create and release the object to be garbage-collected in deeper frame. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62748 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-03-13Rename test classes to allow stable test count when running test-all -jnobu
[Fix GH-1763] From: MSP-Greg <MSP-Greg@users.noreply.github.com> git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62738 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2017-10-27skip tests temporarilyko1
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60491 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-12-16Add frozen_string_literal: false for all filesnaruse
When you change this to true, you may need to add more tests. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53141 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2014-11-13* test/lib/envutil.rb: Moved from test/ruby/.akr
* test/lib/find_executable.rb: Ditto. * test/lib/memory_status.rb: Ditto. * test/lib/test/unit.rb: require envutil. * test/: Don't require envutil in test files. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48409 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2014-09-11* include/ruby/ruby.h: freeze nil/true/false.ko1
* gc.c (should_be_finalizable): check frozen after checkin FL_ABLE. * object.c (rb_obj_taint): check OBJ_TAINTABLE(obj). * object.c (rb_obj_freeze): remove immediate_frozen_tbl because all of immediate values are frozen. YAY! * object.c (rb_obj_frozen_p): ditto. * test/ruby/test_eval.rb: skip instance_variable_set for frozen objects. * test/ruby/test_weakmap.rb: check ArgumentError instead of RuntimeError. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47523 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-12-13test_weakmap.rb: fix testnobu
* test/ruby/test_weakmap.rb (test_include?): create target object in a block, so that collected soon as possible. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44178 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-12-13test_weakmap.rb: fix testnobu
* test/ruby/test_weakmap.rb (test_include?): Object.new does not excute the block, use tap. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44176 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-12-13test_weakmap.rb: fix testnobu
* test/ruby/test_weakmap.rb (test_include?): isolate weak referenced object. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44174 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-12-10gc.c: check arguments firstnobu
* gc.c (wmap_aset): check if both arguments are able to finalize before setting finalizers. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44108 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-12-10gc.c: fix WeakMap#inspectnobu
* gc.c (wmap_inspect_i): fix key/value order. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44107 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-12-09gc.c: ObjectSpace::WeakMap#sizenobu
* gc.c (wmap_size): add ObjectSpace::WeakMap#size and #length. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44093 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-12-09test_weakmap.rb: addnobu
* test/ruby/test_weakmap.rb: test for ObjectSpace::WeakMap. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44092 b2dd03c8-39d4-4d8f-98ff-823fe69b080e