Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

filetest problem with STDIN/OUT on Windows #8502

Open
p5pRT opened this issue Jun 27, 2006 · 11 comments
Open

filetest problem with STDIN/OUT on Windows #8502

p5pRT opened this issue Jun 27, 2006 · 11 comments
Assignees

Comments

@p5pRT
Copy link

p5pRT commented Jun 27, 2006

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

Searchable as RT39637$

@p5pRT
Copy link
Author

p5pRT commented Jun 27, 2006

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
Copy link
Author

p5pRT commented Jul 11, 2006

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
Copy link
Author

p5pRT commented Jul 11, 2006

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

@p5pRT
Copy link
Author

p5pRT commented Jul 11, 2006

From @demerphq

On 7/11/06, Steve Hay <steve.hay@​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
Copy link
Author

p5pRT commented Jul 12, 2006

From @steve-m-hay

demerphq wrote​:

On 7/11/06, Steve Hay <steve.hay@​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
Copy link
Author

p5pRT commented Jul 12, 2006

From @demerphq

On 7/12/06, Steve Hay <steve.hay@​uk.radan.com> wrote​:

demerphq wrote​:

On 7/11/06, Steve Hay <steve.hay@​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
Copy link
Author

p5pRT commented Jul 12, 2006

From @steve-m-hay

demerphq wrote​:

On 7/12/06, Steve Hay <steve.hay@​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
Copy link
Author

p5pRT commented Jul 12, 2006

From @demerphq

On 7/12/06, Steve Hay <steve.hay@​uk.radan.com> wrote​:

demerphq wrote​:

On 7/12/06, Steve Hay <steve.hay@​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
Copy link
Author

p5pRT commented Jul 16, 2006

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

genio added a commit to genio/perl5 that referenced this issue Oct 15, 2020
As discussed on the mailing list here:
https://www.nntp.perl.org/group/perl.perl5.porters/2020/10/msg258453.html

This just removes the declaration that we support the very old versions
of Windows that have long since been EOLed.

For reference of problems related to maintaining the EOLed versions:
Perl#4145
Perl#6080
Perl#7410
Perl#8502
Perl#9025
Perl#12431
Perl#14687
@tonycoz
Copy link
Contributor

tonycoz commented Dec 3, 2020

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)

@jkeenan
Copy link
Contributor

jkeenan commented Apr 7, 2021

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

@xenu xenu removed the Severity Low label Dec 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants