Skip to content

Commit b7d628f

Browse files
committed
Add ASAN and Valgrind integration for CI test suite
Add CMake options ENABLE_ASAN and ENABLE_VALGRIND (Linux/GCC/Clang only, mutually exclusive) with corresponding compiler/linker flags and CTest memcheck configuration. CMake changes: - ENABLE_ASAN appends -fsanitize=address -fno-omit-frame-pointer to compile and link flags; suppresses -DLOGGING in Debug builds for cleaner sanitizer output - ENABLE_VALGRIND finds the valgrind binary and configures MEMORYCHECK_COMMAND for ctest -T memcheck - Mutual exclusion enforced via FATAL_ERROR CMake presets: - Add 'asan' and 'valgrind' configure/build/test presets inheriting from 'debug', with ASAN_OPTIONS env and Valgrind timeout multiplier Build script (firebird-odbc-driver.build.ps1): - Add -Sanitizer parameter (None, Asan, Valgrind) that passes the corresponding CMake option; sets ASAN_OPTIONS at runtime; skips sanitizers on Windows with a warning CI (build-and-test.yml): - Add Linux x64 ASAN matrix entry (ubuntu-22.04, Debug) - Add Linux x64 Valgrind matrix entry (ubuntu-22.04, Debug) with valgrind package installation - Sanitizer jobs do not upload release artifacts Also adds valgrind.supp suppressions file (seeded with fbclient rule). Closes #288
1 parent a2aee27 commit b7d628f

5 files changed

Lines changed: 155 additions & 7 deletions

File tree

.github/workflows/build-and-test.yml

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,17 @@ jobs:
1616
matrix:
1717
include:
1818
- os: windows-latest
19+
config: Release
20+
sanitizer: None
1921
- os: ubuntu-22.04
22+
config: Release
23+
sanitizer: None
24+
- os: ubuntu-22.04
25+
config: Debug
26+
sanitizer: Asan
27+
- os: ubuntu-22.04
28+
config: Debug
29+
sanitizer: Valgrind
2030

2131
runs-on: ${{ matrix.os }}
2232

@@ -33,21 +43,27 @@ jobs:
3343
if: runner.os == 'Linux'
3444
run: sudo apt-get update && sudo apt-get install -y unixodbc unixodbc-dev
3545

46+
- name: Install Valgrind
47+
if: matrix.sanitizer == 'Valgrind'
48+
run: sudo apt-get install -y valgrind
49+
3650
- name: Build, install and test
3751
shell: pwsh
3852
env:
3953
API_GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40-
run: Invoke-Build test -Configuration Release -File ./firebird-odbc-driver.build.ps1
54+
ASAN_OPTIONS: ${{ matrix.sanitizer == 'Asan' && 'detect_leaks=1:halt_on_error=1:print_stats=1' || '' }}
55+
LSAN_OPTIONS: ${{ matrix.sanitizer == 'Asan' && 'suppressions=lsan.supp' || '' }}
56+
run: Invoke-Build test -Configuration ${{ matrix.config }} -Sanitizer ${{ matrix.sanitizer }} -File ./firebird-odbc-driver.build.ps1
4157

4258
- name: Upload driver (Windows)
43-
if: runner.os == 'Windows'
59+
if: runner.os == 'Windows' && matrix.sanitizer == 'None' && matrix.config == 'Release'
4460
uses: actions/upload-artifact@v4
4561
with:
4662
name: FirebirdODBC-windows-x64
4763
path: build/Release/FirebirdODBC.dll
4864

4965
- name: Upload driver (Linux)
50-
if: runner.os == 'Linux'
66+
if: runner.os == 'Linux' && matrix.sanitizer == 'None' && matrix.config == 'Release'
5167
uses: actions/upload-artifact@v4
5268
with:
5369
name: FirebirdODBC-linux-x64

CMakeLists.txt

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,38 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
4141
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
4242
option(BUILD_TESTING "Build tests" ON)
4343

