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)

Reply via email to