213 lines
8 KiB
Java
213 lines
8 KiB
Java
package unit;
|
||
|
||
import java.util.*;
|
||
|
||
/**
|
||
* ZookeeperTest — CWE-407 benchmark for zookeeper-0001 and zookeeper-0002
|
||
*
|
||
* zookeeper-0001: PrepRequestProcessor.removeDuplicates()
|
||
* ArrayList.contains() scan on growing retval — O(N²) total for N ACL entries
|
||
* Fix: parallel HashSet<ACL> seen — O(N) total, O(1) per check
|
||
*
|
||
* zookeeper-0002: AuthenticationHelper.isCnxnAuthenticated()
|
||
* ArrayList<String>.contains() for enforceAuthSchemes — O(M) per auth id, O(I×M) total
|
||
* Fix: HashSet<String> enforceAuthSchemes — O(1) per auth id, O(I) total
|
||
*/
|
||
public class ZookeeperTest {
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// zookeeper-0001: ACL deduplication
|
||
// ---------------------------------------------------------------------------
|
||
|
||
/**
|
||
* Simulates removeDuplicates() with ArrayList.contains() — O(N²) contain calls.
|
||
* Returns the total number of contains() probes executed.
|
||
*/
|
||
static long slowRemoveDuplicates(int totalAcls, int uniqueAcls) {
|
||
// Build input: cycle through uniqueAcls distinct values
|
||
List<Integer> input = new ArrayList<>(totalAcls);
|
||
for (int i = 0; i < totalAcls; i++) {
|
||
input.add(i % uniqueAcls);
|
||
}
|
||
|
||
long probes = 0;
|
||
List<Integer> retval = new ArrayList<>(totalAcls);
|
||
for (Integer acl : input) {
|
||
// Simulate ArrayList.contains() — scan every element already in retval
|
||
boolean found = false;
|
||
for (int j = 0; j < retval.size(); j++) {
|
||
probes++;
|
||
if (retval.get(j).equals(acl)) {
|
||
found = true;
|
||
break;
|
||
}
|
||
}
|
||
if (!found) {
|
||
retval.add(acl);
|
||
}
|
||
}
|
||
return probes;
|
||
}
|
||
|
||
/**
|
||
* Simulates fixed removeDuplicates() with HashSet.add() — O(N) total.
|
||
* Returns the number of set probes (one per element).
|
||
*/
|
||
static long fastRemoveDuplicates(int totalAcls, int uniqueAcls) {
|
||
List<Integer> input = new ArrayList<>(totalAcls);
|
||
for (int i = 0; i < totalAcls; i++) {
|
||
input.add(i % uniqueAcls);
|
||
}
|
||
|
||
long probes = 0;
|
||
List<Integer> retval = new ArrayList<>(totalAcls);
|
||
Set<Integer> seen = new HashSet<>(totalAcls);
|
||
for (Integer acl : input) {
|
||
probes++; // one O(1) HashSet.add probe per element
|
||
if (seen.add(acl)) {
|
||
retval.add(acl);
|
||
}
|
||
}
|
||
return probes;
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// zookeeper-0002: auth scheme membership check
|
||
// ---------------------------------------------------------------------------
|
||
|
||
/**
|
||
* Simulates isCnxnAuthenticated() with ArrayList.contains() — O(I×M).
|
||
* I = number of auth ids on the connection, M = number of enforced schemes.
|
||
* Returns total probes across all scheme lookups.
|
||
*/
|
||
static long slowIsCnxnAuthenticated(int authIds, int schemes) {
|
||
// Build enforceAuthSchemes as ArrayList
|
||
List<String> enforceAuthSchemes = new ArrayList<>();
|
||
for (int i = 0; i < schemes; i++) {
|
||
enforceAuthSchemes.add("scheme_" + i);
|
||
}
|
||
|
||
// Build cnxn authInfo — none of the ids match (worst case: scan all schemes)
|
||
List<String> authInfo = new ArrayList<>();
|
||
for (int i = 0; i < authIds; i++) {
|
||
authInfo.add("unknown_" + i);
|
||
}
|
||
|
||
long probes = 0;
|
||
for (String scheme : authInfo) {
|
||
// Simulate ArrayList.contains() — full scan of enforceAuthSchemes list
|
||
for (int j = 0; j < enforceAuthSchemes.size(); j++) {
|
||
probes++;
|
||
if (enforceAuthSchemes.get(j).equals(scheme)) {
|
||
break; // found — stop scanning
|
||
}
|
||
}
|
||
}
|
||
return probes;
|
||
}
|
||
|
||
/**
|
||
* Simulates fixed isCnxnAuthenticated() with HashSet.contains() — O(I).
|
||
* Returns total probes (one per auth id).
|
||
*/
|
||
static long fastIsCnxnAuthenticated(int authIds, int schemes) {
|
||
Set<String> enforceAuthSchemes = new HashSet<>();
|
||
for (int i = 0; i < schemes; i++) {
|
||
enforceAuthSchemes.add("scheme_" + i);
|
||
}
|
||
|
||
List<String> authInfo = new ArrayList<>();
|
||
for (int i = 0; i < authIds; i++) {
|
||
authInfo.add("unknown_" + i);
|
||
}
|
||
|
||
long probes = 0;
|
||
for (String scheme : authInfo) {
|
||
probes++; // O(1) HashSet.contains per auth id
|
||
if (enforceAuthSchemes.contains(scheme)) {
|
||
return probes; // authenticated
|
||
}
|
||
}
|
||
return probes;
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Benchmarking helper
|
||
// ---------------------------------------------------------------------------
|
||
|
||
static void bench(String label, long slowOps, long fastOps) {
|
||
double ratio = (double) slowOps / Math.max(fastOps, 1);
|
||
System.out.printf(" %-62s slow:%,8d ops fast:%,8d ops ratio:%.0fx%n",
|
||
label, slowOps, fastOps, ratio);
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// main
|
||
// ---------------------------------------------------------------------------
|
||
|
||
public static void main(String[] args) {
|
||
System.out.println("ZookeeperTest — CWE-407: zookeeper-0001 + zookeeper-0002");
|
||
System.out.println();
|
||
|
||
// --- zookeeper-0001 benchmarks ---
|
||
System.out.println(" [zookeeper-0001: PrepRequestProcessor.removeDuplicates() ACL dedup]");
|
||
int[][] aclCases = {{200, 50}, {500, 100}, {1000, 200}};
|
||
for (int[] c : aclCases) {
|
||
int total = c[0], unique = c[1];
|
||
long slow = slowRemoveDuplicates(total, unique);
|
||
long fast = fastRemoveDuplicates(total, unique);
|
||
bench(String.format("N=%d total ACLs, U=%d unique", total, unique), slow, fast);
|
||
}
|
||
System.out.println();
|
||
|
||
// --- zookeeper-0002 benchmarks ---
|
||
System.out.println(" [zookeeper-0002: AuthenticationHelper.isCnxnAuthenticated() scheme lookup]");
|
||
int[][] authCases = {{10, 50}, {50, 200}, {100, 500}};
|
||
for (int[] c : authCases) {
|
||
int ids = c[0], schemes = c[1];
|
||
long slow = slowIsCnxnAuthenticated(ids, schemes);
|
||
long fast = fastIsCnxnAuthenticated(ids, schemes);
|
||
bench(String.format("I=%d auth-ids, M=%d enforced-schemes", ids, schemes), slow, fast);
|
||
}
|
||
System.out.println();
|
||
|
||
// --- assertions ---
|
||
int pass = 0;
|
||
|
||
// zookeeper-0001: O(N²) vs O(N) — at N=1000/U=200, slow >> fast
|
||
{
|
||
long slow = slowRemoveDuplicates(1000, 200);
|
||
long fast = fastRemoveDuplicates(1000, 200);
|
||
// slow is O(N×U) worst-case; fast is exactly N probes
|
||
// expect ratio ≥ 10x
|
||
assert slow > fast * 10
|
||
: "zookeeper-0001 expected >10x ratio; slow=" + slow + " fast=" + fast;
|
||
pass++;
|
||
System.out.printf(" PASS zookeeper-0001: ArrayList.contains dedup O(N²) → HashSet.add O(N)"
|
||
+ " ratio=%.0fx%n", (double) slow / fast);
|
||
}
|
||
|
||
// zookeeper-0002: O(I×M) vs O(I) — at I=100/M=500, slow >> fast
|
||
{
|
||
long slow = slowIsCnxnAuthenticated(100, 500);
|
||
long fast = fastIsCnxnAuthenticated(100, 500);
|
||
// slow = 100×500 = 50000; fast = 100
|
||
// expect ratio ≥ 50x
|
||
assert slow > fast * 50
|
||
: "zookeeper-0002 expected >50x ratio; slow=" + slow + " fast=" + fast;
|
||
pass++;
|
||
System.out.printf(" PASS zookeeper-0002: ArrayList.contains auth-scheme O(I×M) → HashSet O(I)"
|
||
+ " ratio=%.0fx%n", (double) slow / fast);
|
||
}
|
||
|
||
System.out.println();
|
||
System.out.printf("%d/2 PASS%n", pass);
|
||
|
||
if (pass < 2) {
|
||
System.out.println("FAIL");
|
||
System.exit(1);
|
||
}
|
||
|
||
System.out.println("ALL PASS");
|
||
}
|
||
}
|