该缓冲区如何溢出?

时间:2019-05-09 10:05:42

标签: c malloc buffer-overflow

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

这里的想法是将argv复制到另一个变量中,本质上是复制它。因此,该函数的基本思想是,使用malloc()来请求复制空间,然后遍历argv制作每个元素的副本。

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

// Returns a copy of an array of strings (inteded 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;
}

我一直在尝试不同的方法来复制argv,但是每一个方法都让VS相信当我复制参数时(行:argsCopy[i] = _wcsdup(argv[i]);),或者在下一行中读取无效数据,这意味着要读取保留空间的边界。

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

但是我还是要撞墙,试图找出问题所在,我的意思是,我想我要提供足够的空间。

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

无论如何都要感谢您的时间。

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

在作业中:

  

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

下一行,测试NULL:

  

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

4 个答案:

答案 0 :(得分:0)

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

警告

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

误报

没有缓冲区溢出情况,因此它是误报。我认为,此消息在以后的更新中会消失。

稍微更改代码

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

wchar_t** argsCopy = (wchar_t**)calloc(argc + 1, sizeof(wchar_t*));

然后,Visual Studio 2019将不再发出警告。

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

测试

在进行更改之前,“ VS错误”列表如下所示:

before

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

after

答案 1 :(得分:0)

但是,在尝试使用Visual Studio的在线副本(https://rextester.com/l/c_online_compiler_visual)之后,我可能会误解,我被迫假定您忘记包含string.hwchar.h (两个都可以)。 Visual Studio似乎假定您的返回类型是整数而不是wchar_t *,因为未定义函数。由于它是一个以_开头的保留函数,因此似乎没有“魔术”,因此它不会发出其他警告吗?再次没有您的确切环境,尽管我被迫部分猜测(您对目标更改警告的评论为我提供了希望正确的提示)。

答案 2 :(得分:0)

关键点可能是您没有分配足够的空间来容纳要复制的数据。

我不知道我是否真正了解您要做什么,我假设您想将二维字符数组复制到另一个内存段中,然后返回其地址,并且该数组具有“ argc”行,即地址每行字符串的行存储在argv数组中。

但是为什么您使用argc+1而不是argc?是否有malloc的额外空间来防止缓冲区溢出?更重要的是sizeof(wchar_t*)将返回指针的大小(在64位系统中为8个字节)。它不会返回我们想要的二维数组中字符串之一的大小。

答案 3 :(得分:-1)

1)下面说明了一种复制argv的方法,但是。 2)我无法理解为什么要复制argv?它可以解决什么用例/用户问题?

正如我在(1)中提到的,

是其中一种方法,本质上是关于将argv的所有内容复制到缓冲区中。这样的事情(PS:当我在出租车上打手机时可能会出现编译错误,因此无法使用高质量的C编译器进行交叉检查)

int numArgc = argc
char** argvCopy;

for (i=0;i<argc,i++)
{

 argvCopy[i] = malloc(sizeof(char)*strlen(argv[i]));
 strcpy(argvCopy[i], argv[i]);

}

//please do not forget to Free this malloc'ed memory (a very common C programming error) //when you don't need it anymore 

请告诉您您要解决的问题