44+
# ---------------------------------------------------------------------------
45+
# Sanitizer options (Linux / GCC / Clang only)
46+
# ---------------------------------------------------------------------------
47+
if(NOT MSVC)
48+
option(ENABLE_ASAN "Enable AddressSanitizer (-fsanitize=address)" OFF)
49+
option(ENABLE_VALGRIND "Enable Valgrind memcheck via CTest" OFF)
50+
51+
if(ENABLE_ASAN AND ENABLE_VALGRIND)
52+
message(FATAL_ERROR "ENABLE_ASAN and ENABLE_VALGRIND are mutually exclusive. "
53+
"ASAN instruments the binary at compile time; Valgrind instruments at runtime. "
54+
"They must not be combined.")
55+
endif()
56+
57+
if(ENABLE_ASAN)
58+
message(STATUS "AddressSanitizer: ENABLED")
59+
add_compile_options(-fsanitize=address -fno-omit-frame-pointer)
60+
add_link_options(-fsanitize=address)
61+
endif()
62+
63+
if(ENABLE_VALGRIND)
64+
find_program(VALGRIND_COMMAND valgrind)
65+
if(NOT VALGRIND_COMMAND)
66+
message(FATAL_ERROR "Valgrind not found but ENABLE_VALGRIND is ON. "
67+
"Install it with: sudo apt-get install valgrind")
68+
endif()
69+
message(STATUS "Valgrind memcheck: ENABLED (${VALGRIND_COMMAND})")
70+
set(MEMORYCHECK_COMMAND ${VALGRIND_COMMAND})
71+
set(MEMORYCHECK_COMMAND_OPTIONS
72+
"--leak-check=full --error-exitcode=1 --suppressions=${CMAKE_SOURCE_DIR}/valgrind.supp")
73+
endif()
74+
endif()
75+
4476
# ---------------------------------------------------------------------------
4577
# CPU architecture detection (from PR #248)
4678
# ---------------------------------------------------------------------------
@@ -78,8 +110,17 @@ else()
78110
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
79111

80112
# Compiler optimization flags (from PR #248 / old makefile.linux)
113+
if(ENABLE_ASAN)
114+
# ASAN builds: debug flags without extra logging noise
115+
add_compile_options(
116+
"$<$<CONFIG:Debug>:-O0;-g3;-D_DEBUG;-DDEBUG;-fexceptions>"
117+
)
118+
else()
119+
add_compile_options(
120+
"$<$<CONFIG:Debug>:-O0;-g3;-D_DEBUG;-DDEBUG;-DLOGGING;-fexceptions>"
121+
)
122+
endif()
81123
add_compile_options(
82-
"$<$<CONFIG:Debug>:-O0;-g3;-D_DEBUG;-DDEBUG;-DLOGGING;-fexceptions>"
83124
"$<$<CONFIG:Release>:-O3;-DNDEBUG;-ftree-loop-vectorize>"
84125
"$<$<CONFIG:RelWithDebInfo>:-O2;-g;-DNDEBUG>"
85126
"$<$<CONFIG:MinSizeRel>:-Os;-DNDEBUG>"
@@ -233,8 +274,12 @@ endif()
233274
# Debug-specific definitions (matching .vcxproj: DEBUG;LOGGING for Debug configs)
234275
target_compile_definitions(OdbcFb PRIVATE
235276
$<$<CONFIG:Debug>:DEBUG>
236-
$<$<CONFIG:Debug>:LOGGING>
237277
)
278+
if(NOT ENABLE_ASAN)
279+
target_compile_definitions(OdbcFb PRIVATE
280+
$<$<CONFIG:Debug>:LOGGING>
281+
)
282+
endif()
238283

239284
# ---------------------------------------------------------------------------
240285
# Testing

CMakePresets.json

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,22 @@
3030
"cacheVariables": {
3131
"CMAKE_BUILD_TYPE": "Debug"
3232
}
33+
},
34+
{
35+
"name": "asan",
36+
"displayName": "Debug + AddressSanitizer",
37+
"inherits": "debug",
38+
"cacheVariables": {
39+
"ENABLE_ASAN": "ON"
40+
}
41+
},
42+
{
43+
"name": "valgrind",
44+
"displayName": "Debug + Valgrind",
45+
"inherits": "debug",
46+
"cacheVariables": {
47+
"ENABLE_VALGRIND": "ON"
48+
}
3349
}
3450
],
3551
"buildPresets": [
@@ -42,6 +58,16 @@
4258
"name": "debug",
4359
"configurePreset": "default",
4460
"configuration": "Debug"
61+
},
62+
{
63+
"name": "asan",
64+
"configurePreset": "asan",
65+
"configuration": "Debug"
66+
},
67+
{
68+
"name": "valgrind",
69+
"configurePreset": "valgrind",
70+
"configuration": "Debug"
4571
}
4672
],
4773
"testPresets": [
@@ -51,6 +77,26 @@
5177
"output": {
5278
"outputOnFailure": true
5379
}
80+
},
81+
{
82+
"name": "asan",
83+
"configurePreset": "asan",
84+
"output": {
85+
"outputOnFailure": true
86+
},
87+
"environment": {
88+
"ASAN_OPTIONS": "detect_leaks=1:halt_on_error=1:print_stats=1"
89+
}
90+
},
91+
{
92+
"name": "valgrind",
93+
"configurePreset": "valgrind",
94+
"output": {
95+
"outputOnFailure": true
96+
},
97+
"execution": {
98+
"timeout": 600
99+
}
54100
}
55101
]
56102
}

