Skip to content

Commit

Permalink
Added WITH_ASAN, WITH_UBSAN and WITH_MSAN cmake option to enable
Browse files Browse the repository at this point in the history
respective compiler options.
Fix of issued found with ASAN on Windows - mostly in tests and one read
past allocated area in the driver(rather harmless)
  • Loading branch information
lawrinn committed May 15, 2023
1 parent c0d989b commit 00f2da1
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 24 deletions.
71 changes: 58 additions & 13 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,23 @@
# ************************************************************************************

CMAKE_POLICY(SET CMP0048 NEW)
#CMAKE_POLICY(SET CMP0057 NEW)

PROJECT(mariadb_connector_odbc C)

cmake_minimum_required(VERSION 2.8)

GET_PROPERTY(MAODBC_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)

SET(MARIADB_ODBC_VERSION_MAJOR 3)
SET(MARIADB_ODBC_VERSION_MINOR 1)
SET(MARIADB_ODBC_VERSION_PATCH 19)
SET(MARIADB_ODBC_VERSION_QUALITY "ga")

SET(MARIADB_ODBC_VERSION "03.01.0019")

SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)

SET(MARIADB_DEFAULT_PLUGINS_SUBDIR "plugin")
CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/ma_odbc_version.h.in
${CMAKE_SOURCE_DIR}/ma_odbc_version.h)
Expand Down Expand Up @@ -71,20 +77,59 @@ MACRO(ADD_OPTION _name _text _default)
ENDIF()
ENDMACRO()

INCLUDE(check_compiler_flag)

IF(WITH_ASAN)
IF(MSVC)
MA_SET_COMPILER_FLAG("-fsanitize=address" DEBUG RELWITHDEBINFO)
SET(MAODBC_LINKER_FLAGS ${MAODBC_LINKER_FLAGS} /INCREMENTAL:NO)
MA_SET_LINKER_FLAG("${MAODBC_LINKER_FLAGS}" DEBUG RELWITHDEBINFO)
ELSE()
MY_CHECK_AND_SET_COMPILER_FLAG("-U_FORTIFY_SOURCE" DEBUG RELWITHDEBINFO)
MY_CHECK_AND_SET_COMPILER_FLAG("-fsanitize=address -fPIC" DEBUG RELWITHDEBINFO)

SET(WITH_ASAN_OK 1)
FOREACH(lang ${MAODBC_LANGUAGES})
IF(NOT ${have_${lang}__fsanitize_address__fPIC})
SET(WITH_ASAN_OK 0)
ENDIF()
ENDFOREACH()
IF(WITH_ASAN_OK)
OPTION(WITH_ASAN_SCOPE "Enable -fsanitize-address-use-after-scope" OFF)
IF(WITH_ASAN_SCOPE)
MY_CHECK_AND_SET_COMPILER_FLAG("-fsanitize=address -fsanitize-address-use-after-scope" DEBUG RELWITHDEBINFO)
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR "Do not know how to enable address sanitizer")
ENDIF()
ENDIF()
ENDIF()

IF (WITH_UBSAN)
MY_CHECK_AND_SET_COMPILER_FLAG("-fsanitize=undefined -fno-sanitize=alignment -U_FORTIFY_SOURCE -DWITH_UBSAN" DEBUG RELWITHDEBINFO)
ENDIF()

IF (WITH_MSAN)
MY_CHECK_AND_SET_COMPILER_FLAG("-fsanitize=memory -fsanitize-memory-track-origins -U_FORTIFY_SOURCE" DEBUG RELWITHDEBINFO)
ENDIF()

