我有一个很大的遗留程序,其中的argv参数是在程序init中以编程方式更改的,后面是解析参数的逻辑。
在释放模式下,程序正常终止。
在调试模式下,程序执行所有必需的计算并给出正确的输出。但退出时会出现堆损坏错误:
错误消息:
Microsoft Visual C++运行时库
调试错误!
程序:...sers\AMD\source\repos\ArgvOverflow\x64\Debug\ArgvOverflow。exe
检测到堆腐 eclipse :在0x 00000259566 FDC 90的CRT块(#62)之后。CRT检测到应用程序在堆缓冲区结束后写入内存。
内存分配在minkernel\crts\ucrt\src\appcrt\startup\argv_parsing。cpp(285)。
(按“重试”以调试应用程序)
放弃重试忽略
验证码:
#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;
这并不能解决问题。
5条答案
按热度按时间ntjbwcob1#
你可以修改
argc
和argv
,但这并不意味着C会突然为你处理(重新)分配这些变量。argv
将是一个类型为char* argv[argc];
的数组。它将包含argc
所说的指针数量,不多不少。类似地,argv[i]
指向的每个字符串的长度与调用者传递的长度一样长。示例:
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
。示例:wnavrhmk2#
参数
argc
和argv
以及argv
数组指向的字符串应可由程序修改,并在程序启动和程序终止之间保留其最后存储的值。仍然不允许访问数组的边界,
argv
将只有**argc + 1
个元素(值为argc
*,就像在 * main的开头一样),没有你试图填充的那么多。au9on6nz3#
你不能像这样摆弄
argv
。argv
不是您的,它已在程序启动时根据命令行分配并填充。如果你像这样调用你的程序:
那么
argc
是4,argv[0]
指向"program"
,argv[1]
指向"a"
,等等。argv[argc]
是NULL
但是访问
argv[5]
和更高的值是未定义的行为,因为您访问的是越界的数组。这篇文章可能也有帮助:How dangerous is it to access an array out of bounds?。
要解决您的问题,请执行以下操作:不要访问越界的数组。
jgovgodb4#
为了解决这个问题,我创建了一个单独的char**变量,并在代码中使用该变量来解决这个问题。
下面是新代码的样子:
ndh0cuux5#
在进行调试时使用这种设置是完全合理的。其中一项对我有用的工作是在调用程序时设置一个伪参数列表,然后在进入main后用所需的数据重新填充argv。
在你的代码里