这种内存损坏是如何在c++中发生的

How did this memory corruption occur in c++?

本文关键字:c++ 内存 损坏      更新时间:2023-10-16

我不确定我理解下面的bug是什么

const char* packs[] = {"zero","one","two","three","four",..."twelve"} //abbreviated for post
struct packinfo {
    char* data;
    int   len;
};
std::vector<packinfo> k;
k.reserve(10000);
for (int i = 0; i < 10; ++i) {
    const char* data = packs[i];
    packinfo tobuf;
    tobuf.data = new char[strlen(data)];
    tobuf.len = strlen(data);
    memcpy(tobuf.data, data, strlen(data));
    k.push_back(tobuf);
}
for (int i = 0; i < k.size(); ++i)
    std::cout << "k[" << i << "]: " << k[i].data << ", ";
std::cout << std::endl;
for (int i = 0; i < k.size(); ++i) {
    packinfo& pack = k[i];
    bool foo = (i < 5);
    if (foo) std::cout << "inspecting k[" << i << "]: " << k[i].data << std::endl;
    delete pack.data;
    if (!foo) {
        k.erase(k.begin(), k.begin() + i);
        packinfo tobuf;
        const char* data = packs[10];
        tobuf.data = new char[strlen(data)];
        tobuf.len = strlen(data);
        memcpy(tobuf.data, data, strlen(data));
        break; //intentionally forgot to push_back
    }
}
for (int i = 0; i < k.size(); ++i)
    std::cout << "k[" << i << "]: " << k[i].data << ", ";
std::cout << std::endl

;

运行以上命令的输出如下:

k[0]: zero, k[1]: one, ... , k[9]: nine, //all as expected
inspecting k[0]: zero
inspecting k[1]: one
...
inspecting k[4]: four
k[0]: ten^], k[1]: six, k[2] seven, k[3]: eight, k[4]L nine, //gargabe crept in

垃圾是如何爬到vector的开头的?

strlen给出以空结尾的字符串中的字符长度,不包括以空结尾的字符。因此,动态分配的数据缓冲区太短,无法容纳目标字符串:

tobuf.data = new char[strlen(data)]; // too short by 1

当您使用memcpy填充它时,没有空间用于字符串的null终止,并且即使有也不会复制它,因为数组太短了:

memcpy(tobuf.data, data, strlen(data)); // tobuf.data is not nul-terminated

当你试图把它当作一个null结束的字符串来读时,你就越界了。

立即的解决办法是使用strlen(data) +1,但是你真正应该做的是用std::string代替packinfo来避免整个问题。

std::vector<std::string> k;
k.reserve(10000);

问题出在这几行:

tobuf.data = new char[strlen(data)];
tobuf.len = strlen(data);
memcpy(tobuf.data, data, strlen(data));

在哪里为字符串结束符添加空格?

c++有std::string类,你应该使用它,因为它会帮助你解决这类问题。