How to catch SegFault in Python as exception?

Question:

Sometimes Python not only throws exception but also segfaults.

Through many years of my experience with Python I saw many segfaults, half of them where inside binary modules (C libraries, i.e. .so/.pyd files), half of them where inside CPython binary itself.

When segfault is issued then whole Python program finishes with crashdump (or silently). My question is if segfault happens in some block of code or thread is there any chance to catch it as regular Exception through except, and thus preventing whole program from crashing?

It is known that you can use faulthandler, for example through python -q -X faulthandler. Then it creates following dump when segfaults:

>>> 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

But this dump above finishes program entirely. Instead I want to catch this traceback as some standard Exception.


Another question is whether I can catch segfault of Python code inside C API of PyRun_SimpleString() function?

Asked By: Arty

||

Answers:

The simplest way is to have a "parent" process which launches your app process, and check its exit value. -11 means the process received the signal 11 which is 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")

EDIT: here is a reproducible example with a Python dump using the built-in faulthandler :

# 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

(outputs from both processes got mixed in my terminal, but you can separate them as you like)

That way you can pinpoint the problem was caused by the Python code ctypes.string_at.

But as Mark indicated in the comments, you should not trust this too much, if the program got killed is because it was doing bad things.

Answered By: Lenormju
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.