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

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

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

: X, s/ ^/ E8 F5 r0 n9 y4 n& Q
下面就来举例我说说:

* N6 Y" s1 H2 Y$ U
嵌入式专栏
1
问题描述
打印输出的数据并不是理论值,如下图(右边):* O5 u3 P$ o! T; y
微信图片_20201203221139.png
* ~! K- H; w; @
嵌入式专栏
2
进一步描述问题
请细致注意看下面代码,有如以下奇怪的现象:

  1. 3 R' F4 i, s5 F( d0 [
  2. int a=5;
    , P7 b4 h0 B  X8 v5 L
  3. floatx=a;     //这里转换是没有问题的。%f打印x是 5.000000
    + l3 k& u( h- N) a6 v

  4. 0 o0 }. h# f2 ?" ]( O
  5. printf("%d\n",a);
    ) k9 s& B) G. l; _) a1 y$ _5 s. Y
  6. printf("%f\n",a);  //输出为什么是0.000000?-----问题1, j3 a8 x4 I7 q& w1 r1 Z8 H9 {. }
  7. printf("%f\n",x);: E! u. ~4 k& `, B9 Y
  8. printf("%d\n",x);  //输出为什么是0?-----问题2, L, i, y5 Z) H; q
  9. printf("%f,%f\n",a,x);  //输出都是0.000000  为什么?   ----问题3
    ! k" t( l, a2 h7 C
  10. printf("%f,%f\n",x,a);  //调换一下a,x的顺序,正常了,为什么?----问题4
    ' b% y0 z% C: s' t' H
  11. printf("%d,%f\n",a,x);! \. j+ H( [) m& ?: F
  12. * W( N+ S" ^5 L. @% w. g/ N
  13. getchar();
    * C6 Z0 ]6 b% v& ^; t8 t
  14. return0;
复制代码

% }% M9 }  X* g$ \& [2 e6 x
这里有四个问题,下面会进行解答。7 t/ n  T/ D0 w' m. e

& j& ?. J/ o! Q& Y
嵌入式专栏
3
printf()函数的原理解释明确这些问题首先须要明确printf()函数的工作原理。  P; ?! v4 y' _5 r# M( a2 \; s
printf()维持了一个需要打印的变量栈,默认情况下,參数进栈的顺序是由右向左的。因此,參数进栈以后的内存模型例如以下图所看到的: 微信图片_20201203221144.png ) Y% u1 J; j' _9 Y8 j
打印的时候,printf依照字符转换说明符规定的格式从低地址開始提取数据。直到參数打印完。
1 E2 m5 i4 Y" t' ?9 L( l
比方遇到 %f 说明符就提取8个字节的数据,遇到 %d 就提取4个字节。printf()事实上不知道參数的个数,它仅仅会依据format中的打印格式的数目依次打印堆栈中參数format后面地址的内容。
  B) B6 v5 O, m+ Y" A4 L8 o8 T! |
这样一来,printf()事实上存在安全隐患:它会强行读取内存的数据当作正常数据输出,没有边界检测(非常有可能产生堆溢出)。
8 t4 ]6 c4 q" R3 a( n' P; D
比如这种代码:
  1. 3 o# s3 q- {1 i8 l9 c( R* @! y
  2. char string[]="Hello World!";5 u4 [% a) d7 I! K* Z
  3. printf("String: %s  ,强行再读一次: %#p\n", string);
    8 h( c0 \$ n: B6 p& p* v" }
  4. printf("String: %s  ,强行再读一次: %#s\n", string);
复制代码
* F$ \% G! p# p3 X  a- g: m7 n+ g
输出如下:3 p( Q; h  R( p8 t. H# K+ }
  1. " O2 U& J8 ]1 }
  2. String:Hello World!  , 强行再读一次: 0X001C1073
    5 z* v5 f- G2 @4 w4 R
  3. String: Hello World!  ,强行再读一次: 閮
复制代码

& H! L1 ~- ^! G
嵌入式专栏
4
问题解释
问题1:printf("%f\n",a) 输出为什么是0.000000?
答:%f 提取8字节。a仅仅有4字节,提取出来的数占了float表示法的指数部分。尾数部分为0。所以终于是0& w- ]2 `0 T) \! ]
问题2:printf("%d\n",x)  输出为什么是0?答:%d 提取4字节,x有8字节。提取出来的数实际上是float表示法的指数部分(恰好是0),所以终于是0
$ Q' [+ _. Q. i! `. B' W/ l% k( l
问题3:printf("%f,%f\n",a,x); 输出都是0.000000 为什么?答:參照问题1的解释。提取了八字节后,后面的已经乱了7 Y+ M  s* ~* C0 B# y3 c
问题4:printf("%f,%f\n",x,a);调换一下a,x的顺序,正常了,为什么?答:这是正常的情况而已。
, s* k1 @7 Q# p5 z
7 {4 A) w, E/ |0 }* R: Q  G
收藏 1 评论0 发布时间:2020-12-3 22:14

举报

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