Stas Bekman wrote:

Steve Hay wrote:

I've been trying to debug what goes on when I run this:

perl t/SMOKE modperl\post_utf8

This single test is one of those that fails with the "Failed to dup STDOUT" error.
[...]


Continuing walking through Perl_do_openn() we visit line 389 (with dodup set to 2):

fp = PerlIO_fdupopen(aTHX_ that_fp, NULL, dodup);


looks good

[which returns via line 536 of perlio.c] and later on line 555:

fd = PerlIO_fileno(fp);

which sets fd to 35 (!),


sounds quite possible

. We then go to line 561:

if (PerlLIO_fstat(fd,&PL_statbuf) < 0) {

and then it all goes wrong because sadly that PerlLIO_fstat() fails and we return FALSE via lines 563, 564, 697, etc. The PerlLIO_fstat() call actually winds up being _fstati64() on line 500 of win32/win32sck.c, and returned -1.


I'd step through
  PerlIO_fdupopen(aTHX_ that_fp, NULL, dodup);

and see that the dup goes correctly. If stat fails that means that the above has failed. May be it needs a check?

There's not very much to PerlIO_fdupopen():


=====
PerlIO *
PerlIO_fdupopen(pTHX_ PerlIO *f, CLONE_PARAMS *param, int flags)
{
if (PerlIOValid(f)) {
PerlIO_funcs *tab = PerlIOBase(f)->tab;
PerlIO_debug("fdupopen f=%p param=%p\n",(void*)f,(void*)param);
if (tab && tab->Dup)
return (*tab->Dup)(aTHX_ PerlIO_allocate(aTHX), f, param, flags);
else {
return PerlIOBase_dup(aTHX_ PerlIO_allocate(aTHX), f, param, flags);
}
}
else
SETERRNO(EBADF, SS_IVCHAN);


   return NULL;
}
=====

PerlIOValid(f) is true, and so is (tab && tab->Dup). The PerlIO_allocate() returns f when i reaches 36; f is then some non-NULL value, param is 0x00000000 (is that alright or not?) and flags is 2.

We then call (*tab->Dup)(...), which is PerlIOBuf_dup(...), which calls PerlIOBase_dup(...). We goto line 2170 of perlio.c in that function, which is another call to (*tab->Dup)(...), which is PerlIOUnix_dup(...) this time.

Line 2457 of perlio.c sets fd to 1 (which is STDOUT, right?) flags is still 2, so (flags & PERLIO_DUP_FD) is true and we call PerlLIO_dup() on line 2459. That calls win32_dup(), which calls dup(), which I can't step into ;-). Each of dup(), win32_dup() and PerlLIO_dup() returns 35.

Then we call PerlIOBase_dup() at line 2462. f and o are both non-NULL, param is 0x00000000 and flags is still 2. This call skips over the PerlIOValid(nexto) test on line 2167. self->Getarg is 0x00000000 at line 2180.

PerlIO_modestr() returns "wb", which is passed to PerlIO_push at line 2185. The (l && f) test on line 1158 is true. (*l->tab->Pushed) is PerlIOUnix_pushed() which calls PerlIOBase_pushed(). tab->Set_ptrcnt is NULL at line 1965. The 'w' and 'b' chars are handled correctly and we return 0. Back on line 2366 in PerlIOUnix_pushed() now. The *PerlIONext(f) test is false and we return 0. Back on line 1166 in PerlIO_push() now. The "if" test there is therefore false and we return f (which is non-NULL).

This f also gets returned from PerlIOBase_dup(), so back in PerlIOUnix_dup() we call PerlIOUnix_setfd() at line 2465 which looks good. f is non-NULL, fd is 35, os->oflags is 0. The PerlLIO_fstat(35, &st) call at line 2348 is ultimately a call to _fstati64(35, ...) at win32/win32sck.c line 500 which returns -1. I wasn't expecting that to have failed (_fstati64() returns 0 for success, -1 for failure) :-s (***)

Carrying on anyway, PerlIOUnix_dup() returns (non-NULL) f at line 2466. Back in PerlIOBase_dup(), f is true at line 2174. self->Getarg is 0x00000000 at line 2180. This time PerlIO_modestr() returns "w", which is passed to PerlIO_push at line 2185. Again the (l && f) test on line 1158 is true. Now (*l->tab->Pushed) is PerlIOCrlf_pushed() which calls PerlIOBuf_pushed().

PerlIO_fileno() ultimately calls PerlIOUnix_fileno(), which returns 35. The (fd >= 0 && PerlLIO_isatty(fd)) test is false; *PerlIONext(f) is true.

PerlIO_tell() ultimately calls _lseeki64(), which returns 29. Is this just the number of bytes written to STDOUT at this point? I assume that's OK.

Now we call PerlIOBase_pushed() (line 3418) again. This time tab->Set_ptrcnt is PerlIOCrlf_set_ptrcnt at line 1965. The 'w' char is handled correctly and we return 0, which PerlIOBuf_pushed() also returns.

The while loop at the end of PerlIOCrlf_pushed was only run through once, with b->tab == &PerlIO_unix. I think that's OK - if I follow it correctly we have a unix layer already, and we've just pushed a crlf layer. The while loop was looking for any crlf layers below what we've just pushed, and correctly didn't find any.

So we return 0 and the "if" test on line 1166 is false, and we return f (non-NULL) from PerlIO_push(), and from PerlIOBase_dup(), and from PerlIOBuf_dup(), and from PerlIO_fdupopen().

This sets fp to a non-NULL value at line 389 of doio.c. Then as we saw before fd is 35 at line 555 and the PerlLIO_fstat() at line 561 returns -1 (failure) just like it did inside the PerlIO_fdupopen() call detailed above.

So presumably it's that failure above, marked (***), which is where it's all gone wrong. Here's a stack trace showing the path to my_stat() which calls _fstati64():

=====
my_fstat(int 35, _stati64 * 0x02f3fb98) line 532
win32_fstat(int 35, _stati64 * 0x02f3fb98) line 2706 + 13 bytes
PerlLIOFileStat(IPerlLIO * 0x0141becc, int 35, _stati64 * 0x02f3fb98) line 974 + 13 bytes
PerlIOUnix_setfd(interpreter * 0x01b2004c, _PerlIO * * 0x01b20ee4, int 35, int 0) line 2348 + 30 bytes
PerlIOUnix_dup(interpreter * 0x01b2004c, _PerlIO * * 0x01b20ee4, _PerlIO * * 0x0108ec8c, clone_params * 0x00000000, int 2) line 2465 + 24 bytes
PerlIOBase_dup(interpreter * 0x01b2004c, _PerlIO * * 0x01b20ee4, _PerlIO * * 0x01b20e5c, clone_params * 0x00000000, int 2) line 2170 + 26 bytes
PerlIOBuf_dup(interpreter * 0x01b2004c, _PerlIO * * 0x01b20ee4, _PerlIO * * 0x01b20e5c, clone_params * 0x00000000, int 2) line 3871 + 25 bytes
PerlIO_fdupopen(interpreter * 0x01b2004c, _PerlIO * * 0x01b20e5c, clone_params * 0x00000000, int 2) line 536 + 35 bytes
Perl_do_openn(interpreter * 0x01b2004c, gv * 0x01fb0334, char * 0x01ac46dc, long 8, int 0, int 1, int 0, _PerlIO * * 0x00000000, sv * * 0x00000000, long 0) line 389 + 19 bytes
Perl_do_open(interpreter * 0x01b2004c, gv * 0x01fb0334, char * 0x1002c664 `string', long 8, int 0, int 1, int 0, _PerlIO * * 0x00000000) line 60 + 41 bytes
modperl_io_perlio_override_stdout(interpreter * 0x01b2004c, request_rec * 0x03386160) line 137 + 28 bytes
modperl_response_handler_cgi(request_rec * 0x03386160) line 918 + 13 bytes
ap_run_handler(request_rec * 0x03386160) line 195 + 78 bytes
ap_invoke_handler(request_rec * 0x03386160) line 401 + 9 bytes
ap_process_request(request_rec * 0x03386160) line 288 + 9 bytes
ap_process_http_connection(conn_rec * 0x0084c650) line 293 + 9 bytes
ap_run_process_connection(conn_rec * 0x0084c650) line 85 + 78 bytes
ap_process_connection(conn_rec * 0x0084c650, void * 0x0084c588) line 213
worker_main(long 19) line 731
_threadstartex(void * 0x0028def0) line 212 + 13 bytes
KERNEL32! 77e7d33b()
=====


If definitely looks bad because the call to PerlIOUnix_setfd() is commented:

/* If all went well overwrite fd in dup'ed lay with the dup()'ed fd */

so it does look like things should have worked out OK at this point.

I don't know if this helps anyone fix it, though :-(

- Steve


--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]



Reply via email to