Add 88 new defect entries to HIGH and MEDIUM tables:
HIGH: mysql-0001/0002, mariadb-0001, redis-0001/0002, valkey-0001/0002, openvpn-0001,
vlc-0001, prometheus-0001, otel-collector-0001, cockroachdb-0001..0004,
tidb-0001..0008, kubernetes-0001/0002, go-0001, kotlin-0002, scala-0001,
allegro5-0001, sdl2-0001, grafana-0001, clickhouse-0001, duckdb-0001,
mongodb-0001, envoy-0001, istio-0001, cilium-0001, linkerd2-0001,
linux-0001/0002/0003, tor-0002/0003, curl-0001, julia-0001, lua-0001,
perl5-0001, nats-0001, spring-0003/0004, tomcat-0001, onos-0002, odl-0002
MEDIUM: helm-0001, mariadb-0002, openssl-0001/0002, memcached-0001,
cassandra-0001..0004, flink-0001, storm-0001/0002, zookeeper-0001..0003,
pip-0001, gradle-0001, nginx-0001, haproxy-0001, caddy-0001, varnish-0001,
ffmpeg-0001, gstreamer-0001, raylib-0001, love2d-0001, php-0001/0002,
r-source-0001, cpython-0002, ruby-0001, rabbitmq-0003/0004, activemq-0001,
ovs-0001, onos-0003, odl-0002, jetty-0001
PDF: 976K
2.2 KiB
2.2 KiB
ruby-0001 — vm_args.c: O(n²) linear keyword-argument matching per call
| Field | Value |
|---|---|
| ID | ruby-0001 |
| Target | Ruby |
| File | vm_args.c |
| Lines | 300–374 |
| CWE | CWE-407 (Algorithmic Complexity) |
| Severity | HIGH |
| Status | PATCHED |
Description
args_setup_kw_parameters() maps passed keyword arguments to formal parameter
slots. For each of the function's key_num acceptable keywords it calls
args_setup_kw_parameters_lookup(), which linearly scans the full
passed_keyword_len array of passed keyword names:
static inline int
args_setup_kw_parameters_lookup(const ID key, VALUE *ptr,
const VALUE *const passed_keywords, VALUE *passed_values,
const int passed_keyword_len)
{
int i;
const VALUE keyname = ID2SYM(key);
for (i=0; i<passed_keyword_len; i++) { // O(passed_keyword_len)
if (keyname == passed_keywords[i]) {
...
return TRUE;
}
}
return FALSE;
}
Called from two loops in args_setup_kw_parameters:
for (i=0; i<req_key_num; i++) {
args_setup_kw_parameters_lookup(acceptable_keywords[i], ...); // O(P)
}
for (di=0; i<key_num; i++, di++) {
args_setup_kw_parameters_lookup(acceptable_keywords[i], ...); // O(P)
}
Total cost: O(key_num × passed_keyword_len). For a method with K keyword params called with P keyword arguments, every call is O(K × P).
Reproduction
# Method with 20 keyword params, called with all 20 named
def wide(a0:, a1:, a2:, a3:, a4:, a5:, a6:, a7:, a8:, a9:,
b0:, b1:, b2:, b3:, b4:, b5:, b6:, b7:, b8:, b9:) end
# Each call: 20 acceptable keywords × 20 passed = 400 linear comparisons
# vs hash: 20 + 20 = 40 operations
Fix
Build a temporary st_table (Ruby's hash) from passed_keywords → index
once before the two loops, then replace args_setup_kw_parameters_lookup with
an O(1) st_lookup. Build cost: O(P). Total: O(K + P).
Complexity
| Metric | Before | After |
|---|---|---|
| Per call (K params, P passed) | O(K × P) | O(K + P) |
| K=P=20 | 400 comparisons | 40 ops |
| Speedup (K=P=20) | 1× | ~10× |
| K=P=100 | 10 000 comparisons | 200 ops |
| Speedup (K=P=100) | 1× | ~50× |