nmap-0002: nmap.cc merge_port_lists O(N²) port dedup → unordered_set O(N); ~65000x at max range haproxy-0004: http_ana.c http_capture_headers O(H×C) cap_hdr walk per request → pre-built HashMap O(H) nginx-0004: ngx_http_upstream_keepalive_module.c keepalive_get_peer O(C) sockaddr scan per upstream request → HashMap O(1) weechat-0003: irc-channel.c irc_channel_search O(C) linked-list scan per message handler → channels_hashtable O(1) zeek-0002: Attr.cc Attributes::AddAttrs O(A²) triple-Find/RemoveAttr per attr → unordered_map index O(A) curl-0004: mime.c search_header O(P×H) 3x per part per mime_add_headers → pre-indexed header name set O(P)
119 lines
4 KiB
Java
119 lines
4 KiB
Java
package unit;
|
||
|
||
import java.util.*;
|
||
|
||
/**
|
||
* zeek-0002 — CWE-407: Attributes::AddAttrs O(A²) during script compilation
|
||
*
|
||
* Models src/Attr.cc Attributes::AddAttr/AddAttrs/Find/RemoveAttr:
|
||
* Slow: attrs stored as std::vector; Find() and RemoveAttr() are O(A) each.
|
||
* AddAttr() calls Find + RemoveAttr + Find = 3×O(A).
|
||
* AddAttrs(A attrs) → O(A²) total.
|
||
* Fast: attrs indexed by tag in HashMap → O(1) Find/Remove per AddAttr.
|
||
*
|
||
* Trigger: Zeek script compilation of `redef record` with many attributes.
|
||
* Large enterprise deployments can have record types with 20-50+ attributes
|
||
* redefined across many script files.
|
||
*/
|
||
public class ZeekAttributesFindTest {
|
||
|
||
// Simplified AttrTag enum (Zeek has ~40 values)
|
||
enum AttrTag {
|
||
LOG, OPTIONAL, DEFAULT, REDEF, DEPRECATED, ERROR_HANDLER,
|
||
ADD_FUNC, DEL_FUNC, EXPIRE_READ, EXPIRE_WRITE, EXPIRE_CREATE,
|
||
EXPIRE_FUNC, TYPE_COLUMN, BROKER_STORE, BACKEND, RAW_OUTPUT,
|
||
IS_USED, NO_CPP_OPT, NO_ZAM_OPT, BROKER_STORE_ALLOW_COMPLEX,
|
||
A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, A30;
|
||
}
|
||
|
||
static class Attr {
|
||
final AttrTag tag;
|
||
Attr(AttrTag tag) { this.tag = tag; }
|
||
}
|
||
|
||
// --- SLOW: vector-based Attributes (defect) ---
|
||
static class AttributesSlow {
|
||
final List<Attr> attrs = new ArrayList<>();
|
||
long ops = 0;
|
||
|
||
Attr find(AttrTag tag) {
|
||
for (Attr a : attrs) { ops++; if (a.tag == tag) return a; }
|
||
return null;
|
||
}
|
||
|
||
void removeAttr(AttrTag tag) {
|
||
attrs.removeIf(a -> { ops++; return a.tag == tag; });
|
||
}
|
||
|
||
void addAttr(Attr attr) {
|
||
find(attr.tag); // O(A) scan #1 - check for dup
|
||
removeAttr(attr.tag); // O(A) scan #2 - remove old
|
||
attrs.add(attr);
|
||
find(AttrTag.REDEF); // O(A) scan #3 - check redef
|
||
}
|
||
|
||
void addAttrs(List<Attr> newAttrs) {
|
||
for (Attr a : newAttrs) addAttr(a);
|
||
}
|
||
}
|
||
|
||
// --- FAST: map-indexed Attributes (fix) ---
|
||
static class AttributesFast {
|
||
final Map<AttrTag, Attr> attrMap = new HashMap<>();
|
||
final List<Attr> attrs = new ArrayList<>(); // preserved for ordered iteration
|
||
long ops = 0;
|
||
|
||
Attr find(AttrTag tag) {
|
||
ops++; // O(1) map lookup
|
||
return attrMap.get(tag);
|
||
}
|
||
|
||
void removeAttr(AttrTag tag) {
|
||
ops++; // O(1) map remove
|
||
if (attrMap.remove(tag) != null)
|
||
attrs.removeIf(a -> a.tag == tag);
|
||
}
|
||
|
||
void addAttr(Attr attr) {
|
||
find(attr.tag); // O(1) check #1
|
||
removeAttr(attr.tag); // O(1) remove
|
||
attrs.add(attr);
|
||
attrMap.put(attr.tag, attr);
|
||
find(AttrTag.REDEF); // O(1) check #2
|
||
}
|
||
|
||
void addAttrs(List<Attr> newAttrs) {
|
||
for (Attr a : newAttrs) addAttr(a);
|
||
}
|
||
}
|
||
|
||
public static void main(String[] args) {
|
||
System.out.println("zeek-0002 CWE-407: Attributes::AddAttrs O(A²) vs O(A)");
|
||
System.out.println("=======================================================");
|
||
|
||
AttrTag[] allTags = AttrTag.values();
|
||
|
||
for (int A : new int[]{ 10, 20, 30 }) {
|
||
// Build list of A attributes to add
|
||
List<Attr> toAdd = new ArrayList<>();
|
||
for (int i = 0; i < A; i++)
|
||
toAdd.add(new Attr(allTags[i % allTags.length]));
|
||
|
||
// Simulate AddAttrs on a type being redef'd
|
||
AttributesSlow slow = new AttributesSlow();
|
||
AttributesFast fast = new AttributesFast();
|
||
|
||
slow.addAttrs(toAdd);
|
||
fast.addAttrs(toAdd);
|
||
|
||
double ratio = (double) slow.ops / fast.ops;
|
||
System.out.printf(" A=%2d attributes: slow=%,5d ops fast=%,4d ops speedup=%.1fx%n",
|
||
A, slow.ops, fast.ops, ratio);
|
||
|
||
assert slow.ops > fast.ops * (A / 4) :
|
||
"Expected slow > fast*" + (A/4) + " but slow=" + slow.ops + " fast=" + fast.ops;
|
||
}
|
||
|
||
System.out.println("\nPASS");
|
||
}
|
||
}
|