From patchwork Thu Apr 5 05:32:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: DJ Delorie X-Patchwork-Id: 895265 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=sourceware.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=libc-alpha-return-91437-incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b="xDPDqzKz"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40Gs0v5Pthz9s0W for ; Thu, 5 Apr 2018 15:32:47 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:message-id:from:to:subject; q=dns; s= default; b=EcrFb93eXhbcDfyxmW0YPatVkwPiY0BoQxRfsnwSKT7ep/GdD5h9A 6cAaSS7a7puBzaDwO6uFcWRBlTxlk5smodz/619Cv5sNaPt/FXAvXihNL6VAabKj Vclz/+7dwR5E9B7ezBV//e9CafrfXVWWnCRR+byZII0EL1TlS4u4Rk= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:message-id:from:to:subject; s=default; bh=VzDuYyY08e+1dUjpKsGZPvY05YI=; b=xDPDqzKzkzPECrvXg9XE8o2uq7BW Nj4jc+uU2kLwA6TqkyCzqny64b25kjfvcYcHSfJLlyBWbW89mFPWGG+Dbbv3BsFZ DYld02gJTLbYLlLtC3CigKL4aMGlwqnuuhH6FVDR2kj1NseJa8pitISofFlujGwL UoDVc7a70xxXgw0= Received: (qmail 108136 invoked by alias); 5 Apr 2018 05:32:41 -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 108124 invoked by uid 89); 5 Apr 2018 05:32:41 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-24.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy=dlvsym X-HELO: mx1.redhat.com Date: Thu, 05 Apr 2018 01:32:37 -0400 Message-Id: From: DJ Delorie To: libc-alpha@sourceware.org Subject: [patch] yet another memory leak, in dlfcn this time While doing the work on extracting the malloc hooks, I discovered another place where memory needs to be free'd for leak checkers. Unable to reproduce with valgrind but that might just mean valgrind uses a different technique to interpose the calls. This one triggers if you call dlfcn() during LD_PRELOAD. The hook might be a bit hacky, but then again, all the freeres hook stuff is a bit hacky. * dlfcn/Makefile: Add dlfreeres and libc_dlfreeres. * dlfcn/Versions: Add __libdl_freeres as GLIBC_PRIVATE. * dlfcn/dlerror.c (dlerror_main_freeres): New. * dlfcn/dlfreeres.c: New. * dlfcn/sdlfreeres.c: New. * malloc/set-freeres.c: Add hook for libdl.so diff --git a/dlfcn/Makefile b/dlfcn/Makefile index 56dcae0604..34f9923334 100644 --- a/dlfcn/Makefile +++ b/dlfcn/Makefile @@ -22,7 +22,7 @@ include ../Makeconfig headers := bits/dlfcn.h dlfcn.h extra-libs := libdl libdl-routines := dlopen dlclose dlsym dlvsym dlerror dladdr dladdr1 dlinfo \ - dlmopen dlfcn + dlmopen dlfcn dlfreeres routines := $(patsubst %,s%,$(filter-out dlfcn,$(libdl-routines))) elide-routines.os := $(routines) diff --git a/dlfcn/Versions b/dlfcn/Versions index 97902f0dfd..1df6925a92 100644 --- a/dlfcn/Versions +++ b/dlfcn/Versions @@ -13,5 +13,6 @@ libdl { } GLIBC_PRIVATE { _dlfcn_hook; + __libdl_freeres; } } diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c index 04dce9ddc6..8111c69dcb 100644 --- a/dlfcn/dlerror.c +++ b/dlfcn/dlerror.c @@ -215,13 +215,27 @@ static void free_key_mem (void *mem) { check_free ((struct dl_action_result *) mem); - free (mem); __libc_setspecific (key, NULL); } # ifdef SHARED +void +dlerror_main_freeres (void) +{ + void *mem; + + mem = __libc_getspecific (key); + + if (mem) + { + free (mem); + __libc_setspecific (key, NULL); + } +} +text_set_element (libdl_freeres_hooks, dlerror_main_freeres); + struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon)); libdl_hidden_data_def (_dlfcn_hook) diff --git a/dlfcn/dlfreeres.c b/dlfcn/dlfreeres.c new file mode 100644 index 0000000000..567630a2e6 --- /dev/null +++ b/dlfcn/dlfreeres.c @@ -0,0 +1,23 @@ +/* Clean up allocated libdl memory on demand. + Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +DEFINE_HOOK (libdl_freeres_hooks, (void)) + +DEFINE_HOOK_RUNNER (libdl_freeres_hooks, __libdl_freeres, (void), ()) diff --git a/dlfcn/sdlfreeres.c b/dlfcn/sdlfreeres.c new file mode 100644 index 0000000000..7347672990 --- /dev/null +++ b/dlfcn/sdlfreeres.c @@ -0,0 +1 @@ +#include "dlfreeres.c" diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c index f4a0e7bda4..a74f6bd54b 100644 --- a/malloc/set-freeres.c +++ b/malloc/set-freeres.c @@ -26,6 +26,8 @@ DEFINE_HOOK (__libc_subfreeres, (void)); symbol_set_define (__libc_freeres_ptrs); +extern __attribute__((weak)) void __libdl_freeres (void); + void __libc_freeres_fn_section __libc_freeres (void) { @@ -41,6 +43,10 @@ __libc_freeres (void) RUN_HOOK (__libc_subfreeres, ()); + /* This hooks into libdl.so's table of things-to-be-freed. */ + if (__libdl_freeres) + __libdl_freeres (); + for (p = symbol_set_first_element (__libc_freeres_ptrs); !symbol_set_end_p (__libc_freeres_ptrs, p); ++p) free (*p);