1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <general_test/simple_heap_alloc_test.h>
18
19 #include <cstddef>
20
21 #include <general_test/test_names.h>
22 #include <shared/abort.h>
23 #include <shared/array_length.h>
24 #include <shared/nano_string.h>
25 #include <shared/send_message.h>
26
27 #include <chre.h>
28
29 using nanoapp_testing::MessageType;
30 using nanoapp_testing::sendFatalFailureToHost;
31 using nanoapp_testing::sendMessageToHost;
32 using nanoapp_testing::sendSuccessToHost;
33
34 namespace general_test {
35
36 // For most platforms, we expect that what the compiler toolchain claims
37 // is the maximum alignment needed for any type is accurate. However, we
38 // do support one CHRE implementation where it is configured for a lower
39 // max alignment than what the toolchain claims.
40 // To support this, we allow for a compiler define set for building this
41 // test. For the most part, we need to just trust the CHRE implementation
42 // that this number is correct. However, we perform a basic consistency
43 // check on this in testMaxAlignment().
44
45 constexpr size_t kMaxAlignment =
46 #ifdef CHRE_CUSTOM_MAX_ALIGNMENT
47 CHRE_CUSTOM_MAX_ALIGNMENT;
48 #else
49 alignof(max_align_t);
50 #endif // else CHRE_CUSTOM_MAX_ALIGNMENT
51
52 #ifdef CHRE_CUSTOM_MAX_ALIGNMENT
53 // We only test this when a CHRE implementation claims a custom max aligment.
54 // We use an argument here to try to keep the compiler from performing any
55 // of these calculations at compile-time, so they're forced to happen at
56 // runtime. We do a mixture of multiplication and division, to force
57 // various instructions which might have alignment constraints.
testMaxAlignment(uint32_t zero)58 static void testMaxAlignment(uint32_t zero) {
59 // It's not sufficient to use alignas(kMaxAlignment). Say kMaxAlignment
60 // is 4. Then alignas(4) could legally give something aligned on 32 bytes,
61 // and we wouldn't be testing what we hoped to test. So we ask for double
62 // the alignment (alignas(8), in our example), and then offset into that
63 // to assure that we're at exactly kMaxAlignment, and no more.
64
65 #ifdef CHRE_NO_DOUBLE_SUPPORT
66 typedef float MyFloat;
67 #define FLOAT_C(value) value##f
68 #else
69 typedef long double myFloat;
70 #define FLOAT_C(value) value
71 #endif
72
73 alignas(kMaxAlignment * 2)
74 uint8_t myFloatMemory[sizeof(MyFloat) * 3 + kMaxAlignment];
75 MyFloat *mfArray = reinterpret_cast<MyFloat *>(myFloatMemory + kMaxAlignment);
76 mfArray[0] = static_cast<MyFloat>(zero) + FLOAT_C(1.0);
77 mfArray[1] = static_cast<MyFloat>(zero) + FLOAT_C(3.0);
78 mfArray[2] = mfArray[0] / mfArray[1];
79 if ((mfArray[0] * mfArray[1] + mfArray[2]) / FLOAT_C(3.0) == FLOAT_C(1.0)) {
80 sendFatalFailureToHost("Float math is wrong");
81 }
82
83 constexpr size_t kUllSize = sizeof(unsigned long long);
84 static_assert(kUllSize >= 8, "Size of long long violates spec");
85 alignas(kMaxAlignment * 2)
86 uint8_t longlongMemory[kUllSize * 3 + kMaxAlignment];
87 unsigned long long *ullArray =
88 reinterpret_cast<unsigned long long *>(longlongMemory + kMaxAlignment);
89 ullArray[0] =
90 static_cast<unsigned long long>(zero) + (1ULL << (kUllSize * 8 - 4));
91 ullArray[1] = static_cast<unsigned long long>(zero) + (1ULL << 3);
92 ullArray[2] = ullArray[0] * ullArray[1];
93 constexpr unsigned long long kExpected = 747134227367742ULL;
94 unsigned long long result = ullArray[2] / 12345ULL;
95 if (((kUllSize == 8) && (result != kExpected)) ||
96 ((kUllSize > 8) && (result <= kExpected))) {
97 sendFatalFailureToHost("Long long math is wrong");
98 }
99 }
100 #endif // CHRE_CUSTOM_MAX_ALIGNMENT
101
SimpleHeapAllocTest()102 SimpleHeapAllocTest::SimpleHeapAllocTest()
103 : Test(CHRE_API_VERSION_1_0), mHasFreed(false) {}
104
setUp(uint32_t messageSize,const void *)105 void SimpleHeapAllocTest::setUp(uint32_t messageSize,
106 const void * /* message */) {
107 nanoapp_testing::memset(mPtrs, 0, sizeof(mPtrs));
108
109 if (messageSize != 0) {
110 sendFatalFailureToHost(
111 "SimpleHeapAlloc message expects 0 additional bytes, got ",
112 &messageSize);
113 }
114
115 // Allocate random small-ish sizes.
116 static constexpr size_t kSizes[5] = {16, 53, 2, 32, 40};
117
118 mPtrs[0] = chreHeapAlloc(kSizes[0]);
119 mPtrs[1] = chreHeapAlloc(kSizes[1]);
120 // For mPtrs[2] we do _not_ use kSizes[2], because we're going to free
121 // this in a moment, and intentionally want a different size.
122 mPtrs[2] = chreHeapAlloc(23);
123 mPtrs[3] = chreHeapAlloc(kSizes[3]);
124 // We want to mix in a free among the allocs, just to make sure there
125 // isn't some issue there.
126 if (mPtrs[2] == nullptr) {
127 sendFatalFailureToHost("Failed first allocation of mPtrs[2]");
128 } else {
129 chreHeapFree(mPtrs[2]);
130 }
131 mPtrs[4] = chreHeapAlloc(kSizes[4]);
132 mPtrs[2] = chreHeapAlloc(kSizes[2]);
133
134 for (uint32_t i = 0; i < arrayLength(mPtrs); i++) {
135 if (mPtrs[i] == nullptr) {
136 // If we're getting this failure, but convinced the CHRE is
137 // correct, make sure that we're actually performing an allocation
138 // for each element of mPtrs.
139 sendFatalFailureToHost("Failed to allocate index ", &i);
140 }
141 const uintptr_t ptrValue = reinterpret_cast<uintptr_t>(mPtrs[i]);
142 if ((ptrValue & (kMaxAlignment - 1)) != 0) {
143 sendFatalFailureToHost("Misaligned allocation at index ", &i);
144 }
145 // Make sure all of the bytes are addressable. Our assumption
146 // is we'll crash here if that's not the case. Not the most
147 // friendly test, but it's better than allowing a bad CHRE.
148 // TODO: If we convince ourselves that chreLog() should be
149 // safe enough to use here, we could log an 'info' message
150 // prior to each memset attempt.
151 nanoapp_testing::memset(mPtrs[i], 0xFF, kSizes[i]);
152 }
153 #ifdef CHRE_CUSTOM_MAX_ALIGNMENT
154 testMaxAlignment(messageSize);
155 #endif // CHRE_CUSTOM_MAX_ALIGNMENT
156 sendMessageToHost(MessageType::kContinue);
157 }
158
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)159 void SimpleHeapAllocTest::handleEvent(uint32_t senderInstanceId,
160 uint16_t eventType,
161 const void *eventData) {
162 // We ignore the return value, since we expect no data.
163 getMessageDataFromHostEvent(senderInstanceId, eventType, eventData,
164 MessageType::kContinue, 0);
165 if (mHasFreed) {
166 sendFatalFailureToHost("Multiple kContinue messages sent");
167 }
168
169 chreHeapFree(mPtrs[3]);
170 chreHeapFree(mPtrs[1]);
171 chreHeapFree(mPtrs[2]);
172 chreHeapFree(mPtrs[0]);
173 chreHeapFree(mPtrs[4]);
174 mHasFreed = true;
175
176 sendSuccessToHost();
177 }
178
179 } // namespace general_test
180