Skip to content

verify: exponential time in must_write_args_rec #295

Description

@HardMax71

cargo rapx verify takes exponential time in the depth and branching of the local call chain below a target. This crate takes 24 seconds:

fn l4(a: u32) -> u32 { a ^ 1 }

fn l3(mut a: u32) -> u32 {
    if a & 1 != 0 { a = l4(a) }
    if a & 2 != 0 { a = l4(a) }
    if a & 4 != 0 { a = l4(a) }
    if a & 8 != 0 { a = l4(a) }
    a
}

fn l2(mut a: u32) -> u32 {
    if a & 1 != 0 { a = l3(a) }
    if a & 2 != 0 { a = l3(a) }
    if a & 4 != 0 { a = l3(a) }
    if a & 8 != 0 { a = l3(a) }
    a
}

fn l1(mut a: u32) -> u32 {
    if a & 1 != 0 { a = l2(a) }
    if a & 2 != 0 { a = l2(a) }
    if a & 4 != 0 { a = l2(a) }
    if a & 8 != 0 { a = l2(a) }
    a
}

fn l0(mut a: u32) -> u32 {
    if a & 1 != 0 { a = l1(a) }
    if a & 2 != 0 { a = l1(a) }
    if a & 4 != 0 { a = l1(a) }
    if a & 8 != 0 { a = l1(a) }
    a
}

pub fn target(xs: &[u32]) -> String {
    format!("{}", l0(xs[0]))
}

Each function has K independent ifs with a call on the branch, chained D levels deep. target is a scan target because of the format!, and its slice parameter gives it the [T] invariants checked at the return. Seconds per run, same shape:

K D = 3 D = 4 D = 5
3 0.5 1.0 6.0
4 1.2 24 596
5 10.8 823 over 1800

--postfix-repeat 0, 1 and auto make no difference. D = 6 costs the same as D = 5, which matches the depth > 4 cutoff.

A stuck run always sits in the same stack: must_write_args_rec nested five deep, under dependency_summary, under slicer::call_visit::visit, under the backward slicer in check_invariant_from_tree. must_write_args_rec (verify/call_summary/interprocedural.rs:1141) enumerates every whole-CFG path of the callee, up to 4000, and write_args_on_path recurses into it again for every call on each path (line 1358). Nothing is cached, so a callee is summarized once for every path that reaches it. On a real crate, where callees have hundreds of paths, one function ran for over 20 minutes without finishing. Caching the result per callee would likely remove most of it.

RAPx at 29cc910 (main), nightly-2026-09-22 (rustc 1.100.0-nightly 1303417c4 2026-09-21), on a lib crate holding only this file.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions