Bug 14122 - memory leak in nss_parse_service_list()
Summary: memory leak in nss_parse_service_list()
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: 2.11
: P2 normal
Target Milestone: ---
Assignee: Paul Pluzhnikov
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-05-18 20:30 UTC by alois.schloegl
Modified: 2012-05-22 20:13 UTC (History)
3 users (show)

See Also:
Host: linux
Target: linux
Build: linux
Last reconfirmed:


Attachments
/etc/nsswitch.conf (292 bytes, text/plain)
2012-05-20 23:33 UTC, alois.schloegl
Details

Note You need to log in before you can comment on or make changes to this bug.
Description alois.schloegl 2012-05-18 20:30:07 UTC
When calling getpwuid(), a memory leak of 60 bytes is reported by valgrind. 
This is consistently reported on on debian squeeze, ubuntu 10.04, and when compiling and linking with the the latest glibc (git commit e6bdb741d11a5c408f1f162b4d649b93d8012ec9). 

Here is a minimal program for testing. 


#include <pwd.h>
main() {	
	struct passwd *q = getpwuid(geteuid());
}
Comment 1 Paul Pluzhnikov 2012-05-19 15:55:59 UTC
Please provide actual Valgrind output.

Here is what I see using current glibc git (64-bit):
...
==10335== HEAP SUMMARY:
==10335==     in use at exit: 0 bytes in 0 blocks
==10335==   total heap usage: 53 allocs, 53 frees, 7,672 bytes allocated
==10335== 
==10335== All heap blocks were freed -- no leaks are possible

same for 32-bit build.
Comment 2 alois.schloegl 2012-05-19 21:46:52 UTC
My glibc built from the git repository is not working, and these results were valid. Below are the results on my platform, using the glibc 2.11.1. 

==17631== HEAP SUMMARY:
==17631==     in use at exit: 300 bytes in 11 blocks
==17631==   total heap usage: 68 allocs, 57 frees, 9,898 bytes allocated
==17631== 
==17631== 300 (60 direct, 240 indirect) bytes in 1 blocks are definitely lost in loss record 11 of 11
==17631==    at 0x4C274A8: malloc (vg_replace_malloc.c:236)
==17631==    by 0x4F27DCA: nss_parse_service_list (nsswitch.c:622)
==17631==    by 0x4F286ED: __nss_database_lookup (nsswitch.c:164)
==17631==    by 0x55B23CF: ???
==17631==    by 0x55B4244: ???
==17631==    by 0x4ED69FC: getpwuid_r@@GLIBC_2.2.5 (getXXbyYY_r.c:253)
==17631==    by 0x4ED62EE: getpwuid (getXXbyYY.c:117)
==17631==    by 0x40058C: main (in /tmp/a.out)
==17631== 
==17631== LEAK SUMMARY:
==17631==    definitely lost: 60 bytes in 1 blocks
==17631==    indirectly lost: 240 bytes in 10 blocks
==17631==      possibly lost: 0 bytes in 0 blocks
==17631==    still reachable: 0 bytes in 0 blocks
==17631==         suppressed: 0 bytes in 0 blocks
==17631== 
==17631== For counts of detected and suppressed errors, rerun with: -v
==17631== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
Comment 3 alois.schloegl 2012-05-19 21:58:19 UTC
correction 1st sentence: 
  s/valid/invalid
Comment 4 Paul Pluzhnikov 2012-05-19 22:07:06 UTC
Thanks.

I do see several possibilities for a leak in nss_parse_service_list:

      new_service = (service_user *) malloc (sizeof (service_user)
                                             + (line - name + 1));

...

              /* Compare with known statii.  */
              if (line - name == 7)
                {
                  if (__strncasecmp (name, "SUCCESS", 7) == 0)
                    status = NSS_STATUS_SUCCESS;
                  else if (__strncasecmp (name, "UNAVAIL", 7) == 0)
                    status = NSS_STATUS_UNAVAIL;
                  else
                    return result;  /* <<< Leak? */
                }
...


What does your /etc/nsswitch.conf look like?

> My glibc built from the git repository is not working

In what way does it not work?

It might be hard to verify the fix, unless I can reproduce the leak, or you can get a git build working.
Comment 5 Paul Pluzhnikov 2012-05-19 22:16:05 UTC
I've reproduced your leak:

==14114== 300 (60 direct, 240 indirect) bytes in 1 blocks are definitely lost in loss record 14 of 14
==14114==    at 0x4C2A4D6: malloc (vg_replace_malloc.c:263)
==14114==    by 0x4F2DDCA: nss_parse_service_list (/build/buildd/eglibc-2.11.1/nss/nsswitch.c:622)
==14114==    by 0x4F2E6ED: __nss_database_lookup (/build/buildd/eglibc-2.11.1/nss/nsswitch.c:164)
==14114==    by 0x55B83CF: ???
==14114==    by 0x55BA244: ???
==14114==    by 0x4EDC9FC: getpwuid_r@@GLIBC_2.2.5 (/build/buildd/eglibc-2.11.1/pwd/../nss/getXXbyYY_r.c:253)
==14114==    by 0x4EDC2EE: getpwuid (/build/buildd/eglibc-2.11.1/pwd/../nss/getXXbyYY.c:117)
==14114==    by 0x40058C: main (/tmp/t.c:3)

by sticking an invalid entry into /etc/nsswitch.conf:

passwd:   [FOOFFOO] files cache

Also reproduces with current git trunk build:

