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

Rust使用裸指针时出现意外segfault段错误问题咨询

问题描述

我最初使用Rust实现了一个Heap(堆)结构,但运行过程中出现了奇怪的段错误,因此我将代码精简为如下可稳定复现该异常行为的最小示例:

use core::fmt::Debug;

pub struct Node<T: Ord + Debug> {
    pub value: *const T,
}

pub struct MaxHeap<T: Ord + Debug> {
    pub root: *const Node<T>,
}

impl<T: Ord + Debug> MaxHeap<T> {
    pub fn push(&mut self, value: *const T) {
        self.root = &mut Node { value: value };
    }
}

fn main() {
    let a = 124i64;
    let b = 124i64;
    let c = 1i64;

    let mut heap = MaxHeap {
        root: &mut Node { value: &a },
    };
    heap.push(&b);

    println!("{:?}", &c);
    unsafe {
        println!("{:?}", *(*heap.root).value);
    }
}

运行上述代码得到的输出结果为:

1
Segmentation fault (core dumped)

我观察到一个反常现象:如果移除打印变量c的代码,程序就不会触发段错误,且可以正确打印堆根节点的值:

124

按照我的认知,针对变量c的任何操作都不会对heap实例的状态产生影响,但实际运行结果却与预期相悖,请问我在代码编写或Rust内存机制理解上存在什么疏漏?

问题原因

你的代码存在**悬空指针(野指针)**问题,属于典型的未定义行为,和变量c本身没有任何关系,段错误只是内存被复用后刚好触发的表象:

  • 你在push方法里写的self.root = &mut Node { value: value };,是在push函数的栈帧上创建了一个临时的Node实例,然后把这个临时值的栈地址存到了self.root里。
  • 当push函数执行结束返回时,这个临时Node所在的栈内存就会被释放、后续会被其他函数调用复用,此时self.root已经指向了无效的内存地址。
  • 你移除打印c的代码时没有触发段错误,只是刚好这块被释放的栈内存还没被覆写,存的还是原来的值,属于"未定义行为碰巧跑对了"的情况,不是代码没问题。当你加了println!打印c的逻辑时,println!宏内部的函数调用会占用这块刚释放的栈空间,把原来存的Node数据覆写掉,你再去解引用这个悬空指针就会读到乱值、触发段错误。
  • 同理你初始化heap时写的root: &mut Node { value: &a }也是一样的问题,这个临时Node在let mut heap = ...语句结束后就已经失效了,只是刚好内存没被覆写所以没立刻炸。
修复方案

不要直接把栈上临时值的地址存到裸指针里长期持有,如果你需要让Node的生命周期和Heap绑定,要么用Box把Node分配到堆上,要么用安全的引用方式搭配生命周期标注,不要滥用unsafe和裸指针。
参考修复示例:

use core::fmt::Debug;

pub struct Node<T: Ord + Debug> {
    pub value: T,
}

pub struct MaxHeap<T: Ord + Debug> {
    pub root: Option<Box<Node<T>>>,
}

impl<T: Ord + Debug> MaxHeap<T> {
    pub fn new() -> Self {
        Self { root: None }
    }
    pub fn push(&mut self, value: T) {
        self.root = Some(Box::new(Node { value }));
    }
}

fn main() {
    let a = 124i64;
    let b = 124i64;
    let c = 1i64;

    let mut heap = MaxHeap::new();
    heap.push(a);
    heap.push(b);

    println!("{:?}", &c);
    if let Some(root) = &heap.root {
        println!("{:?}", root.value);
    }
}

内容的提问来源于stack exchange,提问作者Валентин Стайков

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 03:39:25