diff --git a/core/encoding/json/parser.odin b/core/encoding/json/parser.odin index bc381efee..6faaf3f32 100644 --- a/core/encoding/json/parser.odin +++ b/core/encoding/json/parser.odin @@ -263,8 +263,17 @@ parse_object_body :: proc(p: ^Parser, end_token: Token_Kind) -> (obj: Object, er return } - obj[key] = elem - + // NOTE(gonz): There are code paths for which this traversal ends up + // inserting empty key/values into the object and for those we do not + // want to allocate anything + if key != "" { + reserve_error := reserve(&obj, len(obj) + 1) + if reserve_error == mem.Allocator_Error.Out_Of_Memory { + return nil, .Out_Of_Memory + } + obj[key] = elem + } + if parse_comma(p) { break } diff --git a/tests/core/encoding/json/test_core_json.odin b/tests/core/encoding/json/test_core_json.odin index 23361d694..813d11b2c 100644 --- a/tests/core/encoding/json/test_core_json.odin +++ b/tests/core/encoding/json/test_core_json.odin @@ -4,6 +4,7 @@ import "core:encoding/json" import "core:testing" import "core:fmt" import "core:os" +import "core:mem/virtual" TEST_count := 0 TEST_fail := 0 @@ -77,6 +78,49 @@ parse_json :: proc(t: ^testing.T) { expect(t, err == nil, msg) } +@test +out_of_memory_in_parse_json :: proc(t: ^testing.T) { + arena: virtual.Arena + arena_buffer: [256]byte + arena_init_error := virtual.arena_init_buffer(&arena, arena_buffer[:]) + testing.expect(t, arena_init_error == nil, fmt.tprintf("Expected arena initialization to not return error, got: %v\n", arena_init_error)) + + context.allocator = virtual.arena_allocator(&arena) + + json_data := ` + { + "firstName": "John", + "lastName": "Smith", + "isAlive": true, + "age": 27, + "address": { + "streetAddress": "21 2nd Street", + "city": "New York", + "state": "NY", + "postalCode": "10021-3100" + }, + "phoneNumbers": [ + { + "type": "home", + "number": "212 555-1234" + }, + { + "type": "office", + "number": "646 555-4567" + } + ], + "children": [], + "spouse": null + } + ` + + _, err := json.parse(transmute([]u8)json_data) + + expected_error := json.Error.Out_Of_Memory + msg := fmt.tprintf("Expected `json.parse` to fail with %v, got %v", expected_error, err) + expect(t, err == json.Error.Out_Of_Memory, msg) +} + @test marshal_json :: proc(t: ^testing.T) {