Alexandre Julliard : user32: Enforce null termination of strings added to the clipboard.
Alexandre Julliard
julliard at winehq.org
Tue Sep 27 11:08:51 CDT 2016
Module: wine
Branch: master
Commit: 8f24641ff382a646ff5b7b0c59666c9a305b948c
URL: http://source.winehq.org/git/wine.git/?a=commit;h=8f24641ff382a646ff5b7b0c59666c9a305b948c
Author: Alexandre Julliard <julliard at winehq.org>
Date: Tue Sep 27 20:28:06 2016 +0900
user32: Enforce null termination of strings added to the clipboard.
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/user32/clipboard.c | 42 +++++++++++---
dlls/user32/tests/clipboard.c | 130 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 164 insertions(+), 8 deletions(-)
diff --git a/dlls/user32/clipboard.c b/dlls/user32/clipboard.c
index a841d7d..9d80813 100644
--- a/dlls/user32/clipboard.c
+++ b/dlls/user32/clipboard.c
@@ -173,6 +173,29 @@ static HANDLE marshal_data( UINT format, HANDLE handle, data_size_t *ret_size )
GlobalUnlock( handle );
return mfbits;
}
+ case CF_UNICODETEXT:
+ {
+ WCHAR *ptr;
+ if (!(size = GlobalSize( handle ))) return 0;
+ if ((data_size_t)size != size) return 0;
+ if (!(ptr = GlobalLock( handle ))) return 0;
+ ptr[(size + 1) / sizeof(WCHAR) - 1] = 0; /* enforce null-termination */
+ GlobalUnlock( handle );
+ *ret_size = size;
+ return handle;
+ }
+ case CF_TEXT:
+ case CF_OEMTEXT:
+ {
+ char *ptr;
+ if (!(size = GlobalSize( handle ))) return 0;
+ if ((data_size_t)size != size) return 0;
+ if (!(ptr = GlobalLock( handle ))) return 0;
+ ptr[size - 1] = 0; /* enforce null-termination */
+ GlobalUnlock( handle );
+ *ret_size = size;
+ return handle;
+ }
default:
if (!(size = GlobalSize( handle ))) return 0;
if ((data_size_t)size != size) return 0;
@@ -382,9 +405,11 @@ static HANDLE render_synthesized_textA( HANDLE data, UINT format, UINT from )
size = len * sizeof(WCHAR);
}
- len = WideCharToMultiByte( codepage, 0, src, size / sizeof(WCHAR), NULL, 0, NULL, NULL );
- if ((ret = GlobalAlloc( GMEM_FIXED, len )))
- WideCharToMultiByte( codepage, 0, src, size / sizeof(WCHAR), ret, len, NULL, NULL );
+ if ((len = WideCharToMultiByte( codepage, 0, src, size / sizeof(WCHAR), NULL, 0, NULL, NULL )))
+ {
+ if ((ret = GlobalAlloc( GMEM_FIXED, len )))
+ WideCharToMultiByte( codepage, 0, src, size / sizeof(WCHAR), ret, len, NULL, NULL );
+ }
done:
HeapFree( GetProcessHeap(), 0, srcW );
@@ -396,16 +421,17 @@ done:
static HANDLE render_synthesized_textW( HANDLE data, UINT from )
{
char *src;
- HANDLE ret;
+ HANDLE ret = 0;
UINT len, size = GlobalSize( data );
UINT codepage = get_format_codepage( get_clipboard_locale(), from );
if (!(src = GlobalLock( data ))) return 0;
- len = MultiByteToWideChar( codepage, 0, src, size, NULL, 0 );
- if ((ret = GlobalAlloc( GMEM_FIXED, len * sizeof(WCHAR) )))
- MultiByteToWideChar( codepage, 0, src, size, ret, len );
-
+ if ((len = MultiByteToWideChar( codepage, 0, src, size, NULL, 0 )))
+ {
+ if ((ret = GlobalAlloc( GMEM_FIXED, len * sizeof(WCHAR) )))
+ MultiByteToWideChar( codepage, 0, src, size, ret, len );
+ }
GlobalUnlock( data );
return ret;
}
diff --git a/dlls/user32/tests/clipboard.c b/dlls/user32/tests/clipboard.c
index 90e1aaa..832eca6 100644
--- a/dlls/user32/tests/clipboard.c
+++ b/dlls/user32/tests/clipboard.c
@@ -2264,6 +2264,130 @@ static void test_GetUpdatedClipboardFormats(void)
ok( count == 4, "wrong count %u\n", count );
}
+static const struct
+{
+ char strA[12];
+ WCHAR strW[12];
+ UINT len;
+} test_data[] =
+{
+ { "foo", {}, 3 }, /* 0 */
+ { "foo", {}, 4 },
+ { "foo\0bar", {}, 7 },
+ { "foo\0bar", {}, 8 },
+ { "", {'f','o','o'}, 3 * sizeof(WCHAR) },
+ { "", {'f','o','o',0}, 4 * sizeof(WCHAR) }, /* 5 */
+ { "", {'f','o','o',0,'b','a','r'}, 7 * sizeof(WCHAR) },
+ { "", {'f','o','o',0,'b','a','r',0}, 8 * sizeof(WCHAR) },
+ { "", {'f','o','o'}, 1 },
+ { "", {'f','o','o'}, 2 },
+ { "", {'f','o','o'}, 5 }, /* 10 */
+ { "", {'f','o','o',0}, 7 },
+ { "", {'f','o','o',0}, 9 },
+};
+
+static void test_string_data(void)
+{
+ UINT i;
+ BOOL r;
+ HANDLE data;
+ char cmd[16];
+ char bufferA[12];
+ WCHAR bufferW[12];
+
+ for (i = 0; i < sizeof(test_data) / sizeof(test_data[0]); i++)
+ {
+ /* 1-byte Unicode strings crash on Win64 */
+#ifdef _WIN64
+ if (!test_data[i].strA[0] && test_data[i].len < sizeof(WCHAR)) continue;
+#endif
+ r = OpenClipboard( 0 );
+ ok( r, "gle %d\n", GetLastError() );
+ r = EmptyClipboard();
+ ok( r, "gle %d\n", GetLastError() );
+ data = GlobalAlloc( GMEM_FIXED, test_data[i].len );
+ if (test_data[i].strA[0])
+ {
+ memcpy( data, test_data[i].strA, test_data[i].len );
+ SetClipboardData( CF_TEXT, data );
+ memcpy( bufferA, test_data[i].strA, test_data[i].len );
+ bufferA[test_data[i].len - 1] = 0;
+ ok( !memcmp( data, bufferA, test_data[i].len ),
+ "%u: wrong data %.*s\n", i, test_data[i].len, (char *)data );
+ }
+ else
+ {
+ memcpy( data, test_data[i].strW, test_data[i].len );
+ SetClipboardData( CF_UNICODETEXT, data );
+ memcpy( bufferW, test_data[i].strW, test_data[i].len );
+ bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0;
+ ok( !memcmp( data, bufferW, test_data[i].len ),
+ "%u: wrong data %s\n", i, wine_dbgstr_wn( data, (test_data[i].len + 1) / sizeof(WCHAR) ));
+ }
+ r = CloseClipboard();
+ ok( r, "gle %d\n", GetLastError() );
+ sprintf( cmd, "string_data %u", i );
+ run_process( cmd );
+ }
+}
+
+static void test_string_data_process( int i )
+{
+ BOOL r;
+ HANDLE data;
+ UINT len, len2;
+ char bufferA[12];
+ WCHAR bufferW[12];
+
+ r = OpenClipboard( 0 );
+ ok( r, "gle %d\n", GetLastError() );
+ if (test_data[i].strA[0])
+ {
+ data = GetClipboardData( CF_TEXT );
+ ok( data != 0, "%u: could not get data\n", i );
+ len = GlobalSize( data );
+ ok( len == test_data[i].len, "%u: wrong size %u / %u\n", i, len, test_data[i].len );
+ memcpy( bufferA, test_data[i].strA, test_data[i].len );
+ bufferA[test_data[i].len - 1] = 0;
+ ok( !memcmp( data, bufferA, len ), "%u: wrong data %.*s\n", i, len, (char *)data );
+ data = GetClipboardData( CF_UNICODETEXT );
+ ok( data != 0, "%u: could not get data\n", i );
+ len = GlobalSize( data );
+ len2 = MultiByteToWideChar( CP_ACP, 0, bufferA, test_data[i].len, bufferW, 12 );
+ ok( len == len2 * sizeof(WCHAR), "%u: wrong size %u / %u\n", i, len, len2 );
+ ok( !memcmp( data, bufferW, len ), "%u: wrong data %s\n", i, wine_dbgstr_wn( data, len2 ));
+ }
+ else
+ {
+ data = GetClipboardData( CF_UNICODETEXT );
+ ok( data != 0, "%u: could not get data\n", i );
+ len = GlobalSize( data );
+ ok( len == test_data[i].len, "%u: wrong size %u / %u\n", i, len, test_data[i].len );
+ memcpy( bufferW, test_data[i].strW, test_data[i].len );
+ bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0;
+ ok( !memcmp( data, bufferW, len ),
+ "%u: wrong data %s\n", i, wine_dbgstr_wn( data, (len + 1) / sizeof(WCHAR) ));
+ data = GetClipboardData( CF_TEXT );
+ if (test_data[i].len >= sizeof(WCHAR))
+ {
+ ok( data != 0, "%u: could not get data\n", i );
+ len = GlobalSize( data );
+ len2 = WideCharToMultiByte( CP_ACP, 0, bufferW, test_data[i].len / sizeof(WCHAR),
+ bufferA, 12, NULL, NULL );
+ bufferA[len2 - 1] = 0;
+ ok( len == len2, "%u: wrong size %u / %u\n", i, len, len2 );
+ ok( !memcmp( data, bufferA, len ), "%u: wrong data %.*s\n", i, len, (char *)data );
+ }
+ else
+ {
+ ok( !data, "%u: got data for empty string\n", i );
+ ok( IsClipboardFormatAvailable( CF_TEXT ), "%u: text not available\n", i );
+ }
+ }
+ r = CloseClipboard();
+ ok( r, "gle %d\n", GetLastError() );
+}
+
START_TEST(clipboard)
{
char **argv;
@@ -2301,6 +2425,11 @@ START_TEST(clipboard)
test_handles_process_dib( argv[3] );
return;
}
+ if (argc == 4 && !strcmp( argv[2], "string_data" ))
+ {
+ test_string_data_process( atoi( argv[3] ));
+ return;
+ }
test_RegisterClipboardFormatA();
test_ClipboardOwner();
@@ -2308,4 +2437,5 @@ START_TEST(clipboard)
test_messages();
test_data_handles();
test_GetUpdatedClipboardFormats();
+ test_string_data();
}
More information about the wine-cvs
mailing list