使用printf函数的安全隐患

电子说

1.3w人已加入

描述

程序员都知道,也都会使用printf函数,但你知道它也有“安全隐患”吗?

  下面就来举例我说说:

  1问题描述

  打印输出的数据并不是理论值,如下图(右边):

Printf

  2进一步描述问题

  请细致注意看下面代码,有如以下奇怪的现象:

 

int a=5;floatx=a;     //这里转换是没有问题的。%f打印x是 5.000000
printf("%d
",a);printf("%f
",a);  //输出为什么是0.000000?-----问题1printf("%f
",x);printf("%d
",x);  //输出为什么是0?-----问题2printf("%f,%f
",a,x);  //输出都是0.000000  为什么?   ----问题3printf("%f,%f
",x,a);  //调换一下a,x的顺序,正常了,为什么?----问题4printf("%d,%f
",a,x);
getchar();return0;
 

 

  这里有四个问题,下面会进行解答。

  3printf()函数的原理解释

  明确这些问题首先须要明确printf()函数的工作原理。

  printf()维持了一个需要打印的变量栈,默认情况下,參数进栈的顺序是由右向左的。因此,參数进栈以后的内存模型例如以下图所看到的:

Printf

  打印的时候,printf依照字符转换说明符规定的格式从低地址開始提取数据。直到參数打印完。

  比方遇到 %f 说明符就提取8个字节的数据,遇到 %d 就提取4个字节。printf()事实上不知道參数的个数,它仅仅会依据format中的打印格式的数目依次打印堆栈中參数format后面地址的内容。

  这样一来,printf()事实上存在安全隐患:它会强行读取内存的数据当作正常数据输出,没有边界检测(非常有可能产生堆溢出)。

  比如这种代码:

 

char string[]="Hello World!";printf("String: %s  ,强行再读一次: %#p
", string);printf("String: %s  ,强行再读一次: %#s
", string);
 输出如下:

 

 

String:Hello World!  , 强行再读一次: 0X001C1073 
String: Hello World!  ,强行再读一次: 閮
 

 

  4问题解释

  问题1:printf("%f ",a) 输出为什么是0.000000?

  答:%f 提取8字节。a仅仅有4字节,提取出来的数占了float表示法的指数部分。尾数部分为0。所以终于是0

  问题2:printf("%d ",x) 输出为什么是0?

  答:%d 提取4字节,x有8字节。提取出来的数实际上是float表示法的指数部分(恰好是0),所以终于是0

  问题3:printf("%f,%f ",a,x); 输出都是0.000000 为什么?

  答:參照问题1的解释。提取了八字节后,后面的已经乱了

  问题4:printf("%f,%f ",x,a);调换一下a,x的顺序,正常了,为什么?

  答:这是正常的情况而已。

 审核编辑:汤梓红

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分