[英]How to use malloc() and memset()
我對 C 非常copy_buffer
並試圖實現一個copy_buffer
函數來分配一個新緩沖區,將現有緩沖區中的內容復制到新緩沖區中,然后返回新緩沖區。
我正在嘗試使用malloc()
和memset()
,我知道我需要malloc
兩次:一次用於結構,一次用於數據。 我是否也需要memset
兩次? 請指出我為copy_buffer
函數寫錯的copy_buffer
。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Structure to hold a buffer of binary data
// Note that we expect that it could hold null(0) characters,
// so we can't rely on strlen to tell us the size or strcpy to copy the data
typedef struct BufferStruct {
char *data;
int size;
} Buffer;
Buffer *copy_buffer(Buffer *buffer) {
Buffer *new_buffer = (Buffer*)malloc(sizeof(Buffer));
memset(new_buffer, 0, sizeof(Buffer));
new_buffer->data = malloc(sizeof(char));
memset(new_buffer->data, 0, sizeof(char));
for (int i = 0; i < buffer->size; ++i) {
new_buffer->data[i] = buffer->data[i];
}
new_buffer->size = buffer->size;
return new_buffer;
}
Buffer *example1() {
Buffer *buffer = (Buffer*)malloc(sizeof(Buffer));
buffer->data = "hello world\nthis is a string";
buffer->size = strlen(buffer->data);
return buffer;
}
// Example buffer storing 3 totally different strings in the same buffer (note the '\0')
Buffer *example2() {
Buffer *buffer = (Buffer*)malloc(sizeof(Buffer));
buffer->data = "this string has null\0characters\0 in the middle, beware!";
buffer->size = 55;
return buffer;
}
//
// Use fopen to create a file for writing
// Then fwrite to write the buffer to a file
//
void write_buffer(const char *filename, Buffer *buffer) {
FILE *file = fopen(filename, "w");
fwrite(buffer->data, 1, buffer->size, file);
fclose(file);
}
int main() {
Buffer *example = example2();
Buffer *copied = copy_buffer(example);
write_buffer("example1.bin", copied);
return 0;
}
我是否也需要 memset 兩次?
從技術上講不可以,前提是您在使用它們之前正確初始化Buffer
結構的所有元素。
然而,我覺得這是一個危險的習慣。 保持一致非常困難,並且在某些情況下,如果您犯了錯誤,程序可能會崩潰。 許多開發人員似乎建議初始化或零初始化變量,尤其是數據緩沖區,但意見(和情況)各不相同。
您可以使用與malloc
和memset
具有相同效果的calloc
:
Buffer *buffer = calloc(1, sizeof(Buffer));
這將分配和零初始化內存。
正如@Chris Rollins 指出的那樣,
new_buffer->data = malloc(sizeof(char));
只分配一個字節的存儲空間,因為sizeof(char)
是 1。當程序將數據從一個緩沖區復制到另一個緩沖區時,它開始覆蓋堆上的未知內存!
for (int i = 0; i < buffer->size; ++i) {
// new_buffer only has space for one byte,
// but we can copy several!
new_buffer->data[i] = buffer->data[i]; // BOOM
}
這是緩沖區溢出。 這是嚴重的缺陷,可能/將導致程序崩潰。 你並不孤單; 類似的錯誤導致了許多安全漏洞。
運行時內存分析可以捕獲這樣的錯誤。 如果您使用 Clang 或 gcc 進行編譯,地址清理器(通常稱為 ASAN)會指出具體的錯誤。
用這樣的東西編譯:
gcc main.c -o main -fsanitize=address -fno-omit-frame-pointer -g
您將收到一條錯誤消息,指出錯誤的代碼行:
=================================================================
==28677==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000efb1 at pc 0x000000400d29 bp 0x7fffa8a5db00 sp 0x7fffa8a5daf0
WRITE of size 1 at 0x60200000efb1 thread T0
#0 0x400d28 in copy_buffer main.c:20
#1 0x400f5d in main main.c:52
#2 0x7ff7256cf82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#3 0x400a88 in _start (main+0x400a88)
0x60200000efb1 is located 0 bytes to the right of 1-byte region [0x60200000efb0,0x60200000efb1)
allocated by thread T0 here:
#0 0x7ff725b11602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
#1 0x400c09 in copy_buffer main.c:17
#2 0x400f5d in main main.c:52
#3 0x7ff7256cf82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
密集但值得破譯:
heap-buffer-overflow on address
in copy_buffer main.c:20
in main main.c:52
in copy_buffer main.c:20
in copy_buffer main.c:17
in main main.c:52
in copy_buffer main.c:17
行號特定於我的.c
文件,可能因您的機器而異。
memcpy
正如@Steve Summit 指出的那樣,您可以替換for
循環:
for (int i = 0; i < buffer->size; ++i) {
new_buffer->data[i] = buffer->data[i];
}
一次調用memcpy
:
memcpy(new_buffer->data, buffer->data, buffer->size);
這與for
循環具有相同的風險,但更簡潔/更易於閱讀。 它也應該一樣快。
將這些想法合並到copy_buffer
可能看起來像這樣:
Buffer *copy_buffer(Buffer *buffer) {
Buffer *new_buffer = calloc(1, sizeof(Buffer));
new_buffer->data = calloc(buffer->size, sizeof(char));
memcpy(new_buffer->data, buffer->data, buffer->size);
new_buffer->size = buffer->size;
return new_buffer;
}
calloc
在堆上分配和初始化內存new_buffer->data
足夠大,可以容納所有buffer
的data
memcpy()
簡潔地將數據從一個緩沖區復制到另一個緩沖區當然,不要忘記free
你分配的內存!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.