C 程序仅在 Visual Studio 中的 Debug模式下,以编程方式更改 argv 在程序退出后会出现堆损坏错误。如何解决?

标签 c argv heap-corruption

我有一个大型遗留程序,其中以编程方式在程序 init 中以编程方式更改 argv 参数,然后是解析参数的逻辑。

在 Release模式下,程序正常终止。

在 Debug模式下,程序会执行所有必需的计算并给出正确的输出。但退出时会出现堆损坏错误:

enter image description here

错误消息:


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;

这并不能解决问题。

最佳答案

您可以修改 argcargv,但这并不意味着 C 会突然为您处理(重新)分配这些变量。 argv 将是 char* argv[argc]; 类型的数组。它将包含与 argc 所说的一样多的指针,不多也不少。同样,argv[i] 指向的每个字符串的长度与调用者传递的长度一样长。

示例:

myprog.exe foo 
  • 这意味着 argc == 2argv 的长度将为 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**。)

<小时/>

总而言之,修改argcargv虽然是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/

相关文章:

c - 如何将段错误地址映射到对应的C代码?

c - C语言中如何求指定值中最大的随机数?

c++ - linux中system()函数中waitpid()函数是如何实现的

c++ - 打开一个通过命令参数做某事的函数

数组内字符串中的 C 索引

c - inet_pton() 函数的二进制文件在哪里?

c++ - 使用 forrange 循环打印 argv

c++ - 使用 CreateWindowExW 时堆损坏

c++ - 立即检测 Windows 上的堆损坏错误。如何?

c++ - 动态数组堆损坏