SIGSEGV on https client with std::thread
toge opened this issue · 14 comments
Probably the same problem as #1797.
SEGSEGV error on https client.
This only occurs with https clients running in std::thread.
Error code is following.
#include <iostream>
#include <thread>
#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "httplib.h"
int main() {
auto th = std::thread([&]() {
auto client = httplib::Client("https://example.org");
auto const&& response = client.Get("/");
if (response->status != httplib::StatusCode::OK_200) { // SIGSEGV
std::cout << "error : " << response->status << '\n';
return;
}
std::cout << response->body << '\n';
});
th.join();
return 0;
}
Both of the two codes that follow work fine.
- http client
#include <iostream>
#include <thread>
#include "httplib.h"
int main() {
auto th = std::thread([&]() {
auto client = httplib::Client("http://example.org");
auto const&& response = client.Get("/");
if (response->status != httplib::StatusCode::OK_200) {
std::cout << "error : " << response->status << '\n';
return;
}
std::cout << response->body << '\n';
});
th.join();
return 0;
}
- https client with https instance on main thread
#include <iostream>
#include <thread>
#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "httplib.h"
int main() {
auto client = httplib::Client("https://example.org");
auto th = std::thread([&]() {
auto const&& response = client.Get("/");
if (response->status != httplib::StatusCode::OK_200) {
std::cout << "error : " << response->status << '\n';
return;
}
std::cout << response->body << '\n';
});
th.join();
return 0;
}
My environments is following:
item | detail |
---|---|
OS | Fedora Linux 40 (x64) |
Compiler | gcc 14.2.1 |
cpp-httplib | 0.18.0 |
openssl | 3.3.2 |
@toge thanks for the report. Which line in the error example code is causing SIGSEGV?
SIGSEGV occurred at the line with comment // SIGSEGV
.
The following is the output of gdb.
0x0000000000421663 in operator() (__closure=<optimized out>) at test05.cpp:11
11 if (response->status != httplib::StatusCode::OK_200) {
(gdb) bt
#0 0x0000000000421663 in operator() (__closure=<optimized out>) at test05.cpp:11
#1 0x00007ffff7ce7564 in std::execute_native_thread_routine (__p=0x985e10) at ../../../../../libstdc++-v3/src/c++11/thread.cc:104
#2 0x00007ffff7aa66d7 in start_thread (arg=<optimized out>) at pthread_create.c:447
#3 0x00007ffff7b2a60c in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78
httplib::Result.res_.get() is null
.
(gdb) p response
$1 = (const httplib::Result &&) @0x7ffff79ffb80: {res_ = std::unique_ptr<httplib::Response> = {get() = 0x0}, err_ = httplib::Error::Success, request_headers_ = std::unordered_multimap with 0 elements}
(gdb) p response.res_.get()
$2 = (httplib::Response *) 0x0
@toge could you try the following code?
https://github.com/yhirose/cpp-httplib?tab=readme-ov-file#client-1
#include <iostream>
#include <thread>
#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "httplib.h"
int main() {
auto th = std::thread([&]() {
auto client = httplib::Client("https://example.org");
if (auto response = client.Get("/")) {
if (response->status != httplib::StatusCode::OK_200) { // SIGSEGV
std::cout << "error status: " << response->status << '\n';
}
std::cout << response->body << '\n';
} else {
auto err = response.error();
std::cout << "error: " << httplib::to_string(err) << std::endl;
}
});
th.join();
return 0;
}
@yhirose thanks for the additional info. I tested it on macOS and Ubuntu 22.04, but I didn't get the problem. So it seems like the particular environment (Fedora Linux 40, g++ 14.2.1, OpenSSL 3.3.2) causes the problem. I'll look into it when I am available.
@yhirose
I have made some progress in investigation and will share it.
It is not caused by cpp-httplib.
It seems to be caused by openssl.
SSL_CTX_new
returns null pointer on multi thread environment.
https://github.com/yhirose/cpp-httplib/blob/v0.18.0/httplib.h#L9161
The following code causes same error.
#include <iostream>
#include <thread>
#include <openssl/ssl.h>
int main() {
SSL_library_init();
auto th = std::thread([&]() {
auto ctx = SSL_CTX_new(TLS_client_method());
if (ctx == nullptr) {
std::cerr << "failed to create SSL_CTX" << std::endl;
}
SSL_CTX_free(ctx);
});
th.join();
}
Of course, following code works fine.
#include <iostream>
#include <thread>
#include <openssl/ssl.h>
int main() {
SSL_library_init();
auto ctx = SSL_CTX_new(TLS_client_method());
if (ctx == nullptr) {
std::cerr << "failed to create SSL_CTX" << std::endl;
}
SSL_CTX_free(ctx);
}
There is a workaround "calling SSL_load_error_strings()
".
But I don't know the reason (yet).
#include <iostream>
#include <thread>
#include <openssl/ssl.h>
int main() {
SSL_library_init();
SSL_load_error_strings();
auto th = std::thread([&]() {
auto ctx = SSL_CTX_new(TLS_client_method());
if (ctx == nullptr) {
std::cerr << "failed to create SSL_CTX" << std::endl;
}
SSL_CTX_free(ctx);
});
th.join();
}