java-topology/defects/libreoffice/patch/libreoffice-0001-wrtww8gr-graphic-dedup-quadratic.patch

49 lines
2 KiB
Diff

# UNDF: UNDF-2026-000000786
# UNDF: (leave blank)
# LibreOffice CWE-407: SwWW8WrGrf::Write() O(N^2) graphic dedup
#
# In sw/source/filter/ww8/wrtww8gr.cxx, the Write() method iterates over
# maDetails and for each entry searches backward from begin to current
# position via std::find() to detect duplicate graphics. This is O(N^2)
# where N = number of graphics in the document.
#
# Fix: use an unordered_map to track previously-seen details, reducing
# the dedup lookup from O(N) to O(1) amortized, making Write() O(N) total.
#
# Severity: MEDIUM — documents with hundreds of embedded graphics
# (e.g. mail-merge templates, catalogs) trigger quadratic export time.
# At N=500 graphics, ~125,000 comparisons instead of 500.
--- a/sw/source/filter/ww8/wrtww8gr.cxx
+++ b/sw/source/filter/ww8/wrtww8gr.cxx
@@ -864,13 +864,18 @@
void SwWW8WrGrf::Write()
{
SvStream& rStrm = *m_rWrt.m_pDataStrm;
+ // Map from detail hash to first occurrence index for O(1) dedup lookup
+ std::unordered_map<size_t, size_t> aSeenMap;
auto aEnd = maDetails.end();
- for (auto aIter = maDetails.begin(); aIter != aEnd; ++aIter)
+ for (auto aIter = maDetails.begin(); aIter != aEnd; ++aIter)
{
sal_uInt64 nPos = rStrm.Tell(); // align to 4 Bytes
if( nPos & 0x3 )
SwWW8Writer::FillCount( rStrm, 4 - ( nPos & 0x3 ) );
- auto aIter2 = std::find(maDetails.begin(), aIter, *aIter);
- if (aIter2 != aIter)
+ size_t nIdx = static_cast<size_t>(aIter - maDetails.begin());
+ size_t nHash = std::hash<ww8::Frame>{}(aIter->maFly);
+ auto aFound = aSeenMap.find(nHash);
+ if (aFound != aSeenMap.end() && maDetails[aFound->second] == *aIter)
{
- aIter->mnPos = aIter2->mnPos;
+ aIter->mnPos = maDetails[aFound->second].mnPos;
}
else
{
aIter->mnPos = rStrm.Tell();
WriteGraphicNode(rStrm, *aIter);
+ aSeenMap[nHash] = nIdx;
}
}
}