From da9bb98c0cef8097ee50341722f08d5042efbe49 Mon Sep 17 00:00:00 2001 From: Georg Richter Date: Tue, 27 Dec 2022 14:36:44 +0100 Subject: [PATCH] CONC-622: Fix double free() if asnyc connect failed If mysql_real_connect_start/cont failed, we need to set async->pvio to zero after calling ma_pvio_close to avoid double free() in mysql_close. --- libmariadb/mariadb_lib.c | 8 ++++++ unittest/libmariadb/async.c | 48 ++++++++++++++++++++++++++++++++ unittest/libmariadb/connection.c | 1 + 3 files changed, 57 insertions(+) diff --git a/libmariadb/mariadb_lib.c b/libmariadb/mariadb_lib.c index 33cf749c..3d403e24 100644 --- a/libmariadb/mariadb_lib.c +++ b/libmariadb/mariadb_lib.c @@ -1727,6 +1727,14 @@ restart: if (ma_pvio_connect(pvio, &cinfo) != 0) { ma_pvio_close(pvio); + if (mysql->options.extension && mysql->options.extension->async_context && + mysql->options.extension->async_context->pvio) + { + /* pvio delegated to mysql->net.pvio by ma_net_init(). + * invalidate the pvio pointer in the async context */ + mysql->options.extension->async_context->pvio = NULL; + } + if (is_multi) { connect_attempts++; diff --git a/unittest/libmariadb/async.c b/unittest/libmariadb/async.c index 4c1a30e3..5f9ca23b 100644 --- a/unittest/libmariadb/async.c +++ b/unittest/libmariadb/async.c @@ -248,12 +248,60 @@ static int test_conc129(MYSQL *unused __attribute__((unused))) return OK; } +static int test_conc622(MYSQL *my __attribute__((unused))) +{ + int rc; + MYSQL mysql, *ret; + int status; + uint default_timeout; + int i; + + if (skip_async) + return SKIP; + + for (i=0; i < 100; i++) + { + mysql_init(&mysql); + rc= mysql_options(&mysql, MYSQL_OPT_NONBLOCK, 0); + check_mysql_rc(rc, (MYSQL *)&mysql); + + /* set timeouts to 300 microseconds */ + default_timeout= 3; + mysql_options(&mysql, MYSQL_OPT_READ_TIMEOUT, &default_timeout); + mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, &default_timeout); + mysql_options(&mysql, MYSQL_OPT_WRITE_TIMEOUT, &default_timeout); + mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "myapp"); + + /* Returns 0 when done, else flag for what to wait for when need to block. */ + status= mysql_real_connect_start(&ret, &mysql, "0.0.0.0", username, password, schema, port, socketname, 0); + while (status) + { + status= wait_for_mysql(&mysql, status); + status= mysql_real_connect_cont(&ret, &mysql, status); + } + if (!ret) + { + status= mysql_close_start(&mysql); + while (status) + { + status= wait_for_mysql(&mysql, status); + status= mysql_close_cont(&mysql, status); + } + } else { + diag("Expected error when connection to host '0.0.0.0'"); + return FAIL; + } + } + return OK; +} + struct my_tests_st my_tests[] = { {"test_async", test_async, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"async1", async1, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc131", test_conc131, TEST_CONNECTION_NONE, 0, NULL, NULL}, {"test_conc129", test_conc129, TEST_CONNECTION_NONE, 0, NULL, NULL}, + {"test_conc622", test_conc622, TEST_CONNECTION_NONE, 0, NULL, NULL}, {NULL, NULL, 0, 0, NULL, NULL} }; diff --git a/unittest/libmariadb/connection.c b/unittest/libmariadb/connection.c index e9f4fdb4..7139fb34 100644 --- a/unittest/libmariadb/connection.c +++ b/unittest/libmariadb/connection.c @@ -1667,6 +1667,7 @@ static int test_conc312(MYSQL *my) if (rc) { + diag("Error: %s", mysql_error(my)); diag("caching_sha256_password not supported"); return SKIP; }