wave17: 562/240 — vim/qemu/tcl/nodejs/bun/httpd-0002/systemd/emacs
This commit is contained in:
parent
cce7ec653a
commit
dde5ec97fb
13 changed files with 887 additions and 4 deletions
164
defects/bun/unit/BunBinFoldersTest.java
Normal file
164
defects/bun/unit/BunBinFoldersTest.java
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
package unit;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Unit test for bun-0001: CWE-407 in dirInfoUncached bin_folders dedup.
|
||||
*
|
||||
* bun-0001 (MEDIUM):
|
||||
* File: src/resolver/resolver.zig ~lines 4041-4073
|
||||
* Symbol: dirInfoUncached — for (bin_folders.constSlice()) |existing_folder|
|
||||
* Defect: Module resolution walks D directory levels. For each level that
|
||||
* contains a node_modules/.bin directory, the path is deduplicated against a
|
||||
* shared bin_folders array using a linear scan: O(B) per call where B grows.
|
||||
* With D levels each contributing one entry: O(D²) total dedup cost.
|
||||
* Fix: Use a HashSet for O(1) membership: O(D) total.
|
||||
*
|
||||
* Modeled here in Java:
|
||||
* Zig slice linear scan ≡ List<String>.contains() (defective)
|
||||
* Zig StringHashMap ≡ java.util.Set<String> (fixed)
|
||||
* Comparison counts tracked at the membership-test site.
|
||||
*
|
||||
* Expected at D=200 directory levels:
|
||||
* defective comparisons ~ D*(D-1)/2 ≈ 19,900
|
||||
* fixed comparisons ~ D = 200
|
||||
* ratio > 50×
|
||||
*/
|
||||
public class BunBinFoldersTest {
|
||||
|
||||
// =========================================================================
|
||||
// Model: dirInfoUncached bin_folders dedup
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Defective: bin_folders is a plain List; dedup is a linear scan per entry.
|
||||
*
|
||||
* Simulates: dirInfoCachedMaybeLog calls dirInfoUncached D times, once per
|
||||
* directory level. Each call finds a unique .bin path and deduplicates it
|
||||
* against the growing bin_folders accumulator.
|
||||
*/
|
||||
static long deduplicateDefective(int D) {
|
||||
long comparisons = 0;
|
||||
List<String> binFolders = new ArrayList<>();
|
||||
|
||||
for (int level = 0; level < D; level++) {
|
||||
String binPath = "/project/level_" + level + "/node_modules/.bin";
|
||||
// for (bin_folders.constSlice()) |existing| — O(binFolders.size())
|
||||
boolean found = false;
|
||||
for (String existing : binFolders) {
|
||||
comparisons++;
|
||||
if (existing.equals(binPath)) { found = true; break; }
|
||||
}
|
||||
if (!found) {
|
||||
binFolders.add(binPath);
|
||||
}
|
||||
}
|
||||
return comparisons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixed: HashSet companion for O(1) membership; same accumulated list.
|
||||
*/
|
||||
static long deduplicateFixed(int D) {
|
||||
long comparisons = 0;
|
||||
List<String> binFolders = new ArrayList<>();
|
||||
Set<String> binFoldersSet = new HashSet<>();
|
||||
|
||||
for (int level = 0; level < D; level++) {
|
||||
String binPath = "/project/level_" + level + "/node_modules/.bin";
|
||||
// binFoldersSet.contains(binPath) — O(1)
|
||||
comparisons++;
|
||||
if (!binFoldersSet.contains(binPath)) {
|
||||
binFoldersSet.add(binPath);
|
||||
binFolders.add(binPath);
|
||||
}
|
||||
}
|
||||
return comparisons;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Tests
|
||||
// =========================================================================
|
||||
|
||||
/** Test 1 — Correctness: both produce the same accumulated bin_folders list. */
|
||||
static void testCorrectnessMatch() {
|
||||
int D = 20;
|
||||
List<String> defList = new ArrayList<>();
|
||||
List<String> fixList = new ArrayList<>();
|
||||
Set<String> fixSet = new HashSet<>();
|
||||
|
||||
for (int level = 0; level < D; level++) {
|
||||
String binPath = "/project/level_" + level + "/node_modules/.bin";
|
||||
if (!defList.contains(binPath)) defList.add(binPath);
|
||||
if (!fixSet.contains(binPath)) { fixSet.add(binPath); fixList.add(binPath); }
|
||||
}
|
||||
|
||||
assert defList.size() == D
|
||||
: "expected " + D + " bin folders; got " + defList.size();
|
||||
assert new HashSet<>(defList).equals(fixSet)
|
||||
: "defective and fixed bin_folders sets differ";
|
||||
|
||||
System.out.println("PASS testCorrectnessMatch");
|
||||
}
|
||||
|
||||
/** Test 2 — bun-0001: defective is O(D²), fixed is O(D). */
|
||||
static void testRatioAtScale() {
|
||||
int D = 200;
|
||||
|
||||
long defComp = deduplicateDefective(D);
|
||||
long fixComp = deduplicateFixed(D);
|
||||
double ratio = (double) defComp / fixComp;
|
||||
|
||||
// Defective: all D paths are unique; accumulator grows 0, 1, ..., D-1.
|
||||
// Sum of scans: 0+1+...+(D-1) = D*(D-1)/2.
|
||||
long expectedDef = (long) D * (D - 1) / 2;
|
||||
assert defComp == expectedDef
|
||||
: "defective comparisons should be D*(D-1)/2=" + expectedDef
|
||||
+ "; got " + defComp;
|
||||
|
||||
// Fixed: exactly D probes (one Set.contains per level).
|
||||
assert fixComp == D
|
||||
: "fixed comparisons should be D=" + D + "; got " + fixComp;
|
||||
|
||||
assert ratio >= 50.0
|
||||
: "ratio should be >=50x at D=200; got " + ratio;
|
||||
|
||||
System.out.printf(
|
||||
"PASS testRatioAtScale (defective=%d, fixed=%d, ratio=%.1fx)%n",
|
||||
defComp, fixComp, ratio);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test 3 — Duplicate bin paths (same .bin dir encountered multiple times):
|
||||
* dedup correctly suppresses re-adding the same path in both implementations.
|
||||
*/
|
||||
static void testWithDuplicateBinPaths() {
|
||||
int D = 40; // 40 levels but only 20 unique .bin dirs (every 2 levels share one)
|
||||
List<String> defList = new ArrayList<>();
|
||||
Set<String> fixSet = new HashSet<>();
|
||||
List<String> fixList = new ArrayList<>();
|
||||
|
||||
for (int level = 0; level < D; level++) {
|
||||
String binPath = "/project/level_" + (level / 2) + "/node_modules/.bin";
|
||||
if (!defList.contains(binPath)) defList.add(binPath);
|
||||
if (!fixSet.contains(binPath)) { fixSet.add(binPath); fixList.add(binPath); }
|
||||
}
|
||||
|
||||
int expectedUnique = D / 2;
|
||||
assert defList.size() == expectedUnique
|
||||
: "expected " + expectedUnique + " unique bin dirs; got " + defList.size();
|
||||
assert new HashSet<>(defList).equals(fixSet)
|
||||
: "duplicate-input bin_folders sets differ";
|
||||
|
||||
System.out.println("PASS testWithDuplicateBinPaths");
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
|
||||
public static void main(String[] args) {
|
||||
testCorrectnessMatch();
|
||||
testRatioAtScale();
|
||||
testWithDuplicateBinPaths();
|
||||
System.out.println("All bun-0001 tests passed.");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue