【问题标题】:Memory corrupt in adding string to vector<string> loop将字符串添加到 vector<string> 循环时内存损坏
【发布时间】:2009-09-29 18:27:06
【问题描述】:

这是在双核 32 位 Vista 机器上的 Visual Studio 2008 上。 在调试代码中运行良好,但在发布模式下这会爆炸:

void getFromDB(vector<string>& dates) {
    ...
    sql::Resultset res = stmt->executeQuery("SELECT FROM ...");
    while (res->next()) {
       string date = res->getString("date");
       dates.push_back(date);
    }   // <<< crashing here (line 56)
    delete res;
}

MySQL C++ 连接器的 ResultSet 中有这个方法:

virtual std::string getString(const std::string& columnLabel) const = 0;

由于某种原因,在编译的版本中(针对 MySQL C++ 连接器 DLL),这会在循环结束时崩溃并导致堆损坏:

HEAP[sa-ms-release.exe]: 指定给 RtlFreeHeap(024E0000, 001C4280) 的地址无效 Windows 已在 sa-ms-release.exe 中触发断点。

    ntdll.dll!_RtlpBreakPointHeap@4()  + 0x28 bytes 
    ntdll.dll!_RtlpValidateHeapEntry@12()  + 0x713e8 bytes  
    ntdll.dll!_RtlDebugFreeHeap@12()  + 0x9a bytes  
    ntdll.dll!@RtlpFreeHeap@16()  + 0x145cf bytes   
    ntdll.dll!_RtlFreeHeap@12()  + 0xed5 bytes  
    kernel32.dll!_HeapFree@12()  + 0x14 bytes   
>   sa-ms-release.exe!free(void * pBlock=0x001c4280)  Line 110  C
    sa-ms-release.exe!std::allocator<char>::deallocate(char * _Ptr=0x001c4280, unsigned int __formal=32)  Line 140 + 0x9 bytes  C++
    sa-ms-release.exe!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Tidy(bool _Built=true, unsigned int _Newsize=0)  Line 2158 C++
    sa-ms-release.exe!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> >()  Line 907    C++
    sa-ms-release.exe!StyleData:: getFromDB( std::vector<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > > & dates)  Line 56 + 0x69 bytes    C++

我认为我可能违反了一些基本的 C++ 规则,导致在我想保留在向量中的字符串上调用析构函数。

如果我替换

string date = res->getString("date")

string date = string ("2008-11-23");

一切正常。它似乎与从 MySQL C++ 连接器 getString() 方法返回的字符串有关。我猜返回的字符串被破坏了,这会导致问题。 但更有可能的是其他事情是错误的。我正在使用发布(选择)MySQL 连接器。

【问题讨论】:

  • 您要针对哪个 STL 版本、SDK 或 VS 进行编译??
  • 在代码中添加行号可能会有所帮助(上面消息中的最后一行指定 StyleData::getFromDB 中的第 56 行)。 Disassebly 可能会有所帮助...
  • sql::Resultset::getString(...); 的签名是什么?
  • 记住,只是因为它碰巧在某处崩溃并不意味着这就是错误所在 - 损坏可能发生在完全不同的部分
  • 你确定你链接的是 VS2008 版本的 MySQL 连接器,而不是 VS2005 版本吗? (见dev.mysql.com/downloads/connector/cpp/1.0.html)?

标签: c++ memory stl vector


【解决方案1】:

恕我直言,问题可能来自 VS 运行时库。这意味着,您用于 sql 连接器方法的 DLL 不是使用“多线程 dll”代码生成选项编译的。因此,不同版本的字符串通过参数传递,它们会崩溃。我认为你应该检查这个代码生成标志。

【讨论】:

  • 是的。我也猜这将是原因。也许 /MD 或 /MDd ?如果我没记错的话。如果这些在 DEBUG 模式选项中存在,那么肯定就是这个原因
  • MySQl 连接器是用 /MD 编译的,我的代码是用 /MT 编译的。现在两者都是/MD。代码现在可以工作了!!!谢谢
【解决方案2】:

你可以看看这个thread

即使在 XP 上报告了问题,情况也是一样的。原因是 “字符串在不同的堆上被销毁,而不是在创建它的堆上。”

在您的情况下,字符串在连接器 DLL 堆中分配,该堆在应用程序堆中被释放。

我想您可以通过该主题找到一些好的建议。 (使用相同的运行时编译DLL和APP,或在应用程序和dll调用之间通过引用传递字符串)

【讨论】:

  • 原因是指定了两个冲突的运行时库。我认为这很复杂。两个 DLL 是否必须有单独的堆?这在 Unix/Linux 下是一样的吗? Java 就简单多了。
  • 我不认为这在 Linux 下是一样的......是的:).. 我也觉得 java 在这些情况下更容易,通过抽象所有较低级别的细节......但可能有具体原因他们是这样设计的!我永远无法理解这些决定背后的复杂推理逻辑! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-22
  • 2020-03-02
  • 1970-01-01
  • 1970-01-01
  • 2015-07-31
  • 2022-11-30
相关资源
最近更新 更多