Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows SetUnhandledExceptionFilter() and MiniDumpWriteDump() not working #4407

Open
ccll opened this issue Oct 21, 2024 · 4 comments
Open
Labels
needs-validation Reviewers need to validate that everything is in working order

Comments

@ccll
Copy link

ccll commented Oct 21, 2024

Context

I'm trying to do Windows SEH in Odin, when exception occurred, catch it and write a dump file for later debugging.

  • Operating System & Odin Version:
  • Please paste odin report output:
        Odin:    dev-2024-10-nightly:af9ae48
        OS:      Windows 11 Professional (version: 23H2), build 22631.4317
        CPU:     Intel(R) Core(TM) i3-10100 CPU @ 3.60GHz
        RAM:     32701 MiB
        Backend: LLVM 18.1.8

Expected Behavior

MiniDumpWriteDump() should write the dump successfully.

Current Behavior

MiniDumpWriteDump() returns FALSE.
GetLastError() returns 2147943398 (0x800703E6), which denotes "Invalid access to memory location".

It seems the problems is that the registered handler got called with a wrong input of ^EXCEPTION_POINTERS, if we don't pass this pointer to MINIDUMP_EXCEPTION_INFORMATION.ExceptionPointers (replace it with a nil pointer), MiniDumpWriteDump() would return TRUE (which apparently would dump a file without correct exception info).

Failure Information (for bugs)

Please help provide information about the failure if this is a bug. If it is not a bug, please remove the rest of this template.

Steps to Reproduce

  1. the sample source code:
package main

import "base:runtime"
import "core:fmt"
import win "core:sys/windows"


exception_handler :: proc "system" (pException: ^win.EXCEPTION_POINTERS) -> win.LONG {
        using win

        context = runtime.default_context()
        context.allocator = context.temp_allocator
        defer free_all()

        fmt.printf("crash detected, pep: %v\n", pException)

        hDumpFile: HANDLE = CreateFileW(
                L("dumpfile.dmp"),
                GENERIC_WRITE,
                0,
                nil,
                CREATE_ALWAYS,
                FILE_ATTRIBUTE_NORMAL,
                nil,
        )

        if hDumpFile == INVALID_HANDLE_VALUE {
                fmt.printf("failed to create dump file")
                return EXCEPTION_EXECUTE_HANDLER
        }

        defer {
                fmt.printf("closing dump file ...\n")
                CloseHandle(hDumpFile)
        }

        fmt.printf("opened dumpfile, handle: %v\n", hDumpFile)

        mdei: MINIDUMP_EXCEPTION_INFORMATION
        mdei.ThreadId = GetCurrentThreadId()
        mdei.ExceptionPointers = pException    // pass in 'nil' would make MiniDumpWriteDump() return TRUE
        mdei.ClientPointers = FALSE

        process_handle := GetCurrentProcess()
        process_id := GetCurrentProcessId()

        fmt.printf(
                "writing dumpfile\n\tprocess_handle: %v\n\tprocess_id: %v\n\tmdei: %v ...\n",
                process_handle,
                process_id,
                mdei,
        )

        succ := MiniDumpWriteDump(
                process_handle,
                process_id,
                hDumpFile,
                .Normal | .WithDataSegs | .WithFullMemoryInfo | .WithIndirectlyReferencedMemory,
                ExceptionParam = &mdei,
                UserStreamParam = nil,
                CallbackPara = nil,
        )

        fmt.printf("MiniDumpWriteDump() result: %v\n", succ)
        if !succ {
                code := GetLastError()
                fmt.printf("MiniDumpWriteDump() error code: %v\n", code)
                message_buf: []u16 = make([]u16, 1024)
                defer delete(message_buf)
                FormatMessageW(
                        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                        nil,
                        code,
                        MAKELANGID(0x09, 0x01), // English
                        raw_data(message_buf),
                        1024,
                        nil,
                )
                message_u8, err := win.utf16_to_utf8(message_buf)
                if err != nil {
                        fmt.eprintf("error converting utf-16 to utf-8: %v", err)
                } else {
                        fmt.printf("error message: %v\n", message_u8)
                }
        }

        return EXCEPTION_EXECUTE_HANDLER
}

crash :: proc() {
        ptr: ^int = nil
        ptr^ = 42
}

main :: proc() {
        using win
        SetUnhandledExceptionFilter(exception_handler)

        fmt.printf("entering program ...\n")
        crash()
        fmt.printf("hello, world\n")
}
  1. compile: odin build . -out:main.exe -debug

  2. run: main.exe<ENTER>

  3. output:

entering program ...
crash detected, pep: &EXCEPTION_POINTERS{ExceptionRecord = 0x922656F7F0, ContextRecord = 0x922656F300}
opened dumpfile, handle: 0x110
writing dumpfile
        process_handle: 0xFFFFFFFFFFFFFFFF
        process_id: 23872
        mdei: MINIDUMP_EXCEPTION_INFORMATION{ThreadId = 18912, ExceptionPointers = &EXCEPTION_POINTERS{ExceptionRecord = 0x922656F7F0, ContextRecord = 0x922656F300}, ClientPointers = false} ...
MiniDumpWriteDump() result: false
MiniDumpWriteDump() error code: 2147943398
error message: Invalid access to memory location.

closing dump file ...
@laytan laytan added the needs-validation Reviewers need to validate that everything is in working order label Oct 22, 2024
@tf2spi
Copy link
Contributor

tf2spi commented Nov 5, 2024

I want it to be stated for the record that I hate Microsoft.

IHateMicrosoft

I just tested that the following change makes it work...

MINIDUMP_EXCEPTION_INFORMATION :: struct #packed {
	ThreadId:          DWORD,
	ExceptionPointers: ^EXCEPTION_POINTERS,
	ClientPointers:    BOOL,
}

@Bambo-Borris
Copy link

Curious if there's any further traction on this issue, I hunted through the PRs and it seems to be in a bit of a quagmire. I am used to having this sort of functionality available in my dev builds for if crashes occur during testing on a testers system. (I don't mind waiting, just curious where things are at 😄 )

tf2spi added a commit to tf2spi/Odin that referenced this issue Dec 22, 2024
tf2spi added a commit to tf2spi/Odin that referenced this issue Dec 22, 2024
tf2spi added a commit to tf2spi/Odin that referenced this issue Dec 22, 2024
@tf2spi
Copy link
Contributor

tf2spi commented Dec 22, 2024

Curious if there's any further traction on this issue, I hunted through the PRs and it seems to be in a bit of a quagmire. I am used to having this sort of functionality available in my dev builds for if crashes occur during testing on a testers system. (I don't mind waiting, just curious where things are at 😄 )

Funnily enough, I was working on this yesterday. Thanks for the reminder!

#4611 and #4474 are the related fixes. I kind of took charge of these then blipped off the map for a while. My apologies for that.

@Bambo-Borris
Copy link

Curious if there's any further traction on this issue, I hunted through the PRs and it seems to be in a bit of a quagmire. I am used to having this sort of functionality available in my dev builds for if crashes occur during testing on a testers system. (I don't mind waiting, just curious where things are at 😄 )

Funnily enough, I was working on this yesterday. Thanks for the reminder!

#4611 and #4474 are the related fixes. I kind of took charge of these then blipped off the map for a while. My apologies for that.

No need for apologies dude, respect the effort to fix this. Thanks for the speedy update 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs-validation Reviewers need to validate that everything is in working order
Projects
None yet
Development

No branches or pull requests

4 participants