Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Re: Re: Problem with filetest -x _ on Win2k AS Perl build 626

by Rudif (Hermit)
on Jul 01, 2001 at 21:45 UTC ( #93038=note: print w/replies, xml ) Need Help??


in reply to Re: Problem with filetest -x _ on Win2k AS Perl build 626
in thread Problem with filetest -x _ on Win2k AS Perl build 626

>> Question to experienced monks: Where should I report the bug? ActiveState, or perl 5 porters? Rudif mumbling to himself ...

OK, I submitted a bug report to perlbug@perl.com, where it received ID 20010627.004.

To investigate the problem further, I built the Perl locally (I had to tweak the makefile to get the symbols) and stepped in with a debugger (windbg). My conclusion: Microsoft implementation of C function _fstat() fails to set the 'Executable' bit correctly for an executable file, while their function _stat() does it correctly. The Perl implemetation of stat() calls _stat(), while the implementation of -T _ calls the rogue _fstat().

Below is my followup report to perl5porters. I hope I won't get flamed for posting C code along with perl code.

Rudif

Re ID 20010627.004 : I have a diagnostic

I investigated some more the bug 20010627.004 and I have a diagnostic.

1. Summary

I found that the failure of Perl filetest operator -x _ on Win2k to report an executable file as executable after a -T _ is due to discrepancy in st_mode values returned by Microsoft functions _stat() and _fstat(). Specifically, I found that _stat() sets the 3 Execute bits (mask 0111 octal) to 1 when it sees an executable file, while _fstat() sets these bits to 0 when looking at the same file.

The C program below demonstrates.

2. Simplified test case

Here is my simplified perl script that demonstrates the problem, in Active Perl build 626 as well as in my local build of Perl from sources currently (Jun 2001) distributed by ActiveState:

#!perl -w use strict; my $exe = '../perl.exe'; stat($exe); printf "BAD $exe text=%d, executable=%d\n", -T _, -x _; stat($exe); printf "OK $exe executable=%d, text=%d\n", -x _, -T _; stat($exe); printf "OK $exe text=%d, executable=%d\n", -T _, -x $exe; __END__ BAD ../perl.exe text=0, executable=0 OK ../perl.exe executable=1, text=0 OK ../perl.exe text=0, executable=1
It demonstrates that doing -T _ after stat() and before -x _ produces erroneous -x result.

3. Results of my investigation

I looked into the implementation of Perl stat() and -T _. In fact, I ran the debugger windbg on my local build while running above test script.

I found this:

Perl_pp_stat() in pp_sys.c implements Perl stat() calls PerlLIONameStat() calls win32_stat() calls stat(path, sbuf) // Win32 library call sbuf.st_mode == 0100777 octal, for perl.exe, GOOD Perl_pp_fttext() in pp_sys.c implements Perl -T calls PerlLIOFileStat() calls win32_fstat() calls my_fstat() calls fstat(fd, sbuf) // Win32 library call sbuf.st_mode == 0100666 octal, for perl.exe, BAD
which explains the misbehavior that I am complaining about.

I wrote a C test program that demonstrates the misbehavior (IMO) of Win32 fstat():

// _stattest.cpp : compare MS implementation of functions stat() and f +stat() // rudif@bluemail.ch 1 Jul 2001 #include <time.h> #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <io.h> #include <fcntl.h> void main( void ) { const char *filename = "c:\\perl\\bin\\perl.exe"; printf( "File name : %s\n", filename ); { static struct stat buf; // initializes to 0 if ( stat( filename, &buf ) != 0 ) perror( "Problem with stat()" ); else { printf( "\nFrom MSDN page on _stat():\n" " Get status information on a file.\n" " st_mode\n" " Bit mask for file-mode information.\n" " The _S_IFDIR bit is set if path specifies a direc +tory;\n" " the _S_IFREG bit is set if path specifies an ordi +nary file or a device.\n" " User read/write bits are set according to the fil +es permission mode;\n" " user execute bits are set according to the filena +me extension.\n" ); printf( "Mode (oct) : 0%06o\n", (unsigned short)buf +.st_mode ); printf( "Mode (hex) : 0x%04x\n", (unsigned short)bu +f.st_mode ); } } { int fh; static struct stat buf; // initializes to 0 if ( (fh = open(filename, _O_RDONLY)) == -1 ) perror( "Problem with open()" ); else if ( fstat( fh, &buf ) != 0 ) perror( "Problem with fstat()" ); else { printf( "\nFrom MSDN page on _fstat():\n" " Get information about an open file.\n" " st_mode\n" " Bit mask for file-mode information.\n" " The _S_IFCHR bit is set if handle refers to a devi +ce.\n" " The _S_IFREG bit is set if handle refers to an ord +inary file.\n" " The read/write bits are set according to the file' +s permission mode.\n" " _S_IFCHR and other constants are defined in SYS\\S +TAT.H.\n" ); printf( "Mode (oct) : 0%06o\n", (unsigned short)buf +.st_mode ); printf( "Mode (hex) : 0x%04x\n", (unsigned short)bu +f.st_mode ); } } }

I included wording from MSDN doc pages on _stat() and _fstat(). The _stat() doc says that "user execute bits are set according to the filename extension.", while the _fstat() doc does NOT mention the "user execute bits".

My observation is that _stat() does what the doc says, while _fstat() silently sets the "user execute bits" to 0. OUCH.

I have found that above code compiles and produces that same results when I replace

stat() by _stat() fstat() by _fstat() struct stat by struct _stat
The later forms are documented in MSDN, while the former are not AFAICS. I am not clear on how does this relate (or not) to the ANSI C standard - IANAL.

HTH

Rudi Farkas rudif@bluemail.ch

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://93038]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (7)
As of 2023-11-30 08:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?