Skip to content

Commit

Permalink
Get rid of PERL_MSVCRT_READFIX
Browse files Browse the repository at this point in the history
The code works around a bug in very old versions of MSVCRT.dll.
The issue has been fixed a long time ago by Microsoft, so anyone
who has installed a Windows Service Pack in the last 10 years
or so won't be affected by the problem.
  • Loading branch information
jandubois committed Dec 7, 2010
1 parent 7ffd658 commit 9b1f181
Show file tree
Hide file tree
Showing 5 changed files with 1 addition and 276 deletions.
7 changes: 0 additions & 7 deletions win32/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -473,13 +473,6 @@ BUILDOPT = $(BUILDOPT) -D_USE_32BIT_TIME_T
! ENDIF
!ENDIF

# Use the MSVCRT read() fix only when using VC++ 6.x or earlier. Later
# versions use MSVCR70.dll, MSVCR71.dll, etc, which do not require the
# fix.
!IF "$(CCTYPE)" == "MSVC60"
BUILDOPT = $(BUILDOPT) -DPERL_MSVCRT_READFIX
!ENDIF

LIBBASEFILES = $(CRYPT_LIB) \
oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib \
comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib \
Expand Down
11 changes: 1 addition & 10 deletions win32/makefile.mk
Original file line number Diff line number Diff line change
Expand Up @@ -555,9 +555,7 @@ OBJOUT_FLAG = -o
EXEOUT_FLAG = -o
LIBOUT_FLAG =

# NOTE: we assume that GCC uses MSVCRT.DLL
# See comments about PERL_MSVCRT_READFIX in the "cl" compiler section below.
BUILDOPT += -fno-strict-aliasing -mms-bitfields -DPERL_MSVCRT_READFIX
BUILDOPT += -fno-strict-aliasing -mms-bitfields

.ELSE

Expand Down Expand Up @@ -631,13 +629,6 @@ BUILDOPT += -D_USE_32BIT_TIME_T
.ENDIF
.ENDIF

# Use the MSVCRT read() fix only when using VC++ 6.x or earlier. Later
# versions use MSVCR70.dll, MSVCR71.dll, etc, which do not require the
# fix.
.IF "$(CCTYPE)" == "MSVC60"
BUILDOPT += -DPERL_MSVCRT_READFIX
.ENDIF

LIBBASEFILES = $(CRYPT_LIB) \
oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib \
comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib \
Expand Down
200 changes: 0 additions & 200 deletions win32/win32.c
Original file line number Diff line number Diff line change
Expand Up @@ -3171,210 +3171,10 @@ win32_dup2(int fd1,int fd2)
return dup2(fd1,fd2);
}

#ifdef PERL_MSVCRT_READFIX

#define LF 10 /* line feed */
#define CR 13 /* carriage return */
#define CTRLZ 26 /* ctrl-z means eof for text */
#define FOPEN 0x01 /* file handle open */
#define FEOFLAG 0x02 /* end of file has been encountered */
#define FCRLF 0x04 /* CR-LF across read buffer (in text mode) */
#define FPIPE 0x08 /* file handle refers to a pipe */
#define FAPPEND 0x20 /* file handle opened O_APPEND */
#define FDEV 0x40 /* file handle refers to device */
#define FTEXT 0x80 /* file handle is in text mode */
#define MAX_DESCRIPTOR_COUNT (64*32) /* this is the maximun that MSVCRT can handle */

