堆溢出还是缓冲区溢出?

Tso*_*nos 0 c

这段代码在 memset 上写了一个额外的字符,但为什么呢?

int main(int argc, char ?argv[]) {

    char ?a, ?b;
    a=(char ?)malloc(12);
    b=(char ?)malloc(12);

    if(!a || !b)
        err(2, "malloc error.\\n");

    bzero(a, 12); bzero(b, 12);
    printf("%x %x (%i)\n", a, b, b?a); // b?a is d.
    memset(a, (int)'a', 11);
    memset(b, (int)'b', 11);
    printf("a: %s\n", a);
    printf("b: %s\n", b);
    printf("???\n");
    memset(a, (int)'a', b?a); // Heap?Overflow? Is this happening here ?
    printf("a: %s\n", a);

    free(a);
    free(b);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

脆弱性?如果这是密码,每次打印后都会有一个额外的字符?

Lun*_*din 6

您不能对指向不同数组的指针使用指针算法。a并且b是两个不同的数组。

C17 6.5.6 强调我的:

如果指针操作数和结果都指向同一个数组对象的元素,或者是数组对象最后一个元素之后的元素,则求值不会产生溢出;否则,行为是 undefined

因此b-a没有明确的结果。它可以是任何东西。因此memset(... , b-a);调用未定义的行为并可能写出数组的边界。或者编译器可以b-a用零替换 。

此外,绝不保证ab在内存中相邻分配。动态分配函数的堆管理器部分可以在任何地方添加大小字节和填充字节。堆可能会被分段并强制在完全不同的地方进行分配。或者b可以在比 低的地址分配a,因为不要求堆使用向上计数分配。(例如,大多数堆栈使用递减计数。)

所以是的,这是非常脆弱的,因为整个程序充满了错误,并且可能在任何时候崩溃。“堆溢出”,如果存在这样的术语,宁愿指代正在使用的堆的所有内存,而这不是这里发生的事情。