java-topology/whitepaper/outreach/blender.md
russell@unturf.com c24246e2e2 feat: add 5 outreach docs (33 defects) + mastodon CWE-1333 benchmark
Outreach docs (unblock intel page generation):
- kdenlive: 10 defects (8 CWE-407 + 1 CWE-362 + 1 keyframe), C++
- libreoffice: 5 defects (Writer, Calc, SFX, Impress), C++
- maven: 7 defects (graph, lifecycle, sort-by-indexOf), Java
- cpython: 7 defects (pkgutil, codegen, mock, pmerge MRO, pydoc), C/Python
- blender: 4 defects (node runtime, USD skel, shader, anim), C++

Mastodon CWE-1333 benchmark:
- test_mastodon_cwe1333.rb: validates (.+\.)? -> ([^@]+\.)? fix
  eliminates O(2^N) backtracking in email validator
2026-04-13 14:03:16 -04:00

5.1 KiB

Blender — CWE-407 Disclosure Brief

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

Finding

Four algorithmic complexity defects in Blender across the node editor runtime, USD skeletal mesh import, shader build tooling, and animation channel reordering. All patched. Three defects affect core Blender infrastructure (node trees, animation, USD import); one affects the shader build tool.

The Defects

blender-0001 (PATCHED — HIGH): source/blender/blenkernel/intern/node_runtime.cc — find_logical_origins_for_socket_recursive()

// O(D^2) cycle detection — Vector.contains() is O(D) per recursive call
if (sockets_in_current_chain.contains(&input_socket)) {
    return;  // cycle guard
}
sockets_in_current_chain.append(&input_socket);

Traverses socket chains in the node editor to compute logically linked sockets. Uses Vector<bNodeSocket*, 16>.contains() (O(D) linear scan) for cycle detection per recursive call. Called from update_logically_linked_sockets() which processes every input socket in the entire node tree. In complex shader/geometry node trees with long reroute chains, D can reach hundreds. 250x overhead at D=500.

blender-0002 (PATCHED — MEDIUM): source/blender/io/usd/intern/usd_skel_convert.cc

// O(J^2) dedup — std::find on Vector<int> per joint index
if (std::find(used_indices.begin(), used_indices.end(), index) == used_indices.end()) {
    used_indices.push_back(index);
}

Builds a unique list of used joint indices during USD skeletal mesh import using std::find() for dedup. O(J^2) where J = joint weight entries (vertices x influences_per_vertex). For high-poly meshes with many bone influences, J can reach 100k+. 250x overhead at J=1,000.

blender-0003 (PATCHED — MEDIUM): source/blender/gpu/shader_tool/shader_tool.cc

// O(D*V) visited dedup — std::find on visited_files vector
if (std::find(visited_files.begin(), visited_files.end(), file) == visited_files.end()) {
    visited_files.emplace_back(file);
}

Shader #include dependency processor checks visited files via std::find() on a vector. O(D*V) where D = dependencies, V = visited count. Fires during Blender build. 50x overhead at D=200.

blender-0004 (PATCHED — MEDIUM): source/blender/editors/animation/anim_channels_edit.cc — rearrange_animchannel_islands()

// O(C*V) — BLI_findptr linear scan per channel
const bool is_hidden =
    (BLI_findptr(anim_data_visible, channel, offsetof(bAnimListElem, data)) == nullptr);

Groups animation channels into islands for reordering (Ctrl+PgUp/PgDn in NLA editor, Dope Sheet). BLI_findptr() is O(V) per channel. Called 4 times per rearrange operation across different animation contexts. At C=V=1,000 channels: 1,000,000 pointer comparisons. 500x overhead at C=V=1,000.

Complexity Proof

blender-0001: At D=500 chain depth:

  • Defective: ~125,000 .contains() comparisons
  • Fixed: ~500 Set.contains() lookups
  • 250x op reduction

blender-0002: At J=1,000 joint weight entries:

  • Defective: ~500,000 std::find comparisons
  • Fixed: ~1,000 Set.add() lookups
  • 500x op reduction

blender-0004: At C=V=1,000 animation channels:

  • Defective: 1,000,000 BLI_findptr comparisons
  • Fixed: 1,000 Set.contains() lookups
  • 1,000x op reduction

Impact

Blender is the most widely used open-source 3D creation suite, used by artists, studios, game developers, and researchers worldwide. blender-0001 fires on every node tree edit, affecting shader and geometry node workflows that are central to modern Blender use. blender-0004 fires on every animation channel reorder in the NLA editor and Dope Sheet. blender-0002 fires during USD skeletal mesh import, increasingly important as USD adoption grows in production pipelines.

The Fix

blender-0001: Add parallel Set<bNodeSocket*> sockets_in_current_chain_set alongside the Vector for O(1) cycle detection. Keep the Vector for ordered pop_last() tracking.

blender-0002: Use Set<int> for O(1) dedup of used joint indices; maintain ordered Vector<int> for downstream use.

blender-0003: Add std::unordered_set<std::string> visited_set alongside visited_files vector for O(1) membership checks.

blender-0004: Build blender::Set<const void*> visible_data_set from anim_data_visible before the channel loop, replacing BLI_findptr() with O(1) hash lookup.

Patch

Patches available in defects/blender/patch/:

  • blender-0001-node-runtime-socket-chain-cycle-detection.patch
  • blender-0002-usd-skel-used-indices-dedup.patch
  • blender-0003-shader-tool-visited-files-linear-scan.patch
  • blender-0004-anim-channels-rearrange-island-BLI-findptr-O-C-V.patch

Language: C++

What We Ask

  1. Confirm receipt and assign a developer.blender.org task reference.
  2. Assess severity — blender-0001 fires on every node tree edit; blender-0004 fires on every animation channel reorder.
  3. Coordinate a disclosure date — we are targeting 90 days from first contact.
  4. We will credit the Blender team in the public disclosure. Preferred acknowledgment format welcome.

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