longjmp解除的C/C++实现?

R..*_*R.. 14 c c++ exception-handling stack-unwinding longjmp

是否有主要的C/C++实现,其中longjmp函数"展开",即它与自动存储对象的析构函数__attribute__((__cleanup__(...))),POSIX线程取消处理程序等交互,而不仅仅是恢复由setjmp?保存的寄存器上下文?我对使用此属性的POSIX实现的存在(或不存在)特别感兴趣,但C/C++通常也很有趣.

对于赏金,我正在寻找符合POSIX或至少类似POSIX的系统,而不是已经提到过的Windows.

小智 0

Interix (SUA) 默认情况下不调用析构函数,但在 x86 模式下,确实有一个选项。

采取这个测试程序,保存为test.cc

#include <stdio.h>
#include <setjmp.h>

struct A {
  ~A() { puts("~A"); }
};

jmp_buf buf;

void f() {
  A a;
  longjmp(buf, 1);
}

int main() {
  if (setjmp (buf))
    return 0;

  f();
}
Run Code Online (Sandbox Code Playgroud)

Interix 的行为方式如下。为简洁起见,我省略了所需的正确设置PATH

$ cc -mx86 test.cc && ./a.out
$ cc -mx86 -X /EHa test.cc && ./a.out
cl:命令行警告 D9025:用“/EHa”覆盖“/EHs”
~A
$ cc -mamd64 test.cc && ./a.out
$ cc -mamd64 -X /EHa test.cc && ./a.out
cl:命令行警告 D9025:用“/EHa”覆盖“/EHs”
$

注释表明cc -X /EHa不符合 POSIX,例如因为/EHa会捕获信号。这并不完全正确:

$ 猫测试.cc
#include <信号.h>
int main() {
  尝试 {
    提高(SIGFPE);
  } 抓住 (...) {
    // 忽略
  }
}
$ cc -mx86 -X /EHa test.cc && ./a.out
cl:命令行警告 D9025:用“/EHa”覆盖“/EHs”
浮点异常(核心转储)

如果我更改raise(SIGFPE)为除以零,我确实看到异常处理程序捕获了它,但 POSIX 和 C++ 都不需要任何特定的行为,因此这不会影响一致性。也不是所有异步信号都被捕获:对于这个程序:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void sigint(int signal) {
  puts("sigint");
  exit(0);
}
int main() {
  signal(SIGINT, sigint);
  try {
    for (;;) ;
  } catch (...) {
    // ignore
  }
}
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,在 Ctrl-C 之后打印“sigint”。我看不出有什么理由声称此实现无法满足 POSIX 要求。

  • 我没有联系,但很容易证明。如果使用 `/EHa` 进行编译不会破坏 POSIX 信号,那么以下程序将由于致命错误而具有退出代码 != 0,就像 CentOS 上的情况一样:http://ideone.com/ HpOmzf。这是因为 POSIX 定义,在未处理信号的情况下,退出代码设置为值 != 0。用 `/EHa` 编译它让它返回 0,因为每个异常都会被捕获(div0 异常也是如此),正如 http://msdn.microsoft.com/en-us/library/1deeycx5.aspx 声称的那样。 (4认同)
  • 奖牌总是有两个面。系统必须支持 POSIX 一致性,并且程序必须使用它。但为了赏金,R.. 正在寻找符合 POSIX 标准的实现(第一个属性),它在展开期间调用析构函数(第二个属性)。当然,Interix 支持这两个属性,但如果您以不支持第一个属性的方式编译程序,则仅支持第二个属性。所以我认为这是有问题的。顺便说一句,甚至微软也警告他们的用户不要将 SEH 和“/EHa”用于可移植程序。 (3认同)
  • @StefanWeiser:该程序调用未定义的行为,因此 POSIX 没有说明它的作用。如果将其更改为“raise(SIGFPE)”,是否会发生同样的情况? (2认同)
  • @StefanWeiser 不仅如 R.. 指出的那样,程序的行为未定义,而且如果定义了它,它甚至不会证明您的观点。POSIX 允许 `catch(...)` 对引发的信号产生影响,只是因为它根本没有说明任何有关 C++ 的内容。(我还没有测试过任何东西。) (2认同)
  • @hvd,@R ..:我想,我们没有以相同的兼容性术语说话。在我看来,如果一个程序在每个 POSIX 兼容系统上都会产生相同的行为,那么它就是 POSIX 兼容的。您可以将 SIGFPE 与 MS 抛出并捕获的任何其他信号交换。顺便说一句,只要不是由“raise”或“kill”引发,该行为就是未定义的。所以我可以使用 raise 更新程序...得到相同的结果... (2认同)