WeHack BBS
C++类同名导致的ABI错误 - 可打印的版本

+- WeHack BBS (https://bbs.wehack.space)
+-- 版块: 计算机技术 (https://bbs.wehack.space/forum-5.html)
+--- 版块: 程序设计讨论区 (https://bbs.wehack.space/forum-14.html)
+--- 主题: C++类同名导致的ABI错误 (/thread-341.html)



C++类同名导致的ABI错误 - vimacs - 06-13-2022

最近发现GCC在对C++程序进行链接时优化的时候,如果在不同的目标文件出现了同名类,会给出一个 "type ‘...’ violates the C++ One Definition Rule [-Wodr]" 的警告。开始我以为不是什么问题,直到后来发现它的确导致了错误之后,才知道为什么会有这个警告。

如何发现此类问题:开 address sanitizer 编译项目,运行时报告错误,但 ASAN 不知道错误的类型,推测可能是 ABI 类错误。

可以导致这类错误的例子如下:

代码:
// v1.cc
#include <vector>

using namespace std;

struct A
{
  int a,b;
  A(int x): a(x), b(x) {}
};

class T1
{
  vector<A> v;
public:
  void test(int n)
  {
    for (int i = 0; i < n; ++i) {
      v.push_back(i);
    }
  }
};

void t1_test(int n)
{
  T1 t;
  t.test(n);
}

代码:
// v2.cc
#include <vector>

using namespace std;

struct A
{
  int a,b,c;
  A(int x): a(x), b(x), c(x) {}
};

class T2
{
  vector<A> v;
public:
  void test(int n)
  {
    for (int i = 0; i < n; ++i) {
      v.push_back(i);
    }
  }
};

void t2_test(int n)
{
  T2 t;
  t.test(n);
}

代码:
// main.cc
void t1_test(int n);
void t2_test(int n);

int main()
{
  t1_test(1000);
  t2_test(1000);
}

先编译这几个文件为目标文件,然后链接:

引用:g++ -o main main.o v1.o v2.o
./main

这时运行结果正常。

但是如果改为:

引用:g++ -o main main.o v2.o v1.o
./main

这时程序会报告一个 stack smashing 后崩溃。

原因就在于 v1.o 和 v2.o 里面 std::vector<A> 的成员函数都编译为弱符号,链接的时候连接器会选择其中一个符号使用,但是实际上相同符号指向的是不同的实现代码,从而导致程序出错。

解决这类问题的方法也很简单,使用 namespace 就可以了。