Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ jobs:
fail-fast: false
matrix:
include:
# ── Windows x64 native ─────────────────────────────────────────────
# ── Windows x64 native ─────────────────────────────────────────────
- os: windows-2022
artifact-name: windows-x64-binaries
firebird-version: '5.0.3'
- os: windows-2022
firebird-branch: master

# ── Windows x86 native (WoW64) ─────────────────────────────────────
# ── Windows x86 native (WoW64) ─────────────────────────────────────
- os: windows-2022
artifact-name: windows-x86-binaries
arch: Win32
Expand All @@ -35,26 +35,34 @@ jobs:
arch: Win32
firebird-branch: master

# ── Windows ARM64 native ───────────────────────────────────────────
# ── Windows ARM64 native ─────────────────────────────────────────────
# Official Firebird releases have no win-arm64 binaries; snapshots do.
- os: windows-11-arm
artifact-name: windows-arm64-binaries
firebird-branch: master

# ── Linux x64 native ───────────────────────────────────────────────
# ── Linux x64 native ─────────────────────────────────────────────────
- os: ubuntu-22.04
artifact-name: linux-x64-binaries
firebird-version: '5.0.3'
- os: ubuntu-22.04
firebird-branch: master

# ── Linux ARM64 native ─────────────────────────────────────────────
# ── Linux ARM64 native ─────────────────────────────────────────────
- os: ubuntu-22.04-arm
artifact-name: linux-arm64-binaries
firebird-version: '5.0.3'
- os: ubuntu-22.04-arm
firebird-branch: master

# ── Linux x64 sanitizers (Debug, Firebird 5.0.3) ─────────────────────
- os: ubuntu-22.04
sanitizer: Asan
firebird-version: '5.0.3'
- os: ubuntu-22.04
sanitizer: Valgrind
firebird-version: '5.0.3'

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

steps:
Expand All @@ -70,6 +78,10 @@ jobs:
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y unixodbc unixodbc-dev

- name: Install Valgrind
if: matrix.sanitizer == 'Valgrind'
run: sudo apt-get install -y valgrind

- name: Build, install and test
shell: pwsh
env:
Expand All @@ -79,7 +91,10 @@ jobs:
run: |
$archArgs = @{}
if ('${{ matrix.arch }}') { $archArgs['Architecture'] = '${{ matrix.arch }}' }
Invoke-Build test -Configuration Release @archArgs -File ./firebird-odbc-driver.build.ps1
$sanitizerArgs = @{}
if ('${{ matrix.sanitizer }}') { $sanitizerArgs['Sanitizer'] = '${{ matrix.sanitizer }}' }
$config = if ('${{ matrix.sanitizer }}') { 'Debug' } else { 'Release' }
Invoke-Build test -Configuration $config @archArgs @sanitizerArgs -File ./firebird-odbc-driver.build.ps1

- name: Upload artifacts (Windows)
if: runner.os == 'Windows' && matrix.artifact-name
Expand Down
50 changes: 43 additions & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,41 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
option(BUILD_TESTING "Build tests" ON)

# ---------------------------------------------------------------------------
# Sanitizer options
# ---------------------------------------------------------------------------
option(BUILD_WITH_ASAN "Enable AddressSanitizer (-fsanitize=address)" OFF)
option(BUILD_WITH_VALGRIND "Enable Valgrind memcheck via CTest" OFF)

if(BUILD_WITH_ASAN AND BUILD_WITH_VALGRIND)
message(FATAL_ERROR "BUILD_WITH_ASAN and BUILD_WITH_VALGRIND are mutually exclusive. "
"ASAN instruments the binary at compile time; Valgrind instruments at runtime. "
"They must not be combined.")
endif()

if(MSVC AND (BUILD_WITH_ASAN OR BUILD_WITH_VALGRIND))
message(WARNING "Sanitizers are not yet supported on MSVC. "
"BUILD_WITH_ASAN / BUILD_WITH_VALGRIND will be ignored.")
elseif(NOT MSVC)
if(BUILD_WITH_ASAN)
message(STATUS "AddressSanitizer: ENABLED")
add_compile_options(-fsanitize=address -fno-omit-frame-pointer)
add_link_options(-fsanitize=address)
endif()

