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

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

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

1 U1 z! _7 T4 z. f
下面就来举例我说说:

/ V9 ~/ ^& P/ r; H+ G$ {
嵌入式专栏
1
问题描述
打印输出的数据并不是理论值,如下图(右边):$ c& `2 l5 Z  Q5 W
微信图片_20201203221139.png

# l* A: Y& c: r2 O! g! a' z
嵌入式专栏
2
进一步描述问题
请细致注意看下面代码,有如以下奇怪的现象:
  1. ( C# m8 p) p" y. u. s& B! S& Z
  2. int a=5;3 Y# Q# a: X' e* Z" o9 e
  3. floatx=a;     //这里转换是没有问题的。%f打印x是 5.000000
    - e  ?! E* f/ p* ?! i
  4. 2 a1 b* w8 l: B' h0 M0 @! Z
  5. printf("%d\n",a);
    # W# u& ~1 E) p6 v2 _; x
  6. printf("%f\n",a);  //输出为什么是0.000000?-----问题1
    * H5 R' b! ~" i) \
  7. printf("%f\n",x);
    3 n  _, z) S; l, O" h+ P: f$ D" A
  8. printf("%d\n",x);  //输出为什么是0?-----问题25 @* u- w& J  V# ]
  9. printf("%f,%f\n",a,x);  //输出都是0.000000  为什么?   ----问题3
    ) k0 V+ r, v( C" j+ h3 l# D7 Z
  10. printf("%f,%f\n",x,a);  //调换一下a,x的顺序,正常了,为什么?----问题4
    3 f1 L9 L( D& v5 U6 ?
  11. printf("%d,%f\n",a,x);
    # W, c  }% r- |  O
  12. 7 R' `, b9 t9 y% S: d
  13. getchar();
    ) A/ o: G4 k8 q( V* T
  14. return0;
复制代码

( z" f5 F( @+ M) Q8 W
这里有四个问题,下面会进行解答。: C2 `+ @9 v1 z/ s  |/ p
5 S7 X. M$ X1 D
嵌入式专栏
3
printf()函数的原理解释明确这些问题首先须要明确printf()函数的工作原理。$ ~5 e; @8 u6 X2 ?" L! x7 t
printf()维持了一个需要打印的变量栈,默认情况下,參数进栈的顺序是由右向左的。因此,參数进栈以后的内存模型例如以下图所看到的: 微信图片_20201203221144.png   D, C; Z: ]  Y6 K
打印的时候,printf依照字符转换说明符规定的格式从低地址開始提取数据。直到參数打印完。% N! Y' _7 e7 j  C0 h
比方遇到 %f 说明符就提取8个字节的数据,遇到 %d 就提取4个字节。printf()事实上不知道參数的个数,它仅仅会依据format中的打印格式的数目依次打印堆栈中參数format后面地址的内容。
- D7 C( U+ l0 O; S
这样一来,printf()事实上存在安全隐患:它会强行读取内存的数据当作正常数据输出,没有边界检测(非常有可能产生堆溢出)。" Q: v' j8 \* c3 i  c+ H
比如这种代码:
  1. 4 ^/ q& n- _* @
  2. char string[]="Hello World!";+ X) }6 f  f3 |8 L8 i: Q' D" L
  3. printf("String: %s  ,强行再读一次: %#p\n", string);% R  |7 z+ V3 d2 J
  4. printf("String: %s  ,强行再读一次: %#s\n", string);
复制代码

0 K9 g  e( d. J8 X5 k2 @
输出如下:, {! c. p$ ]- g$ L0 B
  1. ' F+ p. I. v  v- k% v& }
  2. String:Hello World!  , 强行再读一次: 0X001C1073
    0 n6 w+ t9 r; o- W2 ]
  3. String: Hello World!  ,强行再读一次: 閮
复制代码

& j9 P# f" V6 F5 |
嵌入式专栏
4
问题解释
问题1:printf("%f\n",a) 输出为什么是0.000000?
答:%f 提取8字节。a仅仅有4字节,提取出来的数占了float表示法的指数部分。尾数部分为0。所以终于是0  E9 V. |1 H" d" @- P) a8 @7 @
问题2:printf("%d\n",x)  输出为什么是0?答:%d 提取4字节,x有8字节。提取出来的数实际上是float表示法的指数部分(恰好是0),所以终于是02 m% m' n, \  O4 |1 c' n
问题3:printf("%f,%f\n",a,x); 输出都是0.000000 为什么?答:參照问题1的解释。提取了八字节后,后面的已经乱了+ H( y3 v  o  [5 L( d; }5 b
问题4:printf("%f,%f\n",x,a);调换一下a,x的顺序,正常了,为什么?答:这是正常的情况而已。  _, l" N- j& Y4 T% u* P
% u- z4 ]& P* q# |" t( r
收藏 1 评论0 发布时间:2020-12-3 22:14

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版