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 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 newAttrs) { for (Attr a : newAttrs) addAttr(a); } } // --- FAST: map-indexed Attributes (fix) --- static class AttributesFast { final Map attrMap = new HashMap<>(); final List 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 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 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"); } }