Rust-内存安全

news2025/1/26 15:30:09

堆和栈

一个进程在执行的时候,它所占用的内存的虚拟地址空间一般被分割成好几个区域,我们称为“段”(Segment)。常见的几个段如下。

  • 代码段。编译后的机器码存在的区域。一般这个段是只读的。
  • bss段。存放未初始化的全局变量和静态变量的区域。
  • 数据段。存放有初始化的全局变量和静态变量的区域。
  • 函数调用栈(call stack segment)。存放函数参数、局部变量以及其他函数调用相关信息的区域。
  • 堆(heap)。存放动态分配内存的区域。

函数调用栈(call stack)也可以简称为栈(stack)。

因为函数调用栈本来就是基于栈这样一个数据结构实现的。

它具备“后入先出”(LIFO)的特点。最先进入的数据也是最后出来的数据。

一般来说,CPU有专门的指令可以用于入栈或者出栈的操作。

当一个函数被调用时,就会有指令把当前指令的地址压入栈内保存起来,然后跳转到被调用的函数中执行。

函数返回的时候,就会把栈里面先前的指令地址弹出来继续执行,如图所示。
在这里插入图片描述

堆是为动态分配预留的内存空间,如图所示。
在这里插入图片描述

和栈不一样,从堆上分配和重新分配块没有固定模式,用户可以在任何时候分配和释放它。这样就使得跟踪哪部分堆已经被分配和被释放变得异常复杂;有许多定制的堆分配策略用来为不同的使用模式下调整堆的性能。堆是在内存中动态分配的内存,是无序的。每个线程都有一个栈,但是每一个应用程序通常都只有一个堆。在堆上的变量必须要手动释放,不存在作用域的问题。

段错误

segfault实际上是“segmentation fault”的缩写形式,我们可以翻译为“段错误”。

segfault是这样形成的:进程空间中的每个段通过硬件MMU映射到真正的物理空间;

在这个映射过程中,我们还可以给不同的段设置不同的访问权限,比如代码段就是只能读不能写;

进程在执行过程中,如果违反了这些权限,CPU会直接产生一个硬件异常;

硬件异常会被操作系统内核处理,一般内核会向对应的进程发送一条信号;

如果没有实现自己特殊的信号处理函数,默认情况下,这个进程会直接非正常退出;

如果操作系统打开了core dump功能,在进程退出的时候操作系统会把它当时的内存状态、寄存器状态以及各种相关信息保存到一个文件中,供用户以后调试使用。

在传统系统级编程语言C/C++里面,制造segfault是很容易的。程序员需要非常小心才能避免这种错误,这也是为什么会有那么多的代码标准来规范程序员的行为。

而另外一类编程语言规避segfault的办法是使用自动垃圾回收机制。

在这些编程语言中,指针的能力被大幅限制,内存分配和释放都在一个运行时环境中被严格管理。

当然,这么做也付出了一定的代价。某些应用场景下用这样的代价换取开发效率和安全性是非常划算的,而在某些应用场景下这样的代价是不可接受的。

Rust的主要设计目标之一,是在不用自动垃圾回收机制的前提下避免产生segfault。从这个意义上来说,它是独一无二的。

内存安全

在谈到Rust的时候,经常会提到的一个概念,那就是“内存安全”(Memory safety)。

内存安全是Rust设计的主要目标之一,因此我们有必要把这个概念做一个澄清,让大家能更清楚地理解Rust为什么要这么设计。

  • 空指针
    解引用空指针是不安全的。这块地址空间一般是受保护的,对空指针解引用在大部分平台上会产生segfault。

  • 野指针
    野指针指的是未初始化的指针。它的值取决于它这个位置以前遗留下来的是什么值。所以它可能指向任意一个地方。对它解引用,可能会造成segfault,也可能不会,纯粹凭运气。但无论如何,这个行为都不会是你预期内的行为,是一定会产生bug的。

  • 悬空指针
    悬空指针指的是内存空间在被释放了之后,继续使用。它跟野指针类似,同样会读写已经不属于这个指针的内容。

  • 使用未初始化内存
    不只是指针类型,任何一种类型不初始化就直接使用都是危险的,造成的后果我们完全无法预测。

  • 非法释放
    内存分配和释放要配对。如果对同一个指针释放两次,会制造出内存错误。如果指针并不是内存分配器返回的值,对其执行释放操作,也是危险的。

  • 缓冲区溢出
    指针访问越界了,结果也是类似于野指针,会读取或者修改临近内存空间的值,造成危险。

  • 执行非法函数指针
    如果一个函数指针不是准确地指向一个函数地址,那么调用这个函数指针会导致一段随机数据被当成指令来执行,是非常危险的。

  • 数据竞争
    在有并发的场景下,针对同一块内存同时读写,且没有同步措施。

