【问题标题】:Can I safely access potentially unallocated memory addresses?我可以安全地访问可能未分配的内存地址吗?
【发布时间】:2015-08-05 15:38:44
【问题描述】:

我正在尝试创建类似 memcpy 的函数,当给定内存中的地址是未分配页面的一部分时,该函数将正常失败(即返回错误而不是段错误)。我认为正确的做法是安装一个 sigsegv 信号处理程序,并在处理程序中做一些事情以使 memcpy 函数停止复制。

但我不确定在我的程序是多线程的情况下会发生什么:

  • 信号处理程序是否可以在另一个线程中执行?
  • 如果段错误与任何 memcpy 操作无关,会发生什么情况?
  • 如何处理同时执行 memcpy 的两个线程?
  • 我是否遗漏了其他内容?我在寻找无法实现的东西吗?

【问题讨论】:

    标签: multithreading operating-system signals


    【解决方案1】:

    相信我,你确实不想走那条路。出于多种原因,这是一罐蠕虫。正确的信号处理在单线程环境中已经很困难,但在多线程代码中却很困难。

    首先,从异常条件导致的信号处理程序返回是未定义的行为 - 它在 Linux 中有效,但它仍然是未定义的行为,迟早会给您带来问题。

    来自man 2 sigaction:

    进程正常返回后的行为是不确定的 SIGBUS、SIGFPE、SIGILL 或 SIGSEGV 的信号捕获功能 不是由 kill()、sigqueue() 或 raise() 生成的信号。

    (注意:这不会出现在 Linux 手册页上;but it's in SUSv2)

    这也在 POSIX 中指定。虽然它在 Linux 中有效,但这不是一个好的做法。

    下面是您问题的具体答案:

    信号处理程序是否可以在另一个线程中执行?

    是的,是的。一个信号被传递给任何没有阻塞它的线程(当然只传递给一个线程),尽管在 Linux 和许多其他 UNIX 变体中,异常相关的信号(SIGILL、SIGFPE、SIGBUS 和SIGSEGV) 通常会传递给导致异常的线程。不过这不是必需的,因此为了获得最大的可移植性,您不应依赖它。

    您可以使用pthread_sigmask(2) 来阻止除一个以外的每个线程中的信号;这样你就可以确保每个信号总是被传递到同一个线程。这使得有一个专用于信号处理的线程很容易,这反过来又允许您进行同步信号处理,因为线程可能使用sigwait(2)(注意多线程代码应该使用sigwait(2)而不是sigsuspend(2))直到传递一个信号,然后同步处理它。这是一种很常见的模式。

    如果段错误与任何 memcpy 操作无关,会发生什么?

    好问题。信号已传递,并且没有(微不足道的)方法可以轻松区分真正的段错误和 memcpy(3) 中的段错误。

    如果你有一个线程处理每个信号,就像我上面提到的那样,你可以使用sigwaitinfo(2),然后在sigwaitinfo(2) 返回时检查siginfo_t 的si_addr 字段。 si_addr 字段是导致故障的内存位置,因此您可以将其与传递给memcpy(3) 的内存地址进行比较。

    但某些平台,尤其是 Mac OS,没有实现 sigwaitinfo(2) 或其近亲 sigtimedwait(2)。

    所以没有办法做到便携。

    如何处理同时执行 memcpy 的两个线程?

    这个问题我不是很懂,多线程memcpy(3)有什么特别之处?调用者有责任确保正在读取和写入的内存区域不会被同时访问; memcpy(3) 不是(也从来不是)线程安全的,如果你将它传递给重叠的缓冲区。

    我还缺少其他东西吗?我在寻找什么 无法实现?

    如果您关心可移植性,我会说这几乎是不可能的。即使你只专注于 Linux,也很难。如果这很容易做到,那么这个时候可能已经有人做到了。

    我认为您最好构建自己的分配器并强制用户代码依赖它。然后您可以存储状态并管理分配的内存,并轻松判断传递的缓冲区是否有效。

    【讨论】:

    • 关于我的第三个项目符号,没有什么特别之处,只是如果两个线程在某处注册为执行 memcpy,那么我不确定如何判断将段错误归因于哪个线程。
    • @nitzanms 啊,这是一个好点。我想说你可以在 Linux 中使用相同的 sigwaitinfo(2) 技巧。
    猜你喜欢
    • 1970-01-01
    • 2022-06-10
    • 2012-03-24
    • 1970-01-01
    • 2010-12-02
    • 2012-05-09
    • 1970-01-01
    • 2020-04-09
    • 2017-11-28
    相关资源
    最近更新 更多