繁体   English   中英

如何将 Python 中的段错误捕获为异常?

[英]How to catch SegFault in Python as exception?

有时 Python 不仅会抛出异常,还会抛出段错误。

根据我多年使用 Python 的经验,我看到了许多段错误,其中一半在二进制模块(C 库,即.so / .pyd文件)中,一半在 CPython 二进制文件本身中。

当出现段错误时,整个 Python 程序以故障转储(或静默方式)结束。 我的问题是,如果段错误发生在某些代码块或线程中,是否有机会通过except将其作为常规异常捕获,从而防止整个程序崩溃?

众所周知,您可以使用faulthandler ,例如通过python -q -X faulthandler 然后它在段错误时创建以下转储:

>>> import ctypes
>>> ctypes.string_at(0)
Fatal Python error: Segmentation fault

Current thread 0x00007fb899f39700 (most recent call first):
  File "/home/python/cpython/Lib/ctypes/__init__.py", line 486 in string_at
  File "<stdin>", line 1 in <module>
Segmentation fault

但是上面的转储完全完成了程序。 相反,我想将此回溯作为一些标准异常进行捕获。


另一个问题是我是否可以在PyRun_SimpleString() function 的 C API 中捕获 Python 代码的段错误?

最简单的方法是拥有一个启动您的应用程序进程的“父”进程,并检查其退出值。 -11表示进程接收到信号11 ,即SEGFAULTV ( cf )

import subprocess

SEGFAULT_PROCESS_RETURNCODE = -11


segfaulting_code = "import ctypes ; ctypes.string_at(0)"  # https://codegolf.stackexchange.com/a/4694/115779
try:
    subprocess.run(["python3", "-c", segfaulting_code],
                   check=True)
except subprocess.CalledProcessError as err:
    if err.returncode == SEGFAULT_PROCESS_RETURNCODE:
        print("probably segfaulted")
    else:
        print(f"crashed for other reasons: {err.returncode}")
else:
    print("ok")

编辑:这是一个使用faulthandler故障处理程序的 Python 转储的可重现示例:

# file: parent_handler.py
import subprocess

SEGFAULT_PROCESS_RETURNCODE = -11


try:
    subprocess.run(["python3", "-m", "dangerous_child.py"],
                   check=True)
except subprocess.CalledProcessError as err:
    if err.returncode == SEGFAULT_PROCESS_RETURNCODE:
        print("probably segfaulted")
    else:
        print(f"crashed for other reasons: {err.returncode}")
else:
    print("ok")
# file: dangerous_child.py

import faulthandler
import time

faulthandler.enable()  # by default will dump on sys.stderr, but can also print to a regular file


def cause_segfault():  # https://codegolf.stackexchange.com/a/4694/115779
    import ctypes
    ctypes.string_at(0)


i = 0
while True:
    print("everything is fine ...")
    time.sleep(1)
    i += 1
    if i == 5:
        print("going to segfault!")
        cause_segfault()
everything is fine ...
everything is fine ...
everything is fine ...
everything is fine ...
everything is fine ...
going to segfault!

Fatal Python error: Segmentation fault

Current thread 0x00007f7a9ab35740 (most recent call first):
  File "/usr/lib/python3.8/ctypes/__init__.py", line 514 in string_at
  File "/home/stack_overflow/dangerous_child.py", line 9 in cause_segfault
  File "/home/stack_overflow/dangerous_child.py", line 19 in <module>
  File "<frozen importlib._bootstrap>", line 219 in _call_with_frames_removed
  File "<frozen importlib._bootstrap_external>", line 848 in exec_module
  File "<frozen importlib._bootstrap>", line 671 in _load_unlocked
  File "<frozen importlib._bootstrap>", line 975 in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 991 in _find_and_load
  File "/usr/lib/python3.8/runpy.py", line 111 in _get_module_details
  File "/usr/lib/python3.8/runpy.py", line 185 in _run_module_as_main

probably segfaulted

(两个进程的输出在我的终端中混合在一起,但您可以根据需要将它们分开)

这样您就可以查明问题是由 Python 代码ctypes.string_at引起的。

但正如马克在评论中指出的那样,如果程序被杀死是因为它做了坏事,你不应该相信它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM