[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