if(BUILD_WITH_VALGRIND)
find_program(VALGRIND_COMMAND valgrind)
if(NOT VALGRIND_COMMAND)
message(FATAL_ERROR "Valgrind not found but BUILD_WITH_VALGRIND is ON. "
"Install it with: sudo apt-get install valgrind")
endif()
message(STATUS "Valgrind memcheck: ENABLED (${VALGRIND_COMMAND})")
set(MEMORYCHECK_COMMAND ${VALGRIND_COMMAND})
set(MEMORYCHECK_COMMAND_OPTIONS
"--leak-check=full --error-exitcode=1 --suppressions=${CMAKE_SOURCE_DIR}/valgrind.supp")
endif()
endif()

# ---------------------------------------------------------------------------
# CPU architecture detection (from PR #248)
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -95,12 +130,19 @@ else()

# Compiler optimization flags (from PR #248 / old makefile.linux)
add_compile_options(
"$<$<CONFIG:Debug>:-O0;-g3;-D_DEBUG;-DDEBUG;-DLOGGING;-fexceptions>"
"$<$<CONFIG:Debug>:-O0;-g3;-D_DEBUG;-fexceptions>"
"$<$<CONFIG:Release>:-O3;-DNDEBUG;-ftree-loop-vectorize>"
"$<$<CONFIG:RelWithDebInfo>:-O2;-g;-DNDEBUG>"
"$<$<CONFIG:MinSizeRel>:-Os;-DNDEBUG>"
)

# Debug macros: DEBUG and LOGGING are for Debug builds only;
# sanitizer builds strip them for cleaner output (less noise in reports).
if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT BUILD_WITH_ASAN AND NOT BUILD_WITH_VALGRIND)
add_definitions(-DDEBUG)
add_definitions(-DLOGGING)
endif()

# SSE4.1 for x86/x86_64 (from PR #248)
if(FBODBC_ARCH STREQUAL "x86" OR FBODBC_ARCH STREQUAL "i686"
OR FBODBC_ARCH STREQUAL "x86_64" OR FBODBC_ARCH STREQUAL "AMD64")
Expand Down Expand Up @@ -246,12 +288,6 @@ else()
)
endif()

# Debug-specific definitions (matching .vcxproj: DEBUG;LOGGING for Debug configs)
target_compile_definitions(OdbcFb PRIVATE
$<$<CONFIG:Debug>:DEBUG>
$<$<CONFIG:Debug>:LOGGING>
Comment thread
fdcastel marked this conversation as resolved.
)

# ---------------------------------------------------------------------------
# Testing
# ---------------------------------------------------------------------------
Expand Down
46 changes: 46 additions & 0 deletions CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,22 @@
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "asan",
"displayName": "Debug + AddressSanitizer",
"inherits": "debug",
"cacheVariables": {
"BUILD_WITH_ASAN": "ON"
}
},
{
"name": "valgrind",
"displayName": "Debug + Valgrind",
"inherits": "debug",
"cacheVariables": {
"BUILD_WITH_VALGRIND": "ON"
}
}
],
"buildPresets": [
Expand All @@ -42,6 +58,16 @@
"name": "debug",
"configurePreset": "default",
"configuration": "Debug"
},
{
"name": "asan",
"configurePreset": "asan",
"configuration": "Debug"
},
{
"name": "valgrind",
"configurePreset": "valgrind",
"configuration": "Debug"
}
],
"testPresets": [
Expand All @@ -51,6 +77,26 @@
"output": {
"outputOnFailure": true
}
},
{
"name": "asan",
"configurePreset": "asan",
"output": {
"outputOnFailure": true
},
"environment": {
"ASAN_OPTIONS": "detect_leaks=1:halt_on_error=1:print_stats=1"
}
},
{
"name": "valgrind",
"configurePreset": "valgrind",
"output": {
"outputOnFailure": true
},
"execution": {
"timeout": 600
}
}
]
}
2 changes: 1 addition & 1 deletion MainUnicode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class ConvertingString
if ( length == SQL_NTS )
lengthString = 0;
else if ( retCountOfBytes )
lengthString = length / sizeof(wchar_t);
lengthString = length / sizeof(SQLWCHAR);
else
lengthString = length;
}
Expand Down
13 changes: 8 additions & 5 deletions cmake/GetVersionFromGit.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,15 @@ if(NOT GIT_FOUND)
return()
endif()

