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

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

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

1 }7 M2 {6 y1 f, X' ~/ C# c% M* z, e
下面就来举例我说说:
- x9 a# s; Q- l/ |
嵌入式专栏
1
问题描述
打印输出的数据并不是理论值,如下图(右边):
  |1 K2 s  k6 m# X
微信图片_20201203221139.png
& J: `& I" f0 X: g0 j- T9 O" F8 H
嵌入式专栏
2
进一步描述问题
请细致注意看下面代码,有如以下奇怪的现象:
  1. / y6 n) a' |' _5 ?
  2. int a=5;
    . J2 Z  G* ?9 P
  3. floatx=a;     //这里转换是没有问题的。%f打印x是 5.000000$ L8 M) m/ V7 X' r
  4. & }! S: O+ W6 L: w! p) P* R
  5. printf("%d\n",a);' ^0 Q- f( l  v; W
  6. printf("%f\n",a);  //输出为什么是0.000000?-----问题1
    ) z. d" E! s2 X; B# J
  7. printf("%f\n",x);
    2 s8 d% }9 T! L4 l1 Z' Z8 @
  8. printf("%d\n",x);  //输出为什么是0?-----问题2, O7 z2 A, D: O, I: k1 \
  9. printf("%f,%f\n",a,x);  //输出都是0.000000  为什么?   ----问题3) J# e7 W' p/ k) W
  10. printf("%f,%f\n",x,a);  //调换一下a,x的顺序,正常了,为什么?----问题4
    1 f; a' ]& _, ]6 R0 R" r) f
  11. printf("%d,%f\n",a,x);1 \1 C( ]! _& h9 z
  12. # h) j* t' N& d' X. ^
  13. getchar();
    ) H5 i" x: S! J- c( j0 a: B
  14. return0;
复制代码
3 {: L+ t2 V. s" B% }8 I4 \4 G
这里有四个问题,下面会进行解答。8 S  c5 b" ^0 N% N7 V) S
" |0 C1 U* n2 j
嵌入式专栏
3
printf()函数的原理解释明确这些问题首先须要明确printf()函数的工作原理。$ H* t% D6 Q: }2 B) h
printf()维持了一个需要打印的变量栈,默认情况下,參数进栈的顺序是由右向左的。因此,參数进栈以后的内存模型例如以下图所看到的: 微信图片_20201203221144.png
- B& |3 \7 }5 E2 f2 n5 u8 D
打印的时候,printf依照字符转换说明符规定的格式从低地址開始提取数据。直到參数打印完。
$ @% B& M1 I; O2 q4 e" U& |  m. C  d
比方遇到 %f 说明符就提取8个字节的数据,遇到 %d 就提取4个字节。printf()事实上不知道參数的个数,它仅仅会依据format中的打印格式的数目依次打印堆栈中參数format后面地址的内容。
3 _# J) e6 L+ W2 P9 L
这样一来,printf()事实上存在安全隐患:它会强行读取内存的数据当作正常数据输出,没有边界检测(非常有可能产生堆溢出)。
& K3 D. ?' Q: `3 a' E7 K
比如这种代码:

  1. - x) t4 e/ ^- e) o
  2. char string[]="Hello World!";$ V- d; _  n1 C4 Q$ `2 f5 [
  3. printf("String: %s  ,强行再读一次: %#p\n", string);
    # h* C. b9 r$ t5 u: h! j$ f* c
  4. printf("String: %s  ,强行再读一次: %#s\n", string);
复制代码

* @1 o) N) X5 n1 N
输出如下:# Q  X5 F1 }+ b1 u) ~

  1.   u  [/ j. d( g
  2. String:Hello World!  , 强行再读一次: 0X001C1073
    2 Q# z; m- S8 s+ c5 p
  3. String: Hello World!  ,强行再读一次: 閮
复制代码
: W+ B8 _3 q. n& Q; o
嵌入式专栏
4
问题解释
问题1:printf("%f\n",a) 输出为什么是0.000000?
答:%f 提取8字节。a仅仅有4字节,提取出来的数占了float表示法的指数部分。尾数部分为0。所以终于是0. J6 O2 J% F0 N/ F" l- X
问题2:printf("%d\n",x)  输出为什么是0?答:%d 提取4字节,x有8字节。提取出来的数实际上是float表示法的指数部分(恰好是0),所以终于是0
8 F2 P) f# e' R- a$ U" l
问题3:printf("%f,%f\n",a,x); 输出都是0.000000 为什么?答:參照问题1的解释。提取了八字节后,后面的已经乱了
! s- s: \6 u7 E- O. y" ]* p
问题4:printf("%f,%f\n",x,a);调换一下a,x的顺序,正常了,为什么?答:这是正常的情况而已。
# l- {! L4 l  V: W$ F3 h) X; G' ]0 R( U  A
赞 收藏 1 评论0 发布时间:2020-12-3 22:14

举报

0个回答

所属标签

相似技术帖

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