Linux malloc分段错误丢失

时间:2016-07-07 20:57:42

标签: linux kernel memory-management

包含的程序应该在Linux中产生分段错误,但它不会:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/* This program should produce a segmentation error */
/* but it doesn't */

/* Therefore memory bounds are not being checked by the kernel */

typedef struct {
   double x;
} blkfmt;

int main()
{
   blkfmt *blk;
   unsigned char *p;
   blk = (blkfmt *) malloc(sizeof(blkfmt));
   p = (unsigned char *) blk + 16384;
   /* this assignment should produce a segmentation error */
   *p = (unsigned char) 0xff;
   /* this print statement should produce a segmentation error */
   printf("%02x %d\n", *p, sizeof(blkfmt));
   free(blk);
   return(0);
} /* main */

生成文件:

OBJ=bug.o    
CC=gcc
CFLAGS=-c -Wall -O2
LDFLAGS=

bug:                $(OBJ)
        $(CC) -Wall -O2 $(OBJ) -o bug $(LDFLAGS)

bug.o:              bug.c
        $(CC) $(CFLAGS) bug.c

clean:
        rm -f bug $(OBJ)

3 个答案:

答案 0 :(得分:2)

内存分配器几乎可以做任何想做的事情。这就是为什么这不符合您的预期。

以下是运行程序的strace的输出。在其中,您可以看到brk系统调用用于为程序分配0x21000个字节。这是135,168字节。远远超过16,384你的程序添加到返回的指针。

execve("./malloc-outside-test", ["./malloc-outside-test"], [/* 62 vars */]) = 0
brk(NULL)                               = 0x1211000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2efad76000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=183184, ...}) = 0
mmap(NULL, 183184, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f2efad49000
close(3)                                = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\10\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2089496, ...}) = 0
mmap(NULL, 3938656, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f2efa792000
mprotect(0x7f2efa94b000, 2093056, PROT_NONE) = 0
mmap(0x7f2efab4a000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b8000) = 0x7f2efab4a000
mmap(0x7f2efab50000, 14688, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f2efab50000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2efad48000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2efad47000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2efad46000
arch_prctl(ARCH_SET_FS, 0x7f2efad47700) = 0
mprotect(0x7f2efab4a000, 16384, PROT_READ) = 0
mprotect(0x600000, 4096, PROT_READ)     = 0
mprotect(0x7f2efad77000, 4096, PROT_READ) = 0
munmap(0x7f2efad49000, 183184)          = 0
brk(NULL)                               = 0x1211000
brk(0x1232000)                          = 0x1232000
brk(NULL)                               = 0x1232000
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
write(1, "ff 8\n", 5)                   = 5
exit_group(0)   

答案 1 :(得分:1)

未定义未定义的行为 - 没有要求检测报告错误。大多数实现都支持性能而不是错误检测。

如果你想检查你的程序的正确性(提示:你这样做,就像我们其他人一样!),那么你想要使用Valgrind。当我使用您的程序运行Valgrind时,它会报告您的错误:

==26331== Invalid write of size 1
==26331==    at 0x40059E: main (38255191.c:21)
==26331==  Address 0x51de040 is 16,304 bytes inside an unallocated block of size 4,194,128 in arena "client"
==26331== 
==26331== Invalid read of size 1
==26331==    at 0x4005A5: main (38255191.c:23)
==26331==  Address 0x51de040 is 16,304 bytes inside an unallocated block of size 4,194,128 in arena "client"
==26331== 

顺便说一句,我注意到你的代码中存在一些问题。 sizeof blkfmtsize_t,因此您需要进行%zd转换。

此外,永远不应该施放malloc的结果,因为这可以掩盖其他问题。一个好的习语是p = malloc(sizeof *p) - 这显然是正确的,甚至无需查找p的类型。

此外,您还不需要加入<unistd.h>

简化示例:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    double *blk = malloc(sizeof *blk);;
    unsigned char *p = malloc(sizeof *blk);
    p = (unsigned char*)blk + 16384;
    /* this assignment writes to unallocated memory */
    *p = 0xff;
    /* this reads from unallocated memory */
    printf("%02x %zd\n", *p, sizeof *blk);
    free(blk);
    return 0;
}

答案 2 :(得分:0)

malloc将逐页从内核获取更大的空间(4096),因此如果指针指向有效空间,它将不会崩溃。