-
-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Double free crash on macOS #189
Comments
Yikes, that's not good, but thanks for the detailed report! I'll take a look at this as soon as I am able. Based on a brief look at the backtrace I wonder if some funky things are going on with thread locals. I have not tested Isahc with smol yet, though I'd be a little surprised if it was smol's fault. |
Haven't been able to reproduce so far. What exact dependency versions are you using? |
I pulled in
Happy to put my whole |
Hmm, I'm testing your code with those dependency versions and not getting anything. Surf likes to have libcurl dynamically linked -- what version of curl are you linked to? We can find out by doing a few things:
|
Do I need to have a specific server running on port 8080 to reproduce this? |
OK, I am able to reproduce, though rarely. At this point, this seems to be some sort of SSL library bug to me, as it always occurs on Unfortunately I've only managed to reproduce it two times on my mac after several hundred runs, which makes debugging this pretty difficult. Since it happens more frequently on your machine, there's a few things you could do to help narrow down the problem. The first thing to try would be to build curl without any SSL support, since the test program does not require it. If the problem goes away, then the bug is definitely within the interaction between libcurl and the SSL engine. |
Sorry for not mentioning that! I was running the httpbin Docker image on 8080.
I'll give that a shot tomorrow. Thanks for digging! |
Based on some extremely silly forensics (running |
Confirmed with slightly less silly forensics:
|
Perfect, thanks. When I reproduced it, it was also with |
Good news, I've made progress today narrowing down the problem. Here's what I have so far where I am able to reproduce the double free: [package]
name = "blep"
version = "0.0.1"
edition = "2018"
[dependencies]
curl = "0.4" use std::{
sync::{Arc, Barrier},
thread,
};
fn main() {
println!("version: {:?}", curl::Version::get());
let threads = 8;
let barrier = Arc::new(Barrier::new(threads + 1));
for _ in 0..threads {
let barrier = barrier.clone();
thread::spawn(move || {
let mut easy = curl::easy::Easy::new();
easy.url("http://localhost:8080").unwrap();
easy.perform().unwrap();
barrier.wait();
});
}
barrier.wait();
} My guess is still that LibreSSL is doing something stupid with thread locals or some such thing. Since this appears to be a curl + LibreSSL bug, I'm going to convert this minimum reproduction into C and then open a bug report on the curl project. Just to double-check, it would be great if you could verify that the above program also causes the bug on your machine. Thanks again for discovering this! |
@blinsay What happens if you add I think this is caused by a curl footgun where I don't know if you read C, but the following program will also randomly perform a double free, and demonstrates what all our crates composed together in your program are doing wrong: #include <pthread.h>
#include <curl/curl.h>
#define THREADS 8
// Ensure curl_global_init is called only once.
static pthread_once_t init = PTHREAD_ONCE_INIT;
// Does nothing with the response body.
static size_t write_callback(void *buffer, size_t size, size_t nmemb, void *userp)
{
return size * nmemb;
}
static void init_routine()
{
curl_global_init(CURL_GLOBAL_ALL);
}
static void *thread_main(void *arg)
{
// This lazy initialization is basically what the curl crate does.
pthread_once(&init, init_routine);
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:8080");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_perform(curl);
// Double-free occurs somewhere inside here when LibreSSL cleanup is called.
curl_easy_cleanup(curl);
return NULL;
}
int main(int argc, char **argv)
{
pthread_t tid[THREADS];
// Spawn N threads. One of them will be first to initialize curl.
for (int i = 0; i < THREADS; i++)
{
pthread_create(&tid[i], NULL, thread_main, NULL);
}
// Wait for all threads to return. We won't finish this if we SIGABRT.
for (int i = 0; i < THREADS; i++)
{
pthread_join(tid[i], NULL);
}
return 0;
} I will have to think about how to address this. |
@blinsay For now the correct solution is to call That said, I still intend to fix this in some way because as-is this is quite user-unfriendly, so I will keep this issue labeled as a bug. |
I haven't yet had a crash with Thanks for digging deep and pushing this further upstream! |
We have a fix in place upstream that should resolve this more elegantly for users that I can release soon so that you won't have to call |
awesome, thanks so much! |
I was messing around with smol/surf for the first time and managed to segfault with no
unsafe
code.Based on this lldb backtrace it looks like a problem somewhere in isahc and libcurl. The backtrace and code are here:
https://gist.github.com/blinsay/3d5174aaa03f5546cd492054889d8789
I can reproduce this every 3-6 runs of my test program. Happy to poke around and get more information if you let me know what's useful.
Thanks!
The text was updated successfully, but these errors were encountered: