Bug #102926 sysconf called without error checking
Submitted: 11 Mar 2021 13:57 Modified: 12 Mar 2021 15:03
Reporter: Christian Ehrhardt Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Compiling Severity:S3 (Non-critical)
Version:8.0.23 OS:Linux
Assigned to: Tor Didriksen CPU Architecture:Any

[11 Mar 2021 13:57] Christian Ehrhardt
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.
[11 Mar 2021 14:45] MySQL Verification Team
Hi Mr. Ehrhardt,

Thank you for your bug report.

However, we do not maintain C++ STL , so we do not see how is this our bug.

Thanks for the report, any way..............
[11 Mar 2021 15:29] Christian Ehrhardt
The failing code is in mysql, it is the changed (now correct) behavior in stdc++ that breaks your current code.
[11 Mar 2021 15:42] Terje Røsten
Hi!

Thanks for your report!

Seems like a cross platform fix would make sense here.
[11 Mar 2021 15:50] Terje Røsten
Checking return values from system call for errors is common sense.
[12 Mar 2021 15:03] Paul DuBois
Posted by developer:
 
Fixed in 8.0.25.

System cache size checking could be inaccurate on Ubuntu.
[16 Mar 2021 12:55] MySQL Verification Team
Thank you, Paul.
[24 Apr 2021 14:32] Paul DuBois
Posted by developer:
 
Fixed in 8.0.26, not 8.0.25.