Skip to content

fix(encode): circular reference detection and encode depth limit #62

@membphis

Description

@membphis

Problem

The encoder currently has two correctness holes that can crash the process:

1. Circular reference — infinite recursion / stack overflow

encode_plain_table and encode_lazy_object_walking carry no visited-set. A self-referential table causes unconditional infinite recursion:

local t = {}
t.self = t
qjson.encode(t)   -- stack overflow, not a clean error()

lua-cjson raises a Lua error at the configured encode_max_depth (default 1000). qjson has no guard at all on the encode path — only the parse path enforces max_depth.

2. Encode depth — no limit enforced

Deeply-nested tables (not necessarily circular) can also exhaust the stack. There is no depth counter in any of the four encode helpers (encode_array, encode_object, encode_lazy_object_walking, encode_lazy_array_walking).

Fix scope

  • Add a depth counter (thread-upvalue or passed argument) to all four encode helpers.
  • On depth > limit, raise "qjson.encode: max depth exceeded".
  • Default limit: 1000 (matching lua-cjson).
  • Add Lua-level tests for both cases: circular ref and deep-nest.

Affected files

  • lua/qjson/table.lua — all four encode helpers
  • tests/lua/ — new test cases

Priority

P0 — process crash, no workaround for callers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions