检查评估地址是否会导致段错误而不导致 python 崩溃

问题描述 投票:0回答:1

我尝试过的:

  1. faulthandler
    对于获取发生段错误的回溯非常有用,但它不允许正确处理它。
import faulthandler
faulthandler.enable()

import ctypes
try:
    # Windows fatal exception: access violation
    # Current thread 0x00001334 (most recent call first):
    # File "c:\Users\Andrej\Desktop\pomoika\test.py", line 6 in <module>
    ctypes.c_byte.from_address(0).value
    print('never printed')
except:
    print('never printed')
  1. 使用
    singal.signal
    设置处理程序 - 它有效,如文档这个问题中所述,处理程序的Python代码永远不会执行,因为处理段错误也会递归地导致段错误。
import ctypes
import signal

class AccessError(Exception):
    pass

def handler(signum, frame):
    raise AccessError("Memory access violation")

def is_safe(address: int) -> bool:
    try:
        # Set signal handler for segmentation faults
        signal.signal(signal.SIGSEGV, handler)
        v = ctypes.c_uint.from_address(address)
        a = v.value
        return True
    except AccessError:
        return False
    finally:
        # Reset signal handler to default behavior
        signal.signal(signal.SIGSEGV, signal.SIG_DFL)

# Test the function
print('before')
print(is_safe(0))  # Should print False or True depending on the address
print('after')
  1. 在单独的线程中检查它。它有点工作,但在 Windows 上它返回 False、True、False,所以我猜它不是跨平台的。
import ctypes
import multiprocessing


def check_address(queue, address):
    try:
        ctypes.c_byte.from_address(address).value
        queue.put(True)
    except Exception:
        queue.put(False)


def is_safe(address: int, timeout: float = 1.0) -> bool:
    queue = multiprocessing.Queue()
    process = multiprocessing.Process(target=check_address, args=(queue, address))
    process.start()
    process.join(timeout)
    if process.exitcode is None:
        process.terminate()
        raise Exception(f"Process is stuck (it took longer than {timeout}).")
    elif process.exitcode == 0:
        process.terminate()
        process.join()
        v = queue.get()
        return v
    return False


if __name__ == "__main__":
    print(0, is_safe(0)) # False
    print("id(object)", is_safe(id(object))) # True
    a = object()
    print("a", is_safe(id(a))) # True
python segmentation-fault ctypes python-c-api
1个回答
0
投票

我发现的最简单的解决方案是使用

os.write
。 我想知道是否有一种更简单的方法可以做到这一点,而无需设置
os.pipe
并稍后关闭它。

import ctypes
import os


def is_safe(address: int, /) -> bool:
    # made by @chilaxan
    if address <= 0:
        return False
    r, w = os.pipe()
    try:
        return os.write(w, ctypes.c_char.from_address(address)) == 1
    except OSError as e:
        # [Errno 22] Invalid argument
        return False
    finally:
        os.close(r)
        os.close(w)


if __name__ == "__main__":
    print(0, is_safe(0))  # False
    print(1, is_safe(1))  # False
    print("id(object)", is_safe(id(object)))  # True
    a = object()
    print("a", is_safe(id(a)))  # True
© www.soinside.com 2019 - 2024. All rights reserved.