以上这些问题都是极度危险的,而且它们并不一定会在发生的时候就被发现并立即终止。

它们不一定会直接触发core dump,有可能程序一直带病运行,只是结果一直有bug但却无法找到原因,因为真正的原因与表现之间没有任何肉眼可见的关联关系。

它们有可能造成非常随机的、难以复现和难以调试的诡异bug,就像武林高手一样神出鬼没,行踪不定。

它们也可能在经过许多步骤之后最终触发core dump,可惜此时早已不是案发第一现场,修复这种bug的难度极高。

在Rust语境中,还有一些内存错误是不算在“内存安全”范畴内的,比如内存泄漏以及内存耗尽。

内存泄漏显然是一种bug,但是它不会直接造成非常严重的后果,至少比上面列出的那些错误危险性要低一些,解决的办法也是完全不一样的。

同样,内存耗尽也不是事关安全性的问题,出现内存耗尽的时候,Rust程序的行为依然是确定性的和可控的(目前版本下,如果内存耗尽则发生panic,也有人认为在这种情况发生的时候,应该给个机会由用户自己处理,这种情况后面应该会有改进)。

另外,panic也不属于内存安全相关的问题。

panic和core dump之间有重要区别。panic是发生不可恢复错误后,程序主动执行的一种错误处理机制;而core dump则是程序失控之后,触发了操作系统的保护机制而被动退出的。

发生panic的时候,此处就是确定性的第一现场,我们可以根据call stack信息很快找到事发地点,然后修复。panic是防止更严重内存安全错误的重要机制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1383476.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java: 5-6 break

文章目录 1. break1.1 介绍1.2 语法和流程图1.3 入门练习1.4 细节说明1.5 练习 【老韩视频p137-】 1. break 看个需求:随机生成 1-100 的一个数,直到生成了 97 这个数,看看你一共用了几次? 【思路分析:循环,但是循环的次数不知道…

NLP论文阅读记录 - 2022 W0S | 基于Longformer和Transformer的提取摘要层次表示模型

文章目录 前言0、论文摘要一、Introduction1.1目标问题1.2相关的尝试1.3本文贡献 二.相关工作三.本文方法四 实验效果4.1数据集4.2 对比模型4.3实施细节4.4评估指标4.5 实验结果4.6 细粒度分析 五 总结思考 前言 A Hierarchical Representation Model Based on Longformer and …

【模型评估 04】A/B测试的陷阱

互联网公司中,A/B测试是验证新模块、新功能、新产品是否有效;新算法、新模型的效果是否有提升;新设计是否受到用户欢迎;新更改是否影响用户体验的主要测试方法。在机器学习领域中,A/B测试是验证模型最终效果的主要手段…

知乎x-zse-96算法分析

声明 本文以教学为基准、本文提供的可操作性不得用于任何商业用途和违法违规场景。 本人对任何原因在使用本人中提供的代码和策略时可能对用户自己或他人造成的任何形式的损失和伤害不承担责任。 如有侵权,请联系我进行删除。 这里只是我分析过程,以及一些重要点的记录,没有…

yolov5的完整部署(适合新人和懒人,一键安装)

第一步:安装Anaconda 下载并安装后,配置一下镜像 在这里面,看情况输入镜像源,这里我建议大家搞阿里云镜像源。 # 添加清华源 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda conf…

零知识证明的最新发展和应用

PrimiHub一款由密码学专家团队打造的开源隐私计算平台,专注于分享数据安全、密码学、联邦学习、同态加密等隐私计算领域的技术和内容。 当企业收集大量客户数据去审查、改进产品和服务以及将数据资产货币化时,他们容易受到网络攻击威胁,造成数…

从Demo理解Thrift Thrift和Dubbo的区别

文章目录 安装demo尝试Thrift协议栈Thrift 与 Dubbo 的区别 字节里的RPC框架都是用的Thrift,我猜这主要原因有2: Thrift是Facebook开源的项目,平台中立Thrift支持跨语言调用,这非常适合字节Java、Go语言都存在的环境,语言中立 但…

手把手Docker部署Gitblit服务器

1拉取镜像 docker pull jacekkow/gitblit:v1.9.1 2.启动 docker run -d --name gitblit --restart always -p 10006:8080 -p 18443:8443 -p 19418:9418 -p 29418:29418 -v /data/gitblit/data:/opt/gitblit-data jacekkow/gitblit:v1.9.1 3.查看 默认账户/密码:admin/adm…

