C 越界写入并不总是导致错误

C 越界写入并不总是导致错误,c,memory,malloc,C,Memory,Malloc,我编写了一个函数将项目添加到日志文件中。变量loglevs[]和des加起来超过30个字符(到目前为止)。当我使用下面的函数时,一切正常 char *logitem (int loglev, const char *des) { extern const char *loglevs[]; char *lld; // loglevel & description total 28 characters (7+1+20) lld = (char *) malloc

我编写了一个函数将项目添加到日志文件中。变量
loglevs[]
des
加起来超过30个字符(到目前为止)。当我使用下面的函数时,一切正常

char *logitem (int loglev, const char *des) {

    extern const char *loglevs[];
    char *lld; // loglevel & description total 28 characters (7+1+20)

    lld = (char *) malloc((29) * sizeof(char));
    snprintf(lld, 29, "[%5s] %s", loglevs[loglev], des);

    return lld;

}
但是,当我使用
malloc(24)
而不是
malloc(29)
时,我得到以下错误:

root@vm:/home/geohei/devel#prog
***“prog”中出错:malloc():内存损坏:0x000000000085330***
中止(堆芯转储)
我希望在
malloc(28)
中已经得到错误。为什么它只显示在
malloc(24)
?实际上,在错误弹出之前,我可以进入
malloc(25)

我多次确认了测试。

确实如此。是UB的
malloc
只是一个标准的库例程(它使用类似的方法向内核请求内存,以倍数的形式)。如果“溢出”内存区域,则可能损坏了堆内存


但是考虑使用像(和-例如).< /P> < P>之类的工具,它是未定义的行为,其定义如下:

3.4.3

1未定义的行为使用不可移植或错误的 程序构造或错误数据,本国际标准 标准没有规定任何要求

2注:可能的未定义行为包括忽略情况 完全不可预测的结果,在翻译过程中的行为 或以文件化的方式执行程序 环境(无论是否发出诊断消息),以 终止翻译或执行(通过发布 诊断信息)


因此,程序可以做任何事情,甚至忽略这种情况。但它也可能会崩溃或报警:-)

如果你问为什么,有各种各样的原因说明这样做可能有效。它们取决于执行情况

您的malloc函数可以在后台以固定大小分配内存,也可以分配已经四舍五入到某个值的内存。例如,我们假设您的malloc实现总是以8字节的倍数分配

然后,您的malloc(25)-malloc(29)调用实际上可能分配了32个字节。因此,超越终点,可能不会伤害你。当您转到malloc(24)时,您可能正处于内存块的末尾

我们只能猜测这里到底发生了什么。该库可以在语言规范的范围内自由地执行它想要的操作


如前所述,这里的行为是完全未定义的,这就是为什么您不应该这样做。不同的库可能给出完全不同的结果。

未定义的行为是未定义的。因此,换句话说。。。它工作到25岁(包括在内)纯属巧合吗。。。这通常被认为是缺乏运气:)如果每次都有错误的代码失败,那就太方便了。幸运的是,包含UB的程序在第一次运行时就失败了。运气不好的时候,第一次失败的时候是你展示项目的时候。我去看看。谢谢在不太可能的情况下,它会报警,你认为它会告诉他们什么@机器_1:关于侵入行为可能:-)