1 | //===-- Implementation of libc death test executors -----------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "src/__support/common.h" |
10 | #include "src/__support/macros/config.h" |
11 | #include <stddef.h> |
12 | #include <stdint.h> |
13 | |
14 | #ifdef LIBC_TARGET_ARCH_IS_AARCH64 |
15 | #include "src/sys/auxv/getauxval.h" |
16 | #endif |
17 | |
18 | namespace LIBC_NAMESPACE_DECL { |
19 | |
20 | int bcmp(const void *lhs, const void *rhs, size_t count); |
21 | void bzero(void *ptr, size_t count); |
22 | int memcmp(const void *lhs, const void *rhs, size_t count); |
23 | void *memcpy(void *__restrict, const void *__restrict, size_t); |
24 | void *memmove(void *dst, const void *src, size_t count); |
25 | void *memset(void *ptr, int value, size_t count); |
26 | int atexit(void (*func)(void)); |
27 | |
28 | // TODO: It seems that some old test frameworks does not use |
29 | // add_libc_hermetic_test properly. Such that they won't get correct linkage |
30 | // against the object containing this function. We create a dummy function that |
31 | // always returns 0 to indicate a failure. |
32 | [[gnu::weak]] unsigned long getauxval(unsigned long id) { return 0; } |
33 | |
34 | } // namespace LIBC_NAMESPACE_DECL |
35 | |
36 | constexpr uint64_t ALIGNMENT = alignof(uintptr_t); |
37 | |
38 | namespace { |
39 | |
40 | // Integration tests cannot use the SCUDO standalone allocator as SCUDO pulls |
41 | // various other parts of the libc. Since SCUDO development does not use |
42 | // LLVM libc build rules, it is very hard to keep track or pull all that SCUDO |
43 | // requires. Hence, as a work around for this problem, we use a simple allocator |
44 | // which just hands out continuous blocks from a statically allocated chunk of |
45 | // memory. |
46 | static constexpr uint64_t MEMORY_SIZE = 65336; |
47 | alignas(ALIGNMENT) static uint8_t memory[MEMORY_SIZE]; |
48 | static uint8_t *ptr = memory; |
49 | |
50 | } // anonymous namespace |
51 | |
52 | extern "C" { |
53 | |
54 | // Hermetic tests rely on the following memory functions. This is because the |
55 | // compiler code generation can emit calls to them. We want to map the external |
56 | // entrypoint to the internal implementation of the function used for testing. |
57 | // This is done manually as not all targets support aliases. |
58 | |
59 | int bcmp(const void *lhs, const void *rhs, size_t count) { |
60 | return LIBC_NAMESPACE::bcmp(lhs, rhs, count); |
61 | } |
62 | void bzero(void *ptr, size_t count) { LIBC_NAMESPACE::bzero(ptr, count); } |
63 | int memcmp(const void *lhs, const void *rhs, size_t count) { |
64 | return LIBC_NAMESPACE::memcmp(lhs, rhs, count); |
65 | } |
66 | void *memcpy(void *__restrict dst, const void *__restrict src, size_t count) { |
67 | return LIBC_NAMESPACE::memcpy(dst, src, count); |
68 | } |
69 | void *memmove(void *dst, const void *src, size_t count) { |
70 | return LIBC_NAMESPACE::memmove(dst, src, count); |
71 | } |
72 | void *memset(void *ptr, int value, size_t count) { |
73 | return LIBC_NAMESPACE::memset(ptr, value, count); |
74 | } |
75 | |
76 | // This is needed if the test was compiled with '-fno-use-cxa-atexit'. |
77 | int atexit(void (*func)(void)) { return LIBC_NAMESPACE::atexit(func); } |
78 | |
79 | void *malloc(size_t s) { |
80 | // Keep the bump pointer aligned on an eight byte boundary. |
81 | s = ((s + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT; |
82 | void *mem = ptr; |
83 | ptr += s; |
84 | return static_cast<uint64_t>(ptr - memory) >= MEMORY_SIZE ? nullptr : mem; |
85 | } |
86 | |
87 | void free(void *) {} |
88 | |
89 | void *realloc(void *mem, size_t s) { |
90 | if (mem == nullptr) |
91 | return malloc(s); |
92 | uint8_t *newmem = reinterpret_cast<uint8_t *>(malloc(s)); |
93 | if (newmem == nullptr) |
94 | return nullptr; |
95 | uint8_t *oldmem = reinterpret_cast<uint8_t *>(mem); |
96 | // We use a simple for loop to copy the data over. |
97 | // If |s| is less the previous alloc size, the copy works as expected. |
98 | // If |s| is greater than the previous alloc size, then garbage is copied |
99 | // over to the additional part in the new memory block. |
100 | for (size_t i = 0; i < s; ++i) |
101 | newmem[i] = oldmem[i]; |
102 | return newmem; |
103 | } |
104 | |
105 | // The unit test framework uses pure virtual functions. Since hermetic tests |
106 | // cannot depend C++ runtime libraries, implement dummy functions to support |
107 | // the virtual function runtime. |
108 | void __cxa_pure_virtual() { |
109 | // A pure virtual being called is an error so we just trap. |
110 | __builtin_trap(); |
111 | } |
112 | |
113 | // Hermetic tests are linked with -nostdlib. BFD linker expects |
114 | // __dso_handle when -nostdlib is used. |
115 | void *__dso_handle = nullptr; |
116 | |
117 | #ifdef LIBC_TARGET_ARCH_IS_AARCH64 |
118 | // Due to historical reasons, libgcc on aarch64 may expect __getauxval to be |
119 | // defined. See also https://gcc.gnu.org/pipermail/gcc-cvs/2020-June/300635.html |
120 | unsigned long __getauxval(unsigned long id) { |
121 | return LIBC_NAMESPACE::getauxval(id); |
122 | } |
123 | #endif |
124 | |
125 | } // extern "C" |
126 | |
127 | void *operator new(size_t size, void *ptr) { return ptr; } |
128 | |
129 | void *operator new(size_t size) { return malloc(s: size); } |
130 | |
131 | void *operator new[](size_t size) { return malloc(s: size); } |
132 | |
133 | void operator delete(void *) { |
134 | // The libc runtime should not use the global delete operator. Hence, |
135 | // we just trap here to catch any such accidental usages. |
136 | __builtin_trap(); |
137 | } |
138 | |
139 | void operator delete(void *ptr, size_t size) { __builtin_trap(); } |
140 | |
141 | // Defining members in the std namespace is not preferred. But, we do it here |
142 | // so that we can use it to define the operator new which takes std::align_val_t |
143 | // argument. |
144 | namespace std { |
145 | enum class align_val_t : size_t {}; |
146 | } // namespace std |
147 | |
148 | void operator delete(void *mem, std::align_val_t) noexcept { __builtin_trap(); } |
149 | |
150 | void operator delete(void *mem, unsigned int, std::align_val_t) noexcept { |
151 | __builtin_trap(); |
152 | } |
153 | |