运算放大器相关知识总结(1)

1、 前言 最近做了一个小项目,这个项目是研发一款阻抗测量仪。这个阻抗测量仪可以测量人体在不同频率下的生物电阻抗,该设备的核心是模拟电路,技术难点是减小模拟电路噪声。该项目前前忙了2个多月,借着研发这个项目的机会把自己掌…

Jenkins-用户管理

用户管理 1 安装插件 2 选择安全策略为刚刚安装的插件 3 这个是安装插件以后会有的选项 4 增加一个角色 5 根据需要赋值角色的权限,并分配给用户

Protecting Intellectual Property of Deep NeuralNetworks with Watermarking

保护深度神经网络的知识产权与数字水印技术 ABSTRACT 深度学习是当今人工智能服务的关键组成部分,在视觉分析、语音识别、自然语言处理等多个任务方面表现出色,为人类提供了接近人类水平的能力。构建一个生产级别的深度学习模型是一项非常复杂的任务&a…

每日算法打卡:摘花生 day 14

文章目录 原题链接题目描述输入格式输出格式数据范围输入样例:输出样例: 题目分析示例代码 原题链接 1015. 摘花生 题目难度:简单 题目来源:《信息学奥赛一本通》 题目描述 Hello Kitty想摘点花生送给她喜欢的米老鼠。 她来…

机器学习_捕捉函数的变化趋势(凸函数)

文章目录 连续性是求导的前提条件通过求导发现 y 如何随 x 而变凸函数有一个全局最低点 机器学习所关心的问题之一捕捉函数的变化趋势,也就是标签(y)是如何随着特征字段(x)而变化的,这个变化趋势是通过求导…

Arm Generic Interrupt Controller v3 and v4(GICv3v4)学习(一)

提示 该博客主要为个人学习,通过阅读官网手册整理而来(个人觉得阅读官网的英文文档非常有助于理解各个IP特性)。若有不对之处请参考参考文档,以官网参考文档为准。 Arm Generic Interrupt Controller v3 and v4学习一共分为三章&…

【ArcGIS微课1000例】0088:计算城市建筑物朝向(矩形角度)

文章目录 一、实验描述二、实验数据三、角度计算1. 添加字段2. 计算角度四、方向计算一、实验描述 矩形要素具有长轴和短轴,其长轴方向也称为矩形面的主角度,可用于确定面要素的走向趋势。根据该方向参数,可以对具有矩形特征的地理对象进行方向分析,且适用于很多应用场景,…

利用PicGo和SM.MS图床工具实现Markdown(Typora)图片脱离本地路径

利用PicGo和SM.MS图床工具实现Markdown(Typora)图片脱离本地路径 文章目录 利用PicGo和SM.MS图床工具实现Markdown(Typora)图片脱离本地路径1.**前言:**2.解决方案2.1准备工具2.2. 工具介绍2.2.1. Typora2.2.2. SM.MS图床2.2.3. P…

如何使用手机公网远程访问本地群辉Video Station中视频文件【内网穿透】

最近,我发现了一个超级强大的人工智能学习网站。它以通俗易懂的方式呈现复杂的概念,而且内容风趣幽默。我觉得它对大家可能会有所帮助,所以我在此分享。点击这里跳转到网站。 文章目录 1.使用环境要求:2.下载群晖videostation&am…

AnnData:单细胞和空间组学分析的数据基石

AnnData:单细胞和空间组学分析的数据基石 今天我们来系统学习一下单细胞分析的标准数据类型——AnnData! AnnData就是有注释的数据,全称是Annotated Data。 AnnData是为了矩阵类型数据设计的,也就是长得和表格一样的数据。比如…

SpringMVC零基础入门 - 概述、入门搭建、PostMan的使用(常见数据类型的传输)、REST风格编程

SpringMVC零基础入门 - 概述、入门搭建、PostMan的使用(常见数据类型的传输)、REST风格编程 SpringMVC是隶属于Spring框架的一部分,主要是用来进行Web开发,是对Servlet进行了封装SpringMVC是处于Web层的框架,所以其主要的作用就是用来接收前…

cpp_11_虚函数_多态_纯虚函数

编译器根据指针的类型,来确定调用哪个类的普通成员函数 编译器根据基类类型指针指向的对象类型,来确定调用哪个类的虚函数 0 非虚的世界(全普通函数) 对象的自洽性: 1)对同样的函数调用,各个类的对象都会做出恰当的…