在Python中引发未处理的C异常

时间:2013-10-03 08:21:13

标签: python c windows exception

我正在为Windows扩展一个Python 2.7.5应用程序。该应用程序使用SetUnhandledExceptionFilter来安装在发生未处理的C异常时调用的Python函数:

@ctypes.WINFUNCTYPE(ctypes.wintypes.LONG, PEXCEPTION_POINTERS)
def crashHandler(exceptionInfo):
    # Some code that deals with the unhandled C exception...
...
windll.kernel32.SetUnhandledExceptionFilter(crashHandler)

(我将在下面给出PEXCEPTION_POINTERS的代码,因为我认为这与此问题的目的无关。)

在原始格式中,crashHandler执行一些日志记录并关闭该过程。我已经观察到它处理了几次未处理的异常,因此我非常确信crashHandler已正确安装为UnhandledExceptionFilter。

我对crashHandler做了一些修改,现在想测试它。为此,我的想法是以编程方式引发一个C异常,然后由crashHandler处理。我尝试了以下方法:

>>> windll.kernel32.RaiseException(5, 0, 0, None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
WindowsError: [Error 5] Access is denied
>>> windll.kernel32.RaiseException(6, 0, 0, None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
WindowsError: [Error 6] The handle is invalid

因此异常会被Python解释器立即捕获,因此不会传播到我的crashHandler

我怎样才能a)禁用Python的异常处理或b)以编程方式引发一个C异常,该异常未被Python的异常处理机制捕获并传播到我的crashHandler


以下是PEXCEPTION_POINTERS的代码:

from ctypes import Structure
import ctypes
EXCEPTION_MAXIMUM_PARAMETERS = 15
class EXCEPTION_RECORD(Structure):
    pass
PEXCEPTION_RECORD = ctypes.wintypes.POINTER(EXCEPTION_RECORD)
EXCEPTION_RECORD._fields_ = [
    ('ExceptionCode',           ctypes.wintypes.DWORD),
    ('ExceptionFlags',          ctypes.wintypes.DWORD),
    ('ExceptionRecord',         PEXCEPTION_RECORD),
    ('ExceptionAddress',        ctypes.wintypes.LPVOID),
    ('NumberParameters',        ctypes.wintypes.DWORD),
    ('ExceptionInformation',    ctypes.wintypes.LPVOID * EXCEPTION_MAXIMUM_PARAMETERS),
]
class EXCEPTION_POINTERS(Structure):
    _fields_ = [('ExceptionRecord', PEXCEPTION_RECORD),
                ('ContextRecord', ctypes.wintypes.LPVOID)]
PEXCEPTION_POINTERS = ctypes.wintypes.POINTER(EXCEPTION_POINTERS)

1 个答案:

答案 0 :(得分:2)

windll模块自动捕获调用中发生的Windows SEH异常,并将它们转换为WindowsError python异常。因此,它们不是未经处理的例外。

您需要使用没有这么好的包装器的API。

最好的办法是使用C扩展模块,通过取消引用随机指针(或null)来导致访问冲突。