Merge pull request #1454 from harfbuzz/cff-fixbcd

[CFF] fix oss-fuzz issue 11674: parse_bcd
This commit is contained in:
Behdad Esfahbod 2018-12-05 15:39:34 -08:00 committed by GitHub
commit d9dabc00e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 14 deletions

View File

@ -28,6 +28,7 @@
#include "hb-cff-interp-common.hh" #include "hb-cff-interp-common.hh"
#include <math.h> #include <math.h>
#include <float.h>
namespace CFF { namespace CFF {
@ -105,20 +106,21 @@ struct DictOpSet : OpSet<Number>
static inline double parse_bcd (SubByteStr& substr) static inline double parse_bcd (SubByteStr& substr)
{ {
double v = 0.0;
bool neg = false; bool neg = false;
double int_part = 0; double int_part = 0;
long frac_part = 0; uint64_t frac_part = 0;
unsigned int frac_count = 0; uint32_t frac_count = 0;
bool exp_neg = false; 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 Part { INT_PART=0, FRAC_PART, EXP_PART } part = INT_PART;
enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END }; 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; double value = 0.0;
unsigned char byte = 0; unsigned char byte = 0;
for (unsigned int i = 0;; i++) for (uint32_t i = 0;; i++)
{ {
char d; char d;
if ((i & 1) == 0) if ((i & 1) == 0)
@ -139,12 +141,25 @@ struct DictOpSet : OpSet<Number>
{ {
case RESERVED: case RESERVED:
substr.set_error (); substr.set_error ();
return v; return value;
case END: case END:
value = (double)(neg? -int_part: int_part); value = (double)(neg? -int_part: int_part);
if (frac_count > 0) 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_part != 0)
{ {
if (exp_neg) if (exp_neg)
@ -167,7 +182,7 @@ struct DictOpSet : OpSet<Number>
if (part != INT_PART) if (part != INT_PART)
{ {
substr.set_error (); substr.set_error ();
return v; return value;
} }
part = FRAC_PART; part = FRAC_PART;
break; break;
@ -180,7 +195,7 @@ struct DictOpSet : OpSet<Number>
if (part == EXP_PART) if (part == EXP_PART)
{ {
substr.set_error (); substr.set_error ();
return v; return value;
} }
part = EXP_PART; part = EXP_PART;
break; break;
@ -193,18 +208,26 @@ struct DictOpSet : OpSet<Number>
break; break;
case FRAC_PART: case FRAC_PART:
frac_part = (frac_part * 10) + d; if (likely ((frac_part <= MAX_FRACT / 10)))
frac_count++; {
frac_part = (frac_part * 10) + (unsigned)d;
frac_count++;
}
break; break;
case EXP_PART: 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; break;
} }
} }
} }
return v; return value;
} }
static inline bool is_hint_op (OpCode op) static inline bool is_hint_op (OpCode op)