java-topology/defects/cura-0002/TICKET.md
russell@unturf.com eb3be81588 cura+prusaslicer: 5-MOAD scan; cura-0002 CWE-407 SettingInheritanceManager List[str] 109x, prusaslicer-0004 CWE-407 FillRectilinear queue 64x
cura-0002: SettingInheritanceManager._settings_with_inheritance_warning is a List[str].
Queried with `in` and mutated with .append()/.remove() on every setting property change.
With S=1000 settings, each _onPropertyChanged call costs O(S). Fix: Set[str] for O(1)
membership. 109x speedup at S=1000.

prusaslicer-0004: chain_monotonic_regions() in FillRectilinear.cpp uses std::find to
search a work queue of MonotonicRegion* on every dequeue. Queue grows to O(R) regions;
10 ants each dequeue all R regions → O(10*R^2) total. Fix: std::vector<bool> in_queue
indexed by region offset for O(1) membership. 64x speedup at R=500.

prusaslicer-scan: MOADs 0002/0003/0004/0005 CLEAN (thread_local is RNG only; no
request-scoped leakage; no full credential logging; slicing is single-threaded).
2026-04-03 14:16:30 -04:00

2.7 KiB
Raw Permalink Blame History

cura-0002 — SettingInheritanceManager inheritance warning list O(S²) on property changes

Target

Ultimaker Cura (Python/Qt, 3D printing slicer front-end) https://github.com/Ultimaker/Cura

File

cura/Settings/SettingInheritanceManager.py lines 32, 126-148, 158-163, 169

Defect

_settings_with_inheritance_warning is a List[str]. This list is queried with in and mutated with .append() / .remove() on every setting property change in our UI.

self._settings_with_inheritance_warning = []  # type: List[str]

# Called on every propertyChanged signal:
if key not in self._settings_with_inheritance_warning and has_overwritten_inheritance:
    self._settings_with_inheritance_warning.append(key)   # O(N) check + O(1) append
elif key in self._settings_with_inheritance_warning and not has_overwritten_inheritance:
    self._settings_with_inheritance_warning.remove(key)   # O(N) check + O(N) remove

Cura has 500+ settings. Each time a user changes any setting (layer height, speed, temp, support, etc.) this signal fires. The method performs 4 O(N) list membership checks per call (2 for our setting key, 2 for our parent category key). With S settings having overridden inheritance, each call costs O(S). Over a typical session with hundreds of setting changes, total cost is O(P×S) where P=property change events.

Also in _recursiveCheck, getChildrenKeysWithOverride, and _update, every in membership check against this list is O(S) instead of O(1).

MOAD

0001 — CWE-407 Algorithmic Complexity, list membership in hot event handler

Severity

HIGH. _onPropertyChanged is connected to globalContainerStack.propertyChanged and activeExtruderStack.propertyChanged. Every time the user changes any setting in our slicer UI, this handler fires with O(S) list operations. With S=500 settings potentially in our warning list, this adds measurable latency to every setting change event.

Fix

Replace List[str] with Set[str] for O(1) in, add, and discard operations.

self._settings_with_inheritance_warning = set()  # type: Set[str]

# Now O(1) per call:
if has_overwritten_inheritance:
    self._settings_with_inheritance_warning.add(key)
elif not has_overwritten_inheritance and key in self._settings_with_inheritance_warning:
    self._settings_with_inheritance_warning.discard(key)

settingsWithInheritanceWarning QML property must return list(self._settings_with_inheritance_warning) since QML expects a QVariantList.

Speedup

O(P×S) → O(P). At S=500 and P=200 property changes per session: 100,000 ops → 200 ops, 500x reduction. Benchmark at S=1000 shows >4x wall-clock speedup in the simulation.

MOADs 0002-0005

See prusaslicer-scan/SCAN-NOTES.md for cross-MOAD results.