Code Monkey home page Code Monkey logo

json-parser's Introduction

Very low footprint DOM-style JSON parser written in portable C89 (sometimes referred to as ANSI C).

  • BSD licensed with no dependencies (i.e. just drop json.c and json.h into your project)
  • Never recurses or allocates more memory than it needs to represent the parsed JSON
  • Very simple API with operator sugar for C++

Build Status

Want to serialize? Check out json-builder!

Installing

There is now a makefile which will produce a libjsonparser static and dynamic library. However, this is not required to build json-parser, and the source files (json.c and json.h) should be happy in any build system you already have in place.

API

json_value * json_parse (const json_char * json,
                         size_t length);

json_value * json_parse_ex (json_settings * settings,
                            const json_char * json,
                            size_t length,
                            char * error);

void json_value_free (json_value *);

The type field of json_value is one of:

  • json_object (see u.object.length, u.object.values[x].name, u.object.values[x].value)
  • json_array (see u.array.length, u.array.values)
  • json_integer (see u.integer)
  • json_double (see u.dbl)
  • json_string (see u.string.ptr, u.string.length)
  • json_boolean (see u.boolean)
  • json_null

Compile-Time Options

Unless otherwise specified, compile definitions must be provided both when compiling json.c and when compiling any of your own source files that include json.h.

JSON_TRACK_SOURCE

Stores the source location (line and column number) inside each json_value.

This is useful for application-level error reporting.

json_int_t

By default, json_int_t is defined as long under C89 and int_fast64_t otherwise. For MSVC it is defined as __int64 regardless of language standard support.

Optionally, you may define json_int_t to be your own preferred type name for integer types parsed from JSON documents. It must be a signed integer type, there is no support for unsigned types. If you specify a raw primitive type without signed or unsigned (and not a typdef), JSON_INT_MAX will be calculated for you. Otherwise, you must provide your own definition of JSON_INT_MAX as the highest positive integer value that can be represented by json_int_t.

Example usage:

  • -Djson_int_t=short
  • "-Djson_int_t=signed char" -DJSON_INT_MAX=127
  • "-Djson_int_t=long long"
  • -Djson_int_t=__int128

Runtime Options

settings |= json_enable_comments;

Enables C-style // line and /* block */ comments.

size_t value_extra

The amount of space (if any) to allocate at the end of each json_value, in order to give the application space to add metadata.

void * (* mem_alloc) (size_t, int zero, void * user_data);
void (* mem_free) (void *, void * user_data);

Custom allocator routines. If NULL, the default malloc and free will be used.

The user_data pointer will be forwarded from json_settings to allow application context to be passed.

Changes in version 1.1.0

  • UTF-8 byte order marks are now skipped if present

  • Allows cross-compilation by honoring --host if given (@wkz)

  • Maximum size for error buffer is now exposed in header (@LB--)

  • GCC warning for static after const fixed (@batrick)

  • Optional support for C-style line and block comments added (@Jin-W-FS)

  • name_length field added to object values

  • It is now possible to retrieve the source line/column number of a parsed json_value when JSON_TRACK_SOURCE is enabled

  • The application may now extend json_value using the value_extra setting

  • Un-ambiguate pow call in the case of C++ overloaded pow (@fcartegnie)

  • Fix null pointer de-reference when a non-existing array is closed and no root value is present

json-parser's People

Contributors

alexgartrell avatar amorph avatar batrick avatar canh avatar chromaticisobar avatar dafanasiev avatar dimitripapadopoulos avatar drizt avatar dzavalishin avatar h2co3 avatar holyhead avatar ignatenkobrain avatar isra17 avatar jamesamcl avatar l3w1s-l1u avatar lb-- avatar martinschmauder avatar matpow2 avatar pasqumirk avatar per-ok avatar peterscott avatar raselneck avatar tildearrow avatar wilm0r avatar wkz avatar yangfl avatar zackp30 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

json-parser's Issues

CMake Integration

Hello!

I had modify build process into your parser/builder - I had add (looks like a) full cmake integration:
After sudo make install library will be available for cmake's operator find_package (cjson REQUIRED) - no need write extra cmake-Finder's

Also, I am had merge two libraries (builder+parser) into one, not sure is it interesting for you.

You can check it at:
https://github.com/vaclav2016/cjson

PS: Thanks! nice library !

Parse error when arrays are empty

Hi,

The parser fails when the following JSON is provided: {"myArray": [] }