# This has to be before C/C's cmake run, or it will build with /MD
IF(WIN32)
IF (MSVC)
SET(CONFIG_TYPES "DEBUG" "RELEASE" "RELWITHDEBINFO" "MINSIZEREL")
FOREACH(BUILD_TYPE ${CONFIG_TYPES})
FOREACH(COMPILER CXX C)
FOREACH(COMPILER ${MAODBC_LANGUAGES})
SET(COMPILER_FLAGS "${CMAKE_${COMPILER}_FLAGS_${BUILD_TYPE}}")
IF (NOT COMPILER_FLAGS STREQUAL "")
STRING(REPLACE "/MD" "/MT" COMPILER_FLAGS ${COMPILER_FLAGS})
IF (BUILD_TYPE STREQUAL "Debug")
SET(COMPILER_FLAGS "${COMPILER_FLAGS} /RTC1 /RTCc")
IF(NOT WITH_ASAN)
STRING(REPLACE "/MD" "/MT" COMPILER_FLAGS ${COMPILER_FLAGS})
IF (BUILD_TYPE STREQUAL "Debug")
SET(COMPILER_FLAGS "${COMPILER_FLAGS} /RTC1 /RTCc")
ENDIF()
STRING(REPLACE "/Zi" "/ZI" COMPILER_FLAGS ${COMPILER_FLAGS})
ENDIF()
ENDIF(NOT WITH_ASAN)
MESSAGE (STATUS "CMAKE_${COMPILER}_FLAGS_${BUILD_TYPE}= ${COMPILER_FLAGS}")
MESSAGE (STATUS "CMAKE_SHARED_LINKER_FLAGS_${BUILD_TYPE}= ${CMAKE_SHARED_LINKER_FLAGS_${BUILD_TYPE}}")
SET(CMAKE_${COMPILER}_FLAGS_${BUILD_TYPE} ${COMPILER_FLAGS} CACHE
STRING "overwritten by mariadb-odbc" FORCE)
ENDIF()
Expand All @@ -95,15 +140,14 @@ IF(WIN32)
SET(INSTALL_PLUGINDIR "${MARIADB_DEFAULT_PLUGINS_SUBDIR}")
ENDIF()

INCLUDE(${CMAKE_SOURCE_DIR}/cmake/SearchLibrary.cmake)
INCLUDE(${CMAKE_SOURCE_DIR}/cmake/SetValueMacro.cmake)
INCLUDE(SearchLibrary)
INCLUDE(SetValueMacro)

### Build options, initial settings and platform defaults
INCLUDE("${CMAKE_SOURCE_DIR}/cmake/options_defaults.cmake")
INCLUDE("options_defaults")

### Setting installation paths - should go before C/C subproject sets its own. We need to have control over those
INCLUDE("${CMAKE_SOURCE_DIR}/cmake/install.cmake")

INCLUDE("install")

IF(WIN32 OR WITH_OPENSSL OR "${WITH_SSL}" STREQUAL "OPENSSL")
# If C/C is linked dynamically, we don't need link C/ODBC against encryption library
Expand Down Expand Up @@ -140,7 +184,7 @@ IF(NOT USE_SYSTEM_INSTALLED_LIB)
SET(ODBC_GIT_BUILD_SRCPKG TRUE)
ENDIF()
MESSAGE(STATUS "Running C/C cmake scripts")
INCLUDE(${CMAKE_SOURCE_DIR}/cmake/connector_c.cmake)
INCLUDE(connector_c)

INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/libmariadb/include)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR}/libmariadb/include)
Expand Down Expand Up @@ -254,7 +298,7 @@ ENDIF()

IF(NOT WIN32)
# Looking for DM(UnixODBC) files
INCLUDE(${CMAKE_SOURCE_DIR}/cmake/FindDM.cmake)
INCLUDE(FindDM)

