lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20250902114837.274786-1-pablo@sifflez.org>
Date: Tue,  2 Sep 2025 13:48:37 +0200
From: Pablo de Oliveira Castro <pablo@...flez.org>
To: Peter Zijlstra <peterz@...radead.org>,
	Ingo Molnar <mingo@...hat.com>
Cc: Arnaldo Carvalho de Melo <acme@...nel.org>,
	Namhyung Kim <namhyung@...nel.org>,
	Mark Rutland <mark.rutland@....com>,
	Alexander Shishkin <alexander.shishkin@...ux.intel.com>,
	Jiri Olsa <jolsa@...nel.org>,
	Ian Rogers <irogers@...gle.com>,
	Adrian Hunter <adrian.hunter@...el.com>,
	Kan Liang <kan.liang@...ux.intel.com>,
	James Clark <james.clark@...aro.org>,
	Pablo de Oliveira Castro <pablo@...flez.org>,
	linux-perf-users@...r.kernel.org,
	linux-kernel@...r.kernel.org
Subject: [PATCH] perf stat: fix JSON output with non-C locales

When running `perf stat -j` under a locale that uses ',' as radix point
separator (e.g. LC_NUMERIC=fr_FR.UTF-8), the JSON output becomes
invalid. This is reproducible with perf test "perf stat JSON output
linter", which fails which such locales.

Example failure:

  $ LC_NUMERIC=fr_FR.UTF-8 perf test "JSON output" -v

  Checking json output: no args Test failed for input:

  {"counter-value" : "1,202545", "unit" : "msec", "event" :
   "task-clock", "event-runtime" : 1202545, "pcnt-running" : 100,00,
   "metric-value" : "0,473483", "metric-unit" : "CPUs utilized"}

  json.decoder.JSONDecodeError: Expecting property name enclosed in
  double quotes: line 2 column 121 (char 122)

Fix this by always using the POSIX numeric locale in json_out(),
ensuring that '.' is consistently used as the radix point in all JSON
numbers.

Signed-off-by: Pablo de Oliveira Castro <pablo@...flez.org>
---
 tools/perf/util/stat-display.c | 35 +++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c
index a67b991f4e81..ff8225e7435c 100644
--- a/tools/perf/util/stat-display.c
+++ b/tools/perf/util/stat-display.c
@@ -1,6 +1,8 @@
 #include <stdlib.h>
 #include <stdio.h>
+#include <stdarg.h>
 #include <inttypes.h>
+#include <locale.h>
 #include <linux/string.h>
 #include <linux/time64.h>
 #include <math.h>
@@ -149,7 +151,38 @@ static const char *json_sep(struct outstate *os)
 	return sep;
 }
 
-#define json_out(os, format, ...) fprintf((os)->fh, "%s" format, json_sep(os), ##__VA_ARGS__)
+/* Print formatted output using the POSIX numeric locale */
+static int clocale_fprintf(FILE *os, const char *fmt, ...)
+{
+	int ret;
+	va_list ap;
+
+	/* Create and temporarily switch to a POSIX numeric locale */
+	locale_t posix_numeric = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
+
+	if (posix_numeric) {
+		locale_t prev = uselocale(posix_numeric);
+
+		va_start(ap, fmt);
+		ret = vfprintf(os, fmt, ap);
+		va_end(ap);
+
+		/* restore previous locale */
+		uselocale(prev);
+		freelocale(posix_numeric);
+		return ret;
+	}
+
+	/* If newlocale() failed, just print with the current locale */
+	va_start(ap, fmt);
+	ret = vfprintf(os, fmt, ap);
+	va_end(ap);
+	return ret;
+}
+
+/* use clocale_fprintf so the radix point is always . as required by JSON */
+#define json_out(os, format, ...) \
+	clocale_fprintf((os)->fh, "%s" format, json_sep(os), ##__VA_ARGS__)
 
 static void print_running_json(struct outstate *os, u64 run, u64 ena)
 {
-- 
2.43.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