buflib: Add malloc-backed buflib
This is intended for improving the effectiveness of tools like ASAN when debugging memory errors in the sim. It's not meant to be a serious allocator for hosted targets. Enable it by changing the buflib backend in config.h. Change-Id: I0cf23cefa47ee35dede7b49e0e5b72dac60e8d3e
This commit is contained in:
parent
f2f198663e
commit
92565e9246
5 changed files with 309 additions and 0 deletions
|
@ -6,6 +6,8 @@ events.c
|
||||||
backlight.c
|
backlight.c
|
||||||
#if CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MEMPOOL
|
#if CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MEMPOOL
|
||||||
buflib_mempool.c
|
buflib_mempool.c
|
||||||
|
#elif CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MALLOC
|
||||||
|
buflib_malloc.c
|
||||||
#endif
|
#endif
|
||||||
core_alloc.c
|
core_alloc.c
|
||||||
general.c
|
general.c
|
||||||
|
|
251
firmware/buflib_malloc.c
Normal file
251
firmware/buflib_malloc.c
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Aidan MacDonald
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Malloc backed buflib. This is intended for debugging rather than for
|
||||||
|
* serious use - the buffer passed to the context is wasted, and memory
|
||||||
|
* is acquired from malloc() instead. The main point is to make ASAN more
|
||||||
|
* effective by isolating buflib allocations from each other.
|
||||||
|
*
|
||||||
|
* Currently this is a bare-minimum implementation, it doesn't even run
|
||||||
|
* buflib callbacks since it never moves anything. It could later be
|
||||||
|
* extended with stress-testing options, for example by randomly moving
|
||||||
|
* allocations around.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "buflib.h"
|
||||||
|
#include "panic.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static struct buflib_malloc_handle *get_free_handle(struct buflib_context *ctx)
|
||||||
|
{
|
||||||
|
struct buflib_malloc_handle *h;
|
||||||
|
for (size_t i = 0; i < ctx->num_allocs; ++i)
|
||||||
|
{
|
||||||
|
h = &ctx->allocs[i];
|
||||||
|
if (h->size == 0)
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->num_allocs++;
|
||||||
|
ctx->allocs = realloc(ctx->allocs, ctx->num_allocs * sizeof(*ctx->allocs));
|
||||||
|
if (!ctx->allocs)
|
||||||
|
panicf("buflib %p handle OOM", ctx);
|
||||||
|
|
||||||
|
h = &ctx->allocs[ctx->num_allocs - 1];
|
||||||
|
h->size = 0;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_handle_num(struct buflib_context *ctx,
|
||||||
|
struct buflib_malloc_handle *handle)
|
||||||
|
{
|
||||||
|
return (handle - ctx->allocs) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct buflib_malloc_handle *get_handle(struct buflib_context *ctx,
|
||||||
|
int handle)
|
||||||
|
{
|
||||||
|
return &ctx->allocs[handle - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
struct buflib_callbacks buflib_ops_locked = {
|
||||||
|
.move_callback = NULL,
|
||||||
|
.shrink_callback = NULL,
|
||||||
|
.sync_callback = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
void buflib_init(struct buflib_context *ctx, void *buf, size_t size)
|
||||||
|
{
|
||||||
|
ctx->allocs = NULL;
|
||||||
|
ctx->num_allocs = 0;
|
||||||
|
ctx->buf = buf;
|
||||||
|
ctx->bufsize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t buflib_available(struct buflib_context *ctx)
|
||||||
|
{
|
||||||
|
return ctx->bufsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t buflib_allocatable(struct buflib_context *ctx)
|
||||||
|
{
|
||||||
|
return ctx->bufsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool buflib_context_relocate(struct buflib_context *ctx, void *buf)
|
||||||
|
{
|
||||||
|
ctx->buf = buf;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int buflib_alloc(struct buflib_context *ctx, size_t size)
|
||||||
|
{
|
||||||
|
return buflib_alloc_ex(ctx, size, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int buflib_alloc_ex(struct buflib_context *ctx, size_t size,
|
||||||
|
struct buflib_callbacks *ops)
|
||||||
|
{
|
||||||
|
struct buflib_malloc_handle *handle = get_free_handle(ctx);
|
||||||
|
|
||||||
|
handle->data = malloc(size);
|
||||||
|
handle->user = handle->data;
|
||||||
|
handle->size = size;
|
||||||
|
handle->pin_count = 0;
|
||||||
|
handle->ops = ops;
|
||||||
|
|
||||||
|
if (!handle->data)
|
||||||
|
panicf("buflib %p data OOM", ctx);
|
||||||
|
|
||||||
|
return get_handle_num(ctx, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
int buflib_alloc_maximum(struct buflib_context* ctx,
|
||||||
|
size_t *size, struct buflib_callbacks *ops)
|
||||||
|
{
|
||||||
|
*size = ctx->bufsize;
|
||||||
|
|
||||||
|
return buflib_alloc_ex(ctx, *size, ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool buflib_shrink(struct buflib_context *ctx, int handle,
|
||||||
|
void *newstart, size_t new_size)
|
||||||
|
{
|
||||||
|
struct buflib_malloc_handle *h = get_handle(ctx, handle);
|
||||||
|
if (newstart < h->user || new_size > h->size - (newstart - h->user))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* XXX: this might be allowed, but what would be the point... */
|
||||||
|
if (new_size == 0)
|
||||||
|
{
|
||||||
|
panicf("weird shrink");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* due to buflib semantics we must not realloc */
|
||||||
|
h->user = newstart;
|
||||||
|
h->size = new_size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void buflib_pin(struct buflib_context *ctx, int handle)
|
||||||
|
{
|
||||||
|
struct buflib_malloc_handle *h = get_handle(ctx, handle);
|
||||||
|
|
||||||
|
h->pin_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void buflib_unpin(struct buflib_context *ctx, int handle)
|
||||||
|
{
|
||||||
|
struct buflib_malloc_handle *h = get_handle(ctx, handle);
|
||||||
|
|
||||||
|
h->pin_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned buflib_pin_count(struct buflib_context *ctx, int handle)
|
||||||
|
{
|
||||||
|
struct buflib_malloc_handle *h = get_handle(ctx, handle);
|
||||||
|
|
||||||
|
return h->pin_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int buflib_free(struct buflib_context *ctx, int handle)
|
||||||
|
{
|
||||||
|
if (handle <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
struct buflib_malloc_handle *h = get_handle(ctx, handle);
|
||||||
|
|
||||||
|
free(h->data);
|
||||||
|
h->size = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BUFLIB_DEBUG_GET_DATA
|
||||||
|
void *buflib_get_data(struct buflib_context *ctx, int handle)
|
||||||
|
{
|
||||||
|
/* kind of silly since it's better for ASAN to catch this but... */
|
||||||
|
if (handle <= 0 || handle > ctx->num_allocs)
|
||||||
|
panicf("buflib %p: invalid handle %d", ctx, handle);
|
||||||
|
|
||||||
|
struct buflib_malloc_handle *h = get_handle(ctx, handle);
|
||||||
|
if (h->user == NULL)
|
||||||
|
panicf("buflib %p: handle %d use after free", ctx, handle);
|
||||||
|
|
||||||
|
return h->user;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void *buflib_buffer_out(struct buflib_context *ctx, size_t *size)
|
||||||
|
{
|
||||||
|
if (*size == 0)
|
||||||
|
*size = ctx->bufsize;
|
||||||
|
|
||||||
|
void *ret = ctx->buf;
|
||||||
|
|
||||||
|
ctx->buf += *size;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void buflib_buffer_in(struct buflib_context *ctx, int size)
|
||||||
|
{
|
||||||
|
ctx->buf -= size;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BUFLIB_DEBUG_PRINT
|
||||||
|
int buflib_get_num_blocks(struct buflib_context *ctx)
|
||||||
|
{
|
||||||
|
return ctx->num_allocs;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool buflib_print_block_at(struct buflib_context *ctx, int block_num,
|
||||||
|
char *buf, size_t bufsize)
|
||||||
|
{
|
||||||
|
if (block_num >= ctx->num_allocs)
|
||||||
|
{
|
||||||
|
if (bufsize > 0)
|
||||||
|
*buf = '\0';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct buflib_malloc_handle *handle = &ctx->allocs[block_num];
|
||||||
|
if (handle->data)
|
||||||
|
{
|
||||||
|
snprintf(buf, bufsize, "%03d addr:%8p length:%zu",
|
||||||
|
block_num, handle->data, handle->size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
snprintf(buf, bufsize, "%03d (unallocated)", block_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BUFLIB_DEBUG_CHECK_VALID
|
||||||
|
void buflib_check_valid(struct buflib_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -382,6 +382,7 @@ Lyre prototype 1 */
|
||||||
|
|
||||||
/* CONFIG_BUFLIB_BACKEND */
|
/* CONFIG_BUFLIB_BACKEND */
|
||||||
#define BUFLIB_BACKEND_MEMPOOL 0 /* Default memory pool backed buflib */
|
#define BUFLIB_BACKEND_MEMPOOL 0 /* Default memory pool backed buflib */
|
||||||
|
#define BUFLIB_BACKEND_MALLOC 1 /* malloc() buflib (for debugging) */
|
||||||
|
|
||||||
/* now go and pick yours */
|
/* now go and pick yours */
|
||||||
#if defined(IRIVER_H100)
|
#if defined(IRIVER_H100)
|
||||||
|
|
|
@ -380,6 +380,8 @@ void buflib_check_valid(struct buflib_context *ctx);
|
||||||
|
|
||||||
#if CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MEMPOOL
|
#if CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MEMPOOL
|
||||||
#include "buflib_mempool.h"
|
#include "buflib_mempool.h"
|
||||||
|
#elif CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MALLOC
|
||||||
|
#include "buflib_malloc.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef BUFLIB_ALLOC_OVERHEAD
|
#ifndef BUFLIB_ALLOC_OVERHEAD
|
||||||
|
|
53
firmware/include/buflib_malloc.h
Normal file
53
firmware/include/buflib_malloc.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Aidan MacDonald
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef _BUFLIB_MALLOC_H_
|
||||||
|
#define _BUFLIB_MALLOC_H_
|
||||||
|
|
||||||
|
#ifndef _BUFLIB_H_
|
||||||
|
# error "include buflib.h instead"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct buflib_malloc_handle
|
||||||
|
{
|
||||||
|
void *data;
|
||||||
|
void *user;
|
||||||
|
size_t size;
|
||||||
|
unsigned int pin_count;
|
||||||
|
struct buflib_callbacks *ops;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct buflib_context
|
||||||
|
{
|
||||||
|
struct buflib_malloc_handle *allocs;
|
||||||
|
size_t num_allocs;
|
||||||
|
|
||||||
|
void *buf;
|
||||||
|
size_t bufsize;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef BUFLIB_DEBUG_GET_DATA
|
||||||
|
static inline void *buflib_get_data(struct buflib_context *ctx, int handle)
|
||||||
|
{
|
||||||
|
return ctx->allocs[handle - 1].user;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _BUFLIB_MALLOC_H_ */
|
Loading…
Reference in a new issue