8000 Update travisci by shyouhei · Pull Request #13 · shyouhei/ruby · GitHub
[go: up one dir, main page]

Skip to content

Update travisci #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 878 commits into from
Closed

Update travisci #13

wants to merge 878 commits into from

Conversation

shyouhei
Copy link
Owner

just tesing travis....

shyouhei and others added 30 commits February 6, 2020 11:46
Namely recent Sun C compiler has this function, and is not a GCC.
Meanwhile the code without RUBY_JMP_BUF assumes GCC.  We have to define
the macro when we detect __builtin_setjmp for non-GCC compilers.
There are cases when sizeof(int) == sizeof(long) == sizeof(size_t).  On
such cases however int and long are incompatible types in theory.  We
should not assume typedef long size_t, because on Solaris size_t is
actually a typedef of int.

This reduces compiler warnings on such situations.
Let me quote ISO/IEC 9899:2018 section 6.5.15:

> Constraints
>
> The first operand shall have scalar type.
> One of the following shall hold for the second and third operands:
> — both operands have arithmetic type;
> — both operands have the same structure or union type;
> — both operands have void type;
(snip)

Here, `*option` is a const struct rb_compile_option_struct. OTOH
`COMPILE_OPTION_DEFAULT` is a struct rb_compile_option_struct, without
const.   These two are _not_ the "same structure or union type".  Hence
the expression renders undefined behaviour.  COMPILE_OPTION_DEFAULT is
not a const because `RubyVM::InstructionSequence.compile_option=`
touches its internals on-the-fly.  There is no way to meet the
constraints quoted above.

Using ternary operator here was a mistake at the first place.  Let's
just replace it with a normal `if` statement.
Pointer to this field is passed to ATOMIC_CAS.  We have to use
rb_atomic_t for that purpose.
Check if threads are stopped by Thread#stop? instead of the status
name.
RDoc says nothing about them.  Added an example that
ConditionVariable#wait can be woken up by
ConditionVariable#signal, instead.
Redirect the output of separated child process to
`MiniTest::Unit.output`.
This condition is too restrictive in my opinion. If a user has a pre
version of rubygems installed, she should be fully responsible for it,
and we shouldn't restrict any functionality.

Also, why is a new prerelease disallowed but an old prelease allowed, or
why is 2.0.0.rc2 explictly whitelisted? I believe this kind of
exceptions are one more reason to actually permit this.

rubygems/rubygems@7f77a77620
If `require "a"` is run when two folders have been specified in the -I
option including a "a.rb" file and a "a.so" file respectively, the ruby
spec says that the ".rb" file should always be preferred. However, the
logic we added in rubygems/rubygems@6b81076d9
to make the -I option always beat default gems does not respect this
spec, creating a difference from the original ruby-core's require.

[the ruby spec says]: https://github.com/ruby/spec/blob/d80a6e2b221d4f17a8cadcac75ef950c59cba901/core/kernel/shared/require.rb#L234-L246

rubygems/rubygems@b3944384f4
…ority"

This reverts commit d767da4.

  It fails with spec/ruby/core/kernel/require_spec.rb:5
As SystemExit is ignored, it is just useless.
Auto runner should not run in forked processes in separated tests.
Against changes of the `assert_separately` prologue code.
Function pointers are not void*.  See also
ce4ea95
8427fca
I struggled figuring out which of the pack/unpack functions goes into which direction and the two first sentences were of the documentation were:
* Import an integer into a buffer.
* Export an integer into a buffer.

It sounds like both of them go from a ruby integer to a buffer because both use "into". So I fixed it and went to "Import an integer from a buffer". I find this much more clear.
shyouhei and others added 22 commits February 25, 2020 13:39
We would like to skip this extension library when libstdc++ is missing.
To avoid such situation let's use try_link instead of try_compile.
Extract bundled gems under ".bundle/gems" and get rid of
duplication which cause constant redefinition warnings at
`test-all` after `extract-gems` and `test-bundler`.
Fix up 66d1900, `RubyVM::MJIT` is
available since ruby 2.6.
rbinstall is using `$script_mode` and `$prog_mode`. However, the
`$script_mode` fallbacks to `$prog_mode` if not provided.

However, RubyGems do not distinguish between `$script_mode` and
`$prog_mode`:

https://github.com/rubygems/rubygems/blame/92892bbc3adba86a90756c385433835f6761b8da/lib/rubygems/installer.rb#L196
https://github.com/rubygems/rubygems/blame/92892bbc3adba86a90756c385433835f6761b8da/lib/rubygems/installer.rb#L515
https://github.com/rubygems/rubygems/blame/92892bbc3adba86a90756c385433835f6761b8da/lib/rubygems/installer.rb#L543

Comparing the usage of `$script_mode` and `$prog_mode`, it seems that
the `$script_mode` should be used where RubyGems expects `$prog_mode`.
This just gets the `RbInstall::DirPackage` closer by functionality to
`Gem::Package`.
The local `path` variable does not provide any additional value and was
kept around just for clarity for easier review of the `extrac_files`
method move.
.gemspec files specifies not just `bin`, but also other directories.
It is not necessary to strip the `destdir` prefix every iteration, when
it can be done just once.
Darwin is no longer tested using Travis CI.  See also commit
91aa8bf
It seems UBSAN is quite stable now.
They were necessary when developing YAMLs, but not useful any longer.
The `branch:` specifier was necessary before, to prevent double-testing
master and trunk.  Now that we no longer have trunk, we can slim the
expressions.

See also: https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#on
This target can be a build matrix.  Also it does not make sense to test
it on mjit.
@shyouhei
Copy link
Owner Author

OK.

@shyouhei shyouhei closed this Feb 26, 2020
shyouhei pushed a commit that referenced this pull request Jun 11, 2020
This reverts commit 02b216e.
This reverts commit 9b8825b.

I found that combining sweep and move is not safe.  I don't think that
we can do compaction concurrently with _anything_ unless there is a read
barrier installed.

Here is a simple example.  A class object is freed, and during it's free
step, it tries to remove itself from its parent's subclass list.
However, during the sweep step, the parent class was moved and the
"currently being freed" class didn't have references updated yet.  So we
get a segv like this:

```
(lldb) bt
* thread #1, name = 'ruby', stop reason = signal SIGSEGV
  * frame #0: 0x0000560763e344cb ruby`rb_st_lookup at st.c:320:43
    frame #1: 0x0000560763e344cb ruby`rb_st_lookup(tab=0x2f7469672f6e6f72, key=3809, value=0x0000560765bf2270) at st.c:1010
    frame #2: 0x0000560763e8f16a ruby`rb_search_class_path at variable.c:99:9
    frame #3: 0x0000560763e8f141 ruby`rb_search_class_path at variable.c:145
    frame #4: 0x0000560763e8f141 ruby`rb_search_class_path(klass=94589785585880) at variable.c:191
    frame #5: 0x0000560763ec744e ruby`rb_vm_bugreport at vm_dump.c:996:17
    frame #6: 0x0000560763f5b958 ruby`rb_bug_for_fatal_signal at error.c:675:5
    frame #7: 0x0000560763e27dad ruby`sigsegv(sig=<unavailable>, info=<unavailable>, ctx=<unavailable>) at signal.c:955:5
    frame #8: 0x00007f8b891d33c0 libpthread.so.0`___lldb_unnamed_symbol1$$libpthread.so.0 + 1
    frame #9: 0x0000560763efa8bb ruby`rb_class_remove_from_super_subclasses(klass=94589790314280) at class.c:93:56
    frame #10: 0x0000560763d10cb7 ruby`gc_sweep_step at gc.c:2674:2
    frame #11: 0x0000560763d1187b ruby`gc_sweep at gc.c:4540:2
    frame #12: 0x0000560763d101f0 ruby`gc_start at gc.c:6797:6
    frame #13: 0x0000560763d15153 ruby`rb_gc_compact at gc.c:7479:12
    frame ruby#14: 0x0000560763eb4eb8 ruby`vm_exec_core at vm_insnhelper.c:5183:13
    frame ruby#15: 0x0000560763ea9bae ruby`rb_vm_exec at vm.c:1953:22
    frame ruby#16: 0x0000560763eac08d ruby`rb_yield at vm.c:1132:9
    frame ruby#17: 0x0000560763edb4f2 ruby`rb_ary_collect at array.c:3186:9
    frame ruby#18: 0x0000560763e9ee15 ruby`vm_call_cfunc_with_frame at vm_insnhelper.c:2575:12
    frame ruby#19: 0x0000560763eb2e66 ruby`vm_exec_core at vm_insnhelper.c:4177:11
    frame #20: 0x0000560763ea9bae ruby`rb_vm_exec at vm.c:1953:22
    frame ruby#21: 0x0000560763eac08d ruby`rb_yield at vm.c:1132:9
    frame ruby#22: 0x0000560763edb4f2 ruby`rb_ary_collect at array.c:3186:9
    frame ruby#23: 0x0000560763e9ee15 ruby`vm_call_cfunc_with_frame at vm_insnhelper.c:2575:12
    frame ruby#24: 0x0000560763eb2e66 ruby`vm_exec_core at vm_insnhelper.c:4177:11
    frame ruby#25: 0x0000560763ea9bae ruby`rb_vm_exec at vm.c:1953:22
    frame ruby#26: 0x0000560763ceee01 ruby`rb_ec_exec_node(ec=0x0000560765afa530, n=0x0000560765b088e0) at eval.c:296:2
    frame ruby#27: 0x0000560763cf3b7b ruby`ruby_run_node(n=0x0000560765b088e0) at eval.c:354:12
    frame ruby#28: 0x0000560763cee4a3 ruby`main(argc=<unavailable>, argv=<unavailable>) at main.c:50:9
    frame ruby#29: 0x00007f8b88e560b3 libc.so.6`__libc_start_main + 243
    frame ruby#30: 0x0000560763cee4ee ruby`_start + 46
(lldb) f 9
frame #9: 0x0000560763efa8bb ruby`rb_class_remove_from_super_subclasses(klass=94589790314280) at class.c:93:56
   90
   91  		*RCLASS_EXT(klass)->parent_subclasses = entry->next;
   92  		if (entry->next) {
-> 93  		    RCLASS_EXT(entry->next->klass)->parent_subclasses = RCLASS_EXT(klass)->parent_subclasses;
   94  		}
   95  		xfree(entry);
   96  	    }
(lldb) command script import -r misc/lldb_cruby.py
lldb scripts for ruby has been installed.
(lldb) rp entry->next->klass
(struct RMoved) $1 = (flags = 30, destination = 94589792806680, next = 94589784369160)
(lldb)
```
shyouhei pushed a commit that referenced this pull request Jul 28, 2020
	eliminate use of freed memory

	rb_io_fptr_finalize_internal frees the memory region.

	=================================================================
	==85264==ERROR: AddressSanitizer: heap-use-after-free on address 0x610000000d8c at pc 0x5608e38077f7 bp 0x7ffee12d5440 sp 0x7ffee12d5438
	READ of size 4 at 0x610000000d8c thread T0
	    #0 0x5608e38077f6 in rb_io_memsize io.c:4749:24
	    #1 0x5608e37a0481 in obj_memsize_of gc.c:3547:14
	    #2 0x5608e37a4f30 in check_rvalue_consistency gc.c:1107:2
	    #3 0x5608e37a2624 in RVALUE_OLD_P gc.c:1218:5
	    #4 0x5608e37a5bae in rb_gc_force_recycle gc.c:6652:18
	    #5 0x5608e38191f9 in rb_f_backquote io.c:9021:5
	    #6 0x5608e3d8aa14 in call_cfunc_1 vm_insnhelper.c:2058:12
	    #7 0x5608e3d6e23d in vm_call_cfunc_with_frame vm_insnhelper.c:2211:11
	    #8 0x5608e3d54a35 in vm_call_cfunc vm_insnhelper.c:2229:12
	    #9 0x5608e3d5253b in vm_call_method_each_type vm_insnhelper.c:2564:9
	    #10 0x5608e3d51f50 in vm_call_method vm_insnhelper.c:2701:13
	    #11 0x5608e3cf2de4 in vm_call_general vm_insnhelper.c:2734:12
	    #12 0x5608e3d79918 in vm_sendish vm_insnhelper.c:3627:11
	    #13 0x5608e3d06cf5 in vm_exec_core insns.def:789:11
	    ruby#14 0x5608e3d43700 in rb_vm_exec vm.c:1892:22
	    ruby#15 0x5608e3d47cbf in rb_iseq_eval_main vm.c:2151:11
	    ruby#16 0x5608e37620ca in ruby_exec_internal eval.c:262:2
	    ruby#17 0x5608e376198b in ruby_exec_node eval.c:326:12
	    ruby#18 0x5608e37617d0 in ruby_run_node eval.c:318:25
	    ruby#19 0x5608e35c9486 in main main.c:42:9
	    #20 0x7f62e9421b96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310
	    ruby#21 0x5608e3522289 in _start (miniruby+0x15f289)

	0x610000000d8c is located 76 bytes inside of 192-byte region [0x610000000d40,0x610000000e00)
	freed by thread T0 here:
	    #0 0x5608e359a2ed in free (miniruby+0x1d72ed)
	    #1 0x5608e37af421 in objspace_xfree gc.c:9591:5
	    #2 0x5608e37af3da in ruby_sized_xfree gc.c:9687:2
	    #3 0x5608e3799ac8 in ruby_xfree gc.c:9694:5
	    #4 0x5608e380746d in rb_io_fptr_finalize_internal io.c:4728:5
	    #5 0x5608e38191ed in rb_f_backquote io.c:9020:5
	    #6 0x5608e3d8aa14 in call_cfunc_1 vm_insnhelper.c:2058:12
	    #7 0x5608e3d6e23d in vm_call_cfunc_with_frame vm_insnhelper.c:2211:11
	    #8 0x5608e3d54a35 in vm_call_cfunc vm_insnhelper.c:2229:12
	    #9 0x5608e3d5253b in vm_call_method_each_type vm_insnhelper.c:2564:9
	    #10 0x5608e3d51f50 in vm_call_method vm_insnhelper.c:2701:13
	    #11 0x5608e3cf2de4 in vm_call_general vm_insnhelper.c:2734:12
	    #12 0x5608e3d79918 in vm_sendish vm_insnhelper.c:3627:11
	    #13 0x5608e3d06cf5 in vm_exec_core insns.def:789:11
	    ruby#14 0x5608e3d43700 in rb_vm_exec vm.c:1892:22
	    ruby#15 0x5608e3d47cbf in rb_iseq_eval_main vm.c:2151:11
	    ruby#16 0x5608e37620ca in ruby_exec_internal eval.c:262:2
	    ruby#17 0x5608e376198b in ruby_exec_node eval.c:326:12
	    ruby#18 0x5608e37617d0 in ruby_run_node eval.c:318:25
	    ruby#19 0x5608e35c9486 in main main.c:42:9
	    #20 0x7f62e9421b96 in __libc_start_main
	/build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310

	previously allocated by thread T0 here:
	    #0 0x
F438
5608e359a56d in malloc (miniruby+0x1d756d)
	    #1 0x5608e37aed12 in objspace_xmalloc0 gc.c:9416:5
	    #2 0x5608e37aebe7 in ruby_xmalloc0 gc.c:9600:12
	    #3 0x5608e37aea8b in ruby_xmalloc_body gc.c:9609:12
	    #4 0x5608e37a6d64 in ruby_xmalloc gc.c:11469:12
	    #5 0x5608e380e4b4 in rb_io_fptr_new io.c:8040:19
	    #6 0x5608e380e446 in rb_io_make_open_file io.c:8077:10
	    #7 0x5608e3850ea0 in pipe_open io.c:6707:5
	    #8 0x5608e384edb4 in pipe_open_s io.c:6772:12
	    #9 0x5608e381910b in rb_f_backquote io.c:9014:12
	    #10 0x5608e3d8aa14 in call_cfunc_1 vm_insnhelper.c:2058:12
	    #11 0x5608e3d6e23d in vm_call_cfunc_with_frame vm_insnhelper.c:2211:11
	    #12 0x5608e3d54a35 in vm_call_cfunc vm_insnhelper.c:2229:12
	    #13 0x5608e3d5253b in vm_call_method_each_type vm_insnhelper.c:2564:9
	    ruby#14 0x5608e3d51f50 in vm_call_method vm_insnhelper.c:2701:13
	    ruby#15 0x5608e3cf2de4 in vm_call_general vm_insnhelper.c:2734:12
	    ruby#16 0x5608e3d79918 in vm_sendish vm_insnhelper.c:3627:11
	    ruby#17 0x5608e3d06cf5 in vm_exec_core insns.def:789:11
	    ruby#18 0x5608e3d43700 in rb_vm_exec vm.c:1892:22
	    ruby#19 0x5608e3d47cbf in rb_iseq_eval_main vm.c:2151:11
	    #20 0x5608e37620ca in ruby_exec_internal eval.c:262:2
	    ruby#21 0x5608e376198b in ruby_exec_node eval.c:326:12
	    ruby#22 0x5608e37617d0 in ruby_run_node eval.c:318:25
	    ruby#23 0x5608e35c9486 in main main.c:42:9
	    ruby#24 0x7f62e9421b96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310

	SUMMARY: AddressSanitizer: heap-use-after-free io.c:4749:24 in
	rb_io_memsize
	Shadow bytes around the buggy address:
	  0x0c207fff8160: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
	  0x0c207fff8170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
	  0x0c207fff8180: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
	  0x0c207fff8190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
	  0x0c207fff81a0: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
	=>0x0c207fff81b0: fd[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd fd
	  0x0c207fff81c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
	  0x0c207fff81d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
	  0x0c207fff81e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
	  0x0c207fff81f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
	  0x0c207fff8200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
	Shadow byte legend (one shadow byte represents 8 application bytes):
	  Addressable:           00
	  Partially addressable: 01 02 03 04 05 06 07
	  Heap left redzone:       fa
	  Freed heap region:       fd
	  Stack left redzone:      f1
	  Stack mid redzone:       f2
	  Stack right redzone:     f3
	  Stack after return:      f5
	  Stack use after scope:   f8
	  Global redzone:          f9
	  Global init order:       f6
	  Poisoned by user:        f7
	  Container overflow:      fc
	  Array cookie:            ac
	  Intra object redzone:    bb
	  ASan internal:           fe
	  Left alloca redzone:     ca
	  Right alloca redzone:    cb
	  Shadow gap:              cc
	==85264==ABORTING

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_6@67710 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
shyouhei pushed a commit that referenced this pull request Apr 23, 2021
This commit adds a check on the ep just like in the mark function.  The
env can contain null bytes if allocation tracing is enabled.

We're seeing errors during autocompaction like this:

```
(lldb) bt 40
* thread #1, name = 'ruby', stop reason = signal SIGABRT
    frame #0: 0x00007f7d64b6018b libc.so.6`raise + 203
    frame #1: 0x00007f7d64b3f859 libc.so.6`abort + 299
    frame #2: 0x000055af5f2fefc9 ruby`die at error.c:764:5
    frame #3: 0x000055af5f2ff1ac ruby`rb_bug_for_fatal_signal(default_sighandler=0x0000000000000000, sig=11, ctx=0x000055af60bc3340, fmt="") at error.c:804:5
    frame #4: 0x000055af5f4bd08f ruby`sigsegv(sig=11, info=0x000055af60bc3470, ctx=0x000055af60bc3340) at signal.c:960:5
    frame #5: 0x00007f7d64ebe3c0 libpthread.so.0`__restore_rt
    frame #6: 0x000055af5f339b0a ruby`gc_ref_update_imemo(objspace=0x000055af60b2b040, obj=0x00007f7d5b513fd0) at gc.c:9046:13
    frame #7: 0x000055af5f339172 ruby`gc_update_object_references(objspace=0x000055af60b2b040, obj=0x00007f7d5b513fd0) at gc.c:9307:9
    frame #8: 0x000055af5f338e79 ruby`gc_ref_update(vstart=0x00007f7d5b510010, vend=0x00007f7d5b513ff8, stride=40, objspace=0x000055af60b2b040, page=0x000055af62577aa0) at gc.c:9452:21
    frame #9: 0x000055af5f337846 ruby`gc_update_references(objspace=0x000055af60b2b040, heap=0x000055af60b2b068) at gc.c:9481:9
    frame #10: 0x000055af5f336569 ruby`gc_compact_finish(objspace=0x000055af60b2b040, heap=0x000055af60b2b068) at gc.c:4840:5
    frame #11: 0x000055af5f335efb ruby`gc_page_sweep(objspace=0x000055af60b2b040, heap=0x000055af60b2b068, sweep_page=0x000055af63a1eb30) at gc.c:5046:13
    frame #12: 0x000055af5f3355c5 ruby`gc_sweep_step(objspace=0x000055af60b2b040, heap=0x000055af60b2b068) at gc.c:5214:19
    frame #13: 0x000055af5f33daf6 ruby`gc_sweep_rest(objspace=0x000055af60b2b040) at gc.c:5271:2
    frame ruby#14: 0x000055af5f33cacd ruby`gc_sweep(objspace=0x000055af60b2b040) at gc.c:5389:2
    frame ruby#15: 0x000055af5f33c21d ruby`gc_marks_rest(objspace=0x000055af60b2b040) at gc.c:7555:5
    frame ruby#16: 0x000055af5f324d41 ruby`gc_rest(objspace=0x000055af60b2b040) at gc.c:8457:13
    frame ruby#17: 0x000055af5f3297d8 ruby`garbage_collect(objspace=0x000055af60b2b040, reason=45568) at gc.c:8318:9
    frame ruby#18: 0x000055af5f344ece ruby`garbage_collect_with_gvl(objspace=0x000055af60b2b040, reason=45568) at gc.c:8632:9
    frame ruby#19: 0x000055af5f344e61 ruby`objspace_malloc_gc_stress(objspace=0x000055af60b2b040) at gc.c:10592:9
    frame #20: 0x000055af5f32ced1 ruby`objspace_xmalloc0(objspace=0x000055af60b2b040, size=64) at gc.c:10767:5
    frame ruby#21: 0x000055af5f32ce11 ruby`ruby_xmalloc0(size=64) at gc.c:10988:12
    frame ruby#22: 0x000055af5f32cdac ruby`ruby_xmalloc_body(size=64) at gc.c:10997:12
    frame ruby#23: 0x000055af5f329415 ruby`ruby_xmalloc(size=64) at gc.c:12942:12
    frame ruby#24: 0x00007f7d611c4fe5 objspace.so`newobj_i(tpval=0x00007f7d5b553770, data=0x000055af639031a0) at object_tracing.c:101:35
    frame ruby#25: 0x000055af5f5b283f ruby`tp_call_trace(tpval=0x00007f7d5b553770, trace_arg=0x00007fff1016d398) at vm_trace.c:1115:2
    frame ruby#26: 0x000055af5f5b50ec ruby`exec_hooks_body(ec=0x000055af60b2b700, list=0x000055af60b2b920, trace_arg=0x00007fff1016d398) at vm_trace.c:304:3
    frame ruby#27: 0x000055af5f5b0f24 ruby`exec_hooks_unprotected(ec=0x000055af60b2b700, list=0x000055af60b2b920, trace_arg=0x00007fff1016d398) at vm_trace.c:333:5
    frame ruby#28: 0x000055af5f5b0da8 ruby`rb_exec_event_hooks(trace_arg=0x00007fff1016d398, hooks=0x000055af60b2b920, pop_p=0) at vm_trace.c:378:13
    frame ruby#29: 0x000055af5f33f8e2 ruby`rb_exec_event_hook_orig(ec=0x000055af60b2b700, hooks=0x000055af60b2b920, flag=1048576, self=0x00007f7d5b5c08c0, id=0, called_id=0, klass=0x0000000000000000, data=0x00007f7d5b513fd0, pop_p=0) at vm_core.h:1989:5
    frame ruby#30: 0x000055af5f334975 ruby`gc_event_hook_body(ec=0x000055af60b2b700, objspace=0x000055af60b2b040, event=1048576, data=0x00007f7d5b513fd0) at gc.c:2083:5
  * frame ruby#31: 0x000055af5f3342df ruby`newobj_slowpath_wb_protected [inlined] newobj_slowpath(klass=0x00007f7d5b9d19c8, flags=0x000000000000001a, objspace=0x000055af60b2b040, cr=0x000055af60b2b910, wb_protected=1) at gc.c:2284:9
    frame ruby#32: 0x000055af5f33410f ruby`newobj_slowpath_wb_protected(klass=0x00007f7d5b9d19c8, flags=0x000000000000001a, objspace=0x000055af60b2b040, cr=0x000055af60b2b910) at gc.c:2299
    frame ruby#33: 0x000055af5f333de9 ruby`newobj_of0(klass=0x00007f7d5b9d19c8, flags=0x000000000000001a, wb_protected=1, cr=0x000055af60b2b910) at gc.c:2338:11
    frame ruby#34: 0x000055af5f3227ae ruby`newobj_of(klass=0x00007f7d5b9d19c8, flags=0x000000000000001a, v1=0x000055af657d88a0, v2=0x000055af657d8890, v3=0x0000000000000000, wb_protected=1) at gc.c:2348:17
    frame ruby#35: 0x000055af5f322c5b ruby`rb_imemo_new(type=imemo_env, v1=0x000055af657d88a0, v2=0x000055af657d8890, v3=0x0000000000000000, v0=0x00007f7d5b9d19c8) at gc.c:2434:12
    frame ruby#36: 0x000055af5f5a3925 ruby`vm_env_new(env_ep=0x000055af657d88a0, env_body=0x000055af657d8890, env_size=4, iseq=0x00007f7d5b9d19c8) at vm_core.h:1363:33
    frame ruby#37: 0x000055af5f5a3808 ruby`vm_make_env_each(ec=0x000055af60b2b700, cfp=0x00007f7d6482fc90) at vm.c:801:11
    frame ruby#38: 0x000055af5f5a368d ruby`vm_make_env_each(ec=0x000055af60b2b700, cfp=0x00007f7d6482fc20) at vm.c:752:13
    frame ruby#39: 0x000055af5f5a368d ruby`vm_make_env_each(ec=0x000055af60b2b700, cfp=0x00007f7d6482fbb0) at vm.c:752:13
