summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/utils/utils.h35
-rw-r--r--test/data/number/number.dat5
-rw-r--r--test/number.c2
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);