firebird-odbc-driver.build.ps1

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111

1212
param(
1313
[ValidateSet('Debug', 'Release')]
14-
[string]$Configuration = 'Debug'
14+
[string]$Configuration = 'Debug',
15+
16+
[ValidateSet('None', 'Asan', 'Valgrind')]
17+
[string]$Sanitizer = 'None'
1518
)
1619

1720
# Detect OS
@@ -42,7 +45,20 @@ task clean {
4245

4346
# Synopsis: Build the driver and tests (default task).
4447
task build {
45-
exec { cmake -B $BuildDir -S $BuildRoot -DCMAKE_BUILD_TYPE=$Configuration -DBUILD_TESTING=ON }
48+
# Sanitizer flags (Linux only)
49+
$sanitizerArgs = @()
50+
if ($Sanitizer -ne 'None') {
51+
if ($IsWindowsOS) {
52+
print Yellow "WARNING: Sanitizer=$Sanitizer is not supported on Windows. Building without sanitizer."
53+
} else {
54+
switch ($Sanitizer) {
55+
'Asan' { $sanitizerArgs = @('-DENABLE_ASAN=ON') }
56+
'Valgrind' { $sanitizerArgs = @('-DENABLE_VALGRIND=ON') }
57+
}
58+
}
59+
}
60+
61+
exec { cmake -B $BuildDir -S $BuildRoot -DCMAKE_BUILD_TYPE=$Configuration -DBUILD_TESTING=ON @sanitizerArgs }
4662

4763
if ($IsWindowsOS) {
4864
exec { cmake --build $BuildDir --config $Configuration }
@@ -123,6 +139,13 @@ task test build, build-test-databases, install, {
123139
print Yellow 'WARNING: FIREBIRD_ODBC_CONNECTION environment variable is not set. Using built-in connection strings.'
124140
}
125141

142+
# Set sanitizer runtime options
143+
if ($Sanitizer -eq 'Asan' -and -not $IsWindowsOS) {
144+
$env:ASAN_OPTIONS = 'detect_leaks=1:halt_on_error=1:print_stats=1'
145+
$env:LSAN_OPTIONS = 'suppressions=lsan.supp'
146+
print Cyan "ASAN_OPTIONS=$env:ASAN_OPTIONS"
147+
}
148+
126149
# Test suites that exercise charset/encoding-sensitive code paths.
127150
$charsetSensitiveSuites = @(
128151
'WCharTest'

valgrind.supp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Valgrind suppressions for Firebird ODBC Driver test suite
2+
#
3+
# This file suppresses known false positives from third-party libraries
4+
# (Firebird client, unixODBC, system allocators, etc.).
5+
# Populate as false positives are discovered during Valgrind runs.
6+
#
7+
# Usage:
8+
# valgrind --leak-check=full --suppressions=valgrind.supp ./firebird_odbc_tests
9+
#
10+
# Or via CTest (when ENABLE_VALGRIND=ON):
11+
# ctest -T memcheck
12+
13+
{
14+
fbclient_global_init
15+
Memcheck:Leak
16+
...
17+
obj:*/libfbclient.so*
18+
}

0 commit comments

Comments
 (0)