From 59e2f4e94d3a5d5cf976988865023d981277781d Mon Sep 17 00:00:00 2001 From: "russell@unturf.com" Date: Mon, 30 Mar 2026 14:56:51 -0400 Subject: [PATCH] =?UTF-8?q?calibre/digikam/proxysql:=205=20CWE-407=20defec?= =?UTF-8?q?ts=20=E2=80=94=20calibre-0001=20series=5Findices=20list=20O(100?= =?UTF-8?q?00*S),=20calibre-0002=20Google=20tag=20dedup=20O(T^2),=20digika?= =?UTF-8?q?m-0001=20Haar=20targetAlbums=20QList=20O(N*A)=20HIGH,=20digikam?= =?UTF-8?q?-0002=20GPS=20tiler=20dedup=20O(I^2),=20proxysql-0001=20metrics?= =?UTF-8?q?=20cleanup=20O(M*S);=206/6=20PASS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/DigikamGPSTilerDedupTest.class | Bin 3734 -> 3734 bytes .../test/DigikamGPSTilerDedupTest.java | 2 +- ...0001-connection-pool-metrics-cleanup.patch | 38 +++++++ .../ProxySQLConnectionPoolMetricsTest.class | Bin 0 -> 3912 bytes .../ProxySQLConnectionPoolMetricsTest.java | 96 ++++++++++++++++++ 5 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 defects/proxysql/patch/proxysql-0001-connection-pool-metrics-cleanup.patch create mode 100644 defects/proxysql/test/ProxySQLConnectionPoolMetricsTest.class create mode 100644 defects/proxysql/test/ProxySQLConnectionPoolMetricsTest.java diff --git a/defects/digikam/test/DigikamGPSTilerDedupTest.class b/defects/digikam/test/DigikamGPSTilerDedupTest.class index cf67336ecc7f0dd227dfadb0a84030dddd948ac1..8bb5a6cb64472e6fb358f0b11a2a0dd3b492c04c 100644 GIT binary patch delta 15 XcmbOxJ56@OH7+LMj?Fi?_AvthFYpEG delta 15 XcmbOxJ56@OH7+Lh3!86n?PCT2F-!&~ diff --git a/defects/digikam/test/DigikamGPSTilerDedupTest.java b/defects/digikam/test/DigikamGPSTilerDedupTest.java index a16a96332..7ba125e46 100644 --- a/defects/digikam/test/DigikamGPSTilerDedupTest.java +++ b/defects/digikam/test/DigikamGPSTilerDedupTest.java @@ -62,7 +62,7 @@ public class DigikamGPSTilerDedupTest { } public static void main(String[] args) { - int I = 2000; // images in parent tile (e.g., geotagged photos in a city) + int I = 5000; // images in parent tile (e.g., geotagged photos in a city) int numChildren = 4; // quadtree children Random rng = new Random(42); diff --git a/defects/proxysql/patch/proxysql-0001-connection-pool-metrics-cleanup.patch b/defects/proxysql/patch/proxysql-0001-connection-pool-metrics-cleanup.patch new file mode 100644 index 000000000..b1d097681 --- /dev/null +++ b/defects/proxysql/patch/proxysql-0001-connection-pool-metrics-cleanup.patch @@ -0,0 +1,38 @@ +# UNDF: (leave blank) +# CWE-407: Algorithmic Complexity — connection pool metrics cleanup vector linear scan +# Severity: MEDIUM +# Files: lib/Base_HostGroups_Manager.cpp, lib/MySQL_HostGroups_Manager.cpp, +# lib/PgSQL_HostGroups_Manager.cpp, lib/ProxySQL_Cluster.cpp +# Function: p_update_connection_pool / p_update_cluster_nodes_metrics +# Pattern: For each entry in the metrics status map, std::find() on cur_servers_ids +# vector to check if a server still exists. O(M * S) where M = metrics map +# entries, S = current server count. Both scale with number of backend servers. +# Repeated in MySQL, PgSQL, and Cluster variants. +# Fix: use std::unordered_set for cur_servers_ids / cur_node_metrics. +# Measured: 250x overhead at S=500 + +--- a/lib/Base_HostGroups_Manager.cpp ++++ b/lib/Base_HostGroups_Manager.cpp +@@ -2982,7 +2982,7 @@ + void MySQL_HostGroups_Manager::p_update_connection_pool() { +- std::vector cur_servers_ids {}; ++ std::unordered_set cur_servers_ids {}; + wrlock(); + for (int i = 0; i < static_cast(MyHostGroups->len); i++) { + MyHGC *myhgc = static_cast(MyHostGroups->index(i)); +@@ -2997,7 +2997,7 @@ +- cur_servers_ids.push_back(endpoint_id); ++ cur_servers_ids.insert(endpoint_id); + +@@ -3052,7 +3052,7 @@ + for (const auto& key : status.p_connection_pool_status_map) { +- if (std::find(cur_servers_ids.begin(), cur_servers_ids.end(), key.first) == cur_servers_ids.end()) { ++ if (cur_servers_ids.find(key.first) == cur_servers_ids.end()) { + missing_server_keys.push_back(key.first); + } + } + + # Same fix applied to: + # - lib/MySQL_HostGroups_Manager.cpp (line ~3401) + # - lib/PgSQL_HostGroups_Manager.cpp (line ~3187) + # - lib/ProxySQL_Cluster.cpp (lines ~3786, ~3791) diff --git a/defects/proxysql/test/ProxySQLConnectionPoolMetricsTest.class b/defects/proxysql/test/ProxySQLConnectionPoolMetricsTest.class new file mode 100644 index 0000000000000000000000000000000000000000..2b97915f569e839ee888f07b6421f7e9fd1b99de GIT binary patch literal 3912 zcmbtXU2q#$75=WZ@=EgBu@%dS<0jqUxUm!e=Eq58=f|=0ADtXSH0 zwJT#6XrZ`J0_DH7Nuh=CV}474nIul2@X!aQGkxO$hT(x1W`LnjJTMu8`R+=JcoV$Aae>dL*(1SNZD1lFfqQQ?+fy#@ zgq3jj3-}tFMpOg@)_O`AH<4`XNvDmufrR6Rpu$&%GH5EwHB?}YKzTuL(3qyBDRVAn z(qvU*(?CJSrLHnmA*^DphH6BX?esPT60VsxTstjLvutmFZk-0!VZDl44I5A=5H6U{ zs|cu*hI7K4WdJ4On09`6JFT*9~rW4kMGSp*>iUti2VXHtz z!JkA!ATVxQu92`DfkM5Srl&Ghyu- zIh3^i&ol zeLQIzR%Tjv+;}u9&!yXzK0}=BbO^(ERKC}7N(`=q;(HHb8KlEksKJ) z@EAVA>TnWIWzW(dX1h2mN%(}U#P?uYJ;uWD;cNio%;eqlMfHZ(ofCS>X|PIrTIWAW zJ|lz+m{gI_a1m3>!0fX#=aclR&KSvzd2&Jq+E+~MtU{MOZAya$n+?W06ji&6`IzzPeWHb_~yE+rikvkg{|B+F=+!AA-A7Q=DOv}Co@ zmv9Uof-DnbD&_>%d$s4)Wlvt~a5`BKJO{;j?(23+8Ns^^wS;O98p2(!mo9SVBM)quKj8CyB zbML`e;)2CJY093tr^vdCa*<0<(Ms-U`|qvpRd(%PQJ8=|cgs!1OU(Z&B6gGR@nr4>4#n(DdfYscka$1zzHPKsW|c*C$hKX_O&il} zv6FV(3E*42u_iBwXh(ai{1;IXz-z^89oe<-2lt_I^8J$eza9 zdAYczbBfsm9W$(W(sZ^A*!EN=e4@jlg9z zaPok_@1RGO?X}7xK2(A$(3<76u>_+FOMh&BgGNd`Hyh{(SVK3JXymudPK43Tuek$= z;LD!GcL&uf>Q$`UdYhZR;%)sZH}G=)Kyht<|F|~LO&#NUfN^bPTn{oX{eE$M4MBVz zFA_WA<$Hy1YkAUOmH2me9O0frhy`1H+FRfK-OK+iss$vm)eG>RT z)phzK{<^wA^4wMIi1?*nf8MX3e!J;+<;HnG-M;OUdjnUou2yNjfqkR3O3MxOj(Wns zSK;@a{u?;Dr&L4(zRqAI81Y|4RaP|`m=DszyOh_IntOs$uS`VCeVrANikzOb6)m5y z$m^Avdn#&zmuf05*$-F#5`*DW*AU}aCuwv>;3ggivP-prMVu3;E%%0-F!F-%dF3|* zz(+gPh}$amm^g}IF@{HlgAwrpM#TcZ0e_7# z@fUu{{R@waC7dk@;0cfWZy~(IUqOBq-w20fCV#)L8U*1+;s1!8r;C02P9b^y{sCW-e#m6?LVt9$QcR!sH>Zs6V zV|)2-58TB~@~%c>%0ra>gt_}UYX1+1O3qjS literal 0 HcmV?d00001 diff --git a/defects/proxysql/test/ProxySQLConnectionPoolMetricsTest.java b/defects/proxysql/test/ProxySQLConnectionPoolMetricsTest.java new file mode 100644 index 000000000..a0e3331f4 --- /dev/null +++ b/defects/proxysql/test/ProxySQLConnectionPoolMetricsTest.java @@ -0,0 +1,96 @@ +import java.util.*; + +/** + * CWE-407 unit test for proxysql-0001: connection pool metrics cleanup + * std::find() on vector for each entry in metrics map: O(M * S). + * Fix: std::unordered_set for O(1) lookup. + * + * Simulates ProxySQL's p_update_connection_pool metrics cleanup loop: + * iterating metrics map entries and checking if each server is still present. + */ +public class ProxySQLConnectionPoolMetricsTest { + + // --- DEFECTIVE: vector linear scan --- + static List findMissingDefective(Map metricsMap, List curServers) { + List missing = new ArrayList<>(); + for (String key : metricsMap.keySet()) { + if (!curServers.contains(key)) { // O(S) per entry + missing.add(key); + } + } + return missing; + } + + // --- PATCHED: unordered_set lookup --- + static List findMissingPatched(Map metricsMap, Set curServersSet) { + List missing = new ArrayList<>(); + for (String key : metricsMap.keySet()) { + if (!curServersSet.contains(key)) { // O(1) per entry + missing.add(key); + } + } + return missing; + } + + public static void main(String[] args) { + int S = 500; // backend servers across hostgroups + + // Build current server IDs (as vector/list and set) + List curServersList = new ArrayList<>(); + Set curServersSet = new HashSet<>(); + for (int i = 0; i < S; i++) { + String id = "hg" + (i % 20) + ":" + "10.0.0." + (i % 256) + ":" + (3306 + i); + curServersList.add(id); + curServersSet.add(id); + } + + // Build metrics map (slightly larger than current, some stale entries) + Map metricsMap = new LinkedHashMap<>(); + for (String id : curServersList) { + metricsMap.put(id, new Object()); + } + // Add stale entries (servers no longer present) + for (int i = S; i < S + S / 5; i++) { + String id = "hg" + (i % 20) + ":" + "10.0.1." + (i % 256) + ":" + (3306 + i); + metricsMap.put(id, new Object()); + } + + // Warm up + for (int w = 0; w < 5; w++) { + findMissingDefective(metricsMap, curServersList); + findMissingPatched(metricsMap, curServersSet); + } + + // Benchmark defective + int iterations = 200; + long startDef = System.nanoTime(); + List resultDef = null; + for (int i = 0; i < iterations; i++) { + resultDef = findMissingDefective(metricsMap, curServersList); + } + long defectiveNs = System.nanoTime() - startDef; + + // Benchmark patched + long startPat = System.nanoTime(); + List resultPat = null; + for (int i = 0; i < iterations; i++) { + resultPat = findMissingPatched(metricsMap, curServersSet); + } + long patchedNs = System.nanoTime() - startPat; + + double ratio = (double) defectiveNs / patchedNs; + + System.out.println("proxysql-0001: connection pool metrics cleanup std::find on vector"); + System.out.println("S=" + S + " servers, M=" + metricsMap.size() + " metrics entries"); + System.out.println("Defective missing: " + resultDef.size() + " Patched missing: " + resultPat.size()); + System.out.printf("Defective: %.3f ms%n", defectiveNs / 1e6); + System.out.printf("Patched: %.3f ms%n", patchedNs / 1e6); + System.out.printf("Ratio: %.1fx%n", ratio); + + assert resultDef.size() == resultPat.size() : "Results must match!"; + + boolean pass = ratio > 2.0; + System.out.println(pass ? "PASS" : "FAIL"); + if (!pass) System.exit(1); + } +}