Skip to content

Commit

Permalink
printk: don't print incorrect 64-bit integers
Browse files Browse the repository at this point in the history
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: zephyrproject-rtos#7179

Signed-off-by: Andrew Boie <[email protected]>
  • Loading branch information
Andrew Boie authored and andrewboie committed Jan 18, 2019
1 parent 12836d9 commit 9707584
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 16 deletions.
7 changes: 5 additions & 2 deletions include/misc/printk.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
54 changes: 44 additions & 10 deletions misc/printk.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -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) {
Expand All @@ -158,14 +179,27 @@ void _vprintk(out_func_t out, void *ctx, const char *fmt, va_list ap)
break;
}
case 'u': {
unsigned long u;

if (long_ctr < 2) {
u = va_arg(ap, unsigned long);
u32_t u;

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 {
u = (unsigned long)va_arg(ap,
unsigned long long);
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;
Expand Down
8 changes: 4 additions & 4 deletions tests/kernel/common/src/printk.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
;


Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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");
}
Expand Down

0 comments on commit 9707584

Please sign in to comment.