Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
49 changes: 47 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,38 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
option(BUILD_TESTING "Build tests" ON)

# ---------------------------------------------------------------------------
# Sanitizer options (Linux / GCC / Clang only)
# ---------------------------------------------------------------------------
if(NOT MSVC)
option(ENABLE_ASAN "Enable AddressSanitizer (-fsanitize=address)" OFF)
Comment thread
fdcastel marked this conversation as resolved.
Outdated
option(ENABLE_VALGRIND "Enable Valgrind memcheck via CTest" OFF)
Comment thread
fdcastel marked this conversation as resolved.
Outdated

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

if(ENABLE_ASAN)
message(STATUS "AddressSanitizer: ENABLED")
add_compile_options(-fsanitize=address -fno-omit-frame-pointer)
add_link_options(-fsanitize=address)
endif()

if(ENABLE_VALGRIND)
find_program(VALGRIND_COMMAND valgrind)
if(NOT VALGRIND_COMMAND)
message(FATAL_ERROR "Valgrind not found but ENABLE_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 @@ -94,8 +126,17 @@ else()
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

# Compiler optimization flags (from PR #248 / old makefile.linux)
if(ENABLE_ASAN)
Comment thread
fdcastel marked this conversation as resolved.
Outdated
# ASAN builds: debug flags without extra logging noise
add_compile_options(
"$<$<CONFIG:Debug>:-O0;-g3;-D_DEBUG;-DDEBUG;-fexceptions>"
)
else()
add_compile_options(
"$<$<CONFIG:Debug>:-O0;-g3;-D_DEBUG;-DDEBUG;-DLOGGING;-fexceptions>"
)
endif()
add_compile_options(
"$<$<CONFIG:Debug>:-O0;-g3;-D_DEBUG;-DDEBUG;-DLOGGING;-fexceptions>"
"$<$<CONFIG:Release>:-O3;-DNDEBUG;-ftree-loop-vectorize>"
"$<$<CONFIG:RelWithDebInfo>:-O2;-g;-DNDEBUG>"
"$<$<CONFIG:MinSizeRel>:-Os;-DNDEBUG>"
Expand Down Expand Up @@ -249,8 +290,12 @@ 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.
)
if(NOT ENABLE_ASAN)
target_compile_definitions(OdbcFb PRIVATE
$<$<CONFIG:Debug>:LOGGING>
)
endif()

# ---------------------------------------------------------------------------
# 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": {
"ENABLE_ASAN": "ON"
}
},
{
"name": "valgrind",
"displayName": "Debug + Valgrind",
"inherits": "debug",
"cacheVariables": {
"ENABLE_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);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And please! Have you forgotten that this change causes a stack smash?)) Simply because the the lengthString becomes greater, and the mbstowcs call below begins to break the client's stack, overflowing the unicodeString, passed by the pointer to the ODBC call?

This undoubtedly right change CAN NOT be done without a deep refactoring of the unicode routins. I thought I've explaned it clearly in #289 (comment)

@fdcastel fdcastel Apr 19, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You were right — this change alone breaks the symmetric mbstowcs((wchar_t*)unicodeString, ..., lengthString) call in the destructor, which then writes lengthString * sizeof(wchar_t) bytes into the caller's SQLWCHAR buffer and smashes the stack. Fixing the capacity without also rewriting the write-back path is not viable. Reverted in f20e6fc; the ConvertingString / mbstowcs refactor has been tracked as Tier 9.1 in #287. PR #289 is now strictly scoped to the ASAN/Valgrind CI plumbing plus the safe internal-buffer allocation fix in 832d8e7.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. But it's insufficient to close this thread, please revert the changes) return the line 88 back to the original
lengthString = length / sizeof(wchar_t);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted in f20e6fc;

Cannot see where the line 88 is reverted in ^^^

else
lengthString = length;
}
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 += '-DENABLE_ASAN=ON' }
'Valgrind' { $cmakeArgs += '-DENABLE_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*
}