From 97b39eeca35f5e54429d1ee29a334b7f2e0537c3 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 26 Jan 2020 09:50:07 +0000 Subject: [PATCH] Work around console I/O size limit on Windows 7. A user reports that the ReadFile call in console_get_userpass_input fails with ERROR_NOT_ENOUGH_MEMORY on Windows 7, and further reports that this problem only happens if you tell ReadFile to read more than 31366 bytes in a single call. That seems to be a thing that other people have found as well: I turned up a similar workaround in Ruby's Win32 support module, except that there it's for WriteConsole. So I'm reducing my arbitrary read size of 64K to 16K, which is well under that limit. This issue became noticeable in PuTTY as of the recent commit cd6bc14f0, which reworked console_get_userpass_input to use strbufs. Previously we were trying to read an amount proportional to the existing size of the buffer, so as to grow the buffer exponentially to save quadratic-time reallocation. That was OK in practice, since the initial read size was nice and small. But in principle, the same bug was present in that version of the code, just latent - if we'd ever been called on to read a _really large_ amount of data, then _eventually_ the input size parameter to ReadFile would have grown beyond that mysterious limit! (cherry picked from commit 7b79d22021296e4ae941b383ab34971a9f2b0a1b) --- windows/wincons.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/windows/wincons.c b/windows/wincons.c index 4fb5eb3f..ffc93040 100644 --- a/windows/wincons.c +++ b/windows/wincons.c @@ -504,7 +504,23 @@ int console_get_userpass_input(prompts_t *p) bool failed = false; while (1) { - DWORD toread = 65536; + /* + * Amount of data to try to read from the console in one + * go. This isn't completely arbitrary: a user reported + * that trying to read more than 31366 bytes at a time + * would fail with ERROR_NOT_ENOUGH_MEMORY on Windows 7, + * and Ruby's Win32 support module has evidence of a + * similar workaround: + * + * https://github.com/ruby/ruby/blob/0aa5195262d4193d3accf3e6b9bad236238b816b/win32/win32.c#L6842 + * + * To keep things simple, I stick with a nice round power + * of 2 rather than trying to go to the very limit of that + * bug. (We're typically reading user passphrases and the + * like here, so even this much is overkill really.) + */ + DWORD toread = 16384; + size_t prev_result_len = pr->result->len; void *ptr = strbuf_append(pr->result, toread);