【问题标题】:Pointer corrupted while returning from a function从函数返回时指针损坏
【发布时间】:2015-03-24 15:15:48
【问题描述】:

TL;DR:当我在 OS X Yosemite 下的 Mac 上运行 C++ 程序时,当函数返回时指针会损坏。我该如何阻止它发生? (为什么?)


this sample program 中,我有一个category_map<T> 类型的数据结构,它实际上只是一个

map<string, list<pair<string, T> > >

category_map 类有几个方法,包括get(string&amp; name),它提取存储在给定name 下的list,并从该列表的第一个元素返回T。在我的例子中,T 是一个指针类型。代码从list 中的第一个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 中 - 已损坏。例如,它可能变为0x3000100809c000x5000100809c00。损坏的指针始终是在 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&lt;T&gt;,我可以get 的返回类型更改为T(而不是T&amp;),这似乎可以解决(或至少解决)问题。但是,如果它可以容纳大对象并通过引用返回它们,它会使数据结构更普遍有用,我认为这应该是可能的。另外,无论我在编码时犯了什么错误,我都想理解,所以我不会再犯了。谁能指出我做错了什么,以及在不更改 API 的情况下修复它的正确方法吗?

【问题讨论】:

    标签: c++ macos pointers memory c++98


    【解决方案1】:

    list_type the_list = map_iterator->second;
    

    您复制了map_iterator-&gt;secondthe_list 是一个函数局部对象。那么

    T& p = the_list.front().second;
    return p;
    

    返回对与此函数本地对象一样长的对象的引用,并在函数离开时被销毁。参考悬垂。

    在我看来,您似乎并不打算复制该列表,所以

    //          +------ const because get() is const-qualified
    //          v   v-- reference
    list_type const &the_list = map_iterator->second;
    
    //  v-- const because the_list is const
    T const& p = the_list.front().second;
    

    应该修复它,如果你可以让get() const 返回一个T const &amp;1。否则,您会遇到尝试从const 成员函数返回对非常量成员的引用的问题;这会破坏 const 正确性,因此被禁止(如果允许,您将能够通过该引用更改常量对象)。

    1你也可以让get const()返回一个值而不是一个引用,但似乎没有理由强制复制。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-20
      • 2011-12-06
      • 2010-12-25
      • 2011-07-19
      • 1970-01-01
      • 2019-08-22
      • 2015-07-18
      相关资源
      最近更新 更多