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

问题描述 投票:15回答:3

我现在正在使用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!\n";
    }

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

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

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

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


4
投票

0
投票
© www.soinside.com 2019 - 2024. All rights reserved.