使用简单的 malloc() 时如何修复 libc 中止错误
Posted
技术标签:
【中文标题】使用简单的 malloc() 时如何修复 libc 中止错误【英文标题】:How do i fix libc abort error when using a simple malloc() 【发布时间】:2022-01-05 03:34:58 【问题描述】:我正在尝试重写 printf 函数。为了快速总结我的方法,我创建了一个包含 va_list 和其他一些整数变量的结构,以包含有关每种格式将使用哪些标志的信息。在 ft_printf 函数中,我正在写每个字母,直到找到一个 % 符号。一旦找到,我应用 ft_analise_flags 函数来检查潜在的标志。在该函数内部,我应用了另一个(ft_analise_width),它将检查可选宽度,然后在此内部我还调用另一个函数来查找可选精度。只有在我最终尝试转换格式之后。
我还没有完成程序,但我正在做一些测试,我发现了这个错误。当我使用宽度参数时,我得到了一堆错误。 当我使用 vs 代码调试器时,调用堆栈显示一些 libc.so.6! __GI_raise()、__GI_abort()、__malloc_asssert 等错误。它还提示说:(无法打开'raise.c')。
我已经搜索过这种错误,但我倾向于陷入我不明白如何应用的答案。我认为问题出在执行 malloc 时的 ft_subtr 函数中,因为那是调试器给出错误的地方。其他可能出现错误的地方是当我释放标签时,虽然我不明白为什么会出现错误。也许是因为我释放了一个指向包含 va_list 变量的结构的指针...
我知道这是很多代码,但如果有人理解这一点或遇到类似的问题,我想知道您是否有任何提示可以帮助我继续前进
#include <unistd.h>
#include <stdio.h> // official printf
#include <stdarg.h>
#include <stdlib.h>
size_t ft_strlen(const char *s)
size_t i;
i = 0;
while (s[i] != '\0')
i++;
return (i);
char *ft_substr(char const *s, int start, int len)
char *ptr;
int index;
ptr = (char *)malloc((len + 1) * sizeof(char));
if (!ptr)
return (NULL);
index = 0;
while (index < len)
ptr[index] = s[start + index];
index++;
ptr[index] = '\0';
return (ptr);
int ft_atoi(const char *str)
int number;
int sign;
sign = 1;
number = 0;
while (*str == ' ' || *str == '\f' || *str == '\n' || *str == '\r' || *str == '\t' || *str == '\v')
str++;
if (*str == '+' || *str == '-')
if (*str == '-')
sign *= -1;
str++;
while (*str > 47 && *str < 58)
number = (number * 10) + (*str - 48);
str++;
return (number * sign);
typedef struct print_settings
va_list args;
int hash;
int zero;
int dash;
int space;
int plus;
int width;
int precision;
int point;
int t_length;
frt_settings;
frt_settings *ft_initialise_tab(frt_settings *tab)
tab->hash = 0;
tab->zero = 0;
tab->dash = 0;
tab->space = 0;
tab->plus = 0;
tab->width = 0;
tab->precision = 0;
tab->point = 0;
tab->t_length = 0;
return (tab);
frt_settings *set_tab(frt_settings *tab)
int i;
i = tab->t_length;
ft_initialise_tab(tab);
tab->t_length = i;
return (tab);
void ft_print_percent(frt_settings *tab, char percent)
char a = percent;
tab->t_length += write(1, &a, 1);
set_tab(tab);
int ft_convert(frt_settings *tab, const char *format, int i)
if (format[i] == '%')
ft_print_percent(tab, format[i]);
/*else if (format[i] == 'c')
ft_print_char(tab);
else if (format[i] == 's')
ft_print_string(tab);
else if (format[i] == 'p')
ft_print_void(tab);
else if (format[i] == 'd')
ft_print_dec_num(tab);
else if (format[i] == 'i')
ft_print_int(tab);
else if (format[i] == 'u')
ft_print_unsigned_dec(tab);
else if (format[i] == 'x')
ft_print_num_hex_lower(tab);
else if (format[i] == 'X')
ft_print_num_hex_upper(tab);*/
return (i);
int ft_analise_precision(frt_settings *tab, const char *format, int i)
int j;
char *precision;
tab->point = 1;
j = i;
while (format[i] > 48 && format[i] < 58)
i++;
if (j != i)
precision = ft_substr(format, j, i - j);
tab->precision = ft_atoi(precision);
free(precision);
i = ft_convert(tab, format, i);
return (i);
int ft_analise_width(frt_settings *tab, const char *format, int i)
int j;
char *width;
j = i;
if (format[i] > 48 && format[i] < 58)
while (format[i] > 47 && format[i] < 58)
i++;
if (j != i)
width = ft_substr(format, j, i - j);
tab->width = ft_atoi(width);
free(width);
if (format[i] == '.')
i = ft_analise_precision(tab, format, i + 1);
else
i = ft_convert(tab, format, i);
return (i);
int is_flag(char letter)
char conversions[5];
int i;
conversions[0] = '-';
conversions[1] = '0';
conversions[2] = '#';
conversions[3] = ' ';
conversions[4] = '+';
i = 0;
while (i < 5)
if (conversions[i++] == letter)
return (1);
return (0);
int ft_analise_flags(frt_settings *tab, const char *format, int i)
while (is_flag(format[i]))
if (format[i] == '-')
tab->dash = 1;
if (format[i] == '0')
tab->zero = 1;
if (format[i] == '#')
tab->hash = 1;
if (format[i] == ' ')
tab->space = 1;
if (format[i] == '+')
tab->plus = 1;
i++;
i = ft_analise_width(tab, format, i);
return (i);
int ft_printf(const char *format, ...)
frt_settings *tab;
int i;
int t_printed;
tab = (frt_settings *)malloc(sizeof(tab));
if (!tab)
return (-1);
ft_initialise_tab(tab);
va_start(tab->args, format);
i = -1;
t_printed = 0;
while (format[++i])
if (format[i] == '%')
i = ft_analise_flags(tab, format, i + 1);
else
t_printed += write(1, &format[i], 1);
va_end(tab->args);
t_printed += tab->t_length;
free(tab);
return (t_printed);
int main()
ft_printf("%22%\n");
【问题讨论】:
【参考方案1】:我认为问题在于执行 malloc 时的 ft_subtr 函数
没有。问题是您的程序误用 malloc
(导致堆损坏)。
使用 Address Sanitizer 构建它会产生:
$ gcc -g -fsanitize=address p.c
$ ./a.out
=================================================================
==677491==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000028 at pc 0x5608ee09d565 bp 0x7ffc9b587f60 sp 0x7ffc9b587f58
WRITE of size 4 at 0x602000000028 thread T0
#0 0x5608ee09d564 in ft_initialise_tab /tmp/p.c:75
#1 0x5608ee09e442 in ft_printf /tmp/p.c:214
#2 0x5608ee09e5fc in main /tmp/p.c:233
#3 0x7f778eb31e49 in __libc_start_main ../csu/libc-start.c:314
#4 0x5608ee09d129 in _start (/tmp/a.out+0x1129)
0x602000000028 is located 16 bytes to the right of 8-byte region [0x602000000010,0x602000000018)
allocated by thread T0 here:
#0 0x7f778ed7d7cf in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
#1 0x5608ee09e418 in ft_printf /tmp/p.c:211
#2 0x5608ee09e5fc in main /tmp/p.c:233
#3 0x7f778eb31e49 in __libc_start_main ../csu/libc-start.c:314
SUMMARY: AddressSanitizer: heap-buffer-overflow /tmp/p.c:75 in ft_initialise_tab
Shadow bytes around the buggy address:
0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa fa 00 fa fa[fa]fa fa fa fa fa fa fa fa fa fa
0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8050: 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
==677491==ABORTING
具体来说,这一行有问题(分配 8 个字节而不是预期的sizeof(struct print_settings)
):
tab = (frt_settings *)malloc(sizeof(tab));
应该是:
tab = malloc(sizeof(*tab));
(不应该~永远不要在C
中返回malloc
。)
【讨论】:
非常感谢以上是关于使用简单的 malloc() 时如何修复 libc 中止错误的主要内容,如果未能解决你的问题,请参考以下文章