java-topology/defects/solvespace-0002/SCAN-NOTES.md
russell@unturf.com 5575f6cd9c jitsi-meet+solvespace: 5-MOAD scan; 3 new CWE-407 defects
jitsi-meet-0003: av-moderation pendingAudio/Video/Desktop Array.find()
dedup O(P^2) in large moderated meetings — 249.5x op-count at P=500,
138.5x measured at P=2000. Fix: Map<id, participant> for O(1) dedup.

jitsi-meet-0004: visitors middleware delta Array.findIndex() per update
O(U*V) in large broadcast events — 15x at V=5000 U=1000. Fix: Map-based
apply-delta O(1) per join/leave.

solvespace-0002: VRML export colours_present std::vector + find_if
O(T*C) per triangle — 250x op-count at T=50k C=500. Fix: unordered_map
keyed by ToPackedInt() RGBA uint32.

MOAD-0002/0003/0004/0005: CLEAN for both targets.
All 13 unit tests PASS.
2026-03-31 22:42:46 -04:00

62 lines
2.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# solvespace-0002 — MOAD-0001 CWE-407
## Location
`src/export.cpp`, `ExportWrlMeshes()` (VRML/WRL export), lines 1225-1240
## Pattern
O(T × C): During VRML mesh export, Solvespace builds a per-shape colour palette
by iterating every triangle and scanning a `std::vector<RgbaColor>` to check
whether our triangle's colour is already present:
```cpp
std::vector<int> triangle_colour_ids;
std::vector<RgbaColor> colours_present;
for(const auto & sp : op.second) { // outer: spans
for(const auto & tr : sp) { // inner: triangles O(T)
const auto colour_itr = std::find_if(
colours_present.begin(), colours_present.end(),
[&](const RgbaColor & c) {
return c.Equals(tr.meta.color); // O(C) per triangle
});
if(colour_itr == colours_present.end()) {
colours_present.insert(colours_present.end(), tr.meta.color);
triangle_colour_ids.push_back(colours_present.size() - 1);
} else {
triangle_colour_ids.push_back(colour_itr - colours_present.begin());
}
}
}
```
Each triangle triggers a full O(C) walk of `colours_present`. Total cost: O(T × C).
## Severity
MEDIUM-HIGH. A mechanical assembly export with:
- T = 100,000 triangles (typical for a detailed 3D model)
- C = 64 distinct colours (per-part colour coding is common)
Results in 6,400,000 comparisons vs 100,000 with an `unordered_map`.
`RgbaColor` is a packed `uint32_t` (four `uint8_t` fields: red, green, blue, alpha).
Our hash map key is `color.ToPackedIntBGRA()` (already defined in our codebase).
Fix is a single-line `unordered_map<uint32_t, int>` substitution. 64x overhead at
typical export size.
## Fix
Replace `std::vector<RgbaColor> colours_present` with
`std::unordered_map<uint32_t, int> colour_to_index`. Key: `tr.meta.color.ToPackedIntBGRA()`.
Value: index into our VRML color array. Membership test becomes `colour_to_index.count(key)`
(O(1)). The array output for VRML is built in insertion order from our map values.
`ToPackedIntBGRA()` is already defined in `dsc.h` line 649 — no new infrastructure needed.
## All 5 MOADs
- MOAD-0001: CONFIRMED (this defect)
- MOAD-0002: CLEAN (SS/SK globals are intentional single-user desktop CAD singletons; no coupling to new subsystems)
- MOAD-0003: CLEAN (single-threaded tool; no request-scoped context leakage)
- MOAD-0004: CLEAN (no network features; no credentials handled anywhere)
- MOAD-0005: CLEAN (single-process, single-threaded; no concurrent cache access possible)