diff options
-rw-r--r-- | src/utils/utils.h | 35 | ||||
-rw-r--r-- | test/data/number/number.dat | 5 | ||||
-rw-r--r-- | test/number.c | 2 |
3 files changed, 29 insertions, 13 deletions
diff --git a/src/utils/utils.h b/src/utils/utils.h index 8100669..9c6b082 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -79,7 +79,7 @@ static inline fixed number_from_css_string(const css_string *string, if (ptr[0] < '0' || '9' < ptr[0]) break; - /* Clamp to a max of 2^22 - 1 */ + /* Prevent overflow of 'intpart'; proper clamping below */ if (intpart < (1 << 22)) { intpart *= 10; intpart += ptr[0] - '0'; @@ -113,16 +113,33 @@ static inline fixed number_from_css_string(const css_string *string, } } - /* If the intpart is larger than we can represent, - * then clamp to the maximum value we can store. */ - if (intpart >= (1 << 21)) { - fracpart = (1 << 10) - 1; - intpart = (1 << 21) - 1; - } - *consumed = ptr - string->data; - return FMULI(((intpart << 10) | fracpart), sign); + if (sign > 0) { + /* If the result is larger than we can represent, + * then clamp to the maximum value we can store. */ + if (intpart >= (1 << 21)) { + intpart = (1 << 21) - 1; + fracpart = (1 << 10) - 1; + } + } + else { + /* If the negated result is smaller than we can represent + * then clamp to the minimum value we can store. */ + if (intpart >= (1 << 21)) { + intpart = -(1 << 21); + fracpart = 0; + } + else { + intpart = -intpart; + if (fracpart) { + fracpart = (1 << 10) - fracpart; + intpart--; + } + } + } + + return (intpart << 10) | fracpart; } static inline bool isDigit(uint8_t c) diff --git a/test/data/number/number.dat b/test/data/number/number.dat index 1004f55..f2cc2f4 100644 --- a/test/data/number/number.dat +++ b/test/data/number/number.dat @@ -64,17 +64,16 @@ -2097151.000 #reset -# TODO: should these next two not result in INT_MIN? #data -2097152 #expected --2097151.999 +-2097152 #reset #data -2097153 #expected --2097151.999 +-2097152 #reset #data diff --git a/test/number.c b/test/number.c index 46b2fda..dd44730 100644 --- a/test/number.c +++ b/test/number.c @@ -127,7 +127,7 @@ void run_test(const uint8_t *data, size_t len, const char *exp, size_t explen) void print_fixed(char *buf, size_t len, fixed f) { -#define ABS(x) ((x) < 0 ? -(x) : (x)) +#define ABS(x) (uint32_t)((x) < 0 ? -(x) : (x)) uint32_t uintpart = FIXTOINT(ABS(f)); /* + 500 to ensure round to nearest (division will truncate) */ uint32_t fracpart = ((ABS(f) & 0x3ff) * 1000 + 500) / (1 << 10); |