bug-gnulib@gnu.org mirror (unofficial)
 help / color / mirror / Atom feed
* di-set: Fix memory leak
@ 2019-03-10 13:20 Bruno Haible
  2019-04-18 21:15 ` Bernhard Voelker
  0 siblings, 1 reply; 4+ messages in thread
From: Bruno Haible @ 2019-03-10 13:20 UTC (permalink / raw)
  To: bug-gnulib

Building a gnulib testdir with CC="gcc -fsanitize=leak", I see this finding
in 'test-di-set':

ERROR: LeakSanitizer: detected memory leaks

Direct leak of 80 byte(s) in 1 object(s) allocated from:
    #0 0x7f874eea8858 in __interceptor_malloc ../../../../gcc-8.2.0/libsanitizer/lsan/lsan_interceptors.cc:52
    #1 0x401aee in hash_initialize ../../gllib/hash.c:605

Direct leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x7f874eea8858 in __interceptor_malloc ../../../../gcc-8.2.0/libsanitizer/lsan/lsan_interceptors.cc:52
    #1 0x40259e in ino_map_insert ../../gllib/ino-map.c:133

Indirect leak of 20432 byte(s) in 1 object(s) allocated from:
    #0 0x7f874eea9404 in __interceptor_calloc ../../../../gcc-8.2.0/libsanitizer/lsan/lsan_interceptors.cc:74
    #1 0x401b59 in hash_initialize ../../gllib/hash.c:626

Indirect leak of 32 byte(s) in 2 object(s) allocated from:
    #0 0x7f874eea8858 in __interceptor_malloc ../../../../gcc-8.2.0/libsanitizer/lsan/lsan_interceptors.cc:52
    #1 0x40259e in ino_map_insert ../../gllib/ino-map.c:133

SUMMARY: LeakSanitizer: 20560 byte(s) leaked in 5 allocation(s).
FAIL test-di-set (exit status: 23)


It is confirmed by valgrind:

$ valgrind --tool=memcheck --num-callers=20 --leak-check=yes --leak-resolution=high --show-reachable=yes ./test-di-set 
==5309== Memcheck, a memory error detector
==5309== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==5309== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==5309== Command: ./test-di-set
==5309== 
==5309== 
==5309== HEAP SUMMARY:
==5309==     in use at exit: 20,560 bytes in 5 blocks
==5309==   total heap usage: 27 allocs, 22 frees, 314,688 bytes allocated
==5309== 
==5309== 16 bytes in 1 blocks are indirectly lost in loss record 1 of 5
==5309==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5309==    by 0x40202E: ino_map_insert (ino-map.c:133)
==5309==    by 0x400BDF: di_set_insert (di-set.c:231)
==5309==    by 0x40073A: main (test-di-set.c:39)
==5309== 
==5309== 16 bytes in 1 blocks are indirectly lost in loss record 2 of 5
==5309==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5309==    by 0x40202E: ino_map_insert (ino-map.c:133)
==5309==    by 0x400BDF: di_set_insert (di-set.c:231)
==5309==    by 0x400757: main (test-di-set.c:40)
==5309== 
==5309== 16 bytes in 1 blocks are definitely lost in loss record 3 of 5
==5309==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5309==    by 0x40202E: ino_map_insert (ino-map.c:133)
==5309==    by 0x400BDF: di_set_insert (di-set.c:231)
==5309==    by 0x40079F: main (test-di-set.c:47)
==5309== 
==5309== 20,432 bytes in 1 blocks are indirectly lost in loss record 4 of 5
==5309==    at 0x4C2FB55: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5309==    by 0x401563: hash_initialize (hash.c:626)
==5309==    by 0x401F96: ino_map_alloc (ino-map.c:90)
==5309==    by 0x400AEB: map_inode_number.isra.1 (di-set.c:208)
==5309==    by 0x400BDF: di_set_insert (di-set.c:231)
==5309==    by 0x40073A: main (test-di-set.c:39)
==5309== 
==5309== 20,544 (80 direct, 20,464 indirect) bytes in 1 blocks are definitely lost in loss record 5 of 5
==5309==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5309==    by 0x4014EE: hash_initialize (hash.c:605)
==5309==    by 0x401F96: ino_map_alloc (ino-map.c:90)
==5309==    by 0x400AEB: map_inode_number.isra.1 (di-set.c:208)
==5309==    by 0x400BDF: di_set_insert (di-set.c:231)
==5309==    by 0x40073A: main (test-di-set.c:39)
==5309== 
==5309== LEAK SUMMARY:
==5309==    definitely lost: 96 bytes in 2 blocks
==5309==    indirectly lost: 20,464 bytes in 3 blocks
==5309==      possibly lost: 0 bytes in 0 blocks
==5309==    still reachable: 0 bytes in 0 blocks
==5309==         suppressed: 0 bytes in 0 blocks
==5309== 
==5309== For counts of detected and suppressed errors, rerun with: -v
==5309== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)


This patch fixes it.


2019-03-10  Bruno Haible  <bruno@clisp.org>

	di-set: Fix memory leak.
	* lib/di-set.c (di_set_free): Free the ino_map through ino_map_free(),
	not free().

diff --git a/lib/di-set.c b/lib/di-set.c
index e8f69db..2c0601e 100644
--- a/lib/di-set.c
+++ b/lib/di-set.c
@@ -136,7 +136,7 @@ void
 di_set_free (struct di_set *dis)
 {
   hash_free (dis->dev_map);
-  free (dis->ino_map);
+  ino_map_free (dis->ino_map);
   free (dis->probe);
   free (dis);
 }



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: di-set: Fix memory leak
  2019-03-10 13:20 di-set: Fix memory leak Bruno Haible
@ 2019-04-18 21:15 ` Bernhard Voelker
  2019-04-18 21:42   ` Bruno Haible
  0 siblings, 1 reply; 4+ messages in thread
From: Bernhard Voelker @ 2019-04-18 21:15 UTC (permalink / raw)
  To: Bruno Haible, bug-gnulib

[-- Attachment #1: Type: text/plain, Size: 1519 bytes --]

On 3/10/19 2:20 PM, Bruno Haible wrote:
> 2019-03-10  Bruno Haible  <bruno@clisp.org>
> 
> 	di-set: Fix memory leak.
> 	* lib/di-set.c (di_set_free): Free the ino_map through ino_map_free(),
> 	not free().
> 
> diff --git a/lib/di-set.c b/lib/di-set.c
> index e8f69db..2c0601e 100644
> --- a/lib/di-set.c
> +++ b/lib/di-set.c
> @@ -136,7 +136,7 @@ void
>  di_set_free (struct di_set *dis)
>  {
>    hash_free (dis->dev_map);
> -  free (dis->ino_map);
> +  ino_map_free (dis->ino_map);
>    free (dis->probe);
>    free (dis);
>  }

This commit (3703dbbe88dd) makes coreutils' du(1) crash.

Reproducer:
---------------------------------------------------------
#!/bin/sh
set -x
git clone --depth=1 git://git.sv.gnu.org/gnulib.git \
  && cd gnulib \
  && rm -rf /tmp/testdir/ \
  && ./gnulib-tool --create-testdir --with-tests --dir=/tmp/testdir di-set \
  && cd /tmp/testdir \
  && ./configure --quiet \
  && make \
  && patch -p0 --fuzz=0 <<<'\
--- gltests/test-di-set.c.ORIG	2019-04-10 08:23:09.663882510 +0200
+++ gltests/test-di-set.c	2019-04-18 22:27:57.778264454 +0200
@@ -27,6 +27,9 @@
 {
   struct di_set *dis = di_set_alloc ();
   ASSERT (dis);
+  di_set_free (dis);
+  dis = di_set_alloc ();
+  ASSERT (dis);

   ASSERT (di_set_lookup (dis, 2, 5) == 0); /* initial lookup fails */
   ASSERT (di_set_insert (dis, 2, 5) == 1); /* first insertion succeeds */
' \
&& make check
---------------------------------------------------------

The attached allows for 'ino-map' to free on NULL.

Have a nice day,
Berny



[-- Attachment #2: 0001-ino-map-allow-free-on-NULL.patch --]
[-- Type: text/x-patch, Size: 1303 bytes --]

From c6f24d39f25cbedfba6f728da48e9666d7240894 Mon Sep 17 00:00:00 2001
From: Bernhard Voelker <mail@bernhard-voelker.de>
Date: Thu, 18 Apr 2019 23:04:26 +0200
Subject: [PATCH] ino-map: allow free on NULL

* lib/ino-map.c (ino_map_free): Do nothing when MAP is NULL.
Since commit 3703dbbe88dd, di_set_free calls ino_map_free which may
be NULL.
---
 ChangeLog     | 7 +++++++
 lib/ino-map.c | 9 ++++++---
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 398c33968..1d96402d8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2019-04-18  Bernhard Voelker  <mail@bernhard-voelker.de>
+
+	ino-map: allow free on NULL.
+	* lib/ino-map.c (ino_map_free): Do nothing when MAP is NULL.
+	Since commit 3703dbbe88dd, di_set_free calls ino_map_free which may
+	be NULL.
+
 2019-04-14  Paul Eggert  <eggert@cs.ucla.edu>
 
 	* lib/str-two-way.h: Fix comment typo.
diff --git a/lib/ino-map.c b/lib/ino-map.c
index c48defa65..9d6bd0894 100644
--- a/lib/ino-map.c
+++ b/lib/ino-map.c
@@ -105,9 +105,12 @@ ino_map_alloc (size_t next_mapped_ino)
 void
 ino_map_free (struct ino_map *map)
 {
-  hash_free (map->map);
-  free (map->probe);
-  free (map);
+  if (map)
+    {
+      hash_free (map->map);
+      free (map->probe);
+      free (map);
+    }
 }
 
 
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: di-set: Fix memory leak
  2019-04-18 21:15 ` Bernhard Voelker
