C++取消引用未分配的内存,但没有分段错误

C++ Dereference the Non-allocated Memory but Without Segmentation Fault

本文关键字:分段 错误 内存 引用 取消 分配 C++      更新时间:2023-10-16

我遇到了一个我不理解的问题,下面是我的代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <cstdlib>
using namespace std;
int main(int argc, char **argv)
{
    char *format = "The sum of the two numbers is: %d";
    char *presult;
    int sum = 10;
    presult = (char *)calloc(sizeof(format) + 20, 1);   //allocate 24 bytes
    sprintf(presult, format, sum);  // after this operation, 
                                    // the length of presult is 33
    cout << presult << endl;
    presult[40] = 'g';   //still no segfault here...
    delete(presult);
}

我在不同的机器上编译了这些代码。在一台机器上,sizeof(format)为4字节,在另一台机器中,sizeof(format)为8字节;(在两台机器上,字符只占用一个字节,这意味着sizeof(*format)等于1)

然而,无论在哪台机器上,结果仍然让我感到困惑。因为即使是第二台机器,分配的内存也只有20+8,即28个字节,显然字符串的长度为33,这意味着至少需要33个字节。但在我运行此程序后,出现了NO分段故障。正如你所看到的,即使我试图取消引用位置40处的预设,程序也不会崩溃并显示任何segfault信息。

有人能帮忙解释一下原因吗?非常感谢。

访问未分配的内存是未定义的行为,这意味着你可能会遇到segfault(如果幸运的话),也可能不会。

或者你的程序可以在屏幕上免费显示小猫。

推测为什么某些事情会在未定义的行为领域发生或没有发生通常会适得其反,但我可以想象,发生在你身上的是,操作系统实际上为你的应用程序分配了比它要求的更大的内存块。由于您的应用程序没有试图取消引用较大块之外的任何内容,因此操作系统不会检测到问题,因此不会因分段错误而终止程序。

因为未定义的行为是未定义的。它并没有"定义为崩溃"。

没有seg错误,因为没有理由存在。由于您从堆中获得内存,因此很可能仍在向堆中写入,因此内存不是只读的。此外,那里的内存很可能存在,并且是为您(或者至少是程序)分配的,所以这不是访问冲突。通常情况下,您会遇到seg错误,因为您可能试图访问未提供给您的内存,或者您可能试图写入只读内存。这两种情况似乎都不是,所以没有什么问题。

事实上,写过缓冲区的末尾是一个常见的安全问题,称为缓冲区溢出。这是一段时间以来最常见的安全漏洞。如今,人们使用更高级别的语言来检查超出索引范围的情况,所以这不再是一个大问题。

对此做出回应:"结果仍然让我感到困惑。因为即使是第二台机器,分配的内存也只有20+8,即28字节,显然字符串的长度为33,这意味着至少需要33字节。"

sizeof(some_pointer)==任何基础设施上的sizeof(size_t)。您在32位机器(4B)和64位机器(8B)上进行测试。

您必须给malloc分配的字节数;sizeof(ptr_to_char)不会给出字符串的长度(直到"\0"为止的字符数)。

顺便说一句,斯特伦做你想做的事:http://www.cplusplus.com/reference/cstring/strlen/