develooper Front page | perl.perl5.porters | Postings from July 2001

Followup to bug ID 20010627.004 : I have a diagnostic

Thread Next
From:
Rudif
Date:
July 2, 2001 00:50
Subject:
Followup to bug ID 20010627.004 : I have a diagnostic
Message ID:
3B3A01E700015A4E@mss2n.bluewin.ch
Hello

I investigated some more the bug ID 20010627.004 that I reported recently
and now 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:

<code>
#!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
</code>

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 test program that demonstrates the misbehavior (IMO) of Win32
fstat():

<code>
// _stattest.cpp : compare MS implementation of functions stat() and fstat()
// 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 directory;\n"
				"    the _S_IFREG bit is set if path specifies an ordinary file or a
device.\n"
				"    User read/write bits are set according to the file’s permission
mode;\n"
				"    user execute bits are set according to the filename extension.\n"
			);
			printf( "Mode (oct)        : 0%06o\n", (unsigned short)buf.st_mode );
			printf( "Mode (hex)        : 0x%04x\n", (unsigned short)buf.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 device.\n"
                "   The _S_IFREG bit is set if handle refers to an ordinary
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\\STAT.H.\n"
            );
			printf( "Mode (oct)        : 0%06o\n", (unsigned short)buf.st_mode );
			printf( "Mode (hex)        : 0x%04x\n", (unsigned short)buf.st_mode );

		}
    }
}

</code>


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






________________________________________
E-Mail for everyone! http://www.bluemail.ch/ powered by Bluewin!


Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About