Skip to content

json_decode: a string ending in an escape backslash reads one byte past the allocation (ASan heap-buffer-overflow) #776

Description

@Nitjsefnie

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 :991while (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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions