【坑】putenv与setenv()

文章目录


在这里插入图片描述

在写项目的时候发现了一个bug,在调试了很长时间后终于发现了。
本篇博客是为了记录一下这个坑,以免再次掉入。

测试使用的配置如下:
在这里插入图片描述


在这里插入图片描述
在执行了程序替换execl后,程序崩溃掉了。
在这里插入图片描述

程序执行后,在main.cc中成功的将环境变量写入了,并且能够成功读取出来。

但是在test.cc中通过打印环境变量表发现,环境变量表中并没有METHOD,getenv()返回空指针,使用空指针初始化string,程序崩溃。

问题出现的根本原因在于:
我们使用局部变量method存储的环境变量字符串,在putenv时,是直接将传入的字符串指针写到环境变量表(char** environ)中;出了作用域后,string生命周期到了,析构,字符串被释放,造成环境变量失效。

在 Ubuntu 系统(以及其他基于 Linux 的系统)中,使用 execl 执行程序替换后,环境变量表中不存在之前设置的环境变量字符串是合理的,尤其是当环境变量的字符串是通过局部变量存储时。这种行为是由 execl 的工作原理以及环境变量的存储机制共同决定的。

  1. 为什么环境变量在 execl 后可能不存在?
  • execl 的行为 execl 是 exec 系列函数之一,用于替换当前进程的用户空间内存,加载并运行一个新的程序。在替换过程中,当前进程的用户空间内存(包括栈、堆和全局数据段)会被完全释放,新的程序映像会被加载到内存中。
  • 环境变量的存储机制 环境变量通常存储在进程的环境变量表中,这个表是一个以空指针结尾的字符串数组,每个字符串都是以"key=value" 形式存储的。环境变量表在进程启动时由操作系统初始化,并可以通过 setenv、putenv 等函数进行修改。
  • 局部变量的生命周期 局部变量存储在栈上,其生命周期仅限于定义它们的函数的作用域内。当函数返回或程序被替换时,局部变量的内存会被释放

execl 如何判断环境变量的有效性呢?

execl 函数本身并不直接“判断”环境变量的有效性,而是依赖于以下机制来确保环境变量在程序替换后仍然可用

  • 继承父进程的环境变量表: 默认情况下,子进程会继承父进程的环境变量表。这意味着在调用 execl 之前设置的环境变量(通过 setenv 或 putenv)会被传递给新的程序。
  • 如果环境变量的字符串存储在局部变量中(如栈上),在程序替换后,这些局部变量的内存地址可能不再有效,导致环境变量失效。

如果我们将环境变量字符串在堆上开辟空间,是不是就可以了呢?
在这里插入图片描述

我们发现确实是这样,为了避免该问题,不要使用局部变量存储环境变量字符串。
putenv适用于快速设置环境变量的场景,尤其是当传入的字符串可以保证在调用后不会被释放或修改时


下面我们来介绍一个函数:setenv()

函数原型:

#include <stdlib.h>

int setenv(const char *name, const char *value, int overwrite);

参数说明

  1. name:

指向环境变量名称的指针。名称必须是一个以空字符(\0)结尾的字符串。环境变量名称不能包含等号(=),否则会导致未定义行为。

  1. value:

指向环境变量值的指针。值也必须是一个以空字符(\0)结尾的字符串。

  1. overwrite:

一个布尔值,用于控制是否覆盖已存在的环境变量

  • 如果 overwrite 为非零值(通常为 1),则即使环境变量已存在,也会覆盖其值。
  • 如果 overwrite 为零(0),则只有在环境变量不存在时才会设置该变量
  1. 返回值
  • 0:表示成功。
  • -1:表示失败,通常是因为内存分配失败或参数无效。

在这里插入图片描述

底层原理: 动态内存分配。setenv 函数会为环境变量分配动态内存来存储变量名和值。这意味着它不需要依赖传入的字符串的生命周期。

对比:

  • 内存管理:
    • putenv:直接将传入的字符串指针存储到环境变量数组(environ)中,不会为字符串分配额外的内存,因此,传入的字符串必须在调用后保持有效,不能被释放或修改。
    • setenv:会为环境变量名称和值分配动态内存,传入的字符串在调用后可以被释放或修改,因为 setenv 已经复制了这些字符串。
  • 线程安全性
    • putenv:不是线程安全的,因为多个线程同时调用 putenv 可能会导致竞态条件。
    • setenv:是线程安全的,因为它在内部使用锁来保护对环境变量数组的访问。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值