In code:
static char str[] = "{ "myArray": [] }";
json_value * root = json_parse(str, strlen(str));

This is because malloc is called with a size of 0, due to the empty array. However some implementations of malloc will return NULL when asked to allocate 0 bytes and in this case the parser stops. I think this is wrong. In my opinion the parser should not try to allocate 0 bytes. A simple check in the newValue method for the json_array case can prevent this:

In code:
if (value->u.array.length == 0) {
break;
}

With these three lines of code the parser can also handle the above input.

Regards,
Matthijs

C++ operator sugar - add std::string & wstring operators

Hi,

People using C++ wrapper will most definitely want to use c++ strings. What do you think of adding std::string & std::wstring operators?

In my project I've added this code and it's very useful:

     #ifdef __cplusplus

           #include <string.h>
           #include <string>

     ...

     inline operator std::string () const
     {
        switch (type)
        {
           case json_string:
               return std::string(u.string.ptr);

           default:
               return "";
        }
     }

     inline operator std::wstring () const
     {
        std::string string;
        switch (type)
        {
           case json_string:
              string = u.string.ptr;
              break;
        }
        return Utf8ToWide(string);
     }

Function Utf8ToWide() is windows only:

#include <windows.h>

std::wstring Utf8ToWide(const std::string& utf8String) {
    int requiredSize = MultiByteToWideChar(CP_UTF8, 0, utf8String.c_str(), -1, 
                                           0, 0);
    wchar_t* wideString = new wchar_t[requiredSize];
    int copiedCharacters = MultiByteToWideChar(CP_UTF8, 0, utf8String.c_str(),
            -1, wideString, requiredSize);
    std::wstring returnedString(wideString);
    delete[] wideString;
    return returnedString;
}

For cross-platform conversion there is mbstowcs() function:
http://www.cplusplus.com/reference/cstdlib/mbstowcs/

But I've read there are some problems when using mbstocws() on Windows, seems that it depends on current locale, see this topic:

http://www.gamedev.net/topic/443913-what-is-different-between-multibytetowidechar-and-mbstowcs/

Taking a quick look in VC8's CRT source, it appears mbstowcs calls
MultiByteToWideChar. However, it's only doing so when the current locale
is changed from the default locale. So I'm guessing the default locale is the
C-locale, and conversion from multibyte to wide character is a simple char
to wchar_t assignment. Consistent with what you present.

So maybe for windows use this specific code and for other platforms mbstowcs()?

Czarek.

Raisonance RC51 error

Hey

I just tried compiling this with Raisonance's RC51 compiler, and it threw this error:

*** ERROR C203 IN LINE 638 OF json.c : '(XDATA  CODE)': pointer: different mspace

on the first lines of e_failed.

With those lines commented out it worked fine.

json_parse_ex() does not respect "length" parameter

The parser will fail unless the last character in the buffer to be parsed is \0, even if the "length" parameter indicates the end of the buffer.

To reproduce:

char error_string[1024] = "";
const char *test_str = "{"a":"b"}blah";
json_value x = json_parse_ex(&settings, test_str, 9, error_string);

Expected result:
Valid JSON object hierarchy with object "a" => string("b").

Actual result:
Parser fails with "1:10: Trailing garbage: b" left in error_string.

It looks like an easy fix for this is to check if i >= length in the for loop beginning on line 241 of json.c, or to change line 243 to read:
json_char b = (i == end ? 0 : *i);

I'm not submitting a patch because I don't know why line 243 is what it is currently instead of checking i.

Problem with flag_exponent and flag_got_exponent_sign

Hi,

I tried this little example, and got a parsing error :
{ "min": -1.0e+28, "max": 1.0e+28 }

I suggest you a patch.

I change this line :
flags &= ~ flag_exponent | flag_got_exponent_sign;
into this one :
flags &= ~ ( flag_exponent | flag_got_exponent_sign );

And now it works.

Kind regards

Testing flags may not be correct.

VS2013 flagged a couple of possible issues and I'm not sure it it's right or not.
Line 411:

else if (!state.settings.settings & json_relaxed_commas)

parses as ((!state.settings.settings) & json_relaxed_commas)
and I think maybe it should be (!(state.settings.settings & json_relaxed_commas))

And likewise line 572:

if (flags & flag_need_comma && (!state.settings.settings & json_relaxed_commas))

License problems.

I would like to use the library for a GPL 2 project. Is my project eligible for the GPL if it contains your code?

