1 /*
2 * Copyright (C) 2022 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 <dlmalloc_app.h>
18 #include <dlmalloc_consts.h>
19 #include <errno.h>
20 #include <lib/tipc/tipc.h>
21 #include <lib/unittest/unittest.h>
22 #include <stdlib.h>
23 #include <trusty_unittest.h>
24 #include <uapi/err.h>
25
26 #define TLOG_TAG "dlmalloc_test"
27
28 /*
29 * Sends command to app and then waits for a
30 * reply or channel close. In the non-crashing case, the server
31 * should echo back the original command and dlmalloc_srv_rpc returns
32 * NO_ERROR.
33 */
dlmalloc_srv_rpc_expect(handle_t chan,enum dlmalloc_test_command cmd,int expected)34 static void dlmalloc_srv_rpc_expect(handle_t chan,
35 enum dlmalloc_test_command cmd,
36 int expected) {
37 int ret;
38 struct dlmalloc_test_msg msg = {
39 .cmd = cmd,
40 };
41
42 ret = tipc_send1(chan, &msg, sizeof(msg));
43 ASSERT_EQ(ret, sizeof(msg));
44
45 struct uevent evt;
46 ret = wait(chan, &evt, INFINITE_TIME);
47 ASSERT_EQ(NO_ERROR, ret);
48
49 int event = evt.event & IPC_HANDLE_POLL_MSG;
50 if (evt.event & IPC_HANDLE_POLL_HUP) {
51 ASSERT_EQ(event, 0);
52 ASSERT_EQ(ERR_CHANNEL_CLOSED, expected);
53 goto test_abort;
54 }
55 ASSERT_NE(event, 0);
56
57 ret = tipc_recv1(chan, sizeof(msg), &msg, sizeof(msg));
58 ASSERT_EQ(ret, sizeof(msg));
59 ASSERT_EQ(msg.cmd, cmd);
60
61 test_abort:;
62 }
63
dlmalloc_srv_rpc(handle_t chan,enum dlmalloc_test_command cmd)64 static void dlmalloc_srv_rpc(handle_t chan, enum dlmalloc_test_command cmd) {
65 dlmalloc_srv_rpc_expect(chan, cmd, NO_ERROR);
66 }
67
68 typedef struct dlmalloc_info {
69 handle_t chan;
70 } dlmalloc_info_t;
71
TEST_F_SETUP(dlmalloc_info)72 TEST_F_SETUP(dlmalloc_info) {
73 _state->chan = INVALID_IPC_HANDLE;
74 ASSERT_EQ(tipc_connect(&_state->chan, DLMALLOC_TEST_SRV_PORT), 0);
75
76 test_abort:;
77 }
78
TEST_F_TEARDOWN(dlmalloc_info)79 TEST_F_TEARDOWN(dlmalloc_info) {
80 close(_state->chan);
81 }
82
TEST_F(dlmalloc_info,nop)83 TEST_F(dlmalloc_info, nop) {
84 dlmalloc_srv_rpc(_state->chan, DLMALLOC_TEST_NOP);
85 }
86
TEST_F(dlmalloc_info,one_malloc)87 TEST_F(dlmalloc_info, one_malloc) {
88 dlmalloc_srv_rpc(_state->chan, DLMALLOC_TEST_ONE_MALLOC);
89 }
90
TEST_F(dlmalloc_info,one_calloc)91 TEST_F(dlmalloc_info, one_calloc) {
92 dlmalloc_srv_rpc(_state->chan, DLMALLOC_TEST_ONE_CALLOC);
93 }
94
TEST_F(dlmalloc_info,one_realloc)95 TEST_F(dlmalloc_info, one_realloc) {
96 dlmalloc_srv_rpc(_state->chan, DLMALLOC_TEST_ONE_REALLOC);
97 }
98
TEST_F(dlmalloc_info,many_malloc)99 TEST_F(dlmalloc_info, many_malloc) {
100 dlmalloc_srv_rpc(_state->chan, DLMALLOC_TEST_MANY_MALLOC);
101 }
102
TEST_F(dlmalloc_info,one_new)103 TEST_F(dlmalloc_info, one_new) {
104 dlmalloc_srv_rpc(_state->chan, DLMALLOC_TEST_ONE_NEW);
105 }
106
TEST_F(dlmalloc_info,one_new_arr)107 TEST_F(dlmalloc_info, one_new_arr) {
108 dlmalloc_srv_rpc(_state->chan, DLMALLOC_TEST_ONE_NEW_ARR);
109 }
110
TEST_F(dlmalloc_info,malloc_and_new)111 TEST_F(dlmalloc_info, malloc_and_new) {
112 dlmalloc_srv_rpc(_state->chan, DLMALLOC_TEST_MALLOC_AND_NEW);
113 }
114
TEST_F(dlmalloc_info,double_free)115 TEST_F(dlmalloc_info, double_free) {
116 dlmalloc_srv_rpc_expect(_state->chan, DLMALLOC_TEST_DOUBLE_FREE,
117 ERR_CHANNEL_CLOSED);
118 }
119
TEST_F(dlmalloc_info,realloc_after_free)120 TEST_F(dlmalloc_info, realloc_after_free) {
121 dlmalloc_srv_rpc_expect(_state->chan, DLMALLOC_TEST_REALLOC_AFTER_FREE,
122 ERR_CHANNEL_CLOSED);
123 }
124
TEST_F(dlmalloc_info,alloc_large)125 TEST_F(dlmalloc_info, alloc_large) {
126 dlmalloc_srv_rpc(_state->chan, DLMALLOC_TEST_ALLOC_LARGE);
127 }
128
TEST_F(dlmalloc_info,malloc_loop)129 TEST_F(dlmalloc_info, malloc_loop) {
130 for (int i = 0; i < 1024; i++) {
131 void* ptr = malloc(4096 * 3);
132 ASSERT_NE(0, ptr, "iteration %d", i);
133 free(ptr);
134 }
135
136 test_abort:;
137 }
138
139 #define CLEAR_ERRNO() \
140 do { \
141 errno = 0; \
142 } while (0)
143
TEST_F(dlmalloc_info,malloc_oom)144 TEST_F(dlmalloc_info, malloc_oom) {
145 void* ptr = malloc(8192 * 1024);
146 ASSERT_EQ(0, ptr);
147 /* TODO: ENOMEM */
148 CLEAR_ERRNO();
149
150 test_abort:;
151 }
152
expected_malloc_alignment(size_t size)153 static uintptr_t expected_malloc_alignment(size_t size) {
154 /* TODO use ffs? */
155 if (size >= 16) {
156 return sizeof(void*) * 2;
157 } else if (size >= 8) {
158 return 8;
159 } else if (size >= 4) {
160 return 4;
161 } else if (size >= 2) {
162 return 2;
163 } else {
164 return 1;
165 }
166 }
167
TEST_F(dlmalloc_info,malloc_alignment)168 TEST_F(dlmalloc_info, malloc_alignment) {
169 for (int size = 2; size < 256; size++) {
170 const uintptr_t alignment_mask = expected_malloc_alignment(size) - 1;
171 void* ptr1 = malloc(size);
172 void* ptr2 = malloc(size / 2); /* Try to shake up the alignment. */
173 void* ptr3 = malloc(size);
174
175 ASSERT_EQ(0, (uintptr_t)ptr1 & alignment_mask, "size %d / align %zu",
176 size, alignment_mask + 1);
177 ASSERT_EQ(0, (uintptr_t)ptr3 & alignment_mask, "size %d / align %zu",
178 size, alignment_mask + 1);
179
180 free(ptr3);
181 free(ptr2);
182 free(ptr1);
183 }
184 test_abort:;
185 }
186
187 PORT_TEST(dlmalloc_info, "com.android.trusty.dlmalloctest")
188