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

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

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

5 r" q$ N+ K; g2 Z, s* H7 s
下面就来举例我说说:

0 s/ |" z3 e  ]
嵌入式专栏
1
问题描述
打印输出的数据并不是理论值,如下图(右边):
6 @  }2 o1 K3 p: K- h' i
微信图片_20201203221139.png

4 Y1 @! ]  q# b2 y
嵌入式专栏
2
进一步描述问题
请细致注意看下面代码,有如以下奇怪的现象:
  1. 7 B  S; A( U4 T" X
  2. int a=5;
    $ I* P9 `" K- ?+ _6 X# U* i% s
  3. floatx=a;     //这里转换是没有问题的。%f打印x是 5.000000
    ) t. K0 N5 B$ }4 Q# f& q' g
  4. - p' D& w! P. Y4 U8 C2 H
  5. printf("%d\n",a);) y: V- W7 A! W- R$ g
  6. printf("%f\n",a);  //输出为什么是0.000000?-----问题1
    : Y+ R+ I$ M% G! W
  7. printf("%f\n",x);
    9 w+ R: ]0 y8 g$ L* Y/ A# U7 h8 T
  8. printf("%d\n",x);  //输出为什么是0?-----问题29 k& {! @% Q- ^" Z
  9. printf("%f,%f\n",a,x);  //输出都是0.000000  为什么?   ----问题3
    $ H) T, N, M, i
  10. printf("%f,%f\n",x,a);  //调换一下a,x的顺序,正常了,为什么?----问题4
    ) B; c) ~3 n3 \
  11. printf("%d,%f\n",a,x);! E% I' ?. H2 |/ n
  12. . u9 h# [- ]) f1 M
  13. getchar();
      A# [' s3 X/ ]8 H9 h& d5 h
  14. return0;
复制代码

' R$ w9 y3 Y) K. X
这里有四个问题,下面会进行解答。  k( q  @% K8 I' \" x) ^5 W
  d8 q: U1 |: [8 r. Z' o: o
嵌入式专栏
3
printf()函数的原理解释明确这些问题首先须要明确printf()函数的工作原理。
% y4 T- ?! z4 r1 Q
printf()维持了一个需要打印的变量栈,默认情况下,參数进栈的顺序是由右向左的。因此,參数进栈以后的内存模型例如以下图所看到的: 微信图片_20201203221144.png
7 \9 m% e) \; D3 Q  ^3 W/ @  [* j9 G
打印的时候,printf依照字符转换说明符规定的格式从低地址開始提取数据。直到參数打印完。7 ~' q" ]2 t! [6 W
比方遇到 %f 说明符就提取8个字节的数据,遇到 %d 就提取4个字节。printf()事实上不知道參数的个数,它仅仅会依据format中的打印格式的数目依次打印堆栈中參数format后面地址的内容。
- Z& n% H% a% s% q+ Y6 @$ q
这样一来,printf()事实上存在安全隐患:它会强行读取内存的数据当作正常数据输出,没有边界检测(非常有可能产生堆溢出)。
2 b4 ]7 J$ {" O$ a7 {$ f1 \+ D
比如这种代码:

  1. 2 p: h0 a7 N/ k6 F
  2. char string[]="Hello World!";* F* }; }5 c5 n5 Q: y' P: Z) _1 M
  3. printf("String: %s  ,强行再读一次: %#p\n", string);
    8 ]) c  M8 E! T! K. G% G" ~
  4. printf("String: %s  ,强行再读一次: %#s\n", string);
复制代码

5 U3 C2 W, e7 n" K$ ^$ R, S3 I
输出如下:+ t" ^( D. x7 A% y- K7 V
  1. 1 f) D- r+ k  t0 r; A2 m
  2. String:Hello World!  , 强行再读一次: 0X001C1073
    4 J- ~- }- I) y- @4 a
  3. String: Hello World!  ,强行再读一次: 閮
复制代码

) R! m, @7 \( ^
嵌入式专栏
4
问题解释
问题1:printf("%f\n",a) 输出为什么是0.000000?
答:%f 提取8字节。a仅仅有4字节,提取出来的数占了float表示法的指数部分。尾数部分为0。所以终于是0
$ Q9 L, M) S, ?9 E- g7 K: v
问题2:printf("%d\n",x)  输出为什么是0?答:%d 提取4字节,x有8字节。提取出来的数实际上是float表示法的指数部分(恰好是0),所以终于是0; ]) j% f4 H. l/ a
问题3:printf("%f,%f\n",a,x); 输出都是0.000000 为什么?答:參照问题1的解释。提取了八字节后,后面的已经乱了
# B3 X+ p6 N: S* {
问题4:printf("%f,%f\n",x,a);调换一下a,x的顺序,正常了,为什么?答:这是正常的情况而已。
5 A1 p% K0 i) e; U4 R; f: n; k: F, |. I8 J
赞 收藏 1 评论0 发布时间:2020-12-3 22:14

举报

0个回答

所属标签

相似技术帖

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