在C回调中的C ++中引发异常,可能会跨越动态库边界……是否安全?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在C回调中的C ++中引发异常,可能会跨越动态库边界……是否安全?相关的知识,希望对你有一定的参考价值。

我现在正在使用libjpeg保存JPEG图像。如果有错误,libjpeg的默认行为是调用exit(),我想避免这种错误,因为这对我的程序来说不是致命错误。 libjpeg allows you to use your own error manager,并要求如果使用自己的error_exit()函数(默认情况下会调用exit()),则必须不能将控制权交还给调用者。 libjpeg建议使用setjmp.h来满足此要求,而不要使用exit()该程序。

但是,我正在编写C ++程序,并且可以访问异常。 This question's answer声明从回调中引发异常是安全的(如定义良好的行为)。但是它没有提到动态库,并且有一个普遍的经验法则,即不要跨动态库边界抛出异常。

这里是一个例子:

#include <iostream>
#include <jpeglib.h>
#include <cstdio>
#include <stdexcept>

static void handleLibJpegFatalError(j_common_ptr cinfo)
{
  (*cinfo->err->output_message)(cinfo);
  throw std::runtime_error("error in libjpeg, check stderr");
}

int main()
{
  struct jpeg_compress_struct cinfo;
  struct jpeg_error_mgr jerr;
  FILE* file = std::fopen("out.jpeg", "wb"); // assume this doesn't fail for this example

  try
    {
      cinfo.err = jpeg_std_error(&jerr);
      jerr.error_exit = handleLibJpegFatalError;

      // let's say this triggers a fatal error in libjpeg and handleLibJpegFatalError() is called
      // by libjpeg
      jpeg_create_compress(&cinfo);
    }
  catch (...)
    {
      std::cerr << "Error saving the JPEG!
";
    }

  jpeg_destroy_compress(&cinfo);
  std::fclose(file);
}

[[我想知道的是:即使libjpeg被编译为动态库,我也可以从此回调中引发异常并将其捕获到我的应用程序中吗? libjpeg可以是静态库或动态库,如果它是动态库,则可能使用其他编译器来构建。但是,引发并捕获异常的代码肯定会在同一编译单元中。 以上代码安全吗?

FYI,我正在为OS X和Windows进行开发(并牢记Linux的未来可能性),所以我更感兴趣的是,这通常是否是定义良好的行为,而不是针对特定行为平台/编译器。
答案
这不安全。根据相关非C ++库代码的编译方式,可能不存在必要的展开表。这只是它可能失败的原因。概念上的原因是它只是未定义的行为。

您应该遵循文档,并使用setjmp / longjmp移至libjpeg代码的调用之外,如果要使用异常,请立即在if (setjmp(...)) { ... }正文中引发异常。

另一答案
None
另一答案
None

以上是关于在C回调中的C ++中引发异常,可能会跨越动态库边界……是否安全?的主要内容,如果未能解决你的问题,请参考以下文章

从完成处理程序/块中引发自定义异常会使目标 c 中的应用程序崩溃

C ++中的内存泄漏示例(通过使用异常)[重复]

跨 C API 边界传递异常

在UWP中,我们可以使用动态编译和使用C#Reflection的成员调用动态编译和调用UWP中的新页面吗?

C 语言异常处理(五十二)

C++11 线程是可连接的,但 join() 会引发异常