我有一个大型遗留程序,其中以编程方式在程序 init 中以编程方式更改 argv 参数,然后是解析参数的逻辑。
在 Release模式下,程序正常终止。
在 Debug模式下,程序会执行所有必需的计算并给出正确的输出。但退出时会出现堆损坏错误:
错误消息:
Microsoft Visual C++ Runtime Library
Debug Error!
Program: ...sers\AMD\source\repos\ArgvOverflow\x64\Debug\ArgvOverflow.exe
HEAP CORRUPTION DETECTED: after CRT block (#62) at 0x00000259566FDC90. CRT detected that the application wrote to memory after end of heap buffer.
Memory allocated at minkernel\crts\ucrt\src\appcrt\startup\argv_parsing.cpp(285).
(Press Retry to debug the application)
Abort Retry Ignore
代码:
#include <stdio.h>
int main(int argc, char **argv)
{
argc = 12;
argv[1] = "str1";
argv[2] = "str2";
argv[3] = "str3";
argv[4] = "str4";
argv[5] = "str5";
argv[6] = "str6";
argv[7] = "str7";
argv[8] = "str8";
argv[9] = "str9";
argv[10] = "str10";
argv[11] = "str11";
printf("Hello world\n");
return 0;
}
我读过几篇关于修改 argv 的文章,他们声称根据 C 标准,此类修改是合法的。我也尝试了建议,让线路
argv[argc] = NULL;
这并不能解决问题。
最佳答案
您可以修改 argc
和 argv
,但这并不意味着 C 会突然为您处理(重新)分配这些变量。 argv
将是 char* argv[argc];
类型的数组。它将包含与 argc 所说的一样多的指针,不多也不少。同样,argv[i] 指向的每个字符串的长度与调用者传递的长度一样长。
示例:
myprog.exe foo
- 这意味着
argc == 2
和argv
的长度将为 2。您的程序无法更改此值。 argv[0]
将指向可修改的字符串"myprog.exe"
,大小 10+1 = 11 字节。您可以更改内容,但不能存储超过 11 个字节的任何内容。argv[1]
将指向字符串"foo"
,大小 3+1 = 4 字节。您可以更改内容,但不能存储超过 4 个字节的任何内容。
(好奇心:将 argv
定义为 VLA 非常好,而且可以说是最正确的方法,如下所示:
int main (int argc, char* argv[argc])
,因为 argv
无论如何都会衰减为 char**
。)
总而言之,修改argc
和argv
虽然是C标准允许的,但却是非常糟糕的做法。不要这样做。相反,您应该使用局部变量并让它在需要时引用 argv
。示例:
int main (int argc, char* argv[])
{
const char* argstr [12] =
{
"str0",
"str1",
"str2",
"str3",
"str4",
"str5",
"str6",
"str7",
"str8",
"str9",
"str10",
"str11",
};
for(int i=0; i<argc; i++)
{
argstr[i] = argv[i];
}
/* always use argstr here, never argv */
return 0;
}
关于C 程序仅在 Visual Studio 中的 Debug模式下,以编程方式更改 argv 在程序退出后会出现堆损坏错误。如何解决?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55390338/