Describe the bug
json_decode reads one byte past the end of its heap allocation when the JSON text ends with an
escape backslash. ASan reports a heap-buffer-overflow in eigs_json_parse_string.
Mechanism, all line numbers on main @ abf8294: the escape branch at src/builtins.c:992-993
advances past the backslash onto the terminating NUL; switch (s[*pos]) falls to the default: arm
at :1021, which appends that NUL; the loop-bottom (*pos)++ at :1026 then steps past the
terminator, and the loop guard at :991 — while (s[*pos] && s[*pos] != '"') { — dereferences one
byte beyond the strdup'd buffer.
This is the same shape as the lexer bug fixed in #304, one layer over in the JSON parser.
To reproduce
EigenScript code that triggers the bug:
err is 0
try:
x is json_decode of "\"\\"
catch e:
err is 1
print of err
The JSON text being decoded is two bytes: a quote and a backslash.
Built with make asan and run with ASAN_OPTIONS=detect_leaks=0.
Expected behavior
An unterminated escape at end of input is a malformed document — json_decode should raise the way
it does for any other truncation, without reading out of bounds.
Actual behavior
=================================================================
==1703169==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x502000002073 at pc 0x5623a0636f57 bp 0x7ffe7c6982d0 sp 0x7ffe7c6982c8
READ of size 1 at 0x502000002073 thread T0
#0 0x5623a0636f56 in eigs_json_parse_string src/builtins.c:991
#1 0x5623a0665162 in eigs_json_parse_value src/builtins.c:1161
#2 0x5623a0668415 in builtin_json_decode src/builtins.c:1201
#3 0x5623a080f3bd in vm_run_ex src/vm.c:3454
#4 0x5623a075cad7 in vm_run src/vm.c:5561
#5 0x5623a075cad7 in vm_execute src/vm.c:6265
#6 0x5623a091d1b7 in main src/main.c:353
0x502000002073 is located 0 bytes after 3-byte region [0x502000002070,0x502000002073)
allocated by thread T0 here:
#0 0x7fea25eeed60 in strdup ../../../../src/libsanitizer/asan/asan_interceptors.cpp:578
#1 0x5623a069d63a in xstrdup src/arena.c:75
SUMMARY: AddressSanitizer: heap-buffer-overflow src/builtins.c:991 in eigs_json_parse_string
Environment
- OS: Debian 13 (x86_64)
- GCC version: 14
- EigenScript version:
0.34.0, main @ abf8294
Found while working #724. It is independent of that change — I re-checked on a branch carrying the
#724 fix and it reproduces identically there (same line, shifted by added code), because nothing in
that work touches the loop guard, the advance, or the default: arm. So this wants its own fix.
Happy to send a PR if you'd like it; the #304 fix looks like the precedent to follow.
Describe the bug
json_decodereads one byte past the end of its heap allocation when the JSON text ends with anescape backslash. ASan reports a
heap-buffer-overflowineigs_json_parse_string.Mechanism, all line numbers on
main@abf8294: the escape branch atsrc/builtins.c:992-993advances past the backslash onto the terminating NUL;
switch (s[*pos])falls to thedefault:armat
:1021, which appends that NUL; the loop-bottom(*pos)++at:1026then steps past theterminator, and the loop guard at
:991—while (s[*pos] && s[*pos] != '"') {— dereferences onebyte beyond the
strdup'd buffer.This is the same shape as the lexer bug fixed in #304, one layer over in the JSON parser.
To reproduce
EigenScript code that triggers the bug:
The JSON text being decoded is two bytes: a quote and a backslash.
Built with
make asanand run withASAN_OPTIONS=detect_leaks=0.Expected behavior
An unterminated escape at end of input is a malformed document —
json_decodeshould raise the wayit does for any other truncation, without reading out of bounds.
Actual behavior
Environment
0.34.0,main@abf8294Found while working #724. It is independent of that change — I re-checked on a branch carrying the
#724 fix and it reproduces identically there (same line, shifted by added code), because nothing in
that work touches the loop guard, the advance, or the
default:arm. So this wants its own fix.Happy to send a PR if you'd like it; the #304 fix looks like the precedent to follow.