[compiler-rt] r189753 - [sanitizer_common] Add internal_clone().

Matt Arsenault Matthew.Arsenault at amd.com
Fri Oct 4 13:07:55 PDT 2013


This has been breaking the build for me for a while (I'm using the 
packaged clang 3.2 on Ubuntu 13.04):

/home/marsenau/src/llvm/projects/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc:801:25: 
error: unknown directive
                        ".cfi_undefined %%rip;\n"
                         ^
<inline asm>:8:1: note: instantiated into assembly here
.cfi_undefined %rip;
^
[ 14%] 1 error generated.


On 09/02/2013 04:36 AM, Sergey Matveev wrote:
> Author: smatveev
> Date: Mon Sep  2 06:36:19 2013
> New Revision: 189753
>
> URL: http://llvm.org/viewvc/llvm-project?rev=189753&view=rev
> Log:
> [sanitizer_common] Add internal_clone().
>
> Add a wrapper for the clone syscall for use in StopTheWorld. We
> implement it only for x86_64, so stop building StopTheWorld for other platforms
> (no one uses it outside x86_64 anyway).
>
> See https://code.google.com/p/address-sanitizer/issues/detail?id=214 for why we
> can't use the glibc clone() wrapper.
>
> Modified:
>      compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc
>      compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.h
>      compiler-rt/trunk/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
>      compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc
>
> Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc
> URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc?rev=189753&r1=189752&r2=189753&view=diff
> ==============================================================================
> --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc (original)
> +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc Mon Sep  2 06:36:19 2013
> @@ -679,6 +679,69 @@ void ForEachMappedRegion(link_map *map,
>   }
>   #endif
>   
> +#if defined(__x86_64__)
> +// We cannot use glibc's clone wrapper, because it messes with the child
> +// task's TLS. It writes the PID and TID of the child task to its thread
> +// descriptor, but in our case the child task shares the thread descriptor with
> +// the parent (because we don't know how to allocate a new thread
> +// descriptor to keep glibc happy). So the stock version of clone(), when
> +// used with CLONE_VM, would end up corrupting the parent's thread descriptor.
> +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
> +                    int *parent_tidptr, void *newtls, int *child_tidptr) {
> +  long long res;
> +  if (!fn || !child_stack)
> +    return -EINVAL;
> +  CHECK_EQ(0, (uptr)child_stack % 16);
> +  child_stack = (char *)child_stack - 2 * sizeof(void *);
> +  ((void **)child_stack)[0] = (void *)(uptr)fn;
> +  ((void **)child_stack)[1] = arg;
> +  __asm__ __volatile__(
> +                       /* %rax = syscall(%rax = __NR_clone,
> +                        *                %rdi = flags,
> +                        *                %rsi = child_stack,
> +                        *                %rdx = parent_tidptr,
> +                        *                %r8  = new_tls,
> +                        *                %r10 = child_tidptr)
> +                        */
> +                       "movq   %6,%%r8\n"
> +                       "movq   %7,%%r10\n"
> +                       ".cfi_endproc\n"
> +                       "syscall\n"
> +
> +                       /* if (%rax != 0)
> +                        *   return;
> +                        */
> +                       "testq  %%rax,%%rax\n"
> +                       "jnz    1f\n"
> +
> +                       /* In the child. Terminate unwind chain. */
> +                       ".cfi_startproc\n"
> +                       ".cfi_undefined %%rip;\n"
> +                       "xorq   %%rbp,%%rbp\n"
> +
> +                       /* Call "fn(arg)". */
> +                       "popq   %%rax\n"
> +                       "popq   %%rdi\n"
> +                       "call   *%%rax\n"
> +
> +                       /* Call _exit(%rax). */
> +                       "movq   %%rax,%%rdi\n"
> +                       "movq   %2,%%rax\n"
> +                       "syscall\n"
> +
> +                       /* Return to parent. */
> +                     "1:\n"
> +                       : "=a" (res)
> +                       : "a"(__NR_clone), "i"(__NR_exit),
> +                         "S"(child_stack),
> +                         "D"(flags),
> +                         "d"(parent_tidptr),
> +                         "r"(newtls),
> +                         "r"(child_tidptr)
> +                       : "rsp", "memory", "r8", "r10", "r11", "rcx");
> +  return res;
> +}
> +#endif  // defined(__x86_64__)
>   }  // namespace __sanitizer
>   
>   #endif  // SANITIZER_LINUX
>
> Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.h
> URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.h?rev=189753&r1=189752&r2=189753&view=diff
> ==============================================================================
> --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.h (original)
> +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.h Mon Sep  2 06:36:19 2013
> @@ -29,6 +29,10 @@ uptr internal_getdents(fd_t fd, struct l
>   uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
>   uptr internal_sigaltstack(const struct sigaltstack* ss,
>                             struct sigaltstack* oss);
> +#ifdef __x86_64__
> +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
> +                    int *parent_tidptr, void *newtls, int *child_tidptr);
> +#endif
>   
>   // This class reads thread IDs from /proc/<pid>/task using only syscalls.
>   class ThreadLister {
>
> Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
> URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc?rev=189753&r1=189752&r2=189753&view=diff
> ==============================================================================
> --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc (original)
> +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc Mon Sep  2 06:36:19 2013
> @@ -14,12 +14,12 @@
>   
>   
>   #include "sanitizer_platform.h"
> -#if SANITIZER_LINUX
> +#if SANITIZER_LINUX && defined(__x86_64__)
>   
>   #include "sanitizer_stoptheworld.h"
>   
>   #include <errno.h>
> -#include <sched.h> // for clone
> +#include <sched.h> // for CLONE_* definitions
>   #include <stddef.h>
>   #include <sys/prctl.h> // for PR_* definitions
>   #include <sys/ptrace.h> // for PTRACE_* definitions
> @@ -71,7 +71,6 @@
>   // after it has exited. The following functions are used in this manner:
>   // sigdelset()
>   // sigprocmask()
> -// clone()
>   
>   COMPILER_CHECK(sizeof(SuspendedThreadID) == sizeof(pid_t));
>   
> @@ -371,11 +370,14 @@ void StopTheWorld(StopTheWorldCallback c
>     // Block the execution of TracerThread until after we have set ptrace
>     // permissions.
>     tracer_thread_argument.mutex.Lock();
> -  pid_t tracer_pid = clone(TracerThread, tracer_stack.Bottom(),
> -                           CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED,
> -                           &tracer_thread_argument);
> -  if (tracer_pid < 0) {
> -    Report("Failed spawning a tracer thread (errno %d).\n", errno);
> +  uptr tracer_pid = internal_clone(
> +      TracerThread, tracer_stack.Bottom(),
> +      CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED,
> +      &tracer_thread_argument, 0 /* parent_tidptr */, 0 /* newtls */, 0
> +      /* child_tidptr */);
> +  int local_errno = 0;
> +  if (internal_iserror(tracer_pid, &local_errno)) {
> +    Report("Failed spawning a tracer thread (errno %d).\n", local_errno);
>       tracer_thread_argument.mutex.Unlock();
>     } else {
>       // On some systems we have to explicitly declare that we want to be traced
> @@ -390,9 +392,8 @@ void StopTheWorld(StopTheWorldCallback c
>       // At this point, any signal will either be blocked or kill us, so waitpid
>       // should never return (and set errno) while the tracer thread is alive.
>       uptr waitpid_status = internal_waitpid(tracer_pid, NULL, __WALL);
> -    int wperrno;
> -    if (internal_iserror(waitpid_status, &wperrno))
> -      Report("Waiting on the tracer thread failed (errno %d).\n", wperrno);
> +    if (internal_iserror(waitpid_status, &local_errno))
> +      Report("Waiting on the tracer thread failed (errno %d).\n", local_errno);
>     }
>   }
>   
> @@ -448,4 +449,4 @@ uptr SuspendedThreadsList::RegisterCount
>   }
>   }  // namespace __sanitizer
>   
> -#endif  // SANITIZER_LINUX
> +#endif  // SANITIZER_LINUX && defined(__x86_64__)
>
> Modified: compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc
> URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc?rev=189753&r1=189752&r2=189753&view=diff
> ==============================================================================
> --- compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc (original)
> +++ compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc Mon Sep  2 06:36:19 2013
> @@ -12,7 +12,7 @@
>   //===----------------------------------------------------------------------===//
>   
>   #include "sanitizer_common/sanitizer_platform.h"
> -#if SANITIZER_LINUX
> +#if SANITIZER_LINUX && defined(__x86_64__)
>   
>   #include "sanitizer_common/sanitizer_stoptheworld.h"
>   #include "gtest/gtest.h"
> @@ -191,4 +191,4 @@ TEST(StopTheWorld, SuspendThreadsAdvance
>   
>   }  // namespace __sanitizer
>   
> -#endif  // SANITIZER_LINUX
> +#endif  // SANITIZER_LINUX && defined(__x86_64__)
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>





More information about the llvm-commits mailing list