java-topology/whitepaper/outreach/r-source.md
russell@unturf.com 652608142a feat: close outreach doc gap — 276 docs (batches 11-16)
All projects with patches now have outreach docs. 276 new docs covering
CWE-407, CWE-312, CWE-362 across C, C++, Java, Python, Go, Rust, C#,
PHP, Ruby, JavaScript, Dart, Erlang, R, and more.

Outreach gap: 276 -> 0.
2026-04-15 13:57:42 -04:00

2.2 KiB
Raw Permalink Blame History

R Source (rapply) — CWE-407 Disclosure Brief

2026-04-13 · Patch available — awaiting upstream merge

Finding

An O(k×j) nested class-matching loop in do_one() at src/main/apply.c:308, used by rapply(). The inner loop compares every element of klass against every element of classes using Seql() (string equality), with no early exit on match. For objects with k class names and j filter classes, every call pays full O(k×j) even when a match exists at position (0,0).

The Defect

r-source (PATCHED — MEDIUM): src/main/apply.c:308

for(int i = 0; i < LENGTH(klass); i++)
    for(int j = 0; j < length(classes); j++)
        if(Seql(STRING_ELT(klass, i), STRING_ELT(classes, j)))
            matched = true;  // no break — scans ALL pairs even after finding a match

Complexity Proof

At k=10 class names, j=20 filter classes:

  • Defective: 10 × 20 = 200 comparisons (always, even if first pair matches)
  • Fixed: 1 comparison (early exit) in best case; O(k+j) via symbol interning
  • Up to 200× op reduction in best case; consistent improvement in average case

Impact

R serves millions of users. rapply() applies a function recursively over lists and fires do_one() for every element. Deep nested lists with many elements (common in JSON/XML parsed data, Bioconductor S4 objects) call this path thousands of times per rapply() invocation.

The Fix

Intern class names via Rf_installChar() for pointer-equality comparison, and add early exit (break) on first match:

for(int i = 0; i < nk && !matched; i++) {
    SEXP ki = Rf_installChar(STRING_ELT(klass, i));
    for(int j = 0; j < nc; j++) {
        if(ki == Rf_installChar(STRING_ELT(classes, j))) {
            matched = true;
            break;
        }
    }
}

Patch

Fix available: defects/r-source/patch/0001-rapply-class-match-early-exit.patch

What We Ask

  1. Confirm receipt and assign a Bugzilla reference (bugs.r-project.org).
  2. Assess severity — fires per element in recursive list operations.
  3. Coordinate a disclosure date — targeting 90 days from first contact.
  4. We will credit the R Core Team in the public disclosure.

Contact: see cover email. This brief is confidential until coordinated disclosure.