(lldb) f 31
frame ruby#31: 0x000055af5f3342df ruby`newobj_slowpath_wb_protected [inlined] newobj_slowpath(klass=0x00007f7d5b9d19c8, flags=0x000000000000001a, objspace=0x000055af60b2b040, cr=0x000055af60b2b910, wb_protected=1) at gc.c:2284:9
   2281	        }
   2282	        GC_ASSERT(obj != 0);
   2283	        newobj_init(klass, flags, wb_protected, objspace, obj);
-> 2284	        gc_event_hook_prep(objspace, RUBY_INTERNAL_EVENT_NEWOBJ, obj, newobj_fill(obj, 0, 0, 0));
   2285	    }
   2286	    RB_VM_LOCK_LEAVE_CR_LEV(cr, &lev);
   2287
(lldb) p obj
(VALUE) $3 = 0x00007f7d5b513fd0
(lldb) f 6
frame #6: 0x000055af5f339b0a ruby`gc_ref_update_imemo(objspace=0x000055af60b2b040, obj=0x00007f7d5b513fd0) at gc.c:9046:13
   9043	        {
   9044	            rb_env_t *env = (rb_env_t *)obj;
   9045	            TYPED_UPDATE_IF_MOVED(objspace, rb_iseq_t *, env->iseq);
-> 9046	            UPDATE_IF_MOVED(objspace, env->ep[VM_ENV_DATA_INDEX_ENV]);
   9047	            gc_update_values(objspace, (long)env->env_size, (VALUE *)env->env);
   9048	        }
   9049	        break;
