summaryrefslogtreecommitdiffstats
path: root/libass
diff options
context:
space:
mode:
authorOleg Oshmyan <chortos@inbox.lv>2016-10-30 16:36:14 +0200
committerGrigori Goronzy <greg@chown.ath.cx>2016-11-21 11:05:34 +0100
commit86f65f88d805372fa53d64cb4d08e98180bd735f (patch)
tree4474e387b2d64ca4a308c695b03681e31eeeec06 /libass
parent858196e931e0076c61bc9c816b032a2f4991661c (diff)
downloadlibass-86f65f88d805372fa53d64cb4d08e98180bd735f.tar.bz2
libass-86f65f88d805372fa53d64cb4d08e98180bd735f.tar.xz
ass_strtod: handle overflowing exponents
The exponent may overflow an integer, e. g. in `14e888888888888888888888888888880000000000000000000000000000` on a 32-bit platform. Correctly handle this, including the case when the exponent overflows but the whole string still describes a valid floating-point number, e. g. in `1[4294967200 zeros]e-4294967300`. This fixes libass#244. Buffer overflow was fixed in 67f647e, and this ensures that the string is converted to the correct number.
Diffstat (limited to 'libass')
-rw-r--r--libass/ass_strtod.c44
1 files changed, 37 insertions, 7 deletions
diff --git a/libass/ass_strtod.c b/libass/ass_strtod.c
index 1b1a5c2..6d39899 100644
--- a/libass/ass_strtod.c
+++ b/libass/ass_strtod.c
@@ -1,6 +1,7 @@
/*
* Copyright (c) 1988-1993 The Regents of the University of California.
* Copyright (c) 1994 Sun Microsystems, Inc.
+ * Copyright (c) 2016 Oleg Oshmyan <chortos@inbox.lv>
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -78,7 +79,7 @@ ass_strtod(
* address here. */
)
{
- int sign, fracExpSign, expSign = 0;
+ int sign, fracExpSign, expSign;
double fraction, dblExp, *d;
register const char *p;
register int c;
@@ -206,6 +207,14 @@ ass_strtod(
p = pExp;
if ((*p == 'E') || (*p == 'e')) {
+ size_t expLimit; /* If exp > expLimit, appending another digit
+ * to exp is guaranteed to make it too large.
+ * If exp == expLimit, this may depend on
+ * the exact digit, but in any case exp with
+ * the digit appended and fracExp added will
+ * still fit in size_t, even if it does
+ * exceed maxExponent. */
+ int expWraparound = 0;
p += 1;
if (*p == '-') {
expSign = 1;
@@ -216,17 +225,37 @@ ass_strtod(
}
expSign = 0;
}
+ if (expSign == fracExpSign) {
+ if (maxExponent < fracExp) {
+ expLimit = 0;
+ } else {
+ expLimit = (maxExponent - fracExp) / 10;
+ }
+ } else {
+ expLimit = fracExp / 10 + (fracExp % 10 + maxExponent) / 10;
+ }
while (ass_isdigit(*p)) {
+ if ((exp > expLimit) || expWraparound) {
+ do {
+ p += 1;
+ } while (ass_isdigit(*p));
+ goto expOverflow;
+ } else if (exp > ((size_t) -1 - (*p - '0')) / 10) {
+ expWraparound = 1;
+ }
exp = exp * 10 + (*p - '0');
p += 1;
}
- }
- if (expSign == fracExpSign) {
- exp = fracExp + exp;
- } else if (fracExp <= exp) {
- exp = exp - fracExp;
+ if (expSign == fracExpSign) {
+ exp = fracExp + exp;
+ } else if ((fracExp <= exp) || expWraparound) {
+ exp = exp - fracExp;
+ } else {
+ exp = fracExp - exp;
+ expSign = fracExpSign;
+ }
} else {
- exp = fracExp - exp;
+ exp = fracExp;
expSign = fracExpSign;
}
@@ -238,6 +267,7 @@ ass_strtod(
*/
if (exp > maxExponent) {
+expOverflow:
exp = maxExponent;
if (fraction != 0.0) {
errno = ERANGE;