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
73
defects/weechat/patch/0001-irc-nick-search-hashtable.patch
Normal file
73
defects/weechat/patch/0001-irc-nick-search-hashtable.patch
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
--- a/src/plugins/irc/irc-channel.h
|
||||
+++ b/src/plugins/irc/irc-channel.h
|
||||
@@ -85,6 +85,7 @@ struct t_irc_channel
|
||||
struct t_irc_nick *nicks; /* nicks on channel */
|
||||
int nicks_count; /* number of nicks on channel */
|
||||
+ struct t_hashtable *nicks_hashtable;/* nick_name(lower) → t_irc_nick* */
|
||||
struct t_irc_nick *last_nick; /* last nick on channel */
|
||||
|
||||
--- a/src/plugins/irc/irc-nick.c
|
||||
+++ b/src/plugins/irc/irc-nick.c
|
||||
@@ -533,6 +533,14 @@ irc_nick_new_in_channel (struct t_irc_server *server,
|
||||
struct t_irc_channel *channel, ...)
|
||||
{
|
||||
+ /* maintain hashtable for O(1) lookups */
|
||||
+ if (!channel->nicks_hashtable)
|
||||
+ channel->nicks_hashtable = weechat_hashtable_new (
|
||||
+ 64,
|
||||
+ WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_POINTER,
|
||||
+ NULL, NULL);
|
||||
+
|
||||
/* ... existing insertion code ... */
|
||||
+ if (channel->nicks_hashtable)
|
||||
+ {
|
||||
+ char lower[512];
|
||||
+ irc_server_casemap_lower (server, new_nick->name, lower, sizeof (lower));
|
||||
+ weechat_hashtable_set (channel->nicks_hashtable, lower, new_nick);
|
||||
+ }
|
||||
}
|
||||
|
||||
@@ -808,6 +808,11 @@ irc_nick_free (struct t_irc_server *server, struct t_irc_channel *channel,
|
||||
struct t_irc_nick *nick)
|
||||
{
|
||||
+ /* remove from hashtable */
|
||||
+ if (channel->nicks_hashtable)
|
||||
+ {
|
||||
+ char lower[512];
|
||||
+ irc_server_casemap_lower (server, nick->name, lower, sizeof (lower));
|
||||
+ weechat_hashtable_remove (channel->nicks_hashtable, lower);
|
||||
+ }
|
||||
/* ... existing removal code ... */
|
||||
}
|
||||
|
||||
@@ -830,12 +830,16 @@ irc_nick_search (struct t_irc_server *server, struct t_irc_channel *channel,
|
||||
const char *nickname)
|
||||
{
|
||||
- struct t_irc_nick *ptr_nick;
|
||||
-
|
||||
if (!channel || !nickname)
|
||||
return NULL;
|
||||
|
||||
- for (ptr_nick = channel->nicks; ptr_nick;
|
||||
- ptr_nick = ptr_nick->next_nick)
|
||||
- {
|
||||
- if (irc_server_strcasecmp (server, ptr_nick->name, nickname) == 0)
|
||||
- return ptr_nick;
|
||||
- }
|
||||
- return NULL;
|
||||
+ /* CWE-407 fix: O(1) hash lookup instead of O(n) linked-list scan */
|
||||
+ if (channel->nicks_hashtable)
|
||||
+ {
|
||||
+ char lower[512];
|
||||
+ irc_server_casemap_lower (server, nickname, lower, sizeof (lower));
|
||||
+ return (struct t_irc_nick *)weechat_hashtable_get (
|
||||
+ channel->nicks_hashtable, lower);
|
||||
+ }
|
||||
+
|
||||
+ /* fallback: hashtable not yet built (channel being initialised) */
|
||||
+ struct t_irc_nick *ptr_nick;
|
||||
+ for (ptr_nick = channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick)
|
||||
+ if (irc_server_strcasecmp (server, ptr_nick->name, nickname) == 0)
|
||||
+ return ptr_nick;
|
||||
+ return NULL;
|
||||
}
|
||||
258
defects/weechat/unit/WeechatTest.java
Normal file
258
defects/weechat/unit/WeechatTest.java
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
package unit;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* WeechatTest — CWE-407 benchmark for weechat-0001 + weechat-0002
|
||||
*
|
||||
* weechat-0001: irc_nick_search() O(n) called per-channel in AWAY/NICK/QUIT/KILL
|
||||
* SLOW: for each channel (C), walk linked list of nicks (N) → O(C×N)
|
||||
* FAST: HashMap lookup per channel → O(C)
|
||||
*
|
||||
* weechat-0002: irc_nick_new() calls irc_nick_search() during 353 NAMES → O(n²)
|
||||
* SLOW: for each of n nicks inserted, scan growing list → O(n²)
|
||||
* FAST: HashMap dedup check → O(n)
|
||||
*/
|
||||
public class WeechatTest {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Data model
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
static class IrcNick {
|
||||
final String name;
|
||||
IrcNick(String name) { this.name = name; }
|
||||
}
|
||||
|
||||
static class IrcChannel {
|
||||
final String name;
|
||||
// Slow: linked list representation (simulated as ArrayList for ops counting)
|
||||
final List<IrcNick> nicks = new ArrayList<>();
|
||||
// Fast: pre-built hash map
|
||||
final Map<String, IrcNick> nicksMap = new HashMap<>();
|
||||
|
||||
IrcChannel(String name) { this.name = name; }
|
||||
|
||||
void addNick(IrcNick n) {
|
||||
nicks.add(n);
|
||||
nicksMap.put(n.name.toLowerCase(), n);
|
||||
}
|
||||
}
|
||||
|
||||
static class IrcServer {
|
||||
final List<IrcChannel> channels = new ArrayList<>();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// weechat-0001: AWAY/NICK/QUIT/KILL handlers
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* SLOW: O(C × N) — for each channel, scan linked list for nick.
|
||||
* Returns total comparisons made.
|
||||
*/
|
||||
static long protocolHandler_slow(IrcServer server, String nickName) {
|
||||
long ops = 0;
|
||||
for (IrcChannel ch : server.channels) {
|
||||
// irc_nick_search: O(n) linked-list walk
|
||||
for (IrcNick n : ch.nicks) {
|
||||
ops++;
|
||||
if (n.name.equalsIgnoreCase(nickName)) break;
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* FAST: O(C) — for each channel, O(1) hash lookup.
|
||||
* Returns total lookups made.
|
||||
*/
|
||||
static long protocolHandler_fast(IrcServer server, String nickName) {
|
||||
long ops = 0;
|
||||
String key = nickName.toLowerCase();
|
||||
for (IrcChannel ch : server.channels) {
|
||||
ops++; // one hash lookup per channel
|
||||
ch.nicksMap.get(key); // O(1)
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// weechat-0002: 353 NAMES processing
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* SLOW: O(n²) — for each nick being added, scan the growing list for dedup.
|
||||
* Returns total comparisons.
|
||||
*/
|
||||
static long names353_slow(String[] nickList) {
|
||||
long ops = 0;
|
||||
List<String> added = new ArrayList<>();
|
||||
for (String nick : nickList) {
|
||||
String lc = nick.toLowerCase();
|
||||
// irc_nick_search over already-added nicks
|
||||
boolean found = false;
|
||||
for (String existing : added) {
|
||||
ops++;
|
||||
if (existing.equals(lc)) { found = true; break; }
|
||||
}
|
||||
if (!found) added.add(lc);
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* FAST: O(n) — HashMap for dedup check.
|
||||
* Returns total operations.
|
||||
*/
|
||||
static long names353_fast(String[] nickList) {
|
||||
long ops = 0;
|
||||
Map<String, Boolean> seen = new HashMap<>(nickList.length * 2);
|
||||
for (String nick : nickList) {
|
||||
ops++;
|
||||
seen.putIfAbsent(nick.toLowerCase(), Boolean.TRUE);
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 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 IrcServer makeServer(int numChannels, int nicksPerChannel, String targetNick) {
|
||||
IrcServer srv = new IrcServer();
|
||||
for (int c = 0; c < numChannels; c++) {
|
||||
IrcChannel ch = new IrcChannel("#chan" + c);
|
||||
// Insert target nick near the end (worst case for linear scan)
|
||||
for (int n = 0; n < nicksPerChannel - 1; n++)
|
||||
ch.addNick(new IrcNick("user" + c + "_" + n));
|
||||
ch.addNick(new IrcNick(targetNick));
|
||||
srv.channels.add(ch);
|
||||
}
|
||||
return srv;
|
||||
}
|
||||
|
||||
static String[] makeNickList(int n) {
|
||||
String[] nicks = new String[n];
|
||||
for (int i = 0; i < n; i++) nicks[i] = "nick" + i;
|
||||
return nicks;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Main
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("weechat-0001/0002: irc_nick_search CWE-407 benchmark");
|
||||
System.out.println("======================================================");
|
||||
|
||||
// --- weechat-0001: AWAY handler C=200 channels, N=500 nicks ---
|
||||
{
|
||||
int C = 200, N = 500;
|
||||
IrcServer srv = makeServer(C, N, "awayuser");
|
||||
|
||||
long[] sOps = {0}, fOps = {0};
|
||||
Runnable slow = () -> {
|
||||
long ops = 0;
|
||||
// Simulate 1000 AWAY messages
|
||||
for (int i = 0; i < 1000; i++) ops += protocolHandler_slow(srv, "awayuser");
|
||||
sOps[0] = ops;
|
||||
};
|
||||
Runnable fast = () -> {
|
||||
long ops = 0;
|
||||
for (int i = 0; i < 1000; i++) ops += protocolHandler_fast(srv, "awayuser");
|
||||
fOps[0] = ops;
|
||||
};
|
||||
slow.run(); fast.run();
|
||||
bench("away-handler C=200 N=500 (1000 events)", slow, fast, sOps[0], fOps[0]);
|
||||
assert sOps[0] > fOps[0] * 50 :
|
||||
"Expected slow ops >> fast ops, got slow=" + sOps[0] + " fast=" + fOps[0];
|
||||
}
|
||||
|
||||
// --- weechat-0001: NICK rename handler C=100 channels, N=300 nicks ---
|
||||
{
|
||||
int C = 100, N = 300;
|
||||
IrcServer srv = makeServer(C, N, "oldnick");
|
||||
|
||||
long[] sOps = {0}, fOps = {0};
|
||||
Runnable slow = () -> {
|
||||
long ops = 0;
|
||||
for (int i = 0; i < 500; i++) ops += protocolHandler_slow(srv, "oldnick");
|
||||
sOps[0] = ops;
|
||||
};
|
||||
Runnable fast = () -> {
|
||||
long ops = 0;
|
||||
for (int i = 0; i < 500; i++) ops += protocolHandler_fast(srv, "oldnick");
|
||||
fOps[0] = ops;
|
||||
};
|
||||
slow.run(); fast.run();
|
||||
bench("nick-handler C=100 N=300 (500 events)", slow, fast, sOps[0], fOps[0]);
|
||||
assert sOps[0] > fOps[0] * 50 :
|
||||
"Expected slow ops >> fast ops, got slow=" + sOps[0] + " fast=" + fOps[0];
|
||||
}
|
||||
|
||||
// --- weechat-0001: QUIT handler C=50 channels, N=8000 nicks (large chan) ---
|
||||
{
|
||||
int C = 50, N = 8000;
|
||||
IrcServer srv = makeServer(C, N, "quitter");
|
||||
|
||||
long[] sOps = {0}, fOps = {0};
|
||||
Runnable slow = () -> {
|
||||
long ops = 0;
|
||||
for (int i = 0; i < 100; i++) ops += protocolHandler_slow(srv, "quitter");
|
||||
sOps[0] = ops;
|
||||
};
|
||||
Runnable fast = () -> {
|
||||
long ops = 0;
|
||||
for (int i = 0; i < 100; i++) ops += protocolHandler_fast(srv, "quitter");
|
||||
fOps[0] = ops;
|
||||
};
|
||||
slow.run(); fast.run();
|
||||
bench("quit-handler C=50 N=8000 (100 events)", slow, fast, sOps[0], fOps[0]);
|
||||
assert sOps[0] > fOps[0] * 100 :
|
||||
"Expected slow ops >> fast ops, got slow=" + sOps[0] + " fast=" + fOps[0];
|
||||
}
|
||||
|
||||
// --- weechat-0002: 353 NAMES dedup N=1000 nicks ---
|
||||
{
|
||||
int N = 1000;
|
||||
String[] nicks = makeNickList(N);
|
||||
|
||||
long[] sOps = {0}, fOps = {0};
|
||||
Runnable slow = () -> sOps[0] = names353_slow(nicks);
|
||||
Runnable fast = () -> fOps[0] = names353_fast(nicks);
|
||||
slow.run(); fast.run();
|
||||
bench("names353-dedup N=1000", slow, fast, sOps[0], fOps[0]);
|
||||
assert sOps[0] > fOps[0] * 100 :
|
||||
"Expected slow ops >> fast ops, got slow=" + sOps[0] + " fast=" + fOps[0];
|
||||
}
|
||||
|
||||
// --- weechat-0002: 353 NAMES dedup N=8000 (large channel like freenode) ---
|
||||
{
|
||||
int N = 8000;
|
||||
String[] nicks = makeNickList(N);
|
||||
|
||||
long[] sOps = {0}, fOps = {0};
|
||||
Runnable slow = () -> sOps[0] = names353_slow(nicks);
|
||||
Runnable fast = () -> fOps[0] = names353_fast(nicks);
|
||||
slow.run(); fast.run();
|
||||
bench("names353-dedup N=8000 (large chan)", slow, fast, sOps[0], fOps[0]);
|
||||
assert sOps[0] > fOps[0] * 500 :
|
||||
"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