【问题标题】:Why does this code leak?为什么这段代码会泄露?
【发布时间】:2012-06-06 02:30:41
【问题描述】:

好吧,又来了,这次编译器向我显示了一个内存错误(泄漏):

otest(18015,0xacae32c0) malloc: * 对象 0x194e734 错误: 已释放对象的校验和不正确 - 对象可能已被修改 被释放后。 * 在 malloc_error_break 中设置断点进行调试

我正在使用激活 ARC 和 STL 的 clang,这是一个 C++ 文件 (.cpp)。

我的发现:如果我评论“删除”行,它运行没有问题。这让我想知道是谁在释放我分配的内存 (cStr)。

顺便说一句。此代码采用查询字符串 (arg=abc&arg2=asdb) 并返回包含这些值的映射。

static map<string, string> getDecodedQueryString( string qs ) {
            map<string, string> r;

            qs = qs+"&";

            char key[100], value[100],  * cStr, *ptr;
            cStr = new char[ qs.length() ];
            memcpy( cStr, qs.c_str(), url.length()-1);
            cStr[qs.length()]=0;

            ptr =  strtok(cStr, "&");
            while ( ptr != NULL && sscanf( ptr, "%[^=]=%[^&]", &key, &value ) == 2) { 
                r[key]=value;
                ptr = strtok(NULL, "&");
            }
            delete [] cStr; //leaking?

            return r; 
        }

谢谢

【问题讨论】:

  • 什么是url.length(),它与qs.length() 有什么不同?如果urlqs 长(我怀疑可能是这样),那么您将覆盖已分配缓冲区的末尾。
  • 该错误表明它不是泄漏,而是对已释放内存的过时引用。
  • new char[ qs.length() ] 没有分配足够的内存来保存终止符。解决这个问题并开始使用 std:vector 和/或 std::array ,你就可以上路了。
  • strtok 确实修改数据。但是,因为您所做的是 UB,它也可能工作,或者看起来像它工作。在 C++11 中,您可以使用 string::data,因为它也保证是 nul 终止的。 (与此同时,您可以将 NUL 附加到字符串,因为它只是一个局部变量。)

标签: c++ ios memory memory-management memory-leaks


【解决方案1】:

下面的一些东西会做同样的事情。

std::stringstream ss(qs);
std::string temp;
std::string key;
std::string value;
while(std::getline(ss, temp, '&')) {
   std::stringstream equal(temp);
   std::getline(equal, key, '=');
   std::getline(equal, value, '=');
   r[key] = value;
}

【讨论】:

    【解决方案2】:

    问题可能出在以下几行:

        cStr = new char[ qs.length() ];
        memcpy( cStr, qs.c_str(), url.length()-1);
        cStr[qs.length()]=0;
    

    即使没有memcpy()(由于url 的长度可能有其自身的问题,正如我在上面的评论中提到的那样),cStr[qs.length()] = 0 会在缓冲区末尾写入一个字节。

    如果您的编译器有 strdup() 可用(它是非标准的,但大多数都有),您可以将其替换为:

    cStr = strdup(qs.c_str());
    // ...
    free(cStr);
    

    这使您不必费心手动分配字节、复制它们、在正确的位置终止 null 等等。

    【讨论】:

    • 由于您将 C++ 列为标签之一,您可能需要考虑研究智能指针(std::unique_ptrstd::shared_ptrstd::weak_ptr,此处为:en.cppreference.com/w/cpp/memory)。跨度>
    【解决方案3】:
    Str = new char[ qs.length() ];
    ...
    cStr[qs.length()]=0;
    

    那个写是无效的,它在cStr 的末尾之后。如果分配器在分配后立即存储了校验和,并在删除时对其进行检查,那么您只是踩到了它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-30
      • 2011-01-17
      • 2011-02-20
      • 1970-01-01
      相关资源
      最近更新 更多