fix(dlog): fix bug in handling of `%*`
The `dlog` function was not handling the `%*` format specifier
correctly.
The bug was caused by passing `va_list` by value instead of by
reference: In a call like `dlog("%*s", 10, "hello")`, the `va_list`
argument would be copied when passed to `parse_min_width`, and `10`
would be popped from the `va_list` to be used as the min_width. But then
`10` would be popped again and used as the `%s` argument, rather than
"hello".
Change-Id: I5c53465384196ee21d2a63167cf82e4f8ead9c3a
Signed-off-by: Karl Meakin <karl.meakin@arm.com>
diff --git a/src/dlog.c b/src/dlog.c
index 780cf55..aa174d1 100644
--- a/src/dlog.c
+++ b/src/dlog.c
@@ -317,7 +317,8 @@
*
* Returns a pointer to the first non-digit character in the string.
*/
-static const char *parse_min_width(const char *fmt, va_list args,
+static const char *parse_min_width(const char *fmt,
+ struct va_list_wrapper *args,
struct format_flags *flags, int *min_width)
{
int width = 0;
@@ -325,7 +326,7 @@
/* Read minimum width from arguments. */
if (*fmt == '*') {
fmt++;
- width = va_arg(args, int);
+ width = va_arg(args->va, int);
if (width < 0) {
width = -width;
flags->minus = true;
@@ -408,7 +409,7 @@
*
* Returns number of characters written, or `-1` if format string is invalid.
*/
-size_t vdlog(const char *fmt, va_list args)
+size_t vdlog(const char *fmt, struct va_list_wrapper *args)
{
size_t chars_written = 0;
@@ -442,7 +443,7 @@
break;
case 'c': {
- char str[2] = {va_arg(args, int), 0};
+ char str[2] = {va_arg(args->va, int), '\0'};
fmt++;
chars_written += print_string(
@@ -451,7 +452,7 @@
}
case 's': {
- char *str = va_arg(args, char *);
+ char *str = va_arg(args->va, char *);
fmt++;
chars_written += print_string(
@@ -462,7 +463,7 @@
case 'd':
case 'i': {
fmt++;
- value = va_arg(args, uint64_t);
+ value = va_arg(args->va, uint64_t);
value = reinterpret_signed_int(length, value,
&flags);
@@ -473,7 +474,7 @@
case 'b':
fmt++;
- value = va_arg(args, uint64_t);
+ value = va_arg(args->va, uint64_t);
value = reinterpret_unsigned_int(length, value);
chars_written += print_int(value, base2,
@@ -483,7 +484,7 @@
case 'B':
fmt++;
flags.upper = true;
- value = va_arg(args, uint64_t);
+ value = va_arg(args->va, uint64_t);
value = reinterpret_unsigned_int(length, value);
chars_written += print_int(value, base2,
@@ -492,7 +493,7 @@
case 'o':
fmt++;
- value = va_arg(args, uint64_t);
+ value = va_arg(args->va, uint64_t);
value = reinterpret_unsigned_int(length, value);
chars_written += print_int(value, base8,
@@ -501,7 +502,7 @@
case 'x':
fmt++;
- value = va_arg(args, uint64_t);
+ value = va_arg(args->va, uint64_t);
value = reinterpret_unsigned_int(length, value);
chars_written += print_int(value, base16,
@@ -511,7 +512,7 @@
case 'X':
fmt++;
flags.upper = true;
- value = va_arg(args, uint64_t);
+ value = va_arg(args->va, uint64_t);
value = reinterpret_unsigned_int(length, value);
chars_written += print_int(value, base16,
@@ -520,7 +521,7 @@
case 'u':
fmt++;
- value = va_arg(args, uint64_t);
+ value = va_arg(args->va, uint64_t);
value = reinterpret_unsigned_int(length, value);
chars_written += print_int(value, base10,
@@ -529,7 +530,7 @@
case 'p':
fmt++;
- value = va_arg(args, uint64_t);
+ value = va_arg(args->va, uint64_t);
min_width = sizeof(size_t) * 2 + 2;
flags.zero = true;
flags.alt = true;
@@ -569,10 +570,10 @@
size_t dlog(const char *fmt, ...)
{
size_t chars_written = 0;
- va_list args;
+ struct va_list_wrapper args;
- va_start(args, fmt);
- chars_written = vdlog(fmt, args);
- va_end(args);
+ va_start(args.va, fmt);
+ chars_written = vdlog(fmt, &args);
+ va_end(args.va);
return chars_written;
}