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

faulthandler dumps 'Windows fatal exception: code 0xe06d7363' #75882

Closed
FynnBe mannequin opened this issue Oct 5, 2017 · 30 comments
Closed

faulthandler dumps 'Windows fatal exception: code 0xe06d7363' #75882

FynnBe mannequin opened this issue Oct 5, 2017 · 30 comments
Labels
3.7 (EOL) end of life OS-windows type-bug An unexpected behavior, bug, or error

Comments

@FynnBe
Copy link
Mannequin

FynnBe mannequin commented Oct 5, 2017

BPO 31701
Nosy @pfmoore, @vstinner, @tjguk, @zware, @zooba, @Kentzo
PRs
  • bpo-31701: faulthandler.enable() registers exc handler as last #3928
  • bpo-31701: faulthandler: ignore MSC and COM Windows exception #3929
  • [3.6] bpo-31701: faulthandler: ignore MSC and COM Windows exception (#3929) #4416
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2017-11-18.00:02:50.362>
    created_at = <Date 2017-10-05.09:59:11.251>
    labels = ['type-bug', '3.7', 'OS-windows']
    title = "faulthandler dumps 'Windows fatal exception: code 0xe06d7363'"
    updated_at = <Date 2017-11-18.04:01:39.143>
    user = 'https://bugs.python.org/FynnBe'

    bugs.python.org fields:

    activity = <Date 2017-11-18.04:01:39.143>
    actor = 'Ilya.Kulakov'
    assignee = 'none'
    closed = True
    closed_date = <Date 2017-11-18.00:02:50.362>
    closer = 'vstinner'
    components = ['Windows']
    creation = <Date 2017-10-05.09:59:11.251>
    creator = 'Fynn Be'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 31701
    keywords = ['patch']
    message_count = 30.0
    messages = ['303751', '303752', '303755', '303758', '303771', '303773', '303888', '303889', '303927', '303928', '303939', '303940', '303941', '303942', '303977', '303985', '306312', '306333', '306338', '306354', '306355', '306356', '306396', '306401', '306459', '306460', '306461', '306463', '306464', '306467']
    nosy_count = 7.0
    nosy_names = ['paul.moore', 'vstinner', 'tim.golden', 'zach.ware', 'steve.dower', 'Ilya.Kulakov', 'Fynn Be']
    pr_nums = ['3928', '3929', '4416']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue31701'
    versions = ['Python 3.6', 'Python 3.7']

    @FynnBe
    Copy link
    Mannequin Author

    FynnBe mannequin commented Oct 5, 2017

    c++ extension compiled with MSVC 14
    using python 3.6.2 on Windows 10 x64

    Whenever a C++ exception is thrown in an extension the faulthandler dumps a traceback to it, even if it is caught.

    @FynnBe FynnBe mannequin added OS-windows type-bug An unexpected behavior, bug, or error labels Oct 5, 2017
    @FynnBe
    Copy link
    Mannequin Author

    FynnBe mannequin commented Oct 5, 2017

    Here is a git repository with a test module and a test script:
    https://github.com/FynnBe/faulthandler-spam

    @FynnBe
    Copy link
    Mannequin Author

    FynnBe mannequin commented Oct 5, 2017

    In the github repository there is 'build.bat' that creates the mscv 14 solution, builds it and runs the 'test.py'.
    Here is the output:

    Windows fatal exception: code 0xe06d7363
    
    Current thread 0x0000462c (most recent call first):
      File "test.py", line 5 in <module>
    caught test error: c++ error message
    

    The 'Windows fatal exception: code 0xe06d7363' is only caused by a c++ exception thrown (regardless if it is handled or not). More on the error code is here:
    https://support.microsoft.com/de-de/help/185294/prb-exception-code-0xe06d7363-when-calling-win32-seh-apis

    The last line 'caught test error: c++ error message' is generated within the test module, where the error is caught.

    In larger projects these tracebacks spam the faulthandler's output, as this is valid code and occurs often (for example for an IndexError raised in a c++ extension to end a for loop).

    @vstinner
    Copy link
    Member

    vstinner commented Oct 5, 2017

    The code of the current faulthandler exception handler lives at:

    https://github.com/python/cpython/blob/master/Modules/faulthandler.c#L364-L409

    --

    https://support.microsoft.com/de-de/help/185294/prb-exception-code-0xe06d7363-when-calling-win32-seh-apis

    """
    Resolution

    (...)
    3. Within the Exceptions dialog box, select error 0xE06D7363.
    4. Change the value of Action from Stop if not handled to Stop always.
    """

    Are you asking to *ignore* all 0xE06D7363 exceptions?

    I don't know well Windows exceptions. The latest change was bpo-30557, ignore non-fatal exceptions:

    /* bpo-30557: only log fatal exceptions */
    if (!(code & 0x80000000)) ...
    

    @FynnBe
    Copy link
    Mannequin Author

    FynnBe mannequin commented Oct 5, 2017

    Are you asking to *ignore* all 0xE06D7363 exceptions?
    Yes. This error is only indicating that an error was thrown, regardless if it was handled or not. Therefore it should not be treated as fatal, but it is by faulthandler: 'bool(0xE06D7363 & 0x80000000) == True'

    with the initial "E" standing for "exception" and the final 3 bytes (0x6D7363) representing the ASCII values of "msc"
    https://support.microsoft.com/de-de/help/185294/prb-exception-code-0xe06d7363-when-calling-win32-seh-apis
    In this context it seems like a coincidence to me.

    @zooba
    Copy link
    Member

    zooba commented Oct 5, 2017

    We may just need to special case some well known exception codes for MSVC and the CLR, though if they're handled we may be dumping on the first chance and not the second chance handling.

    If I get a chance to dig into the docs and code I'll take a look, but it's been years since I really did anything with SEH (apart from the recent filtering change, which was pretty trivial).

    @zooba
    Copy link
    Member

    zooba commented Oct 7, 2017

    Haven't had a chance to test this, but I suspect our change should depend on what happens when a C++ exception is actually unhandled.

    In this case, the following sequence has occurred:

    • exception is raised
    • debug event is raised (if a debugger is attached)
    • stack-based handlers get first-chance to ignore the exception
    • there is a stack-based handler that says "let it be raised" and the search stops
    • vector-based handlers are called
    • stack unwind begins, and when the handler is reached it allows execution to continue

    Unfortunately, I don't think there's going to be any difference between the unhandled and handled cases at the point where our handler exists - at worst, the OS is going to say that it is "handled" and its handler will kill the process. The first chance lookup is actually there to continue execution and ignore the exception (possibly after fixing an argument or allocating a new page, etc.).

    So I think our choices are:

    • report no C++/CLR exceptions via faulthandler
    • report all C++/CLR exceptions via faulthandler (current behaviour)

    I'm inclined towards changing to the first option. The runtime is going to dump a more useful message than us if the exception makes it that far, and a C++ exception can never be caused by CPython itself.

    @zooba
    Copy link
    Member

    zooba commented Oct 7, 2017

    Okay, just tested taking out the C++ handler and it goes straight to an error report. Not ideal, especially since the error is logged against "python.exe" and "ucrtbase.dll" (which is going to make my life harder when reviewing the submitted crash reports), but since it can only be caused by user code, it's probably better than spamming on every handled exception.

    E06D7363 (msc) and E0434352 (CCR) at least should be ignored. I think there's a third, but don't remember what it is right now.

    @vstinner
    Copy link
    Member

    vstinner commented Oct 9, 2017

    On the Internet, I also found the code 0xE0434F4D: 0xe0000000 + 'COM'. Should it be ignored as well?

    @vstinner
    Copy link
    Member

    vstinner commented Oct 9, 2017

    So I think our choices are:

    • report no C++/CLR exceptions via faulthandler
    • report all C++/CLR exceptions via faulthandler (current behaviour)

    I'm inclined towards changing to the first option. (...)

    On the Internet, I found users asking why their favorite application crashed with "Unhandled Exception E0434F4D (e0434fedh) at address 7C81EB33h" or "APPCRASH Exception Code e0434f4d".

    While I understand that it's annoying to get a traceback each time an application handles an exception, the faulthandler would leave the user clueless if faulthandler ignore such exception and the exception "kills" the process.

    faulthandler registers its exception handler as the *first* handler to be called:

    AddVectoredExceptionHandler(1, faulthandler_exc_handler);

    Maybe it shouldn't be the first but the *last* to be called? So an earlier handler could handle the exception, and faulthandler wouldn't log its traceback.

    The problem is that I'm confused with "non-error" exceptions (code < 0x80000000), "expected" MSC or COM exceptions, and fatal exceptions like EXCEPTION_INT_DIVIDE_BY_ZERO or EXCEPTION_ACCESS_VIOLATION.

    Is it possible to be asked to be called as the last handler, and still be able to log EXCEPTION_ACCESS_VIOLATION? If not, maybe we need two handlers depending on the exception code. One handler called last for non-fatal exceptions, one handler called first for fatal exceptions.

    By "Fatal" exceptions, I mean:

    case EXCEPTION_ACCESS_VIOLATION: PUTS(fd, "access violation"); break;
    case EXCEPTION_FLT_DIVIDE_BY_ZERO: PUTS(fd, "float divide by zero"); break;
    case EXCEPTION_FLT_OVERFLOW: PUTS(fd, "float overflow"); break;
    case EXCEPTION_INT_DIVIDE_BY_ZERO: PUTS(fd, "int divide by zero"); break;
    case EXCEPTION_INT_OVERFLOW: PUTS(fd, "integer overflow"); break;
    case EXCEPTION_IN_PAGE_ERROR: PUTS(fd, "page error"); break;
    case EXCEPTION_STACK_OVERFLOW: PUTS(fd, "stack overflow"); break;
    

    @vstinner
    Copy link
    Member

    vstinner commented Oct 9, 2017

    I wrote the PR 3928 to call AddVectoredExceptionHandler(0, ...) rather than AddVectoredExceptionHandler(1, ...), but it doesn't work as expected.

    I tested "faulthandler.enable(); faulthandler._sigsegv()": a traceback is logged. But this code tested the *signal handler* rather than the exception handler. I disabled manually the code of faulthandler.enable() to not install signal handlers anymore: no more traceback is logged.

    @vstinner
    Copy link
    Member

    vstinner commented Oct 9, 2017

    I misunderstood how Windows works. UNIX signals handlers and Windows exception handlers are unrelated. Exception handlers are not called to handle a SIGSEGV signal (raised manually by the process itself, not raised by the Windows kernel).

    @vstinner
    Copy link
    Member

    vstinner commented Oct 9, 2017

    I failed to build https://github.com/FynnBe/faulthandler-spam with a Python built myself. But I succeeded to recompile a Python extension (_overlapped) in C++ (I removed two functions which caused compilation error) and then added faulthandler-spam/test_module/module.cpp code into _overlapped. So I was able to test C++ code raising a regular extension called by Python.

    Sadly, using "AddVectoredExceptionHandler(0, faulthandler_exc_handler);" (instead of "AddVectoredExceptionHandler(1, ...") doesn't solve the issue: the exception is still logged. It seems like the faulthandler exception handler is called before C++ has the opportunity to handle the exception.

    So it doesn't seem possible to log *unhandled* C++ exceptions using AddVectoredExceptionHandler() without flooding logs with *handled* C++ extensions.

    I now agree with Steve Dower to ignore *all* C++ exceptions in faulthandler.

    @vstinner
    Copy link
    Member

    vstinner commented Oct 9, 2017

    I abandon my intent to log all interesting errors: PR 3929 now always ignore all MSC and COM Windows exceptions.

    @zooba
    Copy link
    Member

    zooba commented Oct 9, 2017

    Is it possible to be asked to be called as the last handler ...

    Unfortunately not, since the stack-based handlers always come after the vector handlers, and C++ handlers written using try/catch will always be stack-based.

    It may be interesting for faulthandler to have a stack-based version, so that you can provide the function to call and it will call it inside an exception handler. But I don't think it's that interesting and in any case doesn't need to be in the stdlib.

    I wouldn't worry about 0xE0434F4D for now, but if someone comes along with a need for it then we can add it.

    @vstinner
    Copy link
    Member

    vstinner commented Oct 9, 2017

    New changeset 6e3d6b5 by Victor Stinner in branch 'master':
    bpo-31701: faulthandler: ignore MSC and COM Windows exception (bpo-3929)
    6e3d6b5

    @Kentzo
    Copy link
    Mannequin

    Kentzo mannequin commented Nov 15, 2017

    Victor,

    Does this change imply that no python-traceback-for-every-thread will be printed upon both handled and unhandled C++ exception?

    @vstinner
    Copy link
    Member

    Does this change imply that no python-traceback-for-every-thread will be printed upon both handled and unhandled C++ exception?

    Right if I understood correctly. The best is to test yourself ;-)

    @Kentzo
    Copy link
    Mannequin

    Kentzo mannequin commented Nov 16, 2017

    May I ask why AddVectoredExceptionHandler is used instead of SetUnhandledExceptionFilter?

    @vstinner
    Copy link
    Member

    May I ask why AddVectoredExceptionHandler is used instead of SetUnhandledExceptionFilter?

    Honestly, I don't know well Windows API and so I'm not sure which one is the best.

    https://stackoverflow.com/questions/28629351/is-addvectoredexceptionhandler-a-replacement-for-setunhandledexceptionfilter

    @vstinner
    Copy link
    Member

    New changeset 33217d2 by Victor Stinner in branch '3.6':
    bpo-31701: faulthandler: ignore MSC and COM Windows exception (bpo-3929) (bpo-4416)
    33217d2

    @vstinner
    Copy link
    Member

    I backported the fix to Python 3.6.

    @Steve Dower: What do you think of using SetUnhandledExceptionFilter?

    @vstinner vstinner added the 3.7 (EOL) end of life label Nov 16, 2017
    @Kentzo
    Copy link
    Mannequin

    Kentzo mannequin commented Nov 16, 2017

    I think faulthandler should use both. E.g. in [1] you can read about an exception that can be handled by AddVectoredExceptionHandler but not SetUnhandledExceptionFilter.

    Perhaps implementation should use SetUnhandledExceptionFilter for everything and AddVectoredExceptionHandler only for those exceptions that cannot be handled by the former, like c0000374.

    I couldn't find a list, so guess it will be an ongoing WIP.

    1: https://stackoverflow.com/questions/19656946/why-setunhandledexceptionfilter-cannot-capture-some-exception-but-addvectoredexc

    @Kentzo
    Copy link
    Mannequin

    Kentzo mannequin commented Nov 16, 2017

    Another option is to use AddVectoredContinueHandler [1]. It seems to be called if both VEH and SEH failed to handle the error.

    1: https://msdn.microsoft.com/en-us/library/windows/desktop/ms679273(v=vs.85).aspx

    @zooba
    Copy link
    Member

    zooba commented Nov 17, 2017

    SetUnhandledExceptionFilter could be a good option.

    I suspect the difference between that and AddVectorContinueHandler are because of the weird prioritization of the two types of handler, and are probably not significant enough to worry about here.

    @vstinner
    Copy link
    Member

    I suspect the difference between that and AddVectorContinueHandler are because of the weird prioritization of the two types of handler, and are probably not significant enough to worry about here.

    Ok, thanks. I close the issue since the initial bug has been fixed.

    Thank you Fynn Be for the bug report!

    @Kentzo
    Copy link
    Mannequin

    Kentzo mannequin commented Nov 18, 2017

    Steve, the difficulty with SetUnhandledExceptionFilter is that it can replace filter installed by the user (e.g. one of loaded libraries).

    The information about AddVectoredContinueHandler is scarce, but according to what I found at [1]:

    If the exception is still not handled after all your frame based SEH handlers are called, vectored continue handler will be called. This gives you the last opportunity to handle the exception in a way you want.

    1: https://blogs.msdn.microsoft.com/zhanli/2010/06/24/c-tips-addvectoredexceptionhandler-addvectoredcontinuehandler-and-setunhandledexceptionfilter/

    @Kentzo
    Copy link
    Mannequin

    Kentzo mannequin commented Nov 18, 2017

    Please ignore everything I said about AddVectoredContinueHandler. I finally got a chance to test the code on Windows and the way it's called is not suitable for faulthandler.

    @vstinner
    Copy link
    Member

    Please ignore everything I said about AddVectoredContinueHandler. I finally got a chance to test the code on Windows and the way it's called is not suitable for faulthandler.

    Oh, good to know. Thank you for having tested that ;-)

    At least, it seems like my faulthandler is useful to a few people :)

    @Kentzo
    Copy link
    Mannequin

    Kentzo mannequin commented Nov 18, 2017

    Victor, it's very helpful to analyze which Python stack caused exceptions in native code on user's machines.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.7 (EOL) end of life OS-windows type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    2 participants