From 3c3f9639cf4a71eb7e29e8554acca8a35251bfec Mon Sep 17 00:00:00 2001 From: "russell@unturf.com" Date: Tue, 31 Mar 2026 07:48:39 -0400 Subject: [PATCH] undf: assign 908-914; stamp transformers/ray-project/dask-project patches --- UNDF-REGISTRY.json | 9 +- .../patch/dask-project-0001.patch | 1 + .../patch/dask-project-0002.patch | 1 + .../patch/prusaslicer-0001.patch | 21 +++ .../test/PrusaSlicerPresetFamiliesTest.class | Bin 0 -> 3416 bytes .../test/PrusaSlicerPresetFamiliesTest.java | 74 +++++++++++ .../patch/prusaslicer-0002.patch | 33 +++++ ...PrusaSlicerSupportIslandWorklistTest.class | Bin 0 -> 3642 bytes .../PrusaSlicerSupportIslandWorklistTest.java | 120 ++++++++++++++++++ .../patch/prusaslicer-0003.patch | 29 +++++ ...PrusaSlicerCutSurfaceVertexDedupTest.class | Bin 0 -> 3550 bytes .../PrusaSlicerCutSurfaceVertexDedupTest.java | 102 +++++++++++++++ .../ray-project/patch/ray-project-0001.patch | 1 + .../patch/transformers-0001.patch | 1 + 14 files changed, 391 insertions(+), 1 deletion(-) create mode 100644 defects/prusaslicer-0001/patch/prusaslicer-0001.patch create mode 100644 defects/prusaslicer-0001/test/PrusaSlicerPresetFamiliesTest.class create mode 100644 defects/prusaslicer-0001/test/PrusaSlicerPresetFamiliesTest.java create mode 100644 defects/prusaslicer-0002/patch/prusaslicer-0002.patch create mode 100644 defects/prusaslicer-0002/test/PrusaSlicerSupportIslandWorklistTest.class create mode 100644 defects/prusaslicer-0002/test/PrusaSlicerSupportIslandWorklistTest.java create mode 100644 defects/prusaslicer-0003/patch/prusaslicer-0003.patch create mode 100644 defects/prusaslicer-0003/test/PrusaSlicerCutSurfaceVertexDedupTest.class create mode 100644 defects/prusaslicer-0003/test/PrusaSlicerCutSurfaceVertexDedupTest.java diff --git a/UNDF-REGISTRY.json b/UNDF-REGISTRY.json index 8144f43a0..23dfb1c3c 100644 --- a/UNDF-REGISTRY.json +++ b/UNDF-REGISTRY.json @@ -905,5 +905,12 @@ "rpcs3-0001": "UNDF-2026-000000904", "rpcs3-0002": "UNDF-2026-000000905", "rpcs3-0003": "UNDF-2026-000000906", - "weechat-0001-0001": "UNDF-2026-000000907" + "weechat-0001-0001": "UNDF-2026-000000907", + "dask-project-0001": "UNDF-2026-000000908", + "dask-project-0002": "UNDF-2026-000000909", + "prusaslicer-0001-0001": "UNDF-2026-000000910", + "prusaslicer-0002-0002": "UNDF-2026-000000911", + "prusaslicer-0003-0003": "UNDF-2026-000000912", + "ray-project-0001": "UNDF-2026-000000913", + "transformers-0001": "UNDF-2026-000000914" } diff --git a/defects/dask-project/patch/dask-project-0001.patch b/defects/dask-project/patch/dask-project-0001.patch index 6ca3576c6..e266fd5be 100644 --- a/defects/dask-project/patch/dask-project-0001.patch +++ b/defects/dask-project/patch/dask-project-0001.patch @@ -1,3 +1,4 @@ +# UNDF: UNDF-2026-000000908 # dask-project-0001: parquet/core.py filter_partitions disjunction O(P×O) dedup # CWE-407 — Algorithmic Complexity # diff --git a/defects/dask-project/patch/dask-project-0002.patch b/defects/dask-project/patch/dask-project-0002.patch index b49bf7beb..a235bb0fa 100644 --- a/defects/dask-project/patch/dask-project-0002.patch +++ b/defects/dask-project/patch/dask-project-0002.patch @@ -1,3 +1,4 @@ +# UNDF: UNDF-2026-000000909 # dask-project-0002: methods.py describe_aggregate column name dedup O(C²) # CWE-407 — Algorithmic Complexity # diff --git a/defects/prusaslicer-0001/patch/prusaslicer-0001.patch b/defects/prusaslicer-0001/patch/prusaslicer-0001.patch new file mode 100644 index 000000000..718a69fa0 --- /dev/null +++ b/defects/prusaslicer-0001/patch/prusaslicer-0001.patch @@ -0,0 +1,21 @@ +# UNDF: UNDF-2026-000000910 +--- a/src/libslic3r/Preset.cpp ++++ b/src/libslic3r/Preset.cpp +@@ -259,14 +259,14 @@ + std::vector VendorProfile::families() const + { + std::vector res; +- unsigned num_familiies = 0; ++ std::unordered_set seen; + + for (auto &model : models) { +- if (std::find(res.begin(), res.end(), model.family) == res.end()) { ++ if (seen.insert(model.family).second) { + res.push_back(model.family); +- num_familiies++; + } + } + + return res; + } ++// include required diff --git a/defects/prusaslicer-0001/test/PrusaSlicerPresetFamiliesTest.class b/defects/prusaslicer-0001/test/PrusaSlicerPresetFamiliesTest.class new file mode 100644 index 0000000000000000000000000000000000000000..154ed1ad66cd9ad0df0c2c1d8e243eb7609a0bae GIT binary patch literal 3416 zcmb7GS#TUj8UA{&8SRdBY;>&T$c!DymUa5Vjt)DLb=b03vYZuG6hmON+mgoGo!QLH z3MmyJfVo1r12Kj`Vh(cz3PP1F%N5{>2VQuhimE)p11}UWypaN#zk7D2m8GPLt=j4C z>A(N}{;$9PpZ?><`fmXY;g?Ya5L6J-5JrTd`kJw9^kfZdq36=vHJFfEs%uFVHm?m%o6!+s41gmKWwWE8Y8)NDaKZ@7yoPETIY3RoQL-UkVaE(;fOmk<-;V$>ajGUP@xjW6p zIn~S;ha-HRG+-`sh66=PBn;`a`~Ww1IiukTvBjQ}i!pPBXDVp_Aq{6SOzLSdT$ekZ zX$a2OP6aOGNd+kl)A&G%ehDD8 z>Uum!hh!IsraGTy)9#rfEqSCUZsdsTCd_Df3bQ2DWg}bQm*yD`?xv`+lk?@+AE&Im zs^Nq95JN-GSmMLBl{UN?(_5sT>lv0ur@zfvab@u|e3(+(gyh5chyp{y9MYw<-Hw(Z z<^}ew^$=GjuUFz=-~tf^QP(!U>o%9MsKLZF$|1|J>}fMcf}!NR5E<&e{sM&r6|}*r zsi9O#&y+OPr?++=o!4`2r#>%4QZ}X{VcPz9rPYcek7pG)f>esWtVWI41(J^dHc}4E ze=XxLXjsNaNl`LPieaGqAc|4GdkSr5t6#+`2{LIo3tT73JS4oxpa_+IaVn}G6P$f~ z2ejgjDqf)E7x4?Zd`iQoah*WU+YU*Xq4)m+S$^hm1aVcx=ZL1EWKy3VO--kC!Tab) z6kouL3cje}B~e?ew(@E?ODRb;Im2Dk;hD`eOL>M@po!41ogtR1lBUHc3%NP&OpCOo zEGLWf(u9#Ojw@2;f<-0=(*K)E z(2wQ3VP&%1ZAsepQX${J^K8oAY+E?Jn&-Qim$UC*9ZF{_bOmZMhpQAQJZSQ?3vv*OEY`=#n!$jvjR5N@V2dGoe@Ov~( zc68mtqXFDRO!V{sW^O-tyW>~1I3V3O(FQ;jxv!?{L=8HrWSpQY&neX5D{?0IUsNfG zDX3|AhZcQRF8vxUpsy>91)i6v4O2T(!gC*w5w6w=AJ-)9EOE6`$H&zd>TC?%!@&Td z)jC91m(c!F25lc*L66gu zZ({H!8afI8h#+&%eVm((kKe_`-^rPyojcr;pQ4*>YbO0QQ(bGgvW};LJ9wsMQa>3g zQr8y_o{ZE*>O!~B+!z*}a5le=4B%6AJ;H83_?xte+(KPrm>|xG=jj$d z&) familiesDefective(List modelFamilies) { + List res = new ArrayList<>(); + for (String family : modelFamilies) { + if (!res.contains(family)) { // O(N) scan per iteration + res.add(family); + } + } + return res; + } + + // --- FIXED: O(N) hash set for dedup --- + static List familiesFixed(List modelFamilies) { + List res = new ArrayList<>(); + Set seen = new HashSet<>(); + for (String family : modelFamilies) { + if (seen.add(family)) { // O(1) amortized + res.add(family); + } + } + return res; + } + + public static void main(String[] args) { + // Correctness test + List small = Arrays.asList("MK3S", "MINI", "MK3S", "XL", "MINI", "XL", "MK4"); + List defResult = familiesDefective(small); + List fixResult = familiesFixed(small); + assert defResult.equals(fixResult) : "Results must match"; + assert defResult.equals(Arrays.asList("MK3S", "MINI", "XL", "MK4")) : "Dedup must preserve order"; + System.out.println("PASS correctness: " + fixResult); + + // Performance test: N models with N/2 unique families + int N = 20_000; + List models = new ArrayList<>(); + for (int i = 0; i < N; i++) { + models.add("family-" + (i % (N / 2))); + } + + // Warmup + for (int i = 0; i < 3; i++) { + familiesDefective(models); + familiesFixed(models); + } + + long t0 = System.nanoTime(); + List rDef = familiesDefective(models); + long t1 = System.nanoTime(); + List rFix = familiesFixed(models); + long t2 = System.nanoTime(); + + double defMs = (t1 - t0) / 1e6; + double fixMs = (t2 - t1) / 1e6; + double ratio = defMs / fixMs; + + System.out.printf("PASS defective: %.1f ms, fixed: %.1f ms, ratio: %.1fx%n", defMs, fixMs, ratio); + assert rDef.equals(rFix) : "Large results must match"; + assert ratio > 2.0 : "Fixed should be at least 2x faster, got " + ratio + "x"; + System.out.println("PASS performance: ratio " + String.format("%.1f", ratio) + "x"); + System.out.println("ALL TESTS PASSED"); + } +} diff --git a/defects/prusaslicer-0002/patch/prusaslicer-0002.patch b/defects/prusaslicer-0002/patch/prusaslicer-0002.patch new file mode 100644 index 000000000..d39741cc9 --- /dev/null +++ b/defects/prusaslicer-0002/patch/prusaslicer-0002.patch @@ -0,0 +1,33 @@ +# UNDF: UNDF-2026-000000911 +--- a/src/libslic3r/SLA/SupportIslands/UniformSupportIsland.cpp ++++ b/src/libslic3r/SLA/SupportIslands/UniformSupportIsland.cpp +@@ -1994,7 +1994,8 @@ + // Queue of island nodes to propagate shortest distance into their neigbors + // contain indices into node_distances + std::vector process; ++ std::unordered_set process_set; + for (size_t i = 1; i < node_distances.size(); i++) process.push_back(i); // zero index is start ++ for (size_t i = 1; i < node_distances.size(); i++) process_set.insert(i); + size_t next_distance_index = 0; // zero index is start + size_t current_node_distance_index = -1; +@@ -2049,8 +2050,8 @@ + size_t item_index = node_distance_it - node_distances.begin(); + // process store unique indices into node_distances +- if(std::find(process.begin(), process.end(), item_index) != process.end()) ++ if(process_set.count(item_index)) + continue; // already in process + + if (next_distance_index < node_distances.size()) +- process.push_back(next_distance_index); // store for next processing ++ { ++ process.push_back(next_distance_index); ++ process_set.insert(next_distance_index); ++ } + next_distance_index = item_index; +@@ -2060,6 +2061,7 @@ + if (process.empty()) + break; // no more nodes to process + next_distance_index = process.back(); + process.pop_back(); ++ process_set.erase(next_distance_index); + prev_neighbor = nullptr; // do not know previous neighbor diff --git a/defects/prusaslicer-0002/test/PrusaSlicerSupportIslandWorklistTest.class b/defects/prusaslicer-0002/test/PrusaSlicerSupportIslandWorklistTest.class new file mode 100644 index 0000000000000000000000000000000000000000..f9aa53a390569a184eb62ad9e23e76bc6772635d GIT binary patch literal 3642 zcmb7HYj6|S75=WY4{5!CZM;UtKo_v74YC~`5y5r{4(1_Z9z_OYoCem?+ANlKmEDyw zNt4i)Hjg%aHxEdf;69wDbUICDz(7MglbQbLkG8+tnReRg^iQY%TPB2_yDQmpaXYO& zvwQd4bI(2JJKs6?>Q^7%ybYiaR~1AMl_97QAu-gRH71R&ykU=b9UeVvW_<>!*Rm~t zCquNY{kV)6!}36>Cl)S+I+aup5G7?#fO#kV0Zj9iXEYpYrsdfL-|lCNE%BEc8NvX1Q= zmhExjN)^pmMY~(xobP5AcmO8Cw`4 zBWW4iDme*E9X0HnQxGY2{BNUzt$2uMZU+U>cA)(@7xbv;#lsYiVsMyQREve}3wWiEmoc7wUB8>w?mKMYFOxL#@+v~SHV>EA4{@6(w0}P4z z{P$I~_PDO&)>C+gR2;?;h7|>4!rblHS;HT){4+H2e8cv=fI;sS zGXH@n$KyB#;_{G+6Bw=_9I!rf-t)}@5y2@@_*%#^%jr5omVL5s8ik&EFpO~L9>0$l za~?c_Q!-AgFfdvvn1xmd$0E0xxBtz_vI(BdW5}s6LB$fY4ci&C3L!-gNPV3bFAzkC z;Vi@UBYl~So~vZ2TW{^$Jf;`Cq&~*8QT6Q_l!x$ps?}DIM?r?o%hg$cLcdd@JaNbR zt7|kA6TVO2Nfjwah7Aew25tVlFVCb)&+R-@Wjnu9G#X#&desDcQbW zD0%cS{Op--o#~UF&SJRCus+~&)^S~GH#RNk){Ap1nQjvlWbjRfjX|f;y)#ZJpVLQ8 z-SG9iX^_z^Q~DUaO*g5JJHF1QVt9*TWnj2yx&bHbtl6yx)j;#hBwSH2jql3%9#8f6 zsXfl8$Fe7#39~DNFKk15jjZpubc(!I&4{vM81;T?rFqk98E~A5Qn9D15XyO|k}Oy_ zc)n;ZqF$Y@%6WIciQPs%pRs(ihe1u-w&@1kGCdjZFtpwm(_*g5c$Z<#e^;f-3gg0B z>huw+TUMLk?Vd&=HAlKi(DO_5wVK|HOE+Ez`zcq%m+8r;0hQVp9Y!=JRhFhoQ%L%g zTabsZBYsfWxq9U^8j`DLq1-@i1Vb02Z06qIqdTK1K@(D9Bqfk!lO}HImYSs7DLI;o zX)#TnMsJg(#X3{*q!terH%9O}q#3Nygv-!0f$T0zYQmghEl#FlWc)*}5GREzXieTg z6ARa^O47$_Dy-ZMtc~CosJVvLlrVGe>D5=sDJ+q);W?rLnrqN5DTCXTj1fc%lLj;2ISOi7WHNTN-ew53~al5eMC(NtWEYq4qUZ<4imXG-bN zlmODsGTa+A@iNwGBJI+g)WkWsJIZ6ei>8p-IPG+uE5}Ls3LdP2KDj9La)%}d=DN5E zIVH~AJEaNpxfnwe#oR$ibW%pT=<5MOcQgHWVLM%ty0Hxp)2NS7?#B-7Ll3ef@rlpR zVHXjy53dr2mq~tw(7Z|-v)GSc6U%=`JpTg*@FyG$^0X7`$5>7&k&&cSt-lK~OqEhj z6_+o_*1Gv@wMG!f*YNc)TagyJMiYzJfjarOz0DtB^TAu#I^2K_%kIFO-Y)hiPLBz$rc(4!f8!9-CR6;Q6gyn8l>`<&BG#Dk>QBe90Yk)+6U2mJ%J2ysBKaU)aYk?oqd1KVbcuTzIlMwwu{SVA2SpC=z@j=m zi}x`>yvXA=3iuEXeuE-@k0J^m^yDey?KwbSK*YL$lkcAlt z(f6@$KJZGn$H-hJP@B^AxXl@2S#E;PQ EFa11d7XSbN literal 0 HcmV?d00001 diff --git a/defects/prusaslicer-0002/test/PrusaSlicerSupportIslandWorklistTest.java b/defects/prusaslicer-0002/test/PrusaSlicerSupportIslandWorklistTest.java new file mode 100644 index 000000000..e5ce52fe6 --- /dev/null +++ b/defects/prusaslicer-0002/test/PrusaSlicerSupportIslandWorklistTest.java @@ -0,0 +1,120 @@ +import java.util.*; + +/** + * Unit test for PrusaSlicer CWE-407 defect prusaslicer-0002: + * UniformSupportIsland graph traversal uses std::find on a worklist vector + * to check membership before adding nodes, resulting in O(N^2) overall. + * Fix: maintain a parallel unordered_set for O(1) membership checks. + * + * Defect location: src/libslic3r/SLA/SupportIslands/UniformSupportIsland.cpp + * Pattern: std::find(process.begin(), process.end(), item_index) in while-true graph loop + */ +public class PrusaSlicerSupportIslandWorklistTest { + + // --- DEFECTIVE: O(N^2) worklist with linear membership check --- + static int traverseDefective(int nodeCount, int[][] neighbors) { + List process = new ArrayList<>(); + for (int i = 1; i < nodeCount; i++) process.add(i); + int processed = 0; + int nextIdx = 0; + + while (true) { + int current = nextIdx; + nextIdx = -1; + processed++; + + for (int neighbor : neighbors[current]) { + // Check if already in process — O(N) linear scan + if (process.contains(neighbor)) continue; + + if (nextIdx >= 0 && nextIdx < nodeCount) + process.add(nextIdx); + nextIdx = neighbor; + } + + if (nextIdx < 0 || nextIdx >= nodeCount) { + if (process.isEmpty()) break; + nextIdx = process.remove(process.size() - 1); + } + } + return processed; + } + + // --- FIXED: O(N) worklist with hash set membership --- + static int traverseFixed(int nodeCount, int[][] neighbors) { + List process = new ArrayList<>(); + Set processSet = new HashSet<>(); + for (int i = 1; i < nodeCount; i++) { + process.add(i); + processSet.add(i); + } + int processed = 0; + int nextIdx = 0; + + while (true) { + int current = nextIdx; + nextIdx = -1; + processed++; + + for (int neighbor : neighbors[current]) { + // Check if already in process — O(1) hash lookup + if (processSet.contains(neighbor)) continue; + + if (nextIdx >= 0 && nextIdx < nodeCount) { + process.add(nextIdx); + processSet.add(nextIdx); + } + nextIdx = neighbor; + } + + if (nextIdx < 0 || nextIdx >= nodeCount) { + if (process.isEmpty()) break; + int removed = process.remove(process.size() - 1); + processSet.remove(removed); + nextIdx = removed; + } + } + return processed; + } + + public static void main(String[] args) { + // Build a graph: chain with some back edges (simulates Voronoi island graph) + int N = 2000; + int[][] neighbors = new int[N][]; + Random rng = new Random(42); + for (int i = 0; i < N; i++) { + int degree = 2 + rng.nextInt(3); + neighbors[i] = new int[degree]; + for (int d = 0; d < degree; d++) { + neighbors[i][d] = (i + 1 + d) % N; + } + } + + // Correctness + int rDef = traverseDefective(N, neighbors); + int rFix = traverseFixed(N, neighbors); + assert rDef == rFix : "Processed count must match: " + rDef + " vs " + rFix; + System.out.println("PASS correctness: processed " + rFix + " nodes"); + + // Warmup + for (int i = 0; i < 3; i++) { + traverseDefective(N, neighbors); + traverseFixed(N, neighbors); + } + + long t0 = System.nanoTime(); + traverseDefective(N, neighbors); + long t1 = System.nanoTime(); + traverseFixed(N, neighbors); + long t2 = System.nanoTime(); + + double defMs = (t1 - t0) / 1e6; + double fixMs = (t2 - t1) / 1e6; + double ratio = defMs / fixMs; + + System.out.printf("PASS defective: %.1f ms, fixed: %.1f ms, ratio: %.1fx%n", defMs, fixMs, ratio); + assert ratio > 2.0 : "Fixed should be at least 2x faster, got " + ratio + "x"; + System.out.println("PASS performance: ratio " + String.format("%.1f", ratio) + "x"); + System.out.println("ALL TESTS PASSED"); + } +} diff --git a/defects/prusaslicer-0003/patch/prusaslicer-0003.patch b/defects/prusaslicer-0003/patch/prusaslicer-0003.patch new file mode 100644 index 000000000..e78f8d768 --- /dev/null +++ b/defects/prusaslicer-0003/patch/prusaslicer-0003.patch @@ -0,0 +1,29 @@ +# UNDF: UNDF-2026-000000912 +--- a/src/libslic3r/CutSurface.cpp ++++ b/src/libslic3r/CutSurface.cpp +@@ -3758,6 +3758,7 @@ + indexed_triangle_set priv::create_indexed_triangle_set( + const std::vector &faces, const CutMesh &mesh) + { ++ std::unordered_map vertex_map; // VI index -> position in vertices vector + std::vector vertices; + vertices.reserve(faces.size() * 2); + +@@ -3773,8 +3774,13 @@ + do { + VI vi = mesh.source(hi); +- auto res = std::find(vertices.begin(), vertices.end(), vi); +- t[ti++] = res - vertices.begin(); +- if (res == vertices.end()) vertices.push_back(vi); ++ uint32_t vi_idx = static_cast(vi); ++ auto it = vertex_map.find(vi_idx); ++ if (it != vertex_map.end()) { ++ t[ti++] = it->second; ++ } else { ++ int pos = static_cast(vertices.size()); ++ vertex_map[vi_idx] = pos; ++ vertices.push_back(vi); ++ t[ti++] = pos; ++ } + hi = mesh.next(hi); + } while (hi != hi_end); diff --git a/defects/prusaslicer-0003/test/PrusaSlicerCutSurfaceVertexDedupTest.class b/defects/prusaslicer-0003/test/PrusaSlicerCutSurfaceVertexDedupTest.class new file mode 100644 index 0000000000000000000000000000000000000000..fbd7af9000335b0a95cfa69a85b0ac67feff4481 GIT binary patch literal 3550 zcmb7HZFCe@8Gi2W%+6$(kYvduyHIdj6G%cxO27a~q=bAlp<kn2=DhliizS$nMN` zW|ju5iW(_x{r)PV)fTPvc#a<1o&y0a)*l`{{^>9O`paMX$3LFag9yHNb~gzm^=Qu7 znfvj+ci!iDpZDIIKi#`|8$d7K(hx#efuuu5grWMhdB$wdn)Yn_==5ox_8B5QmTmb5 z8NyA?;|f%UO@UFtx3cZMu4|r6TAr^#5$kLqvy&%>HB@4wf+`)=s9~sCS#{X<`7C!C zlrv_wz(;2o>Y9d|lWQ!xH((QL6&O0|P|vV&<)h+zw18!2_<~r#XjK~XmWFkPnkjdK46zkS^_D+B;JS{h zVu*kp=UyS}dx>1Z^AkDKPtR!>z!6agPkn?Y#w##_qY6fK9K+M)fP-R5o%MX4qYOGC zgGMn<%V|I6QXW!1k(ldNks_aCy{S|p?YJ(nX>-rh@F`GPP3Sm*$#QKy=t)}7i*>U0 zLxIu4mOa}o%JO76oPfXMrk!zeGL^XaYtb-;&j@7CQYkbYX&%=I$h3|$C=aS_+Rm7j zE7r%6NN?NXdEupEjz~(^wI*hS23GZ5ld@mz zFErX3vdAg0#rEKo0}puYcM7Bq0keO#z>CA(f~)6rxF9t|0!pa*dsdfAiIMeGv2IQx zhXhpmi_-6T9Sb$#MnS;ER_&> z8|c??5icotS;s5*Dnr#u!SrRRVrgg2aL;miX1RV+zUdcef{ubIg52k1C|6ZU%jQQ5 zxoPf>iQ1+Ok?hj*v=^58QqHtUyLAr~a5-8M?{`S|t5a5*B5n4hv!&BVOF0EM%?B;< zf#&~Z_i7V(2=-ye@jc%)^CR4!b26TaA2758yHvuPa|+o^VwxvRKau4o?FAhRi5Yrx zw>2^A_zAY4;)e{I1F7e^8|2SU^R7goX_~K!;57|D#!nQyF4FP_?XD|STJ{-dp0^hv z6-6~@rhUgHp3)2q}rYi_Aa|_DkbyOr6^w>EB}0l_!J(F|9fs7_DepAoCFnO04WTn)L_)8le&-Fu81>3ikAyJMD$I?@ z=%U1~-hY2FOwYGle@$Ns1+jF}p$ocdsHmmgtPU~M6Ra4T5vS-jqX%2ik4Nal*hV{i zJx-BLhAh58URxmFLsY>g1sc0cSF3+xFJm8~@(yvJigUFHj>!a0C5MZ*kRWi6B}*Vj zN+6F0-~`OsaHnj@1oK3TA$1sXn*b9DaDF_5_fgrU#FamwsWm`K<6TN|KCawAbC}?k ztOfL4!4h%h8g`8?$^`tafP_oCR^T5*6~(okqT506n+SLd9;4d~-Dj{Dy9jz4hUrQ& zhQ~3D-LNU+=Vex{of_;Wc6BTjAP&>j#g%Qb*25rfxke*%c$wq}7^cGd(`Hz7& zWzmQ$6w!ou?w<&z{=NirpBfBzX`;O$nCz+)?TvLC>Qw%6Ex2=_x{i9Kb~IKUi#i8t z15ovGEl$?Uux87!tjK!^O@?FDOPD7DW6|I($7;p<8uAl?`<7U3E&NwsLsXCwtG$Uc zKzWICQgMmEWeG3b#FqeKOR)A8dW#w^*3AW~0ic^MA_s9CPhf&BgAV;i@;piA1-gk{ z#30qzlXw+Fcmqdp6;I(^B=I})_<+X#jHmGz^871O_#3tVfpPqkR=JB4jL}U>#T2W= zGc1lzvqqd^t#tVrgvsVH&0a#9y-9bUUxEh$JO$+*oIrl0K4)gR#rFc{zE6Ar8;Qdo(K?rc=Ve@>F^&2^#hb)a{6B03WL^LO literal 0 HcmV?d00001 diff --git a/defects/prusaslicer-0003/test/PrusaSlicerCutSurfaceVertexDedupTest.java b/defects/prusaslicer-0003/test/PrusaSlicerCutSurfaceVertexDedupTest.java new file mode 100644 index 000000000..1fffbbaea --- /dev/null +++ b/defects/prusaslicer-0003/test/PrusaSlicerCutSurfaceVertexDedupTest.java @@ -0,0 +1,102 @@ +import java.util.*; + +/** + * Unit test for PrusaSlicer CWE-407 defect prusaslicer-0003: + * create_indexed_triangle_set uses std::find on a growing vertices vector + * to deduplicate vertex indices when building triangle sets from cut faces. + * O(F * V) where F = faces, V = unique vertices (~2F). Fix: use unordered_map. + * + * Defect location: src/libslic3r/CutSurface.cpp priv::create_indexed_triangle_set() + * Pattern: std::find(vertices.begin(), vertices.end(), vi) inside face iteration loop + */ +public class PrusaSlicerCutSurfaceVertexDedupTest { + + // Simulate creating indexed triangle set from face data + // Each face has 3 vertex indices; many are shared between faces + + // --- DEFECTIVE: O(F * V) linear scan for vertex dedup --- + static int[][] createITSDefective(int[][] faces) { + List vertices = new ArrayList<>(); + int[][] indices = new int[faces.length][3]; + + for (int f = 0; f < faces.length; f++) { + for (int v = 0; v < 3; v++) { + int vi = faces[f][v]; + int pos = vertices.indexOf(vi); // O(V) linear scan + if (pos == -1) { + pos = vertices.size(); + vertices.add(vi); + } + indices[f][v] = pos; + } + } + return indices; + } + + // --- FIXED: O(F) with hash map for vertex dedup --- + static int[][] createITSFixed(int[][] faces) { + Map vertexMap = new HashMap<>(); + List vertices = new ArrayList<>(); + int[][] indices = new int[faces.length][3]; + + for (int f = 0; f < faces.length; f++) { + for (int v = 0; v < 3; v++) { + int vi = faces[f][v]; + Integer pos = vertexMap.get(vi); // O(1) hash lookup + if (pos == null) { + pos = vertices.size(); + vertexMap.put(vi, pos); + vertices.add(vi); + } + indices[f][v] = pos; + } + } + return indices; + } + + public static void main(String[] args) { + // Correctness test with small mesh + int[][] smallFaces = { + {0, 1, 2}, {1, 2, 3}, {2, 3, 4}, {0, 2, 4} + }; + int[][] rDef = createITSDefective(smallFaces); + int[][] rFix = createITSFixed(smallFaces); + assert Arrays.deepEquals(rDef, rFix) : "Results must match"; + System.out.println("PASS correctness"); + + // Performance test: mesh with F faces, ~2F unique vertices + int F = 20_000; + Random rng = new Random(42); + int maxVertex = F * 2; + int[][] faces = new int[F][3]; + for (int f = 0; f < F; f++) { + // Simulate shared vertices between adjacent faces + int base = f * 2; + faces[f][0] = base % maxVertex; + faces[f][1] = (base + 1) % maxVertex; + faces[f][2] = (base + 2) % maxVertex; + } + + // Warmup + for (int i = 0; i < 3; i++) { + createITSDefective(faces); + createITSFixed(faces); + } + + long t0 = System.nanoTime(); + int[][] defResult = createITSDefective(faces); + long t1 = System.nanoTime(); + int[][] fixResult = createITSFixed(faces); + long t2 = System.nanoTime(); + + double defMs = (t1 - t0) / 1e6; + double fixMs = (t2 - t1) / 1e6; + double ratio = defMs / fixMs; + + assert Arrays.deepEquals(defResult, fixResult) : "Large results must match"; + System.out.printf("PASS defective: %.1f ms, fixed: %.1f ms, ratio: %.1fx%n", defMs, fixMs, ratio); + assert ratio > 2.0 : "Fixed should be at least 2x faster, got " + ratio + "x"; + System.out.println("PASS performance: ratio " + String.format("%.1f", ratio) + "x"); + System.out.println("ALL TESTS PASSED"); + } +} diff --git a/defects/ray-project/patch/ray-project-0001.patch b/defects/ray-project/patch/ray-project-0001.patch index 9bb4660a1..0efd90945 100644 --- a/defects/ray-project/patch/ray-project-0001.patch +++ b/defects/ray-project/patch/ray-project-0001.patch @@ -1,3 +1,4 @@ +# UNDF: UNDF-2026-000000913 # ray-project-0001: dag_node.py _get_toplevel_child_nodes O(A²) dedup # CWE-407 — Algorithmic Complexity # diff --git a/defects/transformers/patch/transformers-0001.patch b/defects/transformers/patch/transformers-0001.patch index 64b5ada84..6d0c604db 100644 --- a/defects/transformers/patch/transformers-0001.patch +++ b/defects/transformers/patch/transformers-0001.patch @@ -1,3 +1,4 @@ +# UNDF: UNDF-2026-000000914 # transformers-0001: tokenization_python.py convert_ids_to_tokens O(T×S) # CWE-407 — Algorithmic Complexity #