win,tty: fix MultiByteToWideChar output buffer

Make sure there's enough room in the output buffer by dynamically
allocating memory in case the size of the buffer needs to be greater
than 8192 characters.

PR-URL: https://github.com/libuv/libuv/pull/1143
Refs: https://github.com/libuv/libuv/pull/1138
Refs: https://github.com/libuv/libuv/pull/889
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
Reviewed-By: Imran Iqbal <imran@imraniqbal.org>
This commit is contained in:
Santiago Gimeno 2016-11-16 16:17:12 +01:00
parent 445e3a1f06
commit c2f0e4f64e
No known key found for this signature in database
GPG Key ID: F28C3C8DA33C03BE
3 changed files with 105 additions and 36 deletions

View File

@ -56,6 +56,7 @@
#define ANSI_BACKSLASH_SEEN 0x80
#define MAX_INPUT_BUFFER_LENGTH 8192
#define MAX_CONSOLE_CHAR 8192
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
@ -1616,17 +1617,29 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
DWORD* error) {
/* We can only write 8k characters at a time. Windows can't handle */
/* much more characters in a single console write anyway. */
WCHAR utf16_buf[8192];
WCHAR utf16_buf[MAX_CONSOLE_CHAR];
WCHAR* utf16_buffer;
DWORD utf16_buf_used = 0;
unsigned int i;
unsigned int i, len, max_len, pos;
int allocate = 0;
#define FLUSH_TEXT() \
do { \
if (utf16_buf_used > 0) { \
uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \
utf16_buf_used = 0; \
} \
} while (0)
#define FLUSH_TEXT() \
do { \
pos = 0; \
do { \
len = utf16_buf_used - pos; \
if (len > MAX_CONSOLE_CHAR) \
len = MAX_CONSOLE_CHAR; \
uv_tty_emit_text(handle, &utf16_buffer[pos], len, error); \
pos += len; \
} while (pos < utf16_buf_used); \
if (allocate) { \
uv__free(utf16_buffer); \
allocate = 0; \
utf16_buffer = utf16_buf; \
} \
utf16_buf_used = 0; \
} while (0)
#define ENSURE_BUFFER_SPACE(wchars_needed) \
if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { \
@ -1644,39 +1657,48 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
/* state. */
*error = ERROR_SUCCESS;
utf16_buffer = utf16_buf;
uv_sem_wait(&uv_tty_output_lock);
for (i = 0; i < nbufs; i++) {
uv_buf_t buf = bufs[i];
unsigned int j;
if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) {
utf16_buf_used = MultiByteToWideChar(CP_UTF8,
0,
buf.base,
buf.len,
NULL,
0);
if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) {
utf16_buf_used = MultiByteToWideChar(CP_UTF8,
0,
buf.base,
buf.len,
NULL,
0);
if (utf16_buf_used == 0) {
*error = GetLastError();
break;
if (utf16_buf_used == 0) {
*error = GetLastError();
break;
}
max_len = (utf16_buf_used + 1) * sizeof(WCHAR);
allocate = max_len > MAX_CONSOLE_CHAR;
if (allocate)
utf16_buffer = uv__malloc(max_len);
if (!MultiByteToWideChar(CP_UTF8,
0,
buf.base,
buf.len,
utf16_buffer,
utf16_buf_used)) {
if (allocate)
uv__free(utf16_buffer);
*error = GetLastError();
break;
}
FLUSH_TEXT();
continue;
}
if (!MultiByteToWideChar(CP_UTF8,
0,
buf.base,
buf.len,
utf16_buf,
utf16_buf_used)) {
*error = GetLastError();
break;
}
FLUSH_TEXT();
continue;
}
for (j = 0; j < buf.len; j++) {
unsigned char c = buf.base[j];

View File

@ -48,6 +48,7 @@ TEST_DECLARE (tty)
#ifdef _WIN32
TEST_DECLARE (tty_raw)
TEST_DECLARE (tty_empty_write)
TEST_DECLARE (tty_large_write)
#endif
TEST_DECLARE (tty_file)
TEST_DECLARE (tty_pty)
@ -406,6 +407,7 @@ TASK_LIST_START
#ifdef _WIN32
TEST_ENTRY (tty_raw)
TEST_ENTRY (tty_empty_write)
TEST_ENTRY (tty_large_write)
#endif
TEST_ENTRY (tty_file)
TEST_ENTRY (tty_pty)

View File

@ -217,11 +217,15 @@ TEST_IMPL(tty_empty_write) {
int r;
int ttyout_fd;
uv_tty_t tty_out;
uv_loop_t* loop = uv_default_loop();
char dummy[1];
uv_buf_t bufs[1];
uv_loop_t* loop;
/* Make sure we have an FD that refers to a tty */
HANDLE handle;
loop = uv_default_loop();
handle = CreateFileA("conout$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
@ -239,8 +243,6 @@ TEST_IMPL(tty_empty_write) {
r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */
ASSERT(r == 0);
char dummy[1];
uv_buf_t bufs[1];
bufs[0].len = 0;
bufs[0].base = &dummy;
@ -254,6 +256,49 @@ TEST_IMPL(tty_empty_write) {
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(tty_large_write) {
int r;
int ttyout_fd;
uv_tty_t tty_out;
char dummy[10000];
uv_buf_t bufs[1];
uv_loop_t* loop;
/* Make sure we have an FD that refers to a tty */
HANDLE handle;
loop = uv_default_loop();
handle = CreateFileA("conout$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
ASSERT(handle != INVALID_HANDLE_VALUE);
ttyout_fd = _open_osfhandle((intptr_t) handle, 0);
ASSERT(ttyout_fd >= 0);
ASSERT(UV_TTY == uv_guess_handle(ttyout_fd));
r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */
ASSERT(r == 0);
bufs[0] = uv_buf_init(dummy, sizeof(dummy));
r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1);
ASSERT(r == 10000);
uv_close((uv_handle_t*) &tty_out, NULL);
uv_run(loop, UV_RUN_DEFAULT);
MAKE_VALGRIND_HAPPY();
return 0;
}
#endif