2

是否有可以标记以下错误的动态检查实用程序?瓦尔格林不能。可以净化或保险++吗?这是在 Linux Ubuntu 最新版本上。

struct A {
    char buff1[8];
    int jj;
    char buff2[8];
    int ii;
    char buff3[8];
} a;

main(int argc, char *args[])
{
    // Set intermediate fields to known flag value
    a.ii = a.jj = 0xdeadbeef;

    // Write 8 char string into 8 byte buffer - null will overflow into neighboring int field. ERROR
    sprintf(a.buff2, "ABCDEFGH");
}
4

4 回答 4

2

据我所知不是。大多数(或更确切地说:全部?)内存验证工具的工作方式是将读写保护页面嵌入变量之间和变量周围的保护区,以便在合法分配区域之外的访问中引发陷阱。

如果不严重干扰结构对齐和完整性,这在结构中间是不容易做到的。

编辑:另一点是:在某些结构中,重写结构成员边界是完全合法的,并且是实现您想要的唯一合理的可能性。一个例子是将结构复制到堆中:

struct x orig, *copy;

orig.a = 100;
strcpy (orig.str, "Test");

copy = malloc (sizeof (struct x));
memcpy (copy, &orig, sizeof (struct x));

这也超出了结构成员的范围,但是将结构放到堆上的唯一合理(并且完全合法)的方式(除了繁琐且缓慢的成员复制)。

另一个例子是

p = malloc (NUM_STRUCTS * sizeof (struct x));
memset (p, NUM_STRUCTS * sizeof (struct x), 0);

这是一个完全有效的构造,它允许您清除堆上的结构数组 - 它甚至不跨越内部结构边界,但也在结构之间

从某种意义上说,甚至calloc()都会超出结构成员的界限......

而且,作为(诚然较旧的)Purify 用户手册的明确答案,我碰巧在我的一个办公桌抽屉中找到:

仅当访问超出整个结构时,Purify 才会检测 C 结构中的数组中的数组边界错误

这对我来说算作“不”。

于 2016-03-14T21:47:43.423 回答
1

它必须是动态工具吗?我所知道的能够检测到上述情况的唯一工具是 Coverity,它是 Synopsis 的一个静态工具。对于上述情况,它将生成以下形式的报告:

Error: OVERRUN:
...
sprintf_overrun: "sprintf" will overrun its first argument "a.buff2" which can accommodate 8 bytes.  The number of bytes written may be 9 bytes, including the terminating null.
于 2016-04-02T19:31:32.700 回答
-1

在启用所有警告的情况下进行编译是一个好的开始:

chqrlie@mac ~/dev/stackoverflow > clang -O3 -std=c11 -Weverything -lm -o 35996676 35996676.c
35996676.c:9:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
main(int argc, char *args[])
^
35996676.c:12:19: warning: implicit conversion changes signedness: 'unsigned int' to 'int' [-Wsign-conversi
    a.ii = a.jj = 0xdeadbeef;
                ~ ^~~~~~~~~~
35996676.c:15:5: warning: implicitly declaring library function 'sprintf' with type 'int (char *, const cha
    sprintf(a.buff2, "ABCDEFGH");
    ^
35996676.c:15:5: note: include the header <stdio.h> or explicitly provide a declaration for 'sprintf'
35996676.c:9:10: warning: unused parameter 'argc' [-Wunused-parameter]
main(int argc, char *args[])
         ^
35996676.c:9:22: warning: unused parameter 'args' [-Wunused-parameter]
main(int argc, char *args[])
                     ^
35996676.c:7:3: warning: no previous extern declaration for non-static variable 'a' [-Wmissing-variable-dec
} a;
  ^
6 warnings generated.

用简单的补丁修复这些,并添加额外的明显错误:

#include <stdio.h>
#include <string.h>

static struct A {
    char buff1[8];
    unsigned int jj;
    char buff2[8];
    unsigned int ii;
    char buff3[8];
} a;

int main(void) {
    // Set intermediate fields to known flag value
    a.ii = a.jj = 0xdeadbeef;

    // Write 8 char string into 8 byte buffer - null will overflow into neighboring int field. ERROR
    sprintf(a.buff1, "ABCDEFGH");
    strcpy(a.buff2, "ABCDEFGH");
    sprintf(a.buff3, "%s", "ABCDEFGH");

    return 0;
}

编译时没有任何警告,尽管存在简单的静态分析应该捕获的明显sprintf和错误。strcpy

gccwith-Wall -W -Wextra也没有发现任何问题。

建议使用snprintf代替sprintf,但这不会阻止strcpy问题。strcpy在一般情况下是不安全的,但是以字符串文字作为源,编译器肯定应该抱怨。

您应该尝试 Frama-c,这是一个强大的源代码分析框架,可从http://frama-c.com/获得开源

于 2016-03-15T15:27:57.630 回答
-2

根据我的经验,Purify 可能会做你想做的事。这是发布在互联网上的旧版 Purify 用户手册的摘录:

Purify 如何检查静态分配的内存

除了检测动态内存中的访问错误外,Purify 还检测全局变量和静态变量中数据边界之外的引用,即在链接时静态分配的数据,而不是在运行时动态分配的数据。

以下是静态检查功能处理的数据示例:

int array[10];
main() {
    array[11] = 1;
}

在此示例中,Purify 在分配到时报告 ABW 错误, array[11]因为它超出数组末尾 4 个字节。

于 2016-03-17T10:58:37.290 回答