printf函数的内涵以及造成的严重内存问题

2023-05-16

问题的引出:在某型号的核心网络交换机设备中,为调试方便,实现了一个把内存内容从终端打印的功能,也就是dump memory,屏幕的左边显示十六进制,右边以ASCII形式显示,用过UltraEdit的十六进制编辑功能朋友应该都很了解。显示ASCII码部分的实现,是这样的:
printf (string_ascii); /* string_ascii指向待显示的内存段 */
结果,这个函数调用引起了一个致命的问题,原本用于调试的功能,居然造成了整机重启。

 

问题解决讨论:

1,问题出在对printf函数的细节理解上。大家都知道调用printf函数要include ,但是有谁看过stdio.h里面对printf函数的原型声明?
一句话,想成为职业C程序员,就必须多看源码,特别是对一些细节的推敲。找出答案的一个重要线索,就藏在stdio.h里面的printf函数原型里。

int __cdecl printf(const char *, ...);

2,printf 的参数应该是字符串,也就是从那个参数指针指向的第一个非零数据一直打印直到遇到0x00。大概是指向的内存段一直都没有0x00这个值吧。

 

3,没错,第一个参数是一个字符串,但它并非一般的字符串,而是格式化字符串。提醒一下,如果这个字符串里面不含有转义字符,如%d, %x这样的符号,那么会打印出字符串本身。但是如果含有这些符号但是后面没有参数来指明这个符号呢?如果这个符号代表指针呢?

比如:printf("%d,%s");后面根本没有参数来指明%d和%s。

 

4,应该说,如果是有%s,那么会在这个地方插入一个字串,该字串的起始地址是printf的下一个参数。如果没有这个参数,会读取一个随机的地址,这个地址很可能是非法的,从而导致系统的崩溃。

 

5,函数看到fmt这个字串里面的转义字符%,就去寻找下一个参数。如果调用函数的时候并没有传递这个参数,函数会取得一个随机值对应这个转义字符。问题是,这个随机值从哪里取出来的?

 

6,printf函数的实现,大致是这样的:

int printf(const char *fmt, ...)
{
char printf_buf[1024];
va_list args;
int printed;

va_start(args, fmt);//调用va_start后args将指向第一个可变参数
printed = vsprintf(printf_buf, fmt, args);//调用vsprintf将fmt字符串按照args指向的第一个可变参数开始格式化输出,并将由args替换fmt中的格式化字符串保存在printf_buf缓冲中。如printf("kevin %d,%f,%s",num,fnum,string),则printf_buf中保存的是kevin 44,3.450000,abc
va_end(args);

puts(printf_buf);

return printed;
}

 

我们可以看到,它是调用vsprintf函数,将第二个参数以后的参数,按格式化字串输出,然后在终端显示出来。如果格式化字串中有多余的%字符,而没有传递相应的参数,会获得一个随机数。
这里有两个问题:首先,如果这个多余的%转义字符是一个“%s”,后果是怎样的呢?后果就是访问了一个没有初始化的指针“野指针”。对于8051/ARM7这样没有内存处理单元(MMU)的处理器,会显示不可预料的内容。但对于MIPS/X86这样有MMU的处理器,CPU内部的硬件线路会判断这个指针是否合法。如果是一个非法指针,会引发系统抛出一个异常(Exception),从而导致进程崩溃(process crash),也就是Windows下常见的“该程序执行了非法操作”。而在操作系统内核中发生了这种错误,会引发内核panic,类似Windows的蓝屏死机的概念,系统彻底崩溃。前面提到的,出现这个问题的核心交换机上,就是由于出现内核panic而死机重启的。

那么,随机数是从哪里获得的呢?
这个问题和体系结构密切相关了。对于x86,我们知道,参数是通过堆栈传递的,那么也就是从没有初始化的堆栈存储区取得的。而对于MIPS/ARM这样的RISC处理器,系统会占用几个寄存器作为传递参数用,如果不够用再通过堆栈传递。因此,在RISC处理器上,错误的参数还有可能从寄存器传递过来。8051是CISC处理器中的一个异类,C51编译器的函数参数传递,使用了R4到R7的四个寄存器,和RISC类似,这点要注意。
最后,请大家吸取一个教训,printf的第一个参数char *fmt,指针指向的内容一定要可控,千万不要用计算机自动生成的内容。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

