From bcc297ea4d1ebb11f1b89387f461b3d69d276c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Grubbstr=C3=B6m=20=28Grubba=29?= <grubba@grubba.org> Date: Thu, 26 Mar 2015 14:09:17 +0100 Subject: [PATCH] I/O [NT]: Reading from the console on NT may fail with ENOMEM. Reading from the console on NT uses system buffers of limited size (nominal limit 64K, in practice 26608 or 31004 bytes), and will fail with ERROR_NOT_ENOUGH_MEMORY if an attempt is made to read more data than the limit. Fixes interactive Hilfe terminating with "Terminal closed." on start on NT. --- src/fdlib.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/src/fdlib.c b/src/fdlib.c index 90d209214f..a22d751e9c 100644 --- a/src/fdlib.c +++ b/src/fdlib.c @@ -2134,17 +2134,46 @@ PMOD_EXPORT ptrdiff_t debug_fd_read(FD fd, void *to, ptrdiff_t len) } ret=0; - if(len && !ReadFile(handle, to, - DO_NOT_WARN((DWORD)len), - &ret,0) && ret<=0) - { + while(len && !ReadFile(handle, to, + DO_NOT_WARN((DWORD)len), + &ret,0) && ret<=0) { unsigned int err = GetLastError(); release_fd(fd); set_errno_from_win32_error (err); switch(err) { - /* Pretend we reached the end of the file */ + case ERROR_NOT_ENOUGH_MEMORY: + /* This can happen when reading from stdin, and can be due + * to running out of OS io-buffers. cf ReadConsole(): + * + * | lpBuffer [out] + * | A pointer to a buffer that receives the data read from + * | the console input buffer. + * | + * | The storage for this buffer is allocated from a shared + * | heap for the process that is 64 KB in size. The maximum + * | size of the buffer will depend on heap usage. + * + * The limit seems to be 26608 bytes on Windows Server 2003, + * and 31004 bytes on some versions of Windows XP. + * + * The gdb people ran into the same bug in 2006. + * cf http://permalink.gmane.org/gmane.comp.gdb.patches/29669 + * + * FIXME: We ought to attempt to fill the remainder of + * the buffer on success and full read, but as + * this failure mode usually only happens with + * the console, we would risk blocking, so let + * the higher levels of code deal with the + * resulting short reads. + */ + /* Halve the size of the request and retry. */ + len = len >> 1; + if (len) continue; + /* Total failure. Fall out to the generic error return. */ + break; case ERROR_BROKEN_PIPE: + /* Pretend we reached the end of the file */ return 0; } FDDEBUG(fprintf(stderr,"Read failed %d\n",errno)); -- GitLab