[PATCH] fix:awk: CONVFMT segfaults with %n, wrong output with %p

Hans Ulli Kroll via busybox <[email protected]> Tue, 5 May 2026 11:06:47 +0200
Newsgroups gmane.linux.busybox
Message-ID <[email protected]>
busybox awk segfaults with %n
 or %p conversion specifiers,
as reported on busybox ML

$ ./busybox awk 'BEGIN { CONVFMT="%nf"; x=3.14; print x "" }'
Segmentation fault

also busybox emits wrong output wth &p
$ ./busybox awk 'BEGIN { CONVFMT="%pf"; x=3.16; print x "" }'; echo $?
0x3f
0

same expression command for gnu awk
$ awk 'BEGIN { CONVFMT="%nf"; x=3.14; print x "" }'; echo $?
%nf
0
$ awk 'BEGIN { CONVFMT="%pf"; x=3.14; print x "" }'; echo $?
%pf
0

For both cases gnu awk logic in busybox awk.

bloatcheck oun x86_64

function                                             old     new   delta
fmt_num                                              246     273     +27
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 27/0)               Total: 27 bytes
   text	   data	    bss	    dec	    hex	filename
 892312	  13915	   1664	 907891	  dda73	busybox_old
 892339	  13915	   1664	 907918	  dda8e	busybox_unstripped

fmt_num                                              246     273     +27
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 27/0)               Total: 27 bytes
   text	   data	    bss	    dec	    hex	filename
 892844	  13923	   1664	 908431	  ddc8f	busybox_old
 892871	  13923	   1664	 908458	  ddcaa	busybox_unstripped

Signed-off-by: Hans Ulli Kroll <[email protected]>
---
 editors/awk.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/editors/awk.c b/editors/awk.c
index dd8f4ac420..b26793e792 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -969,7 +969,14 @@ static const char *fmt_num(const char *format, double n)
 		const char *s = format;
 		char c;
 
-		do { c = *s; } while (c && *++s);
+		do {
+			c = *s;
+			if (c == 'n' || c == 'p') {
+				puts(format);
+				exit(0);
+			}
+		} while (c && *++s);
+
 		if (strchr("diouxX", c)) {
 			snprintf(g_buf, MAXVARFMT, format, (int)n);
 		} else if (strchr("eEfFgGaA", c)) {
-- 
2.54.0