在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信号。

转载于:https://www.cnblogs.com/Harley-Quinn/p/6817958.html

访问进程环境变量environ时的一个坑相关推荐

  1. 11g里创建OEM时的一个坑“emca -config dbcontrol db -repos recreate”

    11g里创建OEM时的一个坑 关于11g的OEM的更多内容: http://blog.itpub.net/26736162/viewspace-2029565/ 关于Oracle里的组件说明: htt ...

  2. 【Linux】孤儿进程 | 环境变量 | 命令行参数 | 进程优先级

    文章目录 1. 孤儿进程 2. 环境变量 1. PATH环境变量 证明ls是系统指令 修改自己写的可执行程序对应路径 2. env--查看系统环境变量 3. 获取环境变量 envp environ g ...

  3. jmeter进程和线程的区别_接口测试01- Jmeter-线程进程-环境变量

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

  4. java 单元测试 私有成员变量,单元测试时测试一个private私有方法 - - ITeye博客

    直接上例子 待测试的类 [code="java"]public class Calculator { private int count = 0; private int add( ...

  5. 环境变量environ

    void getenviron(void) {extern char ** environ;char **pe= environ;while(*pe != NULL){cout<<*pe& ...

  6. 环境变量空格符号带来的坑

    如图所示:设置环境变量: 环境变量对空格符号进行了截断:JAVA_HOME地址为c:\Program

  7. Kafka生产环境缩容遇到的一个坑

    1.背景 最近在折腾Kafka日志集群,由于公司部署的应用不断增加,日志采集程序将采集到的日志发送到Kafka集群时出现了较大延迟,总的TPS始终上不去,为了不影响业务团队通过日志排查问题,采取了先解 ...

  8. 总结-linux初识进程(包括cpu调度、进程创建、僵尸进程(重点)、环境变量)

    冯诺依曼体系结构--现代计算机的硬件体系结构 输入设备.输出设备(数据输出).存储器(数据缓冲).运算器(数据运算).控制器. 所有设备都是围绕存储器工作---CPU是从存储器中获取数据处理---控制 ...

  9. linux中的进程、环境变量和虚拟地址

    目录 冯诺依曼体系结构 操作系统 进程概念 程序和进程 什么是程序 什么是进程 查看进程信息 进程.进程标识符&进程状态 进程创建 僵尸状态和僵尸进程 孤儿进程 环境变量 定义 常见的环境变量 ...

最新文章

  1. Kail Linux渗透测试教程之Recon-NG框架
  2. mysql udf http.so_MySQL-UDF-HTTP + Express + WebSocket 实现数据库推送
  3. Chrome浏览器查看SSL证书信息
  4. 蓝桥杯练习系统习题-算法训练2
  5. mysql 类型_MySQL-约束类型
  6. C#菜鸟正则表达式一
  7. 【转】谈谈Unicode编码,简要解释UCS、UTF、BMP、BOM等名词
  8. n个1组成的整数能被2013整除c语言,求大神解算法,“编写程序,求n至少为多大时,n个1组成的整数能被2013 整除。”...
  9. LSSS线性秘密共享方案详细构造方法与原理解释试读
  10. 使用 Hasor 从数据库查询显示到页面上
  11. “秃“如其来的植发经济是一门好生意吗?
  12. 透明壁纸android,主题透明壁纸软件下载-主题透明壁纸 安卓版v1.0-PC6安卓网
  13. DNA双螺旋结构是怎样发现的?
  14. Java从接触到放弃(二十一)--网络编程
  15. JAVA.SE JUnit单元测试 NIO
  16. ROS官网使用方式以及问题?
  17. 青铜到王者,京东数科这个AI机器人组织有多野?
  18. JavaScript谬论体系
  19. Python3 爬取 NBA 2013-2014 赛季比赛数据
  20. html_常用标签_盒子标签_图片标签_超链接_列表标签(2)

热门文章

  1. nginx有10个以上参数rewrite的处理
  2. MSSQL 判断表是否存在的两种方法
  3. visual stadio 添加 Extjs 智能提示!
  4. IBM技术大会2005
  5. 不要把时间画在抽奖上。。。去学习吧。。。
  6. U3D5.3.5f Monodevelop 仅支持到.NET 3.5
  7. jQuery-强大的jQuery选择器 (详解)
  8. webpack + react 使用 eslint
  9. 大数据创业难度大 五个值得关注的重点
  10. 【Spark Summit EU 2016】在在线学习中使用Structured Streaming流数据处理引擎