From fb0215fa122cc3b3507df4350d53efbe8a9f2993 Mon Sep 17 00:00:00 2001 From: Mathias Westerdahl Date: Sat, 21 Feb 2026 16:15:57 +0100 Subject: [PATCH 1/6] Added more analyze steps --- .github/workflows/build.yml | 56 ++++++++++++++++++++++++++++ AGENTS.md | 32 ++++++++++++++++ scripts/compile.sh | 74 +++++++++++++++++++++++++++++++++---- scripts/compile_cl.bat | 6 ++- src/jc_test.h | 13 ++++--- 5 files changed, 167 insertions(+), 14 deletions(-) create mode 100644 AGENTS.md diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 22a7021..faf4568 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,6 +20,28 @@ jobs: - name: Run Tests run: ./scripts/run_tests.sh + build-linux-ubsan: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install + run: sudo apt-get update && sudo apt-get install -y clang + - name: Build tests + run: CXX=clang++ STDVERSION=c++17 ARCH=-m64 USE_UBSAN=1 ./scripts/compile.sh + - name: Run Tests + run: ./scripts/run_tests.sh + + build-linux-msan: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install + run: sudo apt-get update && sudo apt-get install -y clang + - name: Build tests + run: CXX=clang++ STDVERSION=c++17 ARCH=-m64 USE_MSAN=1 ./scripts/compile.sh + - name: Run Tests + run: ./scripts/run_tests.sh + build-macos: strategy: matrix: @@ -33,6 +55,26 @@ jobs: - name: Run Tests run: ./scripts/run_tests.sh + build-linux-staticanalyze: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install + run: sudo apt-get update && sudo apt-get install -y clang + - name: Build tests + run: CXX=clang++ STDVERSION=c++17 ARCH=-m64 USE_STATICANALYZE=1 ./scripts/compile.sh + - name: Run Tests + run: ./scripts/run_tests.sh + + build-macos-staticanalyze: + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + - name: Build tests + run: CXX=clang++ STDVERSION=c++17 ARCH=-m64 USE_STATICANALYZE=1 ./scripts/compile.sh + - name: Run Tests + run: ./scripts/run_tests.sh + build-windows: strategy: matrix: @@ -47,3 +89,17 @@ jobs: run: ./scripts/compile_cl.bat - name: Run Tests run: ./scripts/run_tests.bat + + build-windows-staticanalyze: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - uses: ilammy/msvc-dev-cmd@v1 + with: + arch: amd64 + - name: Build tests + env: + USE_STATICANALYZE: 1 + run: ./scripts/compile_cl.bat + - name: Run Tests + run: ./scripts/run_tests.bat diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..b8816e3 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,32 @@ +# AGENTS.md + +These instructions apply to the entire repository. + +## Language and Design + +* Prefer C-like C++ ("Orthodox C++"): simple types, explicit ownership, RAII, and clear invariants. +* Target C++98 when possible. +* Do not introduce C++11+ features unless there is a clear need. If newer features are required, guard them and keep a C++98-compatible path when practical. +* Keep dependencies minimal and avoid template-heavy or meta-programming-heavy solutions. +* Do not rely on exceptions (the project builds with `-fno-exceptions`). + +## Style + +* Follow the existing style in nearby files. Do not reformat unrelated code. +* Use 4 spaces for indentation and keep whitespace changes minimal. +* Keep include order consistent with existing files: system headers first, then local headers. +* Prefer project-established forms such as `#if defined(...)` preprocessor guards and uppercase macro names. +* Use simple, readable control flow; avoid clever constructs. + +## Compatibility Guidelines + +* Prefer C/C++98-friendly headers and APIs already used in this repo (``, ``, etc.) unless there is a reason to use something else. +* Avoid unguarded use of features like `nullptr`, `auto`, lambdas, `override`, variadic templates, and `static_assert`. +* Keep code warning-clean under the current compile flags. + +## Validation + +* Build with C++98 first when touching C++ code: + * `STDVERSION=c++98 scripts/compile.sh` +* Run tests after changes: + * `scripts/run_tests.sh` diff --git a/scripts/compile.sh b/scripts/compile.sh index ebea8cb..4fc0705 100755 --- a/scripts/compile.sh +++ b/scripts/compile.sh @@ -8,14 +8,47 @@ fi #DISASSEMBLY="-S -masm=intel" #PREPROCESS="-E" +if [ "$CXX" == "" ]; then + CXX=clang++ +fi + +if [ "$USE_STATICANALYZE" != "" ]; then + if [ "$CXX" == "clang++" ]; then + STATIC_ANALYZER_CLANG=1 + STATIC_ANALYZER_FLAGS="-Xanalyzer -analyzer-output=text -Xanalyzer -analyzer-werror -Xanalyzer -analyzer-disable-checker -Xanalyzer deadcode.DeadStores" + echo "Using STATIC ANALYZER (clang)" + else + echo "USE_STATICANALYZE requires clang++ in scripts/compile.sh" + exit 1 + fi +fi + if [ "$USE_ASAN" != "" ]; then if [ "$CXX" != "g++" ]; then - ASAN="-fsanitize=address -fno-omit-frame-pointer -fsanitize-address-use-after-scope -fsanitize=undefined" - ASAN_LDFLAGS="-fsanitize=address " + SANITIZER_CXXFLAGS="$SANITIZER_CXXFLAGS -fsanitize=address -fno-omit-frame-pointer -fsanitize-address-use-after-scope" + SANITIZER_LDFLAGS="$SANITIZER_LDFLAGS -fsanitize=address" echo "Using ASAN" fi fi +if [ "$USE_UBSAN" != "" ]; then + if [ "$CXX" != "g++" ]; then + SANITIZER_CXXFLAGS="$SANITIZER_CXXFLAGS -fsanitize=undefined -fno-omit-frame-pointer" + SANITIZER_LDFLAGS="$SANITIZER_LDFLAGS -fsanitize=undefined" + echo "Using UBSAN" + fi +fi + +if [ "$USE_MSAN" != "" ]; then + if [ "$CXX" != "clang++" ]; then + echo "MSAN requires clang++" + exit 1 + fi + SANITIZER_CXXFLAGS="$SANITIZER_CXXFLAGS -fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer" + SANITIZER_LDFLAGS="$SANITIZER_LDFLAGS -fsanitize=memory" + echo "Using MSAN" +fi + if [ "$OPT" == "" ]; then OPT="-O2" fi @@ -27,9 +60,6 @@ fi echo Using -std=$STDVERSION -if [ "$CXX" == "" ]; then - CXX=clang++ -fi echo Using CXX=$CXX $CXX --version @@ -39,17 +69,21 @@ if [ "$ARCH" == "" ]; then fi echo Using ARCH=$ARCH -CXXFLAGS="$CXXFLAGS -std=$STDVERSION -g -Wall -pedantic -fno-exceptions -Werror=format -Isrc -I. $ASAN $PREPROCESS -Wno-old-style-cast" +CXXFLAGS="$CXXFLAGS -std=$STDVERSION -g -Wall -pedantic -fno-exceptions -Werror=format -Isrc -I. $SANITIZER_CXXFLAGS $PREPROCESS -Wno-old-style-cast" if [ "$CXX" == "clang++" ]; then - CXXFLAGS="$CXXFLAGS -Weverything -Wno-global-constructors" + CXXFLAGS="$CXXFLAGS -Weverything -Wno-global-constructors -Wuninitialized -Wsometimes-uninitialized -Wconditional-uninitialized" +fi + +if [ "$CXX" == "g++" ]; then + CXXFLAGS="$CXXFLAGS -Wuninitialized -Wmaybe-uninitialized" fi if [ "$CXX" != "c++98" ]; then CXXFLAGS="$CXXFLAGS -Wno-zero-as-null-pointer-constant -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-suggest-override" fi -LDFLAGS="$LDFLAGS $ASAN_LDFLAGS" +LDFLAGS="$LDFLAGS $SANITIZER_LDFLAGS" @@ -72,9 +106,23 @@ echo "COMPILING WITH JCTEST" PREFIX=jctest EXAMPLE_SOURCE_DIR=./hugo/static/code +ANALYZE_INDEX=0 +ANALYZED_MAIN=0 + +function analyze_source { + local file=$1 + shift + local outfile=./build/analyze_${ANALYZE_INDEX}.o + ANALYZE_INDEX=$((ANALYZE_INDEX + 1)) + echo "Analyzing ${file}" + $CXX --analyze $OPT $ARCH $SYSROOT $CXXFLAGS $STATIC_ANALYZER_FLAGS $* ${file} -o ${outfile} +} function compile_doc_example { local file=example_${1}.cpp + if [ "$STATIC_ANALYZER_CLANG" != "" ]; then + analyze_source ${EXAMPLE_SOURCE_DIR}/${file} + fi echo "Compiling ${file}" $CXX -o ./build/example_${1} $OPT $ARCH $SYSROOT $CXXFLAGS ${EXAMPLE_SOURCE_DIR}/${file} } @@ -82,6 +130,13 @@ function compile_doc_example { function compile_test { local name=$1 shift + if [ "$STATIC_ANALYZER_CLANG" != "" ]; then + analyze_source test/test_${name}.cpp $* + if [ "$ANALYZED_MAIN" == "0" ]; then + analyze_source test/main.cpp + ANALYZED_MAIN=1 + fi + fi echo "Compiling test $name" $CXX -o ./build/${PREFIX}_test_${name}.o $OPT $DISASSEMBLY $ARCH $SYSROOT $CXXFLAGS $* -c test/test_${name}.cpp $CXX -o ./build/${PREFIX}_main.o $OPT $DISASSEMBLY $ARCH $SYSROOT $CXXFLAGS -c test/main.cpp @@ -91,6 +146,9 @@ function compile_test { function compile_test_with_main { local name=$1 shift + if [ "$STATIC_ANALYZER_CLANG" != "" ]; then + analyze_source test/test_${name}.cpp $* + fi echo "Compiling test $name" $CXX -o ./build/${PREFIX}_test_${name}.o $OPT $DISASSEMBLY $ARCH $SYSROOT $CXXFLAGS $* -c test/test_${name}.cpp $CXX -o ./build/${PREFIX}_${name} $OPT $ARCH ./build/${PREFIX}_test_${name}.o $LDFLAGS diff --git a/scripts/compile_cl.bat b/scripts/compile_cl.bat index d387dcc..5d012fa 100644 --- a/scripts/compile_cl.bat +++ b/scripts/compile_cl.bat @@ -13,7 +13,11 @@ set TIMEIT mkdir build -set FLAGS=/Od /Zi /D_CRT_SECURE_NO_WARNINGS /nologo /D_HAS_EXCEPTIONS=0 /EHsc /W4 /wd4611 /Isrc +set FLAGS=/Od /Zi /D_CRT_SECURE_NO_WARNINGS /nologo /D_HAS_EXCEPTIONS=0 /EHsc /W4 /wd4611 /Isrc +if not "%USE_STATICANALYZE%"=="" ( + set FLAGS=%FLAGS% /analyze /WX + echo Using STATIC ANALYZER (msvc) +) call %TIMEIT% cl.exe %FLAGS% test\test_params.cpp test\main.cpp /link /out:.\build\test_params.exe call %TIMEIT% cl.exe %FLAGS% test\test_typed_test.cpp test\main.cpp /link /out:.\build\test_typed_test.exe diff --git a/src/jc_test.h b/src/jc_test.h index a4aaa7a..d3e7326 100644 --- a/src/jc_test.h +++ b/src/jc_test.h @@ -1042,7 +1042,7 @@ template <> char* jc_test_print_value(char* buffer, size_t buffer_len, std::null static int jc_get_formatted_test_name(char* buffer, size_t buffer_len, const jc_test_fixture* fixture, const jc_test_entry* test, int usecolor) { if (fixture->index != 0xFFFFFFFF) - return JC_TEST_SNPRINTF(buffer, buffer_len, "%s%s%s.%s%s%s/%d", JC_TEST_COL2(CYAN,usecolor), fixture->name, JC_TEST_COL2(DEFAULT,usecolor), JC_TEST_COL2(YELLOW,usecolor), test->name, JC_TEST_COL2(DEFAULT,usecolor), fixture->index); + return JC_TEST_SNPRINTF(buffer, buffer_len, "%s%s%s.%s%s%s/%u", JC_TEST_COL2(CYAN,usecolor), fixture->name, JC_TEST_COL2(DEFAULT,usecolor), JC_TEST_COL2(YELLOW,usecolor), test->name, JC_TEST_COL2(DEFAULT,usecolor), fixture->index); else return JC_TEST_SNPRINTF(buffer, buffer_len, "%s%s%s.%s%s%s", JC_TEST_COL2(CYAN,usecolor), fixture->name, JC_TEST_COL2(DEFAULT,usecolor), JC_TEST_COL2(YELLOW,usecolor), test->name, JC_TEST_COL2(DEFAULT,usecolor)); } @@ -1206,7 +1206,7 @@ void jc_test_print_logger::OnTestSetup(const jc_test_fixture* fixture, const jc_ str->Appendf("%s%s%s", JC_TEST_COL(YELLOW), test->name, JC_TEST_COL(DEFAULT)); if (fixture->index != 0xFFFFFFFF) { - str->Appendf("/%d ", fixture->index); + str->Appendf("/%u ", fixture->index); } str->Append("\n"); @@ -1219,7 +1219,7 @@ void jc_test_print_logger::OnTestTeardown(const jc_test_fixture* fixture, const str->Appendf("%s%s%s", JC_TEST_COL(YELLOW), test->name, JC_TEST_COL(DEFAULT)); if (fixture->index != 0xFFFFFFFF) { - str->Appendf("/%d ", fixture->index); + str->Appendf("/%u ", fixture->index); } if (test->fail) str->Appendf(" %s%s%s (", JC_TEST_COL(FAIL), "FAIL", JC_TEST_COL(DEFAULT)); @@ -1848,7 +1848,8 @@ int jc_test_keep_test(jc_test_state* state, const char* name) { if (state->num_filter_patterns == 0) return 1; for (uint32_t i = 0; i < state->num_filter_patterns; ++i) { - if (jc_test_strstr(name, state->filter_patterns[i]) != 0) + const char* pattern = state->filter_patterns[i]; + if (pattern != 0 && jc_test_strstr(name, pattern) != 0) return 1; // it matched the pattern, so let's keep it } return 0; @@ -1869,8 +1870,10 @@ static char* jc_test_strdup(const char* s) { } static void jc_test_add_test_filter(jc_test_state* state, const char* pattern) { - if (state->filter_patterns == 0) + if (state->filter_patterns == 0) { state->filter_patterns = new char*[255]; + jc_test_memset(state->filter_patterns, 0, sizeof(char*) * 255); + } if (state->num_filter_patterns == 255) return; state->filter_patterns[state->num_filter_patterns++] = jc_test_strdup(pattern); From 43a73656706c79524b9949277477f4c334fc08f3 Mon Sep 17 00:00:00 2001 From: Mathias Westerdahl Date: Sat, 21 Feb 2026 16:25:02 +0100 Subject: [PATCH 2/6] Fix for uninitialized values --- src/jc_test.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/jc_test.h b/src/jc_test.h index d3e7326..339ce2e 100644 --- a/src/jc_test.h +++ b/src/jc_test.h @@ -732,7 +732,7 @@ struct jc_test_register_typed_class_test { template jc_test_fixture* jc_test_alloc_fixture_with_param(const char* name, unsigned int type) { - return jc_test_create_fixture(new jc_test_fixture_with_param, name, type); + return jc_test_create_fixture(new jc_test_fixture_with_param(), name, type); } template @@ -753,10 +753,11 @@ void jc_test_create_from_prototype(jc_test_fixture_with_param* fixtur jc_test_entry* first = 0; jc_test_entry* prev = 0; while (prototype_test) { - jc_test_entry* test = new jc_test_entry; + jc_test_entry* test = new jc_test_entry(); test->next = 0; test->name = prototype_test->name; test->factory = 0; + test->time = 0; test->fail = 0; test->skipped = 0; @@ -1436,6 +1437,8 @@ jc_test_fixture* jc_test_create_fixture(jc_test_fixture* fixture, const char* na fixture->next = 0; fixture->tests = 0; fixture->name = name; + fixture->filename = 0; + fixture->prototype = 0; fixture->type = fixture_type; fixture->parent = 0; fixture->fail = 0; @@ -1445,6 +1448,8 @@ jc_test_fixture* jc_test_create_fixture(jc_test_fixture* fixture, const char* na fixture->num_tests = 0; fixture->first = fixture->last = 1; fixture->signum = 0; + fixture->line = 0; + fixture->_pad = 0; fixture->fixture_setup = 0; fixture->fixture_teardown = 0; jc_test_memset(&fixture->stats, 0, sizeof(fixture->stats)); @@ -1459,11 +1464,12 @@ jc_test_fixture* jc_test_create_fixture(jc_test_fixture* fixture, const char* na } jc_test_entry* jc_test_add_test_to_fixture(jc_test_fixture* fixture, const char* test_name, jc_test_base_class* instance, jc_test_factory_base_interface* factory) { - jc_test_entry* test = new jc_test_entry; + jc_test_entry* test = new jc_test_entry(); test->next = 0; test->name = test_name; test->instance = instance; test->factory = factory; + test->time = 0; test->fail = 0; test->skipped = 0; jc_test_entry* prev = fixture->tests; @@ -1487,7 +1493,7 @@ jc_test_fixture* jc_test_find_fixture(const char* name, unsigned int fixture_typ } jc_test_fixture* jc_test_alloc_fixture(const char* name, unsigned int fixture_type) { - return jc_test_create_fixture(new jc_test_fixture, name, fixture_type); + return jc_test_create_fixture(new jc_test_fixture(), name, fixture_type); } int jc_test_register_class_test(const char* fixture_name, const char* test_name, From 5aed5c7f8f44d6a4f29ead61616f1483c1942fe8 Mon Sep 17 00:00:00 2001 From: Mathias Westerdahl Date: Sat, 21 Feb 2026 16:33:08 +0100 Subject: [PATCH 3/6] more windows script improvements --- scripts/compile_cl.bat | 64 ++++++++++++++++++++++++------------------ scripts/run_tests.bat | 31 ++++++++++++-------- scripts/timeit.py | 1 + 3 files changed, 57 insertions(+), 39 deletions(-) diff --git a/scripts/compile_cl.bat b/scripts/compile_cl.bat index 5d012fa..ae8d235 100644 --- a/scripts/compile_cl.bat +++ b/scripts/compile_cl.bat @@ -1,33 +1,41 @@ -rem echo off - -call python3 --version 2>NUL -if '%errorlevel%'=='1' goto errorNoPython -set TIMEIT=python %~dp0\timeit.py -goto hasPython -:errorNoPython -echo "No python found!" -goto end - -set TIMEIT -:hasPython - -mkdir build - +@echo off + +call python3 --version 2>NUL +if '%errorlevel%'=='1' goto errorNoPython +set TIMEIT=python3 %~dp0\timeit.py +goto hasPython +:errorNoPython +echo "No python found!" +exit /b 1 + +set TIMEIT +:hasPython + +if not exist build mkdir build + set FLAGS=/Od /Zi /D_CRT_SECURE_NO_WARNINGS /nologo /D_HAS_EXCEPTIONS=0 /EHsc /W4 /wd4611 /Isrc if not "%USE_STATICANALYZE%"=="" ( set FLAGS=%FLAGS% /analyze /WX echo Using STATIC ANALYZER (msvc) ) - -call %TIMEIT% cl.exe %FLAGS% test\test_params.cpp test\main.cpp /link /out:.\build\test_params.exe -call %TIMEIT% cl.exe %FLAGS% test\test_typed_test.cpp test\main.cpp /link /out:.\build\test_typed_test.exe -call %TIMEIT% cl.exe %FLAGS% test\test_expect.cpp test\main.cpp /link /out:.\build\test_expect.exe -call %TIMEIT% cl.exe %FLAGS% test\test_death.cpp test\main.cpp /link /out:.\build\test_death.exe -call %TIMEIT% cl.exe %FLAGS% test\test_empty.cpp test\main.cpp /link /out:.\build\test_empty.exe -call %TIMEIT% cl.exe %FLAGS% test\test_array.cpp test\main.cpp /link /out:.\build\test_array.exe -call %TIMEIT% cl.exe %FLAGS% test\test_color_off.cpp /link /out:.\build\test_color_off.exe -call %TIMEIT% cl.exe %FLAGS% test\test_color_on.cpp /link /out:.\build\test_color_on.exe - -del *.obj - -:end + +call %TIMEIT% cl.exe %FLAGS% test\test_params.cpp test\main.cpp /link /out:.\build\test_params.exe +if errorlevel 1 exit /b %errorlevel% +call %TIMEIT% cl.exe %FLAGS% test\test_typed_test.cpp test\main.cpp /link /out:.\build\test_typed_test.exe +if errorlevel 1 exit /b %errorlevel% +call %TIMEIT% cl.exe %FLAGS% test\test_expect.cpp test\main.cpp /link /out:.\build\test_expect.exe +if errorlevel 1 exit /b %errorlevel% +call %TIMEIT% cl.exe %FLAGS% test\test_death.cpp test\main.cpp /link /out:.\build\test_death.exe +if errorlevel 1 exit /b %errorlevel% +call %TIMEIT% cl.exe %FLAGS% test\test_empty.cpp test\main.cpp /link /out:.\build\test_empty.exe +if errorlevel 1 exit /b %errorlevel% +call %TIMEIT% cl.exe %FLAGS% test\test_array.cpp test\main.cpp /link /out:.\build\test_array.exe +if errorlevel 1 exit /b %errorlevel% +call %TIMEIT% cl.exe %FLAGS% test\test_color_off.cpp /link /out:.\build\test_color_off.exe +if errorlevel 1 exit /b %errorlevel% +call %TIMEIT% cl.exe %FLAGS% test\test_color_on.cpp /link /out:.\build\test_color_on.exe +if errorlevel 1 exit /b %errorlevel% + +del *.obj + +exit /b 0 diff --git a/scripts/run_tests.bat b/scripts/run_tests.bat index 2afefdc..e296489 100644 --- a/scripts/run_tests.bat +++ b/scripts/run_tests.bat @@ -1,11 +1,20 @@ -echo off - -.\build\test_params.exe -.\build\test_typed_test.exe -.\build\test_expect.exe -.\build\test_death.exe -.\build\test_empty.exe -.\build\test_array.exe -.\build\test_doctest.exe -.\build\test_color_off.exe -.\build\test_color_on.exe +@echo off + +call :run_test .\build\test_params.exe +call :run_test .\build\test_typed_test.exe +call :run_test .\build\test_expect.exe +call :run_test .\build\test_death.exe +call :run_test .\build\test_empty.exe +call :run_test .\build\test_array.exe +call :run_test .\build\test_color_off.exe +call :run_test .\build\test_color_on.exe +exit /b 0 + +:run_test +if not exist "%~1" ( + echo Missing test executable: %~1 + exit /b 1 +) +call "%~1" +if errorlevel 1 exit /b %errorlevel% +exit /b 0 diff --git a/scripts/timeit.py b/scripts/timeit.py index 1c912df..5b1bc0d 100644 --- a/scripts/timeit.py +++ b/scripts/timeit.py @@ -6,3 +6,4 @@ p.wait() tend = time.time() print("%s took %f ms" % (sys.argv[1], (tend-tstart)*1000.0)) + sys.exit(p.returncode) From 6b2a85df8b2f4f25c63f913632d67bf6fe0f9b0f Mon Sep 17 00:00:00 2001 From: Mathias Westerdahl Date: Sat, 21 Feb 2026 16:50:05 +0100 Subject: [PATCH 4/6] more static analyze fixes --- src/jc_test.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/jc_test.h b/src/jc_test.h index 339ce2e..34756ed 100644 --- a/src/jc_test.h +++ b/src/jc_test.h @@ -787,6 +787,10 @@ int jc_test_register_param_tests(const char* prototype_fixture_name, const char* // Allocate a new fixture, and create the test class jc_test_fixture_with_param* fixture = JC_TEST_CAST(jc_test_fixture_with_param*, jc_test_alloc_fixture_with_param(fixture_name, JC_TEST_FIXTURE_TYPE_CLASS) ); + if (!fixture) { + delete values; + return 1; + } fixture->first = first_fixture == 0 ? 1 : 0; if (!first_fixture) { @@ -936,6 +940,7 @@ struct jc_buffered_string { capacity += _size; buffer = (char*)realloc(buffer, capacity); + assert(buffer != 0); } void Append(const char* str, size_t len) From 2d53b52e5aa238e293c6a2316cf7a80959f9e590 Mon Sep 17 00:00:00 2001 From: Mathias Westerdahl Date: Sat, 21 Feb 2026 17:10:50 +0100 Subject: [PATCH 5/6] supress static analyzer issue on msvc --- src/jc_test.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/jc_test.h b/src/jc_test.h index 34756ed..b10d1d4 100644 --- a/src/jc_test.h +++ b/src/jc_test.h @@ -939,6 +939,10 @@ struct jc_buffered_string void Grow(size_t _size) { capacity += _size; +#if defined(_MSC_VER) + // C6308: realloc may return null and overwrite the original pointer, causing a leak. + #pragma warning(suppress:6308) +#endif buffer = (char*)realloc(buffer, capacity); assert(buffer != 0); } From 71097ec04f607f722dfe570ef048aca9978b5791 Mon Sep 17 00:00:00 2001 From: Mathias Westerdahl Date: Sat, 21 Feb 2026 17:44:18 +0100 Subject: [PATCH 6/6] disable windows static analyze step for now --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index faf4568..28fe1e8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -92,6 +92,7 @@ jobs: build-windows-staticanalyze: runs-on: windows-latest + if: ${{ false }} steps: - uses: actions/checkout@v2 - uses: ilammy/msvc-dev-cmd@v1