@ 2019-04-18 21:42   ` Bruno Haible
  2019-04-18 22:06     ` Bernhard Voelker
  0 siblings, 1 reply; 4+ messages in thread
From: Bruno Haible @ 2019-04-18 21:42 UTC (permalink / raw)
  To: Bernhard Voelker, bug-gnulib

Hi Berny,

I would prefer to see the fix in lib/di-set.c, not lib/ino-map.c.
Rationale: in 99% of the uses of the 'ino-map' module, the NULL
check is not needed.

The change to tests/test-di-set.c looks good. If you can commit
that as well?

Thanks.

Apologies for the bug.

Bruno


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: di-set: Fix memory leak
  2019-04-18 21:42   ` Bruno Haible
@ 2019-04-18 22:06     ` Bernhard Voelker
  0 siblings, 0 replies; 4+ messages in thread
From: Bernhard Voelker @ 2019-04-18 22:06 UTC (permalink / raw)
  To: Bruno Haible, bug-gnulib

[-- Attachment #1: Type: text/plain, Size: 482 bytes --]

Hi Bruno,

On 4/18/19 11:42 PM, Bruno Haible wrote:
> I would prefer to see the fix in lib/di-set.c, not lib/ino-map.c.
> Rationale: in 99% of the uses of the 'ino-map' module, the NULL
> check is not needed.

Fine by me. ;-)

