是否可以捕获分段错误?

Is it possible to trap a segmentation fault?

我的应用程序依赖于 ghostscript 将一些 pdf 文件转换为文档每一页的一系列图像。这是一个简化版本:

import locale

from ghostscript import Ghostscript as gs
from ghostscript import cleanup
from cv2 import imread, IMREAD_GRAYSCALE as GRAY
from multiprocessing import cpu_count

args = [
  "",
  "-q", "-r300", "-dNOPAUSE",
  "-sDEVICE=pgmraw",
  "-sOutputFile=%d.pgm",
  "-dNumRenderingThreads=" + str(cpu_count()),
  "-f", "_.pdf" #filename will always be "_.pdf"
]
encoding = locale.getpreferredencoding()
args = [a.encode(encoding) for a in args]

def pdftoimarray():
    cleanup()
    gs(*args)
    imarray = []
    for filename in os.listdir():
        imarray.append(imread(filename, GRAY))
    return imarray

(我故意在最后删除了文件系统的清理:这对这个问题来说并不重要)

问题是,我真的不能相信这些文件的来源,其中一些可能有错误。 运行 一些测试,我发现其中一些错误的文件导致 ghostscript 实际上发生了段错误,这反过来又使我的整个应用程序崩溃。

通常,段错误是一个非常严重的事件,我们无法真正从中恢复,所以我怀疑是否真的有可能捕获它。但就我而言,它不应该真的那么严重:假设我的程序仍处于有效状态,我可以将该文档标记为 bad 然后继续。

问题:我能否以某种方式在我的依赖项中捕获此分段错误,并从中恢复?

之前在 Segmentation Fault Catch, but the only answer is wrong (It suggests trapping it with signal.signal, but the documentation clearly says that catching synchronous signals such as SIGSEGV makes little sense using it. The same documentation points to faulthandler 中有人问过这个问题,但它并不能真正捕获信号:它只是在发生这种情况时提供更好的错误消息。

这留下了这个问题如何独特而不是重复的问题:我的限制有所减少:我根本不打算处理这个问题:我只想忽略它并继续前进。任何关于首先实际避免 ghostscript 中的段错误的观点也将得到很好的接受。

这个问题有点老了,但我想我应该分享这个:我正在看一个关于一个很酷的新内存分配器的视频,关于观众的一个问题,作者解释说他 "Installs a segfault handler",这是我非常感兴趣的。我仍然不知道他到底是怎么做到的,所以这并不能完全回答我的问题,但它给了我一个开始研究的好地方。如果我设法自己解决这个问题,我会 post 在这里回答。

这是视频(link是他回答我说的问题的时候) https://youtu.be/c1UBJbfR-H0?t=2058

我有一个类似的问题,通过 pythonocc 渲染 cad 文件。 有时在打开文件时,脚本会出现段错误。真的很烦人。您必须手动删除文件并重新启动批处理。

所以基本上这个想法是为任务启动一个额外的进程并检查它是 exitcode:

import multiprocessing as mp


def do_stuff_that_segfaults(param):
    call_shitty_library(param)

def main():
    p = mp.Process(target=do_stuff_that_segfaults, args=param)            
    p.start()            
    p.join()
    if p.exitcode == -11:  # Segmentation fault
        do_stuff_in_case_of_segfault()

我也尝试过其他建议,例如您链接到的 Segmentation Fault Catch,但无济于事。 我真的很想使用 mp.pool() 来使用所有内核,但是 you don't get the exit status from mp.pool().

到目前为止,代码运行良好,我通过 do_stuff_in_case_of_segfault() 将导致段错误的文件移动到另一个文件夹,而没有杀死我的主脚本。