TL;博士
:当我在Mac OS X Yosemite下运行C++程序时,当函数返回时,指针损坏。我如何阻止它发生?(为什么?)
在里面
this sample program
,我的数据结构类型为
category_map<T>
这实际上只是一个
map<string, list<pair<string, T> > >
这个
category_map
类有几个方法,包括
get(string& name)
它拉动
list
存储在给定的
name
并返回
T
从该列表的第一个元素开始。在我的情况下,
T
是指针类型。代码从第一个
pair
在
列表
-那会是
p
在下面的代码列表中-是有效的。调试器会话显示
p
在函数的最后一行-在析构函数运行之前的右括号-是一个有效的内存位置,例如,
0x100809c00
.
T& get(const string& name) const {
cerr << "searching for " << name << endl;
typename super::const_iterator map_iterator = super::find(name);
// the real code doesn't assume it will be found
list_type the_list = map_iterator->second;
T& p = the_list.front().second;
cerr << "found " << val_loc_string<T>(p) << endl;
return p;
}
然而,当我在Mac(OS X Yosemite)上编译并运行代码时,而不是在Linux上,在清理此函数的过程中,有一些东西会写入内存中的相同位置,因此返回的指针-存储在变量中
ip
在下面的下一个代码列表中-已损坏。例如,它可能变成
0x3000100809c00
或
0x5000100809c00
损坏的指针始终是原始指针,在8字节地址的第二个最高有效字节中设置了一个或几个额外的位。
int main(const int argc, const char** argv) {
category_map<int*> imap;
int a;
imap.add("Q1", "m", &a);
imap.add("Q1", "r", &a);
imap.add("Q2", "m", &a);
int* ip = imap.get("Q1");
cerr << "return value: " << val_loc_string<int*>(ip) << endl;
cout << *ip << endl;
}
使用GDB(通过MacPorts安装),我确定了将额外位写入内存位置的特定指令。
0x00007fff93188279: cmp $0x2,%eax
0x00007fff9318827c: jb 0x7fff9318828d
0x00007fff9318827e: shl $0x4,%rax
=> 0x00007fff93188282: mov %r10w,-0x2(%rax,%rdx,1)
0x00007fff93188288: mov %r10w,0x10(%rdx)
0x00007fff9318828d: test %r10w,%r10w
0x00007fff93188291: jne 0x7fff93188299
(
more context
)但这并没有多大帮助,因为它不是C/C++函数的一部分,我在汇编方面不够流利,无法理解它在大规模地做什么
backtrace
是垃圾,所以我不能将代码放到上下文中。(我还拍摄了
values of the registers
正好在损坏指针的指令之前,以防由于某种原因而有所帮助。)
因为我实例化了
category_map<T>
仅使用指针类型,I
能够
更改的返回类型
get
到
T
(而不是
T&
)这似乎确实解决了(或至少解决了)问题。但是,如果数据结构可以保存大型对象并通过引用返回它们,那么它会使数据结构更为有用,我认为这是可能的。另外,无论我在编码时犯了什么错误,我都想理解,这样我就不会再犯了。有人能指出我做错了什么,以及在不更改API的情况下修复它的正确方法吗?