int __cdecl
_fixed_read(int fh, void *buf, unsigned cnt)
{
int bytes_read; /* number of bytes read */
char *buffer; /* buffer to read to */
int os_read; /* bytes read on OS call */
char *p, *q; /* pointers into buffer */
char peekchr; /* peek-ahead character */
ULONG filepos; /* file position after seek */
ULONG dosretval; /* o.s. return value */

/* validate handle */
if (((unsigned)fh >= (unsigned)MAX_DESCRIPTOR_COUNT) ||
!(_osfile(fh) & FOPEN))
{
/* out of range -- return error */
errno = EBADF;
_doserrno = 0; /* not o.s. error */
return -1;
}

/*
* If lockinitflag is FALSE, assume fd is device
* lockinitflag is set to TRUE by open.
*/
if (_pioinfo(fh)->lockinitflag)
EnterCriticalSection(&(_pioinfo(fh)->lock)); /* lock file */

bytes_read = 0; /* nothing read yet */
buffer = (char*)buf;

if (cnt == 0 || (_osfile(fh) & FEOFLAG)) {
/* nothing to read or at EOF, so return 0 read */
goto functionexit;
}

if ((_osfile(fh) & (FPIPE|FDEV)) && _pipech(fh) != LF) {
/* a pipe/device and pipe lookahead non-empty: read the lookahead
* char */
*buffer++ = _pipech(fh);
++bytes_read;
--cnt;
_pipech(fh) = LF; /* mark as empty */
}

/* read the data */

if (!ReadFile((HANDLE)_osfhnd(fh), buffer, cnt, (LPDWORD)&os_read, NULL))
{
/* ReadFile has reported an error. recognize two special cases.
*
* 1. map ERROR_ACCESS_DENIED to EBADF
*
* 2. just return 0 if ERROR_BROKEN_PIPE has occurred. it
* means the handle is a read-handle on a pipe for which
* all write-handles have been closed and all data has been
* read. */

if ((dosretval = GetLastError()) == ERROR_ACCESS_DENIED) {
/* wrong read/write mode should return EBADF, not EACCES */
errno = EBADF;
_doserrno = dosretval;
bytes_read = -1;
goto functionexit;
}
else if (dosretval == ERROR_BROKEN_PIPE) {
bytes_read = 0;
goto functionexit;
}
else {
bytes_read = -1;
goto functionexit;
}
}

bytes_read += os_read; /* update bytes read */

if (_osfile(fh) & FTEXT) {
/* now must translate CR-LFs to LFs in the buffer */

/* set CRLF flag to indicate LF at beginning of buffer */
/* if ((os_read != 0) && (*(char *)buf == LF)) */
/* _osfile(fh) |= FCRLF; */
/* else */
/* _osfile(fh) &= ~FCRLF; */

_osfile(fh) &= ~FCRLF;

/* convert chars in the buffer: p is src, q is dest */
p = q = (char*)buf;
while (p < (char *)buf + bytes_read) {
if (*p == CTRLZ) {
/* if fh is not a device, set ctrl-z flag */
if (!(_osfile(fh) & FDEV))
_osfile(fh) |= FEOFLAG;
break; /* stop translating */
}
else if (*p != CR)
*q++ = *p++;
else {
/* *p is CR, so must check next char for LF */
if (p < (char *)buf + bytes_read - 1) {
if (*(p+1) == LF) {
p += 2;
*q++ = LF; /* convert CR-LF to LF */
}
else
*q++ = *p++; /* store char normally */
}
else {
/* This is the hard part. We found a CR at end of
buffer. We must peek ahead to see if next char
is an LF. */
++p;

dosretval = 0;
if (!ReadFile((HANDLE)_osfhnd(fh), &peekchr, 1,
(LPDWORD)&os_read, NULL))
dosretval = GetLastError();

if (dosretval != 0 || os_read == 0) {
/* couldn't read ahead, store CR */
*q++ = CR;
}
else {
/* peekchr now has the extra character -- we now
have several possibilities:
1. disk file and char is not LF; just seek back
and copy CR
2. disk file and char is LF; store LF, don't seek back
3. pipe/device and char is LF; store LF.
4. pipe/device and char isn't LF, store CR and
put char in pipe lookahead buffer. */
if (_osfile(fh) & (FDEV|FPIPE)) {
/* non-seekable device */
if (peekchr == LF)
*q++ = LF;
else {
*q++ = CR;
_pipech(fh) = peekchr;
}
}
else {
/* disk file */
if (peekchr == LF) {
/* nothing read yet; must make some
progress */
*q++ = LF;
/* turn on this flag for tell routine */
_osfile(fh) |= FCRLF;
}
else {
HANDLE osHandle; /* o.s. handle value */
/* seek back */
if ((osHandle = (HANDLE)_get_osfhandle(fh)) != (HANDLE)-1)
{
if ((filepos = SetFilePointer(osHandle, -1, NULL, FILE_CURRENT)) == -1)
dosretval = GetLastError();
}
if (peekchr != LF)
*q++ = CR;
}
}
}
}
}
}

/* we now change bytes_read to reflect the true number of chars
in the buffer */
bytes_read = q - (char *)buf;
}

functionexit:
if (_pioinfo(fh)->lockinitflag)
LeaveCriticalSection(&(_pioinfo(fh)->lock)); /* unlock file */

return bytes_read;
}

