This report is filed against Makeinfo 4.0, compiled for the Cygwin B20.1
package from Cygnus Solutions, running on Windows NT 4.0 SP6 (Intel x86).
There is a problem in the "find_and_load" routine in "files.c" that causes
failures on Cygwin (Win32) systems. The Cygwin package defines the symbol
"O_BINARY" but does not define the symbol "WIN32" (which is intended
behavior), so the code at line 172 of files.c will be compiled. This line
attempts to read from the file repeatedly until EOF is encountered.
Unfortunately, every read specifies a requested number of bytes that
corresponds to the full file size, even as the read buffer pointer is being
incremented to account for each previously successful read. The result is
that call to "read" are being made that specify buffer areas beyond the end
of the actual allocated space.
This is an error that wouldn't normally matter, as any remaining bytes in
the file will fit wholly within the originally allocated buffer. However,
the Cygnus implementation of "read" checks to ensure that the entire buffer
is writable before actually retrieving the file data. This check fails if
the buffer allocation is near the end of a physical memory page and the
next page is not readable. In this case, "read" fails with a "-1" error,
and find_and_load therefore fails, causing makeinfo to terminate.
A test case is to attempt to "makeinfo gcc.texi" under Cygwin. This fails
with "gcc.texi: Permission denied"; the failure occurs on the second
iteration of line 172.
A correction would be to issue reads only for the number of bytes remaining
in the buffer. Therefore, the buffer accessibility check will not fail,
and makeinfo will work properly.
A diff is appended that illustrates a possible fix.
As an additional note for the same routine, it appears that special Win32
code is provided which reads from the target file one byte at a time (line
175). This does not appear, or at least no longer appears, to be
necessary. Both the MSVC and CRTDLL versions of the "mingw32" Win32
implementation work fine with the full-file-size read of line 172. I have
verified this both on Windows NT 4.0 and Windows 98. Moreover, the full-
size read is about ten times faster overall than reading one byte at a
time.
If I may clarify any aspect of this report, please do not hesitate to
contact me.
-- Dave Bryan
------------------------------------------------------------
diff -c makeinfo-orig/files.c makeinfo/files.c
*** makeinfo-orig/files.c Tue Mar 23 16:42:44 1999
--- makeinfo/files.c Sat Mar 11 18:42:57 2000
***************
*** 140,146 ****
int file = -1, count = 0;
char *fullpath, *result;
#if O_BINARY || defined (VMS)
! int n;
#endif
result = fullpath = NULL;
--- 140,146 ----
int file = -1, count = 0;
char *fullpath, *result;
#if O_BINARY || defined (VMS)
! int n, bytes_to_read;
#endif
result = fullpath = NULL;
***************
*** 165,181 ****
mysteries of VMS/RMS are too much to probe, so this hack
suffices to make things work. */
#if O_BINARY || defined (VMS)
#ifdef VMS
while ((n = read (file, result + count, file_size)) > 0)
#else /* !VMS */
#ifndef WIN32
! while ((n = read (file, result + count, file_size)) > 0)
#else /* WIN32 */
/* Does WIN32 really need reading 1 character at a time?? */
while ((n = read (file, result + count, 1)) > 0)
#endif /* WIN32 */
#endif /* !VMS */
count += n;
if (0 < count && count < file_size)
result = xrealloc (result, count + 2); /* why waste the slack? */
else if (n == -1)
--- 165,185 ----
mysteries of VMS/RMS are too much to probe, so this hack
suffices to make things work. */
#if O_BINARY || defined (VMS)
+ bytes_to_read = file_size;
#ifdef VMS
while ((n = read (file, result + count, file_size)) > 0)
#else /* !VMS */
#ifndef WIN32
! while ((n = read (file, result + count, bytes_to_read)) > 0)
#else /* WIN32 */
/* Does WIN32 really need reading 1 character at a time?? */
while ((n = read (file, result + count, 1)) > 0)
#endif /* WIN32 */
#endif /* !VMS */
+ {
count += n;
+ bytes_to_read -= n;
+ }
if (0 < count && count < file_size)
result = xrealloc (result, count + 2); /* why waste the slack? */
else if (n == -1)