Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Fri, 7 Apr 2017 10:26:29 -0400
From: Rich Felker <>
Subject: Re: Undefined behavior in sprintf(dest, "%lld", -1LL)

On Fri, Apr 07, 2017 at 02:22:46PM +0000, Pascal Cuoq wrote:
> I am running musl's implementation inside tis-interpreter, a C interpreter that detects a very wide palette of undefined behaviors.
> When musl's printf implementation is invoked through the following test driver:
>   char dest[100];
>   int x = sprintf(dest, "%lld\n", -1LL);
> tis-interpreter emits this warning:
> src/stdio/vfprintf.c:141: warning: although the type provided to the va_arg macro (unsigned long long) and the actual type of the next variadic argument (long long) are corresponding unsigned - signed variants of the same integer type, the actual value of the argument (signed) is negative thus it cannot be represented in the provided (unsigned) type
> The warning of course refers to C11
> To get a clearer view, I instrumented the code thus using the debug function tis_printf (we are inside the implementation of printf, it is a bad idea to call printf here):
> --- ../musl-1.1.16/src/stdio/vfprintf.c 2017-01-01 04:27:17.000000000 +0100
> +++ src/stdio/vfprintf.c 2017-04-07 16:13:19.291592002 +0200
> @@ -547,7 +547,7 @@
>   if (argpos>=0) goto inval;
>   } else {
>   if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos];
> - else if (f) pop_arg(&arg, st, ap);
> + else if (f) { tis_printf("st:%u LLONG:%u ULLONG:%u\n", st, LLONG, ULLONG); pop_arg(&arg, st, ap); }
>   else return 0;
>   }
> This shows the debug message below:
> st:12 LLONG:12 ULLONG:12
> On the basis of this result, I would tentatively offer that the undefined behavior that tis-interpreter warns about is real and is caused by line 55 in vfprintf.c:
> #define LLONG ULLONG
> Because of this approach, when LLONG is passed to the function pop_arg(), the switch case at line 141 is taken:
> break; case ULLONG: arg->i = va_arg(*ap, unsigned long long);
> This causes UB by consuming a (negative) long long argument from a va_list with va_arg(..., unsigned long long).
> Pascal

Does defining the ODD_TYPES macro fix the problem? My leaning is to
just remove that #ifdef logic and always use the correct type with
va_arg. All that was doing was saving a few bytes of code; the change
should not affect performance.


Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.