From 8ba535160cb7f587a617314e9b07541be08f6638 Mon Sep 17 00:00:00 2001 From: Dave Gosselin Date: Fri, 6 Dec 2024 11:36:38 -0500 Subject: [PATCH 1/5] CONC-750 unit.pfs_instr-oom fails on mac with dynamic-stack-overflow Write a NULL byte at end of the array used for reading the executable name, not at one past the end of the array. --- mariadb_config/mariadb_config.c.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mariadb_config/mariadb_config.c.in b/mariadb_config/mariadb_config.c.in index 5c057c4c..b79f0aca 100644 --- a/mariadb_config/mariadb_config.c.in +++ b/mariadb_config/mariadb_config.c.in @@ -175,7 +175,9 @@ static void mariadb_get_install_location() goto end; else { #if defined(__APPLE__) - unsigned int len= PATH_MAX; + // If reading the path was successful, then *bufsize is + // unchanged. + unsigned int len= PATH_MAX - 1; if (_NSGetExecutablePath(p, &len) != 0) *p= 0; else From 5485acd470410dbbf56ee28e302644822e6e373f Mon Sep 17 00:00:00 2001 From: Georg Richter Date: Fri, 20 Dec 2024 12:02:35 +0100 Subject: [PATCH 2/5] Test case fix: Don't connect with anonymous user, since mtr doesn't run with unix_sockets by default. --- unittest/libmariadb/connection.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unittest/libmariadb/connection.c b/unittest/libmariadb/connection.c index 5574557c..aaea1f8f 100644 --- a/unittest/libmariadb/connection.c +++ b/unittest/libmariadb/connection.c @@ -1981,8 +1981,8 @@ static int test_conc748(MYSQL *my __attribute__((unused))) mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL); mysql_optionsv(mysql, MYSQL_OPT_SSL_CIPHER, ciphers[i]); - if (!my_test_connect(mysql, hostname, NULL, - NULL, schema, port, socketname, 0)) + if (!my_test_connect(mysql, hostname, username, + password, schema, port, socketname, 0)) { diag("error: %s", mysql_error(mysql)); return FAIL; From 80a7fa5cee309dd194d13f3a1d6633b0ccd795a6 Mon Sep 17 00:00:00 2001 From: Georg Richter Date: Fri, 20 Dec 2024 14:35:37 +0100 Subject: [PATCH 3/5] Test fix for charsets Skipped 2 tests if running against MariaDB 11.4 or newer version. --- unittest/libmariadb/charset.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/unittest/libmariadb/charset.c b/unittest/libmariadb/charset.c index 6c432749..3579c55d 100644 --- a/unittest/libmariadb/charset.c +++ b/unittest/libmariadb/charset.c @@ -542,6 +542,11 @@ static int test_bug30472(MYSQL *mysql) diag("Test requires MySQL Server version 5.1 or above"); return SKIP; } + if (mariadb_connection(mysql) && mysql_get_server_version(mysql) >= 110400) + { + diag("C/C 3.3 doesn't support all collations from 11.4 and above"); + return SKIP; + } /* Retrieve character set information. */ mysql_set_character_set(mysql, "latin1"); @@ -796,7 +801,11 @@ static int test_conc223(MYSQL *mysql) int found= 0; SKIP_MYSQL(mysql); - + if (mariadb_connection(mysql) && mysql_get_server_version(mysql) >= 110400) + { + diag("C/C 3.3 doesn't support all collations from 11.4 and above"); + return SKIP; + } rc= mysql_query(mysql, "SELECT ID, CHARACTER_SET_NAME, COLLATION_NAME FROM INFORMATION_SCHEMA.COLLATIONS"); check_mysql_rc(rc, mysql); From 12a70541944bf21bfbb9a07d3a1af0345d12b3b6 Mon Sep 17 00:00:00 2001 From: Georg Richter Date: Sun, 22 Dec 2024 11:00:12 +0100 Subject: [PATCH 4/5] Partial revert of 1a2ed3f67af698b394b2faed069b49d4f409a155 Since Item_result enumerations are also used by MariaDB server, we moved them back to mariadb_com.h. Item_result is not used in Connector/C 3.3 and above for replication api. --- CMakeLists.txt | 14 +++++++++++++ include/mariadb_com.h | 2 ++ libmariadb/mariadb_lib.c | 43 ++++++++++++++++++++++++++++++++-------- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 31fcea9d..c3602e2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,6 +68,20 @@ ADD_OPTION(WITH_CURL "Enables use of curl" ON) ADD_OPTION(WITH_SSL "Enables use of TLS/SSL library" ON) ############### +if (WITH_ASAN) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -g -static-libasan") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-sanitize-recover=all") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-common") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-address-use-after-scope") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-sanitize=alignment") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-sanitize=null") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-sanitize=vptr") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libasan") +endif() + INCLUDE(${CC_SOURCE_DIR}/cmake/misc.cmake) INCLUDE(FindCURL) diff --git a/include/mariadb_com.h b/include/mariadb_com.h index 57e48925..195979af 100644 --- a/include/mariadb_com.h +++ b/include/mariadb_com.h @@ -59,6 +59,8 @@ enum mysql_enum_shutdown_level KILL_CONNECTION= 255 }; +enum Item_result {STRING_RESULT,REAL_RESULT,INT_RESULT,ROW_RESULT,DECIMAL_RESULT}; + enum enum_server_command { COM_SLEEP = 0, diff --git a/libmariadb/mariadb_lib.c b/libmariadb/mariadb_lib.c index ebe03a8d..0ce71dfc 100644 --- a/libmariadb/mariadb_lib.c +++ b/libmariadb/mariadb_lib.c @@ -879,6 +879,35 @@ static size_t rset_field_offsets[]= { OFFSET(MYSQL_FIELD, org_name_length) }; +/* calculate lengths for field metadata: + returns zero on success, 1 if null_length was + detected */ +static my_bool ma_get_rset_field_lengths(MYSQL_ROW row, unsigned int field_count, + unsigned long *lengths) +{ + unsigned long *last_length= 0; + char *pos= 0; + MYSQL_ROW end= row + field_count + 1; + my_bool rc= 0; + + while (row != end) + { + if (*row) + { + if (pos) + *last_length= (ulong)(*row - pos - 1); + pos= *row; + } else { + /* NULL_LENGTH (see also CONC-709) */ + rc= 1; + *last_length= 0; + } + last_length= lengths++; + row++; + } + return rc; +} + MYSQL_FIELD * unpack_fields(const MYSQL *mysql, MYSQL_DATA *data, MA_MEM_ROOT *alloc, uint fields, @@ -895,21 +924,19 @@ unpack_fields(const MYSQL *mysql, for (row=data->data; row ; row = row->next,field++) { + unsigned long lengths[9]; + if (field >= result + fields) goto error; + if (ma_get_rset_field_lengths(row->data, field_count, lengths)) + goto error; + for (i=0; i < field_count; i++) { - uint length; - - if (!row->data[i]) - goto error; - - length= (uint)(row->data[i+1] - row->data[i] - 1); - *(char **)(((char *)field) + rset_field_offsets[i*2])= ma_strdup_root(alloc, (char *)row->data[i]); - *(unsigned int *)(((char *)field) + rset_field_offsets[i*2+1])= length; + *(unsigned int *)(((char *)field) + rset_field_offsets[i*2+1])= lengths[i]; } field->extension= NULL; From e09e24e890931d2e8d7e6b9c4b8adf4f17e94866 Mon Sep 17 00:00:00 2001 From: Georg Richter Date: Wed, 15 Jan 2025 07:26:18 +0100 Subject: [PATCH 5/5] CONC-589: First query fails after reconnect If automatic reconnect is enabled (MYSQL_OPT_RECONNECT) it is mandatory to check if the connection/socket is still alive before sending a command to the server (unless the command is COM_QUIT). --- libmariadb/mariadb_lib.c | 9 ++++++ unittest/libmariadb/connection.c | 47 ++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/libmariadb/mariadb_lib.c b/libmariadb/mariadb_lib.c index 0ce71dfc..9cebe6df 100644 --- a/libmariadb/mariadb_lib.c +++ b/libmariadb/mariadb_lib.c @@ -382,6 +382,15 @@ mthd_my_send_cmd(MYSQL *mysql,enum enum_server_command command, const char *arg, { NET *net= &mysql->net; int result= -1; + + /* CONC-589: If reconnect option was specified, we have to check if the connection + (socket) is still available */ + if (command != COM_QUIT && mysql->options.reconnect && ma_pvio_is_alive(mysql->net.pvio)) + { + mysql->net.pvio= NULL; + mysql->net.error= 1; + } + if (mysql->net.pvio == 0) { /* Do reconnect if possible */ diff --git a/unittest/libmariadb/connection.c b/unittest/libmariadb/connection.c index aaea1f8f..58374593 100644 --- a/unittest/libmariadb/connection.c +++ b/unittest/libmariadb/connection.c @@ -1998,7 +1998,54 @@ static int test_conc748(MYSQL *my __attribute__((unused))) } #endif +static int test_conc589(MYSQL *my) +{ + MYSQL *mysql= mysql_init(NULL); + MYSQL_RES *result; + int rc; + my_bool reconnect= 1, verify= 0; + unsigned long last_thread_id= 0; + + mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect); + mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &verify); + + if (!my_test_connect(mysql, hostname, username, + password, schema, port, socketname, CLIENT_REMEMBER_OPTIONS)) + { + diag("error: %s", mysql_error(mysql)); + return FAIL; + } + + rc= mysql_query(mysql, "SET SESSION wait_timeout=5"); + check_mysql_rc(rc, mysql); + + last_thread_id= mysql_thread_id(mysql); + if ((rc= mysql_query(mysql, "SELECT 1")) || (result= mysql_store_result(mysql)) == NULL) + check_mysql_rc(rc, mysql); + + mysql_free_result(result); + sleep(10); + + if ((rc= mysql_query(mysql, "SELECT 2")) || (result= mysql_store_result(mysql)) == NULL) + check_mysql_rc(rc, mysql); + mysql_free_result(result); + FAIL_IF(mysql_thread_id(mysql) == last_thread_id, "Expected new connection id"); + last_thread_id= mysql_thread_id(mysql); + + mysql_kill(my, last_thread_id); + + sleep(10); + + if ((rc= mysql_query(mysql, "SELECT 3")) || (result= mysql_store_result(mysql)) == NULL) + check_mysql_rc(rc, mysql); + mysql_free_result(result); + FAIL_IF(mysql_thread_id(mysql) == last_thread_id, "Expected new connection id"); + mysql_close(mysql); + return OK; +} + struct my_tests_st my_tests[] = { + {"test_conc589", test_conc589, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL) {"test_conc748", test_conc748, TEST_CONNECTION_NONE, 0, NULL, NULL}, #endif