mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-31 11:43:31 +00:00
Added regression test for FormatMessage.
Fixed cr/lf handling. Prevent an infinite loop when an invalid format (%S) is passed as a format string to vsnprintf. Fixed a memory leak in the W version.
This commit is contained in:
parent
49163d5e6a
commit
7018230a3f
4 changed files with 257 additions and 13 deletions
|
@ -279,7 +279,6 @@ DWORD WINAPI FormatMessageA(
|
|||
strcpy( fmtstr, "%s" );
|
||||
}
|
||||
if (args) {
|
||||
int ret;
|
||||
int sz;
|
||||
LPSTR b;
|
||||
|
||||
|
@ -289,18 +288,15 @@ DWORD WINAPI FormatMessageA(
|
|||
argliststart=(*(DWORD**)args)+insertnr-1;
|
||||
|
||||
/* FIXME: precision and width components are not handled correctly */
|
||||
if (strcmp(fmtstr, "%ls") == 0) {
|
||||
if ( (strcmp(fmtstr, "%ls") == 0) || (strcmp(fmtstr,"%S") == 0) ) {
|
||||
sz = WideCharToMultiByte( CP_ACP, 0, *(WCHAR**)argliststart, -1, NULL, 0, NULL, NULL);
|
||||
b = HeapAlloc(GetProcessHeap(), 0, sz);
|
||||
WideCharToMultiByte( CP_ACP, 0, *(WCHAR**)argliststart, -1, b, sz, NULL, NULL);
|
||||
} else {
|
||||
b = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz = 100);
|
||||
b = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz = 1000);
|
||||
/* CMF - This makes a BIG assumption about va_list */
|
||||
TRACE("A BIG assumption\n");
|
||||
while ((ret = vsnprintf(b, sz, fmtstr, (va_list) argliststart) < 0) || (ret >= sz)) {
|
||||
sz = (ret == -1 ? sz + 100 : ret + 1);
|
||||
b = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, b, sz);
|
||||
}
|
||||
vsnprintf(b, sz, fmtstr, (va_list) argliststart);
|
||||
}
|
||||
for (x=b; *x; x++) ADD_TO_T(*x);
|
||||
|
||||
|
@ -334,13 +330,24 @@ DWORD WINAPI FormatMessageA(
|
|||
if (ch == '\r') {
|
||||
if (*f == '\n')
|
||||
f++;
|
||||
ADD_TO_T(' ');
|
||||
} else {
|
||||
if (ch == '\n')
|
||||
if(width)
|
||||
ADD_TO_T(' ');
|
||||
else
|
||||
{
|
||||
ADD_TO_T('\r');
|
||||
ADD_TO_T('\n');
|
||||
}
|
||||
} else {
|
||||
if (ch == '\n')
|
||||
{
|
||||
if(width)
|
||||
ADD_TO_T(' ');
|
||||
else
|
||||
{
|
||||
ADD_TO_T('\r');
|
||||
ADD_TO_T('\n');
|
||||
}
|
||||
}
|
||||
else
|
||||
ADD_TO_T(ch);
|
||||
}
|
||||
|
@ -520,6 +527,7 @@ DWORD WINAPI FormatMessageW(
|
|||
|
||||
/* CMF - This makes a BIG assumption about va_list */
|
||||
vsprintf(sprintfbuf, fmtstr, (va_list) xarr);
|
||||
HeapFree(GetProcessHeap(), 0, (LPVOID) xarr[0]);
|
||||
} else {
|
||||
sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
|
||||
|
||||
|
@ -552,13 +560,24 @@ DWORD WINAPI FormatMessageW(
|
|||
if (ch == '\r') {
|
||||
if (*f == '\n')
|
||||
f++;
|
||||
ADD_TO_T(' ');
|
||||
} else {
|
||||
if (ch == '\n')
|
||||
if(width)
|
||||
ADD_TO_T(' ');
|
||||
else
|
||||
{
|
||||
ADD_TO_T('\r');
|
||||
ADD_TO_T('\n');
|
||||
}
|
||||
} else {
|
||||
if (ch == '\n')
|
||||
{
|
||||
if(width)
|
||||
ADD_TO_T(' ');
|
||||
else
|
||||
{
|
||||
ADD_TO_T('\r');
|
||||
ADD_TO_T('\n');
|
||||
}
|
||||
}
|
||||
else
|
||||
ADD_TO_T(ch);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ atom.ok
|
|||
directory.ok
|
||||
environ.ok
|
||||
file.ok
|
||||
format_msg.ok
|
||||
kernel32_test.exe.spec.c
|
||||
locale.ok
|
||||
path.ok
|
||||
|
|
|
@ -11,6 +11,7 @@ CTESTS = \
|
|||
directory.c \
|
||||
environ.c \
|
||||
file.c \
|
||||
format_msg.c \
|
||||
locale.c \
|
||||
path.c \
|
||||
process.c \
|
||||
|
|
223
dlls/kernel/tests/format_msg.c
Normal file
223
dlls/kernel/tests/format_msg.c
Normal file
|
@ -0,0 +1,223 @@
|
|||
/* Unit test suite for FormatMessageA
|
||||
*
|
||||
* Copyright 2002 Mike McCormack for Codeweavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "winbase.h"
|
||||
|
||||
/* #define ok(cond,failstr) if(!(cond)) {printf("line %d : %s\n",__LINE__,failstr);exit(1);} */
|
||||
|
||||
DWORD doit(DWORD flags, LPCVOID src, DWORD msg_id, DWORD lang_id,
|
||||
LPSTR out, DWORD outsize, ... )
|
||||
{
|
||||
va_list list;
|
||||
DWORD r;
|
||||
|
||||
va_start(list, outsize);
|
||||
r = FormatMessageA(flags, src, msg_id,
|
||||
lang_id, out, outsize, &list);
|
||||
va_end(list);
|
||||
return r;
|
||||
}
|
||||
|
||||
void test_message_from_string(void)
|
||||
{
|
||||
CHAR out[0x100] = {0};
|
||||
DWORD r;
|
||||
WCHAR szwTest[] = { 't','e','s','t',0};
|
||||
|
||||
/* the basics */
|
||||
r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "test", 0,
|
||||
0, out, sizeof out/sizeof (CHAR),NULL);
|
||||
ok(!strcmp("test", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* using the format feature */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!s!", 0,
|
||||
0, out, sizeof out/sizeof (CHAR), "test");
|
||||
ok(!strcmp("test", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* no format */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1", 0,
|
||||
0, out, sizeof out/sizeof (CHAR), "test");
|
||||
ok(!strcmp("test", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* two pieces */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1%2", 0,
|
||||
0, out, sizeof out/sizeof (CHAR), "te","st");
|
||||
ok(!strcmp("test", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* three pieces */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1%3%2%1", 0,
|
||||
0, out, sizeof out/sizeof (CHAR), "t","s","e");
|
||||
ok(!strcmp("test", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* s doesn't seem to work in format strings */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%!s!", 0,
|
||||
0, out, sizeof out/sizeof (CHAR), "test");
|
||||
ok(!strcmp("!s!", out),"failed");
|
||||
ok(r==3,"failed");
|
||||
|
||||
/* S is unicode */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!S!", 0,
|
||||
0, out, sizeof out/sizeof (CHAR), szwTest);
|
||||
ok(!strcmp("test", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* as characters */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!c!%2!c!%3!c!%1!c!", 0,
|
||||
0, out, sizeof out/sizeof (CHAR), 't','e','s');
|
||||
ok(!strcmp("test", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* some numbers */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!d!%2!d!%3!d!", 0,
|
||||
0, out, sizeof out/sizeof (CHAR), 1,2,3);
|
||||
ok(!strcmp("123", out),"failed");
|
||||
ok(r==3,"failed");
|
||||
|
||||
/* a single digit with some spacing */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4d!", 0,
|
||||
0, out, sizeof out/sizeof (CHAR), 1);
|
||||
ok(!strcmp(" 1", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* a single digit, left justified */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!-4d!", 0,
|
||||
0, out, sizeof out/sizeof (CHAR), 1);
|
||||
ok(!strcmp("1 ", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* two digit decimal number */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4d!", 0,
|
||||
0, out, sizeof out/sizeof (CHAR), 11);
|
||||
ok(!strcmp(" 11", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* a hex number */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4x!", 0,
|
||||
0, out, sizeof out/sizeof (CHAR), 11);
|
||||
ok(!strcmp(" b", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* a hex number, upper case */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4X!", 0,
|
||||
0, out, sizeof out/sizeof (CHAR), 11);
|
||||
ok(!strcmp(" B", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* a hex number, upper case, left justified */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!-4X!", 0,
|
||||
0, out, sizeof out/sizeof (CHAR), 11);
|
||||
ok(!strcmp("B ", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* a long hex number, upper case */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4X!", 0,
|
||||
0, out, sizeof out/sizeof (CHAR), 0x1ab);
|
||||
ok(!strcmp(" 1AB", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* two percent... */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, " %%%% ", 0,
|
||||
0, out, sizeof out/sizeof (CHAR));
|
||||
ok(!strcmp(" %% ", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* periods are special cases */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, " %.%. %1!d!", 0,
|
||||
0, out, sizeof out/sizeof (CHAR), 0x1ab);
|
||||
ok(!strcmp(" .. 427", out),"failed");
|
||||
ok(r==7,"failed");
|
||||
|
||||
/* %0 ends the line */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "test%0test", 0,
|
||||
0, out, sizeof out/sizeof (CHAR));
|
||||
ok(!strcmp("test", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* %! prints an exclaimation */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "yah%!%0 ", 0,
|
||||
0, out, sizeof out/sizeof (CHAR));
|
||||
ok(!strcmp("yah!", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* %space */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "% % ", 0,
|
||||
0, out, sizeof out/sizeof (CHAR));
|
||||
ok(!strcmp(" ", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* line feed */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "hi\n", 0,
|
||||
0, out, sizeof out/sizeof (CHAR));
|
||||
ok(!strcmp("hi\r\n", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* carriage return line feed */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "hi\r\n", 0,
|
||||
0, out, sizeof out/sizeof (CHAR));
|
||||
ok(!strcmp("hi\r\n", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* carriage return line feed */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "\r", 0,
|
||||
0, out, sizeof out/sizeof (CHAR));
|
||||
ok(!strcmp("\r\n", out),"failed");
|
||||
ok(r==2,"failed");
|
||||
|
||||
/* carriage return line feed */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "\r\r\n", 0,
|
||||
0, out, sizeof out/sizeof (CHAR));
|
||||
ok(!strcmp("\r\n\r\n", out),"failed");
|
||||
ok(r==4,"failed");
|
||||
|
||||
/* change of pace... test the low byte of dwflags */
|
||||
/* line feed */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, "hi\n", 0,
|
||||
0, out, sizeof out/sizeof (CHAR));
|
||||
ok(!strcmp("hi ", out),"failed");
|
||||
ok(r==3,"failed");
|
||||
|
||||
/* carriage return line feed */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, "hi\r\n", 0,
|
||||
0, out, sizeof out/sizeof (CHAR));
|
||||
ok(!strcmp("hi ", out),"failed");
|
||||
ok(r==3,"failed");
|
||||
|
||||
/* carriage return line feed */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, "\r", 0,
|
||||
0, out, sizeof out/sizeof (CHAR));
|
||||
ok(!strcmp(" ", out),"failed");
|
||||
ok(r==1,"failed");
|
||||
|
||||
/* carriage return line feed */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, "\r\r\n", 0,
|
||||
0, out, sizeof out/sizeof (CHAR));
|
||||
ok(!strcmp(" ", out),"failed");
|
||||
ok(r==2,"failed");
|
||||
}
|
||||
|
||||
START_TEST(format_msg)
|
||||
{
|
||||
test_message_from_string();
|
||||
}
|
Loading…
Reference in a new issue