From patchwork Sat Nov 22 20:02:40 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Biggers X-Patchwork-Id: 3851 Received: (qmail 14669 invoked by alias); 22 Nov 2014 20:05:06 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 14659 invoked by uid 89); 22 Nov 2014 20:05:05 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.4 required=5.0 tests=BAYES_00, FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-ie0-f173.google.com X-Received: by 10.51.15.132 with SMTP id fo4mr4471641igd.36.1416686702397; Sat, 22 Nov 2014 12:05:02 -0800 (PST) From: Eric Biggers To: libc-alpha@sourceware.org Cc: Eric Biggers Subject: [PATCH] setenv(): fix memory leak when setting large, duplicate string Date: Sat, 22 Nov 2014 14:02:40 -0600 Message-Id: <1416686560-12666-1-git-send-email-ebiggers3@gmail.com> glibc maintains a binary tree of environment strings it malloc()ed itself. However, it's possible for it to malloc() a string, then find that an identical string is already in the tree. In this case, the memory is leaked and is not freed if the application later calls __libc_freeres(). Fix this by freeing 'new_value' when it's unneeded. Test case: #include #include int main() { char *p = calloc(100000, 1); memset(p, 'A', 99999); setenv("TESTVAR", p, 1); setenv("TESTVAR", p, 1); free(p); } Leak that was reported by valgrind: 100,008 bytes in 1 blocks are definitely lost in loss record 1 of 1 at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) by 0x4E6B3D4: __add_to_environ (setenv.c:176) by 0x4C31B8F: setenv (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) by 0x400642: main (in /mnt/tmpfs/a.out) --- stdlib/setenv.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/stdlib/setenv.c b/stdlib/setenv.c index 8de5328..3699a33 100644 --- a/stdlib/setenv.c +++ b/stdlib/setenv.c @@ -217,6 +217,13 @@ __add_to_environ (name, value, combined, replace) /* And remember the value. */ STORE_VALUE (np); } +#ifdef USE_TSEARCH + else + { + if (__glibc_unlikely (! use_alloca)) + free (new_value); + } +#endif } *ep = np;