From d86155f72e0a2db73a6cf4b873d400536ed06486 Mon Sep 17 00:00:00 2001 From: Arun Sharma Date: Tue, 5 Apr 2011 20:46:24 -0700 Subject: [PATCH] Add a test to catch calls to calloc from libunwind We'd like to avoid calls to all malloc related functions so libunwind is still usable from such allocators. Signed-off-by: Paul Pluzhnikov --- .gitignore | 1 + tests/Gtest-nocalloc.c | 137 +++++++++++++++++++++++++++++++++++++++++ tests/Ltest-nocalloc.c | 5 ++ tests/Makefile.am | 7 ++- 4 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 tests/Gtest-nocalloc.c create mode 100644 tests/Ltest-nocalloc.c diff --git a/.gitignore b/.gitignore index 120b5553..f21337aa 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ tests/[GL]test-init tests/[GL]test-resume-sig tests/[GL]perf-simple tests/Ltest-nomalloc +tests/Ltest-nocalloc tests/Lperf-simple tests/check-namespace.sh tests/forker diff --git a/tests/Gtest-nocalloc.c b/tests/Gtest-nocalloc.c new file mode 100644 index 00000000..6f61b96c --- /dev/null +++ b/tests/Gtest-nocalloc.c @@ -0,0 +1,137 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2011 Google, Inc + Contributed by Paul Pluzhnikov + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include /* for backtrace */ +#include +#include +#include +#include +#include +#include + +#define panic(args...) \ + { fprintf (stderr, args); exit (-1); } + +int verbose; +int num_mallocs; +int num_callocs; +int in_unwind; + +void * +calloc(size_t n, size_t s) +{ + static void * (*func)(); + +#ifdef __GLIBC__ + /* In glibc, dlsym() calls calloc. Calling dlsym(RTLD_NEXT, "calloc") here + causes infinite recursion. Instead, we simply use it by its other + name. */ + extern void *__libc_calloc(); + func = &__libc_calloc; +#else + if(!func) + func = (void *(*)()) dlsym(RTLD_NEXT, "calloc"); +#endif + + if (in_unwind) { + num_callocs++; + return NULL; + } else { + return func(n, s); + } +} + +void * +malloc(size_t s) +{ + static void * (*func)(); + + if(!func) + func = (void *(*)()) dlsym(RTLD_NEXT, "malloc"); + + if (in_unwind) { + num_mallocs++; + return NULL; + } else { + return func(s); + } +} + +static void +do_backtrace (void) +{ + const int num_levels = 100; + void *pc[num_levels]; + + in_unwind = 1; + backtrace(pc, num_levels); + in_unwind = 0; +} + +void +foo3 () +{ + do_backtrace (); +} + +void +foo2 () +{ + foo3 (); +} + +void +foo1 (void) +{ + foo2 (); + return NULL; +} + +int +main (int argc, char **argv) +{ + int i, num_errors; + + /* Create (and leak) 100 TSDs, then call backtrace() + and check that it doesn't call malloc()/calloc(). */ + for (i = 0; i < 100; ++i) { + pthread_key_t key; + if (pthread_key_create (&key, NULL)) + panic ("FAILURE: unable to create key %d\n", i); + } + foo1 (); + num_errors = num_mallocs + num_callocs; + if (num_errors > 0) + { + fprintf (stderr, + "FAILURE: detected %d error%s (malloc: %d, calloc: %d)\n", + num_errors, num_errors > 1 ? "s" : "", + num_mallocs, num_callocs); + exit (-1); + } + return 0; +} diff --git a/tests/Ltest-nocalloc.c b/tests/Ltest-nocalloc.c new file mode 100644 index 00000000..8463dcf7 --- /dev/null +++ b/tests/Ltest-nocalloc.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if !defined(UNW_REMOTE_ONLY) +#include "Gtest-nocalloc.c" +#endif diff --git a/tests/Makefile.am b/tests/Makefile.am index c724e438..d5e3ae25 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,8 @@ AM_CPPFLAGS = -I$(top_srcdir)/include EXTRA_DIST = run-ia64-test-dyn1 run-ptrace-mapper run-ptrace-misc \ - run-check-namespace check-namespace.sh.in Gtest-nomalloc.c + run-check-namespace check-namespace.sh.in Gtest-nomalloc.c \ + Gtest-nocalloc.c MAINTAINERCLEANFILES = Makefile.in @@ -44,7 +45,7 @@ endif #ARCH_IA64 Gtest-trace Ltest-trace \ test-async-sig test-flush-cache test-init-remote \ test-mem test-setjmp test-ptrace \ - Ltest-nomalloc rs-race + Ltest-nomalloc Ltest-nocalloc rs-race noinst_PROGRAMS_cdep = forker mapper test-ptrace-misc test-varargs \ Gperf-simple Lperf-simple \ Gperf-trace Lperf-trace @@ -102,6 +103,7 @@ Gtest_bt_SOURCES = Gtest-bt.c ident.c Ltest_bt_SOURCES = Ltest-bt.c ident.c test_ptrace_misc_SOURCES = test-ptrace-misc.c ident.c Ltest_nomalloc_SOURCES = Ltest-nomalloc.c +Ltest_nocalloc_SOURCES = Ltest-nocalloc.c Gtest_trace_SOURCES = Gtest-trace.c ident.c Ltest_trace_SOURCES = Ltest-trace.c ident.c @@ -148,6 +150,7 @@ Ltest_dyn1_LDADD = $(LIBUNWIND_local) Ltest_exc_LDADD = $(LIBUNWIND_local) Ltest_init_LDADD = $(LIBUNWIND_local) Ltest_nomalloc_LDADD = $(LIBUNWIND_local) @DLLIB@ +Ltest_nocalloc_LDADD = $(LIBUNWIND_local) @DLLIB@ -lpthread Ltest_resume_sig_LDADD = $(LIBUNWIND) Lperf_simple_LDADD = $(LIBUNWIND_local) Ltest_trace_LDADD = $(LIBUNWIND_local)