printk: don't print incorrect 64-bit integers

printk is supposed to be very lean, but should at least not
print garbage values. Now when a 64-bit integral value is
passed in to be printed, 'ERR' will be reported if it doesn't
fit in 32-bits instead of truncating it.

The printk documentation was slightly out of date, this has been
updated.

Fixes: #7179

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2019-01-17 13:26:51 -08:00 committed by Andrew Boie
parent 12836d9280
commit 970758408b
3 changed files with 52 additions and 15 deletions

View file

@ -33,8 +33,11 @@ extern "C" {
* - character: \%c
* - percent: \%\%
*
* No other conversion specification capabilities are supported, such as flags,
* field width, precision, or length attributes.
* Field width (with or without leading zeroes) are supported.
* Length attributes such as 'h' and 'l' are supported. However,
* integral values with %lld and %lli are only printed if they fit in 32 bits,
* otherwise 'ERR' is printed. Full 64-bit values may be printed with %llx.
* Flags and precision attributes are not supported.
*
* @param fmt Format string.
* @param ... Optional list of format arguments.

View file

@ -82,6 +82,13 @@ void *__printk_get_hook(void)
return _char_out;
}
static void print_err(out_func_t out, void *ctx)
{
out('E', ctx);
out('R', ctx);
out('R', ctx);
}
/**
* @brief Printk internals
*
@ -141,11 +148,25 @@ void _vprintk(out_func_t out, void *ctx, const char *fmt, va_list ap)
goto still_might_format;
case 'd':
case 'i': {
long d;
if (long_ctr < 2) {
d = va_arg(ap, long);
s32_t d;
if (long_ctr == 0) {
d = va_arg(ap, int);
} else if (long_ctr == 1) {
long ld = va_arg(ap, long);
if (ld > INT32_MAX || ld < INT32_MIN) {
print_err(out, ctx);
break;
}
d = (s32_t)ld;
} else {
d = (long)va_arg(ap, long long);
long long lld = va_arg(ap, long long);
if (lld > INT32_MAX ||
lld < INT32_MIN) {
print_err(out, ctx);
break;
}
d = (s32_t)lld;
}
if (d < 0) {
@ -158,14 +179,27 @@ void _vprintk(out_func_t out, void *ctx, const char *fmt, va_list ap)
break;
}
case 'u': {
unsigned long u;
u32_t u;
if (long_ctr < 2) {
u = va_arg(ap, unsigned long);
} else {
u = (unsigned long)va_arg(ap,
unsigned long long);
if (long_ctr == 0) {
u = va_arg(ap, unsigned int);
} else if (long_ctr == 1) {
long lu = va_arg(ap, unsigned long);
if (lu > INT32_MAX) {
print_err(out, ctx);
break;
}
u = (u32_t)lu;
} else {
unsigned long long llu =
va_arg(ap, unsigned long long);
if (llu > INT32_MAX) {
print_err(out, ctx);
break;
}
u = (u32_t)llu;
}
_printk_dec_ulong(out, ctx, u, padding,
min_width);
break;

View file

@ -25,7 +25,7 @@ char *expected = "22 113 10000 32768 40000 22\n"
"42 42 42 42\n"
"42 42 0042 00000042\n"
"255 42 abcdef 0x0000002a 42\n"
"-1 4294967295 ffffffffffffffff\n"
"ERR -1 ERR ffffffffffffffff\n"
;
@ -86,7 +86,7 @@ void test_printk(void)
printk("%u %2u %4u %8u\n", 42, 42, 42, 42);
printk("%u %02u %04u %08u\n", 42, 42, 42, 42);
printk("%-8u%-6d%-4x%-2p%8d\n", 0xFF, 42, 0xABCDEF, (char *)42, 42);
printk("%lld %llu %llx\n", -1LL, -1ULL, -1ULL);
printk("%lld %lld %llu %llx\n", 0xFFFFFFFFFULL, -1LL, -1ULL, -1ULL);
ram_console[pos] = '\0';
zassert_true((strcmp(ram_console, expected) == 0), "printk failed");
@ -117,8 +117,8 @@ void test_printk(void)
"%-8u%-6d%-4x%-2p%8d\n",
0xFF, 42, 0xABCDEF, (char *)42, 42);
count += snprintk(ram_console + count, sizeof(ram_console) - count,
"%lld %llu %llx\n",
-1LL, -1ULL, -1ULL);
"%lld %lld %llu %llx\n",
0xFFFFFFFFFULL, -1LL, -1ULL, -1ULL);
ram_console[count] = '\0';
zassert_true((strcmp(ram_console, expected) == 0), "snprintk failed");
}