* Copyright (c) 2014-2019 Google, Inc. All rights reserved.
* Copyright (c) 2007-2010 VMware, Inc. All rights reserved.
* **********************************************************/
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#include <windows.h>
#include "tools.h"
#include <stdio.h>
static bool thread_ready = false;
static bool past_crash = false;
static uint last_received = 0;
static HWND hwnd;
static uint msgdata;
static const UINT MSG_CUSTOM = WM_APP + 1;
static const LRESULT MSG_SUCCESS = 1;
static const WPARAM WP_NOP = 0;
static const WPARAM WP_EXIT = 1;
static const WPARAM WP_CRASH = 3;
static const ptr_uint_t BAD_WRITE = 0x40;
#ifndef WM_DWMNCRENDERINGCHANGED
# define WM_DWMNCRENDERINGCHANGED 0x031F
#endif
* WM_GETMINMAXINFO 0x0024
* WM_NCCREATE 0x0081
* WM_NCCALCSIZE 0x0083
* WM_CREATE 0x0001
* and then our 2 custom messages that we send.
*
* On Windows 7 we also get (i#520):
* WM_DWMNCRENDERINGCHANGED 0x031F
* and we avoid printing anything about it to simplify the test suite.
*/
LRESULT CALLBACK
wnd_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
bool cross_cb_seh_supported;
if (message == MSG_CUSTOM) {
print("in wnd_callback " PFX " %d %d\n", message, wParam, lParam);
if (wParam == WP_CRASH) {
ReplyMessage(TRUE);
print("About to crash\n");
#ifdef X64
cross_cb_seh_supported = false;
#else
cross_cb_seh_supported = (get_windows_version() < WINDOWS_VERSION_7 ||
!is_wow64(GetCurrentProcess()));
#endif
if (!cross_cb_seh_supported) {
* the callback boundary! Is that a fundamental limitation of the
* overly-structured SEH64? 32-bit SEH has no problem. Neither does
* WOW64, except on win7+.
* For now we have a local try/except.
*/
__try {
*((int *)BAD_WRITE) = 4;
print("Should not get here\n");
} __except (
* case 10579) */
(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION &&
(GetExceptionInformation())
->ExceptionRecord->ExceptionInformation[0] ==
1
&& (GetExceptionInformation())
->ExceptionRecord->ExceptionInformation[1] ==
BAD_WRITE)
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH) {
print("Inside handler\n");
past_crash = true;
}
} else {
*((int *)BAD_WRITE) = 4;
print("Should not get here\n");
}
}
return MSG_SUCCESS;
} else {
if (message != WM_DWMNCRENDERINGCHANGED)
print("in wnd_callback " PFX " %d\n", message, wParam);
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
int WINAPI
run_func(void *arg)
{
MSG msg;
char *winName = "foobar";
WNDCLASS wndclass = {
0, wnd_callback, 0, 0, NULL ,
NULL, NULL, NULL, NULL, winName
};
if (!RegisterClass(&wndclass)) {
print("Unable to create window class\n");
return 0;
}
hwnd = CreateWindow(winName, winName, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, NULL, NULL, NULL ,
NULL);
* to our crash inside a callback */
VirtualAlloc(0, 1024, MEM_RESERVE, PAGE_EXECUTE_READWRITE);
thread_ready = true;
while (true) {
__try {
if (GetMessage(&msg, NULL, 0, 0)) {
if ((msg.message != MSG_CUSTOM || msg.wParam != WP_NOP) &&
msg.message != WM_DWMNCRENDERINGCHANGED) {
print("Got message " PFX " %d %d\n", msg.message, msg.wParam,
msg.lParam);
}
last_received = msg.message;
if (msg.message == MSG_CUSTOM && msg.wParam == WP_EXIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
} __except (
* case 10579) */
(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION &&
(GetExceptionInformation())
->ExceptionRecord->ExceptionInformation[0] == 1
&& (GetExceptionInformation())
->ExceptionRecord->ExceptionInformation[1] == BAD_WRITE)
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH) {
* On xpsp2 and earlier we never see a callback return for
* the crashing callback, while on 2k3sp1 we do see one.
*/
print("Inside handler\n");
past_crash = true;
continue;
}
}
return (int)msg.wParam;
}
int
main()
{
int tid;
HANDLE hThread;
uint msgnum = 0;
print("About to create thread\n");
hThread = CreateThread(NULL, 0, run_func, NULL, 0, &tid);
if (hThread == NULL) {
print("Error creating thread\n");
return -1;
}
while (!thread_ready)
Sleep(0);
* We go ahead and use the blocking SendMessage for simplicity;
* could use SendMessageCallback and get a callback back, but have to
* ask for messages to receive it and then have no clear exit path.
*/
if (SendMessage(hwnd, MSG_CUSTOM, WP_CRASH, msgnum++) != MSG_SUCCESS) {
print("Error %d posting window message\n", GetLastError());
return -1;
}
* thread to go into the except block: it sits waiting in the
* kernel at the NtCallbackReturn from
* KiUserCallbackExceptionHandler, and that is where it receives
* the callback for this message: seems problematic natively?
*/
PostThreadMessage(tid, MSG_CUSTOM, WP_NOP, msgnum++);
while (!past_crash)
Sleep(0);
if (SendMessage(hwnd, MSG_CUSTOM, WP_NOP, msgnum++) != MSG_SUCCESS) {
print("Error %d posting window message\n", GetLastError());
return -1;
}
* with no callback involved. So this bit here is mainly to get the thread
* to exit. */
if (!PostThreadMessage(tid, MSG_CUSTOM, WP_EXIT, msgnum++)) {
print("Error %d posting thread message\n", GetLastError());
return -1;
}
while (last_received != MSG_CUSTOM)
Sleep(0);
WaitForSingleObject(hThread, INFINITE);
print("All done\n");
return 0;
}