为缓冲区溢出错误(C/C+;+;)创建测试用例
如何在c中为缓冲区溢出创建一个单元测试用例,而缓冲区溢出不会导致诸如segfault之类的内存错误 即,给定一个简单的缓冲区溢出,例如为缓冲区溢出错误(C/C+;+;)创建测试用例,c,unit-testing,automated-tests,C,Unit Testing,Automated Tests,如何在c中为缓冲区溢出创建一个单元测试用例,而缓冲区溢出不会导致诸如segfault之类的内存错误 即,给定一个简单的缓冲区溢出,例如 int function () { int exampleArray[10]; exampleArray[10] = 5; return 0; } 如何为这段代码创建单元测试?显然有一个错误,我们正在写一个数组的末尾。但是,您可以在没有任何错误迹象的情况下运行这样的函数 注意:我需要能够为用户在运行时提供数组索引以及上述简化的情况创建测
int function () {
int exampleArray[10];
exampleArray[10] = 5;
return 0;
}
如何为这段代码创建单元测试?显然有一个错误,我们正在写一个数组的末尾。但是,您可以在没有任何错误迹象的情况下运行这样的函数
注意:我需要能够为用户在运行时提供数组索引以及上述简化的情况创建测试用例
在Java这样的托管语言中,代码将抛出一个可以捕获的异常(ArrayIndexOutOfBoundsException)。因此,创建测试用例非常简单(异常的try-catch块)
如何在c中创建这样的测试?C的任何单元测试框架都能处理这种情况吗
背景信息:我正在尝试自动生成测试用例。我知道错误在哪里,并且希望能够创建一个单元测试,以在这些错误上失败
但是,我根本不知道如何创建一个因缓冲区溢出错误而失败的测试用例,而缓冲区溢出错误不会使应用程序崩溃。您只能尝试检测对零以下和最后一个元素正上方索引的访问—类似于分配两个附加数组并用标记值填充它们,然后检查值
不过,在C语言中,您不能轻易地检测到所有缓冲区溢出。您的代码可以访问远远超出缓冲区边界的元素,例如,以静默方式损坏堆。或者在多线程程序中,一个线程可能会意外地覆盖另一个线程的堆栈。在C语言中,内存访问是不受限制的-如果地址映射到地址空间并且是可写的,您的程序就可以在那里写入,您很难检测到它。您没有指定平台,但是GNU C库有一个名为
\uMalloc\uHook
的变量,它是表单static void*my\uMalloc\uHook>上的函数指针(大小,常数为空*)
例如:(摘自)
使用它,您可以分配比所需更多的内存(您需要以某种方式跟踪)然后用一些预定义的标记值填充该空间,将指针以某种方式返回到该空间中。然后,当然,您必须在代码中的适当位置插入边界检查,这可能不是您想要的。希望这至少能提供一些想法。一种检查方法是在缓冲区前后分配额外的字节(如果您是我们的话)但很难跟踪每个变量。函数结束后,您可以检查这些缓冲区中的数据是否被修改。您必须创建一个单独的库来保存这些值 或者检查这个。希望它能给你更多关于测试缓冲区溢出的信息 编辑:更多信息:
void foo()
{
char buffer [5];
strcpy(buffer, "StackOverflow");
// Clearly overflow. Has to be found out in Code reviews or static analysis
}
如果你在英特尔上运行,你可以运行里面的代码。它有一个实验性的缓冲区溢出检测器,所以YMMV。我想不出一个简单的方法来检测C本身的缓冲区溢出,而不添加大量的cruft来放入和检测保护变量。正如已经指出的那样,捕获每个缓冲区溢出是很困难的。在我以前的专业版中ject编译器没有manneorama指出的选项。幸运的是,整个代码库从未直接调用malloc,每个malloc调用的代码准则(严格执行)都必须调用一个函数,默认情况下,该函数用于调用malloc(让我们将其命名为mymalloc) 因此,我们所做的是创建额外的缓冲区大小,比如说4个额外字节(在请求的内存之前2个,之后2个。用您希望代码不会写入的字节填充它们(这就是解决方案不合理的地方) 在顶部的头文件中定义宏:
#define mymalloc(X) testmalloc(X,__FILE__,__LINE__)
并定义一个函数testmalloc,如下所示:
void * testmalloc(size_t size, char *filename, int linenum)
{
void *buff = malloc(size + 4)
char *bytebuff = (char *) buff
//bookkeeping, keep record of buff
bytebuff[0] = 0xBA;
bytebuff[1] = 0xBA;
bytebuff[size+2] = 0xBA;
bytebuff[size+3] = 0xBA;
return bytebuff[2];
}
(此代码来自我的记忆,我没有实际的代码,因此可能会有小错误)
当你需要检查溢出时,只需编写一个例程,它会遍历所有这些缓冲区并检查字节。\uuuuuuuuu
和\uuuuuuuu行
预处理宏将跟踪程序中哪一行导致溢出
这并不能确保所有溢出都被捕获为:
- 程序可能会溢出完全相同的字节(此处为0xBA)
- 程序可能会保持保护字节不变,但溢出超出范围
此外,此机制仅限于堆分配的数组。您应该确保所有的缓冲区写入函数都有一个定义的缓冲区大小,无论是通过变量还是常量 例如,如果你有
void writeSomeString(char * buf, size_t len);
您可以按照如下方式测试缓冲区大小:
char testBuf[100];
memset(&testBuf, 42, sizeof(testBuf));
writeSomeString(&testBuf, sizeof(testBuf)-1);
assert(testBuf[sizeof(testBuf)-1] == 42);
您提供的代码不可进行单元测试。您需要控制需要测试的内容:参数和返回值 如果你真的想用C来说明其他语言的功能,想象一下函数的功能如下:
int setArrayInt(int *array, unsigned int arraySize, unsigned int index, int value)
{
if (index >= arraySize)
{
return -1; /* error */
}
array[index] = value;
return 0; /* success */
}
然后,您可以对该函数进行单元测试(cxxtest语法):
最后,您将使用此函数来操作数组,因为您已经验证了它是否能够正常工作
我并不是说你应该在你的C程序中创建这样的数组操作函数。要抓住你在示例中给出的那种错误,你肯定需要静态分析或代码插入工具。在你的示例中,测试局部变量分配只能用静态分析工具来完成
int setArrayInt(int *array, unsigned int arraySize, unsigned int index, int value)
{
if (index >= arraySize)
{
return -1; /* error */
}
array[index] = value;
return 0; /* success */
}
/* Function returning failure if accessing out of range index */
TS_ASSERT_EQUALS(-1, setArrrayInt(exampleArray, sizeof(exampleArray), 10, 123));
/* Function returning success if we stay inside its range */
TS_ASSERT_EQUALS(-1, setArrrayInt(exampleArray, sizeof(exampleArray), 9, 123));
/* Our array really gets modified if our call is successful */
TS_ASSERT_EQUALS(123, exampleArray[9]);
static union
{
MY_ARRAY fixed_array;
unsigned int dummy_array_overlay[sizeof(MY_ARRAY)+1];
} array_layout;
#define myarray array_layout.fixed_array
#define dummy_array_overlay array_layout.dummy_array_overlay
memset(&dummy_array_overlay, 0xFF, sizeof(dummy_array_overlay));
//Do your thing
ASSERT_EQUAL((unsigned int)0xFF, dummy_array_overlay[sizeof(MY_ARRAY)]);