# Try to find the latest semver tag matching v<MAJOR>.<MINOR>.<PATCH>
# We use --match to only consider tags in vX.Y.Z format (not rc, temp, etc.)
# Find the latest semver tag matching v<MAJOR>.<MINOR>.<PATCH>.
# Prefer a stable vX.Y.Z tag (--exclude "*-*" filters out prereleases like
# v3.5.0-rc1). If no stable tag exists yet, fall back to any matching tag;
# the parser regex below handles the optional -<prerelease> suffix.
# NOTE: --always is intentionally NOT used on the first call so that a
# "no stable tag" case fails with non-zero exit and triggers the fallback.
execute_process(
COMMAND ${GIT_EXECUTABLE} describe --tags --match "v[0-9]*.[0-9]*.[0-9]*"
--exclude "*-*" --long --always
--exclude "*-*" --long
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_DESCRIBE_OUTPUT
OUTPUT_STRIP_TRAILING_WHITESPACE
Expand All @@ -35,10 +39,9 @@ execute_process(
)

if(NOT GIT_DESCRIBE_RESULT EQUAL 0)
# No matching tag found at all, try without --exclude
execute_process(
COMMAND ${GIT_EXECUTABLE} describe --tags --match "v[0-9]*.[0-9]*.[0-9]*"
--long --always
--long
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_DESCRIBE_OUTPUT
OUTPUT_STRIP_TRAILING_WHITESPACE
Expand Down
22 changes: 21 additions & 1 deletion firebird-odbc-driver.build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ param(
[string]$Configuration = 'Debug',

[ValidateSet('', 'Win32')]
[string]$Architecture = ''
[string]$Architecture = '',

[ValidateSet('None', 'Asan', 'Valgrind')]
[string]$Sanitizer = 'None'
)

# Detect OS
Expand Down Expand Up @@ -66,6 +69,16 @@ task build {
if ($IsWindowsOS -and $Architecture) {
$cmakeArgs += @('-A', $Architecture)
}
if ($Sanitizer -ne 'None') {
if ($IsWindowsOS) {
print Yellow "WARNING: Sanitizer=$Sanitizer is not supported on Windows. Building without sanitizer."
} else {
switch ($Sanitizer) {
'Asan' { $cmakeArgs += '-DBUILD_WITH_ASAN=ON' }
'Valgrind' { $cmakeArgs += '-DBUILD_WITH_VALGRIND=ON' }
}
}
}
exec { cmake @cmakeArgs }

if ($IsWindowsOS) {
Expand Down Expand Up @@ -160,6 +173,13 @@ task test build, build-test-databases, install, {
print Yellow 'WARNING: FIREBIRD_ODBC_CONNECTION environment variable is not set. Using built-in connection strings.'
}

# Set sanitizer runtime options
if ($Sanitizer -eq 'Asan' -and -not $IsWindowsOS) {
$env:ASAN_OPTIONS = 'detect_leaks=1:halt_on_error=1:print_stats=1'
$env:LSAN_OPTIONS = "suppressions=$(Join-Path $BuildRoot 'lsan.supp')"
print Cyan "ASAN_OPTIONS=$env:ASAN_OPTIONS"
}

# Test suites that exercise charset/encoding-sensitive code paths.
$charsetSensitiveSuites = @(
'WCharTest'
Expand Down
12 changes: 12 additions & 0 deletions lsan.supp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# LeakSanitizer suppressions for Firebird ODBC Driver test suite
#
# This file suppresses known leak reports from third-party libraries
# (Firebird client, unixODBC, system allocators, etc.).
# Populate as false positives are discovered during ASAN/LSAN runs.
#
# Usage:
# export LSAN_OPTIONS="suppressions=lsan.supp"

leak:libfbclient
leak:libodbc
leak:libodbcinst
18 changes: 18 additions & 0 deletions valgrind.supp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Valgrind suppressions for Firebird ODBC Driver test suite
#
# This file suppresses known false positives from third-party libraries
# (Firebird client, unixODBC, system allocators, etc.).
# Populate as false positives are discovered during Valgrind runs.
#
# Usage:
# valgrind --leak-check=full --suppressions=valgrind.supp ./firebird_odbc_tests
#
# Or via CTest (when ENABLE_VALGRIND=ON):
# ctest -T memcheck

{
fbclient_global_init
Memcheck:Leak
...
obj:*/libfbclient.so*
}