Skip to content

Stack overflow crash on contracts with recursive types in spec #2445

@leighmcculloch

Description

@leighmcculloch

What version are you using?

stellar 25.1.0 (a048a57a75762458b487052e0021ea704a926bee)
stellar-xdr 25.0.0 (dc9f40fcb83c3054341f70b65a2222073369b37b)
xdr curr (0a621ec7811db000a60efae5b35f78dee3aa2533)

What did you do?

Deployed a Soroban contract whose spec contains a recursive type, then attempted to interact with it via stellar contract invoke.

1. Create a contract with a recursive type

stellar contract init recursive-contract

Replace recursive-contract/contracts/hello-world/src/lib.rs with:

#![no_std]
use soroban_sdk::{contract, contractimpl, contracttype, Env, Vec};

#[contracttype]
#[derive(Clone, Debug)]
pub struct TreeNode {
    pub value: u32,
    pub children: Vec<TreeNode>,
}

#[contract]
pub struct Contract;

#[contractimpl]
impl Contract {
    pub fn hello(_env: Env, _tree: TreeNode) -> u32 {
        0
    }
}

2. Build and deploy

cd recursive-contract
stellar contract build
stellar keys generate repro --network local --fund
stellar contract deploy \
  --wasm target/wasm32v1-none/release/hello_world.wasm \
  --source-account repro \
  --network local
# Returns a contract ID

3. Trigger the crash

stellar contract invoke \
  --id <CONTRACT_ID> \
  --source-account repro \
  --network local \
  -- --help

What did you expect to see?

The CLI should handle contracts with recursive types in their spec gracefully — either by detecting cycles and capping recursion depth, or by using an iterative approach when generating the argument parser.

Note that stellar contract info interface works fine and correctly displays the recursive type:

pub struct TreeNode {
    pub children: soroban_sdk::Vec<TreeNode>,
    pub value: u32,
}

What did you see instead?

The CLI crashes with a stack overflow on every interaction, including --help:

thread 'main' (12281) has overflowed its stack
fatal runtime error: stack overflow, aborting
Exit code: 134

The root cause is that the CLI's spec-to-argument resolver does not detect cycles in type definitions, causing unbounded recursion on types like TreeNode → Vec<TreeNode> → TreeNode → ….

Any contract with recursive types in its spec (which Soroban and stellar-core accept without issue) will crash the CLI for anyone who tries to interact with it via stellar contract invoke. This is a client-side DoS vector — an attacker can deploy such a contract to any Stellar network, and any CLI user who attempts to interact with it (even just --help) will experience a crash.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Status

    Backlog (Not Ready)

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions