'Variadic arguments bug Macbook Air M1

I'm currently creating a printf function from scratch which is working on a iMac 2020 and not on Air M1

If I try to test with the same % and different results, it will always show the first one.

For example: ft_printf(“test %s %s”, “test2", “test3”) Output: test test2 test2

But the output on the iMac is the correct one: test test2 test3

this is the main function:

int main()
{
    ft_printf("test %s %s\n", "test2", "test3");
    printf("test %s %s\n", "test2", "test3");
    return (0);
}

int ft_printf(const char *str, ...)
{
    va_list ap;
    int     cont;
    int     ret;

    cont = 0;
    va_start(ap, str);
    while (str[cont] != '\0')
    {
        if (str[cont] == '%')
        {
            ft_after_percentage(ap, str[cont + 1]);
            cont += 2;
            continue ;
        }
        write(1, &str[cont], 1);
        ft_count_return(0);
        cont++;
    }
    va_end(ap);
    ret = ft_count_return(0) - 1;
    ft_count_return(1);
    return (ret);
}

void    ft_after_percentage(va_list ap, char c)
{
    if (c == 'c')
        ft_putchar(va_arg(ap, int));
    else if (c == 's')
        ft_putstr(va_arg(ap, char *));
    else if (c == 'p')
        ft_percentage_p(va_arg(ap, long unsigned));
    else if (c == 'd')
        ft_putnbr(va_arg(ap, int));
    else if (c == 'i')
        ft_putnbr(va_arg(ap, int));
    else if (c == 'u')
        ft_uns_putnbr(va_arg(ap, unsigned int));
    else if (c == 'x')
        ft_puthex(va_arg(ap, int), "0123456789abcdef");
    else if (c == 'X')
        ft_puthex(va_arg(ap, int), "0123456789ABCDEF");
    else if (c == '%')
        ft_putchar('%');
}



Solution 1:[1]

Once you have passed the va_list variable by value to another function which uses va_arg() on it, you are not supposed to use that va_list variable in the calling function again.

The C99 standard, in the section for the stdarg.h header, says:

The type declared is va_list which is an object type suitable for holding information needed by the macros va_start, va_arg, va_end, and va_copy. If access to the varying arguments is desired, the called function shall declare an object (generally referred to as ap in this subclause) having type va_list. The object ap may be passed as an argument to another function; if that function invokes the va_arg macro with parameter ap, the value of ap in the calling function is indeterminate and shall be passed to the va_end macro prior to any further reference to ap.212)

So here, you pass ap by value to ft_after_percentage(), which calls va_arg() on it, and then you continue to use ap in the calling function (by passing it to ft_after_percentage() for the second variable argument). This causes undefined behavior. It might happen to work on one architecture, but not another, due to differences in how va_list is implemented between architectures.

The footnote from above suggests for your ft_after_percentage() to instead take a va_list *, and pass &ap to it:

: 212) It is permitted to create a pointer to a va_list and pass that pointer to another function, in which case the original function may make further use of the original list after the other function returns.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 newacct