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

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

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

6 `* r1 ~3 E( V6 C8 I( u
下面就来举例我说说:

1 K* l: w1 r. I0 A) w7 Z6 Q+ {" I
嵌入式专栏
1
问题描述
打印输出的数据并不是理论值,如下图(右边):
4 t4 C0 v$ x7 T: U- k
微信图片_20201203221139.png
6 u' L' j! [1 Z! ]; l
嵌入式专栏
2
进一步描述问题
请细致注意看下面代码,有如以下奇怪的现象:
  1. 0 b7 F' b; B5 N
  2. int a=5;8 H4 \5 n6 l; |0 Y" n( G: I+ `- N
  3. floatx=a;     //这里转换是没有问题的。%f打印x是 5.0000005 A, m* ~* U$ T% Y2 O7 d; D5 S: N
  4. 4 j* T. X( s$ ?0 k9 m: _
  5. printf("%d\n",a);
    9 G! M* ~& _' ^6 f! I! ^
  6. printf("%f\n",a);  //输出为什么是0.000000?-----问题1$ Y6 W& z3 w. c0 c4 ~( w. b1 i9 X
  7. printf("%f\n",x);* A2 {. C( X" i* `7 O
  8. printf("%d\n",x);  //输出为什么是0?-----问题2$ I- }3 P4 _& C% }- E" j* z
  9. printf("%f,%f\n",a,x);  //输出都是0.000000  为什么?   ----问题3
    2 w1 y3 Q- x8 Y9 j7 |! w
  10. printf("%f,%f\n",x,a);  //调换一下a,x的顺序,正常了,为什么?----问题40 r8 T% J; S" X6 u; O' W$ V
  11. printf("%d,%f\n",a,x);" ?0 G. Y3 H  h, x; T$ T* F
  12. ; G: _8 w( K& Q* o! F+ ~$ L/ @
  13. getchar();9 o, J9 E/ |; [3 Q4 R" d+ F( b
  14. return0;
复制代码
+ i# _( t% G& M/ e# T" L! \7 d
这里有四个问题,下面会进行解答。
! \4 P  X8 x# j; h0 x/ l$ ~

. y: R6 s1 X, o  X$ b4 x
嵌入式专栏
3
printf()函数的原理解释明确这些问题首先须要明确printf()函数的工作原理。
# D: r9 n  i0 @2 ]7 b& u, r8 `3 m3 b
printf()维持了一个需要打印的变量栈,默认情况下,參数进栈的顺序是由右向左的。因此,參数进栈以后的内存模型例如以下图所看到的: 微信图片_20201203221144.png   Y  r0 c, {: O( |& b- B9 ~5 v
打印的时候,printf依照字符转换说明符规定的格式从低地址開始提取数据。直到參数打印完。1 T% q8 d: `5 n7 W! R3 ?
比方遇到 %f 说明符就提取8个字节的数据,遇到 %d 就提取4个字节。printf()事实上不知道參数的个数,它仅仅会依据format中的打印格式的数目依次打印堆栈中參数format后面地址的内容。# L8 o& e4 U. @3 m
这样一来,printf()事实上存在安全隐患:它会强行读取内存的数据当作正常数据输出,没有边界检测(非常有可能产生堆溢出)。
( C7 t" N8 a8 E/ r4 F+ x$ v3 o: u& w
比如这种代码:
  1. 1 f* p- A3 c2 G5 P/ t, i- B
  2. char string[]="Hello World!";
    9 v4 O9 ?/ Z% n& c
  3. printf("String: %s  ,强行再读一次: %#p\n", string);
    ; \! ]* X" {( D2 v% y1 i, }9 w
  4. printf("String: %s  ,强行再读一次: %#s\n", string);
复制代码
  J$ C1 Y+ b- U4 t
输出如下:# T  b7 Z% c' E5 {

  1. 7 k5 k1 [) _9 a3 B
  2. String:Hello World!  , 强行再读一次: 0X001C1073 " J) L( n- y' O) C- W# ]
  3. String: Hello World!  ,强行再读一次: 閮
复制代码
2 V9 h' U% A$ B& i9 t6 M
嵌入式专栏
4
问题解释
问题1:printf("%f\n",a) 输出为什么是0.000000?
答:%f 提取8字节。a仅仅有4字节,提取出来的数占了float表示法的指数部分。尾数部分为0。所以终于是00 X1 V7 q" T/ r3 g. K- l6 P
问题2:printf("%d\n",x)  输出为什么是0?答:%d 提取4字节,x有8字节。提取出来的数实际上是float表示法的指数部分(恰好是0),所以终于是0
4 J! ]0 f: k" X8 t6 U6 |3 ?
问题3:printf("%f,%f\n",a,x); 输出都是0.000000 为什么?答:參照问题1的解释。提取了八字节后,后面的已经乱了
& \- ?0 e4 E- F9 B
问题4:printf("%f,%f\n",x,a);调换一下a,x的顺序,正常了,为什么?答:这是正常的情况而已。
+ V1 d; F  x  \& I9 l# q. r! p- x8 j9 _+ t3 b8 B5 j
收藏 1 评论0 发布时间:2020-12-3 22:14

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版