Use getpwuid_r() instead of getpwuid()
In the Netopeer2 test suite, two threads were calling getpwuid(), which
is not a reentrant function. Here's a trace from TSAN:
WARNING: ThreadSanitizer: data race (pid=3803971)
Write of size 8 at 0x7fc95e073f40 by thread T2:
#0 getpwuid <null> (test_parallel_sessions+0x4367d4)
#1 nc_connect_unix libnetconf2/src/session_client.c:1270:10 (libnetconf2.so.2+0x1ba34)
#2 send_get_rpc Netopeer2/tests/test_parallel_sessions.c:68:15 (test_parallel_sessions+0x4ea807)
Previous write of size 8 at 0x7fc95e073f40 by thread T1:
#0 getpwuid <null> (test_parallel_sessions+0x4367d4)
#1 nc_connect_unix libnetconf2/src/session_client.c:1270:10 (libnetconf2.so.2+0x1ba34)
#2 send_get_rpc Netopeer2/tests/test_parallel_sessions.c:68:15 (test_parallel_sessions+0x4ea807)
Location is global 'resbuf.11357' of size 48 at 0x7fc95e073f40 (libc.so.6+0x1bcf40)
Thread T2 (tid=3807449, running) created by main thread at:
#0 pthread_create <null> (test_parallel_sessions+0x469032)
#1 test_first Netopeer2/tests/test_parallel_sessions.c:115:9 (test_parallel_sessions+0x4ea6c2)
#2 cmocka_run_one_test_or_fixture <null> (libcmocka.so.0+0x630e)
Thread T1 (tid=3807448, running) created by main thread at:
#0 pthread_create <null> (test_parallel_sessions+0x469032)
#1 test_first Netopeer2/tests/test_parallel_sessions.c:115:9 (test_parallel_sessions+0x4ea6ad)
#2 cmocka_run_one_test_or_fixture <null> (libcmocka.so.0+0x630e)
SUMMARY: ThreadSanitizer: data race (Netopeer2/tests/test_parallel_sessions+0x4367d4) in __interceptor_getpwuid
Fix that by switching to getpwuid_r(). The code is very similar to the
auth_password_getpwnam() wrapper from session_server_ssh.c. I chose to
put this into io.c even though it is not really an IO function, but the
existing nc_realloc() is in that file as well.
diff --git a/src/session_client.c b/src/session_client.c
index b2a1854..7640856 100644
--- a/src/session_client.c
+++ b/src/session_client.c
@@ -1238,16 +1238,18 @@
{
struct nc_session *session = NULL;
struct sockaddr_un sun;
- const struct passwd *pw;
+ struct passwd *pw, pw_buf;
char *username;
int sock = -1;
+ char *buf = NULL;
+ size_t buf_size = 0;
if (address == NULL) {
ERRARG("address");
return NULL;
}
- pw = getpwuid(geteuid());
+ pw = nc_getpwuid(geteuid(), &pw_buf, &buf, &buf_size);
if (pw == NULL) {
ERR(NULL, "Failed to find username for euid=%u.\n", geteuid());
goto fail;