该缓冲区如何溢出?

Ale*_*Row 14 c malloc buffer-overflow

对于这个问题的标题,我事先表示歉意,但是似乎没有比这更好的了。

这里的想法是argv在另一个变量中复制,本质上是复制它。因此,函数功能的基本思想是,malloc()用于为副本请求一些空间,然后遍历argv每个元素的副本进行迭代。

这是我正在使用的代码,开发环境现在是Visual Studio 2019(即使严格来讲不是C编译器...):

// Returns a copy of an array of strings (intended for argv, but should work with any of them):
wchar_t** copyArgv(size_t argc, wchar_t* argv[]) {
    // Allocate space for the array of arguments:
    wchar_t** argsCopy = malloc(((argc + 1) * sizeof(wchar_t*)));
    if (!argsCopy)
        return NULL;
    // Copy each one of them:
    for (size_t i = 0; i < argc; i++) {
        argsCopy[i] = _wcsdup(argv[i]);
        if (!argsCopy[i]) {
            // Should also free any previous copied string I left that part out in the paste.
            free(argsCopy);
            return NULL;
        }
    }
    argsCopy[argc] = NULL;
    return argsCopy;
}
Run Code Online (Sandbox Code Playgroud)

我一直在尝试不同的方法来复制argv,但是每一个方法都让VS相信当我复制参数(行argsCopy[i] = _wcsdup(argv[i]);:)或在下一行中读取无效数据时,缓冲区可能会溢出,表示读取预留空间的边界。

所有这些使我相信问题出在(现在)仅malloc()调用来为参数数组保留空间。

但是我要把头撞在墙上,试图弄清楚问题出在哪里,我的意思是,我想我要的是足够的空间。

我也尝试过其他编译器,但是Clang和GCC的最新稳定版本似乎未显示任何此类警告。因此,我决定问您,经验丰富的程序员,是否可以发现问题,或者是某种编译器错误(我敢打赌)。

作为参考,以下是VS2019发出的确切警告(在64位编译中):

在作业中:

写入'argsCopy'时缓冲区溢出:可写大小为'(((argc + 1))* sizeof(wchar_t *)''字节,但可能会写入'16'字节。

下一行,测试NULL:

从'argsCopy'读取无效数据:可读大小为'(((argc + 1))* sizeof(wchar_t *)'字节,但可以读取'16'字节。

Ste*_*cht 1

这些是来自静态分析器的警告。例如,它尝试识别缓冲区溢出情况。

警告

请务必注意,这些是警告而不是错误消息。编译器表示可能存在潜在错误。静态分析通常是一件困难的事情。

假阳性

不存在缓冲区溢出情况,因此属于误报。我假设这条消息会在未来的更新中消失。

稍微改变一下代码

如果我们按如下方式更改内存分配行:

wchar_t** argsCopy = (wchar_t**)calloc(argc + 1, sizeof(wchar_t*));
Run Code Online (Sandbox Code Playgroud)

那么 Visual Studio 2019 将不再发出警告。

分配的字节数保持不变。然而,警告消失了。

测试

更改之前 VS 错误列表如下所示:

前

应用我建议的更改后,警告消失了:

后

  • 无需强制转换即可将“void*”转换为另一种指针类型。(C++ 中需要一个,但问题被标记为 C。) (2认同)