You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无锁跨线程共享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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 15:36:31