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

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

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

' I; d3 o4 R0 c2 p
下面就来举例我说说:
+ n9 |8 Q. M" |8 s. y4 N1 L
嵌入式专栏
1
问题描述
打印输出的数据并不是理论值,如下图(右边):: N' ^, {, p5 j4 }& q
微信图片_20201203221139.png
0 w0 i' G. {, G2 ~
嵌入式专栏
2
进一步描述问题
请细致注意看下面代码,有如以下奇怪的现象:

  1. " \( v. [$ E: g+ Y) |; `% s0 _2 r1 z
  2. int a=5;
    4 P4 o5 G" s3 K  \
  3. floatx=a;     //这里转换是没有问题的。%f打印x是 5.000000" G% q/ D8 }: U# ~) r/ Y2 k+ U# s
  4. & X' t+ m* _; Z) J
  5. printf("%d\n",a);$ N4 e/ s  {# t# ~, Z, L/ N! R
  6. printf("%f\n",a);  //输出为什么是0.000000?-----问题1+ s4 M$ Z3 X/ [
  7. printf("%f\n",x);9 D0 K3 z- R) G" k! H
  8. printf("%d\n",x);  //输出为什么是0?-----问题2
    4 l+ O0 Q- s- ?. j$ I
  9. printf("%f,%f\n",a,x);  //输出都是0.000000  为什么?   ----问题3
    / k! R6 h: s# Q0 b
  10. printf("%f,%f\n",x,a);  //调换一下a,x的顺序,正常了,为什么?----问题4
    8 N3 ?% I9 ]2 t5 m# |  E  y+ ?
  11. printf("%d,%f\n",a,x);
    % n; L  F, v4 _0 A9 {+ {+ e) k( ?

  12. % Q5 g. ~3 q% m8 ^
  13. getchar();
      e1 ^4 X5 r; D- U. Q  M. o
  14. return0;
复制代码

5 J( P4 \3 |: L, E& g) t8 `* Z
这里有四个问题,下面会进行解答。
. N& U) s, S, U! X  m/ R  w1 U5 E
2 E5 V% o* }( ]% Q' ^2 [8 K& K& G8 j
嵌入式专栏
3
printf()函数的原理解释明确这些问题首先须要明确printf()函数的工作原理。
' h& J+ q' n" Y. }) j- E6 U
printf()维持了一个需要打印的变量栈,默认情况下,參数进栈的顺序是由右向左的。因此,參数进栈以后的内存模型例如以下图所看到的: 微信图片_20201203221144.png 2 K+ }' ?. a% d9 O: p$ J) l8 m
打印的时候,printf依照字符转换说明符规定的格式从低地址開始提取数据。直到參数打印完。
6 |8 ^4 |: W# U7 N: B& e4 ~( T
比方遇到 %f 说明符就提取8个字节的数据,遇到 %d 就提取4个字节。printf()事实上不知道參数的个数,它仅仅会依据format中的打印格式的数目依次打印堆栈中參数format后面地址的内容。% |& O1 N8 s+ N9 t9 S
这样一来,printf()事实上存在安全隐患:它会强行读取内存的数据当作正常数据输出,没有边界检测(非常有可能产生堆溢出)。, G7 N+ ?) z& V  w) P
比如这种代码:
  1. 0 o2 s: h3 b4 b8 K, V4 @& l
  2. char string[]="Hello World!";. K' W8 r) L" j- V/ T  R- F
  3. printf("String: %s  ,强行再读一次: %#p\n", string);& s, ]; A5 U8 _+ T" O" x
  4. printf("String: %s  ,强行再读一次: %#s\n", string);
复制代码

' }* N; L1 P9 i& P% M6 O4 e
输出如下:
7 }0 T5 W7 W" w+ y% U; z4 n
  1. 8 [" Z3 [: T3 g$ N
  2. String:Hello World!  , 强行再读一次: 0X001C1073
    0 C, c5 K( m5 @, e; w
  3. String: Hello World!  ,强行再读一次: 閮
复制代码

. u  V  J$ U* w0 D; |/ {2 v$ P8 w
嵌入式专栏
4
问题解释
问题1:printf("%f\n",a) 输出为什么是0.000000?
答:%f 提取8字节。a仅仅有4字节,提取出来的数占了float表示法的指数部分。尾数部分为0。所以终于是0
0 V6 K) b  `. `% j& v/ z% |, p9 P
问题2:printf("%d\n",x)  输出为什么是0?答:%d 提取4字节,x有8字节。提取出来的数实际上是float表示法的指数部分(恰好是0),所以终于是0  f# o/ d/ u. J8 v
问题3:printf("%f,%f\n",a,x); 输出都是0.000000 为什么?答:參照问题1的解释。提取了八字节后,后面的已经乱了7 A) p/ V# x/ C8 h# h- m  I& T
问题4:printf("%f,%f\n",x,a);调换一下a,x的顺序,正常了,为什么?答:这是正常的情况而已。$ i6 X4 Q9 }0 C2 d; `

; a* Q( n3 K7 v& h8 F' s+ ]
收藏 1 评论0 发布时间:2020-12-3 22:14

举报

0个回答

所属标签

相似技术帖

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