[number] Add overflow checks used to be done in parse_bcd
Which were removed in 1083df8
diff --git a/src/hb-number-parser.hh b/src/hb-number-parser.hh
index b666d00..49ade7a 100644
--- a/src/hb-number-parser.hh
+++ b/src/hb-number-parser.hh
@@ -30,8 +30,10 @@
#include "hb.hh"
+#include <float.h>
-#line 35 "hb-number-parser.hh"
+
+#line 37 "hb-number-parser.hh"
static const unsigned char _double_parser_trans_keys[] = {
0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u,
46u, 101u, 0
@@ -91,7 +93,7 @@
static const int double_parser_en_main = 1;
-#line 55 "hb-number-parser.rl"
+#line 70 "hb-number-parser.rl"
constexpr double _pow2 (double x) { return x * x; }
@@ -130,7 +132,9 @@
double frac = 0;
double frac_count = 0;
unsigned int exp = 0;
- bool neg = false, exp_neg = false;
+ bool neg = false, exp_neg = false, exp_overflow = false;
+ const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 1^52-1 */
+ const unsigned int MAX_EXP = 0x7FFu; /* 1^11-1 */
p = buf;
pe = p + strlen (p);
@@ -139,12 +143,12 @@
int cs;
-#line 143 "hb-number-parser.hh"
+#line 147 "hb-number-parser.hh"
{
cs = double_parser_start;
}
-#line 148 "hb-number-parser.hh"
+#line 152 "hb-number-parser.hh"
{
int _slen;
int _trans;
@@ -170,26 +174,39 @@
switch ( _double_parser_trans_actions[_trans] ) {
case 1:
-#line 37 "hb-number-parser.rl"
+#line 39 "hb-number-parser.rl"
{ neg = true; }
break;
case 4:
-#line 38 "hb-number-parser.rl"
+#line 40 "hb-number-parser.rl"
{ exp_neg = true; }
break;
case 2:
-#line 40 "hb-number-parser.rl"
- { value = value * 10. + ((*p) - '0'); }
+#line 42 "hb-number-parser.rl"
+ {
+ value = value * 10. + ((*p) - '0');
+}
break;
case 3:
-#line 41 "hb-number-parser.rl"
- { frac = frac * 10. + ((*p) - '0'); ++frac_count; }
+#line 45 "hb-number-parser.rl"
+ {
+ if (likely (frac <= MAX_FRACT / 10))
+ {
+ frac = frac * 10. + ((*p) - '0');
+ ++frac_count;
+ }
+}
break;
case 5:
-#line 42 "hb-number-parser.rl"
- { exp = exp * 10 + ((*p) - '0'); }
+#line 52 "hb-number-parser.rl"
+ {
+ if (likely (exp * 10 + ((*p) - '0') <= MAX_EXP))
+ exp = exp * 10 + ((*p) - '0');
+ else
+ exp_overflow = true;
+}
break;
-#line 193 "hb-number-parser.hh"
+#line 210 "hb-number-parser.hh"
}
_again:
@@ -201,7 +218,7 @@
_out: {}
}
-#line 104 "hb-number-parser.rl"
+#line 121 "hb-number-parser.rl"
*end_ptr = (char *) p;
@@ -209,12 +226,17 @@
if (frac_count) value += frac / _pow10 (frac_count);
if (neg) value *= -1.;
+ if (unlikely (exp_overflow))
+ {
+ if (value == 0) return value;
+ if (exp_neg) return neg ? -DBL_MIN : DBL_MIN;
+ else return neg ? -DBL_MAX : DBL_MAX;
+ }
+
if (exp)
{
- if (exp_neg)
- value /= _pow10 (exp);
- else
- value *= _pow10 (exp);
+ if (exp_neg) value /= _pow10 (exp);
+ else value *= _pow10 (exp);
}
return value;
diff --git a/src/hb-number-parser.rl b/src/hb-number-parser.rl
index 6f08306..db7b2cc 100644
--- a/src/hb-number-parser.rl
+++ b/src/hb-number-parser.rl
@@ -28,6 +28,8 @@
#include "hb.hh"
+#include <float.h>
+
%%{
machine double_parser;
@@ -37,9 +39,22 @@
action see_neg { neg = true; }
action see_exp_neg { exp_neg = true; }
-action add_int { value = value * 10. + (fc - '0'); }
-action add_frac { frac = frac * 10. + (fc - '0'); ++frac_count; }
-action add_exp { exp = exp * 10 + (fc - '0'); }
+action add_int {
+ value = value * 10. + (fc - '0');
+}
+action add_frac {
+ if (likely (frac <= MAX_FRACT / 10))
+ {
+ frac = frac * 10. + (fc - '0');
+ ++frac_count;
+ }
+}
+action add_exp {
+ if (likely (exp * 10 + (fc - '0') <= MAX_EXP))
+ exp = exp * 10 + (fc - '0');
+ else
+ exp_overflow = true;
+}
num = [0-9]+;
@@ -90,7 +105,9 @@
double frac = 0;
double frac_count = 0;
unsigned int exp = 0;
- bool neg = false, exp_neg = false;
+ bool neg = false, exp_neg = false, exp_overflow = false;
+ const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 1^52-1 */
+ const unsigned int MAX_EXP = 0x7FFu; /* 1^11-1 */
p = buf;
pe = p + strlen (p);
@@ -108,12 +125,17 @@
if (frac_count) value += frac / _pow10 (frac_count);
if (neg) value *= -1.;
+ if (unlikely (exp_overflow))
+ {
+ if (value == 0) return value;
+ if (exp_neg) return neg ? -DBL_MIN : DBL_MIN;
+ else return neg ? -DBL_MAX : DBL_MAX;
+ }
+
if (exp)
{
- if (exp_neg)
- value /= _pow10 (exp);
- else
- value *= _pow10 (exp);
+ if (exp_neg) value /= _pow10 (exp);
+ else value *= _pow10 (exp);
}
return value;