parse_object_body allocates an object key, then may fail in parse_colon or
parse_value before that key is ever inserted into the object. Its cleanup defer
only walks `obj`, so a key that never got there is unreachable to it. The caller
cannot free it either -- a failed parse returns a nil Value -- so it leaks.
The same applies to the parsed element on the duplicate-key path, and to both on
the out-of-memory path.
JSON5 makes this reachable from ordinary malformed input, because an unquoted
ident is a legal key and anything other than a colon after it fails. Plain JSON
leaks it too, via a quoted key.
before, measured with a tracking allocator over 8 inputs x 2 specs:
LEAK JSON5 colon fails after unquoted key 1 alloc / 7 bytes
LEAK JSON colon fails after quoted key 1 alloc / 2 bytes
LEAK JSON5 colon fails after quoted key 1 alloc / 2 bytes
LEAK JSON value fails after key 1 alloc / 2 bytes
LEAK JSON5 value fails after key 1 alloc / 2 bytes
LEAK JSON nested value fails 2 alloc / 4 bytes
LEAK JSON5 nested value fails 2 alloc / 4 bytes
LEAK JSON deep nesting fails 3 alloc / 6 bytes
LEAK JSON5 deep nesting fails 3 alloc / 6 bytes
LEAK JSON array element fails 1 alloc / 2 bytes
LEAK JSON5 array element fails 1 alloc / 2 bytes
total leaked allocations: 17
after, same probe:
total leaked allocations: 0
The leak scales with nesting depth -- one orphaned key per enclosing object -- so
a service parsing untrusted JSON leaks a little on every malformed request.
The fix marks the key and the element as owned by the loop iteration until they
are stored, and frees them otherwise. The duplicate-key path loses its explicit
delete, which the same mechanism now covers.
Found via odinfmt, which reported a 7-byte leak in a downstream test that parses
`{ broken not json` to check that invalid input is rejected.
Regression test added to tests/core/encoding/json: it reports
`17 leaks and 0 bad frees` without this change and passes with it. The existing
11 tests pass unchanged under -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true.
The Data-Oriented Language for Sane Software Development.
The Odin Programming Language
Odin is a general-purpose programming language with distinct typing, built for high performance, modern systems, and built-in data-oriented data types. The Odin Programming Language, the C alternative for the joy of programming.
Website: https://odin-lang.org/
package main
import "core:fmt"
main :: proc() {
program := "+ + * 😃 - /"
accumulator := 0
for token in program {
switch token {
case '+': accumulator += 1
case '-': accumulator -= 1
case '*': accumulator *= 2
case '/': accumulator /= 2
case '😃': accumulator *= accumulator
case: // Ignore everything else
}
}
fmt.printf("The program \"%s\" calculates the value %d\n",
program, accumulator)
}
Documentation
Getting Started
Instructions for downloading and installing the Odin compiler and libraries.
Nightly Builds
Get the latest nightly builds of Odin.
Learning Odin
Overview of Odin
An overview of the Odin programming language.
Frequently Asked Questions (FAQ)
Answers to common questions about Odin.
Packages
Documentation for all the official packages part of the core and vendor library collections.
Examples
Examples on how to write idiomatic Odin code. Shows how to accomplish specific tasks in Odin, as well as how to use packages from core and vendor.
Odin Documentation
Documentation for the Odin language itself.
Odin Discord
Get live support and talk with other Odin programmers on the Odin Discord.
Articles
The Odin Blog
The official blog of the Odin programming language, featuring announcements, news, and in-depth articles by the Odin team and guests.
Warnings
- The Odin compiler is still in development.