#endif /* PERL_MSVCRT_READFIX */

DllExport int
win32_read(int fd, void *buf, unsigned int cnt)
{
#ifdef PERL_MSVCRT_READFIX
return _fixed_read(fd, buf, cnt);
#else
return read(fd, buf, cnt);
#endif
}

DllExport int
Expand Down
53 changes: 0 additions & 53 deletions win32/win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -518,59 +518,6 @@ DllExport int win32_async_check(pTHX);
} STMT_END
#endif

#if defined(USE_FIXED_OSFHANDLE) || defined(PERL_MSVCRT_READFIX)
#ifdef PERL_CORE

/* C doesn't like repeat struct definitions */
#if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION>=3)
#undef _CRTIMP
#endif
#ifndef _CRTIMP
#define _CRTIMP __declspec(dllimport)
#endif

/*
* Control structure for lowio file handles
*/
typedef struct {
intptr_t osfhnd;/* underlying OS file HANDLE */
char osfile; /* attributes of file (e.g., open in text mode?) */
char pipech; /* one char buffer for handles opened on pipes */
int lockinitflag;
CRITICAL_SECTION lock;
} ioinfo;


/*
* Array of arrays of control structures for lowio files.
*/
EXTERN_C _CRTIMP ioinfo* __pioinfo[];

/*
* Definition of IOINFO_L2E, the log base 2 of the number of elements in each
* array of ioinfo structs.
*/
#define IOINFO_L2E 5

/*
* Definition of IOINFO_ARRAY_ELTS, the number of elements in ioinfo array
*/
#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)

/*
* Access macros for getting at an ioinfo struct and its fields from a
* file handle
*/
#define _pioinfo(i) (__pioinfo[(i) >> IOINFO_L2E] + ((i) & (IOINFO_ARRAY_ELTS - 1)))
#define _osfhnd(i) (_pioinfo(i)->osfhnd)
#define _osfile(i) (_pioinfo(i)->osfile)
#define _pipech(i) (_pioinfo(i)->pipech)

/* since we are not doing a dup2(), this works fine */
#define _set_osfhnd(fh, osfh) (void)(_osfhnd(fh) = (intptr_t)osfh)
#endif
#endif

/* IO.xs and POSIX.xs define PERLIO_NOT_STDIO to 1 */
#if defined(PERL_EXT_IO) || defined(PERL_EXT_POSIX)
#undef PERLIO_NOT_STDIO
Expand Down
6 changes: 0 additions & 6 deletions win32/win32sck.c
Original file line number Diff line number Diff line change
Expand Up @@ -473,9 +473,6 @@ int my_close(int fd)
int err;
err = closesocket(osf);
if (err == 0) {
#if defined(USE_FIXED_OSFHANDLE) || defined(PERL_MSVCRT_READFIX)
_set_osfhnd(fd, INVALID_HANDLE_VALUE);
#endif
(void)close(fd); /* handle already closed, ignore error */
return 0;
}
Expand Down Expand Up @@ -504,9 +501,6 @@ my_fclose (FILE *pf)
win32_fflush(pf);
err = closesocket(osf);
if (err == 0) {
#if defined(USE_FIXED_OSFHANDLE) || defined(PERL_MSVCRT_READFIX)
_set_osfhnd(win32_fileno(pf), INVALID_HANDLE_VALUE);
#endif
(void)fclose(pf); /* handle already closed, ignore error */
return 0;
}
Expand Down

0 comments on commit 9b1f181

Please sign in to comment.