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

getpwnam_r函数指针值未修改,结构体内容为空问题求助

问题:自定义getpwnam_r函数输出为空

近期在小型项目中编写简易pwd.h替代实现,实现getpwnam_r函数时出现异常,预期输出用户名和powershell.exe,但实际两者均为空。通过gdb调试发现,函数内pwd地址与result[0]相同,但回到主函数后pwent地址未变化。

相关代码

win_pwd.h

#ifndef _PWD_H
#define _PWD_H 1
#include <stdlib.h>
#include <stddef.h>

typedef unsigned int uid_t;
typedef unsigned int gid_t;

struct passwd{
 char * pw_name;   // User Log-in Name
 uid_t  pw_uid;    // Numerical User ID
 gid_t  pw_gid;    // Numerical Group ID
 char * pw_dir;    // Initial Working Directory
 char * pw_shell;  // Program to use as a shell
};

int getpwnam_r(const char * name, struct passwd * pwd,
               char * buffer, size_t size, struct passwd ** result){

 *result = malloc(sizeof(struct passwd));
 (* result )->pw_name = getenv("USERNAME");
 (* result )->pw_dir = getenv("PWD"); 
 (* result )->pw_shell = "powershell.exe";
 (* result )->pw_uid = 1;
 (* result )->pw_gid = 1;
 
 pwd = * result;
 result[0] = NULL;
 return 0;
}

#endif

main.c

#include "win_pwd.h"
#include <stdio.h>

int main(){
 struct passwd pwent;
 struct passwd *pwentp;
 char buf[1024];
 const char * login = "TEST";
 int lol = getpwnam_r(login, &pwent, buf, sizeof buf, &pwentp);
 printf("Username: %s\n", pwent.pw_name);
 printf("SHELL: %s\n", pwent.pw_shell);
 return 0;
}

问题分析与修复

核心问题

  1. 传值调用导致指针修改无效:C语言函数参数是传值的,pwd是外部&pwent的副本,函数内pwd = *result;只是修改了副本的指向,完全不会影响主函数中的pwent变量。这就是主函数中pwent地址始终不变、内容未初始化的根本原因。
  2. 错误的result赋值:result[0] = NULL;等价于*result = NULL;,直接覆盖了刚分配的内存地址,既造成内存泄漏,又让主函数的pwentp变成空指针。
  3. 未遵循接口设计意图:标准getpwnam_r要求将字符串数据存入传入的buffer(保证线程安全,避免动态分配内存),你的实现直接使用环境变量指针和字符串字面量,虽能运行但不符合接口规范,且存在环境变量被修改时的潜在风险。

修复后的代码

win_pwd.h

#ifndef _PWD_H
#define _PWD_H 1
#include <stdlib.h>
#include <stddef.h>
#include <string.h>

typedef unsigned int uid_t;
typedef unsigned int gid_t;

struct passwd{
 char * pw_name;   // User Log-in Name
 uid_t  pw_uid;    // Numerical User ID
 gid_t  pw_gid;    // Numerical Group ID
 char * pw_dir;    // Initial Working Directory
 char * pw_shell;  // Program to use as a shell
};

int getpwnam_r(const char * name, struct passwd * pwd,
               char * buffer, size_t size, struct passwd ** result){
    // 参数合法性校验
    if (pwd == NULL || buffer == NULL || result == NULL) {
        *result = NULL;
        return -1;
    }

    // 获取环境变量与固定字符串
    const char *username = getenv("USERNAME");
    const char *pwd_dir = getenv("PWD");
    const char *shell = "powershell.exe";

    // 计算所需buffer大小
    size_t needed = 0;
    if (username) needed += strlen(username) + 1;
    if (pwd_dir) needed += strlen(pwd_dir) + 1;
    needed += strlen(shell) + 1;

    if (needed > size) {
        *result = NULL;
        return -1; // buffer空间不足
    }

    // 填充pwd结构体(直接操作传入的外部内存)
    char *buf_ptr = buffer;
    if (username) {
        strcpy(buf_ptr, username);
        pwd->pw_name = buf_ptr;
        buf_ptr += strlen(username) + 1;
    } else {
        pwd->pw_name = NULL;
    }

    if (pwd_dir) {
        strcpy(buf_ptr, pwd_dir);
        pwd->pw_dir = buf_ptr;
        buf_ptr += strlen(pwd_dir) + 1;
    } else {
        pwd->pw_dir = NULL;
    }

    strcpy(buf_ptr, shell);
    pwd->pw_shell = buf_ptr;

    pwd->pw_uid = 1;
    pwd->pw_gid = 1;

    // 设置result指向填充完成的结构体
    *result = pwd;
    return 0;
}

#endif

main.c(无需修改)

#include "win_pwd.h"
#include <stdio.h>

int main(){
 struct passwd pwent;
 struct passwd *pwentp;
 char buf[1024];
 const char * login = "TEST";
 int lol = getpwnam_r(login, &pwent, buf, sizeof buf, &pwentp);
 printf("Username: %s\n", pwent.pw_name);
 printf("SHELL: %s\n", pwent.pw_shell);
 return 0;
}

修复要点说明

  • 直接操作pwd指针指向的外部内存(即主函数的pwent变量),避免修改指针副本的无效操作。
  • 使用传入的buffer存储字符串内容,符合getpwnam_r的线程安全设计,消除内存泄漏风险。
  • 正确设置*result = pwd,让主函数的pwentp指向填充好的结构体。
  • 添加参数校验和buffer大小检查,提升代码健壮性。

内容的提问来源于stack exchange,提问作者Arturo Contreras

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 20:02:28