json fails on double value

Fails with
1:104: Unexpected . in object

{ "status": "ok", "results": [ { "recordings": [ { "id": "889ec8e0-b8a6-4ff1-a104-5512ea49fe87" } ], "score": 0.879051, "id": "45047cb1-3d3f-477e-a3dc-f14e8254e78d" } ] }

CMake support

Hey guys. The json-parser is a great lib, it's tiny enough and useful.
Have you ever considered to add CMake for json-parser? Therefore the json-parser can be compiled in different platforms.
Maybe I can make a PR for this if you like it.

double accuracy

I tried to parse a location returned from Google

{
"location": {
"lat": 40.417881799999996,
"lng": -3.7983548
},
"accuracy": 874.0
}

but due to precision issues, i obtain not too accurate double values. I am using

json_value *json = json_parse(....);
json_value location = json[0]["location"];
double lat = location["lat"];
double lng = location["lng"];
json_value_free(json);

Could be possible a compilation directive to force double as string?

Makes no sense to link unaccurate float routines if i am only interested in value (and I will pass as string to other modules.

_json_value::_none never initialized

When using the c++ glue, the _json_value::_none static const seems to be declared only and never initialized. As a consequence, (some?) compilers do not add the constant to the object file. Linking yields the following:

Undefined symbols:
  "_json_value::_none", referenced from:
      _json_value::operator[](char const*) constin indexer.o
      _json_value::operator[](char const*) constin indexer.o

Stuff compiles when adding the following to the .c:

#ifdef __cplusplus
const _json_value _json_value::_none;
#endif

However, I am uncertain if these imply the correct initialization semantics of the constant at hand, so I did not make a pull request. It seems to work for me, but suggestions on a (better/real) fix are welcome.

Additionally, in the c++ glue, it appears a little inconsistent to me to overload (char *) assignment for strings, but not have something similar for the other types - at the same time, this might lead to quite the clutter.

Keep up the good work!

long hex string will be parsed as intger

here is a test json:

{
"data":[
{
"fid":"4964064645299876352",
"uid":343432,
"aid":1,
"cid":"496405779507429120",
"n":"test.mkv",
"s":134695681,
"sta":1,
"pt":"0",
"pc":"blff0gr7ddtbe8322",
"p":0,
"m":0,
"t":"2015-04-16 21:48",
"d":1,
"c":0,
"sh":0,
"e":"",
"ico":"mkv",
"sha":"8EBA268F096B099346A0ECF0542FE687D7A62895",
"de":"",
"q":0,
"hdf":0,
"et":0,
"epos":""
}
],
"count":194,
"state":true,
"error":"",
"errNo":0,
"t":0.25246405601501
}

the problem line:

"sha":"8EBA268F096B099346A0ECF0542FE687D7A62895"

Visual Studio /analyze results

When /analyze is set for the json it outputs the following warnings:

json.cpp(376): warning C6290: Bitwise operation on logical result: ! has higher precedence than &. Use && or (!(x & y)) instead
json.cpp(531): warning C6290: Bitwise operation on logical result: ! has higher precedence than &. Use && or (!(x & y)) instead
json.cpp(477): warning C6328: 'char' passed as parameter '1' when 'unsigned char' is required in call to 'isdigit'
json.cpp(484): warning C6328: 'char' passed as parameter '1' when 'unsigned char' is required in call to 'isdigit'
json.cpp(568): warning C6328: 'char' passed as parameter '1' when 'unsigned char' is required in call to 'isdigit'
json.cpp(374): warning C6011: Dereferencing NULL pointer 'top': Lines: 194, 195, 196, 197, 198, 199, 200, 202, 204, 205, 207, 208, 210, 211, 213, 215, 216, 217, 218, 220, 221, 223, 224, 226, 228, 230, 246, 365, 367, 369, 226, 228, 230, 246, 365, 367, 369, 226, 228, 230, 246, 365, 367, 372, 374
json.cpp(570): warning C6001: Using uninitialized memory 'num_digits': Lines: 194, 195, 196, 197, 198, 199, 200, 202, 204, 205, 207, 208, 210, 211, 213, 215, 216, 217, 218, 220, 221, 223, 224, 226, 228, 230, 246, 365, 367, 372, 374, 376, 679, 685, 226, 228, 230, 246, 365, 367, 372, 374, 375, 679, 685, 687, 689, 697, 700, 725, 728, 226, 228, 230, 246, 365, 520, 565, 566, 568, 570
json.cpp(634): warning C6001: Using uninitialized memory 'num_fraction': Lines: 194, 195, 196, 197, 198, 199, 200, 202, 204, 205, 207, 208, 210, 211, 213, 215, 216, 217, 218, 220, 221, 223, 224, 226, 228, 230, 246, 365, 367, 372, 374, 376, 679, 685, 226, 228, 230, 246, 365, 367, 372, 374, 375, 679, 685, 687, 689, 697, 700, 725, 728, 226, 228, 230, 246, 365, 520, 565, 566, 568, 599, 601, 625, 627, 629, 634

You might want to check if they could be a potential errors.

C++ operator sugar - a C++ way of looping through array

Hi,

The C++ wrapper is great, but I'm missing one thing: a way to loop through array in a c++ fool-proof way. I know that I can do this:

json_value arr = (*settings)["web_server"]["cgi_extensions"];
if (arr.type == json_array) {
    int length = arr.u.array.length;
    for (int i = 0; i < length; i++) {
    ...
    }
}

But, a newbie might forget the type checking and just go with:

json_value arr = (*settings)["web_server"]["cgi_extensions"];
int length = arr.u.array.length;
for (int i = 0; i < length; i++) {
...
}

If someone makes a mistake in the json file, so that array is missing or becomes a string, then this code will crash the application.

I love the C++ wrapper mostly that it is fool-proof, I can reference to a non-existing key and it just returns an empty string, I will mistake the types and it will just return 0, nothing bad happens. But when it comes to looping through arrays it's easy to make a mistake, I've done it already and I'm a little scared of writing such code.

What I'm looking for is some method like GetArrayLength() that will return array length or 0 when value is not an array.

Czarek.

Where should the json.h really be installed?

Json-builder expects json.h to be placed in the root of a user/system include directory, but json-parser places the file in the json-parser/ subdirectory. Which should be the standard?

How about moving json.h to json/json-parser.h and place json-builder in json/json-builder.h ?

[REGRESSION] drop some functions

Since 83fd768 I have:

src/game/editor/editor.cpp: In member function ‘void CEditorImage::LoadAutoMapper()’:
src/game/editor/editor.cpp:227:72: error: invalid conversion from ‘char*’ to ‘size_t {aka long unsigned int}’ [-fpermissive]
  json_value *pJsonData = json_parse_ex(&JsonSettings, pFileData, aError);
                                                                        ^
src/game/editor/editor.cpp:227:72: error: too few arguments to function ‘json_value* json_parse_ex(json_settings*, const char*, size_t, char*)’
In file included from src/game/editor/auto_map.h:9:0,
                 from src/game/editor/editor.cpp:23:
src/engine/external/json-parser/json.h:247:14: note: declared here
 json_value * json_parse_ex (json_settings * settings,
              ^

And other

Test Suite

tests/valid-0001.json isn't valid json

heap buffer overflow on some inputs

I found a heap buffer overflow bug on json.c with AFL-FUZZ in ASAN mode. ASAN classifies it as a buffer overflow, but it could be an over-read buffer, ASAN does not distinguish them.
I used your sample code test_json.c as a harness for the library, then I compiled library and harness with agl-gcc:

For build library:
AFL_USE_ASAN=1 CC=afl-gcc ./configure
AFL_USE_ASAN=1 make


For compile code:
AFL_USE_ASAN=1 afl-gcc -o test_json -I.. test_json.c ../json.c -lm

here is the crash that was triggered with this input:
{"[unull\uDC

The error output verifiable with the following command :
test_json afl-out/crashes/id\:000001\,sig\:06\,src\:000296\,op\:havoc\,rep\:4
error:

=================================================================
==11311==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000001d at pc 0x000000520c48 bp 0x7ffdbb426970 sp 0x7ffdbb426968
READ of size 1 at 0x60200000001d thread T0
#0 0x520c47 in json_parse_ex /home/canuzzi/Fuzzing-json-parser/ASAN-json-parser/json-parser/examples/../json.c:304:45
#1 0x5225c1 in json_parse /home/canuzzi/Fuzzing-json-parser/ASAN-json-parser/json-parser/examples/../json.c:952:11
#2 0x51abdf in main /home/canuzzi/Fuzzing-json-parser/ASAN-json-parser/json-parser/examples/test_json.c:167:17
#3 0x7f8003b0d82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#4 0x41a2e8 in _start (/home/canuzzi/Fuzzing-json-parser/ASAN-json-parser/json-parser/examples/test_json+0x41a2e8)

0x60200000001d is located 0 bytes to the right of 13-byte region [0x602000000010,0x60200000001d)
allocated by thread T0 here:
#0 0x4e2ce8 in __interceptor_malloc /home/canuzzi/llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:88
#1 0x51aafc in main /home/canuzzi/Fuzzing-json-parser/ASAN-json-parser/json-parser/examples/test_json.c:140:32
#2 0x7f8003b0d82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/canuzzi/Fuzzing-json-parser/ASAN-json-parser/json-parser/examples/../json.c:304:45 in json_parse_ex
Shadow bytes around the buggy address:
0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa fa 00[05]fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==11311==ABORTING

to run afl-fuzz this command was used:
afl-fuzz -m none -i testcase/ -o afl-out/ -x /afl-2.52b/dictionaries/json.dict json-parser/examples/test_json @@

testcasefile:
afl-tmin.zip

dictionary for afl-fuzz:
json.zip

Mutade input:
crashes.zip

for example i use the following file :
id%3A000001,sig%3A06,src%3A000296,op%3Ahavoc,rep%3A4

Make new release

The current release, v1.1.0, seems to be incompatible with json-builder, I get this when I build:

/tmp/json-builder-20190729-11153-1m7ogye/json-builder.c:76:10: error: use of undeclared identifier 'json_object_entry'

Maybe make a new release?

How to modify one of the values within the JSON file

Hi All,
Using below code i can read and parse the json file, but do'nt know how to write or changes the values of a json variable in original file.

int main(int argc, char** argv)
{
char* filename;
FILE fp;
struct stat filestatus;
int file_size;
char
file_contents;
json_char* json;
json_value* value;

    if (argc != 2) {
            fprintf(stderr, "%s <file_json>\n", argv[0]);
            return 1;
    }

    filename = argv[1];

    if ( stat(filename, &filestatus) != 0) {
            fprintf(stderr, "File %s not found\n", filename);
            return 1;
    }
    file_size = filestatus.st_size;
    file_contents = (char*)malloc(filestatus.st_size);
    if ( file_contents == NULL) {
            fprintf(stderr, "Memory error: unable to allocate %d bytes\n", file_size);
            return 1;
    }

    fp = fopen(filename, "rt");
    if (fp == NULL) {
            fprintf(stderr, "Unable to open %s\n", filename);
            fclose(fp);
            free(file_contents);
            return 1;
    }
    if ( fread(file_contents, file_size, 1, fp) != 1 ) {
            fprintf(stderr, "Unable t read content of %s\n", filename);
            fclose(fp);
            free(file_contents);
            return 1;
    }
    fclose(fp);

    printf("%s\n", file_contents);

    printf("--------------------------------\n\n");

    json = (json_char*)file_contents;

    value = json_parse(json,file_size);

    if (value == NULL) {
            fprintf(stderr, "Unable to parse data\n");
            free(file_contents);
            exit(1);
    }

    process_value(value, 0); //can use string to parse

    json_value_free(value);
    free(file_contents);
    return 0;

C++ operator sugar - cast to long returns string length

Hi,

I have this json file:

{
"web_server": {
"listen_on": ["127.0.0.1", "80"]
}
}

"listen_on" value may be:
["127.0.0.1", "80"]
or
["127.0.0.1", 80]

The code is following:

const char* port = (*settings)["web_server"]["listen_on"][1];
long portInt = (*settings)["web_server"]["listen_on"][1];

When port is an int it works fine, but when port is a string, the value
of portInt is 2. I think that it should either convert the string to an
int and return 80 or just return 0 as this is not an int.

I'm not sure why it returns string length, the string struct already
has its "length" property, and "long" operator returns "integer"
property, so how can this happen?

inline operator long () const
{
    return u.integer;
}

Is it okay to change it to this?

inline operator long () const
{
    if (type == json_integer)
        return u.integer;
    return 0;
}

Czarek.

Warnings about always-false character comparisons on some compilers

On my system, running clang generates three warnings about comparisons which are always false:

json-parser>clang json.c -fsyntax-only
json.c:223:32: warning: comparison of constant 239 with expression of type
      'const char' is always false
      [-Wtautological-constant-out-of-range-compare]
   if (length >= 3 && json [0] == 0xEF
                      ~~~~~~~~ ^  ~~~~
json.c:224:32: warning: comparison of constant 187 with expression of type
      'const char' is always false
      [-Wtautological-constant-out-of-range-compare]
                   && json [1] == 0xBB
                      ~~~~~~~~ ^  ~~~~
json.c:225:32: warning: comparison of constant 191 with expression of type
      'const char' is always false
      [-Wtautological-constant-out-of-range-compare]
                   && json [2] == 0xBF)
                      ~~~~~~~~ ^  ~~~~
3 warnings generated.

This was introduced by 1d8bdc8

My suggestion would be to cast each of json [x] to a (possibly unsigned) type which can compare to the constants in all environments.

One byte out of bounds access in json_parse_ex

Note: Not a critical vulnerability (wouldnt even call it a vulnerability) at all but its still a bug which slows down performance and easy to fix.

When json_parse_ex checks for true, false or null it doesnt properly check the remaining length of the json string thus comparing the last character of these strings (true, false and null) with a byte beyond the given json string.

case 't':

  if ((end - state.ptr) < 3 || *(++ state.ptr) != 'r' ||
      *(++ state.ptr) != 'u' || *(++ state.ptr) != 'e')
  {
     goto e_unknown_value;
  }

  if (!new_value (&state, &top, &root, &alloc, json_boolean))
     goto e_alloc_failure;

  top->u.boolean = 1;

  flags |= flag_next;
  break;

case 'f':

  if ((end - state.ptr) < 4 || *(++ state.ptr) != 'a' ||
      *(++ state.ptr) != 'l' || *(++ state.ptr) != 's' ||
      *(++ state.ptr) != 'e')
  {
     goto e_unknown_value;
  }

  if (!new_value (&state, &top, &root, &alloc, json_boolean))
     goto e_alloc_failure;

  flags |= flag_next;
  break;

case 'n':

  if ((end - state.ptr) < 3 || *(++ state.ptr) != 'u' ||
      *(++ state.ptr) != 'l' || *(++ state.ptr) != 'l')
  {
     goto e_unknown_value;
  }

  if (!new_value (&state, &top, &root, &alloc, json_null))
     goto e_alloc_failure;

  flags |= flag_next;
  break;

if you would change the comparisons from < to <= this would be fixed. If you want ill send a pull request. (sorry for all the edits i got confused myself)

Buffer overflow in json-parser

Dear James Alastair McLaughlin,
We have found a buffer overflow issue in json-parser.
The crash input is automatically generated by our test generation tool FOCAL.
You can find crash.json in crash.zip

Here are details to reproduce the buffer overflow.

  • OS & Compiler
    Ubuntu Linux 16.04 x64 and GCC 5.4.0
  • Build command
    $ LDFLAGS="-fsanitize=address" CFLAGS="-fsanitize=address" ./configure && make clean all
    $ gcc -fsanitize=address -o test_json examples/test_json.c -I. libjsonparser.a -lm
  • Run command
    $ ./test_json crash.json
  • Outputs
{ " ▒r@Ja\udADa\uaAdADa\U77ADa\u077a7Ja\udADa\uaAdAD077a7Ja\udADa\uaAdADa\u77ADa\u077Aa\uaAdD0N7a7JaossEntitle": "S",
                        "GlossList":tru
--------------------------------

=================================================================
==4037==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60d00000cff8 at pc 0x000000404170 bp 0x7fff90521d80 sp 0x7fff90521d70
READ of size 1 at 0x60d00000cff8 thread T0
    #0 0x40416f in json_parse_ex (/home/yhkim/json-parser/test_json+0x40416f)
    #1 0x4059b0 in json_parse (/home/yhkim/json-parser/test_json+0x4059b0)
    #2 0x4019d5 in main (/home/yhkim/json-parser/test_json+0x4019d5)
    #3 0x7f7b7c7ba82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #4 0x4010c8 in _start (/home/yhkim/json-parser/test_json+0x4010c8)

0x60d00000cff8 is located 0 bytes to the right of 136-byte region [0x60d00000cf70,0x60d00000cff8)
allocated by thread T0 here:
    #0 0x7f7b7cf05602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
    #1 0x401802 in main (/home/yhkim/json-parser/test_json+0x401802)
    #2 0x7f7b7c7ba82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

SUMMARY: AddressSanitizer: heap-buffer-overflow ??:0 json_parse_ex
Shadow bytes around the buggy address:
  0x0c1a7fff99a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff99b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff99c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff99d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff99e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa 00 00
=>0x0c1a7fff99f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00[fa]
  0x0c1a7fff9a00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff9a10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff9a20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff9a30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff9a40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
==4037==ABORTING

Ambiguous pow call

When compiling json.c as C++ in Visual Studio 2010, I get these errors:

4> json.c
4>......\cmake-root\AudioAgent\external\json-parser\json.c(633): error C2668: 'pow' : ambiguous call to overloaded function
4> c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\math.h(583): could be 'long double pow(long double,int)'
4> c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\math.h(535): or 'float pow(float,int)'
4> c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\math.h(497): or 'double pow(double,int)'
4> while trying to match the argument list '(int, long)'
4>......\cmake-root\AudioAgent\external\json-parser\json.c(659): error C2668: 'pow' : ambiguous call to overloaded function
4> c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\math.h(583): could be 'long double pow(long double,int)'
4> c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\math.h(535): or 'float pow(float,int)'
4> c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\math.h(497): or 'double pow(double,int)'
4> while trying to match the argument list '(int, long)'

I would suggest changing the "10" to "10.0".

Copy function

Hi!

It would be great to be able to copy one json_value to another. For instance: json_value_copy(json_value* dest, json_value* src);. So even after json_value_free() has been called on src, all values are still available in dest. Would it be of interest if I proposed a PR on this issue?

Integer Overflow when supplied large number.

Since any signed integer overflow leads to undefined behavior in C, there should be some checks before adding and multiplication.

For example, the following codes lead to integer overflows.

json_parse("123456789012345678901234567890", 30);
json_parse("123456789012345678901234567890e1", 32);
json_parse("1e234567890123456789012345678901", 32);

My suggestion is to switch from json_integer to json_double type when overflow is about to happen.

For example, the following code may be used for checking integer overflow.

if ((INT64_MAX - (b-'0')) / 10 < top->u.integer)
{
    /* TODO: do something to switch to json_double type */
}

There are three places related to the issue.

num_e = (num_e * 10) + (b - '0');
top->u.integer = (top->u.integer * 10) + (b - '0');
num_fraction = (num_fraction * 10) + (b - '0');

Unicode character decoding

I think there's a problem with decoding unicode entities (\uXXXX), however I'm not sure what exactly is going wrong. Here's a sample JSON:

{ "title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" }

When parsing the JSON sample and printing the value of "title", I get this:

[jkramer/wsk:.../source]$ ./test ������� ��������� [jkramer/wsk:.../source]$ ./test | hexdump -C 00000000 c0 9f c0 be c0 bb c1 82 c0 be c1 80 c0 b0 20 c0 |.............. .| 00000010 97 c0 b5 c0 bc c0 bb c0 b5 c0 ba c0 be c0 bf c0 |................| 00000020 b0 0a |..| 00000022

(LC_CTYPE=de_DE.UTF-8)

Testing the same snippet with a JSON pretty printer (json_pp) I get the correctly decoded UTF-8:

{ "title" : "Полтора Землекопа" }

Dead store (found by scan-build)

Using scan-build (based on clang 3.5) it reports a dead assignment at line 653:

 if ( (++ state.ptr) == end)
 {
  b = 0; <-- HERE
  break;
 }

It's a very minor point... but we expect perfection these days 😉 ... also just to check this is correct because the code jumps through a couple of breaks here and it might not be doing what you expect.

Bug in float numbers reading

Bug while reading numbers without floating point as dbl values:

char string[10] = "{\"a\":10}";
json_char *json;
json = (json_char*)string;
json_value *value = json_parse(json, 8);
double float_value = value->u.object.values[0].value->u.dbl;
printf("%f",  float_value);

In this case the read value is 0.0 instead of 10.0. But if in the JSON file 10.0 is written, then the reading is correct (with adjusting length from 8 to 10).

Compile error using clang

[100%] Building C object AudioAgent/external/CMakeFiles/JsonParser.dir/json-parser/json.c.o
cc: warning: argument unused during compilation: '-no-cpp-precomp'
/Users/johank/safe/audio/trunk/AudioAgent/external/json-parser/json.c:42:51: error: missing field 'type' initializer
[-Werror,-Wmissing-field-initializers]
const struct _json_value json_value_none = { 0 };
^
I would suggest changing to

const struct _json_value json_value_none;

since static variables should anyway be zero initialized by default.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.