Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.98k stars 559 forks source link

filetest problem with STDIN/OUT on Windows #8502

Open p5pRT opened 18 years ago

p5pRT commented 18 years ago

Migrated from rt.perl.org#39637 (status was 'open')

Searchable as RT39637$

p5pRT commented 18 years ago

From @pmqs

[Forgot to forward this to perlbug]

Had a problem with my compression modules reported to me yesterday that boiled down to the -r & -w file test operators not working properly with STDIN/OUT on windows.

perl -e " print -r \*STDIN ? 'Can Read' : 'Cannot Read' " Cannot Read

perl -e " print -w \*STDOUT ? 'Can Write' : 'Cannot Write' " Cannot Write

My windows box has an ActiveState 5.8.8 on it.

Is this a known issue on windows?

Paul

 
___________________________________________________________ The all-new Yahoo! Mail goes wherever you go - free your email address from your Internet provider. http​://uk.docs.yahoo.com/nowyoucan.html

p5pRT commented 18 years ago

From @steve-m-hay

paul.marquess@​ntlworld.com (via RT) wrote​:

Had a problem with my compression modules reported to me yesterday that boiled down to the -r & -w file test operators not working properly with STDIN/OUT on windows.

perl -e " print -r \*STDIN ? 'Can Read' : 'Cannot Read' " Cannot Read

perl -e " print -w \*STDOUT ? 'Can Write' : 'Cannot Write' " Cannot Write

My windows box has an ActiveState 5.8.8 on it.

Is this a known issue on windows?

Not to me\, so thanks for the report!

It isn't mentioned in perlport either\, but it seems to be a Windows thing.

