1/*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *    http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16
17#include <stdio.h>
18#include <malloc.h>
19#include <stdlib.h>
20#include <pthread.h>
21#include <stdint.h>
22#include <memory.h>
23
24#include "test-malloc-api-common.h"
25
26#define BARRIER_HEIGHT 2
27#define ALLOCATIONS_NUMBER 8
28#define MIN(x, y) (((x) < (y)) ? (x) : (y))
29
30typedef struct iterate_arg_s {
31	uintptr_t allocs[ALLOCATIONS_NUMBER];
32	size_t allocs_reported_number[ALLOCATIONS_NUMBER];
33	size_t allocs_actual_sizes[ALLOCATIONS_NUMBER];
34	size_t reported_sizes[ALLOCATIONS_NUMBER];
35} iterate_arg_t;
36
37typedef struct {
38	uintptr_t *base;
39	size_t size;
40} allocations_info_t;
41
42static const size_t allocs_sizes[ALLOCATIONS_NUMBER] = {
43	8,
44	2 * 1024,
45	64 * 1024,
46	512 * 1024,
47	2 * 1024 * 1024,
48	8 * 1024 * 1024,
49	16 * 1024 * 1024,
50	32 * 1024 * 1024
51};
52
53void iterate_callback(void *base, size_t size, void *data)
54{
55	iterate_arg_t *iterate_arg = (iterate_arg_t *) data;
56	uintptr_t end;
57	if (__builtin_add_overflow((uintptr_t) base, size, &end)) {
58		return;
59	}
60
61	for (size_t i = 0; i < ALLOCATIONS_NUMBER; ++i) {
62		if (iterate_arg->allocs[i] >= (uintptr_t) base && iterate_arg->allocs[i] < end) {
63			iterate_arg->allocs_reported_number[i]++;
64			uintptr_t max_size = end - iterate_arg->allocs[i];
65			iterate_arg->reported_sizes[i] = MIN(size, max_size);
66		}
67	}
68}
69
70void fill_allocations_info(const iterate_arg_t *iterate_arg, allocations_info_t *allocations_info)
71{
72	size_t min_idx, max_idx;
73	uintptr_t min_val = UINTPTR_MAX, max_val = 0;
74
75	const uintptr_t *allocs = iterate_arg->allocs;
76
77	for (size_t i = 0; i < ALLOCATIONS_NUMBER; ++i) {
78		if (allocs[i] > max_val) {
79			max_val = allocs[i];
80			max_idx = i;
81		}
82		if (allocs[i] < min_val) {
83			min_val = allocs[i];
84			min_idx = i;
85		}
86	}
87
88	allocations_info->base = (void *) allocs[min_idx];
89	allocations_info->size = allocs[max_idx] - allocs[min_idx] + allocs_sizes[max_idx];
90}
91
92void make_allocations(iterate_arg_t *iterate_arg)
93{
94	uintptr_t *allocs = iterate_arg->allocs;
95	size_t *allocs_actual_sizes = iterate_arg->allocs_actual_sizes;
96
97	for (size_t i = 0; i < ALLOCATIONS_NUMBER; ++i) {
98		allocs[i] = (uintptr_t) malloc(allocs_sizes[i]);
99		allocs_actual_sizes[i] = malloc_usable_size((void *) allocs[i]);
100	}
101}
102
103void free_allocations(iterate_arg_t *iterate_arg)
104{
105	uintptr_t *allocs = iterate_arg->allocs;
106
107	for (size_t i = 0; i < ALLOCATIONS_NUMBER; ++i) {
108		free((void *) allocs[i]);
109	}
110}
111
112int iterate_wrapper(iterate_arg_t *iterate_arg)
113{
114	int ret = 0;
115	allocations_info_t allocations_info;
116	fill_allocations_info(iterate_arg, &allocations_info);
117	malloc_iterate(allocations_info.base, allocations_info.size, iterate_callback, iterate_arg);
118
119	for (size_t i = 0; i < ALLOCATIONS_NUMBER; ++i) {
120		if (iterate_arg->allocs_reported_number[i] != 1) {
121			ret = -1;
122		}
123	}
124	return ret;
125}
126
127pthread_barrier_t routine_allocated;
128pthread_barrier_t routine_iterated;
129
130void *allocate_routine(void *vargp)
131{
132	iterate_arg_t *iterate_arg = (iterate_arg_t *) vargp;
133	make_allocations(iterate_arg);
134	pthread_barrier_wait(&routine_allocated);
135	pthread_barrier_wait(&routine_iterated);
136	return NULL;
137}
138
139void *abandoned_allocate_routine(void *vargp)
140{
141	iterate_arg_t *iterate_arg = (iterate_arg_t *) vargp;
142	make_allocations(iterate_arg);
143	return NULL;
144}
145
146int test_iterate_main_thread(void)
147{
148	int ret;
149	iterate_arg_t iterate_arg = {{0}, {0}, {0}, {0}};
150	make_allocations(&iterate_arg);
151	ret = iterate_wrapper(&iterate_arg);
152	free_allocations(&iterate_arg);
153	return ret;
154}
155
156int test_iterate_another_thread(void)
157{
158	int ret;
159	iterate_arg_t iterate_arg_routine = {{0}, {0}, {0}, {0}};
160	pthread_barrier_init(&routine_allocated, NULL, BARRIER_HEIGHT);
161	pthread_barrier_init(&routine_iterated, NULL, BARRIER_HEIGHT);
162	pthread_t thread_id;
163	pthread_create(&thread_id, NULL, allocate_routine, (void *) &iterate_arg_routine);
164	pthread_barrier_wait(&routine_allocated);
165	ret = iterate_wrapper(&iterate_arg_routine);
166	free_allocations(&iterate_arg_routine);
167	pthread_barrier_wait(&routine_iterated);
168	return ret;
169}
170
171int test_iterate_over_abandoned_allocs(void)
172{
173	int ret;
174	iterate_arg_t iterate_arg_routine = {{0}, {0}, {0}, {0}};
175	pthread_t thread_id;
176	pthread_create(&thread_id, NULL, abandoned_allocate_routine, (void *) &iterate_arg_routine);
177	pthread_join(thread_id, NULL);
178	ret = iterate_wrapper(&iterate_arg_routine);
179	free_allocations(&iterate_arg_routine);
180	return ret;
181}
182
183int main()
184{
185	int ret = 0;
186
187	ret = check_and_report("Testing iterate main thread", test_iterate_main_thread);
188
189	ret = -(ret || check_and_report("Testing iterate another thread", test_iterate_another_thread));
190
191	ret = -(ret || check_and_report("Testing iterate over abandoned allocations", test_iterate_over_abandoned_allocs));
192
193	return ret;
194}
195