__cxxabiv1::__cxa_pure_virtual () 崩溃 - vtable ptr 到抽象基类?
Posted
技术标签:
【中文标题】__cxxabiv1::__cxa_pure_virtual () 崩溃 - vtable ptr 到抽象基类?【英文标题】:crashing for __cxxabiv1::__cxa_pure_virtual () - vtable ptr to abstract base class? 【发布时间】:2018-03-08 10:50:12 【问题描述】:我的应用程序崩溃了:
__cxxabiv1::__cxa_pure_virtual ()
我能理解What is the meaning of a "pure virtual" call in a stack trace?
根据下面的“1 个答案”,我可以练习一个小测试程序:
1 #include <iostream>
2
3 class Base
4
5 public:
6 Base()
7
8 std::cout << "Base c'tor" << std::endl;
9
10
11 virtual ~Base()
12
13 std::cout << "Base d'tor" << std::endl;
14
15
16 ;
17
18 class Derived : public Base
19
20 public:
21 Derived()
22 : Base()
23
24 std::cout << "Derived c'tor" << std::endl;
25
26
27 ~Derived()
28
29 std::cout << "Derived d'tor" << std::endl;
30
31 ;
32
33 int
34 main(
35 int,
36 char**)
37
38
39 Derived d;
40
41 return 0;
42
编译:
g++ -g3 -O0 -o test test.cc
创建 gdb 批处理脚本:
break 8
command
p this
x/10xg this
x/10xg (long)*this
cont
end
break 13
command
p this
x/10xg this
x/10xg (long)*this
cont
end
break 24
command
p this
x/10xg this
x/10xg (long)*this
cont
end
break 29
command
p this
x/10xg this
x/10xg (long)*this
cont
end
run
然后运行:
frank@frank-PC:~$ gdb ./test < gdb.bat |c++filt
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./test...done.
(gdb) Breakpoint 1 at 0x400b72: file test.cc, line 8.
(gdb) >>>>>(gdb) Breakpoint 2 at 0x400baa: file test.cc, line 13.
(gdb) >>>>>(gdb) Breakpoint 3 at 0x400c29: file test.cc, line 24.
(gdb) >>>>>(gdb) Breakpoint 4 at 0x400c81: file test.cc, line 29.
(gdb) >>>>>(gdb) Starting program: /home/frank/test
Breakpoint 1, Base::Base (this=0x7fffffffdab0) at test.cc:8
8 std::cout << "Base c'tor" << std::endl;
$1 = (Base * const) 0x7fffffffdab0
0x7fffffffdab0: 0x0000000000400df8 0x597870ad9bc42900
0x7fffffffdac0: 0x0000000000400d10 0x00007ffff7495830
0x7fffffffdad0: 0x0000000000000000 0x00007fffffffdba8
0x7fffffffdae0: 0x00000001ffffdbb8 0x0000000000400ab6
0x7fffffffdaf0: 0x0000000000000000 0x9e98039144430dd4
0x400df8 <vtable for Base+16>: 0x0000000000400b92 0x0000000000400bde
0x400e08 <typeinfo for Derived>: 0x0000000000602200 0x0000000000400e20
0x400e18 <typeinfo for Derived+16>: 0x0000000000400e30 0x6465766972654437
0x400e28 <typeinfo name for Derived+8>: 0x0000000000000000 0x0000000000602090
0x400e38 <typeinfo for Base+8>: 0x0000000000400e40 0x0000006573614234
Base c'tor
Breakpoint 3, Derived::Derived (this=0x7fffffffdab0) at test.cc:24
24 std::cout << "Derived c'tor" << std::endl;
$2 = (Derived * const) 0x7fffffffdab0
0x7fffffffdab0: 0x0000000000400dd8 0x597870ad9bc42900
0x7fffffffdac0: 0x0000000000400d10 0x00007ffff7495830
0x7fffffffdad0: 0x0000000000000000 0x00007fffffffdba8
0x7fffffffdae0: 0x00000001ffffdbb8 0x0000000000400ab6
0x7fffffffdaf0: 0x0000000000000000 0x9e98039144430dd4
0x400dd8 <vtable for Derived+16>: 0x0000000000400c68 0x0000000000400ce2
0x400de8 <vtable for Base>: 0x0000000000000000 0x0000000000400e30
0x400df8 <vtable for Base+16>: 0x0000000000400b92 0x0000000000400bde
0x400e08 <typeinfo for Derived>: 0x0000000000602200 0x0000000000400e20
0x400e18 <typeinfo for Derived+16>: 0x0000000000400e30 0x6465766972654437
Derived c'tor
Breakpoint 4, Derived::~Derived (this=0x7fffffffdab0, __in_chrg=<optimized out>) at test.cc:29
29 std::cout << "Derived d'tor" << std::endl;
$3 = (Derived * const) 0x7fffffffdab0
0x7fffffffdab0: 0x0000000000400dd8 0x597870ad9bc42900
0x7fffffffdac0: 0x0000000000400d10 0x00007ffff7495830
0x7fffffffdad0: 0x0000000000000000 0x00007fffffffdba8
0x7fffffffdae0: 0x00000001ffffdbb8 0x0000000000400ab6
0x7fffffffdaf0: 0x0000000000000000 0x9e98039144430dd4
0x400dd8 <vtable for Derived+16>: 0x0000000000400c68 0x0000000000400ce2
0x400de8 <vtable for Base>: 0x0000000000000000 0x0000000000400e30
0x400df8 <vtable for Base+16>: 0x0000000000400b92 0x0000000000400bde
0x400e08 <typeinfo for Derived>: 0x0000000000602200 0x0000000000400e20
0x400e18 <typeinfo for Derived+16>: 0x0000000000400e30 0x6465766972654437
Derived d'tor
Breakpoint 2, Base::~Base (this=0x7fffffffdab0, __in_chrg=<optimized out>) at test.cc:13
13 std::cout << "Base d'tor" << std::endl;
$4 = (Base * const) 0x7fffffffdab0
0x7fffffffdab0: 0x0000000000400df8 0x597870ad9bc42900
0x7fffffffdac0: 0x0000000000400d10 0x00007ffff7495830
0x7fffffffdad0: 0x0000000000000000 0x00007fffffffdba8
0x7fffffffdae0: 0x00000001ffffdbb8 0x0000000000400ab6
0x7fffffffdaf0: 0x0000000000000000 0x9e98039144430dd4
0x400df8 <vtable for Base+16>: 0x0000000000400b92 0x0000000000400bde
0x400e08 <typeinfo for Derived>: 0x0000000000602200 0x0000000000400e20
0x400e18 <typeinfo for Derived+16>: 0x0000000000400e30 0x6465766972654437
0x400e28 <typeinfo name for Derived+8>: 0x0000000000000000 0x0000000000602090
0x400e38 <typeinfo for Base+8>: 0x0000000000400e40 0x0000006573614234
Base d'tor
[Inferior 1 (process 4962) exited normally]
(gdb) (gdb) quit
但是我的真实应用程序(不是上面的小演示)的堆栈跟踪命中:
__cxxabiv1::__cxa_pure_virtual ()
而我在调用堆栈上看到的最后一个 d'tor 是 派生 类。 那么这是一个指标,内存对象已经被释放并再次用于其他对象实例吗?
【问题讨论】:
您是否有一个小型的、可重现的测试用例来显示该问题?否则很难提供很多帮助。这只是一个用于捕获永远不会发生的致命错误的存根,它非常有用。也许您试图调用切片指针?检查铸造等 【参考方案1】:怎么可能?编译器这样做是为了中间工作吗?
是的。通常,构造函数首先将 vtable 指针设置为它自己的类的 vtable。然后,当派生类的构造函数运行时,它会用自己的指针覆盖 vtable 指针。
这完全实现了 C++ 标准所要求的行为,即在构造函数(和析构函数;它们反转这些赋值)执行期间调用虚函数,将对象视为具有构造函数的动态类型,而不是实际的完整对象.而在纯虚函数的情况下,行为是未定义的;编译器通常将此诊断存根插入到 vtable 中。
【讨论】:
析构函数是否相反? 不,实际上构造函数和析构函数都在开始时设置了 vtable(在典型实现中)。不同之处在于调用基本版本的顺序。构造函数先调用基构造函数再运行自己的代码,析构函数先运行自己的代码再调用基析构函数。以上是关于__cxxabiv1::__cxa_pure_virtual () 崩溃 - vtable ptr 到抽象基类?的主要内容,如果未能解决你的问题,请参考以下文章