==14568== 292 (52 direct, 240 indirect) bytes in 1 blocks are definitely lost in loss record 14 of 14
==14568==    at 0x4A0A4D6: malloc (vg_replace_malloc.c:263)
==14568==    by 0x4D09804: nss_parse_service_list (/glibc-git/nss/nsswitch.c:595)
==14568==    by 0x4D09F3B: __nss_database_lookup (/glibc-git/nss/nsswitch.c:144)
==14568==    by 0x53DD3CF: ???
==14568==    by 0x53DF244: ???
==14568==    by 0x4CC8B3B: getpwuid_r@@GLIBC_2.2.5 (/glibc-git/pwd/../nss/getXXbyYY_r.c:255)
==14568==    by 0x4CC83ED: getpwuid (/glibc-git/pwd/../nss/getXXbyYY.c:116)
==14568==    by 0x40058C: main (/tmp/t.c:3)
Comment 6 Paul Pluzhnikov 2012-05-20 16:23:50 UTC
(In reply to comment #2)

> ==17631== 300 (60 direct, 240 indirect) bytes in 1 blocks are definitely lost
> in loss record 11 of 11
> ==17631==    at 0x4C274A8: malloc (vg_replace_malloc.c:236)
> ==17631==    by 0x4F27DCA: nss_parse_service_list (nsswitch.c:622)
> ==17631==    by 0x4F286ED: __nss_database_lookup (nsswitch.c:164)

Alois,

I can only reproduce the leak using invalid nsswitch.conf entry.

What does your /etc/nsswitch.conf look like?
Comment 7 Andreas Jaeger 2012-05-20 18:39:49 UTC
Paul, looks like you're on the right track. Looking at the function it calls malloc and returns result (which might be NULL) without freeing the malloc struct. But I didn't dive deeper into it.
Comment 8 alois.schloegl 2012-05-20 23:33:20 UTC
Created attachment 6416 [details]
/etc/nsswitch.conf

Attached is the /etc/nsswitch.conf on my systems. It came with Debian/squeeze and Ubuntu 10.04, I did not change it. 

  Alois 


P.S.: I tried to built the latest glibc. In userspace, make failed in the following way: 
... 
/bin/sh ../scripts/rellns-sh /home/schloegl/glibc/lib/libnss_files.so.2 /home/schloegl/glibc/lib/libnss_files.so.new
mv -f /home/schloegl/glibc/lib/libnss_files.so.new /home/schloegl/glibc/lib/libnss_files.so
/usr/bin/install -c /home/schloegl/src/glibc_built/nss/libnss_db.so /home/schloegl/glibc/lib/libnss_db-2.15.90.so.new
mv -f /home/schloegl/glibc/lib/libnss_db-2.15.90.so.new /home/schloegl/glibc/lib/libnss_db-2.15.90.so
echo libnss_db-2.15.90.so /home/schloegl/glibc/lib/libnss_db.so.2 >> /home/schloegl/src/glibc_built/elf/symlink.list
rm -f /home/schloegl/glibc/lib/libnss_db.so.new
/bin/sh ../scripts/rellns-sh /home/schloegl/glibc/lib/libnss_db.so.2 /home/schloegl/glibc/lib/libnss_db.so.new
mv -f /home/schloegl/glibc/lib/libnss_db.so.new /home/schloegl/glibc/lib/libnss_db.so
.././scripts/mkinstalldirs /var/db
mkdir /var/db
mkdir: cannot create directory `/var/db': Permission denied
make[2]: *** [/var/db/Makefile] Error 1
make[2]: Leaving directory `/home/schloegl/src/glibc/nss'
make[1]: *** [nss/subdir_install] Error 2
make[1]: Leaving directory `/home/schloegl/src/glibc'
make: *** [install] Error 2

Compiling the test file according to 
  http://sourceware.org/glibc/wiki/Testing/Builds
failed in this way: 

$ gcc q.c -I /home/schloegl/glibc/include/ --sysroot=${SYSROOT}   -Wl,-rpath=${SYSROOT}/lib   -Wl,--dynamic-linker=${SYSROOT}/lib/ld.so.1
In file included from /home/schloegl/glibc/include/features.h:399,
                 from /home/schloegl/glibc/include/pwd.h:26,
                 from q.c:3:
/home/schloegl/glibc/include/gnu/stubs.h:9:27: error: gnu/stubs-64.h: No such file or directory
Comment 9 Paul Pluzhnikov 2012-05-21 01:13:11 UTC
I sent a patch to handle leaks on error paths:
http://sourceware.org/ml/libc-alpha/2012-05/msg01433.html

However, with the patch applied, using Alois's copy of nsswitch.conf, or just completely empty nsswitch.conf, I still see the leak.

It's kind of a false positive, and I am not sure we can reasonably do anything about it.

The problem is this code in nss/getXXbyYY_r.c:

   152    static service_user *startp;
...
   230            tmp_ptr = nip;
   231            PTR_MANGLE (tmp_ptr);
   232            startp = tmp_ptr;

That is, the returned (allocated) value is in "nip" variable, and it gets saved into startp (static), so it is not a leak.

But it is saved in mangled form, which makes that invisible to Valgrind.

Perhaps we should free PTR_DEMANGLE(startp) on __libc_freeres ?
Comment 10 Paul Pluzhnikov 2012-05-21 05:15:44 UTC
(In reply to comment #9)

> Perhaps we should free PTR_DEMANGLE(startp) on __libc_freeres ?

No, that wasn't the right solution.

Better patch that fixes the leak from empty nsswitch.conf, and
also from Alois's copy:

http://sourceware.org/ml/libc-alpha/2012-05/msg01435.html