ci: fix test_subagent strcasestr crash; llvm-mingw Windows zip
clang under strict C11 left strcasestr undeclared (returns int → pointer truncation → SIGSEGV). Parse Content-Length portably; keep -Werror on make check. Drop Nix for windows-cross (root /nix fails) and use pinned llvm-mingw UCRT instead; Alpine musl gets linux-headers for audit.h.
This commit is contained in:
+10
-23
@@ -37,7 +37,11 @@ jobs:
|
|||||||
- name: Build (warnings are errors)
|
- name: Build (warnings are errors)
|
||||||
run: make CC=${{ matrix.cc }} CFLAGS="-std=c11 -Wall -Wextra -O2 -g -Werror" -j"$(nproc)"
|
run: make CC=${{ matrix.cc }} CFLAGS="-std=c11 -Wall -Wextra -O2 -g -Werror" -j"$(nproc)"
|
||||||
- name: Unit tests
|
- name: Unit tests
|
||||||
run: make CC=${{ matrix.cc }} check
|
run: |
|
||||||
|
# Same -Werror as the build step so undeclared libc helpers cannot
|
||||||
|
# silently return int and truncate pointers (see test_subagent).
|
||||||
|
make CC=${{ matrix.cc }} \
|
||||||
|
CFLAGS="-std=c11 -Wall -Wextra -O2 -g -Werror" check
|
||||||
- name: CMake build + ctest
|
- name: CMake build + ctest
|
||||||
run: |
|
run: |
|
||||||
cmake -B build -DCMAKE_C_COMPILER=${{ matrix.cc }} -DCST_BUILD_TUI=ON
|
cmake -B build -DCMAKE_C_COMPILER=${{ matrix.cc }} -DCST_BUILD_TUI=ON
|
||||||
@@ -69,7 +73,10 @@ jobs:
|
|||||||
-o /tmp/ci_checkout.sh
|
-o /tmp/ci_checkout.sh
|
||||||
bash /tmp/ci_checkout.sh
|
bash /tmp/ci_checkout.sh
|
||||||
- name: Install build dependencies
|
- name: Install build dependencies
|
||||||
run: apk add --no-cache build-base pkgconf curl-dev ncurses-dev git nodejs bash python3
|
run: |
|
||||||
|
# linux-headers provides linux/audit.h for the seccomp probe path
|
||||||
|
apk add --no-cache build-base pkgconf curl-dev ncurses-dev \
|
||||||
|
linux-headers git nodejs bash python3
|
||||||
- name: Build + unit tests
|
- name: Build + unit tests
|
||||||
run: |
|
run: |
|
||||||
make CFLAGS="-std=c11 -Wall -Wextra -O2 -Werror" -j"$(nproc)"
|
make CFLAGS="-std=c11 -Wall -Wextra -O2 -Werror" -j"$(nproc)"
|
||||||
@@ -97,28 +104,8 @@ jobs:
|
|||||||
$SUDO apt-get install -y --no-install-recommends \
|
$SUDO apt-get install -y --no-install-recommends \
|
||||||
ca-certificates curl git cmake ninja-build make pkg-config \
|
ca-certificates curl git cmake ninja-build make pkg-config \
|
||||||
python3 zip unzip perl xz-utils
|
python3 zip unzip perl xz-utils
|
||||||
- name: Install Nix (TUNA)
|
|
||||||
run: |
|
|
||||||
if ! command -v nix-shell >/dev/null; then
|
|
||||||
curl -L https://mirrors.tuna.tsinghua.edu.cn/nix/latest/install | sh -s -- --no-daemon
|
|
||||||
fi
|
|
||||||
mkdir -p "$HOME/.config/nix"
|
|
||||||
printf '%s\n' \
|
|
||||||
'substituters = https://mirrors.tuna.tsinghua.edu.cn/nix-channels/store https://cache.nixos.org/' \
|
|
||||||
'trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=' \
|
|
||||||
> "$HOME/.config/nix/nix.conf"
|
|
||||||
# shellcheck source=/dev/null
|
|
||||||
. "$HOME/.nix-profile/etc/profile.d/nix.sh"
|
|
||||||
nix --version
|
|
||||||
- name: Proxy GitHub for third_party clones
|
|
||||||
run: |
|
|
||||||
# curl/busybox-w32/ncurses sources; skip if the proxy is down
|
|
||||||
git config --global url."https://gitclone.com/github.com/".insteadOf "https://github.com/"
|
|
||||||
- name: Cross-build Windows zip
|
- name: Cross-build Windows zip
|
||||||
run: |
|
run: bash scripts/ci_windows_cross.sh
|
||||||
# shellcheck source=/dev/null
|
|
||||||
. "$HOME/.nix-profile/etc/profile.d/nix.sh"
|
|
||||||
nix-shell shell-win.nix --run 'scripts/bootstrap_windows.sh .'
|
|
||||||
- name: Verify zip
|
- name: Verify zip
|
||||||
run: |
|
run: |
|
||||||
ls -lah dist/windows-x86_64/
|
ls -lah dist/windows-x86_64/
|
||||||
|
|||||||
Executable
+59
@@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# CI helper: MinGW-w64 UCRT toolchain via llvm-mingw (no Nix / no /nix).
|
||||||
|
# Downloads a pinned release, puts it on PATH, then runs bootstrap_windows.sh.
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
cd "$ROOT"
|
||||||
|
|
||||||
|
VER="${CST_LLVM_MINGW_VER:-20241030}"
|
||||||
|
NAME="llvm-mingw-${VER}-ucrt-ubuntu-20.04-x86_64"
|
||||||
|
TGZ="/tmp/${NAME}.tar.xz"
|
||||||
|
# Prefer /opt when writable (root CI); else unpack under $HOME.
|
||||||
|
if [[ -w /opt || "$(id -u)" -eq 0 ]]; then
|
||||||
|
DIR="/opt/${NAME}"
|
||||||
|
PARENT=/opt
|
||||||
|
else
|
||||||
|
DIR="${HOME}/${NAME}"
|
||||||
|
PARENT="$HOME"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -x "$DIR/bin/x86_64-w64-mingw32-gcc" ]]; then
|
||||||
|
echo "==> download $NAME"
|
||||||
|
urls=(
|
||||||
|
"https://gitclone.com/github.com/mstorsjo/llvm-mingw/releases/download/${VER}/${NAME}.tar.xz"
|
||||||
|
"https://mirror.ghproxy.com/https://github.com/mstorsjo/llvm-mingw/releases/download/${VER}/${NAME}.tar.xz"
|
||||||
|
"https://github.com/mstorsjo/llvm-mingw/releases/download/${VER}/${NAME}.tar.xz"
|
||||||
|
)
|
||||||
|
ok=0
|
||||||
|
for u in "${urls[@]}"; do
|
||||||
|
echo " try $u"
|
||||||
|
if curl -fL --retry 2 --connect-timeout 20 --retry-delay 2 -o "$TGZ" "$u"; then
|
||||||
|
ok=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
[[ $ok -eq 1 ]] || { echo "failed to download llvm-mingw" >&2; exit 1; }
|
||||||
|
rm -rf "$DIR"
|
||||||
|
mkdir -p "$PARENT"
|
||||||
|
tar -C "$PARENT" -xf "$TGZ"
|
||||||
|
fi
|
||||||
|
|
||||||
|
export PATH="$DIR/bin:$PATH"
|
||||||
|
export MINGW_HOST=x86_64-w64-mingw32
|
||||||
|
export BUILD_CC="${BUILD_CC:-cc}"
|
||||||
|
|
||||||
|
need() { command -v "$1" >/dev/null || { echo "missing $1" >&2; exit 1; }; }
|
||||||
|
need x86_64-w64-mingw32-gcc
|
||||||
|
need x86_64-w64-mingw32-windres
|
||||||
|
need cmake; need ninja; need perl; need zip; need git; need make
|
||||||
|
|
||||||
|
if ! printf '#include <stdio.h>\n' | x86_64-w64-mingw32-gcc -dM -E - | grep -qw _UCRT; then
|
||||||
|
echo "toolchain is not UCRT" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Third-party sources live on GitHub; prefer a CN-friendly rewrite.
|
||||||
|
git config --global url."https://gitclone.com/github.com/".insteadOf "https://github.com/" || true
|
||||||
|
|
||||||
|
echo "==> bootstrap_windows.sh"
|
||||||
|
exec bash scripts/bootstrap_windows.sh "$ROOT"
|
||||||
+18
-3
@@ -18,6 +18,7 @@
|
|||||||
#define CST_TEST_SOCKETS
|
#define CST_TEST_SOCKETS
|
||||||
#include "cst_test_util.h"
|
#include "cst_test_util.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
@@ -52,6 +53,20 @@ static void send_all(test_sock_t fd, const char *s, size_t n) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Portable Content-Length lookup (avoid GNU strcasestr; undeclared under
|
||||||
|
* strict C11 it is assumed to return int and the pointer truncates). */
|
||||||
|
static const char *find_content_length(const char *hdrs) {
|
||||||
|
static const char key[] = "content-length:";
|
||||||
|
for (const char *p = hdrs; *p; p++) {
|
||||||
|
size_t i = 0;
|
||||||
|
while (key[i] && tolower((unsigned char)p[i]) == (unsigned char)key[i])
|
||||||
|
i++;
|
||||||
|
if (key[i] == '\0')
|
||||||
|
return p + (sizeof(key) - 1);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void sse(test_sock_t fd, cJSON *delta, const char *finish) {
|
static void sse(test_sock_t fd, cJSON *delta, const char *finish) {
|
||||||
cJSON *o = cJSON_CreateObject();
|
cJSON *o = cJSON_CreateObject();
|
||||||
cJSON *ch = cJSON_AddArrayToObject(o, "choices");
|
cJSON *ch = cJSON_AddArrayToObject(o, "choices");
|
||||||
@@ -205,7 +220,7 @@ static void handle(test_sock_t fd, const char *body_txt) {
|
|||||||
const char *rep = cJSON_IsString(c) ? strstr(c->valuestring,
|
const char *rep = cJSON_IsString(c) ? strstr(c->valuestring,
|
||||||
"child report ")
|
"child report ")
|
||||||
: NULL;
|
: NULL;
|
||||||
if (strcmp(r->valuestring, "tool") == 0 && rep)
|
if (cJSON_IsString(r) && strcmp(r->valuestring, "tool") == 0 && rep)
|
||||||
cst_buf_printf(&b, " [%.14s]", rep);
|
cst_buf_printf(&b, " [%.14s]", rep);
|
||||||
}
|
}
|
||||||
reply_text(fd, b.buf);
|
reply_text(fd, b.buf);
|
||||||
@@ -230,8 +245,8 @@ static void *conn_main(void *p) {
|
|||||||
char *e = strstr(req.buf, "\r\n\r\n");
|
char *e = strstr(req.buf, "\r\n\r\n");
|
||||||
if (e) {
|
if (e) {
|
||||||
hdr_end = (size_t)(e - req.buf) + 4;
|
hdr_end = (size_t)(e - req.buf) + 4;
|
||||||
char *cl = strcasestr(req.buf, "Content-Length:");
|
const char *cl = find_content_length(req.buf);
|
||||||
need = cl ? atol(cl + 15) : 0;
|
need = cl ? atol(cl) : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hdr_end && (long)(req.len - hdr_end) >= need)
|
if (hdr_end && (long)(req.len - hdr_end) >= need)
|
||||||
|
|||||||
Reference in New Issue
Block a user