1

Is there a fix or a workaround for the memory leak in getpwnam?

Sergey Golovchenko
  • 18,203
  • 15
  • 55
  • 72

4 Answers4

8

getpwnam() does not suffer of memory leak. Subsequent calls, indeed, will overwrite its static internal buffer.

Such kind of functions are instead non-reentrant and therefore non-thread safe. Paul suggested the use of getpwnam_r() which is the reentrant version, that is safe to be used in a multithread context.

That said, memory leaks are caused by those system calls that allocate memory by means of malloc() and leave the application the responsability to free() the memory once the returned data has used.

In these cases the RAII idiom is advisable in order to not forget to free the allocated memory -- see exception safety. std::tr1::shared_ptr<> is also a viable way: For the shared_ptr a custom deleter must be provided to free() the raw pointer when the shared_ptr goes out of the scope.

Under this perspective some dangerous functions are scandir(), asprintf(), vasprintf() etc.

Nicola Bonelli
  • 8,101
  • 4
  • 26
  • 35
  • Oh good answer. If I could transfer the "accepted answer" to you, I would. – Paul Tomblin Nov 06 '08 at 19:14
  • The answer is conceptually correct but it's not what's happening with getpwnam or getpwnam_r. Internally, libc (not the user code) dynamically allocates nss data, which is never freed. There's no way to solve this in user code with any idiom, because the issue is inside libc. See: http://sourceware.org/bugzilla/show_bug.cgi?id=2314 – hdante Feb 24 '13 at 23:53
3

Use getpwnam_r.

Paul Tomblin
  • 179,021
  • 58
  • 319
  • 408
2

I don't think there is a workaround. The answers above do not help, see:

daniel@senap:~/dev/tryouts$ uname -a
Linux senap 3.2.0-24-generic #39-Ubuntu SMP Mon May 21 16:52:17 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
daniel@senap:~/dev/tryouts$ cat getpwnam-leak.c 
#include <sys/types.h>
#include <pwd.h>

extern void __libc_freeres(void);

int main()
{
  char buf[1024];
  struct passwd pw, *result;
  getpwnam_r("root", &pw, buf, sizeof(buf), &result);
  __libc_freeres();
}
daniel@senap:~/dev/tryouts$ valgrind --leak-check=full ./getpwnam-leak
==6951== Memcheck, a memory error detector
==6951== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==6951== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==6951== Command: ./getpwnam-leak
==6951== 
==6951== 
==6951== HEAP SUMMARY:
==6951==     in use at exit: 300 bytes in 11 blocks
==6951==   total heap usage: 69 allocs, 58 frees, 9,234 bytes allocated
==6951== 
==6951== 300 (60 direct, 240 indirect) bytes in 1 blocks are definitely lost in loss record 11 of 11
==6951==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==6951==    by 0x4F35D94: nss_parse_service_list (nsswitch.c:678)
==6951==    by 0x4F36855: __nss_database_lookup (nsswitch.c:175)
==6951==    by 0x55F32A4: ???
==6951==    by 0x4EEF1AC: getpwnam_r@@GLIBC_2.2.5 (getXXbyYY_r.c:256)
==6951==    by 0x400607: main (in /home/daniel/dev/tryouts/getpwnam-leak)
==6951== 
==6951== LEAK SUMMARY:
==6951==    definitely lost: 60 bytes in 1 blocks
==6951==    indirectly lost: 240 bytes in 10 blocks
==6951==      possibly lost: 0 bytes in 0 blocks
==6951==    still reachable: 0 bytes in 0 blocks
==6951==         suppressed: 0 bytes in 0 blocks
==6951== 
==6951== For counts of detected and suppressed errors, rerun with: -v
==6951== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2)
daniel@senap:~/dev/tryouts$ 
Daniel
  • 3,326
  • 1
  • 13
  • 3
0

To fix this just do:

sudo sed -i s/compat/files/g /etc/nsswitch.conf

It appears that this is caused because of a bug in libnss_compat. More info at bugs.debian.org.

Carlo Pires
  • 4,606
  • 7
  • 32
  • 32