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