Skip to content

THRIFT-6056: Limit recursion depth in Dart struct read/write#3561

Merged
Jens-G merged 1 commit into
apache:masterfrom
Jens-G:dart-recursion-depth
Jun 1, 2026
Merged

THRIFT-6056: Limit recursion depth in Dart struct read/write#3561
Jens-G merged 1 commit into
apache:masterfrom
Jens-G:dart-recursion-depth

Conversation

@Jens-G
Copy link
Copy Markdown
Member

@Jens-G Jens-G commented May 28, 2026

THRIFT-6056: Limit recursion depth in the Dart library

Change

Adds a _recursionDepth counter (incrementRecursionDepth() / decrementRecursionDepth()) to TProtocol, bounded at 64, and updates the Dart generator to bracket each generated struct read/write body with try/finally so the counter is always restored. Previously the generated read()/write() path had no limit. Unions and exceptions are generated through the same path, so they are bounded too.

Test

A regression test under test/dart/recursion_depth_test drives the recursive IDL types from test/Recursive.thrift through the generated read()/write() over Binary, Compact and JSON:

  • struct CoRec — chains one below / at the limit round-trip; one past it is rejected with DEPTH_LIMIT on both write and read; a wide shallow tree round-trips (the counter unwinds per sibling); a cyclic graph is rejected.
  • exception CoError/CoError2 — round-trips at the limit and is rejected one past it on both write and read.

Over-limit read payloads are hand-serialized with the real recursive field (id 1, type STRUCT) so the reader recurses through the guarded generated read(), not skip() (Dart's skip() is not depth-bounded, so a mis-routed payload would not raise DEPTH_LIMIT — the passing read tests confirm correct routing).

The test needs a null-safe Dart SDK (>= 2.12); generation/execution are wired via make recursion-test and kept out of the default cross chain (the cross images pin an older Dart). Validated locally on Dart stable (3.x): 27/27 pass.

🤖 Generated with Claude Code

@Jens-G Jens-G requested review from fishy and mhlakhani as code owners May 28, 2026 11:47
@mergeable mergeable Bot added dart Pull requests that update Dart code compiler labels May 28, 2026
@Jens-G Jens-G marked this pull request as draft May 28, 2026 22:45
@Jens-G Jens-G force-pushed the dart-recursion-depth branch from 103cd55 to 61ab25f Compare May 30, 2026 11:00
@mergeable mergeable Bot added the build and general CI cmake, automake and build system changes label May 30, 2026
@Jens-G Jens-G changed the title THRIFT-6056: Limit struct read/write recursion depth in Dart library THRIFT-6056: Limit recursion depth in Dart struct read/write May 30, 2026
@Jens-G Jens-G marked this pull request as ready for review May 30, 2026 11:09
Client: dart

Add a _recursionDepth counter with incrementRecursionDepth() and
decrementRecursionDepth() to TProtocol, bounded at 64, and update the
Dart generator to bracket each generated struct read/write body with
try/finally so the counter is always restored. This bounds the work
performed for deeply nested or cyclic structs, which previously had no
limit in the generated read()/write() path. Unions and exceptions are
generated through the same read/write path, so they are bounded too.

Add a regression test under test/dart/recursion_depth_test that drives
the recursive IDL types from test/Recursive.thrift through the generated
read()/write() over the binary, compact and JSON protocols:

  - struct chains at the limit round-trip; chains one past it are rejected
    with DEPTH_LIMIT on both write and read,
  - the recursive exception CoError/CoError2 likewise round-trips at the
    limit and is rejected one past it on both write and read,
  - a wide (shallow) tree confirms decrementRecursionDepth() unwinds each
    sibling back to depth 1,
  - a cyclic object graph is rejected instead of recursing without bound.

The over-limit read payloads are hand-serialized with the real recursive
field (id 1, type STRUCT) so the reader recurses through the guarded
generated read(), not skip().

The test needs a null-safe Dart SDK (>= 2.12); generation and execution
are wired via `make recursion-test` and kept out of the default cross
chain (the cross images currently pin an older Dart).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Jens-G Jens-G force-pushed the dart-recursion-depth branch from 61ab25f to f9930ab Compare June 1, 2026 18:22
@Jens-G Jens-G merged commit aeeaf4b into apache:master Jun 1, 2026
161 of 164 checks passed
@Jens-G Jens-G deleted the dart-recursion-depth branch June 1, 2026 22:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build and general CI cmake, automake and build system changes compiler dart Pull requests that update Dart code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant