无锁跨线程共享UnsafeCell封装的TlsStream是否会引发未定义行为?
TLS流拆分代码的安全性疑问
请考虑以下代码:
use std::{cell::UnsafeCell, io, net::TcpStream, sync::Arc}; use native_tls::TlsStream; #[derive(Debug)] pub struct TcpStreamRecv(Arc<UnsafeCell<TlsStream<TcpStream>>>); unsafe impl Send for TcpStreamRecv {} unsafe impl Sync for TcpStreamRecv {} impl io::Read for TcpStreamRecv { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { unsafe { &mut *self.0.get() }.read(buf) } } #[derive(Debug)] pub struct TcpStreamSend(Arc<UnsafeCell<TlsStream<TcpStream>>>); unsafe impl Send for TcpStreamSend {} unsafe impl Sync for TcpStreamSend {} impl io::Write for TcpStreamSend { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { unsafe { &mut *self.0.get() }.write(buf) } fn flush(&mut self) -> io::Result<()> { unsafe { &mut *self.0.get() }.flush() } } pub fn tcp_split(stream: TlsStream<TcpStream>) -> (TcpStreamSend, TcpStreamRecv) { let inner = Arc::new(UnsafeCell::new(stream)); let send = TcpStreamSend(inner.clone()); let recv = TcpStreamRecv(inner); (send, recv) }
我的推理如下:
- 安全代码可以获取指向同一底层
TlsStream的TcpStreamSend和TcpStreamRecv实例。 - 若将这两个实例分别发送到不同线程,可能会同时调用
TcpStreamSend::write和TcpStreamRecv::read方法。这两个方法都会获取底层TlsStream的&mut引用。 - 由于同时存在两个可变引用是非法的,因此这段代码会导致未定义行为(UB),属于不安全代码。这个结论是否正确?
同事认为“能运行就行”,该代码大多数时候表现正常,但偶尔会出现随机panic。但我认为这会在代码库中引发不可预测的问题,需要立即重写。我是否遗漏了什么?
另外,我经调研发现这段代码的灵感来自某Stack Overflow回答,该实现更为复杂,但在我看来同样存在问题。
内容的提问来源于stack exchange,提问作者Reinis Mažeiks
相关产品推荐
相关产品推荐

