4

考虑以下程序:

struct abc
{
    int x[5];
    int y[5];
};

int main()
{
    struct abc test;
    test.y[0] = 10;
    printf("%d", test.x[5]);
}

(借自Is it legal to overrun a struct of a element to view another?

BoundsChecker不会将此检测为溢出。是否有任何程序可以检测到这种类型的编程错误?

4

2 回答 2

6

clang确实如此,即使没有打开特殊标志:

$ clang example.c -o example
example.c:13:18: warning: array index of '5' indexes past the end of an array
      (that contains 5 elements) [-Warray-bounds]
    printf("%d", test.x[5]);
                 ^      ~
example.c:5:5: note: array 'x' declared here
    int x[5];
    ^
1 warning generated.

编译为 C++ 时会打印相同的警告。

于 2011-12-13T23:45:49.623 回答
2

我们在这里看到的是关于 BoundsChecker 的一个令人讨厌的、鲜为人知的秘密:它根本无法让您看到结构成员。如果将数组声明为结构的一部分,无论该结构是自动分配还是动态分配,BoundsChecker 都会将该结构视为一个 blob。如果超出该结构的边界,它将报告问题。否则,没有。

也就是说,几年前我们编写了一些代码,这些代码目前随产品一起提供,并且可以使用隐藏的配置选项来调用。如果您要手动将该行EnableStructureMemberEnumeration=1插入[BC MemoryTracker]项目配置文件 ( .dpbcd) 的部分,那么您会发现产品可以看到结构的成员(主要是结构和数组),只要该结构是自动分配的(在堆)。

不过,这个选项还没有完全准备好迎接黄金时段。它具有非常复杂的类和结构的问题,例如在 STL 中发现的。此外,在上面给出的具体测试用例中,还有另一个问题。它通常无法区分开始结构/类的数组和类对象本身。两者在内存中具有相同的地址。但是考虑一下这段代码:

struct _Type {
  int Array[5];
} Objects[10];

struct _Type *pObject = &Objects[5];
int *pInt = &Objects[0].Array[5];

在这两种情况下,我们看到相同的地址,第一次的偏移量为 100,第二次的偏移量为 20。第一次,如果根据 评估Array,则无效,但如果根据 评估Objects,则有效。什么是糟糕的程序?

哦,还有一件事:BoundsChecker 通常会忽略对数组末尾之后的第一个元素的访问。这是因为存在大量代码,其中迭代器只会在最后一个元素。这是错误错误的巨大来源,因此有人将其更改为仅在溢出到达下一个位置(及更远位置)时才抱怨。这里的问题是,你增加了迭代器,但你真的要使用它吗?

因此,目前,问题的答案是 BoundsChecker 确实支持这种检查,但并非没有使用未记录的“功能”,也不是没有问题。

于 2011-12-14T15:51:57.343 回答