libcups is not dlopen/dlclose safe, causes segfault in __nptl_deallocate_tsd
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
HPLIP |
New
|
Undecided
|
Unassigned | ||
Fedora |
Won't Fix
|
Undecided
|
Bug Description
The libsane-hpaio driver, in the GetCupsPrinters function, calls _cupsGlobals (through cupsEncryption), which allocates thread local storage. When sane dlcloses the hpaio driver, the thread local storage is not freed. When the thread finishes later on, the thead local storage destructor for the cups globals is called, which causes the program to segfault, since the destructor pointer points to an address which is not mapped into memory anymore.
The following program shows the issue (make sure libsane-hpaio is installed):
-------
g++ -g -std=c++11 -o test test.cpp $(pkg-config --cflags --libs sane-backends)
-------
#include <cassert>
#include <iostream>
#include <thread>
#include <sane/sane.h>
void scan_thread() {
SANE_Status status;
status = sane_init(nullptr, nullptr);
assert(status == SANE_STATUS_GOOD);
const SANE_Device** device_list = nullptr;
status = sane_get_
assert(status == SANE_STATUS_GOOD);
for(int i = 0; device_list[i] != nullptr; ++i){
std::cout << device_
}
sane_exit();
}
int main() {
std::thread t(scan_thread);
t.join();
return 0;
}
See also
https:/
https:/
Changed in fedora: | |
importance: | Unknown → Undecided |
status: | Unknown → Won't Fix |
Description of problem: get_devices (via sane_get_devices) in a thread with parameter local_only=false will result in a segmentation fault when joining the thread in which sane_get_devices was called. This happens only with the hplip sane driver with local_only=false.
Running sane_hpaio_
Sample program and backtrace below.
Version-Release number of selected component (if applicable):
hplip-3.14.1-1.fc20
How reproducible:
Always
Steps to Reproduce:
1. Compile and run application below
2.
3.
Sample program: ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- -------
-------
g++ -g -std=c++11 -o test test.cpp $(pkg-config --cflags --libs sane-backends)
-------
#include <cassert>
#include <iostream>
#include <thread>
#include <sane/sane.h>
void scan_thread() {
SANE_Status status;
status = sane_init(nullptr, nullptr);
assert(status == SANE_STATUS_GOOD);
const SANE_Device** device_list = nullptr; devices( &device_ list, false);
status = sane_get_
assert(status == SANE_STATUS_GOOD);
for(int i = 0; device_list[i] != nullptr; ++i){ list[i] ->name << std::endl;
std::cout << device_
}
sane_exit();
}
int main() { ------- ------- ------- ------- ------- ------- -------
std::thread t(scan_thread);
t.join();
return 0;
}
-------
Gdb output: ------- ------- ------- ------- ------- ------- -------
-------
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff446c700 (LWP 5183)]
0x00007ffff2fce3e0 in ?? ()
(gdb) thread apply all bt
Thread 2 (Thread 0x7ffff446c700 (LWP 5183)): deallocate_ tsd () at pthread_ create. c:157 c700) at pthread_ create. c:322 unix/sysv/ linux/x86_ 64/clone. S:111
#0 0x00007ffff2fce3e0 in ?? ()
#1 0x00007ffff59f0d32 in __nptl_
#2 0x00007ffff59f0f46 in start_thread (arg=0x7ffff446
#3 0x00007ffff70bfded in clone () at ../sysdeps/
Thread 1 (Thread 0x7ffff7fd5840 (LWP 5179)): 140737291667200 , thread_return=0x0) at pthread_join.c:92 libstdc+ +.so.6 ------- ------- ------- ------- ------- ------- -------
#0 0x00007ffff59f2297 in pthread_join (threadid=
#1 0x00007ffff795c077 in std::thread::join() () from /lib64/
#2 0x0000000000400f89 in main () at test.cpp:25
-------
It looks like the program is crashing due to an invalid pointer when freeing up thread local storage: create. c:157: ------- ------- ------- ------- ------- ------- ------- keys[idx] .destr (data); ------- ------- ------- ------- ------- ------- -------
pthread_
-------
/* Call the user-provided destructor. */
__pthread_
-------
Valgrind shows not memory issues.