Description:
Hi,
there was a bug in Ubuntu that seems to have been triggered by a newer glibc or gcc build => https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/1915275
The bug holds details on the debugging, but it eventually turned out that the definition of sysconf says (man page):
"
RETURN VALUE - The return value of sysconf() is one of the following:
* On error, -1 is returned and errno is set to indicate the cause of the error (for example, EINVAL, indicating that name is invalid).
"
Now on riscv-64 for the recent few releases sysconf(_SC_LEVEL1_DCACHE_LINESIZE) as used in:
sql/memory/aligned_atomic.h:81: return sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
used to return "0".
That used to work, but since the latest libstdc++ version it "correctly" delivers -1 now.
Unfortunately the handling in mysql pushed this into a size_t which is unsigned and thereby makes this a value of "18446744073709551615".
Due to that the types based on the alignment feature of the template:
"memory::Aligned_atomic<T>::Aligned_atomic(T value)"
fail allocations very badly.
On a recent system that looks like this:
```
$ sudo mysqld --verbose --innodb-read-only --help
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
08:10:07 UTC - mysqld got signal 6 ;
Most likely, you have hit a bug, but this error can also be caused by malfunctioning hardware.
Thread pointer: 0x0
Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong...
stack_bottom = 0 thread_stack 0x46000
/usr/sbin/mysqld(my_print_stacktrace(unsigned char const*, unsigned long)+0x62) [0x2ae4c357d0]
/usr/sbin/mysqld(handle_fatal_signal+0x270) [0x2ae3fbce64]
linux-vdso.so.1(__vdso_rt_sigreturn+0) [0x3fe1f15800]
/lib/riscv64-linux-gnu/libc.so.6(gsignal+0xa2) [0x3fe1354fec]
/lib/riscv64-linux-gnu/libc.so.6(abort+0xb4) [0x3fe134598c]
```
How to repeat:
1. get a system that can't get cache sizes reported in sysconf. Once case known
for that is Ubtunu on riscv64 with
- libstdc++ 11-20210306-1ubuntu1
- libc6 2.33-0ubuntu2
2. run mysqld
$ sudo mysqld --verbose --innodb-read-only --help
Or for simpler debug of just sysconf
$ cat test-sysconf.cpp
#include <iostream>
#include <unistd.h>
int main() {
std::cout << "_SC_LEVEL1_DCACHE_LINESIZE = " << sysconf(_SC_LEVEL1_DCACHE_LINESIZE) << "\n";
return 0;
}
$ rm test-sysconf; g++ -Wall -o test-sysconf test-sysconf.cpp && ./test-sysconf
riscv64 @ Hirsute
_SC_LEVEL1_DCACHE_LINESIZE = -1
riscv64 @ Focal
_SC_LEVEL1_DCACHE_LINESIZE = 0
Suggested fix:
Fetch the sysconf value as the "long" that it is and bail out on "-1" probably using the default of 64 that mysql already used in other cases.
Suggestion:
```
diff --git a/sql/memory/aligned_atomic.h b/sql/memory/aligned_atomic.h
index 6cd276a4e74..fda65f351c5 100644
--- a/sql/memory/aligned_atomic.h
+++ b/sql/memory/aligned_atomic.h
@@ -78,7 +78,11 @@ static inline size_t _cache_line_size() {
#elif defined(__linux__)
static inline size_t _cache_line_size() {
- return sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
+ long size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
+ if (size == -1)
+ return 64;
+ else
+ return (size_t)size;
}
#else
```
Note: so far on such platforms this was aligned to "0" and would now be "64", if you wan that or another fallback is up to you.