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 <stddef.h> |
10 | #include <stdint.h> |
11 | |
12 | namespace LIBC_NAMESPACE { |
13 | |
14 | int bcmp(const void *lhs, const void *rhs, size_t count); |
15 | void bzero(void *ptr, size_t count); |
16 | int memcmp(const void *lhs, const void *rhs, size_t count); |
17 | void *memcpy(void *__restrict, const void *__restrict, size_t); |
18 | void *memmove(void *dst, const void *src, size_t count); |
19 | void *memset(void *ptr, int value, size_t count); |
20 | int atexit(void (*func)(void)); |
21 | |
22 | } // namespace LIBC_NAMESPACE |
23 | |
24 | namespace { |
25 | |
26 | // Integration tests cannot use the SCUDO standalone allocator as SCUDO pulls |
27 | // various other parts of the libc. Since SCUDO development does not use |
28 | // LLVM libc build rules, it is very hard to keep track or pull all that SCUDO |
29 | // requires. Hence, as a work around for this problem, we use a simple allocator |
30 | // which just hands out continuous blocks from a statically allocated chunk of |
31 | // memory. |
32 | static constexpr uint64_t MEMORY_SIZE = 65336; |
33 | static uint8_t memory[MEMORY_SIZE]; |
34 | static uint8_t *ptr = memory; |
35 | |
36 | } // anonymous namespace |
37 | |
38 | extern "C" { |
39 | |
40 | // Hermetic tests rely on the following memory functions. This is because the |
41 | // compiler code generation can emit calls to them. We want to map the external |
42 | // entrypoint to the internal implementation of the function used for testing. |
43 | // This is done manually as not all targets support aliases. |
44 | |
45 | int bcmp(const void *lhs, const void *rhs, size_t count) { |
46 | return LIBC_NAMESPACE::bcmp(lhs, rhs, count); |
47 | } |
48 | void bzero(void *ptr, size_t count) { LIBC_NAMESPACE::bzero(ptr, count); } |
49 | int memcmp(const void *lhs, const void *rhs, size_t count) { |
50 | return LIBC_NAMESPACE::memcmp(lhs, rhs, count); |
51 | } |
52 | void *memcpy(void *__restrict dst, const void *__restrict src, size_t count) { |
53 | return LIBC_NAMESPACE::memcpy(dst, src, count); |
54 | } |
55 | void *memmove(void *dst, const void *src, size_t count) { |
56 | return LIBC_NAMESPACE::memmove(dst, src, count); |
57 | } |
58 | void *memset(void *ptr, int value, size_t count) { |
59 | return LIBC_NAMESPACE::memset(ptr, value, count); |
60 | } |
61 | |
62 | // This is needed if the test was compiled with '-fno-use-cxa-atexit'. |
63 | int atexit(void (*func)(void)) { return LIBC_NAMESPACE::atexit(func); } |
64 | |
65 | constexpr uint64_t ALIGNMENT = alignof(uintptr_t); |
66 | |
67 | void *malloc(size_t s) { |
68 | // Keep the bump pointer aligned on an eight byte boundary. |
69 | s = ((s + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT; |
70 | void *mem = ptr; |
71 | ptr += s; |
72 | return static_cast<uint64_t>(ptr - memory) >= MEMORY_SIZE ? nullptr : mem; |
73 | } |
74 | |
75 | void free(void *) {} |
76 | |
77 | void *realloc(void *mem, size_t s) { |
78 | if (mem == nullptr) |
79 | return malloc(s); |
80 | uint8_t *newmem = reinterpret_cast<uint8_t *>(malloc(s)); |
81 | if (newmem == nullptr) |
82 | return nullptr; |
83 | uint8_t *oldmem = reinterpret_cast<uint8_t *>(mem); |
84 | // We use a simple for loop to copy the data over. |
85 | // If |s| is less the previous alloc size, the copy works as expected. |
86 | // If |s| is greater than the previous alloc size, then garbage is copied |
87 | // over to the additional part in the new memory block. |
88 | for (size_t i = 0; i < s; ++i) |
89 | newmem[i] = oldmem[i]; |
90 | return newmem; |
91 | } |
92 | |
93 | // The unit test framework uses pure virtual functions. Since hermetic tests |
94 | // cannot depend C++ runtime libraries, implement dummy functions to support |
95 | // the virtual function runtime. |
96 | void __cxa_pure_virtual() { |
97 | // A pure virtual being called is an error so we just trap. |
98 | __builtin_trap(); |
99 | } |
100 | |
101 | // Hermetic tests are linked with -nostdlib. BFD linker expects |
102 | // __dso_handle when -nostdlib is used. |
103 | void *__dso_handle = nullptr; |
104 | |
105 | } // extern "C" |
106 | |
107 | void *operator new(unsigned long size, void *ptr) { return ptr; } |
108 | |
109 | void *operator new(size_t size) { return malloc(s: size); } |
110 | |
111 | void *operator new[](size_t size) { return malloc(s: size); } |
112 | |
113 | void operator delete(void *) { |
114 | // The libc runtime should not use the global delete operator. Hence, |
115 | // we just trap here to catch any such accidental usages. |
116 | __builtin_trap(); |
117 | } |
118 | |
119 | void operator delete(void *ptr, size_t size) { __builtin_trap(); } |
120 | |