1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-24 14:03:55 +01:00

Merge pull request #18912 from maribu/sys/malloc_tracing

sys/malloc_tracing: add module to trace dyn memory management
This commit is contained in:
Marian Buschsieweke 2022-11-17 13:36:47 +01:00 committed by GitHub
commit 095217516e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 65 additions and 2 deletions

View File

@ -277,6 +277,11 @@ PSEUDOMODULES += lora
##
PSEUDOMODULES += libc_gettimeofday
## @defgroup pseudomodule_malloc_tracing malloc_tracing
## @brief Debug dynamic memory management by hooking in a print into each call
## of malloc(), calloc(), realloc() and free
PSEUDOMODULES += malloc_tracing
## @defgroup pseudomodule_mpu_stack_guard mpu_stack_guard
## @brief MPU based stack guard
##

View File

@ -1,4 +1,4 @@
# Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg
# Copyright (C) 2020, 2022 Otto-von-Guericke-Universität Magdeburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
@ -16,3 +16,18 @@ config MODULE_MALLOC_THREAD_SAFE
safe without touching the application code or the c library. This module
is intended to be pulled in automatically if needed. Hence, applications
never should manually use it.
config MODULE_MALLOC_TRACING
bool
depends on TEST_KCONFIG
depends on MODULE_MALLOC_THREAD_SAFE
help
This module enables hooks in the wrappers for malloc(), calloc(),
realloc(), and free() provided by MODULE_MALLOC_THREAD_SAFE that print
the arguments, caller program counter and return value of those
functions. The intent is to aid debugging invalid calls to free(),
duplicated calls to free(), or memory leaks.
Note that generally dynamic memory management is a bad idea on the
constrained devices RIOT is targeting. So maybe it is better to just
adapt your code to use static memory management instead.

View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2019 Gunar Schorcht
* 2022 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -12,12 +13,17 @@
* @file
* @brief Implements various POSIX syscalls
* @author Gunar Schorcht <gunar@schorcht.net>
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*/
#include <stdio.h>
#include <string.h>
#include "architecture.h"
#include "assert.h"
#include "cpu.h"
#include "irq.h"
#include "kernel_defines.h"
#include "mutex.h"
extern void *__real_malloc(size_t size);
@ -28,15 +34,27 @@ static mutex_t _lock;
void __attribute__((used)) *__wrap_malloc(size_t size)
{
uinttxtptr_t pc;
if (IS_USED(MODULE_MALLOC_TRACING)) {
pc = cpu_get_caller_pc();
}
assert(!irq_is_in());
mutex_lock(&_lock);
void *ptr = __real_malloc(size);
mutex_unlock(&_lock);
if (IS_USED(MODULE_MALLOC_TRACING)) {
printf("malloc(%u) @ 0x%" PRIxTXTPTR " returned %p\n",
(unsigned)size, pc, ptr);
}
return ptr;
}
void __attribute__((used)) __wrap_free(void *ptr)
{
if (IS_USED(MODULE_MALLOC_TRACING)) {
uinttxtptr_t pc = cpu_get_caller_pc();
printf("free(%p) @0x%" PRIxTXTPTR ")\n", ptr, pc);
}
assert(!irq_is_in());
mutex_lock(&_lock);
__real_free(ptr);
@ -45,28 +63,53 @@ void __attribute__((used)) __wrap_free(void *ptr)
void * __attribute__((used)) __wrap_calloc(size_t nmemb, size_t size)
{
uinttxtptr_t pc;
if (IS_USED(MODULE_MALLOC_TRACING)) {
pc = cpu_get_caller_pc();
}
/* some c libs don't perform proper overflow check (e.g. newlib < 4.0.0). Hence, we
* just implement calloc on top of malloc ourselves. In addition to ensuring proper
* overflow checks, this likely saves a bit of ROM */
size_t total_size;
if (__builtin_mul_overflow(nmemb, size, &total_size)) {
if (IS_USED(MODULE_MALLOC_TRACING)) {
printf("calloc(%u, %u) @0x%" PRIxTXTPTR " overflowed\n",
(unsigned)nmemb, (unsigned)size, pc);
}
return NULL;
}
void *res = __wrap_malloc(total_size);
mutex_lock(&_lock);
void *res = __real_malloc(total_size);
mutex_unlock(&_lock);
if (res) {
memset(res, 0, total_size);
}
if (IS_USED(MODULE_MALLOC_TRACING)) {
printf("calloc(%u, %u) @0x%" PRIxTXTPTR " returned %p\n",
(unsigned)nmemb, (unsigned)size, pc, res);
}
return res;
}
void * __attribute__((used))__wrap_realloc(void *ptr, size_t size)
{
uinttxtptr_t pc;
if (IS_USED(MODULE_MALLOC_TRACING)) {
pc = cpu_get_caller_pc();
}
assert(!irq_is_in());
mutex_lock(&_lock);
void *new = __real_realloc(ptr, size);
mutex_unlock(&_lock);
if (IS_USED(MODULE_MALLOC_TRACING)) {
printf("realloc(%p, %u) @0x%" PRIxTXTPTR " returned %p\n",
ptr, (unsigned)size, pc, new);
}
return new;
}