在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:
../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  if environ[i]==
(gdb) p ptr
$ = 0x7fffffffefe3 "/home/xyz/TLPI/a.out"
(gdb) p environ[i]
$ = 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时的一个坑的更多相关文章

  1. python解释器的安装;python2与python3同时在环境变量中时的解决方案

    新文档 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,addres ...

  2. Linux系统——访问U-BOOT环境变量

    Linux系统下访问U-BOOT环境变量 移植过U-BOOT的人,都知道:在U-BOOT中存有ENV.但U-BOOT在引导内核启动之后,U-BOOT的生命周期就结束了.那么启动LINUX内核之后,U- ...

  3. 关于pyinstaller打包程序时设置icon时的一个坑

    关于pyinstaller打包程序时设置icon时的一个坑     之前在用pyinstaller打包程序的时候遇到了关于设置图标的一点小问题,无论在后面加--icon 或是-i都出现报错.查了下st ...

  4. WSL Ubuntu 安装MongoDb 4.0导入公钥时遇到一个坑 (转)

    WSL Ubuntu 安装MongoDb 4.0导入公钥时遇到一个坑 一路坑啊~~~网上的密钥都不对????  不应该啊 源中默认是MongoDb 3.x 但是我想用4.0,然后按照mongodb官方 ...

  5. 进程的环境变量environ

    编程之路刚刚开始,错误难免,希望大家能够指出. 每个进程都有自己的环境变量,在C语言程序中可使用外部变量(char **environ)来访问环境,而库函数可允许进程去获取或修改自己环境的值. 两种方 ...

  6. UNIX环境编程学习笔记(16)——进程管理之进程环境变量

    lienhua342014-10-03 1 环境表和环境指针 在每个进程启动时,都会接到一张环境表.环境表是一个字符指针数组,其中每个指针包含一个以 null 结束的 C 字符串的地址.全局变量env ...

  7. 接口测试01- Jmeter-线程进程-环境变量

    1.1 概念 JMeter 是 Apache 组织使用 Java 开发的一款测试工具 ,它最初被设计用于Web应用测试,但后来扩展到其他测试领域. 它可以用于测试静态和动态资源,例如静态文件.Java ...

  8. Web开发之tomcat配置及使用(环境变量设置及测试,一个简单的web应用实例)

    Tomcat的配置及测试: 第一步:下载tomcat,然后解压到任意盘符 第二步:配置系统环境变量 tomcat解压到的D盘 (路径为: D:\tomcat), 配置环境变量: 启动tomcat需要两 ...

  9. Nginx 转发时的一个坑,运维居然让我背锅!!

    最近遇到一个 Nginx 转发的坑,一个请求转发到 Tomcat 时发现有几个 http header 始终获取不到,导致线上出现 bug,运维说不是他的问题,这个锅我背了. 新增的几个 header ...

随机推荐

  1. angularJS---service

    service ng的服务是这样定义的: Angular services are singletons objects or functions that carry out specific ta ...

  2. 使用XMLHttpRequest对象完成原生的AJAX请求

    1.大家眼中的Ajax 说到Ajax,只要有过前端开发经验的童鞋一定都不陌生,大都知道它就是一种与后端之间的通信技术,通过这个神奇的家伙,我们不用像传统表单那样填完信息一点提交就呼啦呼啦跳转了.Aja ...

  3. 快速切题 poj 3026 Borg Maze 最小生成树+bfs prim算法 难度:0

    Borg Maze Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8905   Accepted: 2969 Descrip ...

  4. JS中apply与call的用法

    JavaScript中有一个call和apply方法,其作用基本相同,但也有略微的区别. 先来看看JS手册中对call的解释: call 方法调用一个对象的一个方法,以另一个对象替换当前对象. cal ...

  5. 实现一个简单的lazyman

    function lazyman(name) { return new lazyman.fn.init(name); } lazyman.fn = lazyman.prototype = { cons ...

  6. 联想THINKPAD E40的快捷键怎么关闭?哪些F1 F2 F3的键我需要用到 但是每次都按FN 太烦人了

    1.开机时,按F1进入BIOS,依次选择CONFIG--Keyboard/Mouse,2.在Change to "f1-f12 keys"选项中,更改设置为Legacy或者Defa ...

  7. 求二叉树的深度 python

    二叉树有深度和高度两个属性,一个节点的深度指的是从根节点到该节点路径的长度,根节点的深度为1:一个节点的高度指的是从该节点到叶子节点所有路径上包含节点个数的最大值.叶子节点的高度为1,往上节点的高度依 ...

  8. 在tableView中设置cell的图片和文字

    // 设置UITableViewCellEditingStyle的 accessoryType UITableViewCellAccessoryNone,                   // d ...

  9. times(NULL) Segmentation fault

    ****************************************************************************** * times(NULL) Segment ...

  10. vuex秘籍

    vue项目开发中,大型项目一般vuex所需要存储的状态一般都很都,这时,我们便需要进性模块化划分,然后 再页面中采用映射来实现state的调用: 目录一般如下: store为总的状态库存放文件. mo ...