Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-os by
main.cpp
00001 /* 00002 * Copyright (c) 2013-2016, ARM Limited, All Rights Reserved 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00006 * not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #include "mbed.h" 00019 #include "greentea-client/test_env.h" 00020 #include "unity/unity.h" 00021 #include "utest/utest.h" 00022 #include "mbed_mem_trace.h" 00023 #include <stdlib.h> 00024 #include <stdio.h> 00025 #include <stdarg.h> 00026 00027 #ifndef MBED_MEM_TRACING_ENABLED 00028 #error [NOT_SUPPORTED] test not supported 00029 #endif 00030 00031 using namespace utest::v1; 00032 00033 /******************************************************************************/ 00034 /* Helper functions and data structures */ 00035 /******************************************************************************/ 00036 00037 // This structure keeps data about the various memory allocation operations, 00038 // as traced by 'test_trace_cb' below. 00039 #define TEST_MAX_MEMORY_OPS 10 00040 // Trace results for all possible operations 00041 typedef struct { 00042 uint8_t op; 00043 void *res; 00044 union { 00045 struct { 00046 size_t arg_size; 00047 } malloc_info; 00048 struct { 00049 void *arg_ptr; 00050 size_t arg_size; 00051 } realloc_info; 00052 struct { 00053 size_t arg_nmemb; 00054 size_t arg_size; 00055 } calloc_info; 00056 struct { 00057 void *arg_ptr; 00058 } free_info; 00059 }; 00060 } mem_trace_data_t; 00061 // Memory operation statistics 00062 typedef struct { 00063 mem_trace_data_t op_data[TEST_MAX_MEMORY_OPS]; 00064 uint32_t total_ops; 00065 bool invalid_op, overflow; 00066 } stats_t; 00067 static stats_t stats; 00068 00069 // Clear all the memory statistics 00070 static void test_clear_stats() { 00071 memset(&stats, 0, sizeof(stats)); 00072 } 00073 00074 // Memory tracer callback that records each operation in "stats" (above) 00075 extern "C" void test_trace_cb(uint8_t op, void *res, void *caller, ...) { 00076 va_list va; 00077 mem_trace_data_t *pmem = stats.op_data + stats.total_ops; 00078 00079 if (stats.total_ops >= TEST_MAX_MEMORY_OPS) { 00080 stats.overflow = true; 00081 return; 00082 } 00083 va_start(va, caller); 00084 pmem->op = op; 00085 pmem->res = res; 00086 switch(op) { 00087 case MBED_MEM_TRACE_MALLOC: 00088 pmem->malloc_info.arg_size = va_arg(va, size_t); 00089 break; 00090 00091 case MBED_MEM_TRACE_REALLOC: 00092 pmem->realloc_info.arg_ptr = va_arg(va, void *); 00093 pmem->realloc_info.arg_size = va_arg(va, size_t); 00094 break; 00095 00096 case MBED_MEM_TRACE_CALLOC: 00097 pmem->calloc_info.arg_nmemb = va_arg(va, size_t); 00098 pmem->calloc_info.arg_size = va_arg(va, size_t); 00099 break; 00100 00101 case MBED_MEM_TRACE_FREE: 00102 pmem->free_info.arg_ptr = va_arg(va, void *); 00103 break; 00104 00105 default: 00106 stats.invalid_op = true; 00107 } 00108 stats.total_ops ++; 00109 va_end(va); 00110 } 00111 00112 // Generic sanity checks for the tracer 00113 static void check_sanity(uint32_t expected_ops) { 00114 TEST_ASSERT_FALSE(stats.overflow); 00115 TEST_ASSERT_FALSE(stats.invalid_op); 00116 TEST_ASSERT_EQUAL_UINT32(stats.total_ops, expected_ops); 00117 } 00118 00119 // Check a "malloc" operation 00120 static void check_malloc_op(const mem_trace_data_t *p, void *expected_res, size_t expected_arg_size) { 00121 TEST_ASSERT_EQUAL_UINT8(p->op, MBED_MEM_TRACE_MALLOC); 00122 TEST_ASSERT_EQUAL_PTR(p->res, expected_res); 00123 TEST_ASSERT_EQUAL_UINT32(p->malloc_info.arg_size, expected_arg_size); 00124 } 00125 00126 // Check a "free" operation 00127 static void check_free_op(const mem_trace_data_t *p, void *expected_arg_ptr) { 00128 TEST_ASSERT_EQUAL_UINT8(p->op, MBED_MEM_TRACE_FREE); 00129 TEST_ASSERT_EQUAL_PTR(p->free_info.arg_ptr, expected_arg_ptr); 00130 } 00131 00132 // Check a "realloc" operation 00133 static void check_realloc_op(const mem_trace_data_t *p, void *expected_res, void *expected_arg_ptr, size_t expected_arg_size) { 00134 TEST_ASSERT_EQUAL_UINT8(p->op, MBED_MEM_TRACE_REALLOC); 00135 TEST_ASSERT_EQUAL_PTR(p->res, expected_res); 00136 TEST_ASSERT_EQUAL_UINT32(p->realloc_info.arg_ptr, expected_arg_ptr); 00137 TEST_ASSERT_EQUAL_UINT32(p->realloc_info.arg_size, expected_arg_size); 00138 } 00139 00140 // Check a "calloc" operation 00141 static void check_calloc_op(const mem_trace_data_t *p, void *expected_res, size_t expected_arg_nmemb, size_t expected_arg_size) { 00142 TEST_ASSERT_EQUAL_UINT8(p->op, MBED_MEM_TRACE_CALLOC); 00143 TEST_ASSERT_EQUAL_PTR(p->res, expected_res); 00144 TEST_ASSERT_EQUAL_UINT32(p->calloc_info.arg_nmemb, expected_arg_nmemb); 00145 TEST_ASSERT_EQUAL_UINT32(p->calloc_info.arg_size, expected_arg_size); 00146 } 00147 00148 /******************************************************************************/ 00149 /* Tests */ 00150 /******************************************************************************/ 00151 00152 // Allocate a single buffer, then free it. Check that tracing matches the operations. 00153 static void test_case_single_malloc_free() { 00154 const size_t block_size = 126; 00155 const mem_trace_data_t *pmem = stats.op_data; 00156 00157 test_clear_stats(); 00158 mbed_mem_trace_set_callback(test_trace_cb); 00159 // Allocate a single memory block 00160 void *p = malloc(block_size); 00161 TEST_ASSERT_NOT_EQUAL(p, NULL); 00162 // Free the memory block 00163 free(p); 00164 // Stop tracing 00165 mbed_mem_trace_set_callback(NULL); 00166 // Check tracer result 00167 check_sanity(2); 00168 check_malloc_op(pmem ++, p, block_size); 00169 check_free_op(pmem, p); 00170 } 00171 00172 // Test all memory operations (malloc, realloc, free, calloc) 00173 static void test_case_all_memory_ops() { 00174 const size_t malloc_size = 40, realloc_size = 80, nmemb = 25, size = 10; 00175 const mem_trace_data_t *pmem = stats.op_data; 00176 00177 test_clear_stats(); 00178 mbed_mem_trace_set_callback(test_trace_cb); 00179 // Allocate a single memory block, the realloc it 00180 void *p_malloc = malloc(malloc_size); 00181 TEST_ASSERT_NOT_EQUAL(p_malloc, NULL); 00182 void *p_realloc = realloc(p_malloc, realloc_size); 00183 TEST_ASSERT_NOT_EQUAL(p_realloc, NULL); 00184 // Use calloc() now 00185 void *p_calloc = calloc(nmemb, size); 00186 //TEST_ASSERT_NOT_EQUAL(p_calloc, NULL); 00187 // Free the realloc() pointer first, then the calloc() one 00188 free(p_realloc); 00189 free(p_calloc); 00190 // Stop tracing 00191 mbed_mem_trace_set_callback(NULL); 00192 // Check tracer result 00193 check_sanity(6); 00194 check_malloc_op(pmem ++, p_malloc, malloc_size); 00195 check_realloc_op(pmem ++, p_realloc, p_malloc, realloc_size); 00196 // calloc() calls malloc() internally 00197 check_malloc_op(pmem ++, p_calloc, nmemb * size); 00198 check_calloc_op(pmem ++, p_calloc, nmemb, size); 00199 check_free_op(pmem ++, p_realloc); 00200 check_free_op(pmem, p_calloc); 00201 } 00202 00203 // Test that tracing is off when using a NULL callback 00204 static void test_case_trace_off() { 00205 const size_t malloc_size = 10; 00206 00207 test_clear_stats(); 00208 // We don't want any tracing 00209 mbed_mem_trace_set_callback(NULL); 00210 // Allocate a buffer and free it 00211 void *p_malloc = malloc(malloc_size); 00212 TEST_ASSERT_NOT_EQUAL(p_malloc, NULL); 00213 free(p_malloc); 00214 // Check that we didn't trace anything 00215 check_sanity(0); 00216 } 00217 00218 // Test partial tracing (start tracing, stop tracing, restart later) 00219 static void test_case_partial_trace() { 00220 const size_t malloc_size_1 = 20, malloc_size_2 = 30; 00221 const mem_trace_data_t *pmem = stats.op_data; 00222 00223 test_clear_stats(); 00224 // Start tracing 00225 mbed_mem_trace_set_callback(test_trace_cb); 00226 // Allocate a buffer 00227 void *p_malloc_1 = malloc(malloc_size_1); 00228 TEST_ASSERT_NOT_EQUAL(p_malloc_1, NULL); 00229 // Disable tracing before freeing the first buffer 00230 mbed_mem_trace_set_callback(NULL); 00231 free(p_malloc_1); 00232 // Allocate another buffer (still not traced) 00233 void *p_malloc_2 = malloc(malloc_size_2); 00234 TEST_ASSERT_NOT_EQUAL(p_malloc_2, NULL); 00235 // Re-enable tracing 00236 mbed_mem_trace_set_callback(test_trace_cb); 00237 // And free the second buffer (this operation should be tracer) 00238 free(p_malloc_2); 00239 // Stop tracing 00240 mbed_mem_trace_set_callback(NULL); 00241 // Check tracer result 00242 check_sanity(2); 00243 check_malloc_op(pmem ++, p_malloc_1, malloc_size_1); 00244 check_free_op(pmem, p_malloc_2); 00245 } 00246 00247 // Test new/delete tracing 00248 static void test_case_new_delete() { 00249 const mem_trace_data_t *pmem = stats.op_data; 00250 00251 test_clear_stats(); 00252 // Start tracing 00253 mbed_mem_trace_set_callback(test_trace_cb); 00254 // Test new, new[], delete and delete[] 00255 int *p_int = new int; 00256 int *p_int_array = new int[10]; 00257 delete p_int; 00258 delete[] p_int_array; 00259 // Stop tracing 00260 mbed_mem_trace_set_callback(NULL); 00261 // Check tracer result 00262 check_sanity(4); 00263 check_malloc_op(pmem ++, p_int, sizeof(int)); 00264 check_malloc_op(pmem ++, p_int_array, 10 * sizeof(int)); 00265 check_free_op(pmem ++, p_int); 00266 check_free_op(pmem ++, p_int_array); 00267 } 00268 00269 static Case cases[] = { 00270 Case("single malloc/free", test_case_single_malloc_free), 00271 Case("all memory operations", test_case_all_memory_ops), 00272 Case("trace off", test_case_trace_off), 00273 Case("partial trace", test_case_partial_trace), 00274 Case("test new/delete", test_case_new_delete) 00275 }; 00276 00277 static status_t greentea_test_setup(const size_t number_of_cases) { 00278 GREENTEA_SETUP(20, "default_auto"); 00279 return greentea_test_setup_handler(number_of_cases); 00280 } 00281 00282 static Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); 00283 00284 int main() { 00285 // Disable stdout buffering to prevent any unwanted allocations 00286 setvbuf(stdout, NULL, _IONBF, 0); 00287 Harness::run(specification); 00288 } 00289
Generated on Tue Jul 12 2022 13:15:57 by
