Description:
During trace-based concurrency analysis of MySQL 5.7.36, I found conflicting accesses to the ordinary bool buf_page_cleaner_is_active between the page cleaner coordinator and the thread performing InnoDB shutdown.
The relevant source locations are:
1. storage/innobase/buf/buf0flu.cc
The flag is declared as:
bool buf_page_cleaner_is_active = false;
In buf_flush_page_cleaner_coordinator(), the coordinator executes the following during exit:
buf_flush_page_cleaner_close();
buf_page_cleaner_is_active = false;
2. storage/innobase/log/log0log.cc
In logs_empty_and_mark_files_at_shutdown(), the shutdown thread polls the same flag:
while (buf_page_cleaner_is_active) {
...
os_thread_sleep(100000);
...
}
The surrounding comment explains that this loop waits for the page cleaner to complete buffer pool flushing before shutdown proceeds.
I could not identify synchronization that orders the coordinator's store to this flag against the shutdown thread's polling loads. The flag is non-atomic, the reader does not acquire a common mutex around the access, and sleeping does not establish a happens-before relationship with the coordinator.
The declaration comment appears to justify omitting a mutex because the page cleaner is the only writer. However, a single writer and a concurrent reader can still constitute a C++ data race when their conflicting non-atomic accesses are not ordered by happens-before.
The dynamic evidence identifies a one-byte read and a one-byte write to the same flag from different threads. Source inspection suggests a data race, although the trace detector's conflict report alone is not a complete source-language synchronization proof.
No crash, shutdown hang, or data corruption has been established as a consequence of this finding. In particular, shutdown subsequently performs additional flushing, waiting, and buffer pool checks. This report does not claim that those safeguards can be bypassed.
The finding has been examined in 5.7.36. Its status in current releases has not yet been verified.
How to repeat:
The conflicting accesses were recorded during instrumented MySQL 5.7.36 server lifecycle tests that included normal InnoDB shutdown.
One captured workload ran the existing innodb.innodb_bug49164 mysqltest case with a 16 MiB buffer pool, followed by server shutdown. The test name identifies the workload used to obtain the trace; this report concerns the separate shutdown flag access.
The captured RISC-V instructions were:
Shutdown thread:
PC 0xaf21de
lbu a5,1872(a5)
Function: logs_empty_and_mark_files_at_shutdown()
Source: storage/innobase/log/log0log.cc:2202
Page cleaner coordinator:
PC 0xc097ae
sb zero,1872(a5)
Function: buf_flush_page_cleaner_coordinator()
Source: storage/innobase/buf/buf0flu.cc:3486
Both instructions accessed the same one-byte object at address 0x1639750, identified as buf_page_cleaner_is_active. The recorded read returned 1, and the coordinator's recorded write stored 0.
These addresses and line numbers refer to the captured build.
The build used cross-compilation compatibility changes in CMake files. Those changes did not modify the flag declaration or the two source functions above.
This is an observed access-conflict report, not a deterministic reproducer of a user-visible failure. No standalone ThreadSanitizer reproduction is currently available.
Suggested fix:
Please confirm whether any existing synchronization establishes a happens-before relationship between the coordinator's store and the shutdown thread's polling loads.
If no such synchronization exists, consider making the flag atomic and using a release store when publishing completion and acquire loads when waiting for completion. All declarations and access sites would need to be updated consistently.
Alternatively, an explicit completion event or thread join could provide the required synchronization.
Could you also confirm whether this issue has already been addressed in a later release, and identify the relevant fix if available?
Description: During trace-based concurrency analysis of MySQL 5.7.36, I found conflicting accesses to the ordinary bool buf_page_cleaner_is_active between the page cleaner coordinator and the thread performing InnoDB shutdown. The relevant source locations are: 1. storage/innobase/buf/buf0flu.cc The flag is declared as: bool buf_page_cleaner_is_active = false; In buf_flush_page_cleaner_coordinator(), the coordinator executes the following during exit: buf_flush_page_cleaner_close(); buf_page_cleaner_is_active = false; 2. storage/innobase/log/log0log.cc In logs_empty_and_mark_files_at_shutdown(), the shutdown thread polls the same flag: while (buf_page_cleaner_is_active) { ... os_thread_sleep(100000); ... } The surrounding comment explains that this loop waits for the page cleaner to complete buffer pool flushing before shutdown proceeds. I could not identify synchronization that orders the coordinator's store to this flag against the shutdown thread's polling loads. The flag is non-atomic, the reader does not acquire a common mutex around the access, and sleeping does not establish a happens-before relationship with the coordinator. The declaration comment appears to justify omitting a mutex because the page cleaner is the only writer. However, a single writer and a concurrent reader can still constitute a C++ data race when their conflicting non-atomic accesses are not ordered by happens-before. The dynamic evidence identifies a one-byte read and a one-byte write to the same flag from different threads. Source inspection suggests a data race, although the trace detector's conflict report alone is not a complete source-language synchronization proof. No crash, shutdown hang, or data corruption has been established as a consequence of this finding. In particular, shutdown subsequently performs additional flushing, waiting, and buffer pool checks. This report does not claim that those safeguards can be bypassed. The finding has been examined in 5.7.36. Its status in current releases has not yet been verified. How to repeat: The conflicting accesses were recorded during instrumented MySQL 5.7.36 server lifecycle tests that included normal InnoDB shutdown. One captured workload ran the existing innodb.innodb_bug49164 mysqltest case with a 16 MiB buffer pool, followed by server shutdown. The test name identifies the workload used to obtain the trace; this report concerns the separate shutdown flag access. The captured RISC-V instructions were: Shutdown thread: PC 0xaf21de lbu a5,1872(a5) Function: logs_empty_and_mark_files_at_shutdown() Source: storage/innobase/log/log0log.cc:2202 Page cleaner coordinator: PC 0xc097ae sb zero,1872(a5) Function: buf_flush_page_cleaner_coordinator() Source: storage/innobase/buf/buf0flu.cc:3486 Both instructions accessed the same one-byte object at address 0x1639750, identified as buf_page_cleaner_is_active. The recorded read returned 1, and the coordinator's recorded write stored 0. These addresses and line numbers refer to the captured build. The build used cross-compilation compatibility changes in CMake files. Those changes did not modify the flag declaration or the two source functions above. This is an observed access-conflict report, not a deterministic reproducer of a user-visible failure. No standalone ThreadSanitizer reproduction is currently available. Suggested fix: Please confirm whether any existing synchronization establishes a happens-before relationship between the coordinator's store and the shutdown thread's polling loads. If no such synchronization exists, consider making the flag atomic and using a release store when publishing completion and acquire loads when waiting for completion. All declarations and access sites would need to be updated consistently. Alternatively, an explicit completion event or thread join could provide the required synchronization. Could you also confirm whether this issue has already been addressed in a later release, and identify the relevant fix if available?