user32: Fix a SetClipboardData() buffer overflow.

Wine would append a correctly aligned NUL Unicode character to
terminate the string but overflow the buffer by one byte for odd-sized
strings.
Windows instead overwrites the last two buffer bytes with a NUL Unicode
character which ends up being misaligned for odd-sized strings.
The clipboard data has a size field anyway so match the Windows
behavior.
Tweak the tests to show that SetClipboardData() can overwrite half of
the Unicode string's last character.
This commit is contained in:
Francois Gouget 2022-12-21 18:48:29 +01:00 committed by Alexandre Julliard
parent ee4f8cbb20
commit 605ecafa67
2 changed files with 10 additions and 9 deletions

View file

@ -157,12 +157,13 @@ static HANDLE marshal_data( UINT format, HANDLE handle, size_t *ret_size )
}
case CF_UNICODETEXT:
{
WCHAR *ptr;
char *ptr;
if (!(size = GlobalSize( handle ))) return 0;
if ((data_size_t)size != size) return 0;
if (size < sizeof(WCHAR)) return 0;
if (!(ptr = GlobalLock( handle ))) return 0;
ptr[(size + 1) / sizeof(WCHAR) - 1] = 0; /* enforce null-termination */
/* enforce nul-termination the Windows way: ignoring alignment */
*((WCHAR *)(ptr + size) - 1) = 0;
GlobalUnlock( handle );
*ret_size = size;
return handle;

View file

@ -2224,11 +2224,11 @@ static const struct
{ "", {}, 0 },
{ "", {'f'}, 1 }, /* 5 */
{ "", {'f'}, 2 },
{ "", {'f','o','o'}, 5 },
{ "", {'f','o','o'}, 6 },
{ "", {'f','o','o',0}, 7 }, /* 10 */
{ "", {'f','o','o',0}, 8 },
{ "", {'f','o','o',0,'b'}, 9 },
{ "", {0x3b1,0x3b2,0x3b3}, 5 }, /* Alpha, beta, ... */
{ "", {0x3b1,0x3b2,0x3b3}, 6 },
{ "", {0x3b1,0x3b2,0x3b3,0}, 7 }, /* 10 */
{ "", {0x3b1,0x3b2,0x3b3,0}, 8 },
{ "", {0x3b1,0x3b2,0x3b3,0,0x3b4}, 9 },
{ "", {'f','o','o',0,'b','a','r'}, 7 * sizeof(WCHAR) },
{ "", {'f','o','o',0,'b','a','r',0}, 8 * sizeof(WCHAR) },
};
@ -2274,7 +2274,7 @@ static void test_string_data(void)
{
ok( clip == data, "SetClipboardData() returned %p != %p\n", clip, data );
memcpy( bufferW, test_data[i].strW, test_data[i].len );
bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0;
*((WCHAR *)((char *)bufferW + test_data[i].len) - 1) = 0;
ok( !memcmp( data, bufferW, test_data[i].len ),
"wrong data %s\n", wine_dbgstr_an( data, test_data[i].len ));
}
@ -2336,7 +2336,7 @@ static void test_string_data_process( int i )
len = GlobalSize( data );
ok( len == test_data[i].len, "wrong size %u / %u\n", 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;
*((WCHAR *)((char *)bufferW + test_data[i].len) - 1) = 0;
ok( !memcmp( data, bufferW, len ), "wrong data %s\n", wine_dbgstr_an( data, len ));
}