现在,差不多 2 年后(仍然在 Kristofer 提出问题时在同一家公司工作),再次提出问题 - 最后我想我明白为什么没有生成核心转储!
这个问题是由 Ada 运行时引起的,它默认为一些 POSIX 信号实现信号处理程序(对于 Linux:SIGABRT、SIGFPE、SIGILL、SIGSEGV 和 SIGBUS)。对于 GNAT/linux,信号处理程序在a-init.c中称为__gnat_error_handler,如下所示:
static void
__gnat_error_handler (int sig)
{
struct Exception_Data *exception;
char *msg;
static int recurse = 0;
...
switch (sig)
{
case SIGSEGV:
if (recurse)
{
exception = &constraint_error;
msg = "SIGSEGV";
}
else
{
...
msg = "stack overflow (or erroneous memory access)";
exception = &storage_error;
}
break;
}
recurse = 0;
Raise_From_Signal_Handler (exception, msg);
}
这个处理程序是“进程范围的”,并且将被任何触发信号调用,无论它来自进程的哪个部分(无论是否以 Ada/C/C++ 编码......)。
调用时,处理程序会引发 Ada 异常并将其留给 Ada 运行时以查找适当的异常处理程序 - 如果未找到此类处理程序(例如,当 C++ 代码的任何部分生成 SIGSEGV 时),Ada -runtime 退回到只是终止进程并从__gnat_error_handler留下一个简单的打印输出(例如“堆栈溢出(或错误的内存访问)”)。
http://www2.adacore.com/gap-static/GNAT_Book/html/node25.htm
为了防止 Ada 运行时处理 POSIX 信号并将其转换为 Ada 异常,可以通过使用禁用默认行为
pragma Interrupt_State (Name => value, State => SYSTEM | RUNTIME | USER); ,
例如。要禁用 SIGSEGV 处理,请定义
Pragma Interrupt_State(SIGSEGV, SYSTEM);
在您的 Ada 代码中 - 现在系统的默认行为将在引发 SIGSEGV 时触发,并且将生成一个核心转储,以便您追踪问题的根源!
我认为这是在 *NIX 平台上混合 Ada 和 C/C++ 时需要注意的一个非常重要的问题,因为它可能会误导您认为问题源于 Ada 代码(因为打印输出表明从 Ada 生成的异常) 当问题的真正根源在于 C/C++ 代码时...
尽管禁用 SIGSEGV 的 Ada 运行时默认处理可能是安全的(我猜没有理智的程序员在任何“预期的”错误处理中使用它......好吧,也许在航空软件或类似软件中使用,当某种“最后的手段" 需要维护功能以避免发生真正糟糕的事情..) 我想应该小心一点,然后“覆盖”信号的 Ada 运行时处理。
一个问题可能是 SIGFPE 信号,默认情况下也会引发 Ada Constraint_Error 异常。Ada 代码可以将这种类型的异常用作“预期行为”。通过 Pragma Interrupt_State 禁用 SIGFPE 可能会严重影响 Ada 代码的执行,并在“正常情况下”使您的应用程序崩溃 - 另一方面,C/C++ 代码中的任何除零都会触发 Ada 异常处理机制,并且让您无法真正找到问题的根源......