Merge pull request #1454 from harfbuzz/cff-fixbcd
[CFF] fix oss-fuzz issue 11674: parse_bcd
diff --git a/src/hb-cff-interp-dict-common.hh b/src/hb-cff-interp-dict-common.hh
index 2822af4..63ca685 100644
--- a/src/hb-cff-interp-dict-common.hh
+++ b/src/hb-cff-interp-dict-common.hh
@@ -28,6 +28,7 @@
#include "hb-cff-interp-common.hh"
#include <math.h>
+#include <float.h>
namespace CFF {
@@ -105,20 +106,21 @@
static inline double parse_bcd (SubByteStr& substr)
{
- double v = 0.0;
-
bool neg = false;
double int_part = 0;
- long frac_part = 0;
- unsigned int frac_count = 0;
+ uint64_t frac_part = 0;
+ uint32_t frac_count = 0;
bool exp_neg = false;
- unsigned int exp_part = 0;
+ uint32_t exp_part = 0;
+ bool exp_overflow = false;
enum Part { INT_PART=0, FRAC_PART, EXP_PART } part = INT_PART;
enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END };
+ const uint64_t MAX_FRACT = 0xFFFFFFFFFFFFFllu; /* 1^52-1 */
+ const uint32_t MAX_EXP = 0x7FFu; /* 1^11-1 */
double value = 0.0;
unsigned char byte = 0;
- for (unsigned int i = 0;; i++)
+ for (uint32_t i = 0;; i++)
{
char d;
if ((i & 1) == 0)
@@ -139,12 +141,25 @@
{
case RESERVED:
substr.set_error ();
- return v;
+ return value;
case END:
value = (double)(neg? -int_part: int_part);
if (frac_count > 0)
- value += (frac_part / pow (10.0, (double)frac_count));
+ {
+ double frac = (frac_part / pow (10.0, (double)frac_count));
+ if (neg) frac = -frac;
+ value += frac;
+ }
+ if (unlikely (exp_overflow))
+ {
+ if (value == 0.0)
+ return value;
+ if (exp_neg)
+ return neg? -DBL_MIN: DBL_MIN;
+ else
+ return neg? -DBL_MAX: DBL_MAX;
+ }
if (exp_part != 0)
{
if (exp_neg)
@@ -167,7 +182,7 @@
if (part != INT_PART)
{
substr.set_error ();
- return v;
+ return value;
}
part = FRAC_PART;
break;
@@ -180,7 +195,7 @@
if (part == EXP_PART)
{
substr.set_error ();
- return v;
+ return value;
}
part = EXP_PART;
break;
@@ -193,18 +208,26 @@
break;
case FRAC_PART:
- frac_part = (frac_part * 10) + d;
- frac_count++;
+ if (likely ((frac_part <= MAX_FRACT / 10)))
+ {
+ frac_part = (frac_part * 10) + (unsigned)d;
+ frac_count++;
+ }
break;
case EXP_PART:
- exp_part = (exp_part * 10) + d;
+ if (likely (exp_part * 10) + d <= MAX_EXP)
+ {
+ exp_part = (exp_part * 10) + d;
+ }
+ else
+ exp_overflow = true;
break;
}
}
}
- return v;
+ return value;
}
static inline bool is_hint_op (OpCode op)
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5672006905757696 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5672006905757696
new file mode 100644
index 0000000..cb5fb83
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5672006905757696
Binary files differ