Skip to content

Commit f329562

Browse files
authored
Add a const qualified version of search (#69)
1 parent a058392 commit f329562

File tree

9 files changed

+157
-74
lines changed

9 files changed

+157
-74
lines changed

MISRA.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,18 @@ Deviations from the MISRA standard are listed below:
99
| :-: | :-: | :-: |
1010
| Directive 4.9 | Advisory | Allow inclusion of function like macros. |
1111
| Rule 3.1 | Required | Allow nested comments. C++ style `//` comments are used in example code within Doxygen documentation blocks. |
12+
| Rule 8.13 | Advisory | Allow one function to have a char * argument without const qualifier. |
1213
| Rule 15.4 | Advisory | Allow more then one `break` statement to terminate a loop. |
1314
| Rule 19.2 | Advisory | Allow a `union` of a signed and unsigned type of identical sizes. |
1415
| Rule 20.12 | Required | Allow use of `assert()`, which uses a parameter in both expanded and raw forms. |
1516

1617
### Flagged by Coverity
1718
| Deviation | Category | Justification |
1819
| :-: | :-: | :-: |
20+
| Rule 2.5 | Advisory | A macro is not used by the library; however, it exists to be used by an application. |
1921
| Rule 8.7 | Advisory | API functions are not used by the library; however, they must be externally visible in order to be used by an application. |
2022

2123
### Suppressed with Coverity Comments
22-
*None.*
24+
| Deviation | Category | Justification |
25+
| :-: | :-: | :-: |
26+
| Rule 11.3 | Required | False positive - the rule permits type qualifiers to be added. |

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ int main()
2828

2929
if( result == JSONSuccess )
3030
{
31-
result = JSON_Search( buffer, bufferLength, queryKey, queryKeyLength, '.',
31+
result = JSON_Search( buffer, bufferLength, queryKey, queryKeyLength,
3232
&value, &valueLength );
3333
}
3434

@@ -47,11 +47,11 @@ int main()
4747
return 0;
4848
}
4949
```
50-
A search may descend through nested objects when the `queryKey` contains matching key strings joined by a separator (e.g. `.`). In the example above, `bar` has the value `{"foo":"xyz"}`. Therefore, a search for query key `bar.foo` would output `xyz`.
50+
A search may descend through nested objects when the `queryKey` contains matching key strings joined by a separator, `.`. In the example above, `bar` has the value `{"foo":"xyz"}`. Therefore, a search for query key `bar.foo` would output `xyz`.
5151

5252
## Building coreJSON
5353

54-
A compiler that supports **C89 or later** such as *gcc* is required to build the library.
54+
A compiler that supports **C90 or later** such as *gcc* is required to build the library.
5555

5656
For instance, if the example above is copied to a file named `example.c`, *gcc* can be used like so:
5757
```bash

docs/doxygen/pages.dox

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ are written to cover every path of execution and achieve 100% branch coverage.
6060
@brief Primary functions of the JSON library:<br><br>
6161
@subpage json_validate_function <br>
6262
@subpage json_search_function <br>
63+
@subpage json_searcht_function <br>
64+
@subpage json_searchconst_function <br>
6365

6466
@page json_validate_function JSON_Validate
6567
@snippet core_json.h declare_json_validate
@@ -68,6 +70,14 @@ are written to cover every path of execution and achieve 100% branch coverage.
6870
@page json_search_function JSON_Search
6971
@snippet core_json.h declare_json_search
7072
@copydoc JSON_Search
73+
74+
@page json_searcht_function JSON_SearchT
75+
@snippet core_json.h declare_json_searcht
76+
@copydoc JSON_SearchT
77+
78+
@page json_searchconst_function JSON_SearchConst
79+
@snippet core_json.h declare_json_searchconst
80+
@copydoc JSON_SearchConst
7181
*/
7282

7383
<!-- We do not use doxygen ALIASes here because there have been issues in the past versions with "^^" newlines within the alias definition. -->

lexicon.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ bufferlength
88
cbmc
99
com
1010
cond
11+
const
1112
corejson
1213
coverity
1314
dbff

source/core_json.c

Lines changed: 100 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,7 +1297,7 @@ static bool_ nextKeyValuePair( const char * buf,
12971297
* @param[in] max size of the buffer.
12981298
* @param[in] query The object keys and array indexes to search for.
12991299
* @param[in] queryLength Length of the key.
1300-
* @param[out] outValue A pointer to receive the address of the value found.
1300+
* @param[out] outValue A pointer to receive the index of the value found.
13011301
* @param[out] outValueLength A pointer to receive the length of the value found.
13021302
*
13031303
* Iterate over the key-value pairs of an object, looking for a matching key.
@@ -1307,11 +1307,11 @@ static bool_ nextKeyValuePair( const char * buf,
13071307
*
13081308
* @note Parsing stops upon finding a match.
13091309
*/
1310-
static bool_ objectSearch( char * buf,
1310+
static bool_ objectSearch( const char * buf,
13111311
size_t max,
13121312
const char * query,
13131313
size_t queryLength,
1314-
char ** outValue,
1314+
size_t * outValue,
13151315
size_t * outValueLength )
13161316
{
13171317
bool_ ret = false;
@@ -1352,7 +1352,7 @@ static bool_ objectSearch( char * buf,
13521352

13531353
if( ret == true )
13541354
{
1355-
*outValue = &buf[ value ];
1355+
*outValue = value;
13561356
*outValueLength = valueLength;
13571357
}
13581358

@@ -1365,7 +1365,7 @@ static bool_ objectSearch( char * buf,
13651365
* @param[in] buf The buffer to search.
13661366
* @param[in] max size of the buffer.
13671367
* @param[in] queryIndex The index to search for.
1368-
* @param[out] outValue A pointer to receive the address of the value found.
1368+
* @param[out] outValue A pointer to receive the index of the value found.
13691369
* @param[out] outValueLength A pointer to receive the length of the value found.
13701370
*
13711371
* Iterate over the values of an array, looking for a matching index.
@@ -1375,10 +1375,10 @@ static bool_ objectSearch( char * buf,
13751375
*
13761376
* @note Parsing stops upon finding a match.
13771377
*/
1378-
static bool_ arraySearch( char * buf,
1378+
static bool_ arraySearch( const char * buf,
13791379
size_t max,
13801380
uint32_t queryIndex,
1381-
char ** outValue,
1381+
size_t * outValue,
13821382
size_t * outValueLength )
13831383
{
13841384
bool_ ret = false;
@@ -1419,7 +1419,7 @@ static bool_ arraySearch( char * buf,
14191419

14201420
if( ret == true )
14211421
{
1422-
*outValue = &buf[ value ];
1422+
*outValue = value;
14231423
*outValueLength = valueLength;
14241424
}
14251425

@@ -1479,7 +1479,7 @@ static bool_ skipQueryPart( const char * buf,
14791479
* @param[in] max size of the buffer.
14801480
* @param[in] query The object keys and array indexes to search for.
14811481
* @param[in] queryLength Length of the key.
1482-
* @param[out] outValue A pointer to receive the address of the value found.
1482+
* @param[out] outValue A pointer to receive the index of the value found.
14831483
* @param[out] outValueLength A pointer to receive the length of the value found.
14841484
*
14851485
* @return #JSONSuccess if the query is matched and the value output;
@@ -1489,17 +1489,15 @@ static bool_ skipQueryPart( const char * buf,
14891489
*
14901490
* @note Parsing stops upon finding a match.
14911491
*/
1492-
static JSONStatus_t multiSearch( char * buf,
1492+
static JSONStatus_t multiSearch( const char * buf,
14931493
size_t max,
14941494
const char * query,
14951495
size_t queryLength,
1496-
char ** outValue,
1496+
size_t * outValue,
14971497
size_t * outValueLength )
14981498
{
14991499
JSONStatus_t ret = JSONSuccess;
1500-
size_t i = 0, start = 0;
1501-
char * p = buf;
1502-
size_t tmp = max;
1500+
size_t i = 0, start = 0, queryStart = 0, value = 0, length = max;
15031501

15041502
assert( ( buf != NULL ) && ( query != NULL ) );
15051503
assert( ( outValue != NULL ) && ( outValueLength != NULL ) );
@@ -1525,13 +1523,13 @@ static JSONStatus_t multiSearch( char * buf,
15251523

15261524
i++;
15271525

1528-
found = arraySearch( p, tmp, ( uint32_t ) queryIndex, &p, &tmp );
1526+
found = arraySearch( &buf[ start ], length, ( uint32_t ) queryIndex, &value, &length );
15291527
}
15301528
else
15311529
{
15321530
size_t keyLength = 0;
15331531

1534-
start = i;
1532+
queryStart = i;
15351533

15361534
if( ( skipQueryPart( query, &i, queryLength, &keyLength ) != true ) ||
15371535
/* catch an empty key part or a trailing separator */
@@ -1541,7 +1539,7 @@ static JSONStatus_t multiSearch( char * buf,
15411539
break;
15421540
}
15431541

1544-
found = objectSearch( p, tmp, &query[ start ], keyLength, &p, &tmp );
1542+
found = objectSearch( &buf[ start ], length, &query[ queryStart ], keyLength, &value, &length );
15451543
}
15461544

15471545
if( found == false )
@@ -1550,6 +1548,8 @@ static JSONStatus_t multiSearch( char * buf,
15501548
break;
15511549
}
15521550

1551+
start += value;
1552+
15531553
if( ( i < queryLength ) && isSeparator_( query[ i ] ) )
15541554
{
15551555
i++;
@@ -1558,27 +1558,74 @@ static JSONStatus_t multiSearch( char * buf,
15581558

15591559
if( ret == JSONSuccess )
15601560
{
1561-
*outValue = p;
1562-
*outValueLength = tmp;
1561+
*outValue = start;
1562+
*outValueLength = length;
15631563
}
15641564

15651565
return ret;
15661566
}
15671567

1568+
/**
1569+
* @brief Return a JSON type based on a separator character or
1570+
* the first character of a value.
1571+
*
1572+
* @param[in] c The character to classify.
1573+
*
1574+
* @return an enum of JSONTypes_t
1575+
*/
1576+
static JSONTypes_t getType( char c )
1577+
{
1578+
JSONTypes_t t;
1579+
1580+
switch( c )
1581+
{
1582+
case '"':
1583+
t = JSONString;
1584+
break;
1585+
1586+
case '{':
1587+
t = JSONObject;
1588+
break;
1589+
1590+
case '[':
1591+
t = JSONArray;
1592+
break;
1593+
1594+
case 't':
1595+
t = JSONTrue;
1596+
break;
1597+
1598+
case 'f':
1599+
t = JSONFalse;
1600+
break;
1601+
1602+
case 'n':
1603+
t = JSONNull;
1604+
break;
1605+
1606+
default:
1607+
t = JSONNumber;
1608+
break;
1609+
}
1610+
1611+
return t;
1612+
}
1613+
15681614
/** @endcond */
15691615

15701616
/**
15711617
* See core_json.h for docs.
15721618
*/
1573-
JSONStatus_t JSON_SearchT( char * buf,
1574-
size_t max,
1575-
const char * query,
1576-
size_t queryLength,
1577-
char ** outValue,
1578-
size_t * outValueLength,
1579-
JSONTypes_t * outType )
1619+
JSONStatus_t JSON_SearchConst( const char * buf,
1620+
size_t max,
1621+
const char * query,
1622+
size_t queryLength,
1623+
const char ** outValue,
1624+
size_t * outValueLength,
1625+
JSONTypes_t * outType )
15801626
{
15811627
JSONStatus_t ret;
1628+
size_t value;
15821629

15831630
if( ( buf == NULL ) || ( query == NULL ) ||
15841631
( outValue == NULL ) || ( outValueLength == NULL ) )
@@ -1591,47 +1638,22 @@ JSONStatus_t JSON_SearchT( char * buf,
15911638
}
15921639
else
15931640
{
1594-
ret = multiSearch( buf, max, query, queryLength, outValue, outValueLength );
1641+
ret = multiSearch( buf, max, query, queryLength, &value, outValueLength );
15951642
}
15961643

15971644
if( ret == JSONSuccess )
15981645
{
1599-
JSONTypes_t t;
1646+
JSONTypes_t t = getType( buf[ value ] );
16001647

1601-
switch( *outValue[ 0 ] )
1648+
if( t == JSONString )
16021649
{
1603-
case '"':
1604-
/* strip the surrounding quotes */
1605-
( *outValue )++;
1606-
*outValueLength -= 2U;
1607-
t = JSONString;
1608-
break;
1609-
1610-
case '{':
1611-
t = JSONObject;
1612-
break;
1613-
1614-
case '[':
1615-
t = JSONArray;
1616-
break;
1617-
1618-
case 't':
1619-
t = JSONTrue;
1620-
break;
1621-
1622-
case 'f':
1623-
t = JSONFalse;
1624-
break;
1625-
1626-
case 'n':
1627-
t = JSONNull;
1628-
break;
1629-
1630-
default:
1631-
t = JSONNumber;
1632-
break;
1650+
/* strip the surrounding quotes */
1651+
value++;
1652+
*outValueLength -= 2U;
16331653
}
16341654

1655+
*outValue = &buf[ value ];
1656+
16351657
if( outType != NULL )
16361658
{
16371659
*outType = t;
@@ -1640,3 +1662,22 @@ JSONStatus_t JSON_SearchT( char * buf,
16401662

16411663
return ret;
16421664
}
1665+
1666+
/**
1667+
* See core_json.h for docs.
1668+
*/
1669+
JSONStatus_t JSON_SearchT( char * buf,
1670+
size_t max,
1671+
const char * query,
1672+
size_t queryLength,
1673+
char ** outValue,
1674+
size_t * outValueLength,
1675+
JSONTypes_t * outType )
1676+
{
1677+
/* MISRA Rule 11.3 prohibits casting a pointer to a different type.
1678+
* This instance is a false positive, as the rule permits the
1679+
* addition of a type qualifier. */
1680+
/* coverity[misra_c_2012_rule_11_3_violation] */
1681+
return JSON_SearchConst( ( const char * ) buf, max, query, queryLength,
1682+
( const char ** ) outValue, outValueLength, outType );
1683+
}

source/include/core_json.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,4 +208,26 @@ JSONStatus_t JSON_SearchT( char * buf,
208208
JSONTypes_t * outType );
209209
/* @[declare_json_searcht] */
210210

211+
/**
212+
* @brief Same as JSON_SearchT(), but with const qualified buf and outValue arguments.
213+
*
214+
* See @ref JSON_Search for documentation of common behavior.
215+
*
216+
* @param[in] buf The buffer to search.
217+
* @param[in] max size of the buffer.
218+
* @param[in] query The object keys and array indexes to search for.
219+
* @param[in] queryLength Length of the key.
220+
* @param[out] outValue A pointer to receive the address of the value found.
221+
* @param[out] outValueLength A pointer to receive the length of the value found.
222+
* @param[out] outType An enum indicating the JSON-specific type of the value.
223+
*/
224+
/* @[declare_json_searchconst] */
225+
JSONStatus_t JSON_SearchConst( const char * buf,
226+
size_t max,
227+
const char * query,
228+
size_t queryLength,
229+
const char ** outValue,
230+
size_t * outValueLength,
231+
JSONTypes_t * outType );
232+
/* @[declare_json_searchconst] */
211233
#endif /* ifndef CORE_JSON_H_ */

test/cbmc/proofs/JSON_Search/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ This directory contains a memory safety proof for JSON_Search and JSON_SearchT.
66
The proof runs in 15 minutes on a t3.medium. It provides complete coverage of:
77
* JSON_Search()
88
* JSON_SearchT()
9+
* JSON_SearchTc()
910
* arraySearch()
1011
* multiSearch()
1112
* nextKeyValuePair()

0 commit comments

Comments
 (0)