(lldb) p obj
(VALUE) $4 = 0x00007f7d5b513fd0
(lldb)
```
shyouhei pushed a commit that referenced this pull request Aug 24, 2023
[Bug #19793]

Dummy frames are created at the top level when requiring another file.
While requiring a file, it will try to convert using encodings. Some of
these encodings will not respond to to_str. If method_missing is
redefined on Object, then it will call method_missing and attempt raise
an error. However, the iseq is invalid as it's a dummy frame so it will
write an invalid iseq to the created NoMethodError.

The following script crashes:

```
GC.stress = true

class Object
  public :method_missing
end

File.write("/tmp/empty.rb", "")
require "/tmp/empty.rb"
```

With the following backtrace:

```
frame #0: 0x00000001000fa8b8 miniruby`RVALUE_MARKED(obj=4308637824) at gc.c:1638:12
frame #1: 0x00000001000fb440 miniruby`RVALUE_BLACK_P(obj=4308637824) at gc.c:1763:12
frame #2: 0x00000001000facdc miniruby`gc_writebarrier_incremental(a=4308637824, b=4308332208, objspace=0x000000010180b000) at gc.c:8822:9
frame #3: 0x00000001000faad8 miniruby`rb_gc_writebarrier(a=4308637824, b=4308332208) at gc.c:8864:17
frame #4: 0x000000010016aff0 miniruby`rb_obj_written(a=4308637824, oldv=36, b=4308332208, filename="../iseq.c", line=1279) at gc.h:804:9
frame #5: 0x0000000100162a60 miniruby`rb_obj_write(a=4308637824, slot=0x0000000100d09888, b=4308332208, filename="../iseq.c", line=1279) at gc.h:837:5
frame #6: 0x0000000100165b0c miniruby`iseqw_new(iseq=0x0000000100d09880) at iseq.c:1279:9
frame #7: 0x0000000100165a64 miniruby`rb_iseqw_new(iseq=0x0000000100d09880) at iseq.c:1289:12
frame #8: 0x00000001000d8324 miniruby`name_err_init_attr(exc=4309777920, recv=4304780496, method=827660) at error.c:1830:35
frame #9: 0x00000001000d1b80 miniruby`name_err_init(exc=4309777920, mesg=4308332496, recv=4304780496, method=827660) at error.c:1869:12
frame #10: 0x00000001000d1bd4 miniruby`rb_nomethod_err_new(mesg=4308332496, recv=4304780496, method=827660, args=4308332448, priv=0) at error.c:1957:5
frame #11: 0x000000010039049c miniruby`rb_make_no_method_exception(exc=4304914512, format=4308332496, obj=4304780496, argc=1, argv=0x000000016fdfab00, priv=0) at vm_eval.c:959:16
frame #12: 0x00000001003b3274 miniruby`raise_method_missing(ec=0x0000000100b06f40, argc=1, argv=0x000000016fdfab00, obj=4304780496, last_call_status=MISSING_NOENTRY) at vm_eval.c:999:15
frame #13: 0x00000001003945d4 miniruby`rb_method_missing(argc=1, argv=0x000000016fdfab00, obj=4304780496) at vm_eval.c:944:5
...
frame ruby#23: 0x000000010038f5e4 miniruby`rb_vm_call_kw(ec=0x0000000100b06f40, recv=4304780496, id=2865, argc=1, argv=0x000000016fdfab00, me=0x0000000100cbfcf0, kw_splat=0) at vm_eval.c:326:12
frame ruby#24: 0x00000001003c18e4 miniruby`call_method_entry(ec=0x0000000100b06f40, defined_class=4304927952, obj=4304780496, id=2865, cme=0x0000000100cbfcf0, argc=1, argv=0x000000016fdfab00, kw_splat=0) at vm_method.c:2720:20
frame ruby#25: 0x00000001003c440c miniruby`check_funcall_exec(v=6171896792) at vm_eval.c:589:12
frame ruby#26: 0x00000001000dec00 miniruby`rb_vrescue2(b_proc=(miniruby`check_funcall_exec at vm_eval.c:587), data1=6171896792, r_proc=(miniruby`check_funcall_failed at vm_eval.c:596), data2=6171896792, args="Pȗ") at eval.c:919:18
frame ruby#27: 0x00000001000deab0 miniruby`rb_rescue2(b_proc=(miniruby`check_funcall_exec at vm_eval.c:587), data1=6171896792, r_proc=(miniruby`check_funcall_failed at vm_eval.c:596), data2=6171896792) at eval.c:900:17
frame ruby#28: 0x000000010039008c miniruby`check_funcall_missing(ec=0x0000000100b06f40, klass=4304923536, recv=4304780496, mid=3233, argc=0, argv=0x0000000000000000, respond=-1, def=36, kw_splat=0) at vm_eval.c:666:15
frame ruby#29: 0x000000010038fa60 miniruby`rb_check_funcall_default_kw(recv=4304780496, mid=3233, argc=0, argv=0x0000000000000000, def=36, kw_splat=0) at vm_eval.c:703:21
frame ruby#30: 0x000000010038fb04 miniruby`rb_check_funcall(recv=4304780496, mid=3233, argc=0, argv=0x0000000000000000) at vm_eval.c:685:12
frame ruby#31: 0x00000001001c469c miniruby`convert_type_with_id(val=4304780496, tname="String", method=3233, raise=0, index=-1) at object.c:3061:15
frame ruby#32: 0x00000001001c4a4c miniruby`rb_check_convert_type_with_id(val=4304780496, type=5, tname="String", method=3233) at object.c:3153:9
frame ruby#33: 0x00000001002d59f8 miniruby`rb_check_string_type(str=4304780496) at string.c:2571:11
frame ruby#34: 0x000000010014b7b0 miniruby`io_encoding_set(fptr=0x0000000100d09ca0, 
10000
v1=4304780496, v2=4, opt=4) at io.c:11655:19
frame ruby#35: 0x0000000100139a58 miniruby`rb_io_set_encoding(argc=1, argv=0x000000016fdfb450, io=4308334032) at io.c:13497:5
frame ruby#36: 0x00000001003c0004 miniruby`ractor_safe_call_cfunc_m1(recv=4308334032, argc=1, argv=0x000000016fdfb450, func=(miniruby`rb_io_set_encoding at io.c:13487)) at vm_insnhelper.c:3271:12
...
frame ruby#43: 0x0000000100390b08 miniruby`rb_funcall(recv=4308334032, mid=16593, n=1) at vm_eval.c:1137:12
frame ruby#44: 0x00000001002a43d8 miniruby`load_file_internal(argp_v=6171899936) at ruby.c:2500:5
...
```
shyouhei pushed a commit that referenced this pull request Feb 5, 2025
[Bug #20921]

When we create a cache entry for a constant, the following sequence of
events could happen:

- vm_track_constant_cache is called to insert a constant cache.
- In vm_track_constant_cache, we first look up the ST table for the ID
  of the constant. Assume the ST table exists because another iseq also
  holds a cache entry for this ID.
- We then insert into this ST table with the iseq_inline_constant_cache.
- However, while inserting into this ST table, it allocates memory, which
  could trigger a GC. Assume that it does trigger a GC.
- The GC frees the one and only other iseq that holds a cache entry for
  this ID.
- In remove_from_constant_cache, it will appear that the ST table is now
  empty because there are no more iseq with cache entries for this ID, so
  we free the ST table.
- We complete GC and continue our st_insert. However, this ST table has
  been freed so we now have a use-after-free.

This issue is very hard to reproduce, because it requires that the GC runs
at a very specific time. However, we can make it show up by applying this
patch which runs GC right before the st_insert to mimic the st_insert
triggering a GC:

    diff --git a/vm_insnhelper.c b/vm_insnhelper.c
    index 3cb23f0..a93998136a 100644
    --- a/vm_insnhelper.c
    +++ b/vm_insnhelper.c
    @@ -6338,6 +6338,10 @@ vm_track_constant_cache(ID id, void *ic)
            rb_id_table_insert(const_cache, id, (VALUE)ics);
        }

    +    if (id == rb_intern("MyConstant")) rb_gc();
    +
        st_insert(ics, (st_data_t) ic, (st_data_t) Qtrue);
    }

And if we run this script:

    Object.const_set("MyConstant", "Hello!")

    my_proc = eval("-> { MyConstant }")
    my_proc.call

    my_proc = eval("-> { MyConstant }")
    my_proc.call

We can see that ASAN outputs a use-after-free error:

    ==36540==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000049528 at pc 0x000102f3ceac bp 0x00016d607a70 sp 0x00016d607a68
    READ of size 8 at 0x606000049528 thread T0
        #0 0x102f3cea8 in do_hash st.c:321
        #1 0x102f3ddd0 in rb_st_insert st.c:1132
        #2 0x103140700 in vm_track_constant_cache vm_insnhelper.c:6345
        #3 0x1030b91d8 in vm_ic_track_const_chain vm_insnhelper.c:6356
        #4 0x1030b8cf8 in rb_vm_opt_getconstant_path vm_insnhelper.c:6424
        #5 0x1030bc1e0 in vm_exec_core insns.def:263
        #6 0x1030b55fc in rb_vm_exec vm.c:2585
        #7 0x1030fe0ac in rb_iseq_eval_main vm.c:2851
        #8 0x102a82588 in rb_ec_exec_node eval.c:281
        #9 0x102a81fe0 in ruby_run_node eval.c:319
        #10 0x1027f3db4 in rb_main main.c:43
        #11 0x1027f3bd4 in main main.c:68
        #12 0x183900270  (<unknown module>)

    0x606000049528 is located 8 bytes inside of 56-byte region [0x606000049520,0x606000049558)
    freed by thread T0 here:
        #0 0x104174d40 in free+0x98 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x54d40)
        #1 0x102ada89c in rb_gc_impl_free default.c:8183
        #2 0x102ada7dc in ruby_sized_xfree gc.c:4507
        #3 0x102ac4d34 in ruby_xfree gc.c:4518
        #4 0x102f3cb34 in rb_st_free_table st.c:663
        #5 0x102bd52d8 in remove_from_constant_cache iseq.c:119
        #6 0x102bbe2cc in iseq_clear_ic_references iseq.c:153
        #7 0x102bbd2a0 in rb_iseq_free iseq.c:166
        #8 0x102b32ed0 in rb_imemo_free imemo.c:564
        #9 0x102ac4b44 in rb_gc_obj_free gc.c:1407
        #10 0x102af4290 in gc_sweep_plane default.c:3546
        #11 0x102af3bdc in gc_sweep_page default.c:3634
        #12 0x102aeb140 in gc_sweep_step default.c:3906
        #13 0x102aeadf0 in gc_sweep_rest default.c:3978
        ruby#14 0x102ae4714 in gc_sweep default.c:4155
        ruby#15 0x102af8474 in gc_start default.c:6484
        ruby#16 0x102afbe30 in garbage_collect default.c:6363
        ruby#17 0x102ad37f0 in rb_gc_impl_start default.c:6816
        ruby#18 0x102ad3634 in rb_gc gc.c:3624
        ruby#19 0x1031406ec in vm_track_constant_cache vm_insnhelper.c:6342
        #20 0x1030b91d8 in vm_ic_track_const_chain vm_insnhelper.c:6356
        ruby#21 0x1030b8cf8 in rb_vm_opt_getconstant_path vm_insnhelper.c:6424
        ruby#22 0x1030bc1e0 in vm_exec_core insns.def:263
        ruby#23 0x1030b55fc in rb_vm_exec vm.c:2585
        ruby#24 0x1030fe0ac in rb_iseq_eval_main vm.c:2851
        ruby#25 0x102a82588 in rb_ec_exec_node eval.c:281
        ruby#26 0x102a81fe0 in ruby_run_node eval.c:319
        ruby#27 0x1027f3db4 in rb_main main.c:43
        ruby#28 0x1027f3bd4 in main main.c:68
        ruby#29 0x183900270  (<unknown module>)

    previously allocated by thread T0 here:
        #0 0x104174c04 in malloc+0x94 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x54c04)
        #1 0x102ada0ec in rb_gc_impl_malloc default.c:8198
        #2 0x102acee44 in ruby_xmalloc gc.c:4438
        #3 0x102f3c85c in rb_st_init_table_with_size st.c:571
        #4 0x102f3c900 in rb_st_init_table st.c:600
        #5 0x102f3c920 in rb_st_init_numtable st.c:608
        #6 0x103140698 in vm_track_constant_cache vm_insnhelper.c:6337
        #7 0x1030b91d8 in vm_ic_track_const_chain vm_insnhelper.c:6356
        #8 0x1030b8cf8 in rb_vm_opt_getconstant_path vm_insnhelper.c:6424
        #9 0x1030bc1e0 in vm_exec_core insns.def:263
        #10 0x1030b55fc in rb_vm_exec vm.c:2585
        #11 0x1030fe0ac in rb_iseq_eval_main vm.c:2851
        #12 0x102a82588 in rb_ec_exec_node eval.c:281
        #13 0x102a81fe0 in ruby_run_node eval.c:319
        ruby#14 0x1027f3db4 in rb_main main.c:43
        ruby#15 0x1027f3bd4 in main main.c:68
        ruby#16 0x183900270  (<unknown module>)

This commit fixes this bug by adding a inserting_constant_cache_id field
to the VM, which stores the ID that is currently being inserted and, in
remove_from_constant_cache, we don't free the ST table for ID equal to
this one.

Co-Authored-By: Alan Wu <alanwu@ruby-lang.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

0