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