diff --git a/defects/thrift/patch/thrift-0002-cpp-gen-struct-member-dedup-vector-find.patch b/defects/thrift/patch/thrift-0002-cpp-gen-struct-member-dedup-vector-find.patch deleted file mode 100644 index 00efdd375..000000000 --- a/defects/thrift/patch/thrift-0002-cpp-gen-struct-member-dedup-vector-find.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/compiler/cpp/src/thrift/generate/t_cpp_generator.cc b/compiler/cpp/src/thrift/generate/t_cpp_generator.cc ---- a/compiler/cpp/src/thrift/generate/t_cpp_generator.cc -+++ b/compiler/cpp/src/thrift/generate/t_cpp_generator.cc -@@ -5100,7 +5100,8 @@ bool t_cpp_generator::is_struct_storage_not_throwing(t_struct* tstruct) const { - vector members = tstruct->get_members(); - -+ std::unordered_set memberSet(members.begin(), members.end()); // O(1) dedup - - for(size_t i=0; i < members.size(); ++i) { - t_type* type = get_true_type(members[i]->get_type()); -@@ -5124,8 +5124,9 @@ bool t_cpp_generator::is_struct_storage_not_throwing(t_struct* tstruct) const { - if(type->is_struct()) { - const vector& more = ((t_struct*)type)->get_members(); - for(auto it = more.begin(); it < more.end(); ++it) { -- if(std::find(members.begin(), members.end(), *it) == members.end()) -+ if(memberSet.find(*it) == memberSet.end()) { - members.push_back(*it); -+ memberSet.insert(*it); -+ } - } - continue; - } diff --git a/defects/thrift/unit/Thrift0002CppGenStructDedupTest.java b/defects/thrift/unit/Thrift0002CppGenStructDedupTest.java deleted file mode 100644 index 729e38aa3..000000000 --- a/defects/thrift/unit/Thrift0002CppGenStructDedupTest.java +++ /dev/null @@ -1,185 +0,0 @@ -package unit; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * CWE-407 unit test: thrift-0002 - * - * Models t_cpp_generator::is_struct_storage_not_throwing() member deduplication. - * - * DEFECT: When a struct contains nested struct fields, the generator accumulates - * all transitively-reachable fields in a vector members. - * For each new field from a nested struct, std::find(members.begin(), - * members.end(), field) is O(M) where M = current accumulated size. - * Total: O(M²) for M transitively-reachable members. - * - * FIX: Maintain a parallel unordered_set for O(1) membership. - * Total: O(M). - * - * Asserts: slowOps > fastOps * 10 at M=500. - */ -public class Thrift0002CppGenStructDedupTest { - - /** - * Simulates the defective member deduplication. - * members grows as nested struct fields are discovered. - * std::find is O(current members size). - */ - static long slow(int numMembers) { - // Simulate: outer struct has 1 field of a nested struct, - // which has numMembers unique fields. - List members = new ArrayList<>(); - // Start with some initial members - members.add(0); - - long ops = 0; - // Add numMembers fields from the nested struct, each O(members.size()) to check - for (int i = 1; i <= numMembers; i++) { - // std::find(members.begin(), members.end(), i) - boolean found = false; - for (Integer m : members) { - ops++; - if (m.equals(i)) { - found = true; - break; - } - } - if (!found) { - members.add(i); - } - } - return ops; - } - - /** - * Simulates the patched version. - * Parallel HashSet for O(1) membership check. - */ - static long fast(int numMembers) { - List members = new ArrayList<>(); - Set memberSet = new HashSet<>(); - members.add(0); - memberSet.add(0); - - long ops = 0; - for (int i = 1; i <= numMembers; i++) { - ops++; // O(1) hash probe - if (!memberSet.contains(i)) { - members.add(i); - memberSet.add(i); - } - } - return ops; - } - - /** - * Worst case: later members that are duplicates require scanning the full list. - * First M unique, then M duplicates appended — all duplicates require full scan. - */ - static long slowWorstCase(int numUnique) { - List members = new ArrayList<>(); - for (int i = 0; i < numUnique; i++) members.add(i); - - long ops = 0; - // Try to add each member again — all fail (duplicates), scanning full list - for (int i = 0; i < numUnique; i++) { - for (Integer m : members) { - ops++; - if (m.equals(i)) break; // always found - } - } - return ops; - } - - static long fastWorstCase(int numUnique) { - Set memberSet = new HashSet<>(); - for (int i = 0; i < numUnique; i++) memberSet.add(i); - - long ops = 0; - for (int i = 0; i < numUnique; i++) { - ops++; // O(1) - memberSet.contains(i); - } - return ops; - } - - public static void main(String[] args) { - int passed = 0; - int total = 0; - - // Test 1: 200 new unique members being deduplicated - { - total++; - int M = 200; - long sOps = slow(M); - long fOps = fast(M); - // slow: sum(1..M) ≈ M²/2 = 20000 - // fast: M = 200 - boolean ok = sOps > fOps * 10L; - System.out.printf("Test 1 [M=%d slow=%d fast=%d ratio=%.1fx]: %s%n", - M, sOps, fOps, (double) sOps / fOps, ok ? "PASS" : "FAIL"); - if (ok) passed++; - } - - // Test 2: 500 new unique members - { - total++; - int M = 500; - long sOps = slow(M); - long fOps = fast(M); - boolean ok = sOps > fOps * 50L; - System.out.printf("Test 2 [M=%d slow=%d fast=%d ratio=%.1fx]: %s%n", - M, sOps, fOps, (double) sOps / fOps, ok ? "PASS" : "FAIL"); - if (ok) passed++; - } - - // Test 3: worst case 300 existing members, 300 duplicates attempted - { - total++; - int M = 300; - long sOps = slowWorstCase(M); - long fOps = fastWorstCase(M); - // slow: avg M/2 per duplicate probe = M²/2 = 45000 - // fast: M = 300 - boolean ok = sOps > fOps * 50L; - System.out.printf("Test 3 worst-case [M=%d slow=%d fast=%d ratio=%.1fx]: %s%n", - M, sOps, fOps, (double) sOps / fOps, ok ? "PASS" : "FAIL"); - if (ok) passed++; - } - - // Test 4: correctness — both produce same deduplicated set - { - total++; - int M = 100; - List slowResult = new ArrayList<>(); - slowResult.add(0); - for (int i = 1; i <= M; i++) { - if (!slowResult.contains(i)) slowResult.add(i); - } - - List fastResult = new ArrayList<>(); - Set fastSet = new HashSet<>(); - fastResult.add(0); - fastSet.add(0); - for (int i = 1; i <= M; i++) { - if (!fastSet.contains(i)) { - fastResult.add(i); - fastSet.add(i); - } - } - - boolean ok = slowResult.equals(fastResult) && slowResult.size() == M + 1; - System.out.printf("Test 4 [correctness M=%d slowSize=%d fastSize=%d equal=%b]: %s%n", - M, slowResult.size(), fastResult.size(), slowResult.equals(fastResult), - ok ? "PASS" : "FAIL"); - if (ok) passed++; - } - - System.out.printf("%d/%d PASS%n", passed, total); - if (passed != total) System.exit(1); - } -}