Details
-
Bug
-
Status: Confirmed (View Workflow)
-
Major
-
Resolution: Unresolved
-
10.11, 11.4, 11.8, 12.3, 13.1, 13.2
-
MariaDB 13.2.0-MariaDB-asan (Source distribution), @@version_source_revision
f6d172c03bf3cd71fd30ac9cc7b24fd64497b472 (main branch, 2026-10-21).
Build: cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DWITH_ASAN=ON -DWITH_ASAN_SCOPE=ON,
GCC with libsanitizer, Linux x86_64.
Client: python3 + mysql-connector-python (the reproducer sends raw
COM_STMT_PREPARE / COM_STMT_EXECUTE packets).MariaDB 13.2.0-MariaDB-asan (Source distribution), @@version_source_revision f6d172c03bf3cd71fd30ac9cc7b24fd64497b472 (main branch, 2026-10-21). Build: cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DWITH_ASAN=ON -DWITH_ASAN_SCOPE=ON, GCC with libsanitizer, Linux x86_64. Client: python3 + mysql-connector-python (the reproducer sends raw COM_STMT_PREPARE / COM_STMT_EXECUTE packets).
-
Can result in hang or crash
-
Crash when a large binary-protocol PS string parameter is materialized into an Aria temporary table (UNION DISTINCT dedup)
Description
Summary
When a prepared-statement parameter is declared at the protocol level as
MYSQL_TYPE_STRING (0xfe) and carries a large value (value_bytes * connection
mbmaxlen > 65535), and that parameter is placed directly into an output column
of a UNION DISTINCT over a two-table join, the union dedup temporary table
(Aria, dynamic record format) materializes a row whose blob slot holds a
(length, pointer) pair that does not describe a real buffer. _ma_rec_pack()
then memcpys from the wild address. AddressSanitizer aborts the server; in a
non-ASan build this is a read from an arbitrary address (server crash,
potentially copying arbitrary memory into the temporary table).
Steps to reproduce
- Build the server with -DWITH_ASAN=ON (RelWithDebInfo) and start mariadbd.
- Run the attached reproduce_report.py (requires python3 and
mysql-connector-python):python3 reproduce_report.py -H 127.0.0.1 -P 3306 -u root
The script creates two tiny InnoDB tables (1 row each), then sends
COM_STMT_PREPARE for:
select ref_1.c7, ?, 1, ref_1.c2, ref_0.c1, ref_1.c7 |
from t1 ref_0 inner join t2 ref_1 on (ref_0.c1 >= ref_1.c1) |
union (select 1,2,3,4,5,6) |
and a COM_STMT_EXECUTE whose single parameter has protocol type byte 0xfe
(MYSQL_TYPE_STRING) with a 32869-byte value.
Note on temp table engine: on current main (since MDEV-38975, HEAP blob
support) the internal temp table stays in HEAP with default settings, so the
script forces conversion to Aria with:
SET SESSION tmp_memory_table_size=1024; |
SET SESSION max_heap_table_size=1024; |
Actual result
mariadbd aborts (AddressSanitizer CHECK failed, "Address is not in memory and
not in shadow"):
#8 __interceptor_memcpy
|
#9 _ma_rec_pack storage/maria/ma_dynrec.c:1023
|
#10 _ma_write_blob_record storage/maria/ma_dynrec.c:266
|
#11 maria_write storage/maria/ma_write.c:285
|
#12 handler::ha_write_tmp_row sql/sql_class.h:8238
|
#13 select_unit::write_record sql/sql_union.cc:417
|
#14 select_unit::send_data sql/sql_union.cc:161
|
#15 select_result_sink::send_data_with_check sql/sql_class.cc:3381
|
#16 end_send sql/sql_select.cc:26975
|
#17 JOIN_CACHE::generate_full_extensions sql/sql_join_cache.cc:2538
|
...
|
#33 mysqld_stmt_execute sql/sql_prepare.cc:3407
|
The full ASan trace is attached (mariadb_error_delta.log).
Expected result
The statement executes (or returns an error) without crashing the server.
Analysis / notes
- The bug requires the binary protocol: the parameter must arrive with protocol
type MYSQL_TYPE_STRING (0xfe). SQL-level PREPARE / EXECUTE ... USING,
CAST/CONVERT and text inlining cannot produce this type handler for a value
of this size and do NOT reproduce the crash. COM_STMT_EXECUTE flags are
irrelevant. - Size threshold: value_bytes * connection mbmaxlen > 65535 (with utf8mb4,
16384 bytes suffice). - Trigger requirements (verified by ablation): UNION DISTINCT (UNION ALL does
not crash), >= 6 projection columns (5 do not crash), a two-table join
(join-cache path), real tables (1 row each suffices), and the parameter value
carried straight into a UNION output column. - Root cause: the blob slot of the temp-table record carries a (length,
pointer) pair that does not describe a real buffer; _ma_rec_pack() memcpys
from the wild address. - Reproduced on 13.2.0-MariaDB-asan @ f6d172c03bf3 (main, 2026-10-21).