Details
-
Bug
-
Status: Closed (View Workflow)
-
Major
-
Resolution: Fixed
-
3.2.6, 3.2.10
-
None
-
Linux x86_64 (openSUSE Tumbleweed), unixODBC 2.3.14, MariaDB Server 11.8.9; 3.2.6 = distribution package, 3.2.10 = fedora43 tarball from dlm.mariadb.com (bundled libmariadb 3.4.11)
Description
If a parameter array execute (SQL_ATTR_PARAMSET_SIZE > 1) fails - e.g. with a duplicate key in one of the rows - the next execute of the same SQL text on the same connection crashes, even on a new statement handle with SQL_ATTR_PARAMSET_SIZE = 1.
The single row execute builds a bulk request (ma_stmt_execute_generate_bulk_request) - the server side prepared statement taken from the prepared statement cache apparently still has the array size of the failed execute.
Steps to reproduce (program attached, crash.c):
- CREATE TABLE odbc_ps_crash (id INT PRIMARY KEY, name VARCHAR(20)); INSERT INTO odbc_ps_crash VALUES (1, 'x')
- statement 1: SQLPrepare "INSERT INTO odbc_ps_crash (id, name) VALUES (?, ?)", column-wise binding (SQL_C_LONG, SQL_C_CHAR), SQL_ATTR_PARAMSET_SIZE = 3, ids 2, 1, 3 -> SQLExecute fails with 23000 Duplicate entry '1' (expected). SQLFreeHandle.
- statement 2 (new handle): SQLPrepare of the same text, bind one row (id 10, name 'single'), SQLExecute -> SIGSEGV
gcc -o crash crash.c -lodbc
|
./crash <DSN> <user> <password>
|
 |
SQLExecute (array, duplicate key expected): rc=-1 [23000] [ma-3.2.10][11.8.9-MariaDB-ubu2404]Duplicate entry '1' for key 'PRIMARY'
|
SQLPrepare (single row): rc=0
|
Segmentation fault (core dumped)
|
Backtrace (3.2.10):
#0 __memmove_avx_unaligned_erms () from /lib64/libc.so.6
|
#1 store_param (...) at libmariadb/libmariadb/mariadb_stmt.c:797
|
#2 ma_stmt_execute_generate_bulk_request (...) at libmariadb/libmariadb/mariadb_stmt.c:1210
|
#3 ma_stmt_execute_generate_request (...) at libmariadb/libmariadb/mariadb_stmt.c:1246
|
#5 mysql_stmt_execute (...) at libmariadb/libmariadb/mariadb_stmt.c:2293
|
#6 mariadb::Protocol::executePreparedQuery (...) at driver/cppmini/class/Protocol.cpp:961
|
#7 mariadb::ServerSidePreparedStatement::executeInternal (...)
|
#8 MADB_DoExecute (Stmt=..., ParamsPushed=true) at driver/ma_statement.cpp:1086
|
#9 MADB_StmtExecute (...) at driver/ma_statement.cpp:1393
|
#10 MA_SQLExecute (...) at driver/ma_api_internal.cpp:1143
|
The fault address is the parameter data itself ("single" read as a pointer: 0x656c676e6973), i.e. the single row data is processed as if it were the bulk layout.
Observations
- Crashes with PCALLBACK=1 (default) and PCALLBACK=0.
- No crash with PSCACHESIZE=0, and no crash if the second statement uses a different SQL text (e.g. an extra blank) - so the prepared statement cache is involved.
- No crash if the array execute succeeds.
ODBC-506(fixed in 3.2.10) looks related but does not cover this case.
Workaround: PSCACHESIZE=0 in the DSN, or no parameter arrays.
The analysis and the test program were made with AI assistance (Claude); I have verified the results.