malloc()和memset()行为

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)

Mat*_*lia 5

首先,这是未定义的行为,所以任何事情都可能发生; 正如在评论中所说,在我的机器上,我得到了完全相同的行为,禁用了优化,但启用了优化,我得到一个关于编译时潜在缓冲区溢出的警告(令人印象深刻的作业gcc!)和运行时的大崩溃.更好的是,如果我putsprintf打电话之前打印它,我会用不同数量打印它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在与它给你的一个紧邻的内存块上执行它的东西(可能将其标记为已使用)来调用(或多或少间接)代码.

长话短说:你记忆的不是你的记忆,现在它在第一次需要的时候被其合法的主人修改了; 没什么特别奇怪或有趣的.