首页 > 其他分享 >聊一聊 Rust 的 stack overflow

聊一聊 Rust 的 stack overflow

时间:2023-06-21 17:33:16浏览次数:58  
标签:node self drop 聊一聊 overflow main stack

早上看到了这篇文章 智能指针有可能会让你的应用崩溃, 下面分析一下

会导致 stack overflow 的代码

struct Node<T> {
    val: T,
    next: Option<Box<Node<T>>>,
}
struct LinkedList<T> {
    head: Option<Box<Node<T>>>,
}
impl<T> LinkedList<T> {
    fn new() -> Self {
        Self { head: None }
    }
    fn push_front(&mut self, val: T) {
        let next = self.head.take();
        self.head = Some(Box::new(Node { val, next }));
    }
}

fn main() {
    let mut list = LinkedList::new();
    for i in 0..1000000 {
        list.push_front(i);
    }
}

playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=dfb32796d46df05fd6bcc4855fc11ae1

输出的结果:

thread 'main' has overflowed its stack
fatal runtime error: stack overflow
timeout: the monitored command dumped core
/playground/tools/entrypoint.sh: line 11:     8 Aborted                 timeout --signal=KILL ${timeout} "$@"

原文中给出了解释:

程序崩溃是因为LinkedList的智能指针头部的默认释放导致对下一个节点的递归调用,这不是尾递归的,无法优化。修复方法是手动覆盖LinkedList数据结构的析构函数方法,迭代地释放每个节点,而不需要递归。从某种意义上说,这违背了智能指针的目的——它们无法从程序员那里解放手动内存管理的负担。

但是这个解释还不够直观,也没有给出修复代码

接下来我们一起以更直白的方式看看这个 LinkedList 被 Drop 时到底发生了什么

我们先给 Node<T>LinkedList<T> 加上 Drop trait, 方便我们观察代码执行过程

struct Node<T> {
    val: T,
    next: Option<Box<Node<T>>>,
}
struct LinkedList<T> {
    head: Option<Box<Node<T>>>,
}
impl<T> LinkedList<T> {
    fn new() -> Self {
        Self { head: None }
    }
    fn push_front(&mut self, val: T) {
        let next = self.head.take();
        self.head = Some(Box::new(Node { val, next }));
    }
}

impl<T> Drop for Node<T> {
    fn drop(&mut self) {
        println!("drop node begin");
        let _ = self.next.take();
        println!("drop node end");
    }
}

impl<T> Drop for LinkedList<T> {
    fn drop(&mut self) {
        println!("drop linkedlist begin");
        let _ = self.head.take();
        println!("drop linkedlist end");
    }
}

fn main() {
    let mut list = LinkedList::new();
    for i in 0..1000000 {
        list.push_front(i);
    }
    println!("EOF");
}

playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=61f7aad2bf8ddcd133a146cd88744e97

查看执行结果:

thread 'main' has overflowed its stack
fatal runtime error: stack overflow
timeout: the monitored command dumped core
/playground/tools/entrypoint.sh: line 11:     7 Aborted                 timeout --signal=KILL ${timeout} "$@"

跟原来的代码一致

查看标准输出:

EOF
drop linkedlist begin
drop node begin
drop node begin
drop node begin
(...)
drop node begin

省略处全部都是 drop node begin, 可见我们的程序在链式调用 Node<T>drop 函数。因为 drop 一个 Node 就是依次 drop 它内部的 fields(valnext),当所有 fieldsdrop 完了,这个 Node 结构也就算被释放了

问题就在它内部这个 next,它是一个链条,更准确的说应该是一个套娃

标签:node,self,drop,聊一聊,overflow,main,stack
From: https://www.cnblogs.com/hangj/p/17496798.html

