我有一个非常简单的C程序,使用slow = slow.next
可能导致缓冲区溢出:
strcpy
clang静态分析器(使用#include <string.h>
#include <stdio.h>
void buffer_overflow(char* dst, const char* src)
{
strcpy(dst, src);
}
int main(int argc, char** argv)
{
if(argc == 2)
{
char buffer[16] = {0};
buffer_overflow(buffer, argv[1]);
printf("[%d]: %s", (int)strlen(buffer), buffer);
}
return 0;
}
)和cppcheck(使用scan-build gcc -O0 -g3 -gdwarf-2
)都没有发现这个问题。
我对静态分析工具的要求是否过多?
答案 0 :(得分:1)
我不能说“您的”静态分析工具的质量。
这是我公司的动态分析工具CheckPointer,它发现您的代码有问题(我测试为“ buggy.c”):
C:\DMS\Domains\C\GCC4\Tools\CheckPointer\Example>runexample
RunExample.cmd 1.2: Batch file to execute C CheckPointer example
Copyright (C) 2011-2016 Semantic Designs; All Rights Reserved
c:\DMS\Domains\C\GCC4\Tools\CheckPointer\Example\Source\buggy.c
*** Instrument source code for memory access checking
Copyright (C) 2011 Semantic Designs; All Rights Reserved
C~GCC4 CheckPointer Version 1.2.1001
Copyright (C) 2011-2016 Semantic Designs, Inc; All Rights Reserved; SD Confidential
Powered by DMS (R) Software Reengineering Toolkit
*** Unregistered CheckPointer Version 1.2
*** Operating with evaluation limits.
Parsing source file "C:/Users/idbaxter/AppData/Local/Temp/DMS/Domains/C/GCC4/Tools/CheckPointer/Example/Source/buggy.c" using encoding CP-1252 +CRLF $^J $^M $^e -1 +8 ...
Writing target file "C:/Users/idbaxter/AppData/Local/Temp/DMS/Domains/C/GCC4/Tools/CheckPointer/Example/Target/buggy.c" using encoding CP-1252 +CRLF $^J $^M $^e -1 +8 ...
*** Compiling sources with memory access checking code
gcc.exe -I"c:\DMS\Domains\C\GCC4\Tools\CheckPointer" -I.\Target -obuggy.exe Target\buggy.c ...
C:\DMS\Domains\C\GCC4\Tools\CheckPointer\Example\Source>C:/Users/idbaxter/AppData/Local/Temp/DMS/Domains/C/GCC4/Tools/CheckPointer/Example\buggy.exe foo
[3]: foo
C:\DMS\Domains\C\GCC4\Tools\CheckPointer\Example\Source>C:/Users/idbaxter/AppData/Local/Temp/DMS/Domains/C/GCC4/Tools/CheckPointer/Example\buggy.exe 0123456789ABCDE
[15]: 0123456789ABCDE
C:\DMS\Domains\C\GCC4\Tools\CheckPointer\Example\Source>C:/Users/idbaxter/AppData/Local/Temp/DMS/Domains/C/GCC4/Tools/CheckPointer/Example\buggy.exe 0123456789ABCDEF
*** Error: CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer
Dereference of pointer is out of bounds.
in wrapper function: strcpy
called in function: buffer_overflow, line: 6, file: C:/Users/idbaxter/AppData/Local/Temp/DMS/Domains/C/GCC4/Tools/CheckPointer/Example/Source/buggy.c
called in function: main, line: 14, file: C:/Users/idbaxter/AppData/Local/Temp/DMS/Domains/C/GCC4/Tools/CheckPointer/Example/Source/buggy.c
*** Error: CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer
Dereference of pointer is out of bounds.
in wrapper function: strlen
called in function: main, line: 15, file: C:/Users/idbaxter/AppData/Local/Temp/DMS/Domains/C/GCC4/Tools/CheckPointer/Example/Source/buggy.c
*** Error: CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer
Dereference of pointer is out of bounds.
in wrapper function: printf
called in function: main, line: 15, file: C:/Users/idbaxter/AppData/Local/Temp/DMS/Domains/C/GCC4/Tools/CheckPointer/Example/Source/buggy.c
[16]: 0123456789ABCDEF
C:\DMS\Domains\C\GCC4\Tools\CheckPointer\Example\Source>
答案 1 :(得分:0)
这是一个开放性很强的问题,没有正确的答案。但是作为从事过多个静态分析仪工作的人,我会咬一口并简要解释一下此示例的难点。
您和我都知道argv[1]
可以是任意长的字符串。 (在某种程度上,知识是从堆栈溢出问题的上下文中得出的,该问题通常在没有任何上下文或先验假设的情况下给出代码。)但是,如果静态分析器报告了每个strcpy
,其中源字符串是(通过静态分析器不知道!)具有有限的长度,实际上它会报告大多数开发人员会认为误报(FP)的大量信息:他们不想看到的错误报告。
这是因为在很多情况下正确使用strcpy
,但是正确的原因超出了分析器的推理能力,甚至可能根本不在源代码中出现(例如,“程序X仅由程序Y调用,而程序Y永远不会传递长度超过80个字符的参数”)。相比之下,strcpy
调用中只有很小一部分(带有分析器无法绑定的参数)是错误的。慷慨地说,其中有10%是错的-如果我们全部报告,那仍然是90%的FP率,远远超出了大多数开发人员所能容忍的范围。
当工具报告过多的FP时,大多数开发人员会迅速停止使用它们,这时该工具将提供没有价值。因此,至少在默认情况下,大多数静态分析都会选择将报告的内容限制在该工具相当有信心的情况下。
即使对于想要报告此问题的工具(正如您所说的Cppcheck所做的那样,当strcpy
直接位于main
中时),第二个问题是了解buffer_overflow
的作用。对于静态分析器而言,仅简单地将被调用者的内容任意深入地“内联”到调用者中是不切实际的,因为由此产生的AST将会非常庞大,并且路径数量是天文数字。因此,分析人员通常会总结被调用者的行为。这些摘要的确切形式以及计算这些摘要的算法,是积极的学术研究和严密保护的商业秘密的主题。
strcpy
的行为实际上与典型函数摘要可以表达的行为相当复杂。涉及一个大小,但是该大小是通过检查指针之一所指向的数据的内容得出的,特别是第一个NUL字节的位置。然后,该大小会影响两个参数指向的事物发生了什么。以一般和可扩展的方式在摘要中进行编码有很多,所以大多数工具都没有。结果,该工具对buffer_overflow
所做的事情只有很粗略的了解,通常过于粗糙,以至于无法自信地在此处报告缺陷。