The result from getpwnam()
may be overwritten by another call to getpwnam()
or getpwuid()
or getpwent()
. Your code is demonstrating that.
See the POSIX specifications of:
You have no control over the order of evaluation of the calls. If you saved the pointers returned, you'd probably get different results printed.
POSIX also says:
The application shall not modify the structure to which the return value points, nor any storage areas pointed to by pointers within the structure. The returned pointer, and pointers within the structure, might be invalidated or the structure or the storage areas might be overwritten by a subsequent call to getpwent()
, getpwnam()
, or getpwuid()
. The returned pointer, and pointers within the structure, might also be invalidated if the calling thread is terminated.
You should treat the return values as if they were const
-qualified, in other words.
Note that the code in the library functions need not overwrite previous data. For example, on macOS Big Sur 11.6.8, the following code, compiled with -DUSER1=\"daemon\"
as one of the compiler options, yields the result:
daemon root
1 0
U1A = 0x7fecfa405fd0, U2A = 0x7fecfa405c60
U1B = 0x7fecfa405fd0, U2B = 0x7fecfa405c60
Modified code:
/* SO 7345-2740 */
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef USER1
#define USER1 "steve"
#endif
#ifndef USER2
#define USER2 "root"
#endif
int main(void)
{
const struct passwd *user1a = getpwnam(USER1);
const struct passwd *user2a = getpwnam(USER2);
const char *user1_name = user1a->pw_name;
const char *user2_name = user2a->pw_name;
printf("%s %s\n", user1_name, user2_name);
const struct passwd *user1b = getpwnam(USER1);
const struct passwd *user2b = getpwnam(USER2);
int user1_uid = user1b->pw_uid;
int user2_uid = user2b->pw_uid;
printf("%d %d\n", user1_uid, user2_uid);
printf("U1A = %p, U2A = %p\n", (void *)user1a, (void *)user2a);
printf("U1B = %p, U2B = %p\n", (void *)user1b, (void *)user2b);
return EXIT_SUCCESS;
}
It is moderately likely that the library functions read the whole file into memory and then pass pointers to relevant sections of that memory. Certainly, in this example, the pointers to the entry for user daemon
and user root
are stable.
YMWV — Your Mileage Will Vary!