Fix dehumanize_number() to correctly detect overflows Do not allow numbers greated than INT64_MAX and smaller than INT64_MIN. Clarify the positive sign value by prefixing it with an explicit +. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=66909
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
diff --git a/src/dehumanize_number.c b/src/dehumanize_number.c
index 640f1fb..632bf1d 100644
--- a/src/dehumanize_number.c
+++ b/src/dehumanize_number.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2012 Guillem Jover <guillem@hadrons.org>
+ * Copyright © 2012-2013 Guillem Jover <guillem@hadrons.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -35,8 +35,8 @@
int
dehumanize_number(const char *buf, int64_t *num)
{
- uint64_t rval;
- int sign = 1;
+ uint64_t rval, rmax;
+ int sign = +1;
int rc;
/* The current expand_number() implementation uses bit shifts, so
@@ -52,7 +52,13 @@ dehumanize_number(const char *buf, int64_t *num)
rc = expand_number(buf, &rval);
if (rc < 0)
return rc;
- if (rval == UINT64_MAX && sign == -1) {
+
+ /* The sign has been stripped, so rval has the absolute value.
+ * Error out, regardless of the sign, if rval is greater than
+ * abs(INT64_MIN) (== INT64_MAX + 1), or if the sign is positive
+ * and the value has overflown by one (INT64_MAX + 1). */
+ rmax = INT64_MAX + 1ULL;
+ if (rval > rmax || (rval == rmax && sign == +1)) {
errno = ERANGE;
return -1;
}
diff --git a/test/humanize.c b/test/humanize.c
index 0e8f0cf..59e4cde 100644
--- a/test/humanize.c
+++ b/test/humanize.c
@@ -25,6 +25,7 @@
*/
#include <assert.h>
+#include <errno.h>
#include <stdlib.h>
int
@@ -60,5 +61,17 @@ main(int argc, char **argv)
assert(dehumanize_number("-3G", &val) == 0);
assert(val == -3221225472LL);
+ assert(dehumanize_number("9223372036854775807", &val) == 0);
+ assert(val == INT64_MAX);
+
+ assert(dehumanize_number("9223372036854775808", &val) == -1);
+ assert(errno == ERANGE);
+
+ assert(dehumanize_number("-9223372036854775808", &val) == 0);
+ assert(val == INT64_MIN);
+
+ assert(dehumanize_number("-9223372036854775809", &val) == -1);
+ assert(errno == ERANGE);
+
return 0;
}