pp_ftrread() calls my_stat()\, which calls PerlLIO_fstat() on the appropriate file descriptor. This winds up in win32_fstat() on Windows\, which in turn ends up calling fstat() or _fstati64() (in win32sck.c's my_fstat()). That call sets up a stat buffer which\, in the case of STDIN\, doesn't have the read bit set in its st_mode member.

The following C program replicates the problem​:

/* ---------- */ #include \<stdio.h> #include \<sys/stat.h> #include \<sys/types.h> int main(void) {   int fd = 0; /* stdin */   int mode = 256; /* read? */   struct stat sbuf;   if (fstat(fd\, &sbuf) \< 0) {   printf("stat call failed\n");   return 1;   }   if (sbuf.st_mode & mode)   printf("stdin is readable\n");   else   printf("stdin is not readable\n");   return 0; } /* ---------- */

On Windows\, this outputs "stdin is not readable". (I tried VC++\, MinGW and Borland -- all the same.)

On other platforms\, it presumably says "stdin is readable". (I tried it on Cygwin\, and that certainly does.)

So it looks like a(nother) Windows limitation. If no-one can see a way around it then I think it should at least be mentioned in perlport.

--


Radan Computational Ltd.

The information contained in this message and any files transmitted with it are confidential and intended for the addressee(s) only. If you have received this message in error or there are any problems\, please notify the sender immediately. The unauthorized use\, disclosure\, copying or alteration of this message is strictly forbidden. Note that any views or opinions presented in this email are solely those of the author and do not necessarily represent those of Radan Computational Ltd. The recipient(s) of this message should check it and any attached files for viruses​: Radan Computational will accept no liability for any damage caused by any virus transmitted by this email.

p5pRT commented 18 years ago

The RT System itself - Status changed from 'new' to 'open'

p5pRT commented 18 years ago

From @demerphq

On 7/11/06\, Steve Hay \steve\.hay@&#8203;uk\.radan\.com wrote​:

paul.marquess@​ntlworld.com (via RT) wrote​:

Had a problem with my compression modules reported to me yesterday that boiled down to the -r & -w file test operators not working properly with STDIN/OUT on windows.

perl -e " print -r \*STDIN ? 'Can Read' : 'Cannot Read' " Cannot Read

perl -e " print -w \*STDOUT ? 'Can Write' : 'Cannot Write' " Cannot Write

My windows box has an ActiveState 5.8.8 on it.

Is this a known issue on windows?

Not to me\, so thanks for the report!

It isn't mentioned in perlport either\, but it seems to be a Windows thing.

pp_ftrread() calls my_stat()\, which calls PerlLIO_fstat() on the appropriate file descriptor. This winds up in win32_fstat() on Windows\, which in turn ends up calling fstat() or _fstati64() (in win32sck.c's my_fstat()). That call sets up a stat buffer which\, in the case of STDIN\, doesn't have the read bit set in its st_mode member.

The following C program replicates the problem​:

/* ---------- */ #include \<stdio.h> #include \<sys/stat.h> #include \<sys/types.h> int main(void) { int fd = 0; /* stdin */ int mode = 256; /* read? */ struct stat sbuf; if (fstat(fd\, &sbuf) \< 0) { printf("stat call failed\n"); return 1; } if (sbuf.st_mode & mode) printf("stdin is readable\n"); else printf("stdin is not readable\n"); return 0; } /* ---------- */

On Windows\, this outputs "stdin is not readable". (I tried VC++\, MinGW and Borland -- all the same.)

On other platforms\, it presumably says "stdin is readable". (I tried it on Cygwin\, and that certainly does.)

So it looks like a(nother) Windows limitation. If no-one can see a way around it then I think it should at least be mentioned in perlport.

Or maybe fake it in whatever way that cygwin fakes it.

sbuf.st_mode & _S_IFCHR

is set\, which is documented as

"The _S_IFCHR bit is set if handle refers to a device."

but sbuf.st_rdev is 0\, which is documented as​:

"If a device\, handle; otherwise 0."

and _isatty( fd ) return true.

So maybe under these situations we should lie and say it is readable?

Yves

-- perl -Mre=debug -e "/just|another|perl|hacker/"

p5pRT commented 18 years ago

From @steve-m-hay

demerphq wrote​:

On 7/11/06\, Steve Hay \steve\.hay@&#8203;uk\.radan\.com wrote​:

The following C program replicates the problem​:

/* ---------- */ #include \<stdio.h> #include \<sys/stat.h> #include \<sys/types.h> int main(void) { int fd = 0; /* stdin */ int mode = 256; /* read? */ struct stat sbuf; if (fstat(fd\, &sbuf) \< 0) { printf("stat call failed\n"); return 1; } if (sbuf.st_mode & mode) printf("stdin is readable\n"); else printf("stdin is not readable\n"); return 0; } /* ---------- */

On Windows\, this outputs "stdin is not readable". (I tried VC++\, MinGW and Borland -- all the same.)

On other platforms\, it presumably says "stdin is readable". (I tried it on Cygwin\, and that certainly does.)

So it looks like a(nother) Windows limitation. If no-one can see a way around it then I think it should at least be mentioned in perlport.

Or maybe fake it in whatever way that cygwin fakes it.

sbuf.st_mode & _S_IFCHR

is set\, which is documented as

"The _S_IFCHR bit is set if handle refers to a device."

but sbuf.st_rdev is 0\, which is documented as​:

"If a device\, handle; otherwise 0."

and _isatty( fd ) return true.

So maybe under these situations we should lie and say it is readable?

You're quite right that

  (sbuf.st_mode & S_IFCHR) && isatty(sbuf.st_rdev)

is true in the example above\, but unfortunately it is also true for fd 1 (stdout) and 2 (stderr). So how would we know whether to fake it as "readable" or "writable"?

Just faking fd 0 as readable and fd's 1 and 2 as writable is no good\, of course\, because of fun and games with dup'ing and re-directing.

I couldn't see how/where Cygwin does it. I looked in cygwin-1.5.19-4-src.tar.bz2​: I found what looks like their fstat() function in newlib\libc\syscalls\sysfstat.c\, but it just calls _fstat()\, which is presumably the MS CRT function (?)\, or _fstat_r()\, a reentrant version which also calls _fstat() and just handles errors differently.

Do any Cygwin gurus know more about this?

--


Radan Computational Ltd.

The information contained in this message and any files transmitted with it are confidential and intended for the addressee(s) only. If you have received this message in error or there are any problems\, please notify the sender immediately. The unauthorized use\, disclosure\, copying or alteration of this message is strictly forbidden. Note that any views or opinions presented in this email are solely those of the author and do not necessarily represent those of Radan Computational Ltd. The recipient(s) of this message should check it and any attached files for viruses​: Radan Computational will accept no liability for any damage caused by any virus transmitted by this email.

p5pRT commented 18 years ago

From @demerphq

On 7/12/06\, Steve Hay \steve\.hay@&#8203;uk\.radan\.com wrote​:

demerphq wrote​:

On 7/11/06\, Steve Hay \steve\.hay@&#8203;uk\.radan\.com wrote​:

The following C program replicates the problem​:

/* ---------- */ #include \<stdio.h> #include \<sys/stat.h> #include \<sys/types.h> int main(void) { int fd = 0; /* stdin */ int mode = 256; /* read? */ struct stat sbuf; if (fstat(fd\, &sbuf) \< 0) { printf("stat call failed\n"); return 1; } if (sbuf.st_mode & mode) printf("stdin is readable\n"); else printf("stdin is not readable\n"); return 0; } /* ---------- */

On Windows\, this outputs "stdin is not readable". (I tried VC++\, MinGW and Borland -- all the same.)

On other platforms\, it presumably says "stdin is readable". (I tried it on Cygwin\, and that certainly does.)

So it looks like a(nother) Windows limitation. If no-one can see a way around it then I think it should at least be mentioned in perlport.

Or maybe fake it in whatever way that cygwin fakes it.

sbuf.st_mode & _S_IFCHR

is set\, which is documented as

"The _S_IFCHR bit is set if handle refers to a device."

but sbuf.st_rdev is 0\, which is documented as​:

"If a device\, handle; otherwise 0."

and _isatty( fd ) return true.

So maybe under these situations we should lie and say it is readable?

You're quite right that

(sbuf.st_mode & S_IFCHR) && isatty(sbuf.st_rdev)

is true in the example above\, but unfortunately it is also true for fd 1 (stdout) and 2 (stderr). So how would we know whether to fake it as "readable" or "writable"?

Just faking fd 0 as readable and fd's 1 and 2 as writable is no good\, of course\, because of fun and games with dup'ing and re-directing.

Except that then wouldnt the above test fail? Unless perhaps if they were trying to swap STDIN and STDOUT in which case they kinda deserve what they get dont they?

Or in less flippant terms the realm where the caveat would apply would be reduced to getting a pathological case wrong instead of getting all of the cases wrong.

I couldn't see how/where Cygwin does it. I looked in cygwin-1.5.19-4-src.tar.bz2​: I found what looks like their fstat() function in newlib\libc\syscalls\sysfstat.c\, but it just calls _fstat()\, which is presumably the MS CRT function (?)\, or _fstat_r()\, a reentrant version which also calls _fstat() and just handles errors differently.

Do any Cygwin gurus know more about this?

Ill bet a pint of beer that they fake it as well. :-)

Yves

-- perl -Mre=debug -e "/just|another|perl|hacker/"

p5pRT commented 18 years ago

From @steve-m-hay

demerphq wrote​:

On 7/12/06\, Steve Hay \steve\.hay@&#8203;uk\.radan\.com wrote​:

You're quite right that

(sbuf.st_mode & S_IFCHR) && isatty(sbuf.st_rdev)

is true in the example above\, but unfortunately it is also true for fd 1 (stdout) and 2 (stderr). So how would we know whether to fake it as "readable" or "writable"?

Just faking fd 0 as readable and fd's 1 and 2 as writable is no good\, of course\, because of fun and games with dup'ing and re-directing.

Except that then wouldnt the above test fail? Unless perhaps if they were trying to swap STDIN and STDOUT in which case they kinda deserve what they get dont they?

I was actually thinking of rather less pathological cases like just dup'ing STDIN. For example\, the following doesn't print 'readable'​:

perl -e "open my $dupin\, '\<&STDIN'; print 'readable' if -r $dupin"

but here the file descriptor of $dupin is 3\, not 0.

--


Radan Computational Ltd.

The information contained in this message and any files transmitted with it are confidential and intended for the addressee(s) only. If you have received this message in error or there are any problems\, please notify the sender immediately. The unauthorized use\, disclosure\, copying or alteration of this message is strictly forbidden. Note that any views or opinions presented in this email are solely those of the author and do not necessarily represent those of Radan Computational Ltd. The recipient(s) of this message should check it and any attached files for viruses​: Radan Computational will accept no liability for any damage caused by any virus transmitted by this email.

p5pRT commented 18 years ago

From @demerphq

On 7/12/06\, Steve Hay \steve\.hay@&#8203;uk\.radan\.com wrote​:

demerphq wrote​:

On 7/12/06\, Steve Hay \steve\.hay@&#8203;uk\.radan\.com wrote​:

You're quite right that

(sbuf.st_mode & S_IFCHR) && isatty(sbuf.st_rdev)

is true in the example above\, but unfortunately it is also true for fd 1 (stdout) and 2 (stderr). So how would we know whether to fake it as "readable" or "writable"?

Just faking fd 0 as readable and fd's 1 and 2 as writable is no good\, of course\, because of fun and games with dup'ing and re-directing.

Except that then wouldnt the above test fail? Unless perhaps if they were trying to swap STDIN and STDOUT in which case they kinda deserve what they get dont they?

I was actually thinking of rather less pathological cases like just dup'ing STDIN. For example\, the following doesn't print 'readable'​:

perl -e "open my $dupin\, '\<&STDIN'; print 'readable' if -r $dupin"

but here the file descriptor of $dupin is 3\, not 0.

Ah ok. I see. Im still not sure thats a reason not to special case 0\,1 and 2 tho. Dup'd handles will presumably be a lot rarer than the normal ones. But of course if there is proper solution we should use it instead. I spent a while trawling the docs (msdn/library seems to have improved quite a bit recently) but i didnt really find anything useful.

-- perl -Mre=debug -e "/just|another|perl|hacker/"

p5pRT commented 18 years ago

From @pmqs

From​: Steve Hay [mailto​:steve.hay@​uk.radan.com]

paul.marquess@​ntlworld.com (via RT) wrote​:

Had a problem with my compression modules reported to me yesterday that boiled down to the -r & -w file test operators not working properly with STDIN/OUT on windows.

perl -e " print -r \*STDIN ? 'Can Read' : 'Cannot Read' " Cannot Read

perl -e " print -w \*STDOUT ? 'Can Write' : 'Cannot Write' " Cannot Write

My windows box has an ActiveState 5.8.8 on it.

Is this a known issue on windows?

Not to me\, so thanks for the report!

It isn't mentioned in perlport either\, but it seems to be a Windows thing.

Yep\, perlport was the first place I looked to see if this was a known limitation on windows (which I don't do any development on).

The test suite was my second port of call\, and tests that check filetests with filehandles seem to be a bit thin on the ground.

pp_ftrread() calls my_stat()\, which calls PerlLIO_fstat() on the appropriate file descriptor. This winds up in win32_fstat() on Windows\, which in turn ends up calling fstat() or _fstati64() (in win32sck.c's my_fstat()). That call sets up a stat buffer which\, in the case of STDIN\, doesn't have the read bit set in its st_mode member.

The following C program replicates the problem​:

/* ---------- */ #include \<stdio.h> #include \<sys/stat.h> #include \<sys/types.h> int main(void) { int fd = 0; /* stdin */ int mode = 256; /* read? */ struct stat sbuf; if (fstat(fd\, &sbuf) \< 0) { printf("stat call failed\n"); return 1; } if (sbuf.st_mode & mode) printf("stdin is readable\n"); else printf("stdin is not readable\n"); return 0; } /* ---------- */

On Windows\, this outputs "stdin is not readable". (I tried VC++\, MinGW and Borland -- all the same.)

On other platforms\, it presumably says "stdin is readable". (I tried it on Cygwin\, and that certainly does.)

So it looks like a(nother) Windows limitation. If no-one can see a way around it then I think it should at least be mentioned in perlport.

Ahh joy!

Paul

tonycoz commented 3 years ago

This is partly fixed by e935ef333b3eab54a766de93fad1369f76ddea49, so that -r/-w work on STDIN, STDOUT, STDERR, but it doesn't work on duplicates of those handles.

Windows 10 has an API that might allow this to work, CompareObjectHandles(), but I haven't tried it (yet)

jkeenan commented 3 years ago

This is partly fixed by e935ef3, so that -r/-w work on STDIN, STDOUT, STDERR, but it doesn't work on duplicates of those handles.

Windows 10 has an API that might allow this to work, CompareObjectHandles(), but I haven't tried it (yet)

@tonycoz, has there been any headway on this ticket?

Thank you very much. Jim Keenan