修改环境变量对存储空间布局的影响
1. 环境表
每个程序都会有一张环境表(environment list)。 环境表是一个字符指针数组,除最后一个指针指向 NULL
以外,其他每个指针指向一个以 null 结尾的 C 字符串。全局变量 environ
包含了指向该指针数组的地址, 被称为环境指针(environment pointer),extern char **environ
。
图片来源:Advanced Programming in the UNIX Environment, 3rd Edition
2. 环境变量
环境字符串的形式通常为name=value
。UNIX内核并不查看环境变量,环境变量的解释完全取决于各个应用程序。查看、修改、新增和删除环境变量可以通过以下四个函数来实现:
#include <stdlib.h>
char *getenv(const char *name);
int putenv(char *str);
int setenv(const char *name, const char *value, int rewrite);
int unsetenv(const char *name);
3. C 程序的存储空间布局
图2是典型的存储器安排。由图2可知,环境变量通常存放在进程存储空间的顶部,所以不能再向高地址扩展。同时,低地址方向是栈,我们不能移动栈帧的位置,所以也不能向低地址方向扩展。因此,我们不能在进程空间顶部增加环境变量的空间长度。当我们需要增加环境变量空间长度的时候,必须调用 malloc
函数在堆中分配新空间。
图2 典型的存储器安排
图片来源:Advanced Programming in the UNIX Environment, 3rd Edition
4. 修改环境变量对存储空间布局的影响
从存储空间布局的角度来看,删除一个环境字符串(envrionment strings)很简单。但修改和新增一个环境字符串就困难得多,对存储空间布局的影响较大。
-
删除一个环境字符串,不需要增加环境变量空间长度,只需要在环境表中找到该指针,然后将所有后续指针都向环境表首部顺次移动一个位置。删除一个环境变量对存储空间影响不大。
-
修改一个环境字符串,
-
strlen("name=old_value") >= strlen("name=new_value")
:只需要在"name=old_value"
空间中写入新"name=new_value"
即可,并不需要增加环境变量空间长度。 -
strlen("name=old_value") < strlen("name=new_value")
:则必须要增加环境变量空间长度。此时,需要调用malloc
在堆中分配空间,然后将"name=new_value"
写入到该空间,接着使环境表中对name
的指针指向新分配区。
-
-
新增一个环境字符串,
-
首先需要调用
malloc
分配空间,然后将"name=new_value"
写入到该空间。 -
第一次新增,此时原有的环境表空间不够了,需要调用
malloc
在堆中分配一块较大的区域来存放新的环境表。在环境表的表尾存放指向"name=new_value"
的指针,并将空指针存放其后。同时,更新环境指针environ
,使environ
指向新的环境表。注意,此时环境表中的大多数指针仍指向原来的地方,即栈顶之上。 -
不是第一次新增,则可以知道已经有新的环境表在堆中了。这个时候只需要调用
realloc
来新增环境表分配区的长度,在环境表的表尾存放指向"name=new_value"
的指针,并将空指针存放其后。
-
综上可以知道,修改和新增环境变量对存储空间布局可能有较大的影响,这主要是因为原有存放环境变量的空间不够,需要在堆中分配新空间。