cwindowsmultithreadingdereference

Dereferencing a valid pointer results in an error


I have a pointer to a vector which I am passing into a function. The pointer is valid before being passed in, the pointer remains intact as it's being passed through, and printing it before and after passing it into the function reveals they are the same pointer. Yet, dereferencing it inside the function results in a segmentation fault.

Code before the function:

    /* .
       .
       . */
    const Vector commands = EndLayout();
    printf("About to post commands at 0x%16X\r\n", &commands);
    PostMessageW(handle, WM_PAINT, (WPARAM)&commands, ((long long unsigned int)&commands >> 32));
    free(commands->data);
    return 0;
}

and the function:

CALLBACK LRESULT handlePaint(HWND handle, WPARAM wParam, LPARAM lParam) {
    /* .
       .
       . */
    const Vector *commands = (Vector *)((long long unsigned int)wParam | ((long long unsigned int)lParam << 32));
    printf("Recieved command array at 0x%16X; about to paint\r\n", commands);
    for (unsigned int i = 0; i < commands->length; i++) { // Segmentation fault

In the logs:

About to post commands at 0x        5B5FFC20
Recieved command array at 0x        5B5FFC20; about to paint
* crash *

Perhaps this is because the two are on different threads? Though I don't see how this would affect it.

Edit: The function is Win32's PostMessageW, which passes a message to a window handler (in the same program). The handler function then calls handlePaint (the function diagrammed) with the same arguments as was passed into PostMessageW, minus the redundant WM_PAINT. The arguments are reconstructed as shown in the code, and produce the correct value as shown in the logs. handlePaint shouldn't have a different address space than MainThread, though I wouldn't be surprised if it did. If they do not share an address space, please give instruction on what to do instead.

A link to a "minimal reproducible example" can be found here, though I wouldn't want to put it here because of the sheer amount of boilerplate.


Solution

  • The trouble here is a use-after-free, but a sneaky one. PostMessageW doesn't wait for the message to return, so it goes right through to the next instructions, eventually freeing the memory from the heap and returning 0. By the time handlePaint gets to the command vector, it's already gone, so dereferencing the pointer results in a segfault. Waiting for the message to be processed before continuing fixes the issue. Changing PostMessageW to SendMessageW fixes this.