mirror of
https://github.com/reactos/reactos.git
synced 2025-01-03 21:09:19 +00:00
7c14c0ed73
Avoid buffer overflow. CORE-15289, CORE-11700
345 lines
11 KiB
C
345 lines
11 KiB
C
/*
|
|
* PROJECT: ReactOS API tests
|
|
* LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
|
|
* PURPOSE: debugging and analysis of message states
|
|
* COPYRIGHT: Copyright 2019-2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
#include "undocuser.h"
|
|
#include "winxx.h"
|
|
#include <imm.h>
|
|
#include <strsafe.h>
|
|
|
|
#define MAX_MSGS 512
|
|
|
|
static MSG s_Msgs[MAX_MSGS];
|
|
static UINT s_cMsgs = 0;
|
|
static CHAR s_prefix[16] = "";
|
|
static HWND s_hMainWnd = NULL;
|
|
static HWND s_hwndEdit = NULL;
|
|
static HWND s_hImeWnd = NULL;
|
|
static WNDPROC s_fnOldEditWndProc = NULL;
|
|
static WNDPROC s_fnOldImeWndProc = NULL;
|
|
|
|
static void MsgDumpPrintf(LPCSTR fmt, ...)
|
|
{
|
|
static char s_szText[1024];
|
|
va_list va;
|
|
va_start(va, fmt);
|
|
StringCbVPrintfA(s_szText, sizeof(s_szText), fmt, va);
|
|
trace("%s", s_szText);
|
|
va_end(va);
|
|
}
|
|
#define MSGDUMP_TPRINTF MsgDumpPrintf
|
|
#define MSGDUMP_PREFIX s_prefix
|
|
#include "msgdump.h" /* msgdump.h needs MSGDUMP_TPRINTF and MSGDUMP_PREFIX */
|
|
|
|
static void MD_build_prefix(void)
|
|
{
|
|
DWORD Flags = InSendMessageEx(NULL);
|
|
INT i = 0;
|
|
|
|
if (Flags & ISMEX_CALLBACK)
|
|
s_prefix[i++] = 'C';
|
|
if (Flags & ISMEX_NOTIFY)
|
|
s_prefix[i++] = 'N';
|
|
if (Flags & ISMEX_REPLIED)
|
|
s_prefix[i++] = 'R';
|
|
if (Flags & ISMEX_SEND)
|
|
s_prefix[i++] = 'S';
|
|
if (i == 0)
|
|
s_prefix[i++] = 'P';
|
|
|
|
s_prefix[i++] = ':';
|
|
s_prefix[i++] = ' ';
|
|
s_prefix[i] = 0;
|
|
}
|
|
|
|
#define STAGE_1 1
|
|
#define STAGE_2 2
|
|
#define STAGE_3 3
|
|
#define STAGE_4 4
|
|
#define STAGE_5 5
|
|
|
|
static INT findMessage(INT iMsg, HWND hwnd, UINT uMsg)
|
|
{
|
|
if (iMsg == -1)
|
|
iMsg = 0;
|
|
for (; iMsg < s_cMsgs; ++iMsg)
|
|
{
|
|
if (s_Msgs[iMsg].message == uMsg && s_Msgs[iMsg].hwnd == hwnd)
|
|
return iMsg;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
typedef struct TEST_ENTRY
|
|
{
|
|
INT line;
|
|
LPCSTR name;
|
|
UINT iFound;
|
|
} TEST_ENTRY, *PTEST_ENTRY;
|
|
|
|
static VOID DoAnalyzeEntries(size_t nCount, PTEST_ENTRY pEntries)
|
|
{
|
|
size_t i;
|
|
for (i = 0; i < nCount - 1; ++i)
|
|
{
|
|
PTEST_ENTRY entry1 = &pEntries[i];
|
|
PTEST_ENTRY entry2 = &pEntries[i + 1];
|
|
ok(entry1->iFound < entry2->iFound,
|
|
"Line %d: message wrong order (%d >= %d): %s vs %s\n",
|
|
entry1->line, entry1->iFound, entry2->iFound,
|
|
entry1->name, entry2->name);
|
|
}
|
|
}
|
|
|
|
static VOID DoAnalyzeAllMessages(VOID)
|
|
{
|
|
size_t i;
|
|
TEST_ENTRY entries1[] =
|
|
{
|
|
{ __LINE__, "WM_NCCREATE", findMessage(0, s_hMainWnd, WM_NCCREATE) },
|
|
{ __LINE__, "WM_NCCALCSIZE", findMessage(0, s_hMainWnd, WM_NCCALCSIZE) },
|
|
{ __LINE__, "WM_CREATE", findMessage(0, s_hMainWnd, WM_CREATE) },
|
|
{ __LINE__, "WM_PARENTNOTIFY", findMessage(0, s_hMainWnd, WM_PARENTNOTIFY) },
|
|
{ __LINE__, "WM_WINDOWPOSCHANGING", findMessage(0, s_hMainWnd, WM_WINDOWPOSCHANGING) },
|
|
{ __LINE__, "WM_ACTIVATEAPP", findMessage(0, s_hMainWnd, WM_ACTIVATEAPP) },
|
|
{ __LINE__, "WM_NCACTIVATE", findMessage(0, s_hMainWnd, WM_NCACTIVATE) },
|
|
{ __LINE__, "WM_ACTIVATE", findMessage(0, s_hMainWnd, WM_ACTIVATE) },
|
|
{ __LINE__, "WM_IME_SETCONTEXT", findMessage(0, s_hMainWnd, WM_IME_SETCONTEXT) },
|
|
{ __LINE__, "WM_IME_NOTIFY", findMessage(0, s_hMainWnd, WM_IME_NOTIFY) },
|
|
{ __LINE__, "WM_SETFOCUS", findMessage(0, s_hMainWnd, WM_SETFOCUS) },
|
|
{ __LINE__, "WM_KILLFOCUS", findMessage(0, s_hMainWnd, WM_KILLFOCUS) },
|
|
};
|
|
INT iFound1 = entries1[_countof(entries1) - 1].iFound;
|
|
TEST_ENTRY entries2[] =
|
|
{
|
|
{ __LINE__, "WM_IME_SETCONTEXT", findMessage(iFound1, s_hMainWnd, WM_IME_SETCONTEXT) },
|
|
{ __LINE__, "WM_IME_SETCONTEXT", findMessage(iFound1, s_hwndEdit, WM_IME_SETCONTEXT) },
|
|
{ __LINE__, "WM_SETFOCUS", findMessage(iFound1, s_hwndEdit, WM_SETFOCUS) },
|
|
{ __LINE__, "WM_SHOWWINDOW", findMessage(iFound1, s_hMainWnd, WM_SHOWWINDOW) },
|
|
{ __LINE__, "WM_WINDOWPOSCHANGING", findMessage(iFound1, s_hMainWnd, WM_WINDOWPOSCHANGING) },
|
|
{ __LINE__, "WM_NCPAINT", findMessage(iFound1, s_hMainWnd, WM_NCPAINT) },
|
|
{ __LINE__, "WM_ERASEBKGND", findMessage(iFound1, s_hMainWnd, WM_ERASEBKGND) },
|
|
{ __LINE__, "WM_WINDOWPOSCHANGED", findMessage(iFound1, s_hMainWnd, WM_WINDOWPOSCHANGED) },
|
|
{ __LINE__, "WM_SIZE", findMessage(iFound1, s_hMainWnd, WM_SIZE) },
|
|
{ __LINE__, "WM_MOVE", findMessage(iFound1, s_hMainWnd, WM_MOVE) },
|
|
};
|
|
INT iFound2 = entries2[_countof(entries2) - 1].iFound;
|
|
TEST_ENTRY entries3[] =
|
|
{
|
|
{ __LINE__, "WM_IME_KEYDOWN", findMessage(iFound2, s_hwndEdit, WM_IME_KEYDOWN) },
|
|
{ __LINE__, "WM_KEYDOWN", findMessage(iFound2, s_hwndEdit, WM_KEYDOWN) },
|
|
{ __LINE__, "WM_IME_KEYUP", findMessage(iFound2, s_hwndEdit, WM_IME_KEYUP) },
|
|
{ __LINE__, "WM_CHAR", findMessage(iFound2, s_hwndEdit, WM_CHAR) },
|
|
{ __LINE__, "WM_IME_CHAR", findMessage(iFound2, s_hwndEdit, WM_IME_CHAR) },
|
|
};
|
|
INT iFound3 = entries3[_countof(entries3) - 1].iFound;
|
|
TEST_ENTRY entries4[] =
|
|
{
|
|
{ __LINE__, "WM_IME_NOTIFY", findMessage(iFound3, s_hwndEdit, WM_IME_NOTIFY) },
|
|
{ __LINE__, "WM_IME_NOTIFY", findMessage(iFound3, s_hImeWnd, WM_IME_NOTIFY) },
|
|
{ __LINE__, "WM_IME_SETCONTEXT", findMessage(iFound3, s_hwndEdit, WM_IME_SETCONTEXT) },
|
|
{ __LINE__, "WM_IME_SETCONTEXT", findMessage(iFound3, s_hImeWnd, WM_IME_SETCONTEXT) },
|
|
};
|
|
INT iFound4 = entries4[_countof(entries4) - 1].iFound;
|
|
TEST_ENTRY entries5[] =
|
|
{
|
|
{ __LINE__, "WM_DESTROY", findMessage(iFound4, s_hMainWnd, WM_DESTROY) },
|
|
{ __LINE__, "WM_DESTROY", findMessage(iFound4, s_hwndEdit, WM_DESTROY) },
|
|
{ __LINE__, "WM_NCDESTROY", findMessage(iFound4, s_hwndEdit, WM_NCDESTROY) },
|
|
{ __LINE__, "WM_NCDESTROY", findMessage(iFound4, s_hMainWnd, WM_NCDESTROY) },
|
|
};
|
|
DoAnalyzeEntries(_countof(entries1), entries1);
|
|
DoAnalyzeEntries(_countof(entries2), entries2);
|
|
DoAnalyzeEntries(_countof(entries3), entries3);
|
|
//DoAnalyzeEntries(_countof(entries4), entries4); // No order
|
|
DoAnalyzeEntries(_countof(entries5), entries5);
|
|
|
|
ok(iFound1 < entries2[0].iFound, "%d vs %d\n", iFound1, entries2[0].iFound);
|
|
ok(iFound2 < entries3[0].iFound, "%d vs %d\n", iFound2, entries3[0].iFound);
|
|
ok(iFound3 < entries4[0].iFound, "%d vs %d\n", iFound3, entries4[0].iFound);
|
|
ok(iFound4 < entries5[0].iFound, "%d vs %d\n", iFound4, entries5[0].iFound);
|
|
|
|
for (i = 0; i < _countof(entries4); ++i)
|
|
{
|
|
ok(entries4[i].iFound != -1, "entries4[%d].iFound was -1\n", i);
|
|
}
|
|
}
|
|
|
|
static LRESULT CALLBACK
|
|
EditWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LRESULT ret;
|
|
MSG msg = { hwnd, uMsg, wParam, lParam };
|
|
|
|
/* Build s_prefix */
|
|
MD_build_prefix();
|
|
|
|
/* message dump */
|
|
MD_msgdump(hwnd, uMsg, wParam, lParam);
|
|
|
|
/* Add message */
|
|
if (s_cMsgs < MAX_MSGS)
|
|
s_Msgs[s_cMsgs++] = msg;
|
|
|
|
/* Do inner task */
|
|
ret = CallWindowProc(s_fnOldEditWndProc, hwnd, uMsg, wParam, lParam);
|
|
|
|
/* message return */
|
|
StringCbCopyA(s_prefix, sizeof(s_prefix), "R: ");
|
|
MD_msgresult(hwnd, uMsg, wParam, lParam, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static LRESULT CALLBACK
|
|
ImeWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LRESULT ret;
|
|
MSG msg = { hwnd, uMsg, wParam, lParam };
|
|
|
|
/* Build s_prefix */
|
|
MD_build_prefix();
|
|
|
|
/* message dump */
|
|
MD_msgdump(hwnd, uMsg, wParam, lParam);
|
|
|
|
/* Add message */
|
|
if (s_cMsgs < MAX_MSGS)
|
|
s_Msgs[s_cMsgs++] = msg;
|
|
|
|
/* Do inner task */
|
|
ret = CallWindowProc(s_fnOldImeWndProc, hwnd, uMsg, wParam, lParam);
|
|
|
|
/* message return */
|
|
StringCbCopyA(s_prefix, sizeof(s_prefix), "R: ");
|
|
MD_msgresult(hwnd, uMsg, wParam, lParam, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static LRESULT CALLBACK
|
|
InnerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_NCCREATE:
|
|
s_hMainWnd = hwnd;
|
|
trace("s_hMainWnd: %p\n", s_hMainWnd);
|
|
break;
|
|
case WM_CREATE:
|
|
s_hwndEdit = CreateWindowW(L"EDIT", NULL, WS_CHILD | WS_VISIBLE,
|
|
0, 0, 100, 20, hwnd, NULL, GetModuleHandleW(NULL), NULL);
|
|
ok(s_hwndEdit != NULL, "s_hwndEdit was NULL\n");
|
|
trace("s_hwndEdit: %p\n", s_hwndEdit);
|
|
s_fnOldEditWndProc =
|
|
(WNDPROC)SetWindowLongPtrW(s_hwndEdit, GWLP_WNDPROC, (LONG_PTR)EditWindowProc);
|
|
SetFocus(s_hwndEdit);
|
|
PostMessageW(hwnd, WM_COMMAND, STAGE_1, 0);
|
|
break;
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case STAGE_1:
|
|
s_hImeWnd = ImmGetDefaultIMEWnd(hwnd);
|
|
ok(s_hImeWnd != NULL, "s_hImeWnd was NULL\n");
|
|
trace("s_hImeWnd: %p\n", s_hImeWnd );
|
|
s_fnOldImeWndProc = (WNDPROC)SetWindowLongPtrW(s_hImeWnd, GWLP_WNDPROC,
|
|
(LONG_PTR)ImeWindowProc);
|
|
PostMessageW(hwnd, WM_COMMAND, STAGE_2, 0);
|
|
break;
|
|
case STAGE_2:
|
|
PostMessageW(s_hwndEdit, WM_IME_KEYDOWN, 'A', 0);
|
|
PostMessageW(hwnd, WM_COMMAND, STAGE_3, 0);
|
|
break;
|
|
case STAGE_3:
|
|
PostMessageW(s_hwndEdit, WM_IME_KEYUP, 'A', 0);
|
|
PostMessageW(hwnd, WM_COMMAND, STAGE_4, 0);
|
|
break;
|
|
case STAGE_4:
|
|
PostMessageW(s_hwndEdit, WM_IME_CHAR, 'A', 0);
|
|
PostMessageW(hwnd, WM_COMMAND, STAGE_5, 0);
|
|
break;
|
|
case STAGE_5:
|
|
PostMessageW(hwnd, WM_CLOSE, 0, 0);
|
|
break;
|
|
}
|
|
break;
|
|
case WM_DESTROY:
|
|
PostQuitMessage(0);
|
|
break;
|
|
}
|
|
|
|
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
static LRESULT CALLBACK
|
|
WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LRESULT ret;
|
|
MSG msg = { hwnd, uMsg, wParam, lParam };
|
|
|
|
/* Build s_prefix */
|
|
MD_build_prefix();
|
|
|
|
/* message dump */
|
|
MD_msgdump(hwnd, uMsg, wParam, lParam);
|
|
|
|
/* Add message */
|
|
if (s_cMsgs < MAX_MSGS)
|
|
s_Msgs[s_cMsgs++] = msg;
|
|
|
|
/* Do inner task */
|
|
ret = InnerWindowProc(hwnd, uMsg, wParam, lParam);
|
|
|
|
/* message return */
|
|
StringCbCopyA(s_prefix, sizeof(s_prefix), "R: ");
|
|
MD_msgresult(hwnd, uMsg, wParam, lParam, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
START_TEST(MessageStateAnalyzer)
|
|
{
|
|
WNDCLASSW wc;
|
|
HWND hwnd;
|
|
MSG msg;
|
|
static const WCHAR s_szName[] = L"MessageStateAnalyzer";
|
|
|
|
/* register window class */
|
|
ZeroMemory(&wc, sizeof(wc));
|
|
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
|
|
wc.lpfnWndProc = WindowProc;
|
|
wc.hInstance = GetModuleHandleW(NULL);
|
|
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
|
|
wc.lpszClassName = s_szName;
|
|
if (!RegisterClassW(&wc))
|
|
{
|
|
skip("RegisterClassW failed.\n");
|
|
return;
|
|
}
|
|
|
|
/* create a window */
|
|
hwnd = CreateWindowW(s_szName, s_szName, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, 300, 200, NULL, NULL,
|
|
GetModuleHandleW(NULL), NULL);
|
|
if (!hwnd)
|
|
{
|
|
skip("CreateWindowW failed.\n");
|
|
return;
|
|
}
|
|
|
|
/* message loop */
|
|
while (GetMessageW(&msg, NULL, 0, 0))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessageW(&msg);
|
|
}
|
|
|
|
DoAnalyzeAllMessages();
|
|
}
|