为什么不让C编译器有一个选项(我说一个选项,有些情况下你不想这样做)来转换这样的代码:
char a1[8];
int main( int argc, char *argv[] )
{
char a2[16];
char *p = (char *)malloc( 24 );
int argv1_len = strlen( argv[1] );
memcpy( a1, argv[1], argv1_len );
memcpy( a2, argv[1], argv1_len );
memcpy( p, argv[1], argv1_len );
return 0;
}
进入这个:
char a1[8];
addAddr( a1, sizeof( a1 ) ); // build database of addresses and their lengths
int main( int argc, char *argv[] )
{
char a2[16];
addAddr( a2, sizeof( a2 ) );
char *p = (char *)malloc( 24 );
int argv1_len = strlen( argv[1] );
addAddr( p, 24 );
ptrCheck( a1, argv1_len ); // exit if argv1_len > size of a1
memcpy( a1, argv[1], argv1_len );
ptrCheck( a2, argv1_len );
memcpy( a2, argv[1], argv1_len );
ptrCheck( p, argv1_len );
memcpy( p, argv[1], argv1_len );
ptrCheck( p+5, argv1_len );
memcpy( p+5, argv[1], argv1_len );
return 0;
}
C编译器是否有足够的关于本地和全局的内存布局的信息,它可以构建一个内存位置数据库,无论是在编译时还是在运行时放入代码,以及它们的长度和开启时间任何对strcpy,memcpy,memset等的调用,甚至是执行* ch1 = * ch2之类的赋值的代码;它可以检查内存并确保它在界限内?我假设会出现这样的情况:这不会引起性能损失,可以通过完全打开或关闭此功能,甚至可能通过代码行或部分重新编译来处理。这有点像valgrind,但更好,并且使用编译器的帮助,而不是仅仅依赖于二进制文件而只检查堆。
甚至可以让开发人员使用checkPtr API,这样我就可以编写自己的strcpy:
char *mystrcpy( char *dst, const char *src )
{
if ( checkPtr( dst, strlen( src ) ) )
{ /* do something custom */ }
return strcpy( dst, src );
}
答案 0 :(得分:2)
相对较新版本的编译器可以选择在某种程度上启用此类检查。
例如,here是clang的地址清理程序的文档。
您可以通过使用-fsanitize=address
(gcc和clang)进行编译来启用它们。
Clang(我也相信新版本的gcc)还包括未定义行为(-fsanitize=undefined
),未初始化读取(-fsanitize=memory
)和数据竞赛(-fsanitize=thread
)的清理程序。
答案 1 :(得分:2)
在嵌入式领域,编译器和工具链通常存在执行各种非标准检查的选项:NULL指针解引用,缓冲区溢出等。正如您可能猜到的,这些功能在计算上非常昂贵(对时序和性能产生负面影响) ,诱导膨胀,增加编译时间,以及其他可能不受欢迎的影响。出于这些原因,我已经看到了这些"安全"编译选项仅在开发/调试期间启用(非常类似于应用静态源代码检查器)。我很少看到已发布的代码已启用此功能。
由于我已经提到过静态源代码分析器,我建议您先看看Coverity,Code Sonar等。根据我的经验,这些工具在检测不安全代码方面比通常配备此类检查器的编译器做得更好。