本系列文章是读《coredump问题原理探究》的读书笔记。
Map
1
2
3
4
5
6
7
8
9
10
11
#include <map>
int main() {
std::map<int,int> m;
m[5] = 6;
m[8] = 20;
m[2] = 80;
return 0;
}
参考 stl 的源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// stl_map.h
template <typename _Key, typename _Tp, typename _Compare = std::less<_Key>,
typename _Alloc = std::allocator<std::pair<const _Key, _Tp> > >
class map {
public:
typedef _Compare key_compare;
public:
map() : _M_t() { }
private:
typedef _Rb_tree<key_type, value_type, _Select1st<value_type>,
key_compare, _Pair_alloc_type> _Rep_type;
/// The actual tree structure.
_Rep_type _M_t;
};
// stl_tree.h
struct _Rb_tree_node_base
{
typedef _Rb_tree_node_base* _Base_ptr;
_Rb_tree_color _M_color;
_Base_ptr _M_parent;
_Base_ptr _M_left;
_Base_ptr _M_right;
};
template<typename _Key, typename _Val, typename _KeyOfValue,
typename _Compare, typename _Alloc = allocator<_Val> >
class _Rb_tree {
public:
_Rb_tree() { }
protected:
template<typename _Key_compare,
bool _Is_pod_comparator = __is_pod(_Key_compare)>
struct _Rb_tree_impl : public _Node_allocator {
_Key_compare _M_key_compare;
_Rb_tree_node_base _M_header;
size_type _M_node_count; // Keeps track of size of tree.
_Rb_tree_impl()
: _Node_allocator(), _M_key_compare(), _M_header(),
_M_node_count(0)
{ _M_initialize(); }
private:
void _M_initialize() {
this->_M_header._M_color = _S_red;
this->_M_header._M_parent = 0;
this->_M_header._M_left = &this->_M_header;
this->_M_header._M_right = &this->_M_header;
}
};
_Rb_tree_impl<_Compare> _M_impl;
};
template<typename _Val>
struct _Rb_tree_node : public _Rb_tree_node_base {
typedef _Rb_tree_node<_Val>* _Link_type;
_Val _M_value_field;
};
可以看出 map 的成员变量为:_M_key_compare、_M_header._M_color、_M_header._M_parent、_M_header._M_left、_M_header._M_right、_M_node_count。 对照构造函数的汇编:
1
2
3
4
5
6
7
8
9
10
(gdb) set print asm-demangle
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000000400920 <+0>: push %rbp
0x0000000000400921 <+1>: mov %rsp,%rbp
0x0000000000400924 <+4>: push %rbx
0x0000000000400925 <+5>: sub $0x48,%rsp
0x0000000000400929 <+9>: lea -0x50(%rbp),%rax
0x000000000040092d <+13>: mov %rax,%rdi
0x0000000000400930 <+16>: callq 0x4009f8 <std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int> > >::map()>
1
2
3
4
5
6
7
8
9
(gdb) disassemble 0x4009f8
Dump of assembler code for function _ZNSt3mapIiiSt4lessIiESaISt4pairIKiiEEEC2Ev:
0x00000000004009f8 <+0>: push %rbp
0x00000000004009f9 <+1>: mov %rsp,%rbp
0x00000000004009fc <+4>: sub $0x10,%rsp
0x0000000000400a00 <+8>: mov %rdi,-0x8(%rbp)
0x0000000000400a04 <+12>: mov -0x8(%rbp),%rax
0x0000000000400a08 <+16>: mov %rax,%rdi
0x0000000000400a0b <+19>: callq 0x400b9e <std::_Rb_tree<int, std::pair<int const, int>, std::_Select1st<std::pair<int const, int> >, std::less<int>, std::allocator<std::pair<int const, int> > >::_Rb_tree()>
1
2
3
4
5
6
7
8
9
(gdb) disassemble 0x400b9e
Dump of assembler code for function _ZNSt8_Rb_treeIiSt4pairIKiiESt10_Select1stIS2_ESt4lessIiESaIS2_EEC2Ev:
0x0000000000400b9e <+0>: push %rbp
0x0000000000400b9f <+1>: mov %rsp,%rbp
0x0000000000400ba2 <+4>: sub $0x10,%rsp
0x0000000000400ba6 <+8>: mov %rdi,-0x8(%rbp)
0x0000000000400baa <+12>: mov -0x8(%rbp),%rax
0x0000000000400bae <+16>: mov %rax,%rdi
0x0000000000400bb1 <+19>: callq 0x400d72 <std::_Rb_tree<int, std::pair<int const, int>, std::_Select1st<std::pair<int const, int> >, std::less<int>, std::allocator<std::pair<int const, int> > >::_Rb_tree_impl<std::less<int>, false>::_Rb_tree_impl()>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
(gdb) disassemble 0x400d72
Dump of assembler code for function _ZNSt8_Rb_treeIiSt4pairIKiiESt10_Select1stIS2_ESt4lessIiESaIS2_EE13_Rb_tree_implIS6_Lb0EEC2Ev:
0x0000000000400d72 <+0>: push %rbp
0x0000000000400d73 <+1>: mov %rsp,%rbp
0x0000000000400d76 <+4>: sub $0x10,%rsp
0x0000000000400d7a <+8>: mov %rdi,-0x8(%rbp)
0x0000000000400d7e <+12>: mov -0x8(%rbp),%rax
0x0000000000400d82 <+16>: mov %rax,%rdi
0x0000000000400d85 <+19>: callq 0x400f8c <std::allocator<std::_Rb_tree_node<std::pair<int const, int> > >::allocator()>
0x0000000000400d8a <+24>: mov -0x8(%rbp),%rax
0x0000000000400d8e <+28>: movl $0x0,0x8(%rax) // _M_header._M_color
0x0000000000400d95 <+35>: mov -0x8(%rbp),%rax
0x0000000000400d99 <+39>: movq $0x0,0x10(%rax) // _M_header._M_parent
0x0000000000400da1 <+47>: mov -0x8(%rbp),%rax
0x0000000000400da5 <+51>: movq $0x0,0x18(%rax) // _M_header._M_left
0x0000000000400dad <+59>: mov -0x8(%rbp),%rax
0x0000000000400db1 <+63>: movq $0x0,0x20(%rax) // _M_header._M_right
0x0000000000400db9 <+71>: mov -0x8(%rbp),%rax
0x0000000000400dbd <+75>: movq $0x0,0x28(%rax) // _M_node_count(0)
0x0000000000400dc5 <+83>: mov -0x8(%rbp),%rax
0x0000000000400dc9 <+87>: mov %rax,%rdi
0x0000000000400dcc <+90>: callq 0x400fa6 <std::_Rb_tree<int, std::pair<int const, int>, std::_Select1st<std::pair<int const, int> >, std::less<int>, std::allocator<std::pair<int const, int> > >::_Rb_tree_impl<std::less<int>, false>::_M_initialize()>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(gdb) disassemble 0x400fa6
Dump of assembler code for function _ZNSt8_Rb_treeIiSt4pairIKiiESt10_Select1stIS2_ESt4lessIiESaIS2_EE13_Rb_tree_implIS6_Lb0EE13_M_initializeEv:
0x0000000000400fa6 <+0>: push %rbp
0x0000000000400fa7 <+1>: mov %rsp,%rbp
0x0000000000400faa <+4>: mov %rdi,-0x8(%rbp)
0x0000000000400fae <+8>: mov -0x8(%rbp),%rax
0x0000000000400fb2 <+12>: movl $0x0,0x8(%rax) // this->_M_header._M_color = _S_red;
0x0000000000400fb9 <+19>: mov -0x8(%rbp),%rax
0x0000000000400fbd <+23>: movq $0x0,0x10(%rax) // this->_M_header._M_parent = 0;
0x0000000000400fc5 <+31>: mov -0x8(%rbp),%rax
0x0000000000400fc9 <+35>: lea 0x8(%rax),%rdx
0x0000000000400fcd <+39>: mov -0x8(%rbp),%rax
0x0000000000400fd1 <+43>: mov %rdx,0x18(%rax) // this->_M_header._M_left = &this->_M_header;
0x0000000000400fd5 <+47>: mov -0x8(%rbp),%rax
0x0000000000400fd9 <+51>: lea 0x8(%rax),%rdx
0x0000000000400fdd <+55>: mov -0x8(%rbp),%rax
0x0000000000400fe1 <+59>: mov %rdx,0x20(%rax) // this->_M_header._M_right = &this->_M_header;
0x0000000000400fe5 <+63>: pop %rbp
0x0000000000400fe6 <+64>: retq
End of assembler dump.
在构造函数调用处打断点:
1
2
3
4
5
6
7
8
9
10
11
12
13
(gdb) tbreak *0x0000000000400930
Temporary breakpoint 1 at 0x400930
(gdb) r
(gdb) x /12wx 0x7fffffffe420
0x7fffffffe420: 0x00000001 0x00007fff 0xf7203890 0x00007fff
0x7fffffffe430: 0x00000001 0x00000000 0x00401bbd 0x00000000
0x7fffffffe440: 0x00000000 0x00000000 0x00000000 0x00000000
(gdb) ni
0x0000000000400935 in main ()
(gdb) x /12wx $rbp-0x50
0x7fffffffe420: 0x00000001 0x00007fff 0x00000000 0x00007fff
0x7fffffffe430: 0x00000000 0x00000000 0xffffe428 0x00007fff
0x7fffffffe440: 0xffffe428 0x00007fff 0x00000000 0x00000000
可见初始化后成员变量的值为:
_M_key_compare | 0x00007fff00000001 |
_M_header._M_color | 0x00007fff00000000 |
_M_header._M_parent | 0x0000000000000000 |
_M_header._M_left | 0x00007fffffffe428 |
_M_header._M_right | 0x00007fffffffe428 |
_M_node_count | 0x0000000000000000 |
其中 _M_left 和 _M_right 都指向 &_M_header。
看看插入第一个数据的汇编代码:
1
2
3
4
5
6
7
0x0000000000400935 <+21>: movl $0x5,-0x1c(%rbp)
0x000000000040093c <+28>: lea -0x1c(%rbp),%rdx
0x0000000000400940 <+32>: lea -0x50(%rbp),%rax
0x0000000000400944 <+36>: mov %rdx,%rsi
0x0000000000400947 <+39>: mov %rax,%rdi
0x000000000040094a <+42>: callq 0x400a86 <std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int> > >::operator[](int const&)>
0x000000000040094f <+47>: movl $0x6,(%rax)
调用处打断点:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
(gdb) tbreak *0x0000000000400955
Temporary breakpoint 3 at 0x400955
(gdb) c
Continuing.
Temporary breakpoint 3, 0x0000000000400955 in main ()
(gdb) x /12wx $rbp-0x50
0x7fffffffe420: 0x00000001 0x00007fff 0x00000000 0x00007fff
0x7fffffffe430: 0x00604010 0x00000000 0x00604010 0x00000000
0x7fffffffe440: 0x00604010 0x00000000 0x00000001 0x00000000
(gdb) x /10wx 0x00604010
0x604010: 0x00000001 0x00000000 0xffffe428 0x00007fff
0x604020: 0x00000000 0x00000000 0x00000000 0x00000000
0x604030: 0x00000005 0x00000006
head节点:
_M_key_compare | 0x00007fff00000001 |
_M_header._M_color | 0x00007fff00000000 |
_M_header._M_parent | 0x0000000000604010 |
_M_header._M_left | 0x0000000000604010 |
_M_header._M_right | 0x0000000000604010 |
_M_node_count | 0x0000000x00000001 |
第一个节点(0x00604010):
_M_color | 0x00000x0000000001 |
_M_parent | 0x00007fffffffe428 |
_M_left | 0x0000000000000000 |
_M_right | 0x0000000000000000 |
_M_value_field.first | 0x00000005 |
_M_value_field.second | 0x00000006 |
接着看看插入第二个元素之后:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(gdb) tbreak *0x0000000000400975
Temporary breakpoint 4 at 0x400975
(gdb) c
Continuing.
Temporary breakpoint 4, 0x0000000000400975 in main ()
(gdb) x /12wx $rbp-0x50
0x7fffffffe420: 0x00000001 0x00007fff 0x00000000 0x00007fff
0x7fffffffe430: 0x00604010 0x00000000 0x00604010 0x00000000
0x7fffffffe440: 0x00604040 0x00000000 0x00000002 0x00000000
(gdb) x /10wx 0x00604010
0x604010: 0x00000001 0x00000000 0xffffe428 0x00007fff
0x604020: 0x00000000 0x00000000 0x00604040 0x00000000
0x604030: 0x00000005 0x00000006
(gdb) x /10wx 0x00604040
0x604040: 0x00000000 0x00000000 0x00604010 0x00000000
0x604050: 0x00000000 0x00000000 0x00000000 0x00000000
0x604060: 0x00000008 0x00000014
head节点:
_M_key_compare | 0x00007fff00000001 |
_M_header._M_color | 0x00007fff00000000 |
_M_header._M_parent | 0x0000000000604010 |
_M_header._M_left | 0x0000000000604010 |
_M_header._M_right | 0x0000000000604040 // 变成 0x0000000000604040 |
_M_node_count | 0x0000000x00000001 |
第一个节点(0x00604010):
_M_color | 0x00000x0000000001 |
_M_parent | 0x00007fffffffe428 |
_M_left | 0x0000000000000000 |
_M_right | 0x0000000000604040 // 变成 0x0000000000604040 |
_M_value_field.first | 0x00000005 |
_M_value_field.second | 0x00000006 |
第二个节点(0x00604040):
_M_color | 0x00000x0000000001 |
_M_parent | 0x0000000000604010 |
_M_left | 0x0000000000000000 |
_M_right | 0x0000000000000000 |
_M_value_field.first | 0x00000008 |
_M_value_field.second | 0x00000014 |
最后看看插入第三个元素之后:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(gdb) tbreak *0x0000000000400995
Temporary breakpoint 5 at 0x400995
(gdb) c
Continuing.
Temporary breakpoint 5, 0x0000000000400995 in main ()
(gdb) x /12wx $rbp-0x50
0x7fffffffe420: 0x00000001 0x00007fff 0x00000000 0x00007fff
0x7fffffffe430: 0x00604010 0x00000000 0x00604070 0x00000000
0x7fffffffe440: 0x00604040 0x00000000 0x00000003 0x00000000
(gdb) x /10wx 0x00604010
0x604010: 0x00000001 0x00000000 0xffffe428 0x00007fff
0x604020: 0x00604070 0x00000000 0x00604040 0x00000000
0x604030: 0x00000005 0x00000006
(gdb) x /10wx 0x00604040
0x604040: 0x00000000 0x00000000 0x00604010 0x00000000
0x604050: 0x00000000 0x00000000 0x00000000 0x00000000
0x604060: 0x00000008 0x00000014
(gdb) x /10wx 0x00604070
0x604070: 0x00000000 0x00000000 0x00604010 0x00000000
0x604080: 0x00000000 0x00000000 0x00000000 0x00000000
0x604090: 0x00000002 0x00000050
关系图如下:
coredump 分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
(gdb) set print asm-demangle
(gdb) bt
#0 0x0000000000000000 in ?? ()
#1 0x0000000000400ea0 in main ()
(gdb) i r
rax 0x0 0
rbx 0x0 0
rcx 0x7fff070007b1 140733310830513
rdx 0xa 10
rsi 0x0 0
rdi 0x0 0
rbp 0x7fff06ffe820 0x7fff06ffe820
rsp 0x7fff06ffe788 0x7fff06ffe788
r8 0x7f1790ee2060 139739192500320
r9 0xa 10
r10 0x0 0
r11 0x0 0
r12 0x0 0
r13 0x7fff06ffe900 140733310822656
r14 0x0 0
r15 0x0 0
rip 0x0 0x0
eflags 0x10206 [ PF IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
rip 为 0,根据之前的经验,是调用了空的函数指针。查看 core 附近的汇编:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
Dump of assembler code for function main:
0x0000000000400ced <+0>: push %rbp
0x0000000000400cee <+1>: mov %rsp,%rbp
0x0000000000400cf1 <+4>: push %r12
0x0000000000400cf3 <+6>: push %rbx
0x0000000000400cf4 <+7>: add $0xffffffffffffff80,%rsp
0x0000000000400cf8 <+11>: mov %edi,-0x84(%rbp)
0x0000000000400cfe <+17>: mov %rsi,-0x90(%rbp)
0x0000000000400d05 <+24>: cmpl $0x3,-0x84(%rbp)
0x0000000000400d0c <+31>: jg 0x400d22 <main+53>
0x0000000000400d0e <+33>: mov $0x402310,%edi
0x0000000000400d13 <+38>: callq 0x400a80 <puts@plt>
0x0000000000400d18 <+43>: mov $0xffffffff,%ebx
0x0000000000400d1d <+48>: jmpq 0x400ec6 <main+473>
0x0000000000400d22 <+53>: lea -0x80(%rbp),%rax
0x0000000000400d26 <+57>: mov %rax,%rdi
0x0000000000400d29 <+60>: callq 0x400fae <std::map<std::string, int (*)(int, int), std::less<std::string>, std::allocator<std::pair<std::string const, int (*)(int, int)> > >::map()>
0x0000000000400d2e <+65>: lea -0x41(%rbp),%rax
0x0000000000400d32 <+69>: mov %rax,%rdi
0x0000000000400d35 <+72>: callq 0x400b80 <_ZNSaIcEC1Ev@plt>
0x0000000000400d3a <+77>: lea -0x41(%rbp),%rdx
0x0000000000400d3e <+81>: lea -0x50(%rbp),%rax
0x0000000000400d42 <+85>: mov $0x402326,%esi
0x0000000000400d47 <+90>: mov %rax,%rdi
0x0000000000400d4a <+93>: callq 0x400b00 <_ZNSsC1EPKcRKSaIcE@plt>
0x0000000000400d4f <+98>: lea -0x50(%rbp),%rdx
0x0000000000400d53 <+102>: lea -0x80(%rbp),%rax
0x0000000000400d57 <+106>: mov %rdx,%rsi
0x0000000000400d5a <+109>: mov %rax,%rdi
0x0000000000400d5d <+112>: callq 0x401056 <std::map<std::string, int (*)(int, int), std::less<std::string>, std::allocator<std::pair<std::string const, int (*)(int, int)> > >::operator[](std::string const&)>
0x0000000000400d62 <+117>: movq $0x400cb0,(%rax)
0x0000000000400d69 <+124>: lea -0x50(%rbp),%rax
0x0000000000400d6d <+128>: mov %rax,%rdi
0x0000000000400d70 <+131>: callq 0x400af0 <_ZNSsD1Ev@plt>
0x0000000000400d75 <+136>: lea -0x41(%rbp),%rax
0x0000000000400d79 <+140>: mov %rax,%rdi
0x0000000000400d7c <+143>: callq 0x400b30 <_ZNSaIcED1Ev@plt>
0x0000000000400d81 <+148>: lea -0x31(%rbp),%rax
0x0000000000400d85 <+152>: mov %rax,%rdi
0x0000000000400d88 <+155>: callq 0x400b80 <_ZNSaIcEC1Ev@plt>
0x0000000000400d8d <+160>: lea -0x31(%rbp),%rdx
0x0000000000400d91 <+164>: lea -0x40(%rbp),%rax
0x0000000000400d95 <+168>: mov $0x402328,%esi
0x0000000000400d9a <+173>: mov %rax,%rdi
0x0000000000400d9d <+176>: callq 0x400b00 <_ZNSsC1EPKcRKSaIcE@plt>
0x0000000000400da2 <+181>: lea -0x40(%rbp),%rdx
0x0000000000400da6 <+185>: lea -0x80(%rbp),%rax
0x0000000000400daa <+189>: mov %rdx,%rsi
0x0000000000400dad <+192>: mov %rax,%rdi
0x0000000000400db0 <+195>: callq 0x401056 <std::map<std::string, int (*)(int, int), std::less<std::string>, std::allocator<std::pair<std::string const, int (*)(int, int)> > >::operator[](std::string const&)>
0x0000000000400db5 <+200>: movq $0x400cc4,(%rax)
0x0000000000400dbc <+207>: lea -0x40(%rbp),%rax
0x0000000000400dc0 <+211>: mov %rax,%rdi
0x0000000000400dc3 <+214>: callq 0x400af0 <_ZNSsD1Ev@plt>
0x0000000000400dc8 <+219>: lea -0x31(%rbp),%rax
0x0000000000400dcc <+223>: mov %rax,%rdi
0x0000000000400dcf <+226>: callq 0x400b30 <_ZNSaIcED1Ev@plt>
0x0000000000400dd4 <+231>: lea -0x21(%rbp),%rax
0x0000000000400dd8 <+235>: mov %rax,%rdi
0x0000000000400ddb <+238>: callq 0x400b80 <_ZNSaIcEC1Ev@plt>
0x0000000000400de0 <+243>: lea -0x21(%rbp),%rdx
0x0000000000400de4 <+247>: lea -0x30(%rbp),%rax
0x0000000000400de8 <+251>: mov $0x40232a,%esi
0x0000000000400ded <+256>: mov %rax,%rdi
0x0000000000400df0 <+259>: callq 0x400b00 <_ZNSsC1EPKcRKSaIcE@plt>
0x0000000000400df5 <+264>: lea -0x30(%rbp),%rdx
0x0000000000400df9 <+268>: lea -0x80(%rbp),%rax
0x0000000000400dfd <+272>: mov %rdx,%rsi
0x0000000000400e00 <+275>: mov %rax,%rdi
0x0000000000400e03 <+278>: callq 0x401056 <std::map<std::string, int (*)(int, int), std::less<std::string>, std::allocator<std::pair<std::string const, int (*)(int, int)> > >::operator[](std::string const&)>
0x0000000000400e08 <+283>: movq $0x400cda,(%rax)
0x0000000000400e0f <+290>: lea -0x30(%rbp),%rax
0x0000000000400e13 <+294>: mov %rax,%rdi
0x0000000000400e16 <+297>: callq 0x400af0 <_ZNSsD1Ev@plt>
0x0000000000400e1b <+302>: lea -0x21(%rbp),%rax
0x0000000000400e1f <+306>: mov %rax,%rdi
0x0000000000400e22 <+309>: callq 0x400b30 <_ZNSaIcED1Ev@plt>
0x0000000000400e27 <+314>: lea -0x11(%rbp),%rax
0x0000000000400e2b <+318>: mov %rax,%rdi
0x0000000000400e2e <+321>: callq 0x400b80 <_ZNSaIcEC1Ev@plt>
0x0000000000400e33 <+326>: mov -0x90(%rbp),%rax
0x0000000000400e3a <+333>: add $0x10,%rax
0x0000000000400e3e <+337>: mov (%rax),%rcx
0x0000000000400e41 <+340>: lea -0x11(%rbp),%rdx
0x0000000000400e45 <+344>: lea -0x20(%rbp),%rax
0x0000000000400e49 <+348>: mov %rcx,%rsi
0x0000000000400e4c <+351>: mov %rax,%rdi
0x0000000000400e4f <+354>: callq 0x400b00 <_ZNSsC1EPKcRKSaIcE@plt>
0x0000000000400e54 <+359>: lea -0x20(%rbp),%rdx
0x0000000000400e58 <+363>: lea -0x80(%rbp),%rax
0x0000000000400e5c <+367>: mov %rdx,%rsi
0x0000000000400e5f <+370>: mov %rax,%rdi
0x0000000000400e62 <+373>: callq 0x401056 <std::map<std::string, int (*)(int, int), std::less<std::string>, std::allocator<std::pair<std::string const, int (*)(int, int)> > >::operator[](std::string const&)>
0x0000000000400e67 <+378>: mov (%rax),%rbx
0x0000000000400e6a <+381>: mov -0x90(%rbp),%rax
0x0000000000400e71 <+388>: add $0x18,%rax
0x0000000000400e75 <+392>: mov (%rax),%rax
0x0000000000400e78 <+395>: mov %rax,%rdi
0x0000000000400e7b <+398>: callq 0x400b10 <atoi@plt>
0x0000000000400e80 <+403>: mov %eax,%r12d
0x0000000000400e83 <+406>: mov -0x90(%rbp),%rax
0x0000000000400e8a <+413>: add $0x8,%rax
0x0000000000400e8e <+417>: mov (%rax),%rax
0x0000000000400e91 <+420>: mov %rax,%rdi
0x0000000000400e94 <+423>: callq 0x400b10 <atoi@plt>
0x0000000000400e99 <+428>: mov %r12d,%esi
0x0000000000400e9c <+431>: mov %eax,%edi
0x0000000000400e9e <+433>: callq *%rbx
=> 0x0000000000400ea0 <+435>: mov %eax,%ebx
...
(gdb) i r rbx
rbx 0x0 0
(gdb)
确定是 rbx 寄存器为空地址引起的,rbx 存的是 <+373> 调用 operator[] 的返回值。分析下 operator[] 传的是哪个 key 值:
1
2
3
4
(gdb) x /2wx $rbp-0x20
0x7ffdcb892580: 0x01fce178 0x00000000
(gdb) x /s 0x01fce178
0x1fce178: "b"
再根据 <+112> <+195> <+278> 可以看出 map 中不存在 key 为 “b” 的元素(分别插入了 “+”,”-“,”*“):
1
2
3
4
5
6
7
8
9
10
11
12
(gdb) x /2wx $rbp-0x50
0x7ffdcb892550: 0x01fce028 0x00000000
(gdb) x /s 0x01fce028
0x1fce028: "+"
(gdb) x /2wx $rbp-0x40
0x7ffdcb892560: 0x01fce098 0x00000000
(gdb) x /s 0x01fce098
0x1fce098: "-"
(gdb) x /2wx $rbp-0x30
0x7ffdcb892570: 0x01fce108 0x00000000
(gdb) x /s 0x01fce108
0x1fce108: "*"
对比源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <map>
#include <string>
#include <stdio.h>
#include <stdlib.h>
typedef int (*oper)(int a, int b );
int add(int a, int b) {
return a + b;
}
int sub(int a, int b) {
return a - b;
}
int mul(int a, int b) {
return a * b;
}
int main(int argc, char* argv[]) {
if (argc < 4) {
printf( "parameter less than 4\n" );
return -1;
}
std::map< std::string, oper> operMap;
operMap["+"] = &add;
operMap["-"] = ⊂
operMap["*"] = &mul;
return operMap[argv[2]](atoi(argv[1]), atoi(argv[3]));
}
执行 ./test a b c
导致 core。