BTW: the _GL_ATTRIBUTE_NONNULL decl of ino_map_free would have
made problems anyway ...

> The change to tests/test-di-set.c looks good. If you can commit
> that as well?

Sure, thanks - new patch attached - du(1) works again. ;-)

Have a nice day,
Berny

[-- Attachment #2: 0001-di-set-allow-free-with-ino_map-being-NULL.patch --]
[-- Type: text/x-patch, Size: 1923 bytes --]

From 22b911f63ca11395f03ce2ce3cc0b371a37a576d Mon Sep 17 00:00:00 2001
From: Bernhard Voelker <mail@bernhard-voelker.de>
Date: Thu, 18 Apr 2019 23:04:26 +0200
Subject: [PATCH] di-set: allow free with 'ino_map' being NULL

* lib/di-set.c (di_set_free): Avoid ino_map_free() when dis->ino_map
is NULL.  Bug introduced in commit 3703dbbe88dd.
* tests/test-di-set.c: Add di_set_free() right after di_set_alloc()
as a test.
---
 ChangeLog           | 8 ++++++++
 lib/di-set.c        | 3 ++-
 tests/test-di-set.c | 3 +++
 3 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index 398c33968..916d154eb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2019-04-18  Bernhard Voelker  <mail@bernhard-voelker.de>
+
+	di-set: allow free with 'ino_map' being NULL.
+	* lib/di-set.c (di_set_free): Avoid ino_map_free() when dis->ino_map
+	is NULL.  Bug introduced in commit 3703dbbe88dd.
+	* tests/test-di-set.c: Add di_set_free() right after di_set_alloc()
+	as a test.
+
 2019-04-14  Paul Eggert  <eggert@cs.ucla.edu>
 
 	* lib/str-two-way.h: Fix comment typo.
diff --git a/lib/di-set.c b/lib/di-set.c
index 2c0601e03..47ade5821 100644
--- a/lib/di-set.c
+++ b/lib/di-set.c
@@ -136,7 +136,8 @@ void
 di_set_free (struct di_set *dis)
 {
   hash_free (dis->dev_map);
-  ino_map_free (dis->ino_map);
+  if (dis->ino_map)
+    ino_map_free (dis->ino_map);
   free (dis->probe);
   free (dis);
 }
diff --git a/tests/test-di-set.c b/tests/test-di-set.c
index 6887be3b6..0f492c837 100644
--- a/tests/test-di-set.c
+++ b/tests/test-di-set.c
@@ -27,6 +27,9 @@ main (void)
 {
   struct di_set *dis = di_set_alloc ();
   ASSERT (dis);
+  di_set_free (dis); /* free with dis->ino_map still being NULL */
+  dis = di_set_alloc ();
+  ASSERT (dis);
 
   ASSERT (di_set_lookup (dis, 2, 5) == 0); /* initial lookup fails */
   ASSERT (di_set_insert (dis, 2, 5) == 1); /* first insertion succeeds */
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2019-04-18 22:06 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-10 13:20 di-set: Fix memory leak Bruno Haible
2019-04-18 21:15 ` Bernhard Voelker
2019-04-18 21:42   ` Bruno Haible
2019-04-18 22:06     ` Bernhard Voelker

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).