ref: 3923757ccbde3af0f253824bc9cf9a99127178fb
parent: 2af227c88bbcf8d6c52eb5b3b3a677d88a281774
author: qwx <qwx@sciops.net>
date: Mon Sep 29 06:21:01 EDT 2025
to_number: only reject trailing garbage when tp is nil, check return in lex fixes infinite loops when parsing invalid scripts like '.', '..', '.E.' also now correctly identifies this as a syntax error (T.misc)
--- a/lex.c
+++ b/lex.c
@@ -125,10 +125,12 @@
}
}
*bp = 0;
- to_number(buf, fp, &rem); /* parse the number */
+ if(to_number(buf, fp, &rem)) /* parse the number */
+ c = '0';
+ else
+ c = buf[0];
unputstr(rem); /* put rest back for later */
rem[0] = 0;
- c = '0';
}
*pbuf = buf;
*psz = sz;
--- a/lib.c
+++ b/lib.c
@@ -649,6 +649,8 @@
return 0;
else if (f == 0.0 && ((q = strchr(s, '0')) == nil || q > p))
return 0;
+ else if (tp != nil)
+ return 1;
for (; (c = *p) != '\0'; p++) { switch(c) {case ' ':
@@ -670,7 +672,7 @@
int to_number(char *s, Awkfloat *fp, char **tp)
{vlong v;
- char *p, *q;
+ char c, *p, *q;
v = strtoll(s, &p, 0);
*fp = (Awkfloat)v;
@@ -687,15 +689,15 @@
if (is_float(s, fp, tp))
return NUM;
return 0;
- case '\0':
- if (p == s)
- return 0;
- else if (v != 0 || (q = strchr(s, '0')) != nil && q < p)
- return NUM;
- break;
}
- for (;; p++) {- switch(*p) {+ if (p == s)
+ return 0;
+ else if (v == 0 && ((q = strchr(s, '0')) == nil || q > p))
+ return 0;
+ else if (tp != nil)
+ return NUM;
+ for (; (c = *p) != '\0'; p++) {+ switch(c) {case ' ':
case '\t':
case '\n':
@@ -709,4 +711,5 @@
return 0;
}
}
+ return NUM;
}
--- a/test/to_number.c
+++ b/test/to_number.c
@@ -9,12 +9,14 @@
FLT = 1<<1,
};
-static int is_float(char *s, Awkfloat *fp)
+static int is_float(char *s, Awkfloat *fp, char **tp)
{char c, *p, *q;
Awkfloat f;
f = *fp = strtod(s, &p);
+ if (tp != nil)
+ *tp = p;
if (p == s)
return 0;
else if (isInf(f, 1) || isInf(f, -1) || isNaN(f))
@@ -21,6 +23,8 @@
return 0;
else if (f == 0.0 && ((q = strchr(s, '0')) == nil || q > p))
return 0;
+ else if (tp != nil)
+ return 1;
for (; (c = *p) != '\0'; p++) { switch(c) {case ' ':
@@ -39,13 +43,15 @@
return 1;
}
-int to_number(char *s, Awkfloat *fp)
+int to_number(char *s, Awkfloat *fp, char **tp)
{vlong v;
- char *p, *q;
+ char c, *p, *q;
v = strtoll(s, &p, 0);
*fp = (Awkfloat)v;
+ if (tp != nil)
+ *tp = p;
switch(*p){case '.':
case 'E':
@@ -54,18 +60,18 @@
case 'e':
case 'i':
case 'n':
- if (is_float(s, fp))
+ if (is_float(s, fp, tp))
return NUM | FLT;
return 0;
- case '\0':
- if (p == s)
- return 0;
- else if (v != 0 || (q = strchr(s, '0')) != nil && q < p)
- return NUM;
- break;
}
- for (;; p++) {- switch(*p) {+ if (p == s)
+ return 0;
+ else if (v == 0 && ((q = strchr(s, '0')) == nil || q > p))
+ return 0;
+ else if (tp != nil)
+ return NUM;
+ for (; (c = *p) != '\0'; p++) {+ switch(c) {case ' ':
case '\t':
case '\n':
@@ -79,6 +85,7 @@
return 0;
}
}
+ return NUM;
}
void
@@ -87,32 +94,33 @@
int r;
Awkfloat f;
- r = to_number("3", &f); assert(r == NUM);- r = to_number(" 3", &f); assert(r == NUM);- r = to_number("3 ", &f); assert(r == NUM);- r = to_number(" 3 ", &f); assert(r == NUM);- r = to_number("3x", &f); assert(r == 0);- r = to_number(" 3x", &f); assert(r == 0);- r = to_number("3x ", &f); assert(r == 0);- r = to_number("3x tyu", &f); assert(r == 0);- r = to_number("3e1", &f); assert(r == (NUM | FLT));- r = to_number("3e", &f); assert(r == 0);- r = to_number("-3e", &f); assert(r == 0);- r = to_number(" -3e ", &f); assert(r == 0);- r = to_number("3.1", &f); assert(r == (NUM | FLT));- r = to_number(" 3.1", &f); assert(r == (NUM | FLT));- r = to_number("3.1 ", &f); assert(r == (NUM | FLT));- r = to_number(" 3.1 ", &f); assert(r == (NUM | FLT));- r = to_number("x ", &f); assert(r == 0);- r = to_number(".1 ", &f); assert(r == (NUM | FLT));- r = to_number("-1e4 ", &f); assert(r == (NUM | FLT));- r = to_number(".", &f); assert(r == 0);- r = to_number("", &f); assert(r == 0);- r = to_number("0", &f); assert(r == NUM);- r = to_number("0.", &f); assert(r == (NUM | FLT));- r = to_number("0.0", &f); assert(r == (NUM | FLT));- r = to_number("0e", &f); assert(r == 0);- r = to_number("nan", &f); assert(r == 0);- r = to_number("inf", &f); assert(r == 0);+ r = to_number("3", &f, nil); assert(r == NUM);+ r = to_number(" 3", &f, nil); assert(r == NUM);+ r = to_number("3 ", &f, nil); assert(r == NUM);+ r = to_number(" 3 ", &f, nil); assert(r == NUM);+ r = to_number("3x", &f, nil); assert(r == 0);+ r = to_number(" 3x", &f, nil); assert(r == 0);+ r = to_number("3x ", &f, nil); assert(r == 0);+ r = to_number("3x tyu", &f, nil); assert(r == 0);+ r = to_number("3e1", &f, nil); assert(r == (NUM | FLT));+ r = to_number("3e", &f, nil); assert(r == 0);+ r = to_number("-3e", &f, nil); assert(r == 0);+ r = to_number(" -3e ", &f, nil); assert(r == 0);+ r = to_number("3.1", &f, nil); assert(r == (NUM | FLT));+ r = to_number(" 3.1", &f, nil); assert(r == (NUM | FLT));+ r = to_number("3.1 ", &f, nil); assert(r == (NUM | FLT));+ r = to_number(" 3.1 ", &f, nil); assert(r == (NUM | FLT));+ r = to_number("x ", &f, nil); assert(r == 0);+ r = to_number(".1 ", &f, nil); assert(r == (NUM | FLT));+ r = to_number("-1e4 ", &f, nil); assert(r == (NUM | FLT));+ r = to_number(".", &f, nil); assert(r == 0);+ r = to_number("", &f, nil); assert(r == 0);+ r = to_number("0", &f, nil); assert(r == NUM);+ r = to_number("0.", &f, nil); assert(r == (NUM | FLT));+ r = to_number("0.0", &f, nil); assert(r == (NUM | FLT));+ r = to_number("0e", &f, nil); assert(r == 0);+ r = to_number("nan", &f, nil); assert(r == 0);+ r = to_number("inf", &f, nil); assert(r == 0);+ /* FIXME: more tests + testcases with tp != nil */
exits(nil);
}
--
⑨