diff options
Diffstat (limited to 'lib/vsprintf.c')
-rw-r--r-- | lib/vsprintf.c | 82 |
1 files changed, 69 insertions, 13 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 2b18135446dc..8f56cdd52149 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -2517,29 +2517,34 @@ int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args) { struct printf_spec spec = {0}; char *str, *end; + int width; str = (char *)bin_buf; end = (char *)(bin_buf + size); #define save_arg(type) \ -do { \ +({ \ + unsigned long long value; \ if (sizeof(type) == 8) { \ - unsigned long long value; \ + unsigned long long val8; \ str = PTR_ALIGN(str, sizeof(u32)); \ - value = va_arg(args, unsigned long long); \ + val8 = va_arg(args, unsigned long long); \ if (str + sizeof(type) <= end) { \ - *(u32 *)str = *(u32 *)&value; \ - *(u32 *)(str + 4) = *((u32 *)&value + 1); \ + *(u32 *)str = *(u32 *)&val8; \ + *(u32 *)(str + 4) = *((u32 *)&val8 + 1); \ } \ + value = val8; \ } else { \ - unsigned long value; \ + unsigned int val4; \ str = PTR_ALIGN(str, sizeof(type)); \ - value = va_arg(args, int); \ + val4 = va_arg(args, int); \ if (str + sizeof(type) <= end) \ - *(typeof(type) *)str = (type)value; \ + *(typeof(type) *)str = (type)(long)val4; \ + value = (unsigned long long)val4; \ } \ str += sizeof(type); \ -} while (0) + value; \ +}) while (*fmt) { int read = format_decode(fmt, &spec); @@ -2555,7 +2560,10 @@ do { \ case FORMAT_TYPE_WIDTH: case FORMAT_TYPE_PRECISION: - save_arg(int); + width = (int)save_arg(int); + /* Pointers may require the width */ + if (*fmt == 'p') + set_field_width(&spec, width); break; case FORMAT_TYPE_CHAR: @@ -2577,7 +2585,27 @@ do { \ } case FORMAT_TYPE_PTR: - save_arg(void *); + /* Dereferenced pointers must be done now */ + switch (*fmt) { + /* Dereference of functions is still OK */ + case 'S': + case 's': + case 'F': + case 'f': + save_arg(void *); + break; + default: + if (!isalnum(*fmt)) { + save_arg(void *); + break; + } + str = pointer(fmt, str, end, va_arg(args, void *), + spec); + if (str + 1 < end) + *str++ = '\0'; + else + end[-1] = '\0'; /* Must be nul terminated */ + } /* skip all alphanumeric pointer suffixes */ while (isalnum(*fmt)) fmt++; @@ -2729,11 +2757,39 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf) break; } - case FORMAT_TYPE_PTR: - str = pointer(fmt, str, end, get_arg(void *), spec); + case FORMAT_TYPE_PTR: { + bool process = false; + int copy, len; + /* Non function dereferences were already done */ + switch (*fmt) { + case 'S': + case 's': + case 'F': + case 'f': + process = true; + break; + default: + if (!isalnum(*fmt)) { + process = true; + break; + } + /* Pointer dereference was already processed */ + if (str < end) { + len = copy = strlen(args); + if (copy > end - str) + copy = end - str; + memcpy(str, args, copy); + str += len; + args += len; + } + } + if (process) + str = pointer(fmt, str, end, get_arg(void *), spec); + while (isalnum(*fmt)) fmt++; break; + } case FORMAT_TYPE_PERCENT_CHAR: if (str < end) |