Skip to content

THRIFT-6055: Limit recursion depth in JavaME struct read/write#3560

Open
Jens-G wants to merge 1 commit into
apache:masterfrom
Jens-G:javame-recursion-depth
Open

THRIFT-6055: Limit recursion depth in JavaME struct read/write#3560
Jens-G wants to merge 1 commit into
apache:masterfrom
Jens-G:javame-recursion-depth

Conversation

@Jens-G
Copy link
Copy Markdown
Member

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

Summary

THRIFT-6055 — bound the recursion depth of JavaME struct read/write.

On master the generated JavaME read() / write() call readStructBegin /
writeStructBegin directly with no depth bound, TProtocol has no recursion
counter, and TProtocolException has no DEPTH_LIMIT type, so a deeply nested or
cyclic struct is processed without a limit in the generated path.

This PR:

  • adds DEPTH_LIMIT = 6 to TProtocolException;
  • adds a recursionDepth_ counter with incrementRecursionDepth() /
    decrementRecursionDepth() to TProtocol, bounded at 64;
  • updates the JavaME generator to wrap each generated struct read/write body in
    try { … } finally { decrementRecursionDepth(); }. The bound lives only in the
    generated path (one count per struct); readStructBegin / writeStructBegin
    are left untouched, so there is no double-counting.

Unknown-field skipping is handled separately by TProtocolUtil.skip (which
carries its own maxSkipDepth) and is left unchanged here.

Test

The previous test exercised increment/decrementRecursionDepth() in isolation,
which does not cover the real generated read/write path. It is replaced by
lib/javame/test/TestRecursionDepth.java — a generated-code round-trip over the
recursive IDL types in test/Recursive.thrift (CoRecCoRec2, RecTree),
run over the binary and JSON protocols:

case expectation
chain at the limit (64) round-trips
chain one over (65), write DEPTH_LIMIT
crafted payload one over (65), read DEPTH_LIMIT
wide shallow tree (192 siblings) round-trips (decrement unwinds each sibling)
cyclic graph DEPTH_LIMIT instead of unbounded recursion

Validation with OpenJDK 17 (against lib/javame/src, excluding the
javax.microedition-only THttpClient):

  • with this PR: 12/12 checks pass (6 cases × 2 protocols).
  • against unpatched generated code (master behaviour): the 6 over-limit /
    cyclic checks fail — over-limit writes and reads are not rejected and the
    cyclic case recurses to StackOverflowError — confirming the gap this change
    closes.

JavaME has no build harness or CI; the test is a standalone main, and the
generate / compile / run commands are documented in its header.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

@Jens-G Jens-G requested review from fishy and mhlakhani as code owners May 28, 2026 11:47
@mergeable mergeable Bot added java Pull requests that update Java 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 javame-recursion-depth branch from ba1349e to 307d156 Compare May 30, 2026 11:22
@Jens-G Jens-G changed the title THRIFT-6055: Limit struct read/write recursion depth in JavaME library THRIFT-6055: Limit recursion depth in JavaME struct read/write May 30, 2026
@Jens-G Jens-G marked this pull request as ready for review May 30, 2026 11:22
Client: javame

Add a recursionDepth_ counter with incrementRecursionDepth() and
decrementRecursionDepth() to TProtocol, bounded at 64, plus a DEPTH_LIMIT
type on TProtocolException, and update the JavaME 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.

Add a generated-code round-trip regression test
(lib/javame/test/TestRecursionDepth.java) that drives the recursive IDL
types from test/Recursive.thrift through the generated read()/write() over
the binary and JSON protocols: chains at the limit round-trip, chains one
past it (write and read) are rejected with DEPTH_LIMIT, a wide structure
confirms the counter is decremented for each sibling, and a cyclic graph is
rejected instead of recursing without bound.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Jens-G Jens-G force-pushed the javame-recursion-depth branch from 307d156 to 982b0ee Compare May 30, 2026 11:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

compiler java Pull requests that update Java code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant