You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用get_envaddress后复合字面量varplus内容为何被篡改?

复合字面量栈内存被覆盖的原因解析

问题场景

问题出在insert_envar函数中,相关代码如下:

char **get_envaddress(char **envp, char *find)
{  
    int i;  
    int length;

    length = ft_strlen(find);  
    i = 0;  
    while (envp[i])  
    {  
        if (!ft_strncmp(find, envp[i], length))  
            return (&envp[i]);  
        i++;  
    }  
    return (NULL);  
}

char **variable_and_end(char *string)  
{  
    return ((char *[]){envvar, &string[index]});  
}

void insert_envar(char **string, char *varplus, char **envp)  
{  
    char *build;

    *varplus = 0;  
    varplus = (char *)variable_and_end(varplus + 1);  
    envp = get_envaddress(envp, ((char **)varplus)[0]);  
    *envp = ft_strchr(*envp, '=') + 1;  
    free(((char **)varplus)[0]);  
    varplus = ((char **)varplus)[1];  
    build = ft_strjoin(*string, *envp);  
    ft_stradd(&build, varplus);  
    free(*string);  
    *string = build;  
}

当varplus接收variable_and_end返回的复合字面量后,其[0]和[1]的内容符合预期,但调用get_envaddress函数后,varplus的内容甚至[0]、[1]的内存地址都发生了变化——而get_envaddress并未直接操作varplus的内存或值。推测是栈内存变动影响了复合字面量。

验证过程

为验证推测,在获取varplus后将两个字符串保存到全局的test指针数组中,程序恢复正常。修改后的代码及输出如下:

void insert_envar(char **string, char *varplus, char **envp)
{
    char *build;

    *varplus = 0;  
    varplus = (char *)variable_and_end(varplus + 1);  
    test[0] = ((char **)varplus)[0];  
    test[1] = ((char **)varplus)[1];  
    printf("varplus: [0] = %s\nvarplus: [1] = %s\n", ((char **)varplus)[0], ((char **)varplus)[1]);  
    envp = get_envaddress(envp, ((char **)varplus)[0]);  
    printf("varplus: [0] = %s\nvarplus: [1] = %s\n", ((char **)varplus)[0], ((char **)varplus)[1]);  
    printf("test: [0] = %s\ntest: [1] = %s\n", test[0], test[1]);  
    *envp = ft_strchr(*envp, '=') + 1;  
    free(((char **)varplus)[0]);  
    varplus = ((char **)varplus)[1];  
    build = ft_strjoin(*string, *envp);  
    ft_stradd(&build, varplus);  
    free(*string);  
    *string = build;  
}

输出结果:

varplus: [0] = PATH
varplus: [1] =  "asd
varplus: [0] = PATH
varplus: [1] = ���
test: [0] = PATH
test: [1] =  "asd

调用get_envaddress前varplus内容正常,调用后[1]损坏,但test数组始终保留正确内容。

原因分析

问题的核心是复合字面量的存储位置:

  • 在C语言中,复合字面量(比如(char *[]){envvar, &string[index]})的生命周期是所在的块作用域。variable_and_end函数返回的复合字面量是在该函数的栈帧上创建的,当variable_and_end执行完毕返回后,这个栈帧会被标记为可复用。
  • 此时varplus保存的是指向这个已失效栈帧内存的指针,属于悬空指针。
  • 当调用get_envaddress时,新的函数栈帧会覆盖之前variable_and_end栈帧的内存区域,导致原本存储复合字面量数组的内存被改写,所以varplus指向的内容会出现损坏。
  • 而全局的test数组存储的是指针的副本,指向的是原本的字符串数据(envvar和&string[index]本身的内存不在栈帧上),所以不会被栈帧覆盖影响,始终保持正确。

内容的提问来源于stack exchange,提问作者Rubens Freire

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 07:20:02