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; }
问题分析与修复
核心问题
- 传值调用导致指针修改无效:C语言函数参数是传值的,
pwd是外部&pwent的副本,函数内pwd = *result;只是修改了副本的指向,完全不会影响主函数中的pwent变量。这就是主函数中pwent地址始终不变、内容未初始化的根本原因。 - 错误的
result赋值:result[0] = NULL;等价于*result = NULL;,直接覆盖了刚分配的内存地址,既造成内存泄漏,又让主函数的pwentp变成空指针。 - 未遵循接口设计意图:标准
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
相关产品推荐
相关产品推荐

