【发布时间】:2012-12-25 11:29:21
【问题描述】:
我尝试更好地理解符号可见性。 GCC Wiki (http://gcc.gnu.org/wiki/Visibility) 有一个关于“C++ 异常问题”的部分。根据 GCC Wiki,由于未导出异常,可能会出现 runtime 错误。没有编译时错误/警告的运行时错误是非常危险的,所以我试图更好地理解这个问题。我做了一些实验,但我仍然无法重现它。任何想法如何重现该问题?
Wiki 中提到了三个库相互使用,所以我做了三个小库。
我运行以下命令:
没有 vtable 的异常类(按预期工作):
make
./dsouser
带有 vtable 的异常类,但它不导出(甚至不编译):
make HAS_VIRTUAL=1
异常类导出 vtable(按预期工作):
make HAS_VIRTUAL=1 EXCEPTION_VISIBLE=1
./dsouser
生成文件:
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;
}
谢谢, 丹妮
【问题讨论】:
-
我也无法重现任何问题。我怀疑应该没有。链接的文章告诉我们正确捕获异常需要一个符号,但它没有告诉我们为什么需要它。它说有一个 typeinfo 查找,但它没有说明应该在哪里进行查找。在整个程序的符号表中?如果程序被剥离怎么办?只在抛出的异常数据中包含 typeinfo 指针不是更简单更容易吗?
-
我制作了另一个小型测试应用程序:一个带有异常(从 std::exception 继承)的库,它没有被导出,但它有一个虚拟方法,所以它有 vtable。该库有一个引发异常的函数。主程序包含带有异常的标头,但如果由于缺少类型信息而尝试准确捕获异常,则无法编译。但是它正确捕获了 std::exception。如果没有虚拟方法,它也会捕获我的异常。
标签: c++ exception visibility symbols elf