36 lines
1.6 KiB
Diff
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);
|
|
}
|