Sch*_*cky 2 c malloc gcc glibc memset
我写了一些代码来看看如何malloc()
和memset()
表现,我发现了一个我不知道发生了什么的情况.
我曾经malloc()
为字符数组分配15个字节的内存,我想看看如果我memset()
错误地在我创建的指针中设置了100个字节的内存会发生什么.我希望看到它memset()
设置了15个字节(并且可能会丢弃一些其他内存).我在运行程序时看到的是它为我编码的字符设置了26个字节的内存.
知道为什么为我创建的指针分配了26个字节?我正在用gcc和glibc编译.这是代码:
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#define ARRLEN 14
int main(void) {
/* + 1 for the null terminator */
char *charptr = malloc((sizeof(*charptr) * ARRLEN) + 1);
if (!charptr)
exit(EXIT_FAILURE);
memset(charptr, '\0', (sizeof(*charptr) * ARRLEN) + 1);
/* here's the intentionally incorrect call to memset() */
memset(charptr, 'a', 100);
printf("sizeof(char) ------ %ld\n", sizeof(char));
printf("sizeof(charptr) --- %ld\n", sizeof(charptr));
printf("sizeof(*charptr) --- %ld\n", sizeof(*charptr));
printf("sizeof(&charptr) --- %ld\n", sizeof(&charptr));
printf("strlen(charptr) --- %ld\n", strlen(charptr));
printf("charptr string ---- >>%s<<\n", charptr);
free(charptr);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是我得到的输出:
sizeof(char) ------ 1
sizeof(charptr) --- 8
sizeof(*charptr) --- 1
sizeof(&charptr) --- 8
strlen(charptr) --- 26
charptr string ---- >>aaaaaaaaaaaaaaaaaaaaaaaa<<
Run Code Online (Sandbox Code Playgroud)
首先,这是未定义的行为,所以任何事情都可能发生; 正如在评论中所说,在我的机器上,我得到了完全相同的行为,禁用了优化,但启用了优化,我得到一个关于编译时潜在缓冲区溢出的警告(令人印象深刻的作业gcc!)和运行时的大崩溃.更好的是,如果我puts
在printf
打电话之前打印它,我会用不同数量打印它a
.
尽管如此,我仍然怀有与你完全相同的行为,所以让我们来调查一下.我编译了你的程序没有优化和调试信息
[matteo@teokubuntu ~/scratch]$ gcc -g memset_test.c
Run Code Online (Sandbox Code Playgroud)
然后我启动了调试器并在第一个printf
之后添加了一个断点memset
.
Reading symbols from a.out...done.
(gdb) break 20
Breakpoint 1 at 0x87e: file memset_test.c, line 20.
(gdb) r
Starting program: /home/matteo/scratch/a.out
Breakpoint 1, main () at memset_test.c:20
20 printf("sizeof(char) ------ %ld\n", sizeof(char));
Run Code Online (Sandbox Code Playgroud)
现在我们可以在指向的第26个内存位置设置硬件写断点 charptr
(gdb) p charptr
$1 = 0x555555756260 'a' <repeats 100 times>
(gdb) watch charptr[26]
Hardware watchpoint 2: charptr[26]
Run Code Online (Sandbox Code Playgroud)
... 所以...
(gdb) c
Continuing.
Hardware watchpoint 2: charptr[26]
Old value = 97 'a'
New value = 0 '\000'
_int_malloc (av=av@entry=0x7ffff7dcfc40 <main_arena>, bytes=bytes@entry=1024) at malloc.c:4100
4100 malloc.c: File o directory non esistente.
(gdb) bt
#0 _int_malloc (av=av@entry=0x7ffff7dcfc40 <main_arena>, bytes=bytes@entry=1024) at malloc.c:4100
#1 0x00007ffff7a7b0fc in __GI___libc_malloc (bytes=1024) at malloc.c:3057
#2 0x00007ffff7a6218c in __GI__IO_file_doallocate (fp=0x7ffff7dd0760 <_IO_2_1_stdout_>) at filedoalloc.c:101
#3 0x00007ffff7a72379 in __GI__IO_doallocbuf (fp=fp@entry=0x7ffff7dd0760 <_IO_2_1_stdout_>) at genops.c:365
#4 0x00007ffff7a71498 in _IO_new_file_overflow (f=0x7ffff7dd0760 <_IO_2_1_stdout_>, ch=-1) at fileops.c:759
#5 0x00007ffff7a6f9ed in _IO_new_file_xsputn (f=0x7ffff7dd0760 <_IO_2_1_stdout_>, data=<optimized out>, n=23)
at fileops.c:1266
#6 0x00007ffff7a3f534 in _IO_vfprintf_internal (s=0x7ffff7dd0760 <_IO_2_1_stdout_>,
format=0x5555555549c8 "sizeof(char) ------ %ld\n", ap=ap@entry=0x7fffffffe330) at vfprintf.c:1328
#7 0x00007ffff7a48f26 in __printf (format=<optimized out>) at printf.c:33
#8 0x0000555555554894 in main () at memset_test.c:20
(gdb)
Run Code Online (Sandbox Code Playgroud)
因此,它只是malloc
通过printf
在与它给你的一个紧邻的内存块上执行它的东西(可能将其标记为已使用)来调用(或多或少间接)代码.
长话短说:你记忆的不是你的记忆,现在它在第一次需要的时候被其合法的主人修改了; 没什么特别奇怪或有趣的.