Browse Source

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.
tags/json-c-0.12-20140410
Keith Derrick 12 years ago
parent
commit
c51b88d69a
1 changed files with 32 additions and 1 deletions
  1. +32
    -1
      json_object.c

+ 32
- 1
json_object.c View File

@@ -17,6 +17,7 @@
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include <errno.h>


#include "debug.h" #include "debug.h"
#include "printbuf.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 json_object_get_double(struct json_object *jso)
{ {
double cdouble; double cdouble;
char *errPtr = NULL;


if(!jso) return 0.0; if(!jso) return 0.0;
switch(jso->o_type) { switch(jso->o_type) {
@@ -646,7 +648,36 @@ double json_object_get_double(struct json_object *jso)
case json_type_boolean: case json_type_boolean:
return jso->o.c_boolean; return jso->o.c_boolean;
case json_type_string: 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: default:
return 0.0; return 0.0;
} }


Loading…
Cancel
Save