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:
commit
095217516e
@ -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
|
||||
##
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user