Description:
When an UPDATE on a parent table triggers an ON UPDATE CASCADE into a child table that has a generated column using REGEXP_REPLACE (also REGEXP_LIKE / REGEXP), the cascade itself succeeds but leaves the REGEXP item of the child's cached TABLE instance in a broken state. The next use of that child table on the same connection (another cascade, or even a plain SELECT) crashes the server with an access violation. This looks like a use-after-free of the regexp item (the Regexp_facade engine) evaluated during update_generated_read_fields from the FK cascade path.
Observed backtrace (cascading UPDATE variant):
update_single_table
-> check_all_child_fk_ref
-> update_generated_read_fields
-> Item_func_regexp_replace::val_str
-> Item_func_regexp::set_pattern
-> Regexp_facade::SetPattern / SetupEngine
-> crash (0xc0000005)
Other observed backtraces, apparently the same broken item freed later:
Prepared_statement::prepare -> close_thread_tables -> cleanup_items -> Item_func_regexp::cleanup
open_table -> Table_cache::add_used_table -> free_unused_tables_if_necessary -> intern_close_table -> closefrm -> free_items
Crash is reproducible 3 out of 3 from a clean mysql CLI session. Prepared statements are not required.
Variants that crash: utf8mb4 only (no charset conversion), VIRTUAL instead of STORED, REGEXP_LIKE / REGEXP operator, child read or updated normally first.
Variants that do NOT crash: UPPER() instead of REGEXP (control), cascading DELETEs, plain UPDATEs of the child, the same cascades run as prepared statements (1 try only).
Workaround verified: with innodb_native_foreign_keys=ON (option file + restart) the same script runs 3 out of 3 without crashing and the cascades are applied correctly, so the bug is specific to the SQL-layer FK path. Not tested on 8.4.x.
Config: innodb_native_foreign_keys=OFF (SQL-layer FK enforcement), InnoDB, utf8mb4. MySQL 9.7.4 Community Server, Windows 11 x64.
How to repeat:
Run with the mysql CLI in any scratch schema (the connect; client command opens a new connection and is essential: if the child table was already opened by an ordinary statement in the same table-cache instance, the bug does not trigger):
DROP TABLE IF EXISTS zz_crash_child;
DROP TABLE IF EXISTS zz_crash_parent;
CREATE TABLE zz_crash_parent (
id INT UNSIGNED NOT NULL PRIMARY KEY,
nif VARCHAR(25) DEFAULT NULL,
UNIQUE KEY (nif)
) ENGINE=InnoDB;
CREATE TABLE zz_crash_child (
id INT UNSIGNED NOT NULL PRIMARY KEY,
ext VARCHAR(25) NOT NULL,
ext_custom VARCHAR(23) GENERATED ALWAYS AS (regexp_replace(ext, '_(C|IU|U)$', '')) STORED,
nif VARCHAR(25) DEFAULT NULL,
KEY (nif),
CONSTRAINT zz_crash_child_fk FOREIGN KEY (nif) REFERENCES zz_crash_parent (nif)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;
INSERT INTO zz_crash_parent VALUES (1, 'A_IU'), (2, 'B_IU');
INSERT INTO zz_crash_child (id, ext, nif) VALUES (1, 'X_C', 'A_IU'), (2, 'Y_C', 'B_IU');
connect;
-- succeeds, but leaves the cached child TABLE with a broken regexp item
UPDATE zz_crash_parent SET nif = 'A' WHERE id = 1;
-- server crashes here (a plain SELECT * FROM zz_crash_child also crashes)
UPDATE zz_crash_parent SET nif = 'B' WHERE id = 2;
SELECT * FROM zz_crash_child;
Expected: both cascades succeed, child rows updated, server stays up.
Actual: ERROR 2013 (HY000): Lost connection to MySQL server during query; mysqld terminates with exception 0xc0000005.
Suggested fix:
Not investigated at source level. The evidence points to the regexp item (Regexp_facade pattern/engine state) of a TABLE instance whose generated-column expression was evaluated by the FK cascade code (check_all_child_fk_ref / update_generated_read_fields) being left dangling, probably because the item is not properly (re)prepared or cleaned up in that path while the table is cached. Ensuring the cascade path opens/prepares the child's generated-column items the same way a regular statement does, and that Item_func_regexp::cleanup leaves the facade in a state safe to re-set, should be checked.
Description: When an UPDATE on a parent table triggers an ON UPDATE CASCADE into a child table that has a generated column using REGEXP_REPLACE (also REGEXP_LIKE / REGEXP), the cascade itself succeeds but leaves the REGEXP item of the child's cached TABLE instance in a broken state. The next use of that child table on the same connection (another cascade, or even a plain SELECT) crashes the server with an access violation. This looks like a use-after-free of the regexp item (the Regexp_facade engine) evaluated during update_generated_read_fields from the FK cascade path. Observed backtrace (cascading UPDATE variant): update_single_table -> check_all_child_fk_ref -> update_generated_read_fields -> Item_func_regexp_replace::val_str -> Item_func_regexp::set_pattern -> Regexp_facade::SetPattern / SetupEngine -> crash (0xc0000005) Other observed backtraces, apparently the same broken item freed later: Prepared_statement::prepare -> close_thread_tables -> cleanup_items -> Item_func_regexp::cleanup open_table -> Table_cache::add_used_table -> free_unused_tables_if_necessary -> intern_close_table -> closefrm -> free_items Crash is reproducible 3 out of 3 from a clean mysql CLI session. Prepared statements are not required. Variants that crash: utf8mb4 only (no charset conversion), VIRTUAL instead of STORED, REGEXP_LIKE / REGEXP operator, child read or updated normally first. Variants that do NOT crash: UPPER() instead of REGEXP (control), cascading DELETEs, plain UPDATEs of the child, the same cascades run as prepared statements (1 try only). Workaround verified: with innodb_native_foreign_keys=ON (option file + restart) the same script runs 3 out of 3 without crashing and the cascades are applied correctly, so the bug is specific to the SQL-layer FK path. Not tested on 8.4.x. Config: innodb_native_foreign_keys=OFF (SQL-layer FK enforcement), InnoDB, utf8mb4. MySQL 9.7.4 Community Server, Windows 11 x64. How to repeat: Run with the mysql CLI in any scratch schema (the connect; client command opens a new connection and is essential: if the child table was already opened by an ordinary statement in the same table-cache instance, the bug does not trigger): DROP TABLE IF EXISTS zz_crash_child; DROP TABLE IF EXISTS zz_crash_parent; CREATE TABLE zz_crash_parent ( id INT UNSIGNED NOT NULL PRIMARY KEY, nif VARCHAR(25) DEFAULT NULL, UNIQUE KEY (nif) ) ENGINE=InnoDB; CREATE TABLE zz_crash_child ( id INT UNSIGNED NOT NULL PRIMARY KEY, ext VARCHAR(25) NOT NULL, ext_custom VARCHAR(23) GENERATED ALWAYS AS (regexp_replace(ext, '_(C|IU|U)$', '')) STORED, nif VARCHAR(25) DEFAULT NULL, KEY (nif), CONSTRAINT zz_crash_child_fk FOREIGN KEY (nif) REFERENCES zz_crash_parent (nif) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB; INSERT INTO zz_crash_parent VALUES (1, 'A_IU'), (2, 'B_IU'); INSERT INTO zz_crash_child (id, ext, nif) VALUES (1, 'X_C', 'A_IU'), (2, 'Y_C', 'B_IU'); connect; -- succeeds, but leaves the cached child TABLE with a broken regexp item UPDATE zz_crash_parent SET nif = 'A' WHERE id = 1; -- server crashes here (a plain SELECT * FROM zz_crash_child also crashes) UPDATE zz_crash_parent SET nif = 'B' WHERE id = 2; SELECT * FROM zz_crash_child; Expected: both cascades succeed, child rows updated, server stays up. Actual: ERROR 2013 (HY000): Lost connection to MySQL server during query; mysqld terminates with exception 0xc0000005. Suggested fix: Not investigated at source level. The evidence points to the regexp item (Regexp_facade pattern/engine state) of a TABLE instance whose generated-column expression was evaluated by the FK cascade code (check_all_child_fk_ref / update_generated_read_fields) being left dangling, probably because the item is not properly (re)prepared or cleaned up in that path while the table is cached. Ensuring the cascade path opens/prepares the child's generated-column items the same way a regular statement does, and that Item_func_regexp::cleanup leaves the facade in a state safe to re-set, should be checked.