From f02baefb3ba4d5493816d63f65625ba4269224d2 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Fri, 14 Feb 2014 10:02:51 -0500 Subject: [PATCH] Fix: work-around glibc lying about dlsym()/dlerror() leafness Especially in the LTTng-UST malloc instrumentation, we run into the following situation: 1) Our calloc wrapper is called, 2) we setup the static allocator, 3) we call dlsym() to lookup the symbol of the real allocator, 4) dlsym() calls into calloc(), which is overridden by our own wrapper. Our calloc does not see that the static allocator has been set, because the stores setting up the static allocator have been optimized away by gcc-4.8 (in O2), because the dlsym() prototype declares it with the "leaf" attribute, and thus we end up doing an infinite recursion, and eventually a segmentation fault. Thanks to Alexander Monakov for pointing out the culprit of this glibc bug. Signed-off-by: Mathieu Desnoyers --- include/Makefile.am | 1 + include/lttng/ust-dlfcn.h | 61 +++++++++++++++++++ liblttng-ust-dl/ustdl.c | 2 +- liblttng-ust-fork/ustfork.c | 2 +- liblttng-ust-libc-wrapper/lttng-ust-malloc.c | 2 +- liblttng-ust-libc-wrapper/lttng-ust-pthread.c | 2 +- liblttng-ust/lttng-ust-baddr.c | 1 - liblttng-ust/lttng-ust-comm.c | 1 - 8 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 include/lttng/ust-dlfcn.h diff --git a/include/Makefile.am b/include/Makefile.am index 4f028dba..46cc3fd3 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -29,6 +29,7 @@ noinst_HEADERS = \ ust-comm.h \ lttng/ust-tid.h \ lttng/bitfield.h \ + lttng/ust-dlfcn.h \ helper.h \ share.h diff --git a/include/lttng/ust-dlfcn.h b/include/lttng/ust-dlfcn.h new file mode 100644 index 00000000..786d3b5a --- /dev/null +++ b/include/lttng/ust-dlfcn.h @@ -0,0 +1,61 @@ +#ifndef _LTTNG_UST_DLFCN_H +#define _LTTNG_UST_DLFCN_H + +/* + * lttng/ust-dlfcn.h + * + * Copyright 2014 (c) - Mathieu Desnoyers + * + * dlfcn.h compatibility layer. + * + * 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 _DLFCN_H +#error "Please include lttng/ust-dlfcn.h before dlfcn.h." +#endif /* _DLFCN_H */ + +/* + * glibc declares dlsym() and dlerror() with __attribute__((leaf)) (see + * THROW annotation). Unfortunately, this is not in sync with reality, + * as those functions call the memory allocator. Work-around this glibc + * bug by declaring our own symbols. + * + * There has been a similar issue for dlopen() and dlclose(), as + * constructors and destructors are called from these functions, so they + * are clearly non-leaf. Work-around the issue for those too for older + * glibc where these have not been fixed. + */ +#define dlopen glibc_dlopen_proto_lies_about_leafness +#define dlclose glibc_dlclose_proto_lies_about_leafness +#define dlsym glibc_dlsym_proto_lies_about_leafness +#define dlerror glibc_dlerror_proto_lies_about_leafness +#include +#undef dlerror +#undef dlsym +#undef dlclose +#undef dlopen + +extern void *dlopen(__const char *__file, int __mode); +extern int dlclose(void *__handle) __nonnull ((1)); +extern void *dlsym(void *__restrict __handle, + __const char *__restrict __name) __nonnull ((2)); +extern char *dlerror (void); + +#endif /* _LTTNG_UST_DLFCN_H */ diff --git a/liblttng-ust-dl/ustdl.c b/liblttng-ust-dl/ustdl.c index ceb9b5ba..b6abca7b 100644 --- a/liblttng-ust-dl/ustdl.c +++ b/liblttng-ust-dl/ustdl.c @@ -18,8 +18,8 @@ #define _LGPL_SOURCE #define _GNU_SOURCE +#include #include -#include #include #include #include diff --git a/liblttng-ust-fork/ustfork.c b/liblttng-ust-fork/ustfork.c index 34f674c3..e1429601 100644 --- a/liblttng-ust-fork/ustfork.c +++ b/liblttng-ust-fork/ustfork.c @@ -18,7 +18,7 @@ */ #define _GNU_SOURCE -#include +#include #include #include #include diff --git a/liblttng-ust-libc-wrapper/lttng-ust-malloc.c b/liblttng-ust-libc-wrapper/lttng-ust-malloc.c index 8296ae29..54522b42 100644 --- a/liblttng-ust-libc-wrapper/lttng-ust-malloc.c +++ b/liblttng-ust-libc-wrapper/lttng-ust-malloc.c @@ -18,7 +18,7 @@ */ #define _GNU_SOURCE -#include +#include #include #include #include diff --git a/liblttng-ust-libc-wrapper/lttng-ust-pthread.c b/liblttng-ust-libc-wrapper/lttng-ust-pthread.c index e72b9b40..45789aa3 100644 --- a/liblttng-ust-libc-wrapper/lttng-ust-pthread.c +++ b/liblttng-ust-libc-wrapper/lttng-ust-pthread.c @@ -17,7 +17,7 @@ */ #define _GNU_SOURCE -#include +#include #include #define TRACEPOINT_DEFINE diff --git a/liblttng-ust/lttng-ust-baddr.c b/liblttng-ust/lttng-ust-baddr.c index 90ffe688..42ae630d 100644 --- a/liblttng-ust/lttng-ust-baddr.c +++ b/liblttng-ust/lttng-ust-baddr.c @@ -18,7 +18,6 @@ #define _LGPL_SOURCE #define _GNU_SOURCE -#include #include #include diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index 27786945..74d805ae 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include -- 2.34.1