结构内字符串的 Malloc 溢出
Malloc of string inside struct overflows
以下代码是我目前正在处理的项目的示例,用 C 编写。
我首先 malloc 一个结构,然后作为示例 malloc 第一个里面的字符串。当我尝试将文本从另一个字符串复制到其中,并使用 printf
函数打印它时,当我使用 -fsanitize=address
作为编译标志进行编译时它会溢出。
我不明白为什么,因为我认为我正在为字符串分配足够的内存,因为我只是使用另一个字符串的 strlen
来获取长度,并为字符串添加一个额外的字符[=15=]
.
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
typedef struct s_word
{
int length;
char *str;
} t_word;
typedef struct s_list
{
t_word *word;
} t_list;
int main(void)
{
int i;
char *line = "this is a test";
t_list test;
i = -1;
test.word = malloc(sizeof(t_word) * 10);
test.word[0].str = malloc(sizeof(char) * (strlen(line) + 1));
while (line[++i])
test.word[0].str[i] = line[i];
printf("%s\n", test.word[0].str);
return (0);
}
=================================================================
==48531==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x00010940071f at pc 0x00010543ef60 bp 0x00016aee76a0 sp 0x00016aee6e28
READ of size 16 at 0x00010940071f thread T0
#0 0x10543ef5c in printf_common(void*, char const*, char*)+0x750 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x1ef5c)
#1 0x10543f7b8 in wrap_printf+0x78 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x1f7b8)
#2 0x104f1bc64 in main+0x3ac (a.out:arm64+0x100003c64)
#3 0x193291f30 in start+0x0 (libdyld.dylib:arm64e+0x16f30)
0x00010940071f is located 0 bytes to the right of 15-byte region [0x000109400710,0x00010940071f)
allocated by thread T0 here:
#0 0x10545fa6c in wrap_malloc+0x94 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3fa6c)
#1 0x104f1ba20 in main+0x168 (a.out:arm64+0x100003a20)
#2 0x193291f30 in start+0x0 (libdyld.dylib:arm64e+0x16f30)
SUMMARY: AddressSanitizer: heap-buffer-overflow (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x1ef5c) in printf_common(void*, char const*, char*)+0x750
Shadow bytes around the buggy address:
0x0070212a0090: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0070212a00a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0070212a00b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0070212a00c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0070212a00d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0070212a00e0: fa fa 00[07]fa fa 00 06 fa fa 00 00 fa fa 00 fa
0x0070212a00f0: fa fa 00 00 fa fa fd fd fa fa fa fa fa fa fa fa
0x0070212a0100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0070212a0110: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0070212a0120: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0070212a0130: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==48531==ABORTING
当 line[++i]
变为零时,循环 while (line[++i])
中断,因此终止空字符不会复制到 test.word[0].str
。复制应该是这样的:
do {
++i;
test.word[0].str[i] = line[i];
} while (line[i]);
另一种选择是简单地使用 strcpy()
:
strcpy(test.word[0].str, line);
以下代码是我目前正在处理的项目的示例,用 C 编写。
我首先 malloc 一个结构,然后作为示例 malloc 第一个里面的字符串。当我尝试将文本从另一个字符串复制到其中,并使用 printf
函数打印它时,当我使用 -fsanitize=address
作为编译标志进行编译时它会溢出。
我不明白为什么,因为我认为我正在为字符串分配足够的内存,因为我只是使用另一个字符串的 strlen
来获取长度,并为字符串添加一个额外的字符[=15=]
.
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
typedef struct s_word
{
int length;
char *str;
} t_word;
typedef struct s_list
{
t_word *word;
} t_list;
int main(void)
{
int i;
char *line = "this is a test";
t_list test;
i = -1;
test.word = malloc(sizeof(t_word) * 10);
test.word[0].str = malloc(sizeof(char) * (strlen(line) + 1));
while (line[++i])
test.word[0].str[i] = line[i];
printf("%s\n", test.word[0].str);
return (0);
}
=================================================================
==48531==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x00010940071f at pc 0x00010543ef60 bp 0x00016aee76a0 sp 0x00016aee6e28
READ of size 16 at 0x00010940071f thread T0
#0 0x10543ef5c in printf_common(void*, char const*, char*)+0x750 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x1ef5c)
#1 0x10543f7b8 in wrap_printf+0x78 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x1f7b8)
#2 0x104f1bc64 in main+0x3ac (a.out:arm64+0x100003c64)
#3 0x193291f30 in start+0x0 (libdyld.dylib:arm64e+0x16f30)
0x00010940071f is located 0 bytes to the right of 15-byte region [0x000109400710,0x00010940071f)
allocated by thread T0 here:
#0 0x10545fa6c in wrap_malloc+0x94 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3fa6c)
#1 0x104f1ba20 in main+0x168 (a.out:arm64+0x100003a20)
#2 0x193291f30 in start+0x0 (libdyld.dylib:arm64e+0x16f30)
SUMMARY: AddressSanitizer: heap-buffer-overflow (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x1ef5c) in printf_common(void*, char const*, char*)+0x750
Shadow bytes around the buggy address:
0x0070212a0090: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0070212a00a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0070212a00b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0070212a00c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0070212a00d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0070212a00e0: fa fa 00[07]fa fa 00 06 fa fa 00 00 fa fa 00 fa
0x0070212a00f0: fa fa 00 00 fa fa fd fd fa fa fa fa fa fa fa fa
0x0070212a0100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0070212a0110: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0070212a0120: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0070212a0130: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==48531==ABORTING
当 line[++i]
变为零时,循环 while (line[++i])
中断,因此终止空字符不会复制到 test.word[0].str
。复制应该是这样的:
do {
++i;
test.word[0].str[i] = line[i];
} while (line[i]);
另一种选择是简单地使用 strcpy()
:
strcpy(test.word[0].str, line);