Handle derives Clone, which bitwise-copies its pointer field. The Drop implementation for Handle frees the pointee unconditionally, so cloning an instance of Handle and dropping both copies causes a double-free.
#[derive(Clone)]
pub struct Handle {
handle: *mut pcap_sys::pcap_t,
live_capture: bool,
interrupted: std::sync::Arc<std::sync::Mutex<bool>>,
}
impl Drop for Handle {
fn drop(&mut self) {
self.close();
}
}
Reproducing:
use pcap_async::Handle;
#[test]
fn handle_double_free() {
let foo = Handle::dead(0, 0).unwrap();
let bar: Handle = (*foo).clone();
drop(bar); // pcap_close(handle)
drop(foo); // SAME pcap_t, closed again
}
You can run the above test with valgrind and see an Invalid read error.
cargo test --test repro --no-run
valgrind --leak-check=no ./target/debug/deps/repro-<HASH>
Fix:
- Drop
#[derive(Clone)] on Handle.
HandlederivesClone, which bitwise-copies its pointer field. TheDropimplementation forHandlefrees the pointee unconditionally, so cloning an instance ofHandleand dropping both copies causes a double-free.Reproducing:
You can run the above test with valgrind and see an
Invalid readerror.Fix:
#[derive(Clone)]onHandle.