From: Linus Torvalds <torvalds@linux-foundation.org>
To: Alexei Starovoitov <alexei.starovoitov@gmail.com>,
Daniel Borkmann <daniel@iogearbox.net>,
Florent Revest <revest@google.com>,
Steven Rostedt <rostedt@goodmis.org>
Cc: LKML <linux-kernel@vger.kernel.org>, bpf <bpf@vger.kernel.org>,
Linus Torvalds <torvalds@linux-foundation.org>
Subject: [PATCH] vsprintf: simplify number handling
Date: Tue, 17 Dec 2024 17:32:09 -0800 [thread overview]
Message-ID: <20241218013620.1679088-1-torvalds@linux-foundation.org> (raw)
In-Reply-To: <CAHk-=whOM+D1D4wb5M_SGQeiDSQbmUTrpjghy2+ivo6s1aXwFQ@mail.gmail.com>
Instead of dealing with all the different special types (size_t,
unsigned char, ptrdiff_t..) just deal with the size of the integer type
and the sign.
This avoids a lot of unnecessary case statements, and the games we play
with the value of the 'SIGN' flags value
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
NOTE! Only very lightly tested. Also meant to be purely preparatory.
It might be broken.
I started doing this in the hope that the vsnprintf() core code could
maybe be further cleaned up enough that it would actually be something
we could use more generally and export to other users that want to
basically do the printk format handling.
The code is *not* there yet, though. Small steps.
lib/vsprintf.c | 139 +++++++++++++------------------------------------
1 file changed, 37 insertions(+), 102 deletions(-)
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 9d3dac38a3f4..ad57b43bb9ab 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -407,7 +407,7 @@ int num_to_str(char *buf, int size, unsigned long long num, unsigned int width)
return len + width;
}
-#define SIGN 1 /* unsigned/signed, must be 1 */
+#define SIGN 1 /* unsigned/signed */
#define LEFT 2 /* left justified */
#define PLUS 4 /* show plus */
#define SPACE 8 /* space if plus */
@@ -415,12 +415,15 @@ int num_to_str(char *buf, int size, unsigned long long num, unsigned int width)
#define SMALL 32 /* use lowercase in hex (must be 32 == 0x20) */
#define SPECIAL 64 /* prefix hex with "0x", octal with "0" */
-static_assert(SIGN == 1);
static_assert(ZEROPAD == ('0' - ' '));
static_assert(SMALL == ('a' ^ 'A'));
enum format_type {
FORMAT_TYPE_NONE, /* Just a string part */
+ FORMAT_TYPE_1BYTE = 1, /* char/short/int are their own sizes */
+ FORMAT_TYPE_2BYTE = 2,
+ FORMAT_TYPE_8BYTE = 3,
+ FORMAT_TYPE_4BYTE = 4,
FORMAT_TYPE_WIDTH,
FORMAT_TYPE_PRECISION,
FORMAT_TYPE_CHAR,
@@ -428,19 +431,10 @@ enum format_type {
FORMAT_TYPE_PTR,
FORMAT_TYPE_PERCENT_CHAR,
FORMAT_TYPE_INVALID,
- FORMAT_TYPE_LONG_LONG,
- FORMAT_TYPE_ULONG,
- FORMAT_TYPE_LONG,
- FORMAT_TYPE_UBYTE,
- FORMAT_TYPE_BYTE,
- FORMAT_TYPE_USHORT,
- FORMAT_TYPE_SHORT,
- FORMAT_TYPE_UINT,
- FORMAT_TYPE_INT,
- FORMAT_TYPE_SIZE_T,
- FORMAT_TYPE_PTRDIFF
};
+#define FORMAT_TYPE_SIZE(type) (sizeof(type) <= 4 ? sizeof(type) : FORMAT_TYPE_8BYTE)
+
struct printf_spec {
unsigned int type:8; /* format_type enum */
signed int field_width:24; /* width of output field */
@@ -2707,23 +2701,19 @@ int format_decode(const char *fmt, struct printf_spec *spec)
}
if (qualifier == 'L')
- spec->type = FORMAT_TYPE_LONG_LONG;
+ spec->type = FORMAT_TYPE_SIZE(long long);
else if (qualifier == 'l') {
- BUILD_BUG_ON(FORMAT_TYPE_ULONG + SIGN != FORMAT_TYPE_LONG);
- spec->type = FORMAT_TYPE_ULONG + (spec->flags & SIGN);
+ spec->type = FORMAT_TYPE_SIZE(long);
} else if (qualifier == 'z') {
- spec->type = FORMAT_TYPE_SIZE_T;
+ spec->type = FORMAT_TYPE_SIZE(size_t);
} else if (qualifier == 't') {
- spec->type = FORMAT_TYPE_PTRDIFF;
+ spec->type = FORMAT_TYPE_SIZE(ptrdiff_t);
} else if (qualifier == 'H') {
- BUILD_BUG_ON(FORMAT_TYPE_UBYTE + SIGN != FORMAT_TYPE_BYTE);
- spec->type = FORMAT_TYPE_UBYTE + (spec->flags & SIGN);
+ spec->type = FORMAT_TYPE_SIZE(char);
} else if (qualifier == 'h') {
- BUILD_BUG_ON(FORMAT_TYPE_USHORT + SIGN != FORMAT_TYPE_SHORT);
- spec->type = FORMAT_TYPE_USHORT + (spec->flags & SIGN);
+ spec->type = FORMAT_TYPE_SIZE(short);
} else {
- BUILD_BUG_ON(FORMAT_TYPE_UINT + SIGN != FORMAT_TYPE_INT);
- spec->type = FORMAT_TYPE_UINT + (spec->flags & SIGN);
+ spec->type = FORMAT_TYPE_SIZE(int);
}
return ++fmt - start;
@@ -2747,6 +2737,17 @@ set_precision(struct printf_spec *spec, int prec)
}
}
+/* Turn a 1/2/4-byte value into a 64-bit one with sign handling */
+static unsigned long long get_num(unsigned int val, struct printf_spec spec)
+{
+ unsigned int shift = 32 - spec.type*8;
+
+ val <<= shift;
+ if (!(spec.flags & SIGN))
+ return val >> shift;
+ return (int)val >> shift;
+}
+
/**
* vsnprintf - Format a string and place it in a buffer
* @buf: The buffer to place the result into
@@ -2873,43 +2874,10 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
goto out;
default:
- switch (spec.type) {
- case FORMAT_TYPE_LONG_LONG:
+ if (spec.type == FORMAT_TYPE_8BYTE)
num = va_arg(args, long long);
- break;
- case FORMAT_TYPE_ULONG:
- num = va_arg(args, unsigned long);
- break;
- case FORMAT_TYPE_LONG:
- num = va_arg(args, long);
- break;
- case FORMAT_TYPE_SIZE_T:
- if (spec.flags & SIGN)
- num = va_arg(args, ssize_t);
- else
- num = va_arg(args, size_t);
- break;
- case FORMAT_TYPE_PTRDIFF:
- num = va_arg(args, ptrdiff_t);
- break;
- case FORMAT_TYPE_UBYTE:
- num = (unsigned char) va_arg(args, int);
- break;
- case FORMAT_TYPE_BYTE:
- num = (signed char) va_arg(args, int);
- break;
- case FORMAT_TYPE_USHORT:
- num = (unsigned short) va_arg(args, int);
- break;
- case FORMAT_TYPE_SHORT:
- num = (short) va_arg(args, int);
- break;
- case FORMAT_TYPE_INT:
- num = (int) va_arg(args, int);
- break;
- default:
- num = va_arg(args, unsigned int);
- }
+ else
+ num = get_num(va_arg(args, int), spec);
str = number(str, end, num, spec);
}
@@ -3183,26 +3151,13 @@ int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args)
default:
switch (spec.type) {
-
- case FORMAT_TYPE_LONG_LONG:
+ case FORMAT_TYPE_8BYTE:
save_arg(long long);
break;
- case FORMAT_TYPE_ULONG:
- case FORMAT_TYPE_LONG:
- save_arg(unsigned long);
- break;
- case FORMAT_TYPE_SIZE_T:
- save_arg(size_t);
- break;
- case FORMAT_TYPE_PTRDIFF:
- save_arg(ptrdiff_t);
- break;
- case FORMAT_TYPE_UBYTE:
- case FORMAT_TYPE_BYTE:
+ case FORMAT_TYPE_1BYTE:
save_arg(char);
break;
- case FORMAT_TYPE_USHORT:
- case FORMAT_TYPE_SHORT:
+ case FORMAT_TYPE_2BYTE:
save_arg(short);
break;
default:
@@ -3375,37 +3330,17 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf)
unsigned long long num;
switch (spec.type) {
-
- case FORMAT_TYPE_LONG_LONG:
+ case FORMAT_TYPE_8BYTE:
num = get_arg(long long);
break;
- case FORMAT_TYPE_ULONG:
- case FORMAT_TYPE_LONG:
- num = get_arg(unsigned long);
+ case FORMAT_TYPE_2BYTE:
+ num = get_num(get_arg(short), spec);
break;
- case FORMAT_TYPE_SIZE_T:
- num = get_arg(size_t);
- break;
- case FORMAT_TYPE_PTRDIFF:
- num = get_arg(ptrdiff_t);
- break;
- case FORMAT_TYPE_UBYTE:
- num = get_arg(unsigned char);
- break;
- case FORMAT_TYPE_BYTE:
- num = get_arg(signed char);
- break;
- case FORMAT_TYPE_USHORT:
- num = get_arg(unsigned short);
- break;
- case FORMAT_TYPE_SHORT:
- num = get_arg(short);
- break;
- case FORMAT_TYPE_UINT:
- num = get_arg(unsigned int);
+ case FORMAT_TYPE_1BYTE:
+ num = get_num(get_arg(char), spec);
break;
default:
- num = get_arg(int);
+ num = get_num(get_arg(int), spec);
}
str = number(str, end, num, spec);
--
2.47.1.402.g41f6bc43b7
next prev parent reply other threads:[~2024-12-18 1:36 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20241217173237.836878448@goodmis.org>
[not found] ` <20241217173520.314190793@goodmis.org>
[not found] ` <CAHk-=wg5Kcr=sBuZcWs90CSGbJuKy0QsLaCC5oD15gS+Hk8j1A@mail.gmail.com>
[not found] ` <20241217130454.5bb593e8@gandalf.local.home>
[not found] ` <CAHk-=whLJW1SWvJTHYmdVAL2yL=dh4RzMuxgT7rnksSpkfUVaA@mail.gmail.com>
[not found] ` <20241217133318.06f849c9@gandalf.local.home>
[not found] ` <CAHk-=wgi1z85Cs4VmxTqFiG75qzoS_h_nszg6qP1ennEpdokkw@mail.gmail.com>
[not found] ` <20241217140153.22ac28b0@gandalf.local.home>
[not found] ` <CAHk-=wgpjLhSv9_rnAGS1adekEHMHbjVFvmZEuEmVftuo2sJBw@mail.gmail.com>
[not found] ` <20241217144411.2165f73b@gandalf.local.home>
[not found] ` <CAHk-=whWfmZbwRmySSpOyYEZJgcKG3d-qheYidnwu+b+rk6THg@mail.gmail.com>
[not found] ` <20241217175301.03d25799@gandalf.local.home>
[not found] ` <CAHk-=wg9x1Xt2cmiBbCz5XTppDQ=RNkjkmegwaF6=QghG6kBtA@mail.gmail.com>
2024-12-18 0:47 ` [PATCH 1/3] ring-buffer: Add uname to match criteria for persistent ring buffer Alexei Starovoitov
2024-12-18 1:26 ` Linus Torvalds
2024-12-18 1:32 ` Linus Torvalds [this message]
2024-12-18 9:19 ` [PATCH] vsprintf: simplify number handling Rasmus Villemoes
2024-12-18 15:32 ` Steven Rostedt
2024-12-18 17:32 ` Linus Torvalds
2024-12-18 18:04 ` Steven Rostedt
2024-12-18 18:31 ` Steven Rostedt
2024-12-23 20:11 ` Linus Torvalds
2024-12-18 1:39 ` [PATCH 1/3] ring-buffer: Add uname to match criteria for persistent ring buffer Linus Torvalds
2024-12-18 1:53 ` Alexei Starovoitov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241218013620.1679088-1-torvalds@linux-foundation.org \
--to=torvalds@linux-foundation.org \
--cc=alexei.starovoitov@gmail.com \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=linux-kernel@vger.kernel.org \
--cc=revest@google.com \
--cc=rostedt@goodmis.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox