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