[Bug rtl-optimization/49230] please provide workaround for setjmp/longjmp in mingw32

jojelino at gmail dot com gcc-bugzilla@gcc.gnu.org
Wed Jun 29 19:51:00 GMT 2011


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49230

--- Comment #9 from gee <jojelino at gmail dot com> 2011-06-29 19:50:34 UTC ---
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



More information about the Gcc-bugs mailing list