簡體   English   中英

malloc()和memset()行為

[英]malloc() and memset() behavior

我寫了一些代碼來看看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;
}

這是我得到的輸出:

sizeof(char)   ------  1
sizeof(charptr)   ---  8
sizeof(*charptr)  ---  1
sizeof(&charptr)  ---  8
strlen(charptr)   ---  26
charptr string   ----  >>aaaaaaaaaaaaaaaaaaaaaaaa<<

首先,這是未定義的行為,所以任何事情都可能發生; 正如在評論中所說,在我的機器上,我得到了完全相同的行為,禁用了優化,但啟用了優化,我得到一個關於編譯時潛在緩沖區溢出的警告(令人印象深刻的作業gcc!)和運行時的大崩潰。 更好的是,如果我在printf調用之前使用puts打印它,我會使用不同數量的a打印它。

盡管如此,我仍然懷有與你完全相同的行為,所以讓我們來調查一下。 我編譯了你的程序沒有優化和調試信息

[matteo@teokubuntu ~/scratch]$ gcc -g memset_test.c 

然后我啟動了調試器並在memset之后的第一個printf上添加了一個斷點。

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));

現在我們可以在charptr指向的第26個內存位置設置硬件寫斷點

(gdb) p charptr
$1 = 0x555555756260 'a' <repeats 100 times>
(gdb) watch charptr[26]
Hardware watchpoint 2: charptr[26]

... 所以...

(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) 

因此,它只是通過printf調用malloc代碼(或多或少地間接),在內存塊上執行它的東西,緊鄰它給你的內存塊(可能將其標記為已使用)。

長話短說:你記憶的不是你的記憶,現在它在第一次需要的時候被其合法的主人修改了; 沒什么特別奇怪或有趣的。

我使用malloc()為字符數組分配15個字節的內存,我想看看如果我錯誤地使用memset()在我創建的指針中設置100個字節的內存會發生什么。

就語言標准而言, 未定義的行為會發生什么,並且在特定情況下實際發生的任何事情都無法從源代碼中預測到,並且可能在不同的C實現或甚至同一程序的不同運行中不一致。

我希望看到memset()設置了15個字節(並且可能會丟棄一些其他內存)。

這將是一個看似合理的結果,但你有任何特別的期望是危險的。 不要假設您可以預測UB會采取什么樣的表現,甚至不能根據過去的經驗來預測。 既然你不應該這樣做,也不能從那個方面學到任何有用的東西,那么試驗UB是不值得的。

我在運行程序時看到的是它為我編碼的字符設置了26個字節的內存。

知道為什么為我創建的指針分配了26個字節?

誰說你的實驗表明情況如此? 不僅memset()而且最后的printf()展示了UB。 除了輸出之外,輸出告訴你什么。 那時。

現在一般情況下, malloc可能會保留比您要求的更大的塊。 許多實現在內部管理大於一個字節的塊的內存,例如16或32字節。 但是,對於程序行為的定義,這與這種或那種方式無關,並且它與您的輸出無關。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM