feat: integrate hardening and static analysis features - #920
niteshpurohit wants to merge 3 commits into
Conversation
- Added LaghuHardening.cmake to configure hardening features such as PIE, stack protection, and fortification. - Introduced ExpectHardeningFailure.cmake, ExpectHardeningMetadata.cmake, and ExpectHardeningUnsupported.cmake for testing hardening configurations. - Implemented static analysis configuration in LaghuStaticAnalysis.cmake, allowing integration with clang-tidy, cppcheck, and clang-analyzer. - Created ExpectStaticAnalysisFailure.cmake and ExpectStaticAnalysisOwnership.cmake for validating static analysis outcomes. - Added tests for static analysis failures and ownership checks to ensure proper functionality. - Updated CMakeLists.txt to include new hardening and static analysis configurations and tests. - Refactored build identity to include hardening metadata in the output. closes: #75
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical and moderate issues affect build correctness, hardening validation, and static-analysis coverage.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds CMake-based hardening and static-analysis integration, including metadata, validation fixtures, and CI coverage.
Changes:
- Adds PIE, stack protection, RELRO, binding, and fortification configuration.
- Integrates clang-tidy, Cppcheck, and clang-analyzer.
- Adds validation fixtures, build identity updates, and CI coverage.
File summaries
| File | Review summary |
|---|---|
tests/static-analysis/ownership/third_party/src/unowned.hpp |
Reviewed third-party ownership fixture. |
tests/static-analysis/ownership/owned.cpp |
Reviewed owned-source fixture. |
tests/static-analysis/negative/cppcheck.cpp |
Reviewed Cppcheck failure fixture. |
tests/static-analysis/negative/clang_tidy.cpp |
Reviewed clang-tidy failure fixture. |
tests/static-analysis/negative/clang_analyzer.cpp |
Reviewed clang-analyzer failure fixture. |
tests/hardening/probes/clean.cpp |
Reviewed clean hardening probe. |
src/core/contract/laghu/core/identifiers.hpp |
Critical, 1 vote: Deleting the private default constructor makes StrongIdentifier non-trivial and breaks an existing static_assert; retain the defaulted constructor. |
CMakeLists.txt |
Reviewed module and test registration. |
cmake/static-analysis/cppcheck-2.13.txt |
Reviewed Cppcheck configuration. |
cmake/static-analysis/clang-tidy-19.yaml |
Moderate, 1 vote: Enable floating-point narrowing diagnostics or use a default-enabled narrowing fixture. |
cmake/static-analysis/clang-analyzer-19.txt |
Reviewed clang-analyzer configuration. |
cmake/RunStaticAnalysis.cmake |
Critical, 1 vote: The src/* Cppcheck regex can select no files and bypass the gate. Moderate, 1 vote: scan-build omits profile-specific targets such as laghu_crypto. |
cmake/LaghuToolchain.cmake |
Critical, 1 vote: Apply -fPIE only to executable targets, not shared libraries. Moderate, 2 votes: Preserve sanitizer link options for shared/module targets. |
cmake/LaghuStaticAnalysis.cmake |
Reviewed static-analysis configuration. |
cmake/LaghuHardening.cmake |
Critical, 2 votes: RELRO and immediate-binding probes do not validate executable linking when the toolchain uses static-library try-compiles; temporarily use executable try-compiles for these probes. |
cmake/LaghuBuildIdentity.cmake |
Reviewed hardening metadata integration. |
cmake/HardeningUnsupportedFixture.cmake |
Reviewed unsupported-hardening fixture. |
cmake/HardeningFailureFixture.cmake |
Reviewed hardening-failure fixture. |
cmake/ExpectStaticAnalysisOwnership.cmake |
Critical, 1 vote: The invalid src/* Cppcheck glob can exclude the owned file; use a matching regular expression such as src/.*. |
cmake/ExpectStaticAnalysisFailure.cmake |
Reviewed static-analysis failure expectations. |
cmake/ExpectHardeningUnsupported.cmake |
Reviewed unsupported-hardening expectations. |
cmake/ExpectHardeningMetadata.cmake |
Moderate, 1 vote: Release-mode validation should require every supported hardening feature to have enabled=true. |
cmake/ExpectHardeningFailure.cmake |
Reviewed hardening-failure expectations. |
.github/workflows/toolchain.yml |
Reviewed CI analysis and hardening coverage. |
Review details
Suppressed comments (6)
cmake/ExpectHardeningMetadata.cmake:24
- This assertion only rejects
enabled=truewhensupported=false; it never requires a supported feature to be enabled in a Release build. A regression that drops-fPIE, stack protection, or linker hardening while leaving the probes successful would therefore pass the metadata test. Add a Release-mode assertion that every supported feature hasenabled=true.
if("${enabled_value}" STREQUAL "true" AND NOT "${supported_value}" STREQUAL "true")
message(FATAL_ERROR "Laghu hardening metadata expectation failed: feature=${feature}; enabled_without_support")
endif()
cmake/LaghuHardening.cmake:56
- On ELF targets this probe only compiles with
-fPIE, but the implementation later adds-pieto executable link options. A toolchain can accept the compiler flag while rejecting the linker flag, so configuration records PIE as supported and the Release build then fails at link time (or does not validate the promised link hardening). Include the ELF-only-piein this probe while retaining the compile-only probe on Darwin.
laghu_hardening_probe(pie pie_supported COMPILE_OPTIONS -fPIE)
cmake/LaghuHardening.cmake:60
- The fortification probe compiles an empty source, so
-D_FORTIFY_SOURCE=3is accepted merely as an arbitrary preprocessor definition; it never includes or exercises a fortified libc operation. This records fortification as supported and enables the flag even on POSIX platforms whose C library does not implement it, defeating the explicit unsupported-platform metadata. Probe a real fortified operation or classify support using platform/toolchain-specific checks.
laghu_hardening_probe(fortification fortification_supported
COMPILE_OPTIONS -O2 -D_FORTIFY_SOURCE=3)
cmake/RunStaticAnalysis.cmake:66
- The analyzer build is hard-coded to
MINIMAL, while the clang-tidy/cppcheck source list is derived from the active compile database. Optional first-party sources such assrc/adapters/crypto_provider.cppandsrc/adapters/entropy.cppare only materialized for the TLS feature, so the default CI gate silently omits them from all static analysis. Pass an analysis profile that materializes every owned source or provide a dedicated all-owned-source compilation database.
-DLAGHU_BUILD_PROFILE=MINIMAL)
cmake/RunStaticAnalysis.cmake:81
- Even apart from the forced MINIMAL profile, scan-build only builds
laghu_core,laghu_os, andlaghu; profile-specific targets such aslaghu_cryptoare never passed to the analyzer build. This leaves those first-party translation units unanalysed by clang-analyzer while the other two tools inspect them from the compile database.
execute_process(
COMMAND "${SCAN_BUILD}" --use-cc "${CLANG_ANALYZER}" --use-c++ "${CXX}" ${analyzer_options}
"${CMAKE_COMMAND}" --build "${analyzer_build}" --target laghu_core laghu_os laghu
cmake/static-analysis/clang-tidy-19.yaml:5
bugprone-narrowing-conversionsdoes not enable floating-point narrowing diagnostics by default in clang-tidy 19, but both the negative fixture and the ownership fixture rely onint value = 1.5being rejected. These validation tests can therefore fail with no diagnostic, and the analysis gate will not exercise the seeded defect. EnableWarnOnFloatingPointNarrowingConversion(or change the fixtures to a default-enabled narrowing case).
bugprone-narrowing-conversions,
- Files reviewed: 24/24 changed files
- Comments generated: 6
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved hardening and static-analysis findings include one critical issue and four moderate issues.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (4)
cmake/ExpectStaticAnalysisOwnership.cmake:90
- This analyzer fixture only demonstrates that
scan-buildreports a defect when it is explicitly given the vendor file; it never exercises the ownership filtering used byRunStaticAnalysis.cmake(the compile-databasesrc/selection and_depsexclusion). A regression that feeds third-party compile entries into the production analyzer would therefore still pass this ownership test. Add a mixed owned/vendor compile database or equivalent assertion that the vendor command is not analyzed.
execute_process(
COMMAND "${SCAN_BUILD}" --use-cc "${CLANG_ANALYZER}" --use-c++ "${CLANG_ANALYZER}"
--status-bugs -o "${WORK_DIRECTORY}/scan-unowned" "${CLANG_ANALYZER}" -std=c++23 -c
"${WORK_DIRECTORY}/_deps/vendor-src/src/analyzer.cpp" -o "${WORK_DIRECTORY}/analyzer.o"
cmake/LaghuHardening.cmake:148
- Appending
-O2to every Release target changes the optimization level from CMake's normal Release setting (typically-O3) and can silently downgrade the produced binaries. Keep-O2in the probe if needed to validate fortification, but apply only_FORTIFY_SOURCEto targets so the existing Release optimization is preserved.
list(APPEND common_compile_options -O2 -D_FORTIFY_SOURCE=3)
cmake/LaghuHardening.cmake:84
- This probe can report fortification support on platforms whose libc does not implement it.
try_compileonly verifies that-O2and the_FORTIFY_SOURCEmacro are accepted; the safememcpydoes not require a fortified implementation, so the probe succeeds even when the macro is ignored. Release metadata can therefore claim fortification is enabled and add a no-op hardening flag. Please probe an actual libc/compiler fortify marker or otherwise verify a fortified call before enabling this feature.
laghu_hardening_probe(fortification fortification_supported
SOURCE "${CMAKE_SOURCE_DIR}/tests/hardening/probes/fortification.cpp"
COMPILE_OPTIONS -O2 -D_FORTIFY_SOURCE=3)
cmake/LaghuHardening.cmake:56
- Release detection relies only on
CMAKE_BUILD_TYPE. The top-level generator check also acceptsNinja Multi-Config(CMakeLists.txt:16), where this variable is empty during configure; a latercmake --build --config Releasetherefore skips all hardening flags and the Release failure checks. Either reject multi-config Ninja or generate configuration-specific hardening properties and validation.
if(CMAKE_BUILD_TYPE STREQUAL "Release")
- Files reviewed: 25/25 changed files
- Comments generated: 1
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
Five unresolved moderate findings affect build correctness, verification coverage, metadata, and repeatable testing.
Review details
Suppressed comments (5)
Previously missed (1) — in code that hasn't changed since the last review.
cmake/RunStaticAnalysis.cmake:66
- Taking only the basename discards a custom or absolute compiler path. With
CMAKE_CXX_COMPILER=/opt/llvm/bin/clang++, line 73 invokesclang++throughPATHinstead of the configured compiler, so scan-build can fail or analyze with a different compiler.
CMakeLists.txt:309
- This creates
laghu_static_analysisas a standalone target, but it is not added tolaghu_verify_toolchain'sDEPENDS(see the gate atCMakeLists.txt:345-349). As a result, the documented verification target can pass without analyzing production sources; the CI step's separate build of this target does not fix the normal gate for other callers. Wire this target into the verification target wheneverLAGHU_STATIC_ANALYSISis enabled.
laghu_add_static_analysis_target()
cmake/ExpectSingleConfigNinja.cmake:7
- The test reuses the same binary directory without clearing it. On a second ctest run, CMake sees the existing Ninja Multi-Config cache and fails with a generator-mismatch diagnostic before the project emits
single-config Ninja generator, so this expectation becomes spuriously failing instead of remaining repeatable.
COMMAND "${CMAKE_COMMAND}" -S "${SOURCE}" -B "${BINARY}" -G "Ninja Multi-Config"
cmake/LaghuHardening.cmake:174
static_picis probed, required for Release builds, and applied to static/object targets, but it is omitted from the metadata members assembled here (and from the metadata validation list). Consumers therefore cannot tell whether this required hardening is supported or enabled, and unsupported static-PIC platforms are not reported in the advertised hardening metadata.
laghu_hardening_feature_json(pie_json pie "${pie_supported}" "${pie_enabled}")
laghu_hardening_feature_json(stack_protection_json stack_protection "${stack_protection_supported}" "${stack_protection_enabled}")
laghu_hardening_feature_json(relro_json relro "${relro_supported}" "${relro_enabled}")
laghu_hardening_feature_json(immediate_binding_json immediate_binding "${immediate_binding_supported}" "${immediate_binding_enabled}")
laghu_hardening_feature_json(fortification_json fortification "${fortification_supported}" "${fortification_enabled}")
src/core/contract/laghu/core/identifiers.hpp:63
- Deleting the only default constructor makes
StrongIdentifierfail the existingstd::is_trivial_vchecks inhas_strong_identifier_representation()andtests/core/strong_identifiers.cpp, so every build that includes this header is rejected. The constructor is already private, so keeping it defaulted still prevents public default construction while preserving the required trivial representation.
StrongIdentifier() = delete;
- Files reviewed: 26/26 changed files
- Comments generated: 0 new
- Review effort level: Lite
closes: #75
closes: #72