sprintf做字符串拼接的问题分析

调试之前写的一段代码,其中使用sprintf做字符串拼接:

sprintf(sql, "select * from TEST_TABLE");

......

sprintf(sql, "%s%s", sql, " where (RELY_TYPE='S')");

 

使用auto tools生成Makfile,编译,运行出错:执行完第二句sprintf后sql=“ where (RELY_TYPE='S')”而非预料中的“select * from TEST_TABLE where (RELY_TYPE='S')”

 

问题分析:

1》

automake生成的gcc编译命令为:

gcc -DHAVE_CONFIG_H -I. -I. -I../src/include   -g -fmessage-length=0 -D_FORTIFY_SOURCE=2 -Wall -g -O2 -MT sprintf_test -MD -MP -MF  -c -o sprintf_test sprintf_test.c

 

将该命令简化为:

gcc -D_FORTIFY_SOURCE=2 -g -O2  -o sprintf_test sprintf_test.c

后问题依旧,但是去掉选项 gcc -D_FORTIFY_SOURCE=2 或 -O 2后编译,运行结果sql=“select * from TEST_TABLE where (RELY_TYPE='S')”

 

2》

对比分析不同选项情况下gcc编译出的汇编代码:

 

gcc -D_FORTIFY_SOURCE=2 -g -O2  -o sprintf_test sprintf_test.c

汇编代码中sprintf被编译成__sprintf_chk函数调用,由于__sprintf_chk

 

gcc  -g -O2  -o sprintf_test sprintf_test.c 或 gcc -D_FORTIFY_SOURCE=2 -g -o sprintf_test sprintf_test.c

汇编代码中sprintf被编译成sprintf函数调用

 

__sprintf_chk和sprintf的实现差异导致了上述问题的出现,__sprintf_chk的描述如下:

The interface __sprintf_chk() shall function in the same way as the interface sprintf(), except that __sprintf_chk() shall check for stack overflow before computing a result, depending on the value of the flag parameter. If an overflow is anticipated, the function shall abort and the program calling it shall exit.

The __sprintf_chk() function is not in the source standard; it is only in the binary standard.

 

3》

-D_FORTIFY_SOURCE=2 和-O2一起使用会导致编译器使用做内存边界检验等“安全”的方式实现,从而采用了__sprintf_chk函数调用:

-D_FORTIFY_SOURCE=2 First enabled in Ubuntu 8.10. Provides compile-time best-practices errors for certain libc functions, and provides run-time checks of buffer lengths and memory regions. Only activated when compiled with -O2 or higher. Most problems are related to common unsafe uses of certain libc functions.

 

结论:

sprintf实现字符串拼接,尤其是本例中自身拼接,是不安全的实现,建议使用strcat或strncat实现。

 

 

你可能感兴趣的:(永远的linux)