ci: drop sanitizers job; harden test_subagent fake server

test_subagent segfaulted in the Docker runner: the fake SSE handler took
user + strlen(user) - 1 with an empty user string. Guard JSON access and
format the child report with an empty-safe last character. Remove the
sanitizers job entirely (if: false still queued it and blocked the runner).
This commit is contained in:
WHC
2026-10-07 02:27:00 +08:00
parent e5ea869681
commit 420f9b242c
2 changed files with 23 additions and 41 deletions
-31
View File
@@ -49,37 +49,6 @@ jobs:
./cst-agent --workspace "$PWD" --list-sessions ./cst-agent --workspace "$PWD" --list-sessions
./cst-agent --demo-ctl --workspace . ./cst-agent --demo-ctl --workspace .
# Disabled: Docker runner lacks SYS_PTRACE; ASan spins on DEADLYSIGNAL and
# wedged the only runner. Re-enable after the runner gets --cap-add SYS_PTRACE
# (or seccomp=unconfined).
sanitizers:
if: false
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
env:
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_REPOSITORY: ${{ github.repository }}
GITHUB_SHA: ${{ github.sha }}
run: |
curl -fsSL "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/raw/commit/$GITHUB_SHA/scripts/ci_checkout.sh" \
-o /tmp/ci_checkout.sh
bash /tmp/ci_checkout.sh
- name: Install dependencies
run: |
SUDO=$(command -v sudo || true)
$SUDO bash scripts/ci_pkg_mirror.sh
$SUDO apt-get update
$SUDO apt-get install -y --no-install-recommends \
build-essential pkg-config libcurl4-openssl-dev libncurses-dev
- name: ASan + UBSan
timeout-minutes: 10
env:
ASAN_OPTIONS: abort_on_error=1:halt_on_error=1:detect_leaks=0:use_sigaltstack=0
UBSAN_OPTIONS: halt_on_error=1:print_stacktrace=1
run: timeout -s KILL 480 make asan
musl: musl:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 30 timeout-minutes: 30
+23 -10
View File
@@ -93,7 +93,7 @@ static void reply_calls(test_sock_t fd, const char *const *calls, int n) {
cJSON *tc = cJSON_AddArrayToObject(d, "tool_calls"); cJSON *tc = cJSON_AddArrayToObject(d, "tool_calls");
cJSON *c = cJSON_CreateObject(); cJSON *c = cJSON_CreateObject();
cJSON_AddNumberToObject(c, "index", i); cJSON_AddNumberToObject(c, "index", i);
char id[16]; char id[32];
snprintf(id, sizeof(id), "call_%d", i); snprintf(id, sizeof(id), "call_%d", i);
cJSON_AddStringToObject(c, "id", id); cJSON_AddStringToObject(c, "id", id);
cJSON_AddStringToObject(c, "type", "function"); cJSON_AddStringToObject(c, "type", "function");
@@ -120,19 +120,30 @@ static int has_tool(const cJSON *body, const char *name) {
static void handle(test_sock_t fd, const char *body_txt) { static void handle(test_sock_t fd, const char *body_txt) {
cJSON *body = cJSON_Parse(body_txt); cJSON *body = cJSON_Parse(body_txt);
if (!body) {
const char *err = "HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n";
send_all(fd, err, strlen(err));
return;
}
const cJSON *msgs = cJSON_GetObjectItemCaseSensitive(body, "messages"); const cJSON *msgs = cJSON_GetObjectItemCaseSensitive(body, "messages");
int nm = cJSON_GetArraySize(msgs); int nm = cJSON_IsArray(msgs) ? cJSON_GetArraySize(msgs) : 0;
const cJSON *sys = cJSON_GetObjectItemCaseSensitive( const cJSON *sys = NULL;
cJSON_GetArrayItem(msgs, 0), "content"); const char *last_role = "";
const cJSON *last = cJSON_GetArrayItem(msgs, nm - 1);
const char *last_role =
cJSON_GetObjectItemCaseSensitive(last, "role")->valuestring;
const char *user = ""; const char *user = "";
if (nm > 0) {
sys = cJSON_GetObjectItemCaseSensitive(cJSON_GetArrayItem(msgs, 0),
"content");
const cJSON *last = cJSON_GetArrayItem(msgs, nm - 1);
const cJSON *lr = cJSON_GetObjectItemCaseSensitive(last, "role");
if (cJSON_IsString(lr))
last_role = lr->valuestring;
}
for (int i = 0; i < nm; i++) { for (int i = 0; i < nm; i++) {
const cJSON *m = cJSON_GetArrayItem(msgs, i); const cJSON *m = cJSON_GetArrayItem(msgs, i);
const cJSON *r = cJSON_GetObjectItemCaseSensitive(m, "role"); const cJSON *r = cJSON_GetObjectItemCaseSensitive(m, "role");
const cJSON *c = cJSON_GetObjectItemCaseSensitive(m, "content"); const cJSON *c = cJSON_GetObjectItemCaseSensitive(m, "content");
if (strcmp(r->valuestring, "user") == 0 && cJSON_IsString(c)) if (cJSON_IsString(r) && strcmp(r->valuestring, "user") == 0 &&
cJSON_IsString(c))
user = c->valuestring; user = c->valuestring;
} }
const char *hdr = "HTTP/1.1 200 OK\r\nContent-Type: text/event-stream\r\n" const char *hdr = "HTTP/1.1 200 OK\r\nContent-Type: text/event-stream\r\n"
@@ -160,8 +171,10 @@ static void handle(test_sock_t fd, const char *body_txt) {
const char *calls[] = {"read_file", "{\"path\":\"a.txt\"}"}; const char *calls[] = {"read_file", "{\"path\":\"a.txt\"}"};
reply_calls(fd, calls, 1); reply_calls(fd, calls, 1);
} else { } else {
char out[256]; /* last char of the user prompt (e.g. "Find A" -> "A"); empty-safe */
snprintf(out, sizeof(out), "child report %s", user + strlen(user) - 1); char tag = user[0] ? user[strlen(user) - 1] : '?';
char out[64];
snprintf(out, sizeof(out), "child report %c", tag);
reply_text(fd, out); reply_text(fd, out);
} }
atomic_fetch_sub(&g_child_active, 1); atomic_fetch_sub(&g_child_active, 1);