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

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

[复制链接]
gaosmile 发布时间:2020-12-3 22:14
程序员都知道,也都会使用printf函数,但你知道它也有“安全隐患”吗?
5 r/ D- r9 m) Z  y
下面就来举例我说说:

$ y4 ]- C- L3 y3 N! d8 b3 |5 v
嵌入式专栏
1
问题描述
打印输出的数据并不是理论值,如下图(右边):
; W. j3 g5 B  q0 c9 V# [+ y$ {
微信图片_20201203221139.png
, @8 q  n- R2 E  C' g: `
嵌入式专栏
2
进一步描述问题
请细致注意看下面代码,有如以下奇怪的现象:

  1. ; N2 X3 P! z( |
  2. int a=5;
    & `+ F+ K% u. l% R" _
  3. floatx=a;     //这里转换是没有问题的。%f打印x是 5.000000
    7 H, }  M9 Z/ v* d* b- m- B

  4. 9 U0 I# ]2 i1 h- V" H
  5. printf("%d\n",a);0 E* ]* s- U& ~7 ]" p0 w% I
  6. printf("%f\n",a);  //输出为什么是0.000000?-----问题1
    ; j7 T3 c  z+ C8 |/ [8 a( a
  7. printf("%f\n",x);
    ; m( }+ q9 L7 |6 @9 [
  8. printf("%d\n",x);  //输出为什么是0?-----问题2
    % z. ]- a+ p, _' w+ \. ^
  9. printf("%f,%f\n",a,x);  //输出都是0.000000  为什么?   ----问题3
    $ Q1 L" z4 a6 o/ V6 n+ h0 l; m5 |
  10. printf("%f,%f\n",x,a);  //调换一下a,x的顺序,正常了,为什么?----问题4/ ^! i" H# [6 B! s" V2 ]
  11. printf("%d,%f\n",a,x);
    9 a! q/ h/ \6 s: U% t6 ]
  12. 4 A$ |: k- g3 ]3 [9 U7 [8 i
  13. getchar();
    5 z: Q) }" [+ z% w" f& ~
  14. return0;
复制代码

, e1 w; A% `  B; {8 V2 p" H
这里有四个问题,下面会进行解答。
9 y7 ~8 `7 P7 [1 c
$ a; P' P( P' V9 n
嵌入式专栏
3
printf()函数的原理解释明确这些问题首先须要明确printf()函数的工作原理。; ^! l+ M2 N& h3 G
printf()维持了一个需要打印的变量栈,默认情况下,參数进栈的顺序是由右向左的。因此,參数进栈以后的内存模型例如以下图所看到的: 微信图片_20201203221144.png 5 j6 h& M* k* _1 z
打印的时候,printf依照字符转换说明符规定的格式从低地址開始提取数据。直到參数打印完。
$ v& ^5 ~0 A& K
比方遇到 %f 说明符就提取8个字节的数据,遇到 %d 就提取4个字节。printf()事实上不知道參数的个数,它仅仅会依据format中的打印格式的数目依次打印堆栈中參数format后面地址的内容。7 f/ ?8 `" Q  w# _' D/ h6 Q$ g
这样一来,printf()事实上存在安全隐患:它会强行读取内存的数据当作正常数据输出,没有边界检测(非常有可能产生堆溢出)。
. G5 v& c4 h) @1 Y9 p( c1 _
比如这种代码:

  1. " {# l8 z- X- n" O! f: _9 o
  2. char string[]="Hello World!";
    : _" K5 I  \- s& u3 A
  3. printf("String: %s  ,强行再读一次: %#p\n", string);7 Y& u1 S$ K  G( z3 @
  4. printf("String: %s  ,强行再读一次: %#s\n", string);
复制代码

: ~: D/ T" f8 K+ Q: d0 ^8 {
输出如下:6 i. Q# j$ b3 s. a; v" ^

  1. 0 Y. d: @$ \- T5 C; Q, l
  2. String:Hello World!  , 强行再读一次: 0X001C1073
    ' }4 O+ K' A' {0 u) v# a" x  u
  3. String: Hello World!  ,强行再读一次: 閮
复制代码
, j- F! z: o/ Q
嵌入式专栏
4
问题解释
问题1:printf("%f\n",a) 输出为什么是0.000000?
答:%f 提取8字节。a仅仅有4字节,提取出来的数占了float表示法的指数部分。尾数部分为0。所以终于是0: f% w3 a' M8 N+ u, U/ ]! |( l$ S
问题2:printf("%d\n",x)  输出为什么是0?答:%d 提取4字节,x有8字节。提取出来的数实际上是float表示法的指数部分(恰好是0),所以终于是0# i. d( c( g% Q# T. h8 b
问题3:printf("%f,%f\n",a,x); 输出都是0.000000 为什么?答:參照问题1的解释。提取了八字节后,后面的已经乱了
5 ~1 {+ m0 G( b5 q
问题4:printf("%f,%f\n",x,a);调换一下a,x的顺序,正常了,为什么?答:这是正常的情况而已。
6 l) G. k1 x  f$ a# a1 b. C  k$ d% b9 d  N9 P
收藏 1 评论0 发布时间:2020-12-3 22:14

举报

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