SEGVæ¢åµãå¾ã
人ã¯èª°ãã108ã¤ã®å¤¢ãæã¤ã¨è¨ãã¾ãããèªè ã®çããã«ãæ¢åµã夢è¦ã人ã¯å¤ããã¨ã§ããããå®éåé¡ã¨ãã¦æ¢åµæ¥ããããã¨æã£ããå°éãªèãè¾¼ã¿ï¼å¼µãè¾¼ã¿ã®æ¥ã ã§ãããããéã«æ´¾æãªæ¢åµæ¥ã¯é°è¬ï¼æ®ºäººã§æããããããããèªåã®å½ã¯å¤§äºã§ãããã©ããããããããæ¢åµãã£ããããããã§ããã
ã¨ããããã§SEGVæ¢åµã§ããæ»ã¬ã®ã¯ããã»ã¹ãªã®ã§å®å¿ãRubyã使ã£ã¦ããã°SEGVãªãã¦è¦æ £ãããã®ã§ãããããææ»ãããã¨æãã¨æå¤ã¨ãã®è¾ºã«ã¯è»¢ãã£ã¦ããªããã®ãï¼ãããã¯ã¤ãã¿åãåºæ¥ããããããããã§ããï¼ã¨ã¯ããä»ã§ãããããããã°é±èãã¿ãããªãã®ã¯ããã¾ãã¦ããã®ä¸ã¤ããææ°ã®ã³ã³ãã¤ã©ã§ãã«ããã¦ã¿ããã§ãã
ä»æ¥ã¯GCCã®éçºçã§ããGCC8ã試ãã¦ã¿ã¾ããããFreeBSDã ã¨sudo pkg install lang/gcc8-devel
ã§ç°¡åã«å
¥ããããã®ã§ãããä»ã®ç°å¢ã ã¨ã¡ãã£ã¨å¤§å¤ããããã¾ããããã¦ãããã¡ã§ã¯ç°¡åãªã®ã§å
¥ãã¦ãã«ããã¦make test
ãã¦ã¿ã¾ãã
ã»ã»ã»ã¯ããæ©éSEGVãã¾ããã
test_thread.rb ...................................FF............. #1180 test_thread.rb:330:in `<top (required)>': Fiber.new(&Object.method(:class_eval)).resume("foo") #=> killed by SIGIOT (signal 6) | [BUG] Segmentation fault at 0x0000000000000000 | ruby 2.5.0dev (2017-08-20 trunk 59626) [x86_64-linux] | | -- Control frame information ----------------------------------------------- | c:0003 p:---- s:0009 e:000008 CFUNC :class_eval | c:0002 p:---- s:0006 e:000005 IFUNC | c:0001 p:---- s:0003 e:000002 (none) [FINISH] | | -- Ruby level backtrace information ---------------------------------------- | bootstraptest.tmp.rb:0:in `class_eval' | | -- Machine register context ------------------------------------------------ | RIP: 0x000000000060a481 RBP: 0x00000000010a5630 RSP: 0x00007ff54468ea60 | RAX: 0x00007ff5446af010 RBX: 0x0000000000000001 RCX: 0x00007ff5446af010 | RDX: 0x0000000000000000 RDI: 0x00000000010e5730 RSI: 0x00000000010a5680 | R8: 0x0000000000000034 R9: 0x0000000000000001 R10: 0x000000000000101a | R11: 0x0000000000000000 R12: 0x0000000000000000 R13: 0x0000000000000034 | R14: 0x00000000010e5730 R15: 0x00007ff54468ee48 EFL: 0x0000000000010202 | | -- C level backtrace information ------------------------------------------- | /home/ko1/ruby/build/trunk-test-gcc-trunk-np/miniruby(rb_vm_bugreport+0x50d) [0x6157ad] /home/ko1/ruby/src/trunk-test-gcc-trunk-np/vm_dump.c:671 | /home/ko1/ruby/build/trunk-test-gcc-trunk-np/miniruby(rb_bug_context+0xd8) [0x491e28] /home/ko1/ruby/src/trunk-test-gcc-trunk-np/error.c:539 | /home/ko1/ruby/build/trunk-test-gcc-trunk-np/miniruby(sigsegv+0x42) [0x588802] /home/ko1/ruby/src/trunk-test-gcc-trunk-np/signal.c:930 | /lib/x86_64-linux-gnu/libpthread.so.0 [0x7ff544395390] | /home/ko1/ruby/build/trunk-test-gcc-trunk-np/miniruby(eval_string_with_cref+0xb1) [0x60a481] /home/ko1/ruby/src/trunk-test-gcc-trunk-np/vm.c:505 | /home/ko1/ruby/build/trunk-test-gcc-trunk-np/miniruby(rb_mod_module_eval+0x10a) [0x60afca] /home/ko1/ruby/src/trunk-test-gcc-trunk-np/vm_eval.c:1613 | /home/ko1/ruby/build/trunk-test-gcc-trunk-np/miniruby(vm_call0_body.constprop.158+0x270) [0x60b610] /home/ko1/ruby/src/trunk-test-gcc-trunk-np/vm_eval.c:86 | /home/ko1/ruby/build/trunk-test-gcc-trunk-np/miniruby(rb_vm_call+0x30) [0x60ba80] /home/ko1/ruby/src/trunk-test-gcc-trunk-np/vm_eval.c:59 | /home/ko1/ruby/build/trunk-test-gcc-trunk-np/miniruby(vm_yield_with_cfunc.isra.128+0x14d) [0x5fe39d] /home/ko1/ruby/src/trunk-test-gcc-trunk-np/vm_insnhelper.c:2532 | /home/ko1/ruby/build/trunk-test-gcc-trunk-np/miniruby(rb_vm_invoke_proc+0x5c) [0x6094cc] /home/ko1/ruby/src/trunk-test-gcc-trunk-np/vm.c:1167 | /home/ko1/ruby/build/trunk-test-gcc-trunk-np/miniruby(rb_fiber_start+0x11e) [0x47097e] /home/ko1/ruby/src/trunk-test-gcc-trunk-np/cont.c:1344 | /lib/x86_64-linux-gnu/libc.so.6 [0x7ff54363f5d0] | â¦
Rubyã«ã¯SEGVãçºçããéã«ããããã£ãããã¦Cã¬ãã«ã§ã®ããã¯ãã¬ã¼ã¹ã表示ããæ©è½ãã¤ãã¦ããã®ã§ããããªãCã½ã¼ã¹ã«ãã©ãçããã¨ãåºæ¥ã¾ããä¸ã®4è¡ã¯Cããã¯ãã¬ã¼ã¹è¡¨ç¤ºé¨åã¨ã·ã°ãã«ãã©ã³ããªã³ãªã®ã§é£ã°ãã¦ã/home/ko1/ruby/build/trunk-test-gcc-trunk-np/miniruby(eval_string_with_cref+0xb1) [0x60a481] /home/ko1/ruby/src/trunk-test-gcc-trunk-np/vm.c:505
ãæ¬é¡ã§ãããè¦ã¦ã¿ã¾ãããã
rb_control_frame_t * rb_vm_get_ruby_level_next_cfp(const rb_thread_t *th, const rb_control_frame_t *cfp) { while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) { if (VM_FRAME_RUBYFRAME_P(cfp)) { return (rb_control_frame_t *)cfp; } cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); } return 0; }
505è¡ç®ã¯RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)
ã§ããããã¯ããä¸æ¯ã§ãããããã¾ãããããããã¨ãã¯Makefileãéãã¦ãCFLAGSã®è¡ã«-save-temps
ã追å ãã¦ãã«ããç´ãã¨ã³ã³ãã¤ã«ä¸ã®ä¸æãã¡ã¤ã«ãæ®ãã¾ããä»åã®å ´åvm.iãæ®ã£ã¦ããã¯ãã§ããè¦ãã¨ä»¥ä¸ã®ãããªå
容ãå¾ããã¾ãã
rb_control_frame_t * rb_vm_get_ruby_level_next_cfp(const rb_thread_t *th, const rb_control_frame_t *cfp) { while (!(!((void *)(((rb_control_frame_t *)((th)->ec.vm_stack + (th)->ec.vm_stack_size))) > (void *)((cfp))))) { if (VM_FRAME_RUBYFRAME_P(cfp)) { return (rb_control_frame_t *)cfp; } cfp = ((cfp)+1); } return 0; }
ãªããVM_FRAME_RUBYFRAME_P()
ã¯ãã¯ãã¨è¦ãããã¦é¢æ°ã§ãå®è³ªcfp->ep[0] & 0x80
ã¨ããå
容ã§ãã
å¤ãã³ã³ãã¤ã©ãªãã°åãã®ã«ææ°ã®ã³ã³ãã¤ã©ã§ã ããããã¨ããå ´åã¯ãé常ããé«åº¦ã«ãªã£ãæé©åãåå ã§ããã§ãã®ã§ãã³ã³ãã¤ã©ã®æé©åã§å£ãããããªè¦ç´ ãå ·ä½çã«ã¯Cæ¨æºã«ããã¦æªå®ç¾©ãªåä½ãã¤ãã³ã¼ãããåé·ã§ã³ã³ãã¤ã©ã«ãã£ã¦æ¶ãããããªã³ã¼ããæ¢ãã®ã§ããâ¦â¦è¦å½ããã¾ãããâ¦â¦ãä»®ã«ãã®ãããªã³ã¼ãããã£ããªããç´ãã¦ã¿ã¦ãã¾ãåãã°å¤§åå©ãªã®ã§ãããä»åã¯ããã§ã¯ãªãã£ãããã§ãã
ã¨ããã¨ãããã¯ã³ã³ãã¤ã©å´ã®åé¡ã§ããå¯è½æ§ãé«ã¾ã£ã¦ãã¾ãããããããã©ã®ããã«ãã¦ã³ã³ãã¤ã©ã®åé¡ã§ãããã¨ã示ãã°è¯ãã®ã§ããããããã®åãã¯ç§ã«ã¨ã£ã¦æªè§£æ±ºãªã®ã§ãããã¨ããããæå¾ ã¨ç°ãªãå½ä»¤åãåºåããã¦ãããã¨ã示ããã¨ã«ãã¾ããããããã示ãã«ã¯ããã¤ãæ¹æ³ãããã¾ãã
- gdbãªã©ã®å½ä»¤åä½ã¹ãããå®è¡ã使ã£ã¦ãæå¾ ã¨ç°ãªãåããããã¿ã¤ãã³ã°ãè¦ã¤ãã
- objdumpãªã©ã«ããéã¢ã»ã³ãã«çµæãè¦ã¦ãæå¾ ã¨ç°ãªãå½ä»¤åãè¦ã¤ãã
é常ããããã°ã«ããã¦ã¯ãæå¾ ããåä½ã¨ã¯ã©ããªãã®ããã¨ããé常ã«é£ããåé¡ãããã®ã§ãããä»åã®å ´åå°ãå¤ãã³ã³ãã¤ã©ã®çµæã¨æ¯è¼ãããã¨ã§ããã¹ã姿ãã©ããªãã®ãç¥ããã¨ãåºæ¥ã¾ãã
ã¾ãããã°ãè¦ã¤ããã¨ãã¯ã¾ãåç¾åºæ¥ãããã«ãããã¨ãéè¦ã§ãããããã¯æ¢ã«éæããã¾ãããã¾ããå°ããªRubyã³ã¼ãã§åç¾åºæ¥ãããã«ãããã¨ãéè¦ã§ããããããéæåºæ¥ã¦ãã¾ããããã¾ã§å°ãããã°gdbã§å®è¡ãã¦ã¿ã¾ãããã
% gdb --args ./miniruby -e'Thread.new("foo", &Object.method(:class_eval)).join' GNU gdb (GDB) 8.0 [GDB v8.0 for FreeBSD] Copyright (C) 2017 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-portbld-freebsd10.3". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from ./miniruby...done. (gdb) r Starting program: /tmp/ruby/miniruby -eThread.new\(\"foo\",\ \&Object.method\(:class_eval\)\).join [New LWP 101479 of process 94182] [New LWP 101478 of process 94182] Thread 2 received signal SIGSEGV, Segmentation fault. [Switching to LWP 101479 of process 94182] 0x000000000124c591 in rb_vm_get_ruby_level_next_cfp (cfp=0x805506000, th=<optimized out>) at vm.c:505 505 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
ã¾ããgdbä¸ã§ãåç¾ããã®ã¯ãããã¨ãªã®ã§ãããæ¬å½ã¯ãã®ã¡ãã£ã¨åã§breakãããã®ã§ããããã¯Linuxã ã¨Reverse Debugã¨ããéæ³ã§è§£æ±ºåºæ¥ãã®ã§ãããFreeBSDã§ã¯ãµãã¼ãããã¦ããªãã®ã§conditional breakpointã使ãã¾ããããèããçµæãb rb_vm_get_ruby_level_next_cfp if ruby_current_thread != ruby_current_vm->main_thread&&ruby_current_vm->main_thread
ã§SEGVå°ãåã«è¡ãã¾ãã
ããããstepiï¼å½ä»¤åä½ã¹ãããå®è¡ï¼ã使ã£ã¦ã¨ããããæµãè¦ãã¾ããããã¨ãããã¨çãç¯å²ãã«ã¼ããã¦ãããã¨ãåããã¾ããã¾ãCã®ã³ã¼ããè¦è¿ãã¦ã¿ãã°å½ç¶ãªã®ã§ãããã§ã¯ã«ã¼ããã¦ããç¯å²ãéã¢ã»ã³ãã«ãã¦è¦ã¦ã¿ã¾ããã
(gdb) disas 0x000000000124c591-61,+116 Dump of assembler code from 0x124c554 to 0x124c5c8: 0x000000000124c554 <eval_string_with_cref+116>: mov 0x60(%rsp),%rdx 0x000000000124c559 <eval_string_with_cref+121>: mov 0x28(%rdx),%rcx 0x000000000124c55d <eval_string_with_cref+125>: mov 0x20(%rdx),%rdx 0x000000000124c561 <eval_string_with_cref+129>: mov 0x30(%rax),%rax 0x000000000124c565 <eval_string_with_cref+133>: lea (%rdx,%rcx,8),%rcx 0x000000000124c569 <eval_string_with_cref+137>: cmp %rcx,%rax 0x000000000124c56c <eval_string_with_cref+140>: jae 0x124c59f <eval_string_with_cref+191> 0x000000000124c56e <eval_string_with_cref+142>: mov 0x20(%rax),%rdx 0x000000000124c572 <eval_string_with_cref+146>: testb $0x80,(%rdx) 0x000000000124c575 <eval_string_with_cref+149>: jne 0x124c589 <eval_string_with_cref+169> 0x000000000124c577 <eval_string_with_cref+151>: jmpq 0x124c6d8 <eval_string_with_cref+504> 0x000000000124c57c <eval_string_with_cref+156>: nopl 0x0(%rax) 0x000000000124c580 <eval_string_with_cref+160>: test %rdx,%rdx 0x000000000124c583 <eval_string_with_cref+163>: je 0x124c6d8 <eval_string_with_cref+504> 0x000000000124c589 <eval_string_with_cref+169>: add $0x30,%rax 0x000000000124c58d <eval_string_with_cref+173>: mov 0x20(%rax),%rdx => 0x000000000124c591 <eval_string_with_cref+177>: mov (%rdx),%rdx 0x000000000124c594 <eval_string_with_cref+180>: and $0x80,%edx 0x000000000124c59a <eval_string_with_cref+186>: cmp %rax,%rcx 0x000000000124c59d <eval_string_with_cref+189>: ja 0x124c580 <eval_string_with_cref+160> 0x000000000124c59f <eval_string_with_cref+191>: lea 0x306f5a(%rip),%rax # 0x1553500 <rb_eRuntimeError> 0x000000000124c5a6 <eval_string_with_cref+198>: lea 0x4a79b(%rip),%rsi # 0x1296d48 0x000000000124c5ad <eval_string_with_cref+205>: mov (%rax),%rdi 0x000000000124c5b0 <eval_string_with_cref+208>: xor %eax,%eax 0x000000000124c5b2 <eval_string_with_cref+210>: callq 0x10c4af0 <rb_raise> 0x000000000124c5b7 <eval_string_with_cref+215>: nopw 0x0(%rax,%rax,1) 0x000000000124c5c0 <eval_string_with_cref+224>: lea 0x2f3499(%rip),%rsi # 0x153fa60 <ruby_binding_data_type> 0x000000000124c5c7 <eval_string_with_cref+231>: mov %rax,%rdi
stepiã«ããã¨ãæåããèµ°ã£ã¦ããå¾ããã°ãã0x124c580ã¨0x124c59dã®éãã«ã¼ããã¦ãæå¾ã«0x124c591ã§SEGVãã¦ãã¾ããããã§ã®ç»å ´äººç©ãç´¹ä»ãã¦ããã¨ä»¥ä¸ã®éãã§ãã
- rax:
cfp
- rcx:
(th)->ec.vm_stack + (th)->ec.vm_stack_size
- rdx:
cfp->ep
orcfp->ep[0]
orcfp->ep[0] & 80
add $0x30,%rax
ã cfp+1
ã«å¯¾å¿ããmov; mov; and
ãcfp->ep[0] & 80
ã«å¯¾å¿ããã®ã§ãããåã®è¨ãæ¹ã¯ããæ°ä»ãããã®ã§ã¯ãªãã§ãããããcfpã®å¦¥å½æ§ãã¤ã¾ã確ãã«cfp-ep[0]
ã«ã¢ã¯ã»ã¹åºæ¥ãã¨ããã®ã¯ã(th)->ec.vm_stack + (th)->ec.vm_stack_size > cfp
ãçã®æã«ã ãä¿è¨¼ããã¦ãã¾ãããããããã®éã¢ã»ã³ãã«ã§ã¯ãã®åå²ã§ããcmp %rax,%rcx; ja
ã®åã«ãmov 0x20(%rax),%rdx; mov (%rdx),%rdx
ã§cfp->ep
ã«ã¢ã¯ã»ã¹ãã¦ãã¾ã£ã¦ãã¾ããããã®ãããªé çªã®å
¥ãæ¿ãã¯è¨±ããã¦ãã¾ãããã§ãã®ã§ããããããä»åã®ç´æ¥ã®åå ã ã£ããã¨ãåããã¾ãã
ã¨ãããããªè©±ãã¾ã¨ãã¦ãã°ã¬ãã¼ãããã®ãBug 81954 - gcc8 too aggressively reorders memory access beyond conditionã§ããããã¯çµå±ã¯Bug 81900 - [8 Regression] GCC trunk miscompiles Perl / __sigsetjmp issueã®duplicateã§ãããå ±åã®æ°æ¥åã«ç´ã£ã¦ããã¨ããæ®å¿µãªè©±ã§ãããå®éãGCC8ãtrunkãããã«ããç´ããã¨ãããã£ãã解決ãã¦ãã¾ãã¾ããã
ä»åã¯æ®å¿µãªããç¯äººã«èªæ®ºããã¦ãã¾ããããªæ®å¿µãªå¹åãã¨ãªã£ã¦ãã¾ãã¾ããããããããã®è¨äºã«æ¸ãããããªãæ¢åµä¸ã¤éå ·ã使ãã証æ ãéããSEGVã追ãè©°ãã¦ããéç¨ã¯ãSEGVæ¢åµãå¿ãçããã«ã¨ã£ã¦åèã¨ãªãã®ã§ã¯ãªãã§ããããããªãã¨ããã§ããã
ãã®ã±ã¼ã¹ã¨ã¯ç°ãªããããRubyå´ã«åé¡ããã£ã¦ããã£ã1è¡ã®ãããã§åé¡ã解決åºæ¥ãããããªã±ã¼ã¹ã«åºä¼ãããªãã°ãããªãã¯ãã£ã¨ãã¼ã¯ã½ã¦ã«ãFF14ãªã©ã®ã¨ã¦ãé£ãããã¹ãåããã¨ãã®ãããªæ°æã¡ãä½é¨åºæ¥ããã¨ã§ããããããã誰ã ãããªé£æ度ã«èª¿æ´ãããã£ããã¤ã¯ï¼ãµããããªï¼ï¼ãã¨ããæ°æã¡ã§ããã
ãã®è¨äºãèªãã çããããææ¥ããã¯SEGVãè¸ãã§ããã¯ã¯ããäºä»¶ã®ã«ãããããããã¨ãã¤ãªã¨ç¬ãããã¨ãç¥ã£ã¦ãã¾ãã