64-bit Windows: longjmp lands in a wrong place

1

There's a problem when I use longjmp in a 32-bit application on Windows 64-bit (Windows 7). Instead of returning to a point of the last setjmp() call, it lands after the last DispatchMessage() call. Here's the code example, which works fine if compiled by a 64-bit compiler, and fails with a 32-bit version.

Are there any ideas for a workaround? Microsoft seems to be silent on a tangential question here: https://social.msdn.microsoft.com/Forums/vstudio/en-US/b63a573f-007e-43a3-877c-b06280aa8bcc/0x80000026-application-error-when-exiting-after-using-longjmp-on-windows8-x64?forum=windowscompatibility

// Compile as: cl a.c user32.lib kernel32.lib 

#include <windows.h>
#include <setjmp.h>
#include <stdio.h>

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

jmp_buf jump_buffer;
int flag = 0;

int main()
{
    WNDCLASS wc = {0, };
    ATOM atom = 0;
    HWND wnd;
    MSG msg;
    int ret;
    wc.lpfnWndProc = &WndProc;
    wc.hInstance = GetModuleHandle(NULL);
    wc.lpszClassName = "ExitWindows() handler";
    atom = RegisterClass(&wc);
    wnd = CreateWindow(wc.lpszClassName, wc.lpszClassName,
                        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
                        CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, wc.hInstance, NULL);

    ret = setjmp(jump_buffer);

    switch ( ret ) {
    case 0:
        ShowWindow(wnd,SW_SHOW);
        while (GetMessage(&msg, NULL, 0, 0)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            if ( flag ) {
                printf("not ok\n");
                break;
            }
        }
        break;
    case 1:
        printf("ok\n");
        break;
    }
    return 0;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message) {
    case WM_PAINT:
        flag = 1;
        longjmp(jump_buffer, 1);
        return 0;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
}
c
winapi
32bit-64bit
longjmp
setjmp
asked on Stack Overflow Sep 11, 2015 by Dmitry Karasik • edited Sep 11, 2015 by Ross Ridge

1 Answer

2

Using longjmp in WndProc is unsafe because of the nature of a window procedure:

  • if can be called through a SendMessage function, in which case it in not called with the same context (stack) that what you used for the setjmp. In that case, I think that anything could happen... - Ok WM_PAINT in normally posted and not sent so that should not apply here, even if IMHO it is the main reason to not do that
  • the system could prepare some internal structs for you before calling the window procedure (in DispatchMessage) and expect to be able to clean them after WndProc returns. Using a longjmp would break that.

The Windows API on WindowProc functions says: The return value is the result of the message processing and depends on the message sent.

My understanding of it is that a window procedure is supposed to return and to never call longjmp of exit. It is not explicit in Windows documentation, but I would not dare use a window procedure that would not return.

The correct way to exit correctly from a message loop is by posting a WM_QUIT message (Use the PostQuitMessage function to exit a message loop). It makes the GetMessage functions returns 0 and allows the system to cleanup the message loop that was installed at first call to GetMessage.

answered on Stack Overflow Sep 11, 2015 by Serge Ballesta

User contributions licensed under CC BY-SA 3.0