in mingw32, there is setjmp/longjmp which its implementation is specific to msvc. and, in latest gcc trunk ebp register doesn't have to have its caller's frame address.( unfortunately, this could cause mingw32 application which use setjmp/longjmp to SIGSEGV. because in msvcrt, __NLG_Notify dereferences ebp+8 which is *(((void*)jmp_buf[0])+2) which msvcrt assumes it's correct address(maybe first parameter of caller function), and which it assumes is wrong for now.
Hmm, I can't confirm this. Do you have a testcase for this? As far as I know has msvcrt's setjmp function an hidden argument, which should be for 32-bit NULL. This might be here the real issue.
Created attachment 24635 [details] testcase i hope it would be helpful GNU gdb (GDB) 7.3.50.20110610-cvs Copyright (C) 2011 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 "i686-pc-cygwin". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... warning: the current range check setting does not match the language. warning: the current type check setting does not match the language. Whether backtraces should continue past the entry point of a program is off. Reading symbols from /tmp/a...done. (gdb) r Starting program: /tmp/a [New Thread 9616.0x1628] Program received signal SIGSEGV, Segmentation fault. 0x77b66502 in msvcrt!_abnormal_termination () from /cygdrive/c/WINDOWS/system32/msvcrt.dll (gdb) bt #0 0x77b66502 in msvcrt!_abnormal_termination () from /cygdrive/c/WINDOWS/system32/msvcrt.dll #1 0x77b6ac67 in strerror () from /cygdrive/c/WINDOWS/system32/msvcrt.dll Backtrace stopped: previous frame inner to this frame (corrupt stack?) (gdb) disassemble Dump of assembler code for function msvcrt!_abnormal_termination: 0x77b664cf <+0>: xor %eax,%eax 0x77b664d1 <+2>: mov %fs:0x0,%ecx 0x77b664d8 <+9>: cmpl $0x77b66424,0x4(%ecx) 0x77b664df <+16>: jne 0x77b664f1 <msvcrt!_abnormal_termination+34> 0x77b664e1 <+18>: mov 0xc(%ecx),%edx 0x77b664e4 <+21>: mov 0xc(%edx),%edx 0x77b664e7 <+24>: cmp %edx,0x8(%ecx) 0x77b664ea <+27>: jne 0x77b664f1 <msvcrt!_abnormal_termination+34> 0x77b664ec <+29>: mov $0x1,%eax 0x77b664f1 <+34>: ret 0x77b664f2 <+35>: push %ebx 0x77b664f3 <+36>: push %ecx 0x77b664f4 <+37>: mov $0x77b919b0,%ebx 0x77b664f9 <+42>: jmp 0x77b66505 <msvcrt!_abnormal_termination+54> 0x77b664fb <+44>: push %ebx 0x77b664fc <+45>: push %ecx 0x77b664fd <+46>: mov $0x77b919b0,%ebx => 0x77b66502 <+51>: mov 0x8(%ebp),%ecx 0x77b66505 <+54>: mov %ecx,0x8(%ebx) 0x77b66508 <+57>: mov %eax,0x4(%ebx) 0x77b6650b <+60>: mov %ebp,0xc(%ebx) 0x77b6650e <+63>: push %ebp ---Type <return> to continue, or q <return> to quit---q Quit
Well, this test-file helps pretty much to see your problem. As you didn't mentioned, which options you are specifying to gcc on complilation, I assumed that you were using -fomit-frame-pointer and -O1. But well, as described later, it doesn't really matters much here. As register ebp is used by gcc as internal frame-register. Even if you are specifying -fomit-frame-pointer as option, the main function will still have a frame-pointer setup. Also ebp-register is a callee-saved register, which means its use as local-register variable is in general nothing wise to do. I compiled program with 4.6.0 gcc using mingw-w64 as runtime, and I get a crash when main-function exits. This is to be expected, as epilogue for main is movl %ebp, %esp pop %ebp ret but output looks as expected: $ ./tst.exe start foobar 10 foobar 9 foobar 8 foobar 7 foobar 6 foobar 5 foobar 4 foobar 3 foobar 2 foobar 1 foobar 0 bar So I mark this bug as invalid. If for you the code crashes by using mingw.org, well then file a report to them. This is for sure no gcc issue. Regards, Kai
Created attachment 24637 [details] generated asm with i686-pc-mingw32-gcc testsetjmp.c -S -s > I compiled program with 4.6.0 gcc using mingw-w64 as runtime, and I get a crash yes this testcase crashes at epilogue of main if gcc doesn't do anything but in latest gcc trunk, it doesn't work as expected. sorry. i forgot to say gcc version $ gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/libexec/gcc/i686-pc-cygwin/4.7.0/lto-wrapper.exe Target: i686-pc-cygwin Configured with: ./configure --config-cache --prefix=/usr --disable-win32-registry --enable-threads=win32 --enable-languages=c,c++,lto --with-win32-nlsapi=unicode --enable-tls --disable-bootstrap --enable-shared --disable-sjlj-exceptions --enable-gomp Thread model: win32 gcc version 4.7.0 20110622 (experimental) (GCC) and i attached asm code latest gcc trunk generated i used i686-pc-mingw32-gcc testsetjmp.c -S -s to generate .s file. . please ld using attached asm file. and i expect you and i get same result. D:\cygwin\tmp>i686-pc-mingw32-gcc testsetjmp.s D:\cygwin\tmp>a start foobar 10 foobar 9 foobar 8 foobar 7 foobar 6 foobar 5 foobar 4 foobar 3 foobar 2 foobar 1 foobar 0 (jit debugger message dialog shows)
and expected bar didn't show up as it sigsegvs in msvcrt!nlg_notify
> $ gcc -v i'm sorry to attach invalid gcc -v. this is proper one. $ i686-pc-mingw32-gcc -v Using built-in specs. COLLECT_GCC=i686-pc-mingw32-gcc COLLECT_LTO_WRAPPER=/usr/libexec/gcc/i686-pc-mingw32/4.7.0/lto-wrapper.exe Target: i686-pc-mingw32 Configured with: ./configure --config-cache --prefix=/usr --enable-win32-registry --enable-threads=win32 --enable-languages=c,c++,lto --with-win32-nlsapi=unicode --enable-tls --disable-bootstrap --target=i686-pc-mingw32 --enable-shared --enable-interpreter --disable-sjlj-exceptions --enable-gomp Thread model: win32 gcc version 4.7.0 20110622 (experimental) (GCC)
(In reply to comment #3) > As register ebp is used by gcc as internal frame-register. Even if you are > specifying -fomit-frame-pointer as option, the main function will still have a > frame-pointer setup. Also ebp-register is a callee-saved register, which means > its use as local-register variable is in general nothing wise to do. maybe the following could be counterexample. this code is from gcc 2011110622. ebp may be not internal frame pointer. so in this case setjmp can store invalid ebp. nlg_notify dereferences ebp,causing sigsegv not only it don't use framepointer, but also it doesn't restore framepointer LFE104: .p2align 4,,15 .globl _rb_ensure .def _rb_ensure; .scl 2; .type 32; .endef _rb_ensure: LFB105: .loc 2 727 0 is_stmt 1 .cfi_startproc LVL835: pushl %ebx LCFI228: .cfi_def_cfa_offset 8 .cfi_offset 3, -8 subl $120, %esp LCFI229: .cfi_def_cfa_offset 128 LBB566: .loc 2 731 0 movl _ruby_current_thread, %eax LBE566: .loc 2 729 0 movl $4, 32(%esp) LVL836: LBB567: .loc 2 731 0 movl $0, 100(%esp) movl %eax, %edx movl %eax, 28(%esp) LVL837: movl 152(%eax), %eax movl %eax, 108(%esp) leal 36(%esp), %eax movl %eax, 152(%edx) .loc 2 732 0 movl %eax, (%esp) call __setjmp LVL838: testl %eax, %eax movl %eax, %ebx LVL839: je L733 .loc 2 735 0 movl 108(%esp), %eax LVL840: movl 28(%esp), %edx movl %eax, 152(%edx) LBE567: .loc 2 738 0 movl 140(%esp), %eax movl %eax, (%esp) call *136(%esp) LVL841: .loc 2 740 0 movl _ruby_current_thread, %eax movl %ebx, 4(%esp) movl 152(%eax), %eax movl %eax, (%esp) call _longjmp LVL842: .p2align 4,,10 L733: LBB568: .loc 2 733 0 movl 132(%esp), %eax movl %eax, (%esp) call *128(%esp) LVL843: .loc 2 735 0 movl 28(%esp), %edx .loc 2 733 0 movl %eax, 32(%esp) .loc 2 735 0 movl 108(%esp), %eax movl %eax, 152(%edx) LBE568: .loc 2 738 0 movl 140(%esp), %eax movl %eax, (%esp) call *136(%esp) LVL844: .loc 2 741 0 movl 32(%esp), %eax .loc 2 742 0 addl $120, %esp LCFI230: .cfi_def_cfa_offset 8 popl %ebx LCFI231: .cfi_def_cfa_offset 4 .cfi_restore 3 LVL845: ret .cfi_endproc LFE105: .p2align 4,,15 .globl _rb_frame_this_func .def _rb_frame_this_func; .scl 2; .type 32; .endef _rb_frame_this_func: LFB108: .loc 2 791 0 .cfi_startproc .loc 2 792 0 movl _ruby_current_thread, %eax movl 16(%eax), %eax jmp _frame_func_id LVL846: .cfi_endproc LFE108:
Created attachment 24640 [details] preprocessed source and generated code verbose log i686-pc-mingw32-gcc -O4 -mfpmath=sse -march=native -mtune=native -mthreads -mstackrealign -g3 -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Werror=pointer-arith -Werror=write-strings -Werror=declaration-after-statement -Werror=implicit-function-declaration -include ruby/config.h -include ruby/missing.h -fvisibility=hidden -DRUBY_EXPORT -I. -I.ext/include/i386-mingw32 -I./include -I. -I/usr/include/w32api -o eval.o -c eval.c -save-temps -v Using built-in specs. COLLECT_GCC=i686-pc-mingw32-gcc COLLECT_LTO_WRAPPER=/usr/libexec/gcc/i686-pc-mingw32/4.7.0/lto-wrapper.exe Target: i686-pc-mingw32 Configured with: ./configure --config-cache --prefix=/usr --enable-win32-registry --enable-threads=win32 --enable-languages=c,c++,lto --with-win32-nlsapi=unicode --enable-tls --disable-bootstrap --target=i686-pc-mingw32 --enable-shared --enable-interpreter --disable-sjlj-exceptions --enable-gomp Thread model: win32 gcc version 4.7.0 20110622 (experimental) (GCC) COLLECT_GCC_OPTIONS='-O4' '-mfpmath=sse' '-march=native' '-mtune=native' '-mthreads' '-mstackrealign' '-g3' '-Wextra' '-Wno-unused-parameter' '-Wno-parentheses' '-Wno-long-long' '-Wno-missing-field-initializers' '-Werror=pointer-arith' '-Werror=write-strings' '-Werror=declaration-after-statement' '-Werror=implicit-function-declaration' '-include' 'ruby/config.h' '-include' 'ruby/missing.h' '-fvisibility=hidden' '-D' 'RUBY_EXPORT' '-I' '.' '-I' '.ext/include/i386-mingw32' '-I' './include' '-I' '.' '-I' '/usr/include/w32api' '-o' 'eval.o' '-c' '-save-temps' '-v' /usr/libexec/gcc/i686-pc-mingw32/4.7.0/cc1.exe -E -quiet -v -I . -I .ext/include/i386-mingw32 -I ./include -I . -I /usr/include/w32api -dD -D_MT -D RUBY_EXPORT -include ruby/config.h -include ruby/missing.h eval.c -march=core2 -mcx16 -msahf -mno-movbe -mno-aes -mno-pclmul -mno-popcnt -mno-abm -mno-lwp -mno-fma -mno-fma4 -mno-xop -mno-bmi -mno-tbm -mno-avx -mno-sse4.2 -msse4.1 --param l1-cache-size=32 --param l1-cache-line-size=64 --param l2-cache-size=2048 -mtune=core2 -mfpmath=sse -mthreads -mstackrealign -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Werror=pointer-arith -Werror=write-strings -Werror=declaration-after-statement -Werror=implicit-function-declaration -fvisibility=hidden -g3 -fworking-directory -O4 -fpch-preprocess -o eval.i ignoring nonexistent directory "/usr/lib/gcc/i686-pc-mingw32/4.7.0/../../../../i686-pc-mingw32/sys-include" ignoring duplicate directory "." #include "..." search starts here: #include <...> search starts here: . .ext/include/i386-mingw32 ./include /usr/include/w32api /usr/lib/gcc/i686-pc-mingw32/4.7.0/include /usr/lib/gcc/i686-pc-mingw32/4.7.0/include-fixed /usr/lib/gcc/i686-pc-mingw32/4.7.0/../../../../i686-pc-mingw32/include End of search list. COLLECT_GCC_OPTIONS='-O4' '-mfpmath=sse' '-march=native' '-mtune=native' '-mthreads' '-mstackrealign' '-g3' '-Wextra' '-Wno-unused-parameter' '-Wno-parentheses' '-Wno-long-long' '-Wno-missing-field-initializers' '-Werror=pointer-arith' '-Werror=write-strings' '-Werror=declaration-after-statement' '-Werror=implicit-function-declaration' '-include' 'ruby/config.h' '-include' 'ruby/missing.h' '-fvisibility=hidden' '-D' 'RUBY_EXPORT' '-I' '.' '-I' '.ext/include/i386-mingw32' '-I' './include' '-I' '.' '-I' '/usr/include/w32api' '-o' 'eval.o' '-c' '-save-temps' '-v' /usr/libexec/gcc/i686-pc-mingw32/4.7.0/cc1.exe -fpreprocessed eval.i -march=core2 -mcx16 -msahf -mno-movbe -mno-aes -mno-pclmul -mno-popcnt -mno-abm -mno-lwp -mno-fma -mno-fma4 -mno-xop -mno-bmi -mno-tbm -mno-avx -mno-sse4.2 -msse4.1 --param l1-cache-size=32 --param l1-cache-line-size=64 --param l2-cache-size=2048 -mtune=core2 -quiet -dumpbase eval.c -mfpmath=sse -mthreads -mstackrealign -auxbase-strip eval.o -g3 -O4 -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Werror=pointer-arith -Werror=write-strings -Werror=declaration-after-statement -Werror=implicit-function-declaration -version -fvisibility=hidden -o eval.s GNU C (GCC) version 4.7.0 20110622 (experimental) (i686-pc-mingw32) compiled by GNU C version 4.7.0 20110622 (experimental), GMP version 5.0.0, MPFR version 2.4.2, MPC version 0.8.1 GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096 GNU C (GCC) version 4.7.0 20110622 (experimental) (i686-pc-mingw32) compiled by GNU C version 4.7.0 20110622 (experimental), GMP version 5.0.0, MPFR version 2.4.2, MPC version 0.8.1 GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096 Compiler executable checksum: b98a9904da950a3b4c2a13878d133f7f COLLECT_GCC_OPTIONS='-O4' '-mfpmath=sse' '-march=native' '-mtune=native' '-mthreads' '-mstackrealign' '-g3' '-Wextra' '-Wno-unused-parameter' '-Wno-parentheses' '-Wno-long-long' '-Wno-missing-field-initializers' '-Werror=pointer-arith' '-Werror=write-strings' '-Werror=declaration-after-statement' '-Werror=implicit-function-declaration' '-include' 'ruby/config.h' '-include' 'ruby/missing.h' '-fvisibility=hidden' '-D' 'RUBY_EXPORT' '-I' '.' '-I' '.ext/include/i386-mingw32' '-I' './include' '-I' '.' '-I' '/usr/include/w32api' '-o' 'eval.o' '-c' '-save-temps' '-v' /usr/lib/gcc/i686-pc-mingw32/4.7.0/../../../../i686-pc-mingw32/bin/as.exe -o eval.o eval.s COMPILER_PATH=/usr/libexec/gcc/i686-pc-mingw32/4.7.0/:/usr/libexec/gcc/i686-pc-mingw32/4.7.0/:/usr/libexec/gcc/i686-pc-mingw32/:/usr/lib/gcc/i686-pc-mingw32/4.7.0/:/usr/lib/gcc/i686-pc-mingw32/:/usr/lib/gcc/i686-pc-mingw32/4.7.0/../../../../i686-pc-mingw32/bin/ LIBRARY_PATH=/usr/lib/gcc/i686-pc-mingw32/4.7.0/:/usr/lib/gcc/i686-pc-mingw32/4.7.0/../../../../i686-pc-mingw32/lib/ COLLECT_GCC_OPTIONS='-O4' '-mfpmath=sse' '-march=native' '-mtune=native' '-mthreads' '-mstackrealign' '-g3' '-Wextra' '-Wno-unused-parameter' '-Wno-parentheses' '-Wno-long-long' '-Wno-missing-field-initializers' '-Werror=pointer-arith' '-Werror=write-strings' '-Werror=declaration-after-statement' '-Werror=implicit-function-declaration' '-include' 'ruby/config.h' '-include' 'ruby/missing.h' '-fvisibility=hidden' '-D' 'RUBY_EXPORT' '-I' '.' '-I' '.ext/include/i386-mingw32' '-I' './include' '-I' '.' '-I' '/usr/include/w32api' '-o' 'eval.o' '-c' '-save-temps' '-v'
this is invalid if ebp is used as framepointer 5381 long len = RARRAY_LEN(tmp); 0x62d7ae8b <+155>: mov (%eax),%ebp 0x62d7ae8d <+157>: test $0x2000,%ebp ---Type <return> to continue, or q <return> to quit--- 0x62d7ae93 <+163>: jne 0x62d7af40 <rb_io_s_popen+336> 0x62d7ae99 <+169>: mov 0x8(%eax),%ebp 0x62d7af40 <+336>: shr $0xf,%ebp 0x62d7af43 <+339>: and $0x3,%ebp 0x62d7af46 <+342>: jmp 0x62d7ae9c <rb_io_s_popen+172> 0x62d7af4b <+347>: nop 0x62d7af4c <+348>: lea 0x0(%esi,%eiz,1),%esi ebp is used. isn't it supposed as frame pointer? additionally, long len = RARRAY_LEN(tmp); is expanded to long len = ((((struct RBasic*)(tmp))->flags & (((VALUE)1)<<(12+1))) ? \ (long)((((struct RBasic*)(tmp))->flags >> (12+3)) & \ (((((VALUE)1)<<(12+4))|(((VALUE)1)<<(12+3))) >> (12+3))) : \ ((struct RArray*)(tmp))->as.heap.len); gcc is doing wrong just like my testcase i posted. > which means its use as local-register variable is in general nothing wise to do. like you mentioned. could it be fixed? and debug session Starting program: /tmp/ruby/ruby -I./lib -I. -I.ext/common -I.ext/i386-mingw32 D:/cygwin/tmp/ruby/test/ruby/test_process.rb [New Thread 284.0x1400] [New Thread 284.0x1ac8] [New Thread 284.0x2904] <internal:gem_prelude>:1:in `require': cannot load such file -- rubygems.rb (LoadError) from <internal:gem_prelude>:1:in `<compiled>' Run options: # Running tests: .<internal:gem_prelude>:1:in `require': cannot load such file -- rubygems.rb (LoadError) from <internal:gem_prelude>:1:in `<compiled>' <internal:gem_prelude>:1:in `require': cannot load such file -- rubygems.rb (LoadError) from <internal:gem_prelude>:1:in `<compiled>' F<internal:gem_prelude>:1:in `require': cannot load such file -- rubygems.rb (LoadError) from <internal:gem_prelude>:1:in `<compiled>' F Breakpoint 5, 0x77b671c8 in setjmp () from /cygdrive/c/WINDOWS/system32/msvcrt.dll (gdb) <internal:gem_prelude>:1:in `require': cannot load such file -- rubygems.rb (LoadError) from <internal:gem_prelude>:1:in `<compiled>' (gdb) i b Num Type Disp Enb Address What 5 breakpoint keep y 0x77b671c8 <setjmp> stop only if $ebp<0x10 breakpoint already hit 1 time (gdb) i r eax 0x23eb64 0x23eb64 ecx 0x7c969f8c 0x7c969f8c edx 0x359a8 0x359a8 ebx 0x148fc20 0x148fc20 esp 0x23eb3c 0x23eb3c ebp 0x3 0x3 esi 0x148fe18 0x148fe18 edi 0x23ec1c 0x23ec1c eip 0x77b671c8 0x77b671c8 <setjmp> eflags 0x202 [ IF ] cs 0x1b 0x1b ss 0x23 0x23 ds 0x23 0x23 es 0x23 0x23 fs 0x3b 0x3b gs 0x0 0x0 (gdb) bt #0 0x77b671c8 in setjmp () from /cygdrive/c/WINDOWS/system32/msvcrt.dll #1 0x62d4b37b in rb_ensure (b_proc=0x62e6f310 <rb_yield>, data1=0x148fc20, e_proc=0x62d6aac0 <io_close>, data2=0x148fc20) at eval.c:732 #2 0x62d7af2d in rb_io_s_popen (argc=<optimized out>, argv=0xf801f8, klass=0x1039428) at io.c:5408 #3 0x62e5f3cd in call_cfunc (func=0x62d7adf0 <rb_io_s_popen>, recv=<optimized out>, len=0xffffffff, argc=0x2, argv=0xf801f8) at vm_insnhelper.c:317 #4 0x62e6e0f5 in vm_call_cfunc (me=0x1093de0, blockptr=0xfffae0, recv=0x1039428, num=0x2, reg_cfp=0xfffacc, th=0x359a8) at vm_insnhelper.c:404 #5 vm_call_method (th=0x359a8, cfp=0xfffacc, num=<optimized out>, blockptr=0xfffae0, flag=<optimized out>, id=<optimized out>, me=0x1093de0, recv=0x1039428) at vm_insnhelper.c:526 #6 0x62e6482d in vm_exec_core (th=0x359a8, initial=<optimized out>) at insns.def:1012 #7 0x62e68548 in vm_exec (th=0x359a8) at vm.c:1180 #8 0x62e69208 in invoke_block_from_c (th=0x359a8, block=<optimized out>, self=0x1493370, argc=0x1, argv=0x23ef90, blockptr=0x0, cref=0x0) at vm.c:591 #9 0x62e6f352 in vm_yield (argv=0x23ef90, argc=0x1, th=<optimized out>) at vm.c:621 #10 rb_yield_0 (argv=0x23ef90, argc=0x1) at vm_eval.c:740 ---Type <return> to continue, or q <return> to quit--- #11 rb_yield (val=0x1490100) at vm_eval.c:750 #12 0x62d4b3d1 in rb_ensure (b_proc=0x62d36d00 <chdir_yield>, data1=0x23f024, e_proc=0x62d36a50 <chdir_restore>, data2=0x23f024) at eval.c:733 #13 0x62d36f8b in dir_s_chdir (argc=0x1, argv=0xf801c8, obj=0x1037f70) at dir.c:862 #14 0x62e5f3cd in call_cfunc (func=0x62d36e60 <dir_s_chdir>, recv=<optimized out>, len=0xffffffff, argc=0x1, argv=0xf801c8) at vm_insnhelper.c:317 #15 0x62e6e0f5 in vm_call_cfunc (me=0x10a58f8, blockptr=0xfffb90, recv=0x1037f70, num=0x1, reg_cfp=0xfffb7c, th=0x359a8) at vm_insnhelper.c:404 #16 vm_call_method (th=0x359a8, cfp=0xfffb7c, num=<optimized out>, blockptr=0xfffb90, flag=<optimized out>, id=<optimized out>, me=0x10a58f8, recv=0x1037f70) at vm_insnhelper.c:526 #17 0x62e6482d in vm_exec_core (th=0x359a8, initial=<optimized out>) at insns.def:1012 #18 0x62e68548 in vm_exec (th=0x359a8) at vm.c:1180 #19 0x62e69208 in invoke_block_from_c (th=0x359a8, block=<optimized out>, self=0x1520a60, argc=0x1, argv=0x23f380, blockptr=0x0, cref=0x0) at vm.c:591 #20 0x62e6f352 in vm_yield (argv=0x23f380, argc=0x1, th=<optimized out>) at vm.c:621 #21 rb_yield_0 (argv=0x23f380, argc=0x1) at vm_eval.c:740 ---Type <return> to continue, or q <return> to quit--- #22 rb_yield (val=0x14ea628) at vm_eval.c:750 #23 0x62d0bb7c in rb_ary_collect (ary=0x14c36a0) at array.c:2220 #24 0x62e6e0f5 in vm_call_cfunc (me=0x10807b8, blockptr=0xfffd1c, recv=0x14c36a0, num=0x0, reg_cfp=0xfffd08, th=0x359a8) at vm_insnhelper.c:404 #25 vm_call_method (th=0x359a8, cfp=0xfffd08, num=<optimized out>, blockptr=0xfffd1c, flag=<optimized out>, id=<optimized out>, me=0x10807b8, recv=0x14c36a0) at vm_insnhelper.c:526 #26 0x62e6482d in vm_exec_core (th=0x359a8, initial=<optimized out>) at insns.def:1012 #27 0x62e68548 in vm_exec (th=0x359a8) at vm.c:1180 #28 0x62e69208 in invoke_block_from_c (th=0x359a8, block=<optimized out>, self=0x1520a60, argc=0x1, argv=0x23f690, blockptr=0x0, cref=0x0) at vm.c:591 #29 0x62e6f352 in vm_yield (argv=0x23f690, argc=0x1, th=<optimized out>) at vm.c:621 #30 rb_yield_0 (argv=0x23f690, argc=0x1) at vm_eval.c:740 #31 rb_yield (val=0x1521138) at vm_eval.c:750 #32 0x62d060cc in rb_ary_each (array=0x1509498) at array.c:1478 #33 0x62e6e0f5 in vm_call_cfunc (me=0x107fa90, blockptr=0xfffdcc, recv=0x1509498, num=0x0, reg_cfp=0xfffdb8, th=0x359a8) at vm_insnhelper.c:404 #34 vm_call_method (th=0x359a8, cfp=0xfffdb8, num=<optimized out>, ---Type <return> to continue, or q <return> to quit--- blockptr=0xfffdcc, flag=<optimized out>, id=<optimized out>, me=0x107fa90, recv=0x1509498) at vm_insnhelper.c:526 #35 0x62e6482d in vm_exec_core (th=0x359a8, initial=<optimized out>) at insns.def:1012 #36 0x62e68548 in vm_exec (th=0x359a8) at vm.c:1180 #37 0x62e69208 in invoke_block_from_c (th=0x359a8, block=<optimized out>, self=0x1520a60, argc=0x1, argv=0x23f9a0, blockptr=0x0, cref=0x0) at vm.c:591 #38 0x62e6f352 in vm_yield (argv=0x23f9a0, argc=0x1, th=<optimized out>) at vm.c:621 #39 rb_yield_0 (argv=0x23f9a0, argc=0x1) at vm_eval.c:740 #40 rb_yield (val=0x1509720) at vm_eval.c:750 #41 0x62d060cc in rb_ary_each (array=0x1509528) at array.c:1478 #42 0x62e6e0f5 in vm_call_cfunc (me=0x107fa90, blockptr=0xfffed4, recv=0x1509528, num=0x0, reg_cfp=0xfffec0, th=0x359a8) at vm_insnhelper.c:404 #43 vm_call_method (th=0x359a8, cfp=0xfffec0, num=<optimized out>, blockptr=0xfffed4, flag=<optimized out>, id=<optimized out>, me=0x107fa90, recv=0x1509528) at vm_insnhelper.c:526 #44 0x62e6482d in vm_exec_core (th=0x359a8, initial=<optimized out>) at insns.def:1012 #45 0x62e68548 in vm_exec (th=0x359a8) at vm.c:1180 #46 0x62e69208 in invoke_block_from_c (th=0x359a8, block=<optimized out>, ---Type <return> to continue, or q <return> to quit--- self=0x1458de0, argc=0x0, argv=0x1520af8, blockptr=0x0, cref=0x0) at vm.c:591 #47 0x62e6937d in rb_vm_invoke_proc (th=0x359a8, proc=0x1600848, self=0x1458de0, argc=0x0, argv=0x1520af8, blockptr=0x0) at vm.c:637 #48 0x62d50338 in rb_proc_call (self=0x1458888, args=0x1520af0) at proc.c:580 #49 0x62d48758 in rb_call_end_proc (data=0x1458888) at eval_jump.c:13 #50 0x62d4a55a in rb_exec_end_proc () at eval_jump.c:126 #51 0x62d4a5de in ruby_finalize_0 () at eval.c:92 #52 0x62d4a8cd in ruby_cleanup (ex=0x0) at eval.c:133 #53 0x62d4ac61 in ruby_run_node (n=0x102ca20) at eval.c:241 #54 0x00401e7f in main (argc=0x6, argv=0x357b0) at main.c:38 #55 0x004010fd in __mingw_CRTStartup () at ../../.././winsup/mingw/crt1.c:244 #56 0x00000408 in ?? () #57 0x7ffd9000 in ?? () #58 0x00000000 in ?? () (gdb) up #1 0x62d4b37b in rb_ensure (b_proc=0x62e6f310 <rb_yield>, data1=0x148fc20, e_proc=0x62d6aac0 <io_close>, data2=0x148fc20) at eval.c:732 732 if ((state = EXEC_TAG()) == 0) { (gdb) #2 0x62d7af2d in rb_io_s_popen (argc=<optimized out>, argv=0xf801f8, klass=0x1039428) at io.c:5408 5408 return rb_ensure(rb_yield, port, io_close, port); (gdb) disass Dump of assembler code for function rb_io_s_popen: 0x62d7adf0 <+0>: push %ebp 0x62d7adf1 <+1>: push %edi 0x62d7adf2 <+2>: push %esi 0x62d7adf3 <+3>: push %ebx 0x62d7adf4 <+4>: sub $0x7c,%esp 0x62d7adf7 <+7>: lea 0x40(%esp),%eax 0x62d7adfb <+11>: movl $0x62ea0c34,0x8(%esp) 0x62d7ae03 <+19>: mov %eax,0x14(%esp) 0x62d7ae07 <+23>: mov 0x94(%esp),%eax 0x62d7ae0e <+30>: lea 0x3c(%esp),%edi 0x62d7ae12 <+34>: lea 0x38(%esp),%esi 0x62d7ae16 <+38>: mov %edi,0x10(%esp) 0x62d7ae1a <+42>: mov %esi,0xc(%esp) 0x62d7ae1e <+46>: lea 0x4c(%esp),%ebx 0x62d7ae22 <+50>: mov %eax,0x4(%esp) 0x62d7ae26 <+54>: mov 0x90(%esp),%eax 0x62d7ae2d <+61>: mov %eax,(%esp) 0x62d7ae30 <+64>: call 0x62d29510 <rb_scan_args> 0x62d7ae35 <+69>: mov 0x40(%esp),%ecx 0x62d7ae39 <+73>: lea 0x48(%esp),%eax 0x62d7ae3d <+77>: mov %eax,0x4(%esp) 0x62d7ae41 <+81>: lea 0x44(%esp),%eax ---Type <return> to continue, or q <return> to quit---q Quit (gdb) disass /m Dump of assembler code for function rb_io_s_popen: 4214 int accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR); 0x62d7ae59 <+105>: mov %eax,%edx 0x62d7ae5b <+107>: and $0x3,%edx 4215 if (oflags & O_APPEND) { 0x62d7ae5e <+110>: test $0x8,%al 0x62d7ae60 <+112>: je 0x62d7ae6c <rb_io_s_popen+124> 4216 if (accmode == O_WRONLY) { 0x62d7ae62 <+114>: cmp $0x1,%edx 0x62d7ae65 <+117>: je 0x62d7ae76 <rb_io_s_popen+134> 4217 return MODE_BINARY("a", "ab"); 4218 } 4219 if (accmode == O_RDWR) { 0x62d7ae67 <+119>: cmp $0x2,%edx 0x62d7ae6a <+122>: je 0x62d7ae76 <rb_io_s_popen+134> 4220 return MODE_BINARY("a+", "ab+"); 4221 } 4222 } 4223 switch (oflags & (O_RDONLY|O_WRONLY|O_RDWR)) { ---Type <return> to continue, or q <return> to quit--- 0x62d7ae6c <+124>: cmp $0x2,%edx 0x62d7ae6f <+127>: nop 0x62d7ae70 <+128>: ja 0x62d7af90 <rb_io_s_popen+416> 4224 case O_RDONLY: 4225 return MODE_BINARY("r", "rb"); 4226 case O_WRONLY: 4227 return MODE_BINARY("w", "wb"); 4228 case O_RDWR: 4229 return MODE_BINARY("r+", "rb+"); 4230 } 4231 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags); 0x62d7af90 <+416>: mov %eax,0x8(%esp) 0x62d7af94 <+420>: mov 0x62f3e7b0,%eax 0x62d7af99 <+425>: movl $0x62ea0a14,0x4(%esp) 0x62d7afa1 <+433>: mov %eax,(%esp) 0x62d7afa4 <+436>: call 0x62d44410 <rb_raise> 0x62d7afa9 <+441>: lea 0x0(%esi,%eiz,1),%esi 4232 return NULL; /* not reached */ 4233 } 4234 4235 /* ---Type <return> to continue, or q <return> to quit--- 4236 * Convert external/internal encodings to enc/enc2 4237 * NULL => use default encoding 4238 * Qnil => no encoding specified (internal only) 4239 */ 4240 static void 4241 rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2) 4242 { 4243 int default_ext = 0; 4244 4245 if (ext == NULL) { 4246 ext = rb_default_external_encoding(); 4247 default_ext = 1; 4248 } 4249 if (intern == NULL && ext != rb_ascii8bit_encoding()) 4250 /* If external is ASCII-8BIT, no default transcoding */ 4251 intern = rb_default_internal_encoding(); 4252 if (intern == NULL || intern == (rb_encoding *)Qnil || intern == ext) { 4253 /* No internal encoding => use external + no transcoding */ 4254 *enc = (default_ext && intern != ext) ? NULL : ext; 4255 *enc2 = NULL; 4256 } ---Type <return> to continue, or q <return> to quit--- 4257 else { 4258 *enc = intern; 4259 *enc2 = ext; 4260 } 4261 } 4262 4263 static void 4264 parse_mode_enc(const char *estr, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p) 4265 { 4266 const char *p; 4267 char encname[ENCODING_MAXNAMELEN+1]; 4268 int idx, idx2; 4269 rb_encoding *ext_enc, *int_enc; 4270 4271 /* parse estr as "enc" or "enc2:enc" or "enc:-" */ 4272 4273 p = strrchr(estr, ':'); 4274 if (p) { 4275 long len = (p++) - estr; 4276 if (len == 0 || len > ENCODING_MAXNAMELEN) 4277 idx = -1; 4278 else { ---Type <return> to continue, or q <return> to quit--- 4279 if (io_encname_bom_p(estr, len)) { 4280 if (fmode_p) *fmode_p |= FMODE_SETENC_BY_BOM; 4281 estr += 4; 4282 len -= 4; 4283 } 4284 memcpy(encname, estr, len); 4285 encname[len] = '\0'; 4286 estr = encname; 4287 idx = rb_enc_find_index(encname); 4288 } 4289 } 4290 else { 4291 long len = strlen(estr); 4292 if (io_encname_bom_p(estr, len)) { 4293 if (fmode_p) *fmode_p |= FMODE_SETENC_BY_BOM; 4294 estr += 4; 4295 len -= 4; 4296 memcpy(encname, estr, len); 4297 encname[len] = '\0'; 4298 estr = encname; 4299 } 4300 idx = rb_enc_find_index(estr); 4301 } ---Type <return> to continue, or q <return> to quit--- 4302 4303 if (idx >= 0) 4304 ext_enc = rb_enc_from_index(idx); 4305 else { 4306 if (idx != -2) 4307 rb_warn("Unsupported encoding %s ignored", estr); 4308 ext_enc = NULL; 4309 } 4310 4311 int_enc = NULL; 4312 if (p) { 4313 if (*p == '-' && *(p+1) == '\0') { 4314 /* Special case - "-" => no transcoding */ 4315 int_enc = (rb_encoding *)Qnil; 4316 } 4317 else { 4318 idx2 = rb_enc_find_index(p); 4319 if (idx2 < 0) 4320 rb_warn("Unsupported encoding %s ignored", p); 4321 else if (idx2 == idx) { 4322 rb_warn("Ignoring internal encoding %s: it is identical to external encoding %s", p, estr); 4323 int_enc = (rb_encoding *)Qnil; ---Type <return> to continue, or q <return> to quit--- 4324 } 4325 else 4326 int_enc = rb_enc_from_index(idx2); 4327 } 4328 } 4329 4330 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p); 4331 } 4332 4333 static void 4334 mode_enc(rb_io_t *fptr, const char *estr) 4335 { 4336 clear_codeconv(fptr); 4337 4338 parse_mode_enc(estr, &fptr->encs.enc, &fptr->encs.enc2, NULL); 4339 } 4340 4341 static void 4342 rb_io_mode_enc(rb_io_t *fptr, const char *modestr) 4343 { 4344 const char *p = strchr(modestr, ':'); 4345 if (p) { 4346 mode_enc(fptr, p+1); ---Type <return> to continue, or q <return> to quit--- 4347 } 4348 } 4349 4350 int 4351 rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p) 4352 { 4353 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp; 4354 int extracted = 0; 4355 rb_encoding *extencoding = NULL; 4356 rb_encoding *intencoding = NULL; 4357 4358 if (!NIL_P(opt)) { 4359 VALUE v; 4360 v = rb_hash_lookup2(opt, sym_encoding, Qnil); 4361 if (v != Qnil) encoding = v; 4362 v = rb_hash_lookup2(opt, sym_extenc, Qundef); 4363 if (v != Qnil) extenc = v; 4364 v = rb_hash_lookup2(opt, sym_intenc, Qundef); 4365 if (v != Qundef) intenc = v; 4366 } 4367 if ((extenc != Qundef || intenc != Qundef) && !NIL_P(encoding)) { 4368 if (!NIL_P(ruby_verbose)) { ---Type <return> to continue, or q <return> to quit--- 4369 int idx = rb_to_encoding_index(encoding); 4370 rb_warn("Ignoring encoding parameter '%s': %s_encoding is used", 4371 idx < 0 ? StringValueCStr(encoding) : rb_enc_name(rb_enc_from_index(idx)), 4372 extenc == Qundef ? "internal" : "external"); 4373 } 4374 encoding = Qnil; 4375 } 4376 if (extenc != Qundef && !NIL_P(extenc)) { 4377 extencoding = rb_to_encoding(extenc); 4378 } 4379 if (intenc != Qundef) { 4380 if (NIL_P(intenc)) { 4381 /* internal_encoding: nil => no transcoding */ 4382 intencoding = (rb_encoding *)Qnil; 4383 } 4384 else if (!NIL_P(tmp = rb_check_string_type(intenc))) { 4385 char *p = StringValueCStr(tmp); 4386 4387 if (*p == '-' && *(p+1) == '\0') { 4388 /* Special case - "-" => no transcoding */ 4389 intencoding = (rb_encoding *)Qnil; ---Type <return> to continue, or q <return> to quit--- 4390 } 4391 else { 4392 intencoding = rb_to_encoding(intenc); 4393 } 4394 } 4395 else { 4396 intencoding = rb_to_encoding(intenc); 4397 } 4398 if (extencoding == intencoding) { 4399 intencoding = (rb_encoding *)Qnil; 4400 } 4401 } 4402 if (!NIL_P(encoding)) { 4403 extracted = 1; 4404 if (!NIL_P(tmp = rb_check_string_type(encoding))) { 4405 parse_mode_enc(StringValueCStr(tmp), enc_p, enc2_p, fmode_p); 4406 } 4407 else { 4408 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p); 4409 } 4410 } ---Type <return> to continue, or q <return> to quit--- 4411 else if (extenc != Qundef || intenc != Qundef) { 4412 extracted = 1; 4413 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p); 4414 } 4415 return extracted; 4416 } 4417 4418 typedef struct rb_io_enc_t convconfig_t; 4419 4420 static void 4421 validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2) 4422 { 4423 int fmode = *fmode_p; 4424 4425 if ((fmode & FMODE_READABLE) && 4426 !enc2 && 4427 !(fmode & FMODE_BINMODE) && 4428 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding())) 4429 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode"); 4430 ---Type <return> to continue, or q <return> to quit--- 4431 if (!(fmode & FMODE_BINMODE) && 4432 (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) { 4433 fmode |= DEFAULT_TEXTMODE; 4434 *fmode_p = fmode; 4435 } 4436 #if !DEFAULT_TEXTMODE 4437 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) { 4438 fmode &= ~FMODE_TEXTMODE; 4439 *fmode_p = fmode; 4440 } 4441 #endif 4442 } 4443 4444 static void 4445 extract_binmode(VALUE opthash, int *fmode) 4446 { 4447 if (!NIL_P(opthash)) { 4448 VALUE v; 4449 v = rb_hash_aref(opthash, sym_textmode); 4450 if (!NIL_P(v) && RTEST(v)) 4451 *fmode |= FMODE_TEXTMODE; 4452 v = rb_hash_aref(opthash, sym_binmode); 4453 if (!NIL_P(v) && RTEST(v)) ---Type <return> to continue, or q <return> to quit--- 4454 *fmode |= FMODE_BINMODE; 4455 4456 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE)) 4457 rb_raise(rb_eArgError, "both textmode and binmode specified"); 4458 } 4459 } 4460 4461 static void 4462 rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, 4463 int *oflags_p, int *fmode_p, convconfig_t *convconfig_p) 4464 { 4465 VALUE vmode; 4466 int oflags, fmode; 4467 rb_encoding *enc, *enc2; 4468 int ecflags; 4469 VALUE ecopts; 4470 int has_enc = 0, has_vmode = 0; 4471 VALUE intmode; 4472 4473 vmode = *vmode_p; 4474 4475 /* Set to defaults */ ---Type <return> to continue, or q <return> to quit--- 4476 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2); 4477 4478 vmode_handle: 4479 if (NIL_P(vmode)) { 4480 fmode = FMODE_READABLE | DEFAULT_TEXTMODE; 4481 oflags = O_RDONLY; 4482 } 4483 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) { 4484 vmode = intmode; 4485 oflags = NUM2INT(intmode); 4486 fmode = rb_io_oflags_fmode(oflags); 4487 } 4488 else { 4489 const char *p; 4490 4491 SafeStringValue(vmode); 4492 p = StringValueCStr(vmode); 4493 fmode = rb_io_modestr_fmode(p); 4494 oflags = rb_io_fmode_oflags(fmode); 4495 p = strchr(p, ':'); 4496 if (p) { 4497 has_enc = 1; 4498 parse_mode_enc(p+1, &enc, &enc2, &fmode); ---Type <return> to continue, or q <return> to quit--- 4499 } 4500 else { 4501 rb_encoding *e; 4502 4503 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL; 4504 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2); 4505 } 4506 } 4507 4508 if (NIL_P(opthash)) { 4509 ecflags = (fmode & FMODE_READABLE) ? 4510 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR, 4511 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0; 4512 ecopts = Qnil; 4513 } 4514 else { 4515 VALUE v; 4516 extract_binmode(opthash, &fmode); 4517 #ifdef O_BINARY 4518 if (fmode & FMODE_BINMODE) 4519 oflags |= O_BINARY; 4520 #endif ---Type <return> to continue, or q <return> to quit--- 4521 if (!has_vmode) { 4522 v = rb_hash_aref(opthash, sym_mode); 4523 if (!NIL_P(v)) { 4524 if (!NIL_P(vmode)) { 4525 rb_raise(rb_eArgError, "mode specified twice"); 4526 } 4527 has_vmode = 1; 4528 vmode = v; 4529 goto vmode_handle; 4530 } 4531 } 4532 v = rb_hash_aref(opthash, sym_perm); 4533 if (!NIL_P(v)) { 4534 if (vperm_p) { 4535 if (!NIL_P(*vperm_p)) { 4536 rb_raise(rb_eArgError, "perm specified twice"); 4537 } 4538 *vperm_p = v; 4539 } 4540 else { 4541 /* perm no use, just ignore */ 4542 } 4543 } ---Type <return> to continue, or q <return> to quit--- 4544 ecflags = (fmode & FMODE_READABLE) ? 4545 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR, 4546 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0; 4547 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags); 4548 4549 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) { 4550 if (has_enc) { 4551 rb_raise(rb_eArgError, "encoding specified twice"); 4552 } 4553 } 4554 } 4555 4556 validate_enc_binmode(&fmode, ecflags, enc, enc2); 4557 4558 *vmode_p = vmode; 4559 4560 *oflags_p = oflags; 4561 *fmode_p = fmode; 4562 convconfig_p->enc = enc; 4563 convconfig_p->enc2 = enc2; 4564 convconfig_p->ecflags = ecflags; 4565 convconfig_p->ecopts = ecopts; ---Type <return> to continue, or q <return> to quit--- 4566 } 4567 4568 struct sysopen_struct { 4569 VALUE fname; 4570 int oflags; 4571 mode_t perm; 4572 }; 4573 4574 static VALUE 4575 sysopen_func(void *ptr) 4576 { 4577 const struct sysopen_struct *data = ptr; 4578 const char *fname = RSTRING_PTR(data->fname); 4579 return (VALUE)open(fname, data->oflags, data->perm); 4580 } 4581 4582 static inline int 4583 rb_sysopen_internal(struct sysopen_struct *data) 4584 { 4585 return (int)rb_thread_blocking_region(sysopen_func, data, RUBY_UBF_IO, 0); 4586 } 4587 ---Type <return> to continue, or q <return> to quit--- 4588 static int 4589 rb_sysopen(VALUE fname, int oflags, mode_t perm) 4590 { 4591 int fd; 4592 struct sysopen_struct data; 4593 4594 #ifdef O_BINARY 4595 oflags |= O_BINARY; 4596 #endif 4597 data.fname = rb_str_encode_ospath(fname); 4598 data.oflags = oflags; 4599 data.perm = perm; 4600 4601 fd = rb_sysopen_internal(&data); 4602 if (fd < 0) { 4603 if (errno == EMFILE || errno == ENFILE) { 4604 rb_gc(); 4605 fd = rb_sysopen_internal(&data); 4606 } 4607 if (fd < 0) { 4608 rb_sys_fail(RSTRING_PTR(fname)); 4609 } 4610 } ---Type <return> to continue, or q <return> to quit--- 4611 UPDATE_MAXFD(fd); 4612 return fd; 4613 } 4614 4615 FILE * 4616 rb_fdopen(int fd, const char *modestr) 4617 { 4618 FILE *file; 4619 4620 #if defined(sun) 4621 errno = 0; 4622 #endif 4623 file = fdopen(fd, modestr); 4624 if (!file) { 4625 if ( 4626 #if defined(sun) 4627 errno == 0 || 4628 #endif 4629 errno == EMFILE || errno == ENFILE) { 4630 rb_gc(); 4631 #if defined(sun) 4632 errno = 0; 4633 #endif ---Type <return> to continue, or q <return> to quit--- 4634 file = fdopen(fd, modestr); 4635 } 4636 if (!file) { 4637 #ifdef _WIN32 4638 if (errno == 0) errno = EINVAL; 4639 #elif defined(sun) 4640 if (errno == 0) errno = EMFILE; 4641 #endif 4642 rb_sys_fail(0); 4643 } 4644 } 4645 4646 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */ 4647 #ifdef USE_SETVBUF 4648 if (setvbuf(file, NULL, _IOFBF, 0) != 0) 4649 rb_warn("setvbuf() can't be honoured (fd=%d)", fd); 4650 #endif 4651 return file; 4652 } 4653 4654 static void 4655 io_check_tty(rb_io_t *fptr) 4656 { ---Type <return> to continue, or q <return> to quit--- 4657 if (isatty(fptr->fd)) 4658 fptr->mode |= FMODE_TTY|FMODE_DUPLEX; 4659 } 4660 4661 static VALUE rb_io_internal_encoding(VALUE); 4662 static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE); 4663 4664 static int 4665 io_strip_bom(VALUE io) 4666 { 4667 int b1, b2, b3, b4; 4668 switch (b1 = FIX2INT(rb_io_getbyte(io))) { 4669 case 0xEF: 4670 b2 = FIX2INT(rb_io_getbyte(io)); 4671 if (b2 == 0xBB) { 4672 b3 = FIX2INT(rb_io_getbyte(io)); 4673 if (b3 == 0xBF) { 4674 return rb_utf8_encindex(); 4675 } 4676 rb_io_ungetbyte(io, INT2FIX(b3)); 4677 } 4678 rb_io_ungetbyte(io, INT2FIX(b2)); 4679 break; ---Type <return> to continue, or q <return> to quit--- 4680 4681 case 0xFE: 4682 b2 = FIX2INT(rb_io_getbyte(io)); 4683 if (b2 == 0xFF) { 4684 return rb_enc_find_index("UTF-16BE"); 4685 } 4686 rb_io_ungetbyte(io, INT2FIX(b2)); 4687 break; 4688 4689 case 0xFF: 4690 b2 = FIX2INT(rb_io_getbyte(io)); 4691 if (b2 == 0xFE) { 4692 b3 = FIX2INT(rb_io_getbyte(io)); 4693 if (b3 == 0) { 4694 b4 = FIX2INT(rb_io_getbyte(io)); 4695 if (b4 == 0) { 4696 return rb_enc_find_index("UTF-32LE"); 4697 } 4698 rb_io_ungetbyte(io, INT2FIX(b4)); 4699 } 4700 else { 4701 rb_io_ungetbyte(io, INT2FIX(b3)); 4702 return rb_enc_find_index("UTF-16LE"); ---Type <return> to continue, or q <return> to quit--- 4703 } 4704 rb_io_ungetbyte(io, INT2FIX(b3)); 4705 } 4706 rb_io_ungetbyte(io, INT2FIX(b2)); 4707 break; 4708 4709 case 0: 4710 b2 = FIX2INT(rb_io_getbyte(io)); 4711 if (b2 == 0) { 4712 b3 = FIX2INT(rb_io_getbyte(io)); 4713 if (b3 == 0xFE) { 4714 b4 = FIX2INT(rb_io_getbyte(io)); 4715 if (b4 == 0xFF) { 4716 return rb_enc_find_index("UTF-32BE"); 4717 } 4718 rb_io_ungetbyte(io, INT2FIX(b4)); 4719 } 4720 rb_io_ungetbyte(io, INT2FIX(b3)); 4721 } 4722 rb_io_ungetbyte(io, INT2FIX(b2)); 4723 break; 4724 } 4725 rb_io_ungetbyte(io, INT2FIX(b1)); ---Type <return> to continue, or q <return> to quit--- 4726 return 0; 4727 } 4728 4729 static void 4730 io_set_encoding_by_bom(VALUE io) 4731 { 4732 int idx = io_strip_bom(io); 4733 4734 if (idx) { 4735 rb_io_t *fptr; 4736 GetOpenFile(io, fptr); 4737 io_encoding_set(fptr, rb_enc_from_encoding(rb_enc_from_index(idx)), 4738 rb_io_internal_encoding(io), Qnil); 4739 } 4740 } 4741 4742 static VALUE 4743 rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode, convconfig_t *convconfig, mode_t perm) 4744 { 4745 rb_io_t *fptr; 4746 convconfig_t cc; ---Type <return> to continue, or q <return> to quit--- 4747 if (!convconfig) { 4748 /* Set to default encodings */ 4749 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2); 4750 cc.ecflags = 0; 4751 cc.ecopts = Qnil; 4752 convconfig = &cc; 4753 } 4754 validate_enc_binmode(&fmode, convconfig->ecflags, 4755 convconfig->enc, convconfig->enc2); 4756 4757 MakeOpenFile(io, fptr); 4758 fptr->mode = fmode; 4759 fptr->encs = *convconfig; 4760 fptr->pathv = rb_str_new_frozen(filename); 4761 fptr->fd = rb_sysopen(fptr->pathv, oflags, perm); 4762 io_check_tty(fptr); 4763 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io); 4764 4765 return io; 4766 } 4767 4768 static VALUE 4769 rb_file_open_internal(VALUE io, VALUE filename, const char *modestr) ---Type <return> to continue, or q <return> to quit--- 4770 { 4771 int fmode = rb_io_modestr_fmode(modestr); 4772 const char *p = strchr(modestr, ':'); 4773 convconfig_t convconfig; 4774 4775 if (p) { 4776 parse_mode_enc(p+1, &convconfig.enc, &convconfig.enc2, &fmode); 4777 } 4778 else { 4779 rb_encoding *e; 4780 /* Set to default encodings */ 4781 4782 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL; 4783 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2); 4784 convconfig.ecflags = 0; 4785 convconfig.ecopts = Qnil; 4786 } 4787 4788 return rb_file_open_generic(io, filename, 4789 rb_io_fmode_oflags(fmode), 4790 fmode, 4791 &convconfig, ---Type <return> to continue, or q <return> to quit--- 4792 0666); 4793 } 4794 4795 VALUE 4796 rb_file_open_str(VALUE fname, const char *modestr) 4797 { 4798 FilePathValue(fname); 4799 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr); 4800 } 4801 4802 VALUE 4803 rb_file_open(const char *fname, const char *modestr) 4804 { 4805 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr); 4806 } 4807 4808 #if defined(__CYGWIN__) || !defined(HAVE_FORK) 4809 static struct pipe_list { 4810 rb_io_t *fptr; 4811 struct pipe_list *next; 4812 } *pipe_list; 4813 ---Type <return> to continue, or q <return> to quit--- 4814 static void 4815 pipe_add_fptr(rb_io_t *fptr) 4816 { 4817 struct pipe_list *list; 4818 4819 list = ALLOC(struct pipe_list); 4820 list->fptr = fptr; 4821 list->next = pipe_list; 4822 pipe_list = list; 4823 } 4824 4825 static void 4826 pipe_del_fptr(rb_io_t *fptr) 4827 { 4828 struct pipe_list *list = pipe_list; 4829 struct pipe_list *tmp; 4830 4831 if (list->fptr == fptr) { 4832 pipe_list = list->next; 4833 free(list); 4834 return; 4835 } 4836 ---Type <return> to continue, or q <return> to quit--- 4837 while (list->next) { 4838 if (list->next->fptr == fptr) { 4839 tmp = list->next; 4840 list->next = list->next->next; 4841 free(tmp); 4842 return; 4843 } 4844 list = list->next; 4845 } 4846 } 4847 4848 static void 4849 pipe_atexit(void) 4850 { 4851 struct pipe_list *list = pipe_list; 4852 struct pipe_list *tmp; 4853 4854 while (list) { 4855 tmp = list->next; 4856 rb_io_fptr_finalize(list->fptr); 4857 list = tmp; 4858 } 4859 } ---Type <return> to continue, or q <return> to quit--- 4860 4861 static void 4862 pipe_finalize(rb_io_t *fptr, int noraise) 4863 { 4864 #if !defined(HAVE_FORK) && !defined(_WIN32) 4865 int status = 0; 4866 if (fptr->stdio_file) { 4867 status = pclose(fptr->stdio_file); 4868 } 4869 fptr->fd = -1; 4870 fptr->stdio_file = 0; 4871 rb_last_status_set(status, fptr->pid); 4872 #else 4873 fptr_finalize(fptr, noraise); 4874 #endif 4875 pipe_del_fptr(fptr); 4876 } 4877 #endif 4878 4879 void 4880 rb_io_synchronized(rb_io_t *fptr) 4881 { 4882 rb_io_check_initialized(fptr); ---Type <return> to continue, or q <return> to quit--- 4883 fptr->mode |= FMODE_SYNC; 4884 } 4885 4886 void 4887 rb_io_unbuffered(rb_io_t *fptr) 4888 { 4889 rb_io_synchronized(fptr); 4890 } 4891 4892 int 4893 rb_pipe(int *pipes) 4894 { 4895 int ret; 4896 ret = pipe(pipes); 4897 if (ret == -1) { 4898 if (errno == EMFILE || errno == ENFILE) { 4899 rb_gc(); 4900 ret = pipe(pipes); 4901 } 4902 } 4903 if (ret == 0) { 4904 UPDATE_MAXFD(pipes[0]); 4905 UPDATE_MAXFD(pipes[1]); ---Type <return> to continue, or q <return> to quit--- 4906 } 4907 return ret; 4908 } 4909 4910 #ifdef HAVE_FORK 4911 struct popen_arg { 4912 struct rb_exec_arg *execp; 4913 int modef; 4914 int pair[2]; 4915 int write_pair[2]; 4916 }; 4917 4918 static void 4919 popen_redirect(struct popen_arg *p) 4920 { 4921 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) { 4922 close(p->write_pair[1]); 4923 if (p->write_pair[0] != 0) { 4924 dup2(p->write_pair[0], 0); 4925 close(p->write_pair[0]); 4926 } 4927 close(p->pair[0]); 4928 if (p->pair[1] != 1) { ---Type <return> to continue, or q <return> to quit--- 4929 dup2(p->pair[1], 1); 4930 close(p->pair[1]); 4931 } 4932 } 4933 else if (p->modef & FMODE_READABLE) { 4934 close(p->pair[0]); 4935 if (p->pair[1] != 1) { 4936 dup2(p->pair[1], 1); 4937 close(p->pair[1]); 4938 } 4939 } 4940 else { 4941 close(p->pair[1]); 4942 if (p->pair[0] != 0) { 4943 dup2(p->pair[0], 0); 4944 close(p->pair[0]); 4945 } 4946 } 4947 } 4948 4949 void 4950 rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds) 4951 { ---Type <return> to continue, or q <return> to quit--- 4952 int fd, ret; 4953 int max = max_file_descriptor; 4954 if (max < maxhint) 4955 max = maxhint; 4956 for (fd = lowfd; fd <= max; fd++) { 4957 if (!NIL_P(noclose_fds) && 4958 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) 4959 continue; 4960 #ifdef FD_CLOEXEC 4961 ret = fcntl(fd, F_GETFD); 4962 if (ret != -1 && !(ret & FD_CLOEXEC)) { 4963 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); 4964 } 4965 #else 4966 ret = close(fd); 4967 #endif 4968 #define CONTIGUOUS_CLOSED_FDS 20 4969 if (ret != -1) { 4970 if (max < fd + CONTIGUOUS_CLOSED_FDS) 4971 max = fd + CONTIGUOUS_CLOSED_FDS; 4972 } 4973 } 4974 } ---Type <return> to continue, or q <return> to quit--- 4975 4976 static int 4977 popen_exec(void *pp, char *errmsg, size_t errmsg_len) 4978 { 4979 struct popen_arg *p = (struct popen_arg*)pp; 4980 4981 rb_thread_atfork_before_exec(); 4982 return rb_exec_err(p->execp, errmsg, errmsg_len); 4983 } 4984 #endif 4985 4986 static VALUE 4987 pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *modestr, int fmode, convconfig_t *convconfig) 4988 { 4989 rb_pid_t pid = 0; 4990 rb_io_t *fptr; 4991 VALUE port; 4992 rb_io_t *write_fptr; 4993 VALUE write_port; 4994 #if defined(HAVE_FORK) 4995 int status; 4996 struct popen_arg arg; ---Type <return> to continue, or q <return> to quit--- 4997 char errmsg[80] = { '\0' }; 4998 #elif defined(_WIN32) 4999 volatile VALUE argbuf; 5000 char **args = NULL; 5001 int pair[2], write_pair[2]; 5002 #endif 5003 #if !defined(HAVE_FORK) 5004 struct rb_exec_arg sarg; 5005 #endif 5006 FILE *fp = 0; 5007 int fd = -1; 5008 int write_fd = -1; 5009 const char *cmd = 0; 5010 int argc; 5011 VALUE *argv; 5012 5013 if (prog) 5014 cmd = StringValueCStr(prog); 5015 5016 if (!eargp) { 5017 /* fork : IO.popen("-") */ 5018 argc = 0; 5019 argv = 0; ---Type <return> to continue, or q <return> to quit--- 5020 } 5021 else if (eargp->argc) { 5022 /* no shell : IO.popen([prog, arg0], arg1, ...) */ 5023 argc = eargp->argc; 5024 argv = eargp->argv; 5025 } 5026 else { 5027 /* with shell : IO.popen(prog) */ 5028 argc = 0; 5029 argv = 0; 5030 } 5031 5032 #if defined(HAVE_FORK) 5033 arg.execp = eargp; 5034 arg.modef = fmode; 5035 arg.pair[0] = arg.pair[1] = -1; 5036 arg.write_pair[0] = arg.write_pair[1] = -1; 5037 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) { 5038 case FMODE_READABLE|FMODE_WRITABLE: 5039 if (rb_pipe(arg.write_pair) < 0) 5040 rb_sys_fail(cmd); 5041 if (rb_pipe(arg.pair) < 0) { 5042 int e = errno; ---Type <return> to continue, or q <return> to quit--- 5043 close(arg.write_pair[0]); 5044 close(arg.write_pair[1]); 5045 errno = e; 5046 rb_sys_fail(cmd); 5047 } 5048 if (eargp) { 5049 rb_exec_arg_addopt(eargp, INT2FIX(0), INT2FIX(arg.write_pair[0])); 5050 rb_exec_arg_addopt(eargp, INT2FIX(1), INT2FIX(arg.pair[1])); 5051 } 5052 break; 5053 case FMODE_READABLE: 5054 if (rb_pipe(arg.pair) < 0) 5055 rb_sys_fail(cmd); 5056 if (eargp) 5057 rb_exec_arg_addopt(eargp, INT2FIX(1), INT2FIX(arg.pair[1])); 5058 break; 5059 case FMODE_WRITABLE: 5060 if (rb_pipe(arg.pair) < 0) 5061 rb_sys_fail(cmd); 5062 if (eargp) ---Type <return> to continue, or q <return> to quit--- 5063 rb_exec_arg_addopt(eargp, INT2FIX(0), INT2FIX(arg.pair[0])); 5064 break; 5065 default: 5066 rb_sys_fail(cmd); 5067 } 5068 if (eargp) { 5069 rb_exec_arg_fixup(arg.execp); 5070 pid = rb_fork_err(&status, popen_exec, &arg, arg.execp->redirect_fds, errmsg, sizeof(errmsg)); 5071 } 5072 else { 5073 fflush(stdin); /* is it really needed? */ 5074 pid = rb_fork(&status, 0, 0, Qnil); 5075 if (pid == 0) { /* child */ 5076 rb_thread_atfork(); 5077 popen_redirect(&arg); 5078 rb_io_synchronized(RFILE(orig_stdout)->fptr); 5079 rb_io_synchronized(RFILE(orig_stderr)->fptr); 5080 return Qnil; 5081 } 5082 } 5083 ---Type <return> to continue, or q <return> to quit--- 5084 /* parent */ 5085 if (pid == -1) { 5086 int e = errno; 5087 close(arg.pair[0]); 5088 close(arg.pair[1]); 5089 if ((fmode & (FMODE_READABLE|FMODE_WRITABLE)) == (FMODE_READABLE|FMODE_WRITABLE)) { 5090 close(arg.write_pair[0]); 5091 close(arg.write_pair[1]); 5092 } 5093 errno = e; 5094 if (errmsg[0]) 5095 rb_sys_fail(errmsg); 5096 rb_sys_fail(cmd); 5097 } 5098 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) { 5099 close(arg.pair[1]); 5100 fd = arg.pair[0]; 5101 close(arg.write_pair[0]); 5102 write_fd = arg.write_pair[1]; 5103 } 5104 else if (fmode & FMODE_READABLE) { 5105 close(arg.pair[1]); ---Type <return> to continue, or q <return> to quit--- 5106 fd = arg.pair[0]; 5107 } 5108 else { 5109 close(arg.pair[0]); 5110 fd = arg.pair[1]; 5111 } 5112 #elif defined(_WIN32) 5113 if (argc) { 5114 int i; 5115 5116 if (argc >= (int)(FIXNUM_MAX / sizeof(char *))) { 5117 rb_raise(rb_eArgError, "too many arguments"); 5118 } 5119 argbuf = rb_str_tmp_new((argc+1) * sizeof(char *)); 5120 args = (void *)RSTRING_PTR(argbuf); 5121 for (i = 0; i < argc; ++i) { 5122 args[i] = StringValueCStr(argv[i]); 5123 } 5124 args[i] = NULL; 5125 } 5126 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) { 5127 case FMODE_READABLE|FMODE_WRITABLE: 5128 if (rb_pipe(write_pair) < 0) ---Type <return> to continue, or q <return> to quit--- 5129 rb_sys_fail(cmd); 5130 if (rb_pipe(pair) < 0) { 5131 int e = errno; 5132 close(write_pair[0]); 5133 close(write_pair[1]); 5134 errno = e; 5135 rb_sys_fail(cmd); 5136 } 5137 if (eargp) { 5138 rb_exec_arg_addopt(eargp, INT2FIX(0), INT2FIX(write_pair[0])); 5139 rb_exec_arg_addopt(eargp, INT2FIX(1), INT2FIX(pair[1])); 5140 } 5141 break; 5142 case FMODE_READABLE: 5143 if (rb_pipe(pair) < 0) 5144 rb_sys_fail(cmd); 5145 if (eargp) 5146 rb_exec_arg_addopt(eargp, INT2FIX(1), INT2FIX(pair[1])); 5147 break; 5148 case FMODE_WRITABLE: 5149 if (rb_pipe(pair) < 0) 5150 rb_sys_fail(cmd); ---Type <return> to continue, or q <return> to quit--- 5151 if (eargp) 5152 rb_exec_arg_addopt(eargp, INT2FIX(0), INT2FIX(pair[0])); 5153 break; 5154 default: 5155 rb_sys_fail(cmd); 5156 } 5157 if (eargp) { 5158 rb_exec_arg_fixup(eargp); 5159 rb_run_exec_options(eargp, &sarg); 5160 } 5161 while ((pid = (args ? 5162 rb_w32_aspawn(P_NOWAIT, cmd, args) : 5163 rb_w32_spawn(P_NOWAIT, cmd, 0))) == -1) { 5164 /* exec failed */ 5165 switch (errno) { 5166 case EAGAIN: 5167 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN 5168 case EWOULDBLOCK: 5169 #endif 5170 rb_thread_sleep(1); 5171 break; 5172 default: 5173 { ---Type <return> to continue, or q <return> to quit--- 5174 int e = errno; 5175 if (eargp) 5176 rb_run_exec_options(&sarg, NULL); 5177 close(pair[0]); 5178 close(pair[1]); 5179 if ((fmode & (FMODE_READABLE|FMODE_WRITABLE)) == (FMODE_READABLE|FMODE_WRITABLE)) { 5180 close(write_pair[0]); 5181 close(write_pair[1]); 5182 } 5183 errno = e; 5184 rb_sys_fail(cmd); 5185 } 5186 break; 5187 } 5188 } 5189 5190 RB_GC_GUARD(argbuf); 5191 5192 if (eargp) 5193 rb_run_exec_options(&sarg, NULL); 5194 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) { 5195 close(pair[1]); ---Type <return> to continue, or q <return> to quit--- 5196 fd = pair[0]; 5197 close(write_pair[0]); 5198 write_fd = write_pair[1]; 5199 } 5200 else if (fmode & FMODE_READABLE) { 5201 close(pair[1]); 5202 fd = pair[0]; 5203 } 5204 else { 5205 close(pair[0]); 5206 fd = pair[1]; 5207 } 5208 #else 5209 if (argc) { 5210 prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" ")); 5211 cmd = StringValueCStr(prog); 5212 } 5213 if (eargp) { 5214 rb_exec_arg_fixup(eargp); 5215 rb_run_exec_options(eargp, &sarg); 5216 } 5217 fp = popen(cmd, modestr); 5218 if (eargp) ---Type <return> to continue, or q <return> to quit--- 5219 rb_run_exec_options(&sarg, NULL); 5220 if (!fp) rb_sys_fail(RSTRING_PTR(prog)); 5221 fd = fileno(fp); 5222 #endif 5223 5224 port = io_alloc(rb_cIO); 5225 MakeOpenFile(port, fptr); 5226 fptr->fd = fd; 5227 fptr->stdio_file = fp; 5228 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX; 5229 if (convconfig) { 5230 fptr->encs = *convconfig; 5231 } 5232 else if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) { 5233 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR; 5234 } 5235 fptr->pid = pid; 5236 5237 if (0 <= write_fd) { 5238 write_port = io_alloc(rb_cIO); 5239 MakeOpenFile(write_port, write_fptr); 5240 write_fptr->fd = write_fd; 5241 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_D---Type <return> to continue, or q <return> to quit--- UPLEX; 5242 fptr->mode &= ~FMODE_WRITABLE; 5243 fptr->tied_io_for_writing = write_port; 5244 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port); 5245 } 5246 5247 #if defined (__CYGWIN__) || !defined(HAVE_FORK) 5248 fptr->finalize = pipe_finalize; 5249 pipe_add_fptr(fptr); 5250 #endif 5251 return port; 5252 } 5253 5254 static VALUE 5255 pipe_open_v(int argc, VALUE *argv, const char *modestr, int fmode, convconfig_t *convconfig) 5256 { 5257 VALUE prog; 5258 struct rb_exec_arg earg; 5259 prog = rb_exec_arg_init(argc, argv, FALSE, &earg); 0x62d7aebf <+207>: lea 0x5c(%esp),%edi 0x62d7aec3 <+211>: movl $0x0,0x8(%esp) ---Type <return> to continue, or q <return> to quit--- 0x62d7aecb <+219>: mov %edi,0xc(%esp) 0x62d7aecf <+223>: mov %eax,0x4(%esp) 0x62d7aed3 <+227>: mov %ebp,(%esp) 0x62d7aed6 <+230>: mov %ecx,0x2c(%esp) 0x62d7aeda <+234>: call 0x62dbf910 <rb_exec_arg_init> 5260 return pipe_open(&earg, prog, modestr, fmode, convconfig); 0x62d7aedf <+239>: mov 0x2c(%esp),%ecx 0x62d7aee6 <+246>: mov %eax,%edx 0x62d7aee8 <+248>: mov %edi,%eax 0x62d7aeea <+250>: call 0x62d79d00 <pipe_open> 0x62d7aef2 <+258>: mov %eax,%ebx 5261 } 5262 5263 static VALUE 5264 pipe_open_s(VALUE prog, const char *modestr, int fmode, convconfig_t *convconfig) 5265 { 5266 const char *cmd = RSTRING_PTR(prog); 5267 int argc = 1; 5268 VALUE *argv = &prog; 5269 struct rb_exec_arg earg; ---Type <return> to continue, or q <return> to quit--- 5270 5271 if (RSTRING_LEN(prog) == 1 && cmd[0] == '-') { 5272 #if !defined(HAVE_FORK) 5273 rb_raise(rb_eNotImpError, 5274 "fork() function is unimplemented on this machine"); 5275 #endif 5276 return pipe_open(0, 0, modestr, fmode, convconfig); 5277 } 5278 5279 rb_exec_arg_init(argc, argv, TRUE, &earg); 5280 return pipe_open(&earg, prog, modestr, fmode, convconfig); 5281 } 5282 5283 /* 5284 * call-seq: 5285 * IO.popen(cmd, mode="r" [, opt]) -> io 5286 * IO.popen(cmd, mode="r" [, opt]) {|io| block } -> obj 5287 * 5288 * Runs the specified command as a subprocess; the subprocess's 5289 * standard input and output will be connected to the returned 5290 * <code>IO</code> object. 5291 * 5292 * The PID of the started process can be obtained by IO#pid method. ---Type <return> to continue, or q <return> to quit--- 5293 * 5294 * _cmd_ is a string or an array as follows. 5295 * 5296 * cmd: 5297 * "-" : fork 5298 * commandline : command line string which is passed to a shell 5299 * [env, cmdname, arg1, ..., opts] : command name and zero or more arguments (no shell) 5300 * [env, [cmdname, argv0], arg1, ..., opts] : command name, argv[0] and zero or more arguments (no shell) 5301 * (env and opts are optional.) 5302 * 5303 * If _cmd_ is a +String+ ``<code>-</code>'', 5304 * then a new instance of Ruby is started as the subprocess. 5305 * 5306 * If <i>cmd</i> is an +Array+ of +String+, 5307 * then it will be used as the subprocess's +argv+ bypassing a shell. 5308 * The array can contains a hash at first for environments and 5309 * a hash at last for options similar to <code>spawn</code>. 5310 * 5311 * The default mode for the new file object is ``r'', 5312 * but <i>mode</i> may be set to any of the modes listed in the descrip---Type <return> to continue, or q <return> to quit--- tion for class IO. 5313 * The last argument <i>opt</i> qualifies <i>mode</i>. 5314 * 5315 * # set IO encoding 5316 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io| 5317 * euc_jp_string = nkf_io.read 5318 * } 5319 * 5320 * # merge standard output and standard error using 5321 * # spawn option. See the document of Kernel.spawn. 5322 * IO.popen(["ls", "/", :err=>[:child, :out]]) {|ls_io| 5323 * ls_result_with_error = ls_io.read 5324 * } 5325 * 5326 * Raises exceptions which <code>IO.pipe</code> and 5327 * <code>Kernel.spawn</code> raise. 5328 * 5329 * If a block is given, Ruby will run the command as a child connected 5330 * to Ruby with a pipe. Ruby's end of the pipe will be passed as a 5331 * parameter to the block. 5332 * At the end of block, Ruby close the pipe and sets <code>$?</code>. 5333 * In this case <code>IO.popen</code> returns ---Type <return> to continue, or q <return> to quit--- 5334 * the value of the block. 5335 * 5336 * If a block is given with a _cmd_ of ``<code>-</code>'', 5337 * the block will be run in two separate processes: once in the parent, 5338 * and once in a child. The parent process will be passed the pipe 5339 * object as a parameter to the block, the child version of the block 5340 * will be passed <code>nil</code>, and the child's standard in and 5341 * standard out will be connected to the parent through the pipe. Not 5342 * available on all platforms. 5343 * 5344 * f = IO.popen("uname") 5345 * p f.readlines 5346 * f.close 5347 * puts "Parent is #{Process.pid}" 5348 * IO.popen("date") { |f| puts f.gets } 5349 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"} 5350 * p $? 5351 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f| 5352 * f.puts "bar"; f.close_write; puts f.gets 5353 * } 5354 * ---Type <return> to continue, or q <return> to quit--- 5355 * <em>produces:</em> 5356 * 5357 * ["Linux\n"] 5358 * Parent is 21346 5359 * Thu Jan 15 22:41:19 JST 2009 5360 * 21346 is here, f is #<IO:fd 3> 5361 * 21352 is here, f is nil 5362 * #<Process::Status: pid 21352 exit 0> 5363 * <foo>bar;zot; 5364 */ 5365 5366 static VALUE 5367 rb_io_s_popen(int argc, VALUE *argv, VALUE klass) 5368 { 0x62d7adf0 <+0>: push %ebp 0x62d7adf1 <+1>: push %edi 0x62d7adf2 <+2>: push %esi 0x62d7adf3 <+3>: push %ebx 0x62d7adf4 <+4>: sub $0x7c,%esp 5369 const char *modestr; 5370 VALUE pname, pmode, port, tmp, opt; 5371 int oflags, fmode; ---Type <return> to continue, or q <return> to quit--- 5372 convconfig_t convconfig; 5373 5374 argc = rb_scan_args(argc, argv, "11:", &pname, &pmode, &opt); 0x62d7adf7 <+7>: lea 0x40(%esp),%eax 0x62d7adfb <+11>: movl $0x62ea0c34,0x8(%esp) 0x62d7ae03 <+19>: mov %eax,0x14(%esp) 0x62d7ae07 <+23>: mov 0x94(%esp),%eax 0x62d7ae0e <+30>: lea 0x3c(%esp),%edi 0x62d7ae12 <+34>: lea 0x38(%esp),%esi 0x62d7ae16 <+38>: mov %edi,0x10(%esp) 0x62d7ae1a <+42>: mov %esi,0xc(%esp) 0x62d7ae22 <+50>: mov %eax,0x4(%esp) 0x62d7ae26 <+54>: mov 0x90(%esp),%eax 0x62d7ae2d <+61>: mov %eax,(%esp) 0x62d7ae30 <+64>: call 0x62d29510 <rb_scan_args> 5375 5376 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig); 0x62d7ae1e <+46>: lea 0x4c(%esp),%ebx 0x62d7ae35 <+69>: mov 0x40(%esp),%ecx 0x62d7ae39 <+73>: lea 0x48(%esp),%eax 0x62d7ae3d <+77>: mov %eax,0x4(%esp) ---Type <return> to continue, or q <return> to quit--- 0x62d7ae41 <+81>: lea 0x44(%esp),%eax 0x62d7ae45 <+85>: xor %edx,%edx 0x62d7ae47 <+87>: mov %eax,(%esp) 0x62d7ae4a <+90>: mov %edi,%eax 0x62d7ae4c <+92>: mov %ebx,0x8(%esp) 0x62d7ae50 <+96>: call 0x62d79190 <rb_io_extract_modeenc> 5377 modestr = rb_io_oflags_modestr(oflags); 0x62d7ae55 <+101>: mov 0x44(%esp),%eax 5378 5379 tmp = rb_check_array_type(pname); 0x62d7ae76 <+134>: mov 0x38(%esp),%eax 0x62d7ae7a <+138>: mov %eax,(%esp) 0x62d7ae7d <+141>: call 0x62d0e770 <rb_check_array_type> 5380 if (!NIL_P(tmp)) { 0x62d7ae82 <+146>: cmp $0x4,%eax 0x62d7ae85 <+149>: je 0x62d7afb0 <rb_io_s_popen+448> 5381 long len = RARRAY_LEN(tmp); 0x62d7ae8b <+155>: mov (%eax),%ebp 0x62d7ae8d <+157>: test $0x2000,%ebp ---Type <return> to continue, or q <return> to quit--- 0x62d7ae93 <+163>: jne 0x62d7af40 <rb_io_s_popen+336> 0x62d7ae99 <+169>: mov 0x8(%eax),%ebp 0x62d7af40 <+336>: shr $0xf,%ebp 0x62d7af43 <+339>: and $0x3,%ebp 0x62d7af46 <+342>: jmp 0x62d7ae9c <rb_io_s_popen+172> 0x62d7af4b <+347>: nop 0x62d7af4c <+348>: lea 0x0(%esi,%eiz,1),%esi 5382 #if SIZEOF_LONG > SIZEOF_INT 5383 if (len > INT_MAX) { 5384 rb_raise(rb_eArgError, "too many arguments"); 5385 } 5386 #endif 5387 tmp = rb_ary_dup(tmp); 0x62d7ae9c <+172>: mov %eax,(%esp) 0x62d7ae9f <+175>: call 0x62d117a0 <rb_ary_dup> 0x62d7aea8 <+184>: mov %eax,%esi 5388 RBASIC(tmp)->klass = 0; 0x62d7aeaa <+186>: movl $0x0,0x4(%eax) 5389 port = pipe_open_v((int)len, RARRAY_PTR(tmp), modestr, fmode, &convconfig); ---Type <return> to continue, or q <return> to quit--- 0x62d7aea4 <+180>: mov 0x48(%esp),%ecx 0x62d7aeb1 <+193>: testl $0x2000,(%esi) 0x62d7aeb7 <+199>: lea 0x8(%eax),%eax 0x62d7aeba <+202>: jne 0x62d7aebf <rb_io_s_popen+207> 0x62d7aebc <+204>: mov 0x10(%esi),%eax 0x62d7aee3 <+243>: mov %ebx,(%esp) 5390 rb_ary_clear(tmp); 0x62d7aeef <+255>: mov %esi,(%esp) 0x62d7aef4 <+260>: call 0x62d08da0 <rb_ary_clear> 5391 } 5392 else { 5393 SafeStringValue(pname); 0x62d7afb0 <+448>: mov %esi,(%esp) 0x62d7afb3 <+451>: call 0x62e16740 <rb_string_value> 0x62d7afb8 <+456>: mov 0x38(%esp),%eax 0x62d7afbc <+460>: mov %eax,(%esp) 0x62d7afbf <+463>: call 0x62dfea50 <rb_check_safe_obj> 5394 port = pipe_open_s(pname, modestr, fmode, &convconfig); 0x62d7afc4 <+468>: mov 0x48(%esp),%edx 0x62d7afc8 <+472>: mov %ebx,%ecx ---Type <return> to continue, or q <return> to quit--- 0x62d7afca <+474>: mov 0x38(%esp),%eax 0x62d7afce <+478>: call 0x62d7a410 <pipe_open_s> 0x62d7afd3 <+483>: mov %eax,%ebx 0x62d7afd5 <+485>: jmp 0x62d7aef9 <rb_io_s_popen+265> 0x62d7afda <+490>: lea 0x0(%esi),%esi 5395 } 5396 if (NIL_P(port)) { 0x62d7aef9 <+265>: cmp $0x4,%ebx 0x62d7aefc <+268>: je 0x62d7af50 <rb_io_s_popen+352> 5397 /* child */ 5398 if (rb_block_given_p()) { 0x62d7af50 <+352>: call 0x62d4aea0 <rb_block_given_p> 0x62d7af55 <+357>: test %eax,%eax 0x62d7af57 <+359>: je 0x62d7af2f <rb_io_s_popen+319> 5399 rb_yield(Qnil); 0x62d7af59 <+361>: movl $0x4,(%esp) 0x62d7af60 <+368>: call 0x62e6f310 <rb_yield> 5400 rb_io_flush(rb_stdout); 0x62d7af65 <+373>: mov 0x62f3e850,%eax ---Type <return> to continue, or q <return> to quit--- 0x62d7af6a <+378>: mov %eax,(%esp) 0x62d7af6d <+381>: call 0x62d70830 <rb_io_flush> 5401 rb_io_flush(rb_stderr); 0x62d7af72 <+386>: mov 0x62f3e800,%eax 0x62d7af77 <+391>: mov %eax,(%esp) 0x62d7af7a <+394>: call 0x62d70830 <rb_io_flush> 5402 _exit(0); 0x62d7af7f <+399>: movl $0x0,(%esp) 0x62d7af86 <+406>: call 0x62e97338 <_exit> 0x62d7af8b <+411>: nop 0x62d7af8c <+412>: lea 0x0(%esi,%eiz,1),%esi 5403 } 5404 return Qnil; 5405 } 5406 RBASIC(port)->klass = klass; 0x62d7aefe <+270>: mov 0x98(%esp),%eax 0x62d7af05 <+277>: mov %eax,0x4(%ebx) 5407 if (rb_block_given_p()) { 0x62d7af08 <+280>: call 0x62d4aea0 <rb_block_given_p> ---Type <return> to continue, or q <return> to quit--- 0x62d7af0d <+285>: test %eax,%eax 0x62d7af0f <+287>: je 0x62d7af2f <rb_io_s_popen+319> 5408 return rb_ensure(rb_yield, port, io_close, port); 0x62d7af11 <+289>: mov %ebx,0xc(%esp) 0x62d7af15 <+293>: mov %ebx,0x4(%esp) 0x62d7af19 <+297>: movl $0x62d6aac0,0x8(%esp) 0x62d7af21 <+305>: movl $0x62e6f310,(%esp) 0x62d7af28 <+312>: call 0x62d4b340 <rb_ensure> => 0x62d7af2d <+317>: mov %eax,%ebx 5409 } 5410 return port; 5411 } 0x62d7af2f <+319>: add $0x7c,%esp 0x62d7af32 <+322>: mov %ebx,%eax 0x62d7af34 <+324>: pop %ebx 0x62d7af35 <+325>: pop %esi 0x62d7af36 <+326>: pop %edi 0x62d7af37 <+327>: pop %ebp 0x62d7af38 <+328>: ret 0x62d7af39 <+329>: lea 0x0(%esi,%eiz,1),%esi
Please stop to reopen this bug. It isn't related to gcc at all. I just rebuild a gcc 4.7 (trunk) version for i686-w64-mingw32 and test passes as expected (with crash after trying to leave main function). This issue is related to mingw.org's header-set and handling of setjmp. As I mentioned before, this is caused by a missing (undocumented) argument for setjmp. You disassembly of this function shows that msvcrt's setjmp function tries to read this hidden argument and just by accident it is here the place of ebp. See on msdn the user-comment about setjmp.