【问题标题】:How do i fix libc abort error when using a simple malloc()使用简单的 malloc() 时如何修复 libc 中止错误
【发布时间】: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");
}

【问题讨论】:

    标签: c printf malloc variadic-functions libc


    【解决方案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。)

    【讨论】:

    • 非常感谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-20
    • 1970-01-01
    • 2019-12-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多