mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] lib/vsprintf: Preserve the sign of seconds in %ptSp
@ 2026-10-20 22:02 Hungyu Lin
  2026-10-21  9:22 ` Andy Shevchenko
  0 siblings, 1 reply; 2+ messages in thread
From: Hungyu Lin @ 2026-10-20 22:02 UTC (permalink / raw)
  To: pmladek, rostedt
  Cc: andriy.shevchenko, linux, senozhatsky, akpm, linux-kernel, Hungyu Lin

The documentation defines %ptSp as equivalent to %lld.%09ld, but
timespec64_str() formats tv_sec with default_dec_spec, which does not
have SIGN set. Negative seconds are therefore printed as unsigned
values: {-1, 0} produces "18446744073709551615.000000000" instead of
"-1.000000000".

Negative values can arise from time differences, for example in
fnic_get_stats_data() after the realtime clock steps backwards.

Use signed decimal formatting for the seconds and add printf KUnit
coverage for zero, negative seconds and the signed limits.

Fixes: bccd5937447f ("lib/vsprintf: Add specifier for printing struct timespec64")
Signed-off-by: Hungyu Lin <dennylin0707@gmail.com>
---
Tested with GCC 13.3.0 and W=1. The ARM64 printf KUnit suite, booted
in QEMU 10.2.1 with HVF, reports 27 pass / 1 fail before the fix and
28 pass / 0 fail afterwards. A 32-bit x86 build of lib/vsprintf.o and
lib/tests/printf_kunit.o also passes without warnings.

 lib/tests/printf_kunit.c | 15 +++++++++++++++
 lib/vsprintf.c           |  9 ++++++---
 2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/lib/tests/printf_kunit.c b/lib/tests/printf_kunit.c
index eccf041ebd56..3bd5115c2eab 100644
--- a/lib/tests/printf_kunit.c
+++ b/lib/tests/printf_kunit.c
@@ -572,6 +572,21 @@ time_and_date(struct kunit *kunittest)
 
 	test("2019-01-04T15:32:23.011235813", "%ptS", &ts);
 	test("1546615943.011235813", "%ptSp", &ts);
+
+	ts.tv_sec = 0;
+	ts.tv_nsec = 0;
+	test("0.000000000", "%ptSp", &ts);
+
+	ts.tv_sec = -1;
+	test("-1.000000000", "%ptSp", &ts);
+	test("1969-12-31T23:59:59.000000000", "%ptS", &ts);
+	ts.tv_nsec = 999999999;
+	test("-1.999999999", "%ptSp", &ts);
+
+	ts.tv_sec = S64_MIN;
+	test("-9223372036854775808.999999999", "%ptSp", &ts);
+	ts.tv_sec = S64_MAX;
+	test("9223372036854775807.999999999", "%ptSp", &ts);
 }
 
 static void
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 1d95ab9314bf..7c1964e7822e 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -1997,10 +1997,13 @@ char *timespec64_str(char *buf, char *end, const struct timespec64 *ts,
 		.flags = ZEROPAD,
 	};
 
-	if (fmt[2] == 'p')
-		buf = number(buf, end, ts->tv_sec, default_dec_spec);
-	else
+	if (fmt[2] == 'p') {
+		spec = default_dec_spec;
+		spec.flags |= SIGN;
+		buf = number(buf, end, ts->tv_sec, spec);
+	} else {
 		buf = time64_str(buf, end, ts->tv_sec, spec, fmt);
+	}
 	if (buf < end)
 		*buf = '.';
 	buf++;
-- 
2.43.0


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] lib/vsprintf: Preserve the sign of seconds in %ptSp
  2026-10-20 22:02 [PATCH] lib/vsprintf: Preserve the sign of seconds in %ptSp Hungyu Lin
@ 2026-10-21  9:22 ` Andy Shevchenko
  0 siblings, 0 replies; 2+ messages in thread
From: Andy Shevchenko @ 2026-10-21  9:22 UTC (permalink / raw)
  To: Hungyu Lin; +Cc: pmladek, rostedt, linux, senozhatsky, akpm, linux-kernel

On Tue, Oct 20, 2026 at 10:02:43PM +0000, Hungyu Lin wrote:
> The documentation defines %ptSp as equivalent to %lld.%09ld, but
> timespec64_str() formats tv_sec with default_dec_spec, which does not
> have SIGN set. Negative seconds are therefore printed as unsigned
> values: {-1, 0} produces "18446744073709551615.000000000" instead of
> "-1.000000000".
> 
> Negative values can arise from time differences, for example in
> fnic_get_stats_data() after the realtime clock steps backwards.
> 
> Use signed decimal formatting for the seconds and add printf KUnit
> coverage for zero, negative seconds and the signed limits.

Thanks for the report and the patch. My comment below.

...

> -	if (fmt[2] == 'p')
> -		buf = number(buf, end, ts->tv_sec, default_dec_spec);
> -	else
> +	if (fmt[2] == 'p') {
> +		spec = default_dec_spec;
> +		spec.flags |= SIGN;
> +		buf = number(buf, end, ts->tv_sec, spec);

Instead, add a new default_signed_dec_spec above and use it here.
While at it, make field_width to be explicitly -1, so

static const struct printf_spec default_signed_dec_spec = {
        .base = 10,
        .field_width = -1,
        .precision = -1,
	.flags = SIGN,
};

> +	} else {
>  		buf = time64_str(buf, end, ts->tv_sec, spec, fmt);
> +	}

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-21  9:22 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-20 22:02 [PATCH] lib/vsprintf: Preserve the sign of seconds in %ptSp Hungyu Lin
2026-10-21  9:22 ` Andy Shevchenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®