diff options
author | Keith Derrick <keith.derrick@lge.com> | 2013-10-01 09:18:51 -0700 |
---|---|---|
committer | Keith Derrick <keith.derrick@lge.com> | 2013-10-01 10:17:00 -0700 |
commit | c51b88d69a3bb70f7bfed3f78a9283726cc827dd (patch) | |
tree | 963e005b1914e80dbe2391e6ff03e3f00b5b15d4 | |
parent | 06450206c4f3de4af8d81bb6d93e9db1d5fedec1 (diff) | |
download | json-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.c | 33 |
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; } |