修改C语言main函数for循环的argc为固定值后程序崩溃原因解析
超出argc范围访问argv为何会读取到环境变量甚至崩溃?
最小可复现代码
#include <stdio.h> int main( int argc, char* argv[]) { printf (" this is the contents of argc:%d\n",argc); int i; for (i = 0; i < argc ; i++){ printf(" argv = %d = %s\n",i,argv[i]); } return 0; }
异常现象
当把for循环中的argc改为固定数值(比如10)时,运行程序会输出超出命令行参数的内容:
$ ./argc one two three this is the contents of argc:4 argv = 0 = ./argc argv = 1 = one argv = 2 = two argv = 3 = three argv = 4 = (null) argv = 5 = SHELL=/bin/bash argv = 6 = SESSION_MANAGER=local/wajih:@/tmp/.ICE-unix/1230,unix/wajih:/tmp/.ICE-unix/1230 argv = 7 = QT_ACCESSIBILITY=1 argv = 8 = COLORTERM=truecolor argv = 9 = XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/etc/xdg
如果将上限改为100,输出会包含大量环境变量,最终触发崩溃:
argv = 54 = GDMSESSION=ubuntu argv = 55 = DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus argv = 56 = LC_NUMERIC=ar_AE.UTF-8 argv = 57 = _=./argc argv = 58 = OLDPWD=/home/wajih argv = 59 = (null) Segmentation fault (core dumped).
原因解析
- 内存布局特性:在Linux等系统的进程内存中,
argv数组的末尾直接挨着环境变量列表(由全局变量environ指向)。C标准规定argv[argc]必须是NULL,而环境变量列表同样以NULL结尾。当循环上限超过argc时,就会越界访问到argv之后的环境变量区域,这就是你看到各种系统环境变量的原因。 - 段错误的本质:环境变量列表也有边界,当继续越界到环境变量之后的内存区域时,这些内存要么是未分配的垃圾数据,要么是进程没有访问权限的内存。此时操作系统会触发段错误,终止进程以保护内存安全。
- 未定义行为:C标准仅保证
argv[0]到argv[argc-1]是有效的命令行参数,argv[argc]为NULL。超出这个范围的访问属于未定义行为,结果完全不可控——读取环境变量、垃圾数据、直接崩溃都是可能的表现。
内容的提问来源于stack exchange,提问作者Wajih Mansouri
相关产品推荐
相关产品推荐

