Skip to content

Commit

Permalink
win,tty: fix MultiByteToWideChar output buffer
Browse files Browse the repository at this point in the history
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: libuv#1143
Refs: libuv#1138
Refs: libuv#889
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
Reviewed-By: Imran Iqbal <imran@imraniqbal.org>
  • Loading branch information
santigimeno committed Nov 29, 2016
1 parent 445e3a1 commit c2f0e4f
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 36 deletions.
88 changes: 55 additions & 33 deletions src/win/tty.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;

#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)
unsigned int i, len, max_len, pos;
int allocate = 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) { \
Expand All @@ -1644,38 +1657,47 @@ 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;
}

if (!MultiByteToWideChar(CP_UTF8,
0,
buf.base,
buf.len,
utf16_buf,
utf16_buf_used)) {
*error = GetLastError();
break;
}
FLUSH_TEXT();

FLUSH_TEXT();
continue;
}
continue;
}

for (j = 0; j < buf.len; j++) {
unsigned char c = buf.base[j];
Expand Down
2 changes: 2 additions & 0 deletions test/test-list.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
51 changes: 48 additions & 3 deletions test/test-tty.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;

Expand All @@ -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


Expand Down

0 comments on commit c2f0e4f

Please sign in to comment.