printf函数的内涵以及造成的严重内存问题 的相关文章

  • jetson nano 散热风扇控制

    由于jetson nano开发板完全依靠自带的静态散热在运行程序时通过jtop查看GPU CPU等组件温度均超过70 xff0c 所以添加一个5v散热风扇 xff08 tegrastats也可以用来查看系统状态 xff09 tegrasta
  • win10环境安装numpy,tensorflow,keras及版本对应关系

    python未安装的 xff0c 可以阅读我的文章如下图标题 xff0c 虚拟环境不是必要的 xff0c 但是为了规范和后续工作的方便管理 xff0c 建立虚拟环境也是非常重要的 建议安装python3 6版本的 xff0c 这个版本相对来
  • 解决方案No module named ‘sklearn.utils.linear_assignment_‘

    错误原因 xff1a linear assignment被弃用 xff0c 官方将scipy optimize linear sum assignment代替了sklearn utils linear assignment 方法一 xff1
  • pip使用豆瓣镜像源

    一 镜像源 清华镜像源 https pypi tuna tsinghua edu cn simple 豆瓣镜像源 http pypi douban com simple 阿里镜像源 http mirrors aliyun com pypi
  • 信息熵(ID3)、信息增益(C4.5)、基尼值和基尼指数

    1 信息熵 熵 Entropy 是 混乱 程度的量度 系统越有序 xff0c 熵值越低 xff1b 系统越混乱或者分散 xff0c 熵值越高 信息理论 xff1a 1 从信息的完整性上进行的描述 当系统的有序状态一致时 xff0c 数据越集
  • nvidia-smi 系列命令,查看gpu ,显存信息

    显卡包含gpu xff0c 显存 xff0c gpu不等于显存 nvidia smi 的定义 xff1a 基于 NVIDIA Management Library xff08 NVIDIA 管理库 xff09 xff0c 实现 NVIDIA
  • chown和chmod区别

    一 文件权限结构 ll查看某一个目录会得到一个7字段的列表 第一个字段是文件属性字段 xff08 eg drwxr xr x xff09 xff0c 文件属性字段总共10个字母 xff1a 第一个字符代表文件类型 xff1a xff1a 普
  • git常用命令大全

    目录 1 设置用户签名 2 初始化本地库 3 添加到暂存区 4 删除暂存区文件 xff0c 但是工作区仍存在 5 提交本地库 6 查看日志信息 7 修改文件 8 版本穿梭 参考文献 尚硅谷Git入门到精通全套教程 xff08 涵盖GitHu
  • 安装kalibr踩坑1:Could NOT find GTest (missing: GTEST_LIBRARY GTEST_MAIN_LIBRARY)

    Could NOT find GTest missing GTEST LIBRARY GTEST MAIN LIBRARY 因为GTest虽然安装过 xff0c 但是好像找不到头文件 sudo apt get install libgtes
  • 安装kalibr踩坑2:fatal error: ceres/rotation.h: No such file or directory #include “ceres/rotation.h“

    fatal error ceres rotation h No such file or directory include 34 ceres rotation h 34 ceres没有装好 xff0c 需要重装 xff0c 安装方法如下
  • 嵌入式数据结构以及算法(数据结构篇)

    数据结构可以说是嵌入式开发学习中比较重要的一个部分了 xff0c 而沉迷于基础硬件控制的我到现在才意识到这个东西的重要性可以说是比较迟钝了 xff0c 但是迟钝总比知道也不学来的好 xff08 自我安慰请忽略 xff09 下面总结一下经过几
  • ubuntu18.04安装kalibr疯狂踩坑记录

    1 安装ubuntu18 04对应的ros 我用的是镜像Docker Hub xff0c 该镜像包含vnc和ros docker pull tiryoh ros desktop vnc melodic 2 安装kalibr 1 安装依赖环境
  • CMakeList.txt写法

    ROS 创建并运行一个c 43 43 的demo xyzxyz576的博客 CSDN博客 目录 样例 解释如下 1 确定cmake最低版本需求 2 确定工程名 3 添加需要的库 4 添加需要的头文件 5 确定编译语言 6 设定变量 7 添加
  • 解决WSL2中Vmmem内存占用过大问题

    Vmmem介绍 Vmmem 进程是系统合成的一个虚拟进程 xff0c 用于表示虚拟机消耗的内存和 CPU 资源 换句话说 xff0c 如果您看到 Vmmem 消耗大量内存和 CPU 资源 xff0c 那么这意味着您的虚拟机正在消耗大量内存和
  • gnss、gps、imu、rtk、ins区分及含义

    gnss和gps区别 1 GPS xff08 全球卫星定位系统 xff09 是由美国国防部研制建立的一种具有全方位 全天候 全时段 高精度的卫星导航系统 xff1b 能为全球用户提供低成本 高精度的三维位置 速度和精确定时等导航信息 2 G
  • Windows下启动Docker容器遇到Error invoking remote method ‘docker-start-container‘: Error解决办法

    报错 xff1a Error invoking remote method 39 docker start container 39 Error HTTP code 500 server error Ports are not availa
  • java变量的定义

    JAVA数据类型 对于整型数据 xff0c 通常情况下使用int类型 但是如果表示极大的数据 xff0c 就需要long类型了 xff0c byte和short类型主要用于特定的应用场合 xff0c 例如 xff1a 底层的文件处理或者需要
  • java数据类型转换(强制转换)

    数据类型的转换 xff0c 分为自动转换和强制转换 自动转换是程序在执行过程中 无声 进行的转换 xff0c 不需要提前声明 xff0c 一般是从位数低的类型向位数高的类型转换 xff1b 强制转换则必须在代码中声明 xff0c 转换顺序不
  • 斗鱼直播与熊猫直播竞品分析

    引言 xff1a 目前国内直播平台虽然十分火爆 xff0c 但是直播的市场尚未成熟 xff0c 斗鱼等其他直播平台在利用自己用户的基础一直处在直播平台的主流市场 xff0c 而新晋直播平台开始大肆的宣传和吸引用户 xff0c 最终直播这块市
  • 知乎产品分析|知识社区何去何从

    一 引言 2017 年 2 月 xff0c 知乎月独立用户设备数再次回升 xff0c 相比 1 月上涨了 11 2 xff0c 达到了 1109 万台 1 1 目的 通过对知乎这款产品的分析 xff0c 锻炼自己的思维能力 xff0c 深化

