c++ 符号可见性,异常,运行时错误

栏目: C++ · 发布时间: 6年前

内容简介:http://stackoverflow.com/questions/14268736/symbol-visibility-exceptions-runtime-error
我尝试更好地了解符号的可见性. GCC Wiki( http://gcc.gnu.org/wiki/Visibility

)有一个关于“C异常问题”的部分.根据GCC Wiki,由于没有导出的异常,有可能出现运行时错误.没有编译时错误/警告的运行时错误是相当危险的,所以我试图更好地了解问题.我做了一些实验,但我仍然无法重现.任何想法如何重现问题?

维基提到三个图书馆互相使用,所以我做了三个小图书馆.

我运行以下命令:

没有vtable的异常类(按预期工作):

make
./dsouser

异常类与vtable,但它不导出(甚至不编译):

make HAS_VIRTUAL=1

异常类导出vtable(按预期工作):

make HAS_VIRTUAL=1 EXCEPTION_VISIBLE=1
./dsouser

Makefile文件:

CXX=g++-4.7.1
CFLAGS=-ggdb -O0 -fvisibility=hidden
ifdef EXCEPTION_VISIBLE
  CFLAGS+=-DEXCEPTION_VISIBLE
endif
ifdef HAS_VIRTUAL
  CFLAGS+=-DHAS_VIRTUAL
endif
all: dsouser

libmydso.so: mydso.cpp mydso.h
    $(CXX) $(CFLAGS) -fPIC -shared -Wl,-soname,$@ -o $@ $<

libmydso2.so: mydso2.cpp mydso.h mydso2.h libmydso.so
    $(CXX) $(CFLAGS) -L.  -fPIC -shared -Wl,-soname,$@ -o $@ $< -lmydso

libmydso3.so: mydso3.cpp mydso.h mydso2.h mydso3.h libmydso2.so
    $(CXX) $(CFLAGS) -L.  -fPIC -shared -Wl,-soname,$@ -o $@ $< -lmydso -lmydso2

dsouser: dsouser.cpp libmydso3.so
    $(CXX) $< $(CFLAGS) -L. -o $@ -lmydso -lmydso2 -lmydso3

clean:
    rm -f *.so *.o dsouser

.PHONY: all clean

mydso.h:

#ifndef DSO_H_INCLUDED
#define DSO_H_INCLUDED
#include <exception>
#define SYMBOL_VISIBLE __attribute__ ((visibility ("default")))
namespace dso
{
  class
#ifdef EXCEPTION_VISIBLE
    SYMBOL_VISIBLE
#endif
    MyException : public std::exception
  {
  public:
#ifdef HAS_VIRTUAL
    virtual void dump();
#endif
    void SYMBOL_VISIBLE foo();
  };
}
#endif

mydso.cpp:

#include <iostream>
#include "mydso.h"
namespace dso
{

#ifdef HAS_VIRTUAL
void MyException::dump()
{
}
#endif

void MyException::foo()
{
#ifdef HAS_VIRTUAL
  dump();
#endif
}

}

mydso2.h:

#ifndef DSO2_H_INCLUDED
#define DSO2_H_INCLUDED
#define SYMBOL_VISIBLE __attribute__ ((visibility ("default")))
namespace dso2
{
  void SYMBOL_VISIBLE some_func();
}
#endif

mydso2.cpp:

#include <iostream>
#include "mydso.h"
#include "mydso2.h"
namespace dso2
{
  void some_func()
  {
    throw dso::MyException();
  }
}

mydso3.h:

#ifndef DSO3_H_INCLUDED
#define DSO3_H_INCLUDED
#define SYMBOL_VISIBLE __attribute__ ((visibility ("default")))
namespace dso3
{
  void SYMBOL_VISIBLE some_func();
}
#endif

mydso3.cpp:

#include <iostream>

#include "mydso2.h"
#include "mydso3.h"

#include <iostream>

namespace dso3
{

  void some_func()
  {
    try
    {
      dso2::some_func();
    } catch (std::exception e)
    {
      std::cout << "Got exception\n";
    }
  }

}

dsouser.cpp:

#include <iostream>
#include "mydso3.h"
int main()
{
  dso3::some_func();
  return 0;
}

谢谢,

达尼

我是GCC的原始补丁的作者,添加了类可见性支持,而我原来的GCC克隆的是 http://www.nedprod.com/programs/gccvisibility.html

.我感谢VargaD给我个人电子邮件告诉我这个SO问题.