相关文章

  • 聊一聊多源最短路径问题(只有5行代码哦)
    暑假,小哼准备去一些城市旅游。有些城市之间有公路,有些城市之间则没有,如下图。为了节省经费以及方便计划旅程,小哼希望在出发之前知道任意两个城市之前的最短路程。上图中有4个城市8条公路,公路上的数字表示这条公路的长短。请注意这些公路是单向的。我们现在需要求任意两个城市之......
  • 数据结构代码整理_栈Stack(C++)
           所谓栈,就是先进后出规则的实现,这种数据结构在DFS等算法体现的较为明显,因为课程要求不得不进行各种数据结构实现代码整理,就发出来与大家分享。下面有两种实现方法一个是基于数组实现的,另一个是基于链表实现的。基于数组实现源码main.cpp//main.cpp:定义控制台应用程......
  • 融合模型stacking14条经验总结和5个成功案例(互联网最全,硬核收藏)_机器学习_人工智能_
    来自Toby老师,《融合模型stacking14条经验总结和5个成功案例》我也看了很多关于融合模型stacking文章,很多作者倾向于赞美融合模型stacking,对其缺点轻描淡写,这容易误导初学者。一叶障目就是这意思。我的很多学员喜欢用融合模型作为论文或专利创新点,这是一个热门技术。最近有个同学在......
  • C++面试八股文:聊一聊指针?
    某日二师兄参加XXX科技公司的C++工程师开发岗位第17面:面试官:聊一聊指针?二师兄:好的。面试官:你觉得指针本质上是什么?二师兄:这要从内存地址开始说起了。如果有一块容量是1G的内存,假设它的地址是从0x00000000到0x3fffffff,每一个字节都对应一个地址。当我们声明一个变量并初始化它......
  • C++面试八股文:聊一聊指针?
    某日二师兄参加XXX科技公司的C++工程师开发岗位第17面:面试官:聊一聊指针?二师兄:好的。面试官:你觉得指针本质上是什么?二师兄:这要从内存地址开始说起了。如果有一块容量是1G的内存,假设它的地址是从0x00000000到0x3fffffff,每一个字节都对应一个地址。当我们声明一个变量并初始化......
  • 栈 | stack ?
    栈栈(Stack)是一种经典的数据结构,它具有“后进先出”(Last-In-First-Out,LIFO)的特性。栈通常有两个基本操作:压栈(Push)和弹栈(Pop)。压栈操作将数据元素添加到栈顶,弹栈操作将栈顶的元素弹出。除了基本操作,栈还有其他几个重要的概念:栈顶(Top):栈中最后一个压入的元素。栈底(Bottom):栈中......
  • 一条新的glibc IO_FILE利用链:_IO_obstack_jumps利用分析
    一条新的glibcIO_FILE利用链:_IO_obstack_jumps利用分析本文首发于[跳跳糖],仅在个人博客记录。由于跳跳糖的文章无法修改,所以本文有部分不同前言众所周知,由于移除了__malloc_hook/__free_hook/__realloc_hook等等一众hook全局变量,高版本glibc想要劫持程序流,离不开攻击_IO_FIL......
  • stack、vector的使用和特点
    Stack的方法stack是继承VectorclassStackextendsVector特点:栈模式----遍历时元素是先进后出具体代码实现:publicstaticvoidmain(String[]args){ Stack<String>stack=newStack<>(); //将元素添加到栈顶 stack.push("aaa"); stack.push("bbb"); stack......
  • cloudstack的重新封装--api调用
    使用python将cloudstack的多个功能进行重新封装形成api调用。#coding=utf-8#!/usr/bin/envpythonimportbase64importhmacimportjsonimportrequestsimportsysimporttimeimporturllibimportreimporthashlibimportloggingLOG=logging.getLogger(__name__......
  • LiveVideoStackCon 2020上海 6月见
    自强不息,否极泰来。当你在2020年底总结这一年的得失时,LiveVideoStackCon可能保留了难忘的瞬间——我们等待他太久了。原本计划于4月举行的LiveVideoStackCon2020上海由于COVID-19不得不推迟到6月13-14日,LiveVideoStack团队全体远程办公,线下活动全面停摆,并被每周四/周日晚间线上公......