Batch 9 (15): bun, bzflag (3), cake_wallet (4), calligra, caprice32 (2), cataclysm (3), cemu Batch 10 (15): cemu-0002, citra, clickhouse-java, cmake (3), cocos2d (3), conduit, cura (2), curaengine, clamav, contiki
2.7 KiB
Calligra — CWE-407 Disclosure Brief (calligra-0001)
2026-04-14 · Patch available — awaiting upstream merge
Finding
One O(n²) defect in Calligra's shape manager. KoShapeManager::addShape() uses QList::contains() for membership testing, which performs a linear scan. When setShapes() adds N shapes, the i-th insertion scans i existing entries, yielding O(N²) total cost. Fires during document load, SVG import, and image export.
The Defect
calligra-0001 (PATCHED — MEDIUM): libs/flake/KoShapeManager.cpp:138
// In KoShapeManager::addShape() — fires per shape during setShapes():
if (d->shapes.contains(shape)) // QList::contains is O(N) linear scan
return;
d->shapes.append(shape);
d->shapes and d->additionalShapes are QList<KoShape*>. The setShapes() method iterates all shapes and calls addShape() for each. The membership guard scans the growing list linearly. This path fires from SvgImport.cpp (per-layer shape iteration), document loading (all shapes), and KoPAPageBase::paintPage (image export per page).
Complexity Proof
At N=5,000 shapes:
- Defective: 5,000 + 4,999 + ... + 1 = ~12,500,000 comparisons
- Fixed: 5,000 × O(1) = 5,000 hash lookups
- ~2,500× op reduction. Measured 12.6x speedup at N=5,000.
Impact
Calligra (KDE office suite) handles complex documents with thousands of shapes. SVG files from design tools, presentation slides with many elements, and multi-page documents all hit this path. Document load time and export time scale quadratically with shape count.
The Fix
Change shapes and additionalShapes from QList<KoShape*> to QSet<KoShape*>:
// Before
QList<KoShape *> shapes;
if (d->shapes.contains(shape)) return; // O(N)
d->shapes.append(shape);
// After
// CWE-407 fix: QSet for O(1) membership test instead of O(N) QList scan.
QSet<KoShape *> shapes;
if (d->shapes.contains(shape)) return; // O(1)
d->shapes.insert(shape);
The shapes() accessor returns d->shapes.values() to preserve the QList<KoShape*> public API.
Patch
Fix available: defects/calligra-0001/patch/calligra-0001.patch
Two-file patch across KoShapeManager_p.h and KoShapeManager.cpp. Changes both shapes and additionalShapes from QList to QSet, updates all insertion and removal calls.
What We Ask
A patch is ready for review.
- Confirm receipt and assign a GitHub issue reference (KDE/calligra).
- Assess severity — fires during document load, SVG import, and image export.
- Coordinate a disclosure date — we target 90 days from first contact.
- We will credit the Calligra team in the public disclosure. Preferred acknowledgment format welcome.
Contact: see cover email. This brief is confidential until coordinated disclosure.