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