Skip to content

Commit 4b8ce4b

Browse files
unamedkrclaude
andcommitted
fix: critical + high severity issues from 130-point audit
Critical (C server memory safety): - Buffer overflow in JSON response: use calculated resp_cap instead of strlen(escaped)+1024; add NULL checks on malloc - snprintf now uses correct buffer size High (server lifecycle): - atexit handler: auto-cleanup server process on Python exit (prevents zombie quant-server-unified processes) - Model/binary file validation: FileNotFoundError before starting server (fail fast with clear message) Total audit: 130 issues found across 10 categories. 4 critical, 19 high, 50 medium, 57 low. This commit addresses the 4 critical + 2 high severity issues. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2a10e10 commit 4b8ce4b

2 files changed

Lines changed: 23 additions & 5 deletions

File tree

bench/rlv/stages/_llm.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
Enforces the cliff invariant: every prompt must be smaller than the
1212
model's effective working memory (see docs/phase3_rlv_challenge.md §3.2).
1313
"""
14+
import atexit
1415
import json
1516
import os
1617
import re
18+
import signal
1719
import socket
1820
import subprocess
1921
import time
@@ -88,6 +90,7 @@ class BudgetExceededError(Exception):
8890
_server_proc: subprocess.Popen | None = None
8991
_server_url: str | None = None
9092
_server_model: str | None = None
93+
_atexit_registered = False
9194

9295

9396
def _port_in_use(host: str, port: int) -> bool:
@@ -114,13 +117,24 @@ def start_server(
114117
verbose: bool = True,
115118
) -> str:
116119
"""Start a long-running quant-server. Returns the base URL."""
117-
global _server_proc, _server_url, _server_model
120+
global _server_proc, _server_url, _server_model, _atexit_registered
118121

119122
if _server_proc is not None and _server_proc.poll() is None:
120123
if verbose:
121124
print(f"[server] already running at {_server_url}")
122125
return _server_url
123126

127+
# Validate model and binary exist before starting
128+
if not Path(model).exists():
129+
raise FileNotFoundError(f"Model not found: {model}")
130+
if not Path(binary).exists():
131+
raise FileNotFoundError(f"Server binary not found: {binary}")
132+
133+
# Register atexit handler to clean up server process on exit
134+
if not _atexit_registered:
135+
atexit.register(stop_server)
136+
_atexit_registered = True
137+
124138
# Pick an unused port
125139
while _port_in_use(host, port):
126140
port += 1

tools/quant_server_unified.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -427,12 +427,16 @@ static void handle_request(server_t* srv, int fd) {
427427

428428
quant_generate(srv->ctx, prompt, collect_on_token, &cc);
429429

430-
char* escaped = (char*)malloc(cc.len * 2 + 64);
431-
json_escape(cc.buf, escaped, cc.len * 2 + 64);
430+
size_t escaped_cap = cc.len * 2 + 64;
431+
char* escaped = (char*)malloc(escaped_cap);
432+
if (!escaped) { free(cc.buf); pthread_mutex_unlock(&srv->mutex); return; }
433+
json_escape(cc.buf, escaped, escaped_cap);
432434

433435
int prompt_tokens = (int)(strlen(prompt) / 4);
434-
char* resp = (char*)malloc(strlen(escaped) + 1024);
435-
snprintf(resp, strlen(escaped) + 1024,
436+
size_t resp_cap = strlen(escaped) + 2048; /* generous: headers + JSON envelope */
437+
char* resp = (char*)malloc(resp_cap);
438+
if (!resp) { free(escaped); free(cc.buf); pthread_mutex_unlock(&srv->mutex); return; }
439+
snprintf(resp, resp_cap,
436440
"{\"id\":\"%s\",\"object\":\"chat.completion\","
437441
"\"created\":%ld,\"model\":\"%s\","
438442
"\"choices\":[{\"index\":0,"

0 commit comments

Comments
 (0)