java-topology/defects/inkscape/patch/inkscape-0001-sp-object-getLinkedRecursive-vector-membership.patch

36 lines
1.6 KiB
Diff

# UNDF: UNDF-2026-000000783
# UNDF: (leave blank)
# CWE-407: sp-object.cpp getLinkedRecursive() — O(N^2) vector linear scan for dedup
#
# SPObject::getLinkedRecursive() builds a vector of linked objects by recursively
# following links. For each discovered link, it does std::find() on the growing
# vector to check for duplicates — O(N) per check, O(N^2) total for N linked objects.
#
# In deeply-linked SVG documents (e.g., clones referencing clones, heavy use of
# <use> elements), N can grow large. Every recursive call scans the entire vector.
#
# Fix: maintain a parallel std::unordered_set<SPObject*> for O(1) membership checks.
# The vector is still needed for ordered output.
#
# Severity: HIGH — recursive graph traversal on document model, triggered by any
# operation that queries linked objects (copy, delete, style cascade).
# Overhead: ~250x at N=500 linked objects.
#
--- a/src/object/sp-object.cpp
+++ b/src/object/sp-object.cpp
@@ -612,10 +612,13 @@
void SPObject::getLinkedRecursive(std::vector<SPObject *> &objects, LinkedObjectNature direction) const
{
+ // CWE-407 fix: use a set for O(1) dedup instead of vector linear scan
+ static thread_local std::unordered_set<SPObject *> seen;
+ if (seen.empty()) {
+ seen.insert(objects.begin(), objects.end());
+ }
// Recurse through multiple links
for (auto link : getLinked(direction)) {
- // Make sure we never recurse objects multiple times.
- if (std::find(objects.begin(), objects.end(), link) == objects.end()) {
+ if (seen.insert(link).second) {
objects.push_back(link);
link->getLinkedRecursive(objects, direction);
}