[git commit] awk: do not infinitely recurse getvar_s() if CONVFMT is set to a numeric value

Denys Vlasenko vda.linux at googlemail.com
Tue Jul 9 01:04:26 UTC 2024


commit: https://git.busybox.net/busybox/commit/?id=49340d93edc778b193cb40b59cf94dbe38650013
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
fmt_num                                              247     257     +10
evaluate                                            3385    3379      -6
getvar_s                                             111     102      -9
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/2 up/down: 10/-15)             Total: -5 bytes

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 editors/awk.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/editors/awk.c b/editors/awk.c
index ff6d6350b..8bc214b69 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -532,6 +532,7 @@ static const char vValues[] ALIGN1 =
 	"%.6g\0"    "%.6g\0"    " \0"       " \0"
 	"\n\0"      "\n\0"      "\0"        "\0"
 	"\034\0"    "\0"        "\377";
+#define str_percent_dot_6g vValues
 
 /* hash size may grow to these values */
 #define FIRST_PRIME 61
@@ -922,7 +923,7 @@ static double my_strtod_or_hexoct(char **pp)
 
 /* -------- working with variables (set/get/copy/etc) -------- */
 
-static void fmt_num(const char *format, double n)
+static const char *fmt_num(const char *format, double n)
 {
 	if (n == (long long)n) {
 		snprintf(g_buf, MAXVARFMT, "%lld", (long long)n);
@@ -939,6 +940,7 @@ static void fmt_num(const char *format, double n)
 			syntax_error(EMSG_INV_FMT);
 		}
 	}
+	return g_buf;
 }
 
 static xhash *iamarray(var *a)
@@ -1025,8 +1027,15 @@ static const char *getvar_s(var *v)
 {
 	/* if v is numeric and has no cached string, convert it to string */
 	if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
-		fmt_num(getvar_s(intvar[CONVFMT]), v->number);
-		v->string = xstrdup(g_buf);
+		const char *convfmt = str_percent_dot_6g; /* "%.6g" */
+		/* Get CONVFMT, unless we already recursed on it:
+		 * someone might try to cause stack overflow by setting
+		 * CONVFMT=9 (a numeric, not string, value)
+		 */
+		if (v != intvar[CONVFMT])
+			convfmt = getvar_s(intvar[CONVFMT]);
+		/* Convert the value */
+		v->string = xstrdup(fmt_num(convfmt, v->number));
 		v->type |= VF_CACHED;
 	}
 	return (v->string == NULL) ? "" : v->string;
@@ -3097,9 +3106,8 @@ static var *evaluate(node *op, var *res)
 					for (;;) {
 						var *v = evaluate(nextarg(&op1), TMPVAR0);
 						if (v->type & VF_NUMBER) {
-							fmt_num(getvar_s(intvar[OFMT]),
-									getvar_i(v));
-							fputs(g_buf, F);
+							fputs(fmt_num(getvar_s(intvar[OFMT]), getvar_i(v)),
+								F);
 						} else {
 							fputs(getvar_s(v), F);
 						}


More information about the busybox-cvs mailing list