From 042ddecb5d6f09c8cf89cd3d96d7bb649d02e8ef Mon Sep 17 00:00:00 2001 From: Chris Desjardins Date: Fri, 25 Nov 2022 10:15:48 +0100 Subject: [PATCH 1/4] Get the test suite to build --- tests/src/test.c | 170 +++++++++++++++++++++++++---------------------- 1 file changed, 92 insertions(+), 78 deletions(-) diff --git a/tests/src/test.c b/tests/src/test.c index a8f0bac..43c6840 100644 --- a/tests/src/test.c +++ b/tests/src/test.c @@ -68,10 +68,11 @@ static int test_suit( struct test const* tests, int numtests ) { static int escape( void ) { char buff[512]; - char* p = json_objOpen( buff, NULL ); - p = json_str( p, "name", "\tHello: \"man\"\n" ); - p = json_objClose( p ); - p = json_end( p ); + size_t remLen = sizeof(buff); + char* p = json_objOpen( buff, NULL, &remLen ); + p = json_str( p, "name", "\tHello: \"man\"\n", &remLen ); + p = json_objClose( p, &remLen ); + p = json_end( p, &remLen ); printf( "\n\n%s\n\n", buff ); static char const rslt[] = "{\"name\":\"\\tHello: \\\"man\\\"\\n\"}"; check( p - buff == sizeof rslt - 1 ); @@ -81,10 +82,11 @@ static int escape( void ) { static int len( void ) { char buff[512]; - char* p = json_objOpen( buff, NULL ); - p = json_nstr( p, "name", "\tHello: \"man\"\n", 6 ); - p = json_objClose( p ); - p = json_end( p ); + size_t remLen = sizeof(buff); + char* p = json_objOpen( buff, NULL, &remLen ); + p = json_nstr( p, "name", "\tHello: \"man\"\n", 6, &remLen ); + p = json_objClose( p, &remLen ); + p = json_end( p, &remLen ); static char const rslt[] = "{\"name\":\"\\tHello\"}"; check( p - buff == sizeof rslt - 1 ); check( 0 == strcmp( buff, rslt ) ); @@ -94,33 +96,36 @@ static int len( void ) { static int empty( void ) { char buff[512]; { - char* p = json_objOpen( buff, NULL ); - p = json_objClose( p ); - p = json_end( p ); + size_t remLen = sizeof(buff); + char* p = json_objOpen( buff, NULL, &remLen ); + p = json_objClose( p, &remLen ); + p = json_end( p, &remLen ); static char const rslt[] = "{}"; check( p - buff == sizeof rslt - 1 ); check( 0 == strcmp( buff, rslt ) ); } { - char* p = json_objOpen( buff, NULL ); - p = json_arrOpen( p, "a" ); - p = json_arrClose( p ); - p = json_objClose( p ); - p = json_end( p ); + size_t remLen = sizeof(buff); + char* p = json_objOpen( buff, NULL, &remLen ); + p = json_arrOpen( p, "a", &remLen ); + p = json_arrClose( p, &remLen ); + p = json_objClose( p, &remLen ); + p = json_end( p, &remLen ); static char const rslt[] = "{\"a\":[]}"; check( p - buff == sizeof rslt - 1 ); check( 0 == strcmp( buff, rslt ) ); } { - char* p = json_objOpen( buff, NULL ); - p = json_arrOpen( p, "a" ); - p = json_objOpen( p, NULL ); - p = json_objClose( p ); - p = json_objOpen( p, NULL ); - p = json_objClose( p ); - p = json_arrClose( p ); - p = json_objClose( p ); - p = json_end( p ); + size_t remLen = sizeof(buff); + char* p = json_objOpen( buff, NULL, &remLen ); + p = json_arrOpen( p, "a", &remLen ); + p = json_objOpen( p, NULL, &remLen ); + p = json_objClose( p, &remLen ); + p = json_objOpen( p, NULL, &remLen ); + p = json_objClose( p, &remLen ); + p = json_arrClose( p, &remLen ); + p = json_objClose( p, &remLen ); + p = json_end( p, &remLen ); static char const rslt[] = "{\"a\":[{},{}]}"; check( p - buff == sizeof rslt - 1 ); check( 0 == strcmp( buff, rslt ) ); @@ -135,14 +140,15 @@ static int empty( void ) { static int primitive( void ) { char buff[512]; - char* p = json_objOpen( buff, NULL ); - p = json_verylong( p, "max", LONG_LONG_MAX ); - p = json_verylong( p, "min", LONG_LONG_MIN ); - p = json_bool( p, "boolvar0", 0 ); - p = json_bool( p, "boolvar1", 1 ); - p = json_null( p, "nullvar" ); - p = json_objClose( p ); - p = json_end( p ); + size_t remLen = sizeof(buff); + char* p = json_objOpen( buff, NULL, &remLen ); + p = json_verylong( p, "max", LONG_LONG_MAX, &remLen ); + p = json_verylong( p, "min", LONG_LONG_MIN, &remLen ); + p = json_bool( p, "boolvar0", 0, &remLen ); + p = json_bool( p, "boolvar1", 1, &remLen ); + p = json_null( p, "nullvar", &remLen ); + p = json_objClose( p, &remLen ); + p = json_end( p, &remLen ); static char const rslt[] = "{" "\"max\":9223372036854775807," "\"min\":-9223372036854775808," @@ -158,74 +164,80 @@ static int primitive( void ) { static int integers( void ) { { char buff[64]; - char* p = json_objOpen( buff, NULL ); - p = json_int( p, "a", 0 ); - p = json_int( p, "b", 1 ); - p = json_objClose( p ); - p = json_end( p ); + size_t remLen = sizeof( buff ); + char* p = json_objOpen( buff, NULL, &remLen ); + p = json_int( p, "a", 0, &remLen ); + p = json_int( p, "b", 1, &remLen ); + p = json_objClose( p, &remLen ); + p = json_end( p, &remLen ); static char const rslt[] = "{\"a\":0,\"b\":1}"; check( p - buff == sizeof rslt - 1 ); check( 0 == strcmp( buff, rslt ) ); } { char buff[64]; - char* p = json_objOpen( buff, NULL ); - p = json_int( p, "max", INT_MAX ); - p = json_int( p, "min", INT_MIN ); - p = json_objClose( p ); - p = json_end( p ); + size_t remLen = sizeof( buff ); + char* p = json_objOpen( buff, NULL, &remLen ); + p = json_int( p, "max", INT_MAX, &remLen ); + p = json_int( p, "min", INT_MIN, &remLen ); + p = json_objClose( p, &remLen ); + p = json_end( p, &remLen ); char rslt[ sizeof buff ]; - int len = sprintf( rslt, "{\"max\":%d,\"min\":%d}", INT_MAX, INT_MIN ); + int len = snprintf( rslt, sizeof( rslt ), "{\"max\":%d,\"min\":%d}", INT_MAX, INT_MIN); check( len < sizeof buff ); check( p - buff == len ); check( 0 == strcmp( buff, rslt ) ); } { char buff[64]; - char* p = json_objOpen( buff, NULL ); - p = json_uint( p, "max", UINT_MAX ); - p = json_objClose( p ); - p = json_end( p ); + size_t remLen = sizeof( buff ); + char* p = json_objOpen( buff, NULL, &remLen ); + p = json_uint( p, "max", UINT_MAX, &remLen ); + p = json_objClose( p, &remLen ); + p = json_end( p, &remLen ); char rslt[ sizeof buff ]; - int len = sprintf( rslt, "{\"max\":%u}", UINT_MAX ); + int len = snprintf( rslt, sizeof( rslt ), "{\"max\":%u}", UINT_MAX); check( len < sizeof buff ); check( p - buff == len ); check( 0 == strcmp( buff, rslt ) ); } { char buff[64]; - char* p = json_objOpen( buff, NULL ); - p = json_long( p, "max", LONG_MAX ); - p = json_long( p, "min", LONG_MIN ); - p = json_objClose( p ); - p = json_end( p ); + size_t remLen = sizeof( buff ); + char* p = json_objOpen( buff, NULL, &remLen ); + p = json_long( p, "max", LONG_MAX, &remLen ); + p = json_long( p, "min", LONG_MIN, &remLen ); + p = json_objClose( p, &remLen ); + p = json_end( p, &remLen ); char rslt[ sizeof buff ]; - int len = sprintf( rslt, "{\"max\":%ld,\"min\":%ld}", LONG_MAX, LONG_MIN ); + int len = snprintf( rslt, sizeof( rslt ), "{\"max\":%ld,\"min\":%ld}", LONG_MAX, LONG_MIN ); check( len < sizeof buff ); check( p - buff == len ); check( 0 == strcmp( buff, rslt ) ); } { char buff[64]; - char* p = json_objOpen( buff, NULL ); - p = json_ulong( p, "max", ULONG_MAX ); - p = json_objClose( p ); - p = json_end( p ); + size_t remLen = sizeof( buff ); + char* p = json_objOpen( buff, NULL, &remLen ); + p = json_ulong( p, "max", ULONG_MAX, &remLen ); + p = json_objClose( p, &remLen ); + p = json_end( p, &remLen ); char rslt[ sizeof buff ]; - int len = sprintf( rslt, "{\"max\":%lu}", ULONG_MAX ); + int len = snprintf( rslt, sizeof( rslt ), "{\"max\":%lu}", ULONG_MAX ); check( len < sizeof buff ); check( p - buff == len ); check( 0 == strcmp( buff, rslt ) ); } { char buff[64]; - char* p = json_objOpen( buff, NULL ); - p = json_verylong( p, "max", LONG_LONG_MAX ); - p = json_verylong( p, "min", LONG_LONG_MIN ); - p = json_objClose( p ); - p = json_end( p ); + size_t remLen = sizeof( buff ); + char* p = json_objOpen( buff, NULL, &remLen ); + p = json_verylong( p, "max", LONG_LONG_MAX, &remLen ); + p = json_verylong( p, "min", LONG_LONG_MIN, &remLen ); + p = json_objClose( p, &remLen ); + p = json_end( p, &remLen ); char rslt[ sizeof buff ]; - int len = sprintf( rslt, "{\"max\":%lld,\"min\":%lld}", LONG_LONG_MAX, LONG_LONG_MIN ); + int len = snprintf( rslt, sizeof( rslt ), "{\"max\":%lld,\"min\":%lld}", LONG_LONG_MAX, LONG_LONG_MIN ); check( len < sizeof buff ); check( p - buff == len ); check( 0 == strcmp( buff, rslt ) ); @@ -235,13 +247,14 @@ static int integers( void ) { static int array( void ) { char buff[64]; - char* p = json_objOpen( buff, NULL ); - p = json_arrOpen( p, "a" ); + size_t remLen = sizeof( buff ); + char* p = json_objOpen( buff, NULL, &remLen ); + p = json_arrOpen( p, "a", &remLen ); for( int i = 0; i < 4; ++i ) - p = json_int( p, NULL, i ); - p = json_arrClose( p ); - p = json_objClose( p ); - p = json_end( p ); + p = json_int( p, NULL, i, &remLen ); + p = json_arrClose( p, &remLen ); + p = json_objClose( p, &remLen ); + p = json_end( p, &remLen ); static char const rslt[] = "{\"a\":[0,1,2,3]}"; check( p - buff == sizeof rslt - 1 ); check( 0 == strcmp( buff, rslt ) ); @@ -250,14 +263,15 @@ static int array( void ) { static int real( void ) { char buff[64]; - char* p = json_objOpen( buff, NULL ); - p = json_arrOpen( p, "data" ); + size_t remLen = sizeof( buff ); + char* p = json_objOpen( buff, NULL, &remLen ); + p = json_arrOpen( p, "data", &remLen ); static double const lut[] = { 0.2, 2e-6, 5e6 }; for( int i = 0; i < sizeof lut / sizeof *lut; ++i ) - p = json_double( p, NULL, lut[i] ); - p = json_arrClose( p ); - p = json_objClose( p ); - p = json_end( p ); + p = json_double( p, NULL, lut[i], &remLen ); + p = json_arrClose( p, &remLen ); + p = json_objClose( p, &remLen ); + p = json_end( p, &remLen ); #ifdef NO_SPRINTF static char const rslt1[] = "{\"data\":[0,0,5000000]}"; static char const rslt2[] = "{\"data\":[0,0,5000000]}"; From cf2646ea599fb9aced6cd02de465026522262303 Mon Sep 17 00:00:00 2001 From: Chris Desjardins Date: Fri, 25 Nov 2022 10:23:41 +0100 Subject: [PATCH 2/4] Get the sample to build again as well --- samples/src/example.c | 57 ++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/samples/src/example.c b/samples/src/example.c index da00594..69aab21 100644 --- a/samples/src/example.c +++ b/samples/src/example.c @@ -51,45 +51,45 @@ struct data { /* Add a time object property in a JSON string. "name":{"temp":-5,"hum":48}, */ -char* json_weather( char* dest, char const* name, struct weather const* weather ) { - dest = json_objOpen( dest, name ); // --> "name":{\0 - dest = json_int( dest, "temp", weather->temp ); // --> "name":{"temp":22,\0 - dest = json_int( dest, "hum", weather->hum ); // --> "name":{"temp":22,"hum":45,\0 - dest = json_objClose( dest ); // --> "name":{"temp":22,"hum":45},\0 +char* json_weather( char* dest, char const* name, struct weather const* weather, size_t* remLen ) { + dest = json_objOpen( dest, name, remLen ); // --> "name":{\0 + dest = json_int( dest, "temp", weather->temp, remLen ); // --> "name":{"temp":22,\0 + dest = json_int( dest, "hum", weather->hum, remLen ); // --> "name":{"temp":22,"hum":45,\0 + dest = json_objClose( dest, remLen ); // --> "name":{"temp":22,"hum":45},\0 return dest; } /* Add a time object property in a JSON string. "name":{"hour":18,"minute":32}, */ -char* json_time( char* dest, char const* name, struct time const* time ) { - dest = json_objOpen( dest, name ); - dest = json_int( dest, "hour", time->hour ); - dest = json_int( dest, "minute", time->minute ); - dest = json_objClose( dest ); +char* json_time( char* dest, char const* name, struct time const* time, size_t* remLen ) { + dest = json_objOpen( dest, name, remLen ); + dest = json_int( dest, "hour", time->hour, remLen ); + dest = json_int( dest, "minute", time->minute, remLen ); + dest = json_objClose( dest, remLen ); return dest; } /* Add a measure object property in a JSON string. "name":{"weather":{"temp":-5,"hum":48},"time":{"hour":18,"minute":32}}, */ -char* json_measure( char* dest, char const* name, struct measure const* measure ) { - dest = json_objOpen( dest, name ); - dest = json_weather( dest, "weather", &measure->weather ); - dest = json_time( dest, "time", &measure->time ); - dest = json_objClose( dest ); +char* json_measure( char* dest, char const* name, struct measure const* measure, size_t* remLen ) { + dest = json_objOpen( dest, name, remLen ); + dest = json_weather( dest, "weather", &measure->weather, remLen ); + dest = json_time( dest, "time", &measure->time, remLen ); + dest = json_objClose( dest, remLen ); return dest; } /* Add a data object property in a JSON string. */ -char* json_data( char* dest, char const* name, struct data const* data ) { - dest = json_objOpen( dest, NULL ); - dest = json_str( dest, "city", data->city ); - dest = json_str( dest, "street", data->street ); - dest = json_measure( dest, "measure", &data->measure ); - dest = json_arrOpen( dest, "samples" ); +char* json_data( char* dest, char const* name, struct data const* data, size_t* remLen ) { + dest = json_objOpen( dest, NULL, remLen ); + dest = json_str( dest, "city", data->city, remLen ); + dest = json_str( dest, "street", data->street, remLen ); + dest = json_measure( dest, "measure", &data->measure, remLen ); + dest = json_arrOpen( dest, "samples", remLen ); for( int i = 0; i < 4; ++i ) - dest = json_int( dest, NULL, data->samples[i] ); - dest = json_arrClose( dest ); - dest = json_objClose( dest ); + dest = json_int( dest, NULL, data->samples[i], remLen ); + dest = json_arrClose( dest, remLen ); + dest = json_objClose( dest, remLen ); return dest; } @@ -97,9 +97,9 @@ char* json_data( char* dest, char const* name, struct data const* data ) { * @param dest Destination memory block. * @param data Source data structure. * @return The JSON string length. */ -int data_to_json( char* dest, struct data const* data ) { - char* p = json_data( dest, NULL, data ); - p = json_end( p ); +int data_to_json( char* dest, struct data const* data, size_t* remLen ) { + char* p = json_data( dest, NULL, data, remLen ); + p = json_end( p, remLen ); return p - dest; } @@ -149,7 +149,8 @@ int main(int argc, char** argv) { } }; char buff[512]; - int len = data_to_json( buff, &data ); + size_t remLen = sizeof(buff); + int len = data_to_json( buff, &data, &remLen ); if( len >= sizeof buff ) { fprintf( stderr, "%s%d%s%d\n", "Error. Len: ", len, " Max: ", (int)sizeof buff - 1 ); return EXIT_FAILURE; From 40bc74b77e90f88b2a421f38d87a7f3761b06f41 Mon Sep 17 00:00:00 2001 From: Chris Desjardins Date: Fri, 25 Nov 2022 10:16:04 +0100 Subject: [PATCH 3/4] Add a new test for bounds checking the buffer I noticed there were some bugs if your buffer was too small to fit the json, sometimes it would write a NULL char past the end of the buffer. Add two tests for this situation. --- tests/src/test.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/tests/src/test.c b/tests/src/test.c index 43c6840..6cfe43e 100644 --- a/tests/src/test.c +++ b/tests/src/test.c @@ -284,6 +284,31 @@ static int real( void ) { done(); } +static int bounds(void) { + char buff[6]; + char fillVal = 0x7c; + { + size_t remLen = sizeof(buff) - 1; + memset( buff, fillVal, sizeof( buff ) ); + char* p = json_objOpen( buff, NULL, &remLen ); + p = json_str( p, "0123456789", "value", &remLen ); + p = json_objClose( p, &remLen ); + p = json_end( p, &remLen ); + // Check we didn't write past remLen bytes + check(buff[sizeof( buff ) - 1] == fillVal); + } + { + size_t remLen = sizeof( buff ) - 1; + memset( buff, fillVal, sizeof( buff )); + char* p = json_objOpen( buff, NULL, &remLen ); + p = json_str( p, "v", "0123456789", &remLen ); + p = json_objClose( p, &remLen ); + p = json_end( p, &remLen ); + // Check we didn't write past remLen bytes + check(buff[sizeof( buff ) - 1] == fillVal); + } + done(); +} // --------------------------------------------------------- Execute tests: --- int main( void ) { @@ -294,7 +319,8 @@ int main( void ) { { primitive, "Primitives values" }, { integers, "Integers values" }, { array, "Array" }, - { real, "Real" } + { real, "Real" }, + { bounds, "Bounds" }, }; return test_suit( tests, sizeof tests / sizeof *tests ); } From 2b2b4742b996ec399e37a3af2ea5c708131bd3a6 Mon Sep 17 00:00:00 2001 From: Chris Desjardins Date: Fri, 25 Nov 2022 10:18:12 +0100 Subject: [PATCH 4/4] Fix buffer overflow in json-maker.c --- src/json-maker.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/json-maker.c b/src/json-maker.c index 129a2c3..afd9904 100644 --- a/src/json-maker.c +++ b/src/json-maker.c @@ -48,7 +48,8 @@ static char* chtoa( char* dest, char ch, size_t* remLen ) { static char* atoa( char* dest, char const* src, size_t* remLen ) { for( ; *src != '\0' && *remLen != 0; ++dest, ++src, --*remLen ) *dest = *src; - *dest = '\0'; + if (*remLen != 0) + *dest = '\0'; return dest; } @@ -177,7 +178,8 @@ static char* atoesc( char* dest, char const* src, int len, size_t* remLen ) { if (*remLen == 0) break; } - *dest = '\0'; + if (*remLen != 0) + *dest = '\0'; return dest; }