你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

C语言printf函数的“安全隐患”

[复制链接]
gaosmile 发布时间:2020-12-3 22:14
程序员都知道,也都会使用printf函数,但你知道它也有“安全隐患”吗?

1 E" i) a* P* ?# A$ W9 I
下面就来举例我说说:

2 k. E  [' @$ u/ ^% m, J' P" s7 Z
嵌入式专栏
1
问题描述
打印输出的数据并不是理论值,如下图(右边):; q6 E5 K+ M) \3 `) s
微信图片_20201203221139.png
; ]3 M7 ]2 s1 r
嵌入式专栏
2
进一步描述问题
请细致注意看下面代码,有如以下奇怪的现象:

  1.   u- y( S' `; [! T
  2. int a=5;2 a5 [8 V3 |5 P
  3. floatx=a;     //这里转换是没有问题的。%f打印x是 5.000000
    5 @" s$ F( @2 a7 J
  4. % Z# R7 h' D7 t* p  a
  5. printf("%d\n",a);( J! z3 `! `7 ~
  6. printf("%f\n",a);  //输出为什么是0.000000?-----问题1
    1 U! b9 P) O0 O' q# _* C$ A
  7. printf("%f\n",x);
    0 w- d7 P' a0 L5 g+ S( V' d% Z9 q
  8. printf("%d\n",x);  //输出为什么是0?-----问题2& u+ w- F" k  I3 J- v9 Z. @5 h
  9. printf("%f,%f\n",a,x);  //输出都是0.000000  为什么?   ----问题3: ~- n% ]/ \& q, ^) U& ]
  10. printf("%f,%f\n",x,a);  //调换一下a,x的顺序,正常了,为什么?----问题4, R$ b' ~# y- N: f1 X. X, ~) e
  11. printf("%d,%f\n",a,x);- D3 O, A7 J8 _4 Z
  12. $ A" z( [3 V0 y' a! k
  13. getchar();+ Q: p: Z/ v3 G/ a3 X% S5 _$ K9 N
  14. return0;
复制代码
* G0 l$ T- ]: L: \6 R. O5 |8 {8 f+ g
这里有四个问题,下面会进行解答。9 m  I1 P) i: M, w3 I

* g, b) g2 @& w4 K, t" s' z
嵌入式专栏
3
printf()函数的原理解释明确这些问题首先须要明确printf()函数的工作原理。. }% h% P6 H( b3 d7 a
printf()维持了一个需要打印的变量栈,默认情况下,參数进栈的顺序是由右向左的。因此,參数进栈以后的内存模型例如以下图所看到的: 微信图片_20201203221144.png
7 W; [7 Z$ I7 i! A+ G3 N- s; M
打印的时候,printf依照字符转换说明符规定的格式从低地址開始提取数据。直到參数打印完。* ~% O  \* f( O$ x2 Y# F  l" U  _
比方遇到 %f 说明符就提取8个字节的数据,遇到 %d 就提取4个字节。printf()事实上不知道參数的个数,它仅仅会依据format中的打印格式的数目依次打印堆栈中參数format后面地址的内容。
: G4 y& U  y& M* A5 d' b3 x# O
这样一来,printf()事实上存在安全隐患:它会强行读取内存的数据当作正常数据输出,没有边界检测(非常有可能产生堆溢出)。1 Z9 s/ K' G4 K0 D+ ^9 R
比如这种代码:
  1.   X5 C+ a/ Q5 f
  2. char string[]="Hello World!";
    * A3 H  L; @% V3 ~3 g
  3. printf("String: %s  ,强行再读一次: %#p\n", string);
    9 O6 v- U- `7 O8 W* A# [& v) m
  4. printf("String: %s  ,强行再读一次: %#s\n", string);
复制代码

- s- g) y* p' d
输出如下:! n; M* G$ [! |4 Z# t, \. s

  1. 0 i$ n! a1 v2 D
  2. String:Hello World!  , 强行再读一次: 0X001C1073
    # n) F' k0 }) C. |" h* o/ W' @2 V
  3. String: Hello World!  ,强行再读一次: 閮
复制代码

" h) A! D2 ^% Q7 E* N
嵌入式专栏
4
问题解释
问题1:printf("%f\n",a) 输出为什么是0.000000?
答:%f 提取8字节。a仅仅有4字节,提取出来的数占了float表示法的指数部分。尾数部分为0。所以终于是0
( O4 O* e9 V! A& r. I
问题2:printf("%d\n",x)  输出为什么是0?答:%d 提取4字节,x有8字节。提取出来的数实际上是float表示法的指数部分(恰好是0),所以终于是0
: L) b% w$ N* i, ~6 m, |
问题3:printf("%f,%f\n",a,x); 输出都是0.000000 为什么?答:參照问题1的解释。提取了八字节后,后面的已经乱了
$ y* |& x  k5 h% m6 }7 `
问题4:printf("%f,%f\n",x,a);调换一下a,x的顺序,正常了,为什么?答:这是正常的情况而已。
$ A6 e: }9 K' H' y) v* O/ `. G9 k
5 `. b/ G" k0 }. n
赞 收藏 1 评论0 发布时间:2020-12-3 22:14

举报

0个回答

所属标签

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版