-
Notifications
You must be signed in to change notification settings - Fork 252
Closed
Description
Problem
OS: CentOS Linux release 7.3.1611 (Core)
Use curl::multi::Multi to fetch more than one https url will cause the program to crash when some ssl error occurred(rel issue):
[root@hugo-devm-b4pc3 easycurl]# cargo run
Compiling easycurl v0.1.0 (/mnt/vdc1/home/apps/easycurl)
Finished dev [unoptimized + debuginfo] target(s) in 0.58s
Running `target/debug/easycurl`
result for easy with token 0: Some(Err(Error { description: "SSL peer certificate or SSH remote key was not OK", code: 60, extra: Some("SSL: certificate subject name 'Test' does not match target host name '127.0.0.1'") }))
*** Error in `target/debug/easycurl': double free or corruption (!prev): 0x00007f74f921f4e0 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x7c503)[0x7f74f6dec503]
/apps/svr/curl/lib/libcurl.so.4(+0x57d08)[0x7f74f7cc9d08]
/apps/svr/curl/lib/libcurl.so.4(+0x58c3c)[0x7f74f7ccac3c]
/apps/svr/curl/lib/libcurl.so.4(+0x1132c)[0x7f74f7c8332c]
/apps/svr/curl/lib/libcurl.so.4(curl_multi_cleanup+0xbf)[0x7f74f7cafbff]
target/debug/easycurl(_ZN63_$LT$curl..multi..RawMulti$u20$as$u20$core..ops..drop..Drop$GT$4drop17h76af921506dcf405E+0x12)[0x7f74f87a6a22]
target/debug/easycurl(_ZN4core3ptr42drop_in_place$LT$curl..multi..RawMulti$GT$17h3353ba6689bfbe2eE+0xb)[0x7f74f87a4f0b]
target/debug/easycurl(_ZN5alloc4sync12Arc$LT$T$GT$9drop_slow17h56cde95cf342e66dE+0x24)[0x7f74f87a2de4]
target/debug/easycurl(_ZN67_$LT$alloc..sync..Arc$LT$T$GT$$u20$as$u20$core..ops..drop..Drop$GT$4drop17hb73c8a2d4d00a004E+0x63)[0x7f74f87a2f43]
target/debug/easycurl(_ZN4core3ptr66drop_in_place$LT$alloc..sync..Arc$LT$curl..multi..RawMulti$GT$$GT$17he1315d4334cfd101E+0xb)[0x7f74f87a573b]
target/debug/easycurl(+0x24657)[0x7f74f879b657]
target/debug/easycurl(+0x2565f)[0x7f74f879c65f]
target/debug/easycurl(+0x245db)[0x7f74f879b5db]
target/debug/easycurl(+0x25e6e)[0x7f74f879ce6e]
target/debug/easycurl(+0x26ba1)[0x7f74f879dba1]
target/debug/easycurl(_ZN3std2rt19lang_start_internal17h571831ebdba142deE+0x431)[0x7f74f87d4e81]
target/debug/easycurl(+0x26b70)[0x7f74f879db70]
target/debug/easycurl(+0x25c4c)[0x7f74f879cc4c]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7f74f6d91b35]
target/debug/easycurl(+0x23d69)[0x7f74f879ad69]
Rust code
///
/// Simulate cargo download_accessible to reproduce crash issue https://github.com/rust-lang/cargo/issues/10034
///
use curl::easy::{Easy, HttpVersion};
use curl::multi::{EasyHandle, Multi};
use curl::Error as CurlError;
fn main() {
let ret = {
let mut multi = Multi::new();
multi.pipelining(false, true).unwrap();
multi.set_max_host_connections(2).unwrap();
let mut handles = Vec::new();
handles.push(add_easy_to_multi(&mut multi, handles.len()));
// push more than one EasyHandle to trigger crash
handles.push(add_easy_to_multi(&mut multi, handles.len()));
let (token, result) = wait_for_curl(&mut multi, &handles);
let handle = handles.remove(token);
multi.remove(handle).unwrap();
/*
// comment out this loop it won't crash
while !handles.is_empty() {
let handle = handles.pop().unwrap();
multi.remove(handle).unwrap();
}
*/
result
};
{
println!("wait for url: {:?}", ret);
}
}
fn add_easy_to_multi(multi: &mut Multi, token: usize) -> EasyHandle {
let mut easy = Easy::new();
easy.get(true).unwrap();
easy.url("https://127.0.0.1:443").unwrap();
easy.follow_location(true).unwrap();
easy.http_version(HttpVersion::V2).unwrap();
easy.pipewait(true).unwrap();
easy.ssl_verify_peer(false).unwrap(); // comment out this line it won't crash
easy.write_function(move |data| {
println!("easy with token {} read {} bytes", token, data.len());
Ok(data.len())
}).unwrap();
let mut h = multi.add(easy).unwrap();
h.set_token(token).unwrap();
h
}
fn wait_for_curl(multi: &mut Multi, handles: &Vec<EasyHandle>) -> (usize, Option<Result<(), CurlError>>) {
let mut e = None;
let mut out_token = 0usize;
loop {
multi.perform().unwrap();
multi.messages(|msg| {
let token = msg.token().unwrap();
let r = msg.result_for(&handles[token]);
println!("result for easy with token {}: {:?}", token, r);
e = r;
out_token = token;
});
if e.is_some() {
break;
}
multi.wait(&mut [], std::time::Duration::from_secs(5)).unwrap();
}
(out_token, e)
}
The url https://127.0.0.1:433 in the code is a service implemented by the simple golang code:
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "It works!")
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServeTLS(":443", "server.crt", "server.key", nil)
}
server.crt is a self signed certificate generated by OpenSSL, you can replace with your version.
Cargo.toml
[package]
name = "easycurl"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
curl = { version = "0.4.40", features = ["http2"] }
curl-sys = "0.4.50"
curl -V:
libcurl/7.80.0-DEV OpenSSL/1.1.1h zlib/1.2.7 libidn2/2.3.1 nghttp2/1.41.0
sagebind
Metadata
Metadata
Assignees
Labels
No labels