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