Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion cJSON.c
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,17 @@ static void update_offset(printbuffer * const buffer)
/* securely comparison of floating-point variables */
static cJSON_bool compare_double(double a, double b)
{
double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
double maxVal = 0.0;

/* the epsilon-based comparison below breaks down for infinities: a - b
* and maxVal both come out as +/-infinity, so it can't tell +inf from
* -inf, or notice that two separately computed +inf values match */
if (isinf(a) || isinf(b))
{
return (a == b);
}

maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
return (fabs(a - b) <= maxVal * DBL_EPSILON);
}

Expand Down
20 changes: 19 additions & 1 deletion cJSON_Utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@

#include "cJSON_Utils.h"

/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
#ifndef isinf
#define isinf(d) (isnan((d - d)) && !isnan(d))
#endif
#ifndef isnan
#define isnan(d) (d != d)
#endif

/* define our own boolean type */
#ifdef true
#undef true
Expand Down Expand Up @@ -111,7 +119,17 @@ static int compare_strings(const unsigned char *string1, const unsigned char *st
/* securely comparison of floating-point variables */
static cJSON_bool compare_double(double a, double b)
{
double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
double maxVal = 0.0;

/* the epsilon-based comparison below breaks down for infinities: a - b
* and maxVal both come out as +/-infinity, so it can't tell +inf from
* -inf, or notice that two separately computed +inf values match */
if (isinf(a) || isinf(b))
{
return (a == b);
}

maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
return (fabs(a - b) <= maxVal * DBL_EPSILON);
}

Expand Down
31 changes: 31 additions & 0 deletions tests/compare_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
THE SOFTWARE.
*/

#include <math.h>

#include "unity/examples/unity_config.h"
#include "unity/src/unity.h"
#include "common.h"
Expand Down Expand Up @@ -189,13 +191,42 @@ static void cjson_compare_should_compare_objects(void)
false))
}

static void cjson_compare_should_compare_infinities_correctly(void)
{
/* JSON text has no way to spell an infinite number, so build these
* directly instead of going through compare_from_string. */
cJSON *positive_a = cJSON_CreateNumber(INFINITY);
cJSON *positive_b = cJSON_CreateNumber(INFINITY);
cJSON *negative_a = cJSON_CreateNumber(-INFINITY);
cJSON *negative_b = cJSON_CreateNumber(-INFINITY);

TEST_ASSERT_NOT_NULL(positive_a);
TEST_ASSERT_NOT_NULL(positive_b);
TEST_ASSERT_NOT_NULL(negative_a);
TEST_ASSERT_NOT_NULL(negative_b);

/* two separately created +Infinity values are equal to each other */
TEST_ASSERT_TRUE(cJSON_Compare(positive_a, positive_b, true));
/* two separately created -Infinity values are equal to each other */
TEST_ASSERT_TRUE(cJSON_Compare(negative_a, negative_b, true));
/* +Infinity and -Infinity are not equal */
TEST_ASSERT_FALSE(cJSON_Compare(positive_a, negative_a, true));
TEST_ASSERT_FALSE(cJSON_Compare(negative_a, positive_a, true));

cJSON_Delete(positive_a);
cJSON_Delete(positive_b);
cJSON_Delete(negative_a);
cJSON_Delete(negative_b);
}

int CJSON_CDECL main(void)
{
UNITY_BEGIN();

RUN_TEST(cjson_compare_should_compare_null_pointer_as_not_equal);
RUN_TEST(cjson_compare_should_compare_invalid_as_not_equal);
RUN_TEST(cjson_compare_should_compare_numbers);
RUN_TEST(cjson_compare_should_compare_infinities_correctly);
RUN_TEST(cjson_compare_should_compare_booleans);
RUN_TEST(cjson_compare_should_compare_null);
RUN_TEST(cjson_compare_should_not_accept_invalid_types);
Expand Down