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
29using nanoapp_testing::MessageType;
30using nanoapp_testing::sendFatalFailureToHost;
31using nanoapp_testing::sendMessageToHost;
32using nanoapp_testing::sendSuccessToHost;
33
34namespace 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 make a basic sanity check of
43// this in testMaxAlignment().
44
45constexpr 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.
58static 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) uint8_t
74      myFloatMemory[sizeof(MyFloat) * 3 + kMaxAlignment];
75  MyFloat *mfArray =
76      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    sendFatalFailureToHost("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) uint8_t
87      longlongMemory[kUllSize * 3 + kMaxAlignment];
88  unsigned long long *ullArray =
89      reinterpret_cast<unsigned long long*>(longlongMemory + kMaxAlignment);
90  ullArray[0] = static_cast<unsigned long long>(zero) +
91      (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    sendFatalFailureToHost("Long long math is wrong");
99  }
100}
101#endif  // CHRE_CUSTOM_MAX_ALIGNMENT
102
103
104SimpleHeapAllocTest::SimpleHeapAllocTest()
105  : Test(CHRE_API_VERSION_1_0), mHasFreed(false) {
106}
107
108void SimpleHeapAllocTest::setUp(uint32_t messageSize,
109                                const void * /* message */) {
110  nanoapp_testing::memset(mPtrs, 0, sizeof(mPtrs));
111
112  if (messageSize != 0) {
113    sendFatalFailureToHost(
114        "SimpleHeapAlloc message expects 0 additional bytes, got ",
115        &messageSize);
116  }
117
118  // Allocate random small-ish sizes.
119  static constexpr size_t kSizes[5] = {
120    16, 53, 2, 32, 40 };
121
122  mPtrs[0] = chreHeapAlloc(kSizes[0]);
123  mPtrs[1] = chreHeapAlloc(kSizes[1]);
124  // For mPtrs[2] we do _not_ use kSizes[2], because we're going to free
125  // this in a moment, and intentionally want a different size.
126  mPtrs[2] = chreHeapAlloc(23);
127  mPtrs[3] = chreHeapAlloc(kSizes[3]);
128  // We want to mix in a free among the allocs, just to make sure there
129  // isn't some issue there.
130  if (mPtrs[2] == nullptr) {
131    sendFatalFailureToHost("Failed first allocation of mPtrs[2]");
132  } else {
133    chreHeapFree(mPtrs[2]);
134  }
135  mPtrs[4] = chreHeapAlloc(kSizes[4]);
136  mPtrs[2] = chreHeapAlloc(kSizes[2]);
137
138  for (uint32_t i = 0; i < arrayLength(mPtrs); i++) {
139    if (mPtrs[i] == nullptr) {
140      // If we're getting this failure, but convinced the CHRE is
141      // correct, make sure that we're actually performing an allocation
142      // for each element of mPtrs.
143      sendFatalFailureToHost("Failed to allocate index ", &i);
144    }
145    const uintptr_t ptrValue = reinterpret_cast<uintptr_t>(mPtrs[i]);
146    if ((ptrValue & (kMaxAlignment - 1)) != 0) {
147      sendFatalFailureToHost("Misaligned allocation at index ", &i);
148    }
149    // Make sure all of the bytes are addressable.  Our assumption
150    // is we'll crash here if that's not the case.  Not the most
151    // friendly test, but it's better than allowing a bad CHRE.
152    // TODO: If we convince ourselves that chreLog() should be
153    //     safe enough to use here, we could log an 'info' message
154    //     prior to each memset attempt.
155    nanoapp_testing::memset(mPtrs[i], 0xFF, kSizes[i]);
156  }
157#ifdef CHRE_CUSTOM_MAX_ALIGNMENT
158  testMaxAlignment(messageSize);
159#endif  // CHRE_CUSTOM_MAX_ALIGNMENT
160  sendMessageToHost(MessageType::kContinue);
161}
162
163void SimpleHeapAllocTest::handleEvent(uint32_t senderInstanceId,
164                                      uint16_t eventType,
165                                      const void* eventData) {
166  // We ignore the return value, since we expect no data.
167  getMessageDataFromHostEvent(senderInstanceId, eventType, eventData,
168                              MessageType::kContinue, 0);
169  if (mHasFreed) {
170    sendFatalFailureToHost("Multiple kContinue messages sent");
171  }
172
173  chreHeapFree(mPtrs[3]);
174  chreHeapFree(mPtrs[1]);
175  chreHeapFree(mPtrs[2]);
176  chreHeapFree(mPtrs[0]);
177  chreHeapFree(mPtrs[4]);
178  mHasFreed = true;
179
180  sendSuccessToHost();
181}
182
183}  // namespace general_test
184