|
@@ -389,6 +389,8 @@ struct printf_spec {
|
|
|
unsigned int base:8; /* number base, 8, 10 or 16 only */
|
|
|
signed int precision:16; /* # of digits/chars */
|
|
|
} __packed;
|
|
|
+#define FIELD_WIDTH_MAX ((1 << 23) - 1)
|
|
|
+#define PRECISION_MAX ((1 << 15) - 1)
|
|
|
|
|
|
static noinline_for_stack
|
|
|
char *number(char *buf, char *end, unsigned long long num,
|
|
@@ -1845,6 +1847,24 @@ qualifier:
|
|
|
return ++fmt - start;
|
|
|
}
|
|
|
|
|
|
+static void
|
|
|
+set_field_width(struct printf_spec *spec, int width)
|
|
|
+{
|
|
|
+ spec->field_width = width;
|
|
|
+ if (WARN_ONCE(spec->field_width != width, "field width %d too large", width)) {
|
|
|
+ spec->field_width = clamp(width, -FIELD_WIDTH_MAX, FIELD_WIDTH_MAX);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+set_precision(struct printf_spec *spec, int prec)
|
|
|
+{
|
|
|
+ spec->precision = prec;
|
|
|
+ if (WARN_ONCE(spec->precision != prec, "precision %d too large", prec)) {
|
|
|
+ spec->precision = clamp(prec, 0, PRECISION_MAX);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* vsnprintf - Format a string and place it in a buffer
|
|
|
* @buf: The buffer to place the result into
|
|
@@ -1912,11 +1932,11 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
|
|
|
}
|
|
|
|
|
|
case FORMAT_TYPE_WIDTH:
|
|
|
- spec.field_width = va_arg(args, int);
|
|
|
+ set_field_width(&spec, va_arg(args, int));
|
|
|
break;
|
|
|
|
|
|
case FORMAT_TYPE_PRECISION:
|
|
|
- spec.precision = va_arg(args, int);
|
|
|
+ set_precision(&spec, va_arg(args, int));
|
|
|
break;
|
|
|
|
|
|
case FORMAT_TYPE_CHAR: {
|
|
@@ -2356,11 +2376,11 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf)
|
|
|
}
|
|
|
|
|
|
case FORMAT_TYPE_WIDTH:
|
|
|
- spec.field_width = get_arg(int);
|
|
|
+ set_field_width(&spec, get_arg(int));
|
|
|
break;
|
|
|
|
|
|
case FORMAT_TYPE_PRECISION:
|
|
|
- spec.precision = get_arg(int);
|
|
|
+ set_precision(&spec, get_arg(int));
|
|
|
break;
|
|
|
|
|
|
case FORMAT_TYPE_CHAR: {
|