访问进程环境变量environ时的一个坑
Posted Harley_Quinn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了访问进程环境变量environ时的一个坑相关的知识,希望对你有一定的参考价值。
在unistd.h中定义了变量char **environ;来表示当前所有环境变量,一般来说访问特定环境变量可以用getenv,但是想遍历所有环境变量就得使用environ。
即在程序内全局声明extern char **environ;当然设定main函数第3个参数也可以,不过不推荐,因为ISO C的main函数没有第三个参数。
environ维护了一个char*数组,每个元素都是一个指针指向函数栈帧顶部的环境变量,数组结尾是NULL。
于是正确的遍历姿势是下面这样
for (int i = 0; environ[i] != NULL; i++) puts(environ[i]);
然后我试了下错误的姿势
for (char *ptr = environ[0]; ptr; ptr++) puts(ptr);
结果是程序dump了,审查了下发现错误出在ptr++上,因为ptr类型是char*,执行++后指针只向前移动1 byte。
于是就变成这样
for (char *ptr = environ[0]; ptr; ptr += (strlen(ptr) + 1) puts(environ[i]);
代码已经比较丑陋了,而且还多出了不必要的计算,即strlen函数,但是程序依然dump了。
我的调试方式是这样的
for (char *ptr = environ[0]; ptr; ptr += (strlen(ptr) + 1)) { static int i = 0; if (strcmp(ptr, environ[i]) != 0) { printf("error: %d\\n", i); break; } puts(ptr); i++; }
错误如下
Program received signal SIGSEGV, Segmentation fault. __strcmp_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcmp-sse2-unaligned.S:204 204 ../sysdeps/x86_64/multiarch/strcmp-sse2-unaligned.S: No such file or directory.
对啊,environ数组最后一个元素是NULL,但是strcmp必须接收非NULL指针作为参数(因为strcmp的参数s1、s2必须可以用*s1、*s2来访问,NULL是地址0,是用户无法访问的地址,用户访问无法访问的地址时就会产生SIGSEGV信号)。
于是我定位到了strcmp这句
(gdb) b 15 if environ[i]==0
(gdb) p ptr $1 = 0x7fffffffefe3 "/home/xyz/TLPI/a.out" (gdb) p environ[i] $2 = 0x0
原因也清楚了。在C程序的存储空间高地址是命令行参数和环境变量依次排列,如下图
n1是环境变量的数量,n2是命令行参数的数量。因此在ptr指向最后一个环境变量时,ptr+=(strlen[ptr]+1)后指向的是argv[0]。
字符指针数组environ保存了n1+1个元素,多出一个元素是NULL。而ptr+=(strlen[ptr]+1)则是直接访问程序的存储空间,并没有一个终止符。
当ptr到达内存中不可访问的区域(即argv[n2-1]的下面,函数栈帧的地址),就会引发SIGSEGV信号。
以上是关于访问进程环境变量environ时的一个坑的主要内容,如果未能解决你的问题,请参考以下文章