From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from bee.birch.relay.mailchannels.net (bee.birch.relay.mailchannels.net [23.83.209.14]) by sourceware.org (Postfix) with ESMTPS id 94CAB386FC0E for ; Mon, 5 Jul 2021 17:09:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 94CAB386FC0E X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 158298411C3; Mon, 5 Jul 2021 17:09:04 +0000 (UTC) Received: from pdx1-sub0-mail-a29.g.dreamhost.com (100-101-162-64.trex.outbound.svc.cluster.local [100.101.162.64]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 663DA841030; Mon, 5 Jul 2021 17:09:03 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a29.g.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384) by 100.101.162.64 (trex/6.3.3); Mon, 05 Jul 2021 17:09:03 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Attack-Illegal: 28771b7a47de5483_1625504943755_3644658552 X-MC-Loop-Signature: 1625504943755:2021028319 X-MC-Ingress-Time: 1625504943755 Received: from pdx1-sub0-mail-a29.g.dreamhost.com (localhost [127.0.0.1]) by pdx1-sub0-mail-a29.g.dreamhost.com (Postfix) with ESMTP id F25A77F058; Mon, 5 Jul 2021 10:09:02 -0700 (PDT) Received: from rhbox.intra.reserved-bit.com (unknown [1.186.101.110]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a29.g.dreamhost.com (Postfix) with ESMTPSA id CE3627E4A5; Mon, 5 Jul 2021 10:08:59 -0700 (PDT) X-DH-BACKEND: pdx1-sub0-mail-a29 From: Siddhesh Poyarekar To: libc-alpha@sourceware.org Cc: dj@redhat.com, carlos@redhat.com, fweimer@redhat.com Subject: [PATCH v5 2/8] mcheck: Wean away from malloc hooks Date: Mon, 5 Jul 2021 22:38:08 +0530 Message-Id: <20210705170814.4132997-3-siddhesh@sourceware.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210705170814.4132997-1-siddhesh@sourceware.org> References: <20210705170814.4132997-1-siddhesh@sourceware.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-3494.4 required=5.0 tests=BAYES_00, GIT_PATCH_0, JMQ_SPF_NEUTRAL, KAM_DMARC_NONE, KAM_DMARC_STATUS, KAM_SHORT, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NEUTRAL, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 05 Jul 2021 17:09:09 -0000 Split the mcheck implementation into the debugging hooks and API so that the API can be replicated in libc and libc_malloc_debug.so. The libc APIs always result in failure. The mcheck implementation has also been moved entirely into libc_malloc_debug.so and its initialization is now dependent upon whether the debug versions of malloc, realloc, etc. were called or not. That is, it no longer depends on __malloc_initialized and consequently, on any internal glibc constructs. --- include/mcheck.h | 4 - malloc/Makefile | 2 - malloc/hooks.c | 1 - malloc/malloc-debug.c | 112 ++++++++++-- malloc/mcheck-impl.c | 406 ++++++++++++++++++++++++++++++++++++++++++ malloc/mcheck.c | 397 +++-------------------------------------- 6 files changed, 527 insertions(+), 395 deletions(-) create mode 100644 malloc/mcheck-impl.c diff --git a/include/mcheck.h b/include/mcheck.h index 8883c3d53e..5ad7cd1313 100644 --- a/include/mcheck.h +++ b/include/mcheck.h @@ -3,9 +3,5 @@ #include =20 # ifndef _ISOMAC - -libc_hidden_proto (mcheck) -libc_hidden_proto (mcheck_check_all) - # endif /* !_ISOMAC */ #endif diff --git a/malloc/Makefile b/malloc/Makefile index deff659d34..b1c8e3c9e0 100644 --- a/malloc/Makefile +++ b/malloc/Makefile @@ -90,8 +90,6 @@ tests-exclude-mcheck =3D tst-mallocstate \ tst-malloc-thread-fail \ tst-malloc-usable-tunables \ tst-malloc_info \ - tst-memalign \ - tst-posix_memalign \ tst-compathooks-off tst-compathooks-on =20 tests-mcheck =3D $(filter-out $(tests-exclude-mcheck), $(tests)) diff --git a/malloc/hooks.c b/malloc/hooks.c index b18c2b8c90..d924e35e6f 100644 --- a/malloc/hooks.c +++ b/malloc/hooks.c @@ -59,7 +59,6 @@ generic_hook_ini (void) if (hook !=3D NULL) (*hook)(); #endif - __malloc_initialized =3D 1; } =20 static void * diff --git a/malloc/malloc-debug.c b/malloc/malloc-debug.c index 1c80c33f43..daf48e0633 100644 --- a/malloc/malloc-debug.c +++ b/malloc/malloc-debug.c @@ -43,6 +43,35 @@ DEBUG_FN(valloc); DEBUG_FN(pvalloc); DEBUG_FN(calloc); =20 +static bool malloc_called; + +enum malloc_debug_hooks +{ + MALLOC_NONE_HOOK =3D 0, + MALLOC_MCHECK_HOOK =3D 1 << 0, /* mcheck() */ +}; +static unsigned __malloc_debugging_hooks; + +static __always_inline bool +__is_malloc_debug_enabled (enum malloc_debug_hooks flag) +{ + return __malloc_debugging_hooks & flag; +} + +static __always_inline void +__malloc_debug_enable (enum malloc_debug_hooks flag) +{ + __malloc_debugging_hooks |=3D flag; +} + +static __always_inline void +__malloc_debug_disable (enum malloc_debug_hooks flag) +{ + __malloc_debugging_hooks &=3D ~flag; +} + +#include "mcheck.c" + extern void (*__free_hook) (void *, const void *); compat_symbol_reference (libc, __free_hook, __free_hook, GLIBC_2_0); extern void * (*__malloc_hook) (size_t, const void *); @@ -63,7 +92,19 @@ __debug_malloc (size_t bytes) if (__builtin_expect (hook !=3D NULL, 0)) return (*hook)(bytes, RETURN_ADDRESS (0)); =20 - return __libc_malloc (bytes); + malloc_called =3D true; + + void *victim =3D NULL; + size_t orig_bytes =3D bytes; + if (!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) + || !malloc_mcheck_before (&bytes, &victim)) + { + victim =3D __libc_malloc (bytes); + } + if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && victim !=3D NULL= ) + victim =3D malloc_mcheck_after (victim, orig_bytes); + + return victim; } strong_alias (__debug_malloc, malloc) =20 @@ -76,6 +117,10 @@ __debug_free (void *mem) (*hook)(mem, RETURN_ADDRESS (0)); return; } + + if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)) + mem =3D free_mcheck (mem); + __libc_free (mem); } strong_alias (__debug_free, free) @@ -88,7 +133,21 @@ __debug_realloc (void *oldmem, size_t bytes) if (__builtin_expect (hook !=3D NULL, 0)) return (*hook)(oldmem, bytes, RETURN_ADDRESS (0)); =20 - return __libc_realloc (oldmem, bytes); + malloc_called =3D true; + + size_t orig_bytes =3D bytes, oldsize =3D 0; + void *victim =3D NULL; + + if (!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) + || !realloc_mcheck_before (&oldmem, &bytes, &oldsize, &victim)) + { + victim =3D __libc_realloc (oldmem, bytes); + } + if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && victim !=3D NULL= ) + victim =3D realloc_mcheck_after (victim, oldmem, orig_bytes, + oldsize); + + return victim; } strong_alias (__debug_realloc, realloc) =20 @@ -100,7 +159,20 @@ _mid_memalign (size_t alignment, size_t bytes, const= void *address) if (__builtin_expect (hook !=3D NULL, 0)) return (*hook)(alignment, bytes, address); =20 - return __libc_memalign (alignment, bytes); + malloc_called =3D true; + + void *victim =3D NULL; + size_t orig_bytes =3D bytes; + + if (!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) + || !memalign_mcheck_before (alignment, &bytes, &victim)) + { + victim =3D __libc_memalign (alignment, bytes); + } + if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && victim !=3D NULL= ) + victim =3D memalign_mcheck_after (victim, alignment, orig_bytes); + + return victim; } =20 static void * @@ -165,17 +237,17 @@ strong_alias (__debug_posix_memalign, posix_memalig= n) static void * __debug_calloc (size_t nmemb, size_t size) { + size_t bytes; + + if (__glibc_unlikely (__builtin_mul_overflow (nmemb, size, &bytes))) + { + errno =3D ENOMEM; + return NULL; + } + void *(*hook) (size_t, const void *) =3D atomic_forced_read (__malloc_= hook); if (__builtin_expect (hook !=3D NULL, 0)) { - size_t bytes; - - if (__glibc_unlikely (__builtin_mul_overflow (nmemb, size, &bytes)= )) - { - errno =3D ENOMEM; - return NULL; - } - void *mem =3D (*hook)(bytes, RETURN_ADDRESS (0)); =20 if (mem !=3D NULL) @@ -184,6 +256,22 @@ __debug_calloc (size_t nmemb, size_t size) return mem; } =20 - return __libc_calloc (nmemb, size); + malloc_called =3D true; + + size_t orig_bytes =3D bytes; + void *victim =3D NULL; + + if (!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) + || !malloc_mcheck_before (&bytes, &victim)) + { + victim =3D __libc_malloc (bytes); + } + if (victim !=3D NULL) + { + if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)) + victim =3D malloc_mcheck_after (victim, orig_bytes); + memset (victim, 0, orig_bytes); + } + return victim; } strong_alias (__debug_calloc, calloc) diff --git a/malloc/mcheck-impl.c b/malloc/mcheck-impl.c new file mode 100644 index 0000000000..0b96fdabda --- /dev/null +++ b/malloc/mcheck-impl.c @@ -0,0 +1,406 @@ +/* mcheck debugging hooks for malloc. + Copyright (C) 1990-2021 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written May 1989 by Mike Haertel. + + 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 +#include +#include +#include +#include + +/* Arbitrary magical numbers. */ +#define MAGICWORD 0xfedabeeb +#define MAGICFREE 0xd8675309 +#define MAGICBYTE ((char) 0xd7) +#define MALLOCFLOOD ((char) 0x93) +#define FREEFLOOD ((char) 0x95) + +/* Function to call when something awful happens. */ +static void (*abortfunc) (enum mcheck_status); + +struct hdr +{ + size_t size; /* Exact size requested by user. */ + unsigned long int magic; /* Magic number to check header integrit= y. */ + struct hdr *prev; + struct hdr *next; + void *block; /* Real block allocated, for memalign. = */ + unsigned long int magic2; /* Extra, keeps us doubleword aligned. = */ +}; + +/* This is the beginning of the list of all memory blocks allocated. + It is only constructed if the pedantic testing is requested. */ +static struct hdr *__mcheck_root; + +/* Nonzero if pedentic checking of all blocks is requested. */ +static bool pedantic; + +#if defined _LIBC || defined STDC_HEADERS || defined USG +# include +# define flood memset +#else +static void flood (void *, int, size_t); +static void +flood (void *ptr, int val, size_t size) +{ + char *cp =3D ptr; + while (size--) + *cp++ =3D val; +} +#endif + +static enum mcheck_status +checkhdr (const struct hdr *hdr) +{ + enum mcheck_status status; + bool mcheck_used =3D __is_malloc_debug_enabled (MALLOC_MCHECK_HOOK); + + if (!mcheck_used) + /* Maybe the mcheck used is disabled? This happens when we find + an error and report it. */ + return MCHECK_OK; + + switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next)) + { + default: + status =3D MCHECK_HEAD; + break; + case MAGICFREE: + status =3D MCHECK_FREE; + break; + case MAGICWORD: + if (((char *) &hdr[1])[hdr->size] !=3D MAGICBYTE) + status =3D MCHECK_TAIL; + else if ((hdr->magic2 ^ (uintptr_t) hdr->block) !=3D MAGICWORD) + status =3D MCHECK_HEAD; + else + status =3D MCHECK_OK; + break; + } + if (status !=3D MCHECK_OK) + { + mcheck_used =3D 0; + (*abortfunc) (status); + mcheck_used =3D 1; + } + return status; +} + +static enum mcheck_status +__mcheck_checkptr (const void *ptr) +{ + if (!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)) + return MCHECK_DISABLED; + + if (ptr !=3D NULL) + return checkhdr (((struct hdr *) ptr) - 1); + + /* Walk through all the active blocks and test whether they were tampe= red + with. */ + struct hdr *runp =3D __mcheck_root; + + /* Temporarily turn off the checks. */ + pedantic =3D false; + + while (runp !=3D NULL) + { + (void) checkhdr (runp); + + runp =3D runp->next; + } + + /* Turn checks on again. */ + pedantic =3D true; + + return MCHECK_OK; +} + +static void +unlink_blk (struct hdr *ptr) +{ + if (ptr->next !=3D NULL) + { + ptr->next->prev =3D ptr->prev; + ptr->next->magic =3D MAGICWORD ^ ((uintptr_t) ptr->next->prev + + (uintptr_t) ptr->next->next); + } + if (ptr->prev !=3D NULL) + { + ptr->prev->next =3D ptr->next; + ptr->prev->magic =3D MAGICWORD ^ ((uintptr_t) ptr->prev->prev + + (uintptr_t) ptr->prev->next); + } + else + __mcheck_root =3D ptr->next; +} + +static void +link_blk (struct hdr *hdr) +{ + hdr->prev =3D NULL; + hdr->next =3D __mcheck_root; + __mcheck_root =3D hdr; + hdr->magic =3D MAGICWORD ^ (uintptr_t) hdr->next; + + /* And the next block. */ + if (hdr->next !=3D NULL) + { + hdr->next->prev =3D hdr; + hdr->next->magic =3D MAGICWORD ^ ((uintptr_t) hdr + + (uintptr_t) hdr->next->next); + } +} + +static void * +free_mcheck (void *ptr) +{ + if (pedantic) + __mcheck_checkptr (NULL); + if (ptr) + { + struct hdr *hdr =3D ((struct hdr *) ptr) - 1; + checkhdr (hdr); + hdr->magic =3D MAGICFREE; + hdr->magic2 =3D MAGICFREE; + unlink_blk (hdr); + hdr->prev =3D hdr->next =3D NULL; + flood (ptr, FREEFLOOD, hdr->size); + ptr =3D hdr->block; + } + return ptr; +} + +static bool +malloc_mcheck_before (size_t *sizep, void **victimp) +{ + size_t size =3D *sizep; + + if (pedantic) + __mcheck_checkptr (NULL); + + if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1)) + { + __set_errno (ENOMEM); + *victimp =3D NULL; + return true; + } + + *sizep =3D sizeof (struct hdr) + size + 1; + return false; +} + +static void * +malloc_mcheck_after (void *mem, size_t size) +{ + struct hdr *hdr =3D mem; + + if (hdr =3D=3D NULL) + return NULL; + + hdr->size =3D size; + link_blk (hdr); + hdr->block =3D hdr; + hdr->magic2 =3D (uintptr_t) hdr ^ MAGICWORD; + ((char *) &hdr[1])[size] =3D MAGICBYTE; + flood ((void *) (hdr + 1), MALLOCFLOOD, size); + return (void *) (hdr + 1); +} + +static bool +memalign_mcheck_before (size_t alignment, size_t *sizep, void **victimp) +{ + struct hdr *hdr; + size_t slop, size =3D *sizep; + + /* Punt to malloc to avoid double headers. */ + if (alignment <=3D MALLOC_ALIGNMENT) + { + *victimp =3D __debug_malloc (size); + return true; + } + + if (pedantic) + __mcheck_checkptr (NULL); + + slop =3D (sizeof *hdr + alignment - 1) & - alignment; + + if (size > ~((size_t) 0) - (slop + 1)) + { + __set_errno (ENOMEM); + *victimp =3D NULL; + return true; + } + + *sizep =3D slop + size + 1; + return false; +} + +static void * +memalign_mcheck_after (void *block, size_t alignment, size_t size) +{ + if (block =3D=3D NULL) + return NULL; + + /* This was served by __debug_malloc, so return as is. */ + if (alignment <=3D MALLOC_ALIGNMENT) + return block; + + size_t slop =3D (sizeof (struct hdr) + alignment - 1) & - alignment; + struct hdr *hdr =3D ((struct hdr *) (block + slop)) - 1; + + hdr->size =3D size; + link_blk (hdr); + hdr->block =3D (void *) block; + hdr->magic2 =3D (uintptr_t) block ^ MAGICWORD; + ((char *) &hdr[1])[size] =3D MAGICBYTE; + flood ((void *) (hdr + 1), MALLOCFLOOD, size); + return (void *) (hdr + 1); +} + +static bool +realloc_mcheck_before (void **ptrp, size_t *sizep, size_t *oldsize, + void **victimp) +{ + size_t size =3D *sizep; + void *ptr =3D *ptrp; + + if (size =3D=3D 0) + { + __debug_free (ptr); + *victimp =3D NULL; + return true; + } + + if (ptr =3D=3D NULL) + { + *victimp =3D __debug_malloc (size); + *oldsize =3D 0; + return true; + } + + if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1)) + { + __set_errno (ENOMEM); + *victimp =3D NULL; + *oldsize =3D 0; + return true; + } + + if (pedantic) + __mcheck_checkptr (NULL); + + struct hdr *hdr; + size_t osize; + + /* Update the oldptr for glibc realloc. */ + *ptrp =3D hdr =3D ((struct hdr *) ptr) - 1; + + osize =3D hdr->size; + + checkhdr (hdr); + unlink_blk (hdr); + if (size < osize) + flood ((char *) ptr + size, FREEFLOOD, osize - size); + + *oldsize =3D osize; + *sizep =3D sizeof (struct hdr) + size + 1; + return false; +} + +static void * +realloc_mcheck_after (void *ptr, void *oldptr, size_t size, size_t osize= ) +{ + struct hdr *hdr =3D ptr; + + if (hdr =3D=3D NULL) + return NULL; + + /* Malloc already added the header so don't tamper with it. */ + if (oldptr =3D=3D NULL) + return ptr; + + hdr->size =3D size; + link_blk (hdr); + hdr->block =3D hdr; + hdr->magic2 =3D (uintptr_t) hdr ^ MAGICWORD; + ((char *) &hdr[1])[size] =3D MAGICBYTE; + if (size > osize) + flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize); + return (void *) (hdr + 1); +} + +__attribute__ ((noreturn)) +static void +mabort (enum mcheck_status status) +{ + const char *msg; + switch (status) + { + case MCHECK_OK: + msg =3D _ ("memory is consistent, library is buggy\n"); + break; + case MCHECK_HEAD: + msg =3D _ ("memory clobbered before allocated block\n"); + break; + case MCHECK_TAIL: + msg =3D _ ("memory clobbered past end of allocated block\n"); + break; + case MCHECK_FREE: + msg =3D _ ("block freed twice\n"); + break; + default: + msg =3D _ ("bogus mcheck_status, library is buggy\n"); + break; + } +#ifdef _LIBC + __libc_fatal (msg); +#else + fprintf (stderr, "mcheck: %s", msg); + fflush (stderr); + abort (); +#endif +} + +/* Memory barrier so that GCC does not optimize out the argument. */ +#define malloc_opt_barrier(x) \ + ({ __typeof (x) __x =3D x; __asm ("" : "+m" (__x)); __x; }) + +static int +__mcheck_initialize (void (*func) (enum mcheck_status), bool in_pedantic= ) +{ + abortfunc =3D (func !=3D NULL) ? func : &mabort; + + if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)) + goto out; + + /* There was a call to malloc before this initializer was called. */ + if (malloc_called) + return -1; + + /* We call malloc() once here to ensure it is initialized. */ + void *p =3D malloc (0); + /* GCC might optimize out the malloc/free pair without a barrier. */ + p =3D malloc_opt_barrier (p); + free (p); + /* FALLTHROUGH */ + __malloc_debug_enable (MALLOC_MCHECK_HOOK); + +out: + pedantic =3D in_pedantic; + return 0; +} diff --git a/malloc/mcheck.c b/malloc/mcheck.c index b46b9b26bf..74c20ffe25 100644 --- a/malloc/mcheck.c +++ b/malloc/mcheck.c @@ -1,4 +1,4 @@ -/* Standard debugging hooks for `malloc'. +/* The mcheck() interface. Copyright (C) 1990-2021 Free Software Foundation, Inc. This file is part of the GNU C Library. Written May 1989 by Mike Haertel. @@ -17,401 +17,46 @@ License along with the GNU C Library; if not, see . */ =20 -#ifndef _MALLOC_INTERNAL -# define _MALLOC_INTERNAL -# include -# include -# include -# include -# include -# include -# include -#endif - -/* Old hook values. */ -static void (*old_free_hook)(void *ptr, const void *); -static void *(*old_malloc_hook) (size_t size, const void *); -static void *(*old_memalign_hook) (size_t alignment, size_t size, - const void *); -static void *(*old_realloc_hook) (void *ptr, size_t size, - const void *); - -/* Function to call when something awful happens. */ -static void (*abortfunc) (enum mcheck_status); - -/* Arbitrary magical numbers. */ -#define MAGICWORD 0xfedabeeb -#define MAGICFREE 0xd8675309 -#define MAGICBYTE ((char) 0xd7) -#define MALLOCFLOOD ((char) 0x93) -#define FREEFLOOD ((char) 0x95) - -struct hdr -{ - size_t size; /* Exact size requested by user. */ - unsigned long int magic; /* Magic number to check header integrit= y. */ - struct hdr *prev; - struct hdr *next; - void *block; /* Real block allocated, for memalign. = */ - unsigned long int magic2; /* Extra, keeps us doubleword aligned. = */ -}; - -/* This is the beginning of the list of all memory blocks allocated. - It is only constructed if the pedantic testing is requested. */ -static struct hdr *root; - -static int mcheck_used; - -/* Nonzero if pedentic checking of all blocks is requested. */ -static int pedantic; - -#if defined _LIBC || defined STDC_HEADERS || defined USG -# include -# define flood memset +#if !IS_IN (libc) +# include "mcheck-impl.c" #else -static void flood (void *, int, size_t); -static void -flood (void *ptr, int val, size_t size) -{ - char *cp =3D ptr; - while (size--) - *cp++ =3D val; -} +# include #endif =20 -static enum mcheck_status -checkhdr (const struct hdr *hdr) -{ - enum mcheck_status status; - - if (!mcheck_used) - /* Maybe the mcheck used is disabled? This happens when we find - an error and report it. */ - return MCHECK_OK; - - switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next)) - { - default: - status =3D MCHECK_HEAD; - break; - case MAGICFREE: - status =3D MCHECK_FREE; - break; - case MAGICWORD: - if (((char *) &hdr[1])[hdr->size] !=3D MAGICBYTE) - status =3D MCHECK_TAIL; - else if ((hdr->magic2 ^ (uintptr_t) hdr->block) !=3D MAGICWORD) - status =3D MCHECK_HEAD; - else - status =3D MCHECK_OK; - break; - } - if (status !=3D MCHECK_OK) - { - mcheck_used =3D 0; - (*abortfunc) (status); - mcheck_used =3D 1; - } - return status; -} - void mcheck_check_all (void) { - /* Walk through all the active blocks and test whether they were tampe= red - with. */ - struct hdr *runp =3D root; - - /* Temporarily turn off the checks. */ - pedantic =3D 0; - - while (runp !=3D NULL) - { - (void) checkhdr (runp); - - runp =3D runp->next; - } - - /* Turn checks on again. */ - pedantic =3D 1; -} -#ifdef _LIBC -libc_hidden_def (mcheck_check_all) +#if !IS_IN (libc) + __mcheck_checkptr (NULL); #endif - -static void -unlink_blk (struct hdr *ptr) -{ - if (ptr->next !=3D NULL) - { - ptr->next->prev =3D ptr->prev; - ptr->next->magic =3D MAGICWORD ^ ((uintptr_t) ptr->next->prev - + (uintptr_t) ptr->next->next); - } - if (ptr->prev !=3D NULL) - { - ptr->prev->next =3D ptr->next; - ptr->prev->magic =3D MAGICWORD ^ ((uintptr_t) ptr->prev->prev - + (uintptr_t) ptr->prev->next); - } - else - root =3D ptr->next; -} - -static void -link_blk (struct hdr *hdr) -{ - hdr->prev =3D NULL; - hdr->next =3D root; - root =3D hdr; - hdr->magic =3D MAGICWORD ^ (uintptr_t) hdr->next; - - /* And the next block. */ - if (hdr->next !=3D NULL) - { - hdr->next->prev =3D hdr; - hdr->next->magic =3D MAGICWORD ^ ((uintptr_t) hdr - + (uintptr_t) hdr->next->next); - } } -static void -freehook (void *ptr, const void *caller) -{ - if (pedantic) - mcheck_check_all (); - if (ptr) - { - struct hdr *hdr =3D ((struct hdr *) ptr) - 1; - checkhdr (hdr); - hdr->magic =3D MAGICFREE; - hdr->magic2 =3D MAGICFREE; - unlink_blk (hdr); - hdr->prev =3D hdr->next =3D NULL; - flood (ptr, FREEFLOOD, hdr->size); - ptr =3D hdr->block; - } - __free_hook =3D old_free_hook; - if (old_free_hook !=3D NULL) - (*old_free_hook)(ptr, caller); - else - free (ptr); - __free_hook =3D freehook; -} - -static void * -mallochook (size_t size, const void *caller) -{ - struct hdr *hdr; - - if (pedantic) - mcheck_check_all (); - - if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1)) - { - __set_errno (ENOMEM); - return NULL; - } - - __malloc_hook =3D old_malloc_hook; - if (old_malloc_hook !=3D NULL) - hdr =3D (struct hdr *) (*old_malloc_hook)(sizeof (struct hdr) + size= + 1, - caller); - else - hdr =3D (struct hdr *) malloc (sizeof (struct hdr) + size + 1); - __malloc_hook =3D mallochook; - if (hdr =3D=3D NULL) - return NULL; - - hdr->size =3D size; - link_blk (hdr); - hdr->block =3D hdr; - hdr->magic2 =3D (uintptr_t) hdr ^ MAGICWORD; - ((char *) &hdr[1])[size] =3D MAGICBYTE; - flood ((void *) (hdr + 1), MALLOCFLOOD, size); - return (void *) (hdr + 1); -} - -static void * -memalignhook (size_t alignment, size_t size, - const void *caller) -{ - struct hdr *hdr; - size_t slop; - char *block; - - if (pedantic) - mcheck_check_all (); - - slop =3D (sizeof *hdr + alignment - 1) & - alignment; - - if (size > ~((size_t) 0) - (slop + 1)) - { - __set_errno (ENOMEM); - return NULL; - } - - __memalign_hook =3D old_memalign_hook; - if (old_memalign_hook !=3D NULL) - block =3D (*old_memalign_hook)(alignment, slop + size + 1, caller); - else - block =3D memalign (alignment, slop + size + 1); - __memalign_hook =3D memalignhook; - if (block =3D=3D NULL) - return NULL; - - hdr =3D ((struct hdr *) (block + slop)) - 1; - - hdr->size =3D size; - link_blk (hdr); - hdr->block =3D (void *) block; - hdr->magic2 =3D (uintptr_t) block ^ MAGICWORD; - ((char *) &hdr[1])[size] =3D MAGICBYTE; - flood ((void *) (hdr + 1), MALLOCFLOOD, size); - return (void *) (hdr + 1); -} - -static void * -reallochook (void *ptr, size_t size, const void *caller) -{ - if (size =3D=3D 0) - { - freehook (ptr, caller); - return NULL; - } - - struct hdr *hdr; - size_t osize; - - if (pedantic) - mcheck_check_all (); - - if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1)) - { - __set_errno (ENOMEM); - return NULL; - } - - if (ptr) - { - hdr =3D ((struct hdr *) ptr) - 1; - osize =3D hdr->size; - - checkhdr (hdr); - unlink_blk (hdr); - if (size < osize) - flood ((char *) ptr + size, FREEFLOOD, osize - size); - } - else - { - osize =3D 0; - hdr =3D NULL; - } - __free_hook =3D old_free_hook; - __malloc_hook =3D old_malloc_hook; - __memalign_hook =3D old_memalign_hook; - __realloc_hook =3D old_realloc_hook; - if (old_realloc_hook !=3D NULL) - hdr =3D (struct hdr *) (*old_realloc_hook)((void *) hdr, - sizeof (struct hdr) + size = + 1, - caller); - else - hdr =3D (struct hdr *) realloc ((void *) hdr, - sizeof (struct hdr) + size + 1); - __free_hook =3D freehook; - __malloc_hook =3D mallochook; - __memalign_hook =3D memalignhook; - __realloc_hook =3D reallochook; - if (hdr =3D=3D NULL) - return NULL; - - hdr->size =3D size; - link_blk (hdr); - hdr->block =3D hdr; - hdr->magic2 =3D (uintptr_t) hdr ^ MAGICWORD; - ((char *) &hdr[1])[size] =3D MAGICBYTE; - if (size > osize) - flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize); - return (void *) (hdr + 1); -} - -__attribute__ ((noreturn)) -static void -mabort (enum mcheck_status status) -{ - const char *msg; - switch (status) - { - case MCHECK_OK: - msg =3D _ ("memory is consistent, library is buggy\n"); - break; - case MCHECK_HEAD: - msg =3D _ ("memory clobbered before allocated block\n"); - break; - case MCHECK_TAIL: - msg =3D _ ("memory clobbered past end of allocated block\n"); - break; - case MCHECK_FREE: - msg =3D _ ("block freed twice\n"); - break; - default: - msg =3D _ ("bogus mcheck_status, library is buggy\n"); - break; - } -#ifdef _LIBC - __libc_fatal (msg); -#else - fprintf (stderr, "mcheck: %s", msg); - fflush (stderr); - abort (); -#endif -} - -/* Memory barrier so that GCC does not optimize out the argument. */ -#define malloc_opt_barrier(x) \ - ({ __typeof (x) __x =3D x; __asm ("" : "+m" (__x)); __x; }) =20 int mcheck (void (*func) (enum mcheck_status)) { - abortfunc =3D (func !=3D NULL) ? func : &mabort; - - /* These hooks may not be safely inserted if malloc is already in use.= */ - if (__malloc_initialized <=3D 0 && !mcheck_used) - { - /* We call malloc() once here to ensure it is initialized. */ - void *p =3D malloc (0); - /* GCC might optimize out the malloc/free pair without a barrier. = */ - p =3D malloc_opt_barrier (p); - free (p); - - old_free_hook =3D __free_hook; - __free_hook =3D freehook; - old_malloc_hook =3D __malloc_hook; - __malloc_hook =3D mallochook; - old_memalign_hook =3D __memalign_hook; - __memalign_hook =3D memalignhook; - old_realloc_hook =3D __realloc_hook; - __realloc_hook =3D reallochook; - mcheck_used =3D 1; - } - - return mcheck_used ? 0 : -1; -} -#ifdef _LIBC -libc_hidden_def (mcheck) +#if IS_IN (libc) + return -1; +#else + return __mcheck_initialize (func, false); #endif +} =20 int mcheck_pedantic (void (*func) (enum mcheck_status)) { - int res =3D mcheck (func); - if (res =3D=3D 0) - pedantic =3D 1; - return res; +#if IS_IN (libc) + return -1; +#else + return __mcheck_initialize (func, true); +#endif } =20 enum mcheck_status mprobe (void *ptr) { - return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISA= BLED; +#if IS_IN (libc) + return MCHECK_DISABLED; +#else + return __mcheck_checkptr (ptr); +#endif } --=20 2.31.1