comms/voip/smtp: 30 CWE-407 defects + 9 CLEAN; 224 sites, 101 ecosystems
This commit is contained in:
parent
4d3fcc8e73
commit
b3842ab6b8
86 changed files with 6516 additions and 5 deletions
248
defects/unrealircd/unit/UnrealircdTest.java
Normal file
248
defects/unrealircd/unit/UnrealircdTest.java
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
package unit;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* UnrealircdTest — CWE-407 benchmark for unrealircd-0001
|
||||
*
|
||||
* Models has_common_channels(c1, c2):
|
||||
* SLOW: O(c1_channels × c2_channels) — IsMember = linked-list scan per channel
|
||||
* FAST: O(c1_channels + c2_channels) — pre-build HashSet of c2's channels
|
||||
*
|
||||
* Also models the WHO global scan: O(U × c1 × c2) vs O(U × (c1+c2))
|
||||
*/
|
||||
public class UnrealircdTest {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Data model
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
static class Channel {
|
||||
final int id;
|
||||
Channel(int id) { this.id = id; }
|
||||
}
|
||||
|
||||
static class Client {
|
||||
final String nick;
|
||||
final List<Channel> channels = new ArrayList<>();
|
||||
Client(String nick) { this.nick = nick; }
|
||||
void join(Channel c) { channels.add(c); }
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// SLOW: IsMember = find_membership_link = O(n) list scan
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** Returns ops count (number of channel comparisons performed) */
|
||||
static long hasCommonChannels_slow(Client c1, Client c2) {
|
||||
long ops = 0;
|
||||
for (Channel ch1 : c1.channels) {
|
||||
// IsMember(c2, ch1) = find_membership_link = O(c2.channels)
|
||||
for (Channel ch2 : c2.channels) {
|
||||
ops++;
|
||||
if (ch2 == ch1) break;
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* WHO global scan: for each user in server, call hasCommonChannels_slow.
|
||||
* Returns total ops across all users.
|
||||
*/
|
||||
static long whoGlobalScan_slow(List<Client> users, Client requester) {
|
||||
long totalOps = 0;
|
||||
for (Client target : users) {
|
||||
if (target == requester) continue;
|
||||
totalOps += hasCommonChannels_slow(requester, target);
|
||||
}
|
||||
return totalOps;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// FAST: pre-build HashSet of c2's channels → O(1) membership test
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
static long hasCommonChannels_fast(Client c1, Client c2) {
|
||||
long ops = 0;
|
||||
// Build O(c2) set
|
||||
Set<Channel> c2set = new HashSet<>(c2.channels.size() * 2);
|
||||
for (Channel ch : c2.channels) {
|
||||
ops++;
|
||||
c2set.add(ch);
|
||||
}
|
||||
// O(c1) probe with O(1) set membership
|
||||
for (Channel ch : c1.channels) {
|
||||
ops++;
|
||||
if (c2set.contains(ch)) break; // found, same as early-exit in real code
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
static long whoGlobalScan_fast(List<Client> users, Client requester) {
|
||||
long totalOps = 0;
|
||||
// Pre-build requester's channel set once
|
||||
Set<Channel> reqSet = new HashSet<>(requester.channels.size() * 2);
|
||||
for (Channel ch : requester.channels) reqSet.add(ch);
|
||||
for (Client target : users) {
|
||||
if (target == requester) continue;
|
||||
long ops = reqSet.size(); // "build" cost amortised — count as 1 per target
|
||||
for (Channel ch : target.channels) {
|
||||
ops++;
|
||||
if (reqSet.contains(ch)) break;
|
||||
}
|
||||
totalOps += ops;
|
||||
}
|
||||
return totalOps;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Benchmark harness
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
static void bench(String label, Runnable slow, Runnable fast, long sOps, long fOps) {
|
||||
slow.run(); fast.run();
|
||||
long t0 = System.nanoTime(); slow.run(); long sMs = (System.nanoTime() - t0) / 1_000_000;
|
||||
long t1 = System.nanoTime(); fast.run(); long fMs = (System.nanoTime() - t1) / 1_000_000;
|
||||
double r = fOps > 0 ? (double) sOps / fOps : 0;
|
||||
System.out.printf(" %-52s slow:%4dms (%,d ops) fast:%4dms (%,d ops) speedup:%.0fx%n",
|
||||
label, sMs, sOps, fMs, fOps, r);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Setup helpers
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
static List<Channel> makeChannels(int n) {
|
||||
List<Channel> list = new ArrayList<>(n);
|
||||
for (int i = 0; i < n; i++) list.add(new Channel(i));
|
||||
return list;
|
||||
}
|
||||
|
||||
static Client makeClient(String nick, List<Channel> allChannels, int count, int offset) {
|
||||
Client c = new Client(nick);
|
||||
for (int i = 0; i < count; i++) c.join(allChannels.get((offset + i) % allChannels.size()));
|
||||
return c;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Main
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("unrealircd-0001: has_common_channels CWE-407 benchmark");
|
||||
System.out.println("=======================================================");
|
||||
|
||||
// --- Scenario 1: single has_common_channels call, C=50 channels/user ---
|
||||
{
|
||||
int C = 50;
|
||||
List<Channel> allChans = makeChannels(200);
|
||||
// c1 and c2 share ~half their channels (worst case: no early exit until middle)
|
||||
Client c1 = makeClient("alice", allChans, C, 0);
|
||||
Client c2 = makeClient("bob", allChans, C, C / 2);
|
||||
|
||||
long[] sOps = {0}, fOps = {0};
|
||||
Runnable slow = () -> {
|
||||
long ops = 0;
|
||||
for (int i = 0; i < 10_000; i++) ops += hasCommonChannels_slow(c1, c2);
|
||||
sOps[0] = ops;
|
||||
};
|
||||
Runnable fast = () -> {
|
||||
long ops = 0;
|
||||
for (int i = 0; i < 10_000; i++) ops += hasCommonChannels_fast(c1, c2);
|
||||
fOps[0] = ops;
|
||||
};
|
||||
slow.run(); fast.run();
|
||||
bench("has_common_channels C=50 (10k calls)", slow, fast, sOps[0], fOps[0]);
|
||||
assert sOps[0] > fOps[0] * 5 :
|
||||
"Expected slow ops >> fast ops, got slow=" + sOps[0] + " fast=" + fOps[0];
|
||||
}
|
||||
|
||||
// --- Scenario 2: WHO global scan, U=500 users, C=30 channels/user ---
|
||||
{
|
||||
int U = 500, C = 30;
|
||||
List<Channel> allChans = makeChannels(300);
|
||||
List<Client> users = new ArrayList<>(U);
|
||||
for (int i = 0; i < U; i++)
|
||||
users.add(makeClient("user" + i, allChans, C, i));
|
||||
Client requester = users.get(0);
|
||||
|
||||
long[] sOps = {0}, fOps = {0};
|
||||
Runnable slow = () -> sOps[0] = whoGlobalScan_slow(users, requester);
|
||||
Runnable fast = () -> fOps[0] = whoGlobalScan_fast(users, requester);
|
||||
slow.run(); fast.run();
|
||||
bench("who_global_scan U=500 C=30", slow, fast, sOps[0], fOps[0]);
|
||||
assert sOps[0] > fOps[0] * 3 :
|
||||
"Expected slow ops >> fast ops, got slow=" + sOps[0] + " fast=" + fOps[0];
|
||||
}
|
||||
|
||||
// --- Scenario 3: high channel density, C=100 channels/user ---
|
||||
{
|
||||
int C = 100;
|
||||
List<Channel> allChans = makeChannels(500);
|
||||
Client c1 = makeClient("heavyuser1", allChans, C, 0);
|
||||
Client c2 = makeClient("heavyuser2", allChans, C, 50);
|
||||
|
||||
long[] sOps = {0}, fOps = {0};
|
||||
Runnable slow = () -> {
|
||||
long ops = 0;
|
||||
for (int i = 0; i < 5_000; i++) ops += hasCommonChannels_slow(c1, c2);
|
||||
sOps[0] = ops;
|
||||
};
|
||||
Runnable fast = () -> {
|
||||
long ops = 0;
|
||||
for (int i = 0; i < 5_000; i++) ops += hasCommonChannels_fast(c1, c2);
|
||||
fOps[0] = ops;
|
||||
};
|
||||
slow.run(); fast.run();
|
||||
bench("has_common_channels C=100 (5k calls)", slow, fast, sOps[0], fOps[0]);
|
||||
assert sOps[0] > fOps[0] * 10 :
|
||||
"Expected slow ops >> fast ops, got slow=" + sOps[0] + " fast=" + fOps[0];
|
||||
}
|
||||
|
||||
// --- Scenario 4: unrealircd-0002 SJOIN member loop, M=500 members, C=50 chans/client ---
|
||||
{
|
||||
int M = 500, C = 50;
|
||||
List<Channel> allChans = makeChannels(C + 50);
|
||||
Channel targetChan = allChans.get(0);
|
||||
|
||||
// Create M clients each in C channels (targetChan is always one of them)
|
||||
List<Client> members = new ArrayList<>(M);
|
||||
for (int i = 0; i < M; i++) {
|
||||
Client cl = makeClient("member" + i, allChans, C - 1, i + 1);
|
||||
cl.join(targetChan); // each member is in targetChan
|
||||
members.add(cl);
|
||||
}
|
||||
|
||||
// SLOW: for each member, find targetChan in their channel list = O(C) per member
|
||||
long[] sOps = {0}, fOps = {0};
|
||||
Runnable slow = () -> {
|
||||
long ops = 0;
|
||||
for (Client cl : members) {
|
||||
// find_membership_link(cl->user->channel, targetChan)
|
||||
for (Channel ch : cl.channels) {
|
||||
ops++;
|
||||
if (ch == targetChan) break;
|
||||
}
|
||||
}
|
||||
sOps[0] = ops;
|
||||
};
|
||||
|
||||
// FAST: Member already has a direct reference to Membership (no search needed)
|
||||
Runnable fast = () -> {
|
||||
long ops = 0;
|
||||
// Direct access — O(1) per member because Member struct already holds
|
||||
// a reference to the client's Membership entry for this channel.
|
||||
for (Client cl : members) {
|
||||
ops++; // direct struct dereference, no scan
|
||||
}
|
||||
fOps[0] = ops;
|
||||
};
|
||||
slow.run(); fast.run();
|
||||
bench("sjoin-member-loop M=500 C=50", slow, fast, sOps[0], fOps[0]);
|
||||
assert sOps[0] > fOps[0] * 5 :
|
||||
"Expected slow ops >> fast ops, got slow=" + sOps[0] + " fast=" + fOps[0];
|
||||
}
|
||||
|
||||
System.out.println("\nAll assertions passed.");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue