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:
parent
36595d65fb
commit
d0cb5fa834
2 changed files with 105 additions and 0 deletions
|
|
@ -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",
|
||||
77
defects/llvm/unit/LlvmTest.java
Normal file
77
defects/llvm/unit/LlvmTest.java
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
import java.util.*;
|
||||
|
||||
/**
|
||||
* CWE-407 unit tests for LLVM defects (new: llvm-0006).
|
||||
*
|
||||
* llvm-0006: PartialInlining IsSingleExit — is_contained(BlockList, ...) O(N²)
|
||||
*
|
||||
* (llvm-0001 through llvm-0005 have separate unit tests or are covered
|
||||
* by LlvmAliasSetTest.java, LlvmDomConditionCacheTest.java, etc.)
|
||||
*/
|
||||
public class LlvmTest {
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// llvm-0006: PartialInlining IsSingleExit BlockList membership
|
||||
// is_contained(BlockList, Succ) inside nested for loops → O(N² × S)
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/** Defective: linear scan for block list membership */
|
||||
static int isSingleExitDefective(int blockCount) {
|
||||
List<Integer> blockList = new ArrayList<>();
|
||||
for (int i = 0; i < blockCount; i++) blockList.add(i);
|
||||
int ops = 0;
|
||||
|
||||
for (int block : blockList) {
|
||||
// Each block has ~2 successors
|
||||
int[] successors = { block + 1, block + blockCount / 3 };
|
||||
for (int succ : successors) {
|
||||
// Linear scan: is_contained(BlockList, Succ)
|
||||
for (int b : blockList) {
|
||||
ops++;
|
||||
if (b == succ) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
/** Fixed: SmallPtrSet for block list membership */
|
||||
static int isSingleExitFixed(int blockCount) {
|
||||
Set<Integer> blockSet = new HashSet<>();
|
||||
for (int i = 0; i < blockCount; i++) blockSet.add(i);
|
||||
int ops = 0;
|
||||
|
||||
for (int block = 0; block < blockCount; block++) {
|
||||
int[] successors = { block + 1, block + blockCount / 3 };
|
||||
for (int succ : successors) {
|
||||
ops++; // O(1) hash lookup
|
||||
blockSet.contains(succ);
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Test runner
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
static void check(String name, boolean cond) {
|
||||
System.out.println((cond ? "PASS" : "FAIL") + " " + name);
|
||||
if (!cond) System.exit(1);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// llvm-0006: PartialInlining IsSingleExit
|
||||
{
|
||||
int N = 500;
|
||||
int defectOps = isSingleExitDefective(N);
|
||||
int fixedOps = isSingleExitFixed(N);
|
||||
double ratio = (double) defectOps / fixedOps;
|
||||
System.out.printf("llvm-0006: defect=%d fixed=%d ratio=%.1fx%n", defectOps, fixedOps, ratio);
|
||||
check("llvm-0006-quadratic", defectOps > fixedOps * 10);
|
||||
check("llvm-0006-fixed-linear", fixedOps <= N * 3);
|
||||
}
|
||||
|
||||
System.out.println("ALL PASS");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue