Memory & Structure Tests
Relevant source files
The following files were used as context for generating this wiki page:
Memory and structure tests in libfastjson are designed to validate the integrity of JSON object manipulation, reference counting, and dynamic buffer management. These tests ensure that the library efficiently handles large object structures, correctly performs type casting, and maintains memory safety through rigorous validation of internal components like the printbuf and atomic reference counters.
The test suite employs automated scripts and dedicated C programs to exercise edge cases such as deep nesting, large-scale object additions/deletions, and various string formatting scenarios. This ensures that the library remains high-performance while minimizing memory overhead.
Sources: README.md, tests/test-defs.sh, tests/test_many_subobj.c
Internal Buffer Management (printbuf)
The printbuf is a core internal structure used for string manipulation and JSON serialization. Tests focus on the buffer's ability to dynamically resize, handle large data appends, and maintain null-termination across different operations.
Dynamic Resizing and Memory Allocation
The printbuf starts with an initial size (default 32 bytes) and grows as needed. Tests validate that printbuf_extend correctly calculates new sizes and handles potential integer overflows.
Sources: printbuf.c:30-45, tests/test_printbuf.c:54-70
The diagram above illustrates the logic used by printbuf_memappend to ensure memory safety during dynamic growth.
Sources: printbuf.c:71-92
Printbuf Functionality Summary
| Function | Purpose | Key Constraint |
|---|---|---|
printbuf_new() | Allocates a new buffer structure | Initial size set by printbuf_initial_size |
printbuf_memappend() | Appends data and ensures null termination | Checks for signed integer overflow |
printbuf_memset() | Sets a range of the buffer to a specific character | Automatically extends buffer if needed |
sprintbuf() | Formatted print into the buffer | Uses stack buffer for small strings; vasprintf for large |
| Sources: printbuf.c:47-65, printbuf.c:134-150, printbuf.c:191-215 |
Object Structure and Stress Testing
Structural tests verify how the library handles complex JSON trees, specifically focusing on object member addition, deletion, and replacement.
Large Scale Object Manipulation
Tests like test_many_subobj.c simulate high-load scenarios by adding hundreds of keys to a single JSON object, deleting subsets, and then re-adding or updating them. This validates the internal child page allocation logic defined by FJSON_OBJECT_CHLD_PG_SIZE.
Sources: tests/test_many_subobj.c:25-68, json_object.h:37-43
This sequence ensures that memory is correctly managed during repeated allocation and deallocation cycles.
Sources: tests/test_many_subobj.c:36-72
Memory Safety and Synchronization
libfastjson implements reference counting to manage the lifecycle of objects. In multi-threaded environments, it relies on atomic operations to ensure the integrity of these counts.
Atomic Operations
The library uses GCC built-ins for atomic increments and decrements when HAVE_ATOMIC_BUILTINS is defined. If unavailable, it falls back to pthread_mutex_t for synchronization.
Sources: atomic.h:46-64, atomic.h:80-100
Reference Counting Logic
| Macro/Function | Action | Purpose |
|---|---|---|
ATOMIC_INC | Increment count | Shared ownership acquisition |
ATOMIC_DEC | Decrement count | Release ownership |
fjson_object_get | ATOMIC_INC | Increments internal refcount |
fjson_object_put | ATOMIC_DEC | Decrements count; frees if zero |
| Sources: atomic.h:49-54, json_object.h:130-145 |
Type Casting and Parse Validation
Tests ensure that the library can safely convert between JSON types and handle malformed input.
Casting Validation
The test_cast.c utility verifies that retrieving a value as a different type (e.g., getting a string of digits as an integer) behaves predictably.
Sources: tests/test_cast.c:75-92
Parse Error Handling
The tokener is tested incrementally to ensure it correctly identifies structural errors and deep nesting.
Sources: tests/test_parse.c:166-190
| Error State | Triggering Condition | Source File |
|---|---|---|
fjson_tokener_continue | Input ends mid-token | json_tokener.c:166 |
fjson_tokener_error_depth | Nesting exceeds max_depth | json_tokener.c:537 |
fjson_tokener_error_parse_number | Invalid characters in numeric string | json_tokener.c:490 |
fjson_tokener_error_parse_unexpected | Unexpected character in strict mode | json_tokener.c:233 |
Test Bench Infrastructure
The library uses a shell-based test runner (test-defs.sh) that integrates with valgrind to detect memory leaks and errors during test execution.
Sources: tests/test-defs.sh:76-115
Summary
The Memory & Structure tests provide a comprehensive validation layer for libfastjson. By combining stress tests for large object structures, dynamic buffer validation, and atomic reference counting checks, the library ensures high performance without sacrificing memory stability. The integration with Valgrind via the test-defs infrastructure provides a final layer of assurance against leaks and memory corruption.