diff options
-rw-r--r-- | ChangeLog | 36 | ||||
-rw-r--r-- | elf/get-dynamic-info.h | 3 | ||||
-rw-r--r-- | include/libc-symbols.h | 15 | ||||
-rw-r--r-- | malloc/Makefile | 14 | ||||
-rw-r--r-- | malloc/tst-interpose-aux-nothread.c | 20 | ||||
-rw-r--r-- | malloc/tst-interpose-aux-thread.c | 20 | ||||
-rw-r--r-- | malloc/tst-interpose-aux.c | 270 | ||||
-rw-r--r-- | malloc/tst-interpose-aux.h | 30 | ||||
-rw-r--r-- | sysdeps/mach/hurd/fork.c | 6 | ||||
-rw-r--r-- | sysdeps/nptl/fork.c | 6 | ||||
-rw-r--r-- | sysdeps/powerpc/powerpc64/power8/fpu/math_private.h | 49 | ||||
-rw-r--r-- | test-skeleton.c | 2 |
12 files changed, 462 insertions, 9 deletions
@@ -502,6 +502,32 @@ (reg_AVX512BW): Likewise. (reg_AVX512VL): Likewise. +2016-08-26 Florian Weimer <fweimer@redhat.com> + + [BZ #20432] + Avoid strong references to malloc-internal symbols when linking + statically, to support statically interposed mallocs. + * include/libc-symbols.h (call_function_static_weak): New macro. + * malloc/Makefile (extra-tests-objs): Add tst-interpose-aux-nothread.o, + tst-interpose-aux-thread.o. + (test-extras): Add tst-interpose-aux-nothread, + tst-interpose-aux-thread. + * malloc/tst-interpose-aux-nothread.c: New file. + * malloc/tst-interpose-aux-thread.c: Likewise. + * malloc/tst-interpose-aux.c: Likewise. + * malloc/tst-interpose-aux.h: Likewise. + * sysdeps/mach/hurd/fork.c (__fork): Only call + __malloc_fork_lock_parent, __malloc_fork_unlock_parent, + __malloc_fork_unlock_child if defined. + * sysdeps/nptl/fork.c (__libc_fork): Likewise. + +2016-08-02 Florian Weimer <fweimer@redhat.com> + + [BZ #19469] + * malloc/Makefile (CPPFLAGS): Compile tests with + -DTEST_NO_MALLOPT. + * test-skeleton.c (main): Only call mallopt if !TEST_NO_MALLOPT. + 2017-01-05 Joseph Myers <joseph@codesourcery.com> [BZ #21026] @@ -722,6 +748,11 @@ * sysdeps/unix/sysv/linux/spawni.c (__spawni): Correctly enable and disable asynchronous cancellation. +2016-10-18 Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com> + + * sysdeps/powerpc/powerpc64/power8/fpu/math_private.h (GET_FLOAT_WORD): + (SET_FLOAT_WORD): New macros. + 2016-09-19 Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com> [BZ #20615] @@ -835,6 +866,11 @@ (ifunc_one): Add "12" to the clobber list. Use "i" constraint instead of "X". +2015-08-06 Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com> + + * elf/get-dynamic-info.h (elf_get_dynamic_info): Remove assert + if DT_RUNPATH and DT_RPATH flags are found in ld.so. + 2016-08-04 Carlos O'Donell <carlos@redhat.com> * po/de.po: Update from Translation Project. diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h index 4cf18a46cc..06519b9bc5 100644 --- a/elf/get-dynamic-info.h +++ b/elf/get-dynamic-info.h @@ -138,9 +138,6 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) || (info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val & ~DF_1_NOW) == 0); assert (info[DT_FLAGS] == NULL || (info[DT_FLAGS]->d_un.d_val & ~DF_BIND_NOW) == 0); - /* Flags must not be set for ld.so. */ - assert (info[DT_RUNPATH] == NULL); - assert (info[DT_RPATH] == NULL); #else if (info[DT_FLAGS] != NULL) { diff --git a/include/libc-symbols.h b/include/libc-symbols.h index 4548e097dc..8245885c9f 100644 --- a/include/libc-symbols.h +++ b/include/libc-symbols.h @@ -121,6 +121,21 @@ # define weak_extern(symbol) _weak_extern (weak symbol) # define _weak_extern(expr) _Pragma (#expr) +/* In shared builds, the expression call_function_static_weak + (FUNCTION-SYMBOL, ARGUMENTS) invokes FUNCTION-SYMBOL (an + identifier) unconditionally, with the (potentially empty) argument + list ARGUMENTS. In static builds, if FUNCTION-SYMBOL has a + definition, the function is invoked as before; if FUNCTION-SYMBOL + is NULL, no call is performed. */ +# ifdef SHARED +# define call_function_static_weak(func, ...) func (__VA_ARGS__) +# else /* !SHARED */ +# define call_function_static_weak(func, ...) \ + ({ \ + extern __typeof__ (func) func weak_function; \ + (func != NULL ? func (__VA_ARGS__) : (void)0); \ + }) +# endif #else /* __ASSEMBLER__ */ diff --git a/malloc/Makefile b/malloc/Makefile index fa1730ecb7..e683daab35 100644 --- a/malloc/Makefile +++ b/malloc/Makefile @@ -31,6 +31,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ tst-malloc-backtrace tst-malloc-thread-exit \ tst-malloc-thread-fail tst-malloc-fork-deadlock \ tst-mallocfork2 + test-srcs = tst-mtrace routines = malloc morecore mcheck mtrace obstack \ @@ -44,6 +45,15 @@ non-lib.a := libmcheck.a extra-libs = libmemusage extra-libs-others = $(extra-libs) +# Helper objects for some tests. +extra-tests-objs += \ + tst-interpose-aux-nothread.o \ + tst-interpose-aux-thread.o \ + +test-extras = \ + tst-interpose-aux-nothread \ + tst-interpose-aux-thread \ + libmemusage-routines = memusage libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes)) @@ -166,3 +176,7 @@ $(objpfx)libmemusage.so: $(libdl) # Extra dependencies $(foreach o,$(all-object-suffixes),$(objpfx)malloc$(o)): arena.c hooks.c + +# Compile the tests with a flag which suppresses the mallopt call in +# the test skeleton. +$(tests:%=$(objpfx)%.o): CPPFLAGS += -DTEST_NO_MALLOPT diff --git a/malloc/tst-interpose-aux-nothread.c b/malloc/tst-interpose-aux-nothread.c new file mode 100644 index 0000000000..0eae66fa6c --- /dev/null +++ b/malloc/tst-interpose-aux-nothread.c @@ -0,0 +1,20 @@ +/* Interposed malloc, version without threading support. + Copyright (C) 2016 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; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. */ + +#define INTERPOSE_THREADS 0 +#include "tst-interpose-aux.c" diff --git a/malloc/tst-interpose-aux-thread.c b/malloc/tst-interpose-aux-thread.c new file mode 100644 index 0000000000..354e4d8ed1 --- /dev/null +++ b/malloc/tst-interpose-aux-thread.c @@ -0,0 +1,20 @@ +/* Interposed malloc, version with threading support. + Copyright (C) 2016 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; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. */ + +#define INTERPOSE_THREADS 1 +#include "tst-interpose-aux.c" diff --git a/malloc/tst-interpose-aux.c b/malloc/tst-interpose-aux.c new file mode 100644 index 0000000000..77866b2e5d --- /dev/null +++ b/malloc/tst-interpose-aux.c @@ -0,0 +1,270 @@ +/* Minimal malloc implementation for interposition tests. + Copyright (C) 2016 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; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "tst-interpose-aux.h" + +#include <errno.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/uio.h> +#include <unistd.h> + +#if INTERPOSE_THREADS +#include <pthread.h> +#endif + +/* Print the error message and terminate the process with status 1. */ +__attribute__ ((noreturn)) +__attribute__ ((format (printf, 1, 2))) +static void * +fail (const char *format, ...) +{ + /* This assumes that vsnprintf will not call malloc. It does not do + so for the format strings we use. */ + char message[4096]; + va_list ap; + va_start (ap, format); + vsnprintf (message, sizeof (message), format, ap); + va_end (ap); + + enum { count = 3 }; + struct iovec iov[count]; + + iov[0].iov_base = (char *) "error: "; + iov[1].iov_base = (char *) message; + iov[2].iov_base = (char *) "\n"; + + for (int i = 0; i < count; ++i) + iov[i].iov_len = strlen (iov[i].iov_base); + + int unused __attribute__ ((unused)); + unused = writev (STDOUT_FILENO, iov, count); + _exit (1); +} + +#if INTERPOSE_THREADS +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + +static void +lock (void) +{ +#if INTERPOSE_THREADS + int ret = pthread_mutex_lock (&mutex); + if (ret != 0) + { + errno = ret; + fail ("pthread_mutex_lock: %m"); + } +#endif +} + +static void +unlock (void) +{ +#if INTERPOSE_THREADS + int ret = pthread_mutex_unlock (&mutex); + if (ret != 0) + { + errno = ret; + fail ("pthread_mutex_unlock: %m"); + } +#endif +} + +struct __attribute__ ((aligned (__alignof__ (max_align_t)))) allocation_header +{ + size_t allocation_index; + size_t allocation_size; +}; + +/* Array of known allocations, to track invalid frees. */ +enum { max_allocations = 65536 }; +static struct allocation_header *allocations[max_allocations]; +static size_t allocation_index; +static size_t deallocation_count; + +/* Sanity check for successful malloc interposition. */ +__attribute__ ((destructor)) +static void +check_for_allocations (void) +{ + if (allocation_index == 0) + { + /* Make sure that malloc is called at least once from libc. */ + void *volatile ptr = strdup ("ptr"); + free (ptr); + /* Compiler barrier. The strdup function calls malloc, which + updates allocation_index, but strdup is marked __THROW, so + the compiler could optimize away the reload. */ + __asm__ volatile ("" ::: "memory"); + /* If the allocation count is still zero, it means we did not + interpose malloc successfully. */ + if (allocation_index == 0) + fail ("malloc does not seem to have been interposed"); + } +} + +static struct allocation_header *get_header (const char *op, void *ptr) +{ + struct allocation_header *header = ((struct allocation_header *) ptr) - 1; + if (header->allocation_index >= allocation_index) + fail ("%s: %p: invalid allocation index: %zu (not less than %zu)", + op, ptr, header->allocation_index, allocation_index); + if (allocations[header->allocation_index] != header) + fail ("%s: %p: allocation pointer does not point to header, but %p", + op, ptr, allocations[header->allocation_index]); + return header; +} + +/* Internal helper functions. Those must be called while the lock is + acquired. */ + +static void * +malloc_internal (size_t size) +{ + if (allocation_index == max_allocations) + { + errno = ENOMEM; + return NULL; + } + size_t allocation_size = size + sizeof (struct allocation_header); + if (allocation_size < size) + { + errno = ENOMEM; + return NULL; + } + + size_t index = allocation_index++; + void *result = mmap (NULL, allocation_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (result == MAP_FAILED) + return NULL; + allocations[index] = result; + *allocations[index] = (struct allocation_header) + { + .allocation_index = index, + .allocation_size = allocation_size + }; + return allocations[index] + 1; +} + +static void +free_internal (const char *op, struct allocation_header *header) +{ + size_t index = header->allocation_index; + int result = mprotect (header, header->allocation_size, PROT_NONE); + if (result != 0) + fail ("%s: mprotect (%p, %zu): %m", op, header, header->allocation_size); + /* Catch double-free issues. */ + allocations[index] = NULL; + ++deallocation_count; +} + +static void * +realloc_internal (void *ptr, size_t new_size) +{ + struct allocation_header *header = get_header ("realloc", ptr); + size_t old_size = header->allocation_size - sizeof (struct allocation_header); + if (old_size >= new_size) + return ptr; + + void *newptr = malloc_internal (new_size); + if (newptr == NULL) + return NULL; + memcpy (newptr, ptr, old_size); + free_internal ("realloc", header); + return newptr; +} + +/* Public interfaces. These functions must perform locking. */ + +size_t +malloc_allocation_count (void) +{ + lock (); + size_t count = allocation_index; + unlock (); + return count; +} + +size_t +malloc_deallocation_count (void) +{ + lock (); + size_t count = deallocation_count; + unlock (); + return count; +} +void * +malloc (size_t size) +{ + lock (); + void *result = malloc_internal (size); + unlock (); + return result; +} + +void +free (void *ptr) +{ + if (ptr == NULL) + return; + lock (); + struct allocation_header *header = get_header ("free", ptr); + free_internal ("free", header); + unlock (); +} + +void * +calloc (size_t a, size_t b) +{ + if (b > 0 && a > SIZE_MAX / b) + { + errno = ENOMEM; + return NULL; + } + lock (); + /* malloc_internal uses mmap, so the memory is zeroed. */ + void *result = malloc_internal (a * b); + unlock (); + return result; +} + +void * +realloc (void *ptr, size_t n) +{ + if (n ==0) + { + free (ptr); + return NULL; + } + else if (ptr == NULL) + return malloc (n); + else + { + lock (); + void *result = realloc_internal (ptr, n); + unlock (); + return result; + } +} diff --git a/malloc/tst-interpose-aux.h b/malloc/tst-interpose-aux.h new file mode 100644 index 0000000000..2fb22d312a --- /dev/null +++ b/malloc/tst-interpose-aux.h @@ -0,0 +1,30 @@ +/* Statistics interface for the minimal malloc implementation. + Copyright (C) 2016 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; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef TST_INTERPOSE_AUX_H +#define TST_INTERPOSE_AUX_H + +#include <stddef.h> + +/* Return the number of allocations performed. */ +size_t malloc_allocation_count (void); + +/* Return the number of deallocations performed. */ +size_t malloc_deallocation_count (void); + +#endif /* TST_INTERPOSE_AUX_H */ diff --git a/sysdeps/mach/hurd/fork.c b/sysdeps/mach/hurd/fork.c index 2e8b59e7c0..9973b1bb9e 100644 --- a/sysdeps/mach/hurd/fork.c +++ b/sysdeps/mach/hurd/fork.c @@ -112,7 +112,7 @@ __fork (void) handlers may use malloc, and the libio list lock has an indirect malloc dependency as well (via the getdelim function). */ - __malloc_fork_lock_parent (); + call_function_static_weak (__malloc_fork_lock_parent); /* Lock things that want to be locked before we fork. */ { @@ -612,7 +612,7 @@ __fork (void) } /* Release malloc locks. */ - __malloc_fork_unlock_parent (); + call_function_static_weak (__malloc_fork_unlock_parent); /* Run things that want to run in the parent to restore it to normality. Usually prepare hooks and parent hooks are @@ -666,7 +666,7 @@ __fork (void) __sigemptyset (&_hurdsig_traced); /* Release malloc locks. */ - __malloc_fork_unlock_child (); + call_function_static_weak (__malloc_fork_unlock_child); /* Run things that want to run in the child task to set up. */ RUN_HOOK (_hurd_fork_child_hook, ()); diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c index a5d1e86d71..4ff13726a3 100644 --- a/sysdeps/nptl/fork.c +++ b/sysdeps/nptl/fork.c @@ -128,7 +128,7 @@ __libc_fork (void) handlers may use malloc, and the libio list lock has an indirect malloc dependency as well (via the getdelim function). */ - __malloc_fork_lock_parent (); + call_function_static_weak (__malloc_fork_lock_parent); } #ifdef ARCH_FORK @@ -177,7 +177,7 @@ __libc_fork (void) if (multiple_threads) { /* Release malloc locks. */ - __malloc_fork_unlock_child (); + call_function_static_weak (__malloc_fork_unlock_child); /* Reset the file list. These are recursive mutexes. */ fresetlockfiles (); @@ -220,7 +220,7 @@ __libc_fork (void) if (multiple_threads) { /* Release malloc locks, parent process variant. */ - __malloc_fork_unlock_parent (); + call_function_static_weak (__malloc_fork_unlock_parent); /* We execute this even if the 'fork' call failed. */ _IO_list_unlock (); diff --git a/sysdeps/powerpc/powerpc64/power8/fpu/math_private.h b/sysdeps/powerpc/powerpc64/power8/fpu/math_private.h new file mode 100644 index 0000000000..fe00c738ae --- /dev/null +++ b/sysdeps/powerpc/powerpc64/power8/fpu/math_private.h @@ -0,0 +1,49 @@ +/* Private inline math functions for POWER8. + Copyright (C) 2016 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 + <http://www.gnu.org/licenses/>. */ + +/* The compiler isn't extracting this without going through memory, so + we use some VSX scalar instructions to convert to the 32b format + and move to a GPR. */ +#define GET_FLOAT_WORD(i,d) \ + do { \ + float tmpd = d; \ + double tmp; \ + long tmpi; \ + __asm__ ("xscvdpspn %x1, %x2\n\t" \ + "mfvsrd %0, %x1\n\t" \ + : "=wr" (tmpi), \ + "=wa" (tmp) \ + : "wa" (tmpd) ); \ + i = tmpi >> 32; \ + } while(0) + +/* To ensure that we don't go through memory, we use some VSX scalar + instructions to move VSR and to convert to the 32b format. */ +#define SET_FLOAT_WORD(d,i) \ + do { \ + long tmpi = i; \ + float tmpd; \ + tmpi = tmpi << 32; \ + __asm__ ("mtvsrd %x0, %1\n\t" \ + "xscvspdpn %x0, %x0\n\t" \ + : "=wa" (tmpd) \ + : "wr" (tmpi) ); \ + d = tmpd; \ + } while(0) + +#include_next <math_private.h> diff --git a/test-skeleton.c b/test-skeleton.c index d9bf989fa8..5a90c65826 100644 --- a/test-skeleton.c +++ b/test-skeleton.c @@ -346,8 +346,10 @@ main (int argc, char *argv[]) unsigned int timeoutfactor = 1; pid_t termpid; +#ifndef TEST_NO_MALLOPT /* Make uses of freed and uninitialized memory known. */ mallopt (M_PERTURB, 42); +#endif #ifdef STDOUT_UNBUFFERED setbuf (stdout, NULL); |