summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Derrick <keith.derrick@lge.com>2013-10-01 09:18:51 -0700
committerKeith Derrick <keith.derrick@lge.com>2013-10-01 10:17:00 -0700
commitc51b88d69a3bb70f7bfed3f78a9283726cc827dd (patch)
tree963e005b1914e80dbe2391e6ff03e3f00b5b15d4
parent06450206c4f3de4af8d81bb6d93e9db1d5fedec1 (diff)
downloadjson-c-c51b88d69a3bb70f7bfed3f78a9283726cc827dd.tar.gz
Avoid potential overflow in json_object_get_double
sscanf is always a potential problem when converting numeric values as it does not correctly handle over- and underflow (or at least gives no indication that it has done so). This change converts json_object_get_double() to use strtod() according to CERT guidelines.
-rw-r--r--json_object.c33
1 files changed, 32 insertions, 1 deletions
diff --git a/json_object.c b/json_object.c
index faf6193..377ab59 100644
--- a/json_object.c
+++ b/json_object.c
@@ -17,6 +17,7 @@
#include <stddef.h>
#include <string.h>
#include <math.h>
+#include <errno.h>
#include "debug.h"
#include "printbuf.h"
@@ -636,6 +637,7 @@ void json_object_free_userdata(struct json_object *jso, void *userdata)
double json_object_get_double(struct json_object *jso)
{
double cdouble;
+ char *errPtr = NULL;
if(!jso) return 0.0;
switch(jso->o_type) {
@@ -646,7 +648,36 @@ double json_object_get_double(struct json_object *jso)
case json_type_boolean:
return jso->o.c_boolean;
case json_type_string:
- if(sscanf(jso->o.c_string.str, "%lf", &cdouble) == 1) return cdouble;
+ errno = 0;
+ cdouble = strtod(jso->o.c_string.str,&errPtr);
+
+ /* if conversion stopped at the first character, return 0.0 */
+ if (errPtr == jso->o.c_string.str)
+ return 0.0;
+
+ /*
+ * Check that the conversion terminated on something sensible
+ *
+ * For example, { "pay" : 123AB } would parse as 123.
+ */
+ if (*errPtr != '\0')
+ return 0.0;
+
+ /*
+ * If strtod encounters a string which would exceed the
+ * capacity of a double, it returns +/- HUGE_VAL and sets
+ * errno to ERANGE. But +/- HUGE_VAL is also a valid result
+ * from a conversion, so we need to check errno.
+ *
+ * Underflow also sets errno to ERANGE, but it returns 0 in
+ * that case, which is what we will return anyway.
+ *
+ * See CERT guideline ERR30-C
+ */
+ if ((HUGE_VAL == cdouble || -HUGE_VAL == cdouble) &&
+ (ERANGE == errno))
+ cdouble = 0.0;
+ return cdouble;
default:
return 0.0;
}