IF(DM_FOUND)
INCLUDE_DIRECTORIES(${ODBC_INCLUDE_DIR})
Expand All @@ -270,7 +314,7 @@ IF(APPLE OR CMAKE_SYSTEM_NAME MATCHES AIX)
SET(PLATFORM_DEPENDENCIES ${PLATFORM_DEPENDENCIES} ${ICONV_LIBRARIES})
ELSE()
# Looking for iconv files
INCLUDE(${CMAKE_SOURCE_DIR}/cmake/FindIconv.cmake)
INCLUDE(FindIconv)
IF(ICONV_FOUND)
INCLUDE_DIRECTORIES(${ICONV_INCLUDE_DIR})
SET(PLATFORM_DEPENDENCIES ${PLATFORM_DEPENDENCIES} ${ICONV_LIBRARIES})
Expand Down Expand Up @@ -345,6 +389,7 @@ ELSE()

IF(APPLE)
SET(MAODBC_INSTALL_RPATH "${ODBC_LIB_DIR}" "@loader_path" "/usr/local/opt/libiodbc" "/usr/local/iODBC/lib" "/usr/local/opt/[email protected]/lib" "/usr/local/opt/libressl/lib")
# Not sure is that -Wl right here, and why is it here
SET_TARGET_PROPERTIES(${LIBRARY_NAME}
PROPERTIES LINK_FLAGS "-Wl"
INSTALL_RPATH_USE_LINK_PATH 0
Expand Down
113 changes: 113 additions & 0 deletions cmake/check_compiler_flag.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
include(CheckCSourceCompiles)
include(CheckCXXSourceCompiles)

# We need some extra FAIL_REGEX patterns
# Note that CHECK_C_SOURCE_COMPILES is a misnomer, it will also link.
SET(fail_patterns
FAIL_REGEX "argument unused during compilation"
FAIL_REGEX "unsupported .*option"
FAIL_REGEX "unknown .*option"
FAIL_REGEX "unrecognized .*option"
FAIL_REGEX "ignoring unknown option"
FAIL_REGEX "warning:.*ignored"
FAIL_REGEX "warning:.*is valid for.*but not for"
FAIL_REGEX "warning:.*redefined"
FAIL_REGEX "[Ww]arning: [Oo]ption"
)
#The regex patterns above are not localized, thus LANG=C
SET(ENV{LANG} C)
MACRO (MY_CHECK_C_COMPILER_FLAG flag)
STRING(REGEX REPLACE "[-,= +]" "_" result "have_C_${flag}")
SET(SAVE_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${flag}")
CHECK_C_SOURCE_COMPILES("int main(void) { return 0; }" ${result}
${fail_patterns})
SET(CMAKE_REQUIRED_FLAGS "${SAVE_CMAKE_REQUIRED_FLAGS}")
ENDMACRO()

MACRO (MY_CHECK_CXX_COMPILER_FLAG flag)
STRING(REGEX REPLACE "[-,= +]" "_" result "have_CXX_${flag}")
SET(SAVE_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${flag}")
CHECK_CXX_SOURCE_COMPILES("int main(void) { return 0; }" ${result}
${fail_patterns})
SET(CMAKE_REQUIRED_FLAGS "${SAVE_CMAKE_REQUIRED_FLAGS}")
ENDMACRO()

FUNCTION(MY_CHECK_AND_SET_COMPILER_FLAG flag_to_set)
# At the moment this is gcc-only.
# Let's avoid expensive compiler tests on Windows:
IF(WIN32)
RETURN()
ENDIF()
STRING(REGEX REPLACE "^-Wno-" "-W" flag_to_check ${flag_to_set})

LIST(FIND MAODBC_LANGUAGES "C" LANGIDX)
IF(NOT LANGIDX EQUAL -1)
MY_CHECK_C_COMPILER_FLAG(${flag_to_check})
ENDIF()
LIST(FIND MAODBC_LANGUAGES "CXX" LANGIDX)
IF(NOT LANGIDX EQUAL -1)
MY_CHECK_CXX_COMPILER_FLAG(${flag_to_check})
ENDIF()

STRING(REGEX REPLACE "[-,= +]" "_" result "${flag_to_check}")
MESSAGE(STATUS "Langs: ${MAODBC_LANGUAGES}")
FOREACH(lang ${MAODBC_LANGUAGES})
IF (have_${lang}_${result})
IF(ARGN)
FOREACH(type ${ARGN})
SET(CMAKE_${lang}_FLAGS_${type} "${CMAKE_${lang}_FLAGS_${type}} ${flag_to_set}" PARENT_SCOPE)
ENDFOREACH()
ELSE()
SET(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS} ${flag_to_set}" PARENT_SCOPE)
ENDIF()
ENDIF()
ENDFOREACH()
ENDFUNCTION()

FUNCTION(MA_SET_COMPILER_FLAG flag_to_set)
IF(MSVC)
STRING(REGEX REPLACE "-" "/" result_flag "${flag_to_set}")
ENDIF()
GET_PROPERTY(languages GLOBAL PROPERTY ENABLED_LANGUAGES)
MESSAGE(STATUS "Langs: ${MAODBC_LANGUAGES}")
FOREACH(lang ${MAODBC_LANGUAGES})
IF(ARGN)
FOREACH(type ${ARGN})
STRING(REGEX REPLACE "${result_flag}" "" CMAKE_${lang}_FLAGS_${type} "${CMAKE_${lang}_FLAGS_${type}}")
SET(CMAKE_${lang}_FLAGS_${type} "${CMAKE_${lang}_FLAGS_${type}} ${result_flag}" PARENT_SCOPE)
ENDFOREACH()
ELSE()
STRING(REGEX REPLACE "${result_flag}" "" CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS}")
SET(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS} ${result_flag}" PARENT_SCOPE)
ENDIF()
ENDFOREACH()
ENDFUNCTION()

FUNCTION(MA_SET_LINKER_FLAG flag_to_set)
IF(MSVC)
STRING(REGEX REPLACE ":NO" "" flag_to_check ${flag_to_set})
STRING(REGEX REPLACE "-" "/" result_flag "${flag_to_set}")
ELSE()
STRING(REGEX REPLACE "^-Wno-" "-W" flag_to_check ${flag_to_set})
SET(result_flag "${flag_to_set}")
ENDIF()
IF(ARGN)
FOREACH(type ${ARGN})
STRING(REGEX REPLACE "${flag_to_set}" "" CMAKE_EXE_LINKER_FLAGS_${type} "${CMAKE_EXE_LINKER_FLAGS_${type}}")
STRING(REGEX REPLACE "${flag_to_set}" "" CMAKE_SHARED_LINKER_FLAGS_${type} "${CMAKE_SHARED_LINKER_FLAGS_${type}}")
STRING(REGEX REPLACE "${flag_to_set}" "" CMAKE_MODULE_LINKER_FLAGS_${type} "${CMAKE_MODULE_LINKER_FLAGS_${type}}")
STRING(REGEX REPLACE "${flag_to_check}" "" CMAKE_EXE_LINKER_FLAGS_${type} "${CMAKE_EXE_LINKER_FLAGS_${type}}")
STRING(REGEX REPLACE "${flag_to_check}" "" CMAKE_SHARED_LINKER_FLAGS_${type} "${CMAKE_SHARED_LINKER_FLAGS_${type}}")
STRING(REGEX REPLACE "${flag_to_check}" "" CMAKE_MODULE_LINKER_FLAGS_${type} "${CMAKE_MODULE_LINKER_FLAGS_${type}}")
#MESSAGE(STATUS "Before: ${CMAKE_EXE_LINKER_FLAGS_${type}} ${CMAKE_SHARED_LINKER_FLAGS_${type}} ${CMAKE_MODULE_LINKER_FLAGS_${type}}")
SET(CMAKE_EXE_LINKER_FLAGS_${type} "${CMAKE_EXE_LINKER_FLAGS_${type}} ${result_flag}" PARENT_SCOPE)
SET(CMAKE_SHARED_LINKER_FLAGS_${type} "${CMAKE_SHARED_LINKER_FLAGS_${type}} ${result_flag}" PARENT_SCOPE)
SET(CMAKE_MODULE_LINKER_FLAGS_${type} "${CMAKE_MODULE_LINKER_FLAGS_${type}} ${result_flag}" PARENT_SCOPE)
#MESSAGE(STATUS "After: ${CMAKE_EXE_LINKER_FLAGS_${type}} ${CMAKE_SHARED_LINKER_FLAGS_${type}} ${CMAKE_MODULE_LINKER_FLAGS_${type}}, Expected: ${CMAKE_SHARED_LINKER_FLAGS_${type}} ${result_flag}")
ENDFOREACH()
ELSE()
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${result_flag}" PARENT_SCOPE)
ENDIF()
ENDFUNCTION()
14 changes: 12 additions & 2 deletions cmake/options_defaults.cmake
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (C) 2021 MariaDB Corporation AB
# Copyright (C) 2021,2023 MariaDB Corporation AB
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
Expand All @@ -8,18 +8,24 @@

OPTION(BUILD_INTERACTIVE_TESTS "Build test(s) requiring user interaction" OFF)
OPTION(USE_INTERACTIVE_TESTS "Run interactive test(s) with ctest" OFF)
OPTION(CONC_WITH_UNIT_TESTS "Build C/C unit tests" OFF)
OPTION(WITH_ASAN "Compile with ASAN" OFF)
OPTION(WITH_UBSAN "Enable undefined behavior sanitizer" OFF)
OPTION(WITH_MSAN "Enable memory sanitizer" OFF)

IF(WIN32)
OPTION(WITH_MSI "Build MSI installation package" ON)
OPTION(CONC_WITH_MSI "Build C/C MSI installation package" OFF)
OPTION(WITH_SIGNCODE "Digitally sign files" OFF)

OPTION(MARIADB_LINK_DYNAMIC "Link Connector/C library dynamically" OFF)
OPTION(ALL_PLUGINS_STATIC "Compile all plugins in, i.e. make them static" ON)
SET(CLIENT_PLUGIN_PVIO_NPIPE "STATIC")
# We don't provide its support in ODBC yet, thus there is no need to bloat the library size
#SET(CLIENT_PLUGIN_PVIO_SHMEM "STATIC")
SET(WITH_UBSAN OFF)
SET(WITH_MSAN OFF)
ELSE()
OPTION(WITH_MSI "Build MSI installation package" OFF)
IF(APPLE)
OPTION(MARIADB_LINK_DYNAMIC "Link Connector/C library dynamically" OFF)
ELSE()
Expand Down Expand Up @@ -52,6 +58,8 @@ IF(NOT EXISTS ${CMAKE_SOURCE_DIR}/libmariadb)
SET(USE_SYSTEM_INSTALLED_LIB ON)
ENDIF()

SET(MAODBC_LINKER_FLAGS "")

IF(APPLE)
SET(CMAKE_SKIP_BUILD_RPATH FALSE)
SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
Expand Down Expand Up @@ -79,6 +87,8 @@ IF(WIN32)
SET(MARIADB_LINK_DYNAMIC OFF)
ENDIF()
ELSE()
SET(WITH_MSI OFF)
SET(CONC_WITH_MSI OFF)
# Defaults for creating odbc(inst).ini for tests with Unix/iOdbc
IF(WITH_UNIT_TESTS)
SET_VALUE(TEST_DRIVER "maodbc_test")
Expand Down
4 changes: 3 additions & 1 deletion ma_string.c
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,9 @@ my_bool MADB_DynStrGetWhere(MADB_Stmt *Stmt, MADB_DynString *DynString, char *Ta
/* If we already know index columns - we walk through column index values stored in Stmt->UniqueIndex, all columns otherwise */
for (i= IndexArrIdx == 0 ? 0 : Stmt->UniqueIndex[1];
IndexArrIdx == 0 ? i < MADB_STMT_COLUMN_COUNT(Stmt) : IndexArrIdx <= Stmt->UniqueIndex[0];
i= IndexArrIdx == 0 ? i + 1 : Stmt->UniqueIndex[++IndexArrIdx])
i= IndexArrIdx == 0 ? i + 1 : (++IndexArrIdx > Stmt->UniqueIndex[0] ? 0 /* Doesn't really matter what we set here - loop won't go further,
we just don't want to read past Stmt->UniqueIndex allocated area */
: Stmt->UniqueIndex[IndexArrIdx]))
{
MYSQL_FIELD *field= mysql_fetch_field_direct(Stmt->metadata, i);

Expand Down
2 changes: 1 addition & 1 deletion test/multistatement.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ ODBC_TEST(test_semicolon)
Also tests ODBC-97*/
ODBC_TEST(t_odbc74)
{
SQLCHAR ref[][4]= {"\"", "'", "*/", "/*", "end", "one\\", "two\\"}, val[8];
SQLCHAR ref[][6]= {"\"", "'", "*/", "/*", "end", "one\\", "two\\"}, val[10];
unsigned int i;
SQLHDBC hdbc1;
SQLHSTMT Stmt1;
Expand Down
6 changes: 3 additions & 3 deletions test/param.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,13 +376,13 @@ ODBC_TEST(t_param_offset)
{
rows[20+i].id= i * 10;
rows[20+i].x= (i * 1000) % 97;
OK_SIMPLE_STMT(Stmt, "insert into t_param_offset values (?,?)");
OK_SIMPLE_STMT(Stmt, "INSERT INTO t_param_offset VALUES (?,?)");
bind_offset+= row_size;
}

/* verify the data */

OK_SIMPLE_STMT(Stmt, "select id, x from t_param_offset order by 1");
CHECK_STMT_RC(Stmt, SQLFreeStmt(Stmt, SQL_RESET_PARAMS));
OK_SIMPLE_STMT(Stmt, "SELECT id, x FROM t_param_offset order by 1");

CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 1, SQL_C_LONG, &out_id, 0, NULL));
CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 2, SQL_C_LONG, &out_x, 0, NULL));
Expand Down
17 changes: 13 additions & 4 deletions test/tap.h
Original file line number Diff line number Diff line change
Expand Up @@ -652,9 +652,18 @@ do {\
}

#define IS(A) if (!(A)) { diag("Error in %s:%d", __FILE__, __LINE__); return FAIL; }
#define IS_STR_EX(A,B,C,D) do {const char *loc_a=(const char *)(A), *loc_b=(const char *)(B);\
if ((D)) diag("%s %s", loc_a, loc_b);\
FAIL_IF(loc_a == NULL || loc_b == NULL || strncmp(loc_a, loc_b, (C)) != 0, "Strings do not match"); } while(0)

BOOL is_str_ex(const char* str1, const char* str2, size_t len, BOOL verbose)
{
if (verbose)
{
fprintf(stdout, "# %s %s", str1, str2);
}
return str1 == NULL || str2 == NULL || strncmp(str1, str2, len) != 0;
}

#define IS_STR_EX(A,B,C,D) FAIL_IF(is_str_ex((const char *)(A), (const char *)(B), (C), (D)), "Strings do not match")

#define IS_STR(A,B,C) IS_STR_EX(A,B,C,TRUE)

#define is_num(A,B) \
Expand Down Expand Up @@ -719,7 +728,7 @@ SQLWCHAR *my_fetch_wstr(SQLHSTMT Stmt, SQLWCHAR *buffer, SQLUSMALLINT icol, SQLL

const char *my_fetch_str(SQLHSTMT Stmt, SQLCHAR *szData, SQLUSMALLINT icol)
{
SQLLEN nLen;
SQLLEN nLen= 0;

SQLGetData(Stmt, icol, SQL_CHAR, szData, 1000, &nLen);
/* If Null value - putting down smth meaningful. also that allows caller to
Expand Down

0 comments on commit 00f2da1

Please sign in to comment.