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/heap_alloc_stress_test.h>
18
19 #include <cstddef>
20
21 #include <general_test/test_names.h>
22 #include <shared/abort.h>
23 #include <shared/send_message.h>
24
25 #include <chre.h>
26
27 using nanoapp_testing::sendFailureToHost;
28 using nanoapp_testing::sendFatalFailureToHost;
29 using nanoapp_testing::sendSuccessToHost;
30
31 namespace general_test {
32
tryAbsurdMalloc(uint32_t hugeSize)33 static void tryAbsurdMalloc(uint32_t hugeSize) {
34 void *ptr = chreHeapAlloc(hugeSize);
35 if (ptr != NULL) {
36 sendFailureToHost("chreHeapAlloc claimed allocation of huge size ",
37 &hugeSize);
38 chreHeapFree(ptr);
39 nanoapp_testing::abort();
40 }
41 }
42
HeapAllocStressTest()43 HeapAllocStressTest::HeapAllocStressTest()
44 : Test(CHRE_API_VERSION_1_0) {
45 }
46
setUp(uint32_t messageSize,const void *)47 void HeapAllocStressTest::setUp(uint32_t messageSize,
48 const void * /* message */) {
49 if (messageSize != 0) {
50 sendFatalFailureToHost(
51 "HeapAllocStress message expects 0 additional bytes, got ",
52 &messageSize);
53 }
54
55 // 1GB should be absurd on any CHRE implementation we anticipate for a
56 // while.
57 tryAbsurdMalloc(UINT32_C(0x40000000));
58
59 // Let's also make sure there's nothing treating this as signed behind
60 // the scenes and breaking things.
61 tryAbsurdMalloc(UINT32_C(-16));
62
63 // Since NULL is a valid response to chreHeapAlloc(), chreHeapFree()
64 // must accept it as an argument.
65 chreHeapFree(NULL);
66
67 // We do not test chreHeapFree() with invalid pointers, because that's
68 // an error by the caller, and there's no requirement for the CHRE
69 // implementation to handle it nicely.
70
71
72 // Now let's exhaust the heap, and make sure it properly frees up to allow
73 // things to be allocated again.
74 constexpr size_t kNumPtrs = 256;
75 void **ptrs = reinterpret_cast<void**>(
76 chreHeapAlloc(kNumPtrs * sizeof(void*)));
77 if (ptrs == NULL) {
78 // Oh, the irony.
79 sendFatalFailureToHost(
80 "Insufficient free heap to test heap exhaustion.");
81 }
82
83 size_t index;
84 uint32_t last_alloc_size = 1024 * 1024 * 256;
85 for (index = 0; (index < kNumPtrs); index++) {
86 uint32_t curr_alloc_size = last_alloc_size;
87 void *ptr = chreHeapAlloc(curr_alloc_size);
88 while (ptr == NULL) {
89 curr_alloc_size /= 2;
90 if (curr_alloc_size < 16) {
91 break;
92 }
93 ptr = chreHeapAlloc(curr_alloc_size);
94 }
95 if (ptr == NULL) {
96 break;
97 }
98 last_alloc_size = curr_alloc_size;
99 ptrs[index] = ptr;
100 }
101 if (index == 0) {
102 sendFatalFailureToHost(
103 "Failed to allocate anything for heap exhaustion");
104 }
105
106 // We should be able to free this allocation, and then obtain it again.
107 index--;
108 chreHeapFree(ptrs[index]);
109 ptrs[index] = chreHeapAlloc(last_alloc_size);
110 if (ptrs[index] == NULL) {
111 sendFatalFailureToHost(
112 "After exhausting heap and then free'ing, unable to alloc "
113 "again for size ", &last_alloc_size);
114 }
115
116 // Everything's good, let's free up our memory.
117 for (size_t i = 0; i <= index; i++) {
118 chreHeapFree(ptrs[i]);
119 }
120 chreHeapFree(ptrs);
121
122 sendSuccessToHost();
123 }
124
handleEvent(uint32_t,uint16_t eventType,const void *)125 void HeapAllocStressTest::handleEvent(uint32_t /* senderInstanceId */,
126 uint16_t eventType,
127 const void* /* eventData */) {
128 unexpectedEvent(eventType);
129 }
130
131 } // namespace general_test
132