c - 可变修改类型的兼容性及其安全隐患

标签 c gcc c99 variable-length-array

我对 C99 的可变修改类型系统产生了浓厚的兴趣。这个问题的灵感来自 this one .

检查这个问题的代码,我发现了一些有趣的东西。考虑这段代码:

int myFunc(int, int, int, int[][100]);

int myFunc(int a, int b, int c, int d[][200]) {
    /* Some code here... */
}

这显然不会(也不会)编译。但是,这段代码:

int myFunc(int, int, int, int[][100]);

int myFunc(int a, int b, int c, int d[][c]) {
    /* Some code here... */
}

编译甚至没有警告(在 gcc 上)。

这似乎暗示可变修改的数组类型与任何非可变修改的数组类型兼容!

但这还不是全部。您希望可变修改类型至少会考虑使用哪个变量来设置其大小。但它似乎并没有这样做!

int myFunc(int, int b, int, int[][b]);

int myFunc(int a, int b, int c, int d[][c]) {
    return 0;
}

编译也没有任何错误。

所以,我的问题是:这是正确的标准化行为吗?

此外,如果可变修改的数组类型真的与任何具有相同维度的数组兼容,这是否意味着严重的安全问题?例如,考虑以下代码:

int myFunc(int a, int b, int c, int d[][c]) {
    printf("%d\n", sizeof(*d) / sizeof((*d)[0]));
    return 0;
}

int main(){
    int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    myFunc(0, 0, 100, &arr);

    return 0;
}

编译并输出 100,没有错误或警告,什么都没有。正如我所见,这意味着即使您通过 sizeof 严格检查数组的大小,也很容易越界写入数组,不执行单个转换,甚至已打开所有警告!还是我遗漏了什么?

最佳答案

C99,section 6.7.5.2 似乎是给出相关规则的地方。特别是,

第 6 行:

For two array types to be compatible, both shall have compatible element types, and if both size specifiers are present, and are integer constant expressions, then both size specifiers shall have the same constant value. If the two array types are used in a context which requires them to be compatible, it is undefined behavior if the two size specifiers evaluate to unequal values.

之前的一个现已删除的答案也引用了第 6 行。对该答案的评论认为第二句话受第一句末尾的条件的约束,但这似乎不太可能解读。该部分的示例 3 可能会阐明(摘录):

int c[n][n][6][m];
int (*r)[n][n][n+1];
r=c;   // compatible, but defined behavior only if
       // n == 6 and m == n+1

这似乎与问题中的示例相当:两种数组类型,一种具有常量维度,另一种具有相应的可变维度,并且需要兼容。当运行时变量维度与编译时常量维度不同时,行为未定义(根据示例 3 中的注释和 6.7.5.2/6 的合理阅读)。无论如何,未定义的行为不是您所期望的吗?否则为什么提出这个问题?

假设我们可以同意在发生这种不匹配时行为是未定义的,我观察到编译器通常不需要识别未定义或可能未定义的行为,也不需要发出任何类型的诊断(如果它们确实识别出此类行为)。在这种情况下,我希望编译器能够警告可能未定义的行为,但它必须成功编译代码,因为它在语法上是正确的并且满足所有适用的约束。请注意,能够针对此类使用发出警告的编译器可能不会默认这样做。

关于c - 可变修改类型的兼容性及其安全隐患,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28591113/

相关文章:

c - 空参数列表是什么意思?

c++ - 带回调的 ObjC/C/C++ 高分辨率计时器

c - 另一个字符串中的字符串标识符

c - 如何克服 "An array is allocated or declared with size zero"限制?

c++ - GNU const/纯属性与 constexpr

c++ - 将指针分配给带或不带限定符的指针

c++ - 是否可以在编译时将 gcc 编译标志检测为宏?

python - 为什么 GCC 忽略 Snow Leopard 中的 ARCHFLAGS?

整型常量表达式的说明

捕获 c bool 的错误用法