随机推荐

  • 以CSDN为例解释尼尔森十大交互原则

    一 状态可见原则 用户在网页上的任何操作 xff0c 不论是单击 滚动还是按下键盘 xff0c 页面应即时给出反馈 即时 是指 xff0c 页面响应时间小于用户能忍受的等待时间 举例 xff1a CSDN上文章底部都会有一个 喜欢 按钮 x
  • Chapter007-FPGA学习之IIC总线EEPROM读取

    IIC总线是嵌入式领域较为重要的器件间通信总线 xff0c 同样 xff0c FPGA也能通过模块的形式实现IIC的功能 xff0c 其原理和STM32的模拟IIC总线一致 xff0c 就是控制每个时间点的SCL SDA总线电平 IIC总线
  • 游戏化思维——核心驱动力

    游戏是一个令人着迷 xff0c 并且能够让人沉迷于此的东西 xff0c 而游戏之所以如此迷人 xff0c 不但是游戏的制作精良和剧情引人入胜 除此之外还有些其他原因 xff0c 激励人民玩游戏的原因是 xff1a 游戏能够触及到人性的核心驱
  • 从产品设计到用户设计

    从产品设计到用户设计 一说起产品设计 xff0c 人们往往想到两个方面 感官方面 功能方面 感官方面 xff1a 精心设计的产品能够给用户带来赏心悦目的感觉 xff0c 当然极大部分是属于触感方面 xff08 嗅觉和味觉因为局限问题无法在产
  • 十年寒窗,从高考到海盗,人的梦想是不会结束的

    其实这是讲述我是如何想要成为一名海盗的 又是一年高考时 我翻看着手机 xff0c 看着朋友圈里面各种高考热文一篇篇的出现 xff0c 心里难免有些感慨和一些自己的回忆 当年高考时也像现在一样 xff0c 看到了许多这样的文章 xff0c 看
  • 为体验设计——使用第一

    产品设计和用户体验设计有什么不同呢 xff1f 每个产品都是以用户是人类为前提而设计出来的 xff0c 而产品的每一次使用 xff0c 都会产生相应的体验 用户体验设计并完全不等同于产品设计 但是对于一个简单的情况下 xff0c 创建一个良
  • 用户体验和网站

    用户体验对于所有的产品和服务来讲 xff0c 都是至关重要的 现在讨论一种特殊产品的用户体验 xff1a 网站 xff08 这里的 网站 一词包括以内容为主的网站产品和以交互为主的网站应用 xff09 在网站上 xff0c 用户体验比任何一
  • UCOS II两个任务的模板

    芯片lm3s9b92 include lt includes h gt include 34 utils uartstdio h 34 Application tasks 优先级 define TASK2 PRIO 11 define ta
  • UCOSII 信号量和信号量集实例

    代码来自于书本光盘 嵌入式操作系统UCOSII原理及应用 实例1信号量 include 34 includes h 34 define TASK STK SIZE 512 任务堆栈长度 OS STK StartTaskStk TASK ST
  • 正点原子MiniFly V1.2学习笔记一

    之前看过原子哥的FreeRTOS开发手册 xff0c 但是对整个项目 怎么架构还不是很清楚 由于最近工作需要上FreeRTOS xff0c 所以决定通过MiniFly来学习一下FreeRTOS的架构 一 main 函数 int main s
  • 正点原子MiniFly V1.2学习笔记三---atkpRxAnlTask

    第5个任务 解析处理接收到的指令 xTaskCreate atkpRxAnlTask 34 ATKP RX ANL 34 300 NULL 6 NULL 上面第1个任务 xff0c 把串口接收到的数据解包后得到指令 xff0c 然后把指令发
  • 正点原子MiniFly V1.2学习笔记五---sensorsTask

    这里先学习第8个任务sensorsTask xff0c 2 xff0c 3 xff0c 6 xff0c 7任务后面再学 xff0c 先学重要的 xTaskCreate sensorsTask 34 SENSORS 34 450 NULL 4
  • 嵌入式项目管理学习——001重点明确和心态转换

    相信做嵌入式的码哥们在参与一定数量的产品设计和生产之后 xff0c 都会发现一个问题 xff0c 如果没有一个负责的产品经理 xff0c 就会陷入到产品延期 沟通缺失 目标不清晰 需求不明确等等的问题 xff0c 我目前也是达到了这样一个状
  • 正点原子MiniFly V1.2学习笔记六---stabilizerTask

    第9个任务 xff0c 优先级5 xTaskCreate stabilizerTask 34 STABILIZER 34 450 NULL 5 NULL 一 任务函数 使用绝对延时 xff0c 周期执行任务 二 传感器数据是怎么传到这个任务
  • 正点原子MiniFly V1.2学习笔记七---configParamTask

    第6个任务 xff0c 优先级1 xff0c 最低优先级 配置参数任务 xTaskCreate configParamTask 34 CONFIG TASK 34 150 NULL 1 NULL 一 全局参数configParam 1 参数
  • C++码农要读的经典

    刚大四 xff0c 还在忙着找工作 xff0c 读过的书不是很多 xff0c 还有一些好书在读 xff0c 还有一些书将来必读 C语言程序设计 谭浩强版本 这个版本一致被人说误导子弟 xff0c 当然还有很多人推崇 我觉得这本书不是什么好书
  • 解读gazebo_ros_control gazebo_ros

    本篇的目的是想解读gazebo ros control 以及 gazebo ros 因为gazebo本身是独立于ros的 通过教程Intermediate Control plugin 以及教程 Category Write a plugi
  • vtaskstartscheduler(); //开启任务调度语句不执行

    项目场景 xff1a FreeRTOS实时嵌入式操作系统开发 基于stm32 第一章移植代码 问题描述 xff1a 任务调度器执行到vtaskstartscheduler 开启任务调度语句不执行 span class token keywo
  • python3中定义类变量,并使用类函数修改类变量的值

    定义类变量的方式有两种 1 在 init 中定义self elements 其中self elements是类变量名 a是传入Difference类的参数名 xff0c 这里的 init 作用是定义了类变量名 xff0c 将外部参数a传给类
  • printf函数的内涵以及造成的严重内存问题

    问题的引出 xff1a 在某型号的核心网络交换机设备中 xff0c 为调试方便 xff0c 实现了一个把内存内容从终端打印的功能 xff0c 也就是dump memory xff0c 屏幕的左边显示十六进制 xff0c 右边以ASCII形式