From: Luís Marques Date: Mon, 8 Mar 2021 22:28:19 +0000 (+0000) Subject: [Sanitizer][RISCV] Fix internal_clone X-Git-Tag: llvmorg-14-init~12984 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c5a6ad86b066a6f159b687d181d947cb43aab70b;p=platform%2Fupstream%2Fllvm.git [Sanitizer][RISCV] Fix internal_clone A RISC-V implementation of `internal_clone` was introduced in D87573, as part of the RISC-V ASan patch set by @EccoTheDolphin. That function was never used/tested until I ported LSan for RISC-V, as part of D92403. That port revealed problems in the original implementation, so I provided a fix in D92403. Unfortunately, my choice of replacing the assembly with regular C++ code wasn't correct. The clone syscall arguments specify a separate stack, so non-inlined calls, spills, etc. aren't going to work. This wasn't a problem in practice for optimized builds of Compiler-RT, but it breaks for debug builds. This patch fixes the original problem while keeping the assembly. Differential Revision: https://reviews.llvm.org/D96954 --- diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp index 9d4fd06..25c0751 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -1338,17 +1338,41 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr) { if (!fn || !child_stack) return -EINVAL; + CHECK_EQ(0, (uptr)child_stack % 16); - child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); - ((unsigned long long *)child_stack)[0] = (uptr)fn; - ((unsigned long long *)child_stack)[1] = (uptr)arg; - int tid = internal_syscall(SYSCALL(clone), (unsigned long)flags, child_stack, - parent_tidptr, newtls, child_tidptr); - if (tid != 0) - return tid; - fn(arg); - internal_syscall(SYSCALL(exit), 0); + register int res __asm__("a0"); + register int __flags __asm__("a0") = flags; + register void *__stack __asm__("a1") = child_stack; + register int *__ptid __asm__("a2") = parent_tidptr; + register void *__tls __asm__("a3") = newtls; + register int *__ctid __asm__("a4") = child_tidptr; + register int (*__fn)(void *) __asm__("a5") = fn; + register void *__arg __asm__("a6") = arg; + register int nr_clone __asm__("a7") = __NR_clone; + + __asm__ __volatile__( + "ecall\n" + + /* if (a0 != 0) + * return a0; + */ + "bnez a0, 1f\n" + + // In the child, now. Call "fn(arg)". + "mv a0, a6\n" + "jalr a5\n" + + // Call _exit(a0). + "addi a7, zero, %9\n" + "ecall\n" + "1:\n" + + : "=r"(res) + : "0"(__flags), "r"(__stack), "r"(__ptid), "r"(__tls), "r"(__ctid), + "r"(__fn), "r"(__arg), "r"(nr_clone), "i"(__NR_exit) + : "memory"); + return res; } #elif defined(__aarch64__) uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,