2019-09-14 20:45:11 |
Maxim Egorushkin |
bug |
|
|
added bug |
2019-09-14 20:47:54 |
Maxim Egorushkin |
description |
pthread_setattr_default_np race condition with pthread_create.
When creating a new thread with pthread_create and a NULL pthread_attr_t* argument, the pthread_attr_t* argument must come from the last call to pthread_setattr_default_np preceding the call to pthread_create.
It seems that there is a race condition in glibc implementation such that pthread_attr_t* argument comes from a pthread_setattr_default_np call that succeeds a pthread_create call.
Example:
[max@supernova:~/src/test] $ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) stable release version 2.27.
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 7.3.0.
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
[max@supernova:~/src/test] $ g++ --version
g++ (Ubuntu 8.3.0-6ubuntu1~18.04.1) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[max@supernova:~/src/test] $ cat test.cc
#include <cstdio>
#include <thread>
#include <system_error>
#include <pthread.h>
void set_default_thread_stack_size(size_t size) {
pthread_attr_t attr;
if(int err = ::pthread_attr_init(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_init");
if(int err = ::pthread_attr_setstacksize(&attr, size))
throw std::system_error(err, std::system_category(), "pthread_attr_setstacksize");
if(int err = ::pthread_setattr_default_np(&attr))
throw std::system_error(err, std::system_category(), "pthread_setattr_default_np");
if(int err = ::pthread_attr_destroy(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_destroy");
}
void another_thread() {
pthread_attr_t attr;
if(int err = ::pthread_attr_init(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_init");
size_t stack_size;
if(int err = ::pthread_attr_getstacksize(&attr, &stack_size))
throw std::system_error(err, std::system_category(), "pthread_attr_getstacksize");
if(int err = ::pthread_attr_destroy(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_destroy");
std::printf("thread stack size is %zu\n", stack_size);
}
int main() {
another_thread();
std::thread t0(another_thread);
set_default_thread_stack_size(1024 * 1024);
std::thread t1(another_thread);
t0.join();
t1.join();
}
[max@supernova:~/src/test] $ g++ -std=gnu++14 -W{all,extra,error} -O3 -march=native -o test test.cc -pthread
[max@supernova:~/src/test] $ ./test
thread stack size is 8720384
thread stack size is 1048576
thread stack size is 1048576
The above output is incorrect. The expected output is:
thread stack size is 8720384
thread stack size is 8720384
thread stack size is 1048576
If `t0.join();` line is moved to right after `std::thread t0(another_thread);` line then the code produces the correct output.
It looks that setting the default pthread_attr_t is not atomic with respect to pthread_create calls. |
pthread_setattr_default_np race condition with pthread_create.
When creating a new thread with pthread_create and a NULL pthread_attr_t* argument, the pthread_attr_t* argument must come from the last call to pthread_setattr_default_np preceding the call to pthread_create.
It seems that there is a race condition in glibc implementation such that pthread_attr_t* argument comes from a pthread_setattr_default_np call that succeeds a pthread_create call.
Example:
[max@supernova:~/src/test] $ g++ --version
g++ (Ubuntu 8.3.0-6ubuntu1~18.04.1) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[max@supernova:~/src/test] $ cat test.cc
#include <cstdio>
#include <thread>
#include <system_error>
#include <pthread.h>
void set_default_thread_stack_size(size_t size) {
pthread_attr_t attr;
if(int err = ::pthread_attr_init(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_init");
if(int err = ::pthread_attr_setstacksize(&attr, size))
throw std::system_error(err, std::system_category(), "pthread_attr_setstacksize");
if(int err = ::pthread_setattr_default_np(&attr))
throw std::system_error(err, std::system_category(), "pthread_setattr_default_np");
if(int err = ::pthread_attr_destroy(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_destroy");
}
void another_thread() {
pthread_attr_t attr;
if(int err = ::pthread_attr_init(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_init");
size_t stack_size;
if(int err = ::pthread_attr_getstacksize(&attr, &stack_size))
throw std::system_error(err, std::system_category(), "pthread_attr_getstacksize");
if(int err = ::pthread_attr_destroy(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_destroy");
std::printf("thread stack size is %zu\n", stack_size);
}
int main() {
another_thread();
std::thread t0(another_thread);
set_default_thread_stack_size(1024 * 1024);
std::thread t1(another_thread);
t0.join();
t1.join();
}
[max@supernova:~/src/test] $ g++ -std=gnu++14 -W{all,extra,error} -O3 -march=native -o test test.cc -pthread
[max@supernova:~/src/test] $ ldd test
linux-vdso.so.1 (0x00007ffd74d74000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f597ed00000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f597eae8000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f597e8c9000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f597e4d8000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f597e13a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f597f28d000)
[max@supernova:~/src/test] $ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) stable release version 2.27.
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 7.3.0.
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
[max@supernova:~/src/test] $ ./test
thread stack size is 8720384
thread stack size is 1048576
thread stack size is 1048576
The above output is incorrect. The expected output is:
thread stack size is 8720384
thread stack size is 8720384
thread stack size is 1048576
If `t0.join();` line is moved to right after `std::thread t0(another_thread);` line then the code produces the correct output.
It looks that setting the default pthread_attr_t is not atomic with respect to pthread_create calls. |
|
2019-09-14 20:49:22 |
Maxim Egorushkin |
description |
pthread_setattr_default_np race condition with pthread_create.
When creating a new thread with pthread_create and a NULL pthread_attr_t* argument, the pthread_attr_t* argument must come from the last call to pthread_setattr_default_np preceding the call to pthread_create.
It seems that there is a race condition in glibc implementation such that pthread_attr_t* argument comes from a pthread_setattr_default_np call that succeeds a pthread_create call.
Example:
[max@supernova:~/src/test] $ g++ --version
g++ (Ubuntu 8.3.0-6ubuntu1~18.04.1) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[max@supernova:~/src/test] $ cat test.cc
#include <cstdio>
#include <thread>
#include <system_error>
#include <pthread.h>
void set_default_thread_stack_size(size_t size) {
pthread_attr_t attr;
if(int err = ::pthread_attr_init(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_init");
if(int err = ::pthread_attr_setstacksize(&attr, size))
throw std::system_error(err, std::system_category(), "pthread_attr_setstacksize");
if(int err = ::pthread_setattr_default_np(&attr))
throw std::system_error(err, std::system_category(), "pthread_setattr_default_np");
if(int err = ::pthread_attr_destroy(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_destroy");
}
void another_thread() {
pthread_attr_t attr;
if(int err = ::pthread_attr_init(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_init");
size_t stack_size;
if(int err = ::pthread_attr_getstacksize(&attr, &stack_size))
throw std::system_error(err, std::system_category(), "pthread_attr_getstacksize");
if(int err = ::pthread_attr_destroy(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_destroy");
std::printf("thread stack size is %zu\n", stack_size);
}
int main() {
another_thread();
std::thread t0(another_thread);
set_default_thread_stack_size(1024 * 1024);
std::thread t1(another_thread);
t0.join();
t1.join();
}
[max@supernova:~/src/test] $ g++ -std=gnu++14 -W{all,extra,error} -O3 -march=native -o test test.cc -pthread
[max@supernova:~/src/test] $ ldd test
linux-vdso.so.1 (0x00007ffd74d74000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f597ed00000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f597eae8000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f597e8c9000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f597e4d8000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f597e13a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f597f28d000)
[max@supernova:~/src/test] $ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) stable release version 2.27.
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 7.3.0.
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
[max@supernova:~/src/test] $ ./test
thread stack size is 8720384
thread stack size is 1048576
thread stack size is 1048576
The above output is incorrect. The expected output is:
thread stack size is 8720384
thread stack size is 8720384
thread stack size is 1048576
If `t0.join();` line is moved to right after `std::thread t0(another_thread);` line then the code produces the correct output.
It looks that setting the default pthread_attr_t is not atomic with respect to pthread_create calls. |
pthread_setattr_default_np race condition with pthread_create.
When creating a new thread with pthread_create and a NULL pthread_attr_t* argument, the pthread_attr_t* argument must come from the last call to pthread_setattr_default_np preceding the call to pthread_create.
It seems that there is a race condition in glibc implementation such that pthread_attr_t* argument comes from a pthread_setattr_default_np call that succeeds a pthread_create call.
Example:
[max@supernova:~/src/test] $ g++ --version
g++ (Ubuntu 8.3.0-6ubuntu1~18.04.1) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[max@supernova:~/src/test] $ cat test.cc
#include <cstdio>
#include <thread>
#include <system_error>
#include <pthread.h>
void set_default_thread_stack_size(size_t size) {
pthread_attr_t attr;
if(int err = ::pthread_attr_init(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_init");
if(int err = ::pthread_attr_setstacksize(&attr, size))
throw std::system_error(err, std::system_category(), "pthread_attr_setstacksize");
if(int err = ::pthread_setattr_default_np(&attr))
throw std::system_error(err, std::system_category(), "pthread_setattr_default_np");
if(int err = ::pthread_attr_destroy(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_destroy");
}
void another_thread() {
pthread_attr_t attr;
if(int err = ::pthread_attr_init(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_init");
size_t stack_size;
if(int err = ::pthread_attr_getstacksize(&attr, &stack_size))
throw std::system_error(err, std::system_category(), "pthread_attr_getstacksize");
if(int err = ::pthread_attr_destroy(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_destroy");
std::printf("thread stack size is %zu\n", stack_size);
}
int main() {
another_thread();
std::thread t0(another_thread);
set_default_thread_stack_size(1024 * 1024);
std::thread t1(another_thread);
t0.join();
t1.join();
}
[max@supernova:~/src/test] $ g++ -std=gnu++14 -W{all,extra,error} -O3 -march=native -o test test.cc -pthread
[max@supernova:~/src/test] $ ldd test
linux-vdso.so.1 (0x00007ffd74d74000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f597ed00000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f597eae8000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f597e8c9000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f597e4d8000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f597e13a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f597f28d000)
[max@supernova:~/src/test] $ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) stable release version 2.27.
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 7.3.0.
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
[max@supernova:~/src/test] $ ./test
thread stack size is 8720384
thread stack size is 1048576
thread stack size is 1048576
The above output is incorrect. The expected output is:
thread stack size is 8720384
thread stack size is 8720384
thread stack size is 1048576
If `t0.join();` line is moved to right after `std::thread t0(another_thread);` line then the code produces the correct output.
It appears that setting the default pthread_attr_t is not atomic with respect to pthread_create calls. |
|
2019-09-14 20:50:43 |
Maxim Egorushkin |
description |
pthread_setattr_default_np race condition with pthread_create.
When creating a new thread with pthread_create and a NULL pthread_attr_t* argument, the pthread_attr_t* argument must come from the last call to pthread_setattr_default_np preceding the call to pthread_create.
It seems that there is a race condition in glibc implementation such that pthread_attr_t* argument comes from a pthread_setattr_default_np call that succeeds a pthread_create call.
Example:
[max@supernova:~/src/test] $ g++ --version
g++ (Ubuntu 8.3.0-6ubuntu1~18.04.1) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[max@supernova:~/src/test] $ cat test.cc
#include <cstdio>
#include <thread>
#include <system_error>
#include <pthread.h>
void set_default_thread_stack_size(size_t size) {
pthread_attr_t attr;
if(int err = ::pthread_attr_init(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_init");
if(int err = ::pthread_attr_setstacksize(&attr, size))
throw std::system_error(err, std::system_category(), "pthread_attr_setstacksize");
if(int err = ::pthread_setattr_default_np(&attr))
throw std::system_error(err, std::system_category(), "pthread_setattr_default_np");
if(int err = ::pthread_attr_destroy(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_destroy");
}
void another_thread() {
pthread_attr_t attr;
if(int err = ::pthread_attr_init(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_init");
size_t stack_size;
if(int err = ::pthread_attr_getstacksize(&attr, &stack_size))
throw std::system_error(err, std::system_category(), "pthread_attr_getstacksize");
if(int err = ::pthread_attr_destroy(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_destroy");
std::printf("thread stack size is %zu\n", stack_size);
}
int main() {
another_thread();
std::thread t0(another_thread);
set_default_thread_stack_size(1024 * 1024);
std::thread t1(another_thread);
t0.join();
t1.join();
}
[max@supernova:~/src/test] $ g++ -std=gnu++14 -W{all,extra,error} -O3 -march=native -o test test.cc -pthread
[max@supernova:~/src/test] $ ldd test
linux-vdso.so.1 (0x00007ffd74d74000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f597ed00000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f597eae8000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f597e8c9000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f597e4d8000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f597e13a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f597f28d000)
[max@supernova:~/src/test] $ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) stable release version 2.27.
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 7.3.0.
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
[max@supernova:~/src/test] $ ./test
thread stack size is 8720384
thread stack size is 1048576
thread stack size is 1048576
The above output is incorrect. The expected output is:
thread stack size is 8720384
thread stack size is 8720384
thread stack size is 1048576
If `t0.join();` line is moved to right after `std::thread t0(another_thread);` line then the code produces the correct output.
It appears that setting the default pthread_attr_t is not atomic with respect to pthread_create calls. |
pthread_setattr_default_np race condition with pthread_create.
When creating a new thread with pthread_create and a NULL pthread_attr_t* argument, the pthread_attr_t* argument must come from the last call to pthread_setattr_default_np preceding the call to pthread_create.
It seems that there is a race condition in glibc implementation such that pthread_attr_t* argument comes from a pthread_setattr_default_np call that succeeds a pthread_create call.
Example:
[max@supernova:~/src/test] $ g++ --version
g++ (Ubuntu 8.3.0-6ubuntu1~18.04.1) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[max@supernova:~/src/test] $ cat test.cc
#include <cstdio>
#include <thread>
#include <system_error>
#include <pthread.h>
void set_default_thread_stack_size(size_t size) {
pthread_attr_t attr;
if(int err = ::pthread_attr_init(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_init");
if(int err = ::pthread_attr_setstacksize(&attr, size))
throw std::system_error(err, std::system_category(), "pthread_attr_setstacksize");
if(int err = ::pthread_setattr_default_np(&attr))
throw std::system_error(err, std::system_category(), "pthread_setattr_default_np");
if(int err = ::pthread_attr_destroy(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_destroy");
}
void another_thread() {
pthread_attr_t attr;
if(int err = ::pthread_attr_init(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_init");
size_t stack_size;
if(int err = ::pthread_attr_getstacksize(&attr, &stack_size))
throw std::system_error(err, std::system_category(), "pthread_attr_getstacksize");
if(int err = ::pthread_attr_destroy(&attr))
throw std::system_error(err, std::system_category(), "pthread_attr_destroy");
std::printf("thread stack size is %zu\n", stack_size);
}
int main() {
another_thread();
std::thread t0(another_thread);
set_default_thread_stack_size(1024 * 1024);
std::thread t1(another_thread);
t0.join();
t1.join();
}
[max@supernova:~/src/test] $ g++ -std=gnu++14 -W{all,extra,error} -O3 -march=native -o test test.cc -pthread
[max@supernova:~/src/test] $ ldd test
linux-vdso.so.1 (0x00007ffd74d74000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f597ed00000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f597eae8000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f597e8c9000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f597e4d8000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f597e13a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f597f28d000)
[max@supernova:~/src/test] $ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) stable release version 2.27.
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 7.3.0.
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
[max@supernova:~/src/test] $ ./test
thread stack size is 8720384
thread stack size is 1048576
thread stack size is 1048576
The above output is incorrect. The expected output is:
thread stack size is 8720384
thread stack size is 8720384
thread stack size is 1048576
If `t0.join();` line is moved to right after `std::thread t0(another_thread);` line then the code produces the correct output.
It appears that setting the default pthread_attr_t is not atomic/ordered with respect to pthread_create calls. |
|