zoukankan      html  css  js  c++  java
  • 访问进程环境变量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
    ", 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信号。

  • 相关阅读:
    WCF 入门例子
    C#傻瓜日志类
    ajax长链接拉实现
    linux命令备忘
    .Net 并发异步处理总结
    grafana初始化密码(转载)
    Android 调用照相机拍照
    自定义android控件EditText 自定义边框 背景
    JSON 请求的实现过程
    [转]Android开发教程:shape和selector的结合使用
  • 原文地址:https://www.cnblogs.com/Harley-Quinn/p/6817958.html
Copyright © 2011-2022 走看看