llvm-0006: PartialInlining IsSingleExit BlockList is_contained O(N^2)

CWE-407: is_contained(BlockList, Succ) inside nested for loops in
computeOutliningColdRegionsInfo. Fix: SmallPtrSet for O(1) membership.
GCC deep scan: CLEAN (bitmaps/hash_sets throughout).
This commit is contained in:
russell@unturf.com 2026-03-30 10:34:02 -04:00
parent 36595d65fb
commit d0cb5fa834
2 changed files with 105 additions and 0 deletions

View file

@ -0,0 +1,28 @@
# UNDF: (leave blank)
# CWE-407: PartialInlinerImpl IsSingleExit BlockList membership O(N²)
#
# In computeOutliningColdRegionsInfo, the IsSingleExit lambda iterates
# over every block in BlockList and for each successor calls
# is_contained(BlockList, Succ), which is O(N) per call.
# Total: O(N × S × N) = O(N² × S) where N = region blocks, S = avg successors.
#
# Fix: build a SmallPtrSet from BlockList for O(1) membership lookups.
#
# Severity: LOW-MEDIUM — only runs with instrumentation profiling data,
# but region sizes can be large in profiled builds of complex functions.
#
--- a/llvm/lib/Transforms/IPO/PartialInlining.cpp
+++ b/llvm/lib/Transforms/IPO/PartialInlining.cpp
@@ -368,10 +368,12 @@
auto IsSingleExit =
[&ORE](SmallVectorImpl<BasicBlock *> &BlockList) -> BasicBlock * {
BasicBlock *ExitBlock = nullptr;
+ // Build set for O(1) membership tests (was O(N) linear scan).
+ SmallPtrSet<BasicBlock *, 16> BlockSet(BlockList.begin(), BlockList.end());
for (auto *Block : BlockList) {
for (BasicBlock *Succ : successors(Block)) {
- if (!is_contained(BlockList, Succ)) {
+ if (!BlockSet.count(Succ)) {
if (ExitBlock) {
ORE.emit([&]() {
return OptimizationRemarkMissed(DEBUG_TYPE, "MultiExitRegion",