您观察到的行为对最近的海湾合作委员会是有效的,但并不总是如此.在2004年我原来修补GCC的时候,我向GCC的bugzilla提交了GCC异常处理运行时间的请求,以比较它们的被破坏符号的字符串比较而不是比较这些字符串的地址来比较抛出的类型 – 当时被GCC拒绝维护者作为不可接受的运行时成本,尽管这种行为是MSVC所做的,尽管在异常抛出期间的性能一般不被认为是重要的,因为它们应该是罕见的.因此,我不得不在我的可见性指南中添加一个特定的异常来说,任何抛出的类型永远不会被隐藏,而不是一次在二进制中,因为“隐藏”胜过“默认”,所以只有一个隐藏的符号声明保证覆盖所有的在给定二进制文件中的相同符号.

接下来发生了什么我想我们没有人希望 – KDE非常公开地接受了我的贡献.几乎每个大型GCC使用项目都在惊人的短暂时间内逐级进行.突然的象征隐藏是常态,而不是例外.

不幸的是,少数人没有正确地应用我的引导异常抛出类型,并且关于GCC中不正确的交叉共享对象异常处理的常量错误报告最终导致GCC维护者放弃和多年后补丁的字符串比较对于投掷类型匹配,正如我原来要求的那样.因此,在新的海湾合作机构中,情况有所好转.我没有改变我的指南和说明,因为这种方法在v4.0之后的每个GCC上仍然是最安全的,而由于现在使用字符串比较,较新的GCC更可靠地处理异常抛出,遵循指南的规则并不会那.

这给我们带来了typeinfo的问题.一个大问题是,最佳实践C要求您始终以可抛弃类型继承,因为如果您组合两个异常类型,则从std :: exception继承(让我们说),具有两个等距的std :: exception基类将导致catch (std :: exception&)自动调用terminate(),因为它不能解析要匹配的基类,所以你一直只能有一个std :: exception基类,并且相同的理由适用于任何可能的组合可抛出型这种最佳做法在任何C库中都是特别需要的,因为您无法知道第三方用户将如何处理异常类型.

换句话说,这意味着最佳实践中所有抛出的异常类型将始终带有每个基类的连续RTTI链,并且该异常匹配现在是内部执行成功的dynamic_cast的一种情况.到匹配的类型,O(基类数)操作.而对于dynamic_cast<>您可以通过一系列几乎继承的类型进行处理,您可以猜到,您需要每个链接中的每一个都具有默认的可见性.如果从执行catch()的代码中隐藏了一个,那么整个caboodle都会被打开,你会得到一个terminate().如果您重写上面的示例代码,我将非常感兴趣,以便虚拟地继承并看到会发生什么 – 您的一个评论表示拒绝链接,这是非常好的.但是我们来说,DLL A将类型A,DLL B子类型A分类为B,将C类C类C类转换为C,而程序D在C类引发时尝试捕获类型A的异常.程序D将具有A的类型信息可用,但是当尝试获取类型B和C的RTTI时,应该出现故障.尽管如此,最近的GCC也已经修复了?我不知道,我近年来的注意事项是cl铛,因为这是所有C编译器的未来.

显然,这是一个混乱,但它是一个ELF特定的混乱 – 没有一个会影响PE或MachO,这两个都通过不使用进程全局符号表来获得上述所有权利.然而,针对C 17的WG21 SG2模块研究组必须有效地实施模块的导出模板才能解决ODR违规问题,而C 17是我看到的第一个提出的使用LLVM编写的标准.换句话说,C 17编译器将不得不将复杂的AST转储到盘上,如ang ang.这意味着RTTI可用的担保大幅增加 – 实际上,这就是为什么我们有SG7反思研究组,因为来自C模块的AST可以大大增加可能的自我反省机会.换句话说,预期上述问题很快就会被C 17采用.

所以,简而言之,现在继续遵循我的原始指南.在未来的十年中,事情有望得到更好的发展.并感谢苹果为这个解决方案提供资金,由于恶意的恶化已经很久了.

尼尔

http://stackoverflow.com/questions/14268736/symbol-visibility-exceptions-runtime-error


以上所述就是小编给大家介绍的《c++ 符号可见性,异常,运行时错误》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

周鸿祎自述

周鸿祎自述

周鸿祎 / 中信出版社 / 2014-8 / 45.00元

在很多方面,周鸿祎都是互联网领域的颠覆者。他重新定义了“微创新”,提出从细微之处着手,通过聚焦战略,以持续的创新,最终改变市场格局、为客户创造全新价值。他第一个提出了互联网免费安全的理念,也由此让奇虎360拥有了超过4亿的用户。 在《周鸿祎自述:我的互联网方法论》中,周鸿祎首次讲述了自己的互联网观、产品观和管理思想,厘清了互联网产品的本质特征和互联网时代的新趋势,列举了颠覆式创新在现实中的实......一起来看看 《周鸿祎自述》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换