summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2023-01-02 22:48:07 +0000
committerAidan MacDonald <amachronic@protonmail.com>2023-01-15 10:04:13 +0000
commit92565e9246f3a47b90fea4a436ecfd8e7a1198b8 (patch)
tree5e2fa26fff921296729b74bd8947dd225e69c84f
parentf2f198663edc01a1f19e35b8a0c302f8ee47ae5e (diff)
downloadrockbox-92565e9246f3a47b90fea4a436ecfd8e7a1198b8.tar.gz
rockbox-92565e9246f3a47b90fea4a436ecfd8e7a1198b8.zip
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
-rw-r--r--firmware/SOURCES2
-rw-r--r--firmware/buflib_malloc.c251
-rw-r--r--firmware/export/config.h1
-rw-r--r--firmware/include/buflib.h2
-rw-r--r--firmware/include/buflib_malloc.h53
5 files changed, 309 insertions, 0 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 02e962c0c3..7e2ffb323e 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -6,6 +6,8 @@ events.c
6backlight.c 6backlight.c
7#if CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MEMPOOL 7#if CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MEMPOOL
8buflib_mempool.c 8buflib_mempool.c
9#elif CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MALLOC
10buflib_malloc.c
9#endif 11#endif
10core_alloc.c 12core_alloc.c
11general.c 13general.c
diff --git a/firmware/buflib_malloc.c b/firmware/buflib_malloc.c
new file mode 100644
index 0000000000..fdc2b5b925
--- /dev/null
+++ b/firmware/buflib_malloc.c
@@ -0,0 +1,251 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2023 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22/*
23 * Malloc backed buflib. This is intended for debugging rather than for
24 * serious use - the buffer passed to the context is wasted, and memory
25 * is acquired from malloc() instead. The main point is to make ASAN more
26 * effective by isolating buflib allocations from each other.
27 *
28 * Currently this is a bare-minimum implementation, it doesn't even run
29 * buflib callbacks since it never moves anything. It could later be
30 * extended with stress-testing options, for example by randomly moving
31 * allocations around.
32 */
33
34#include "buflib.h"
35#include "panic.h"
36#include <stdlib.h>
37
38static struct buflib_malloc_handle *get_free_handle(struct buflib_context *ctx)
39{
40 struct buflib_malloc_handle *h;
41 for (size_t i = 0; i < ctx->num_allocs; ++i)
42 {
43 h = &ctx->allocs[i];
44 if (h->size == 0)
45 return h;
46 }
47
48 ctx->num_allocs++;
49 ctx->allocs = realloc(ctx->allocs, ctx->num_allocs * sizeof(*ctx->allocs));
50 if (!ctx->allocs)
51 panicf("buflib %p handle OOM", ctx);
52
53 h = &ctx->allocs[ctx->num_allocs - 1];
54 h->size = 0;
55 return h;
56}
57
58static int get_handle_num(struct buflib_context *ctx,
59 struct buflib_malloc_handle *handle)
60{
61 return (handle - ctx->allocs) + 1;
62}
63
64static struct buflib_malloc_handle *get_handle(struct buflib_context *ctx,
65 int handle)
66{
67 return &ctx->allocs[handle - 1];
68}
69
70struct buflib_callbacks buflib_ops_locked = {
71 .move_callback = NULL,
72 .shrink_callback = NULL,
73 .sync_callback = NULL,
74};
75
76void buflib_init(struct buflib_context *ctx, void *buf, size_t size)
77{
78 ctx->allocs = NULL;
79 ctx->num_allocs = 0;
80 ctx->buf = buf;
81 ctx->bufsize = size;
82}
83
84size_t buflib_available(struct buflib_context *ctx)
85{
86 return ctx->bufsize;
87}
88
89size_t buflib_allocatable(struct buflib_context *ctx)
90{
91 return ctx->bufsize;
92}
93
94bool buflib_context_relocate(struct buflib_context *ctx, void *buf)
95{
96 ctx->buf = buf;
97 return true;
98}
99
100int buflib_alloc(struct buflib_context *ctx, size_t size)
101{
102 return buflib_alloc_ex(ctx, size, NULL);
103}
104
105int buflib_alloc_ex(struct buflib_context *ctx, size_t size,
106 struct buflib_callbacks *ops)
107{
108 struct buflib_malloc_handle *handle = get_free_handle(ctx);
109
110 handle->data = malloc(size);
111 handle->user = handle->data;
112 handle->size = size;
113 handle->pin_count = 0;
114 handle->ops = ops;
115
116 if (!handle->data)
117 panicf("buflib %p data OOM", ctx);
118
119 return get_handle_num(ctx, handle);
120}
121
122int buflib_alloc_maximum(struct buflib_context* ctx,
123 size_t *size, struct buflib_callbacks *ops)
124{
125 *size = ctx->bufsize;
126
127 return buflib_alloc_ex(ctx, *size, ops);
128}
129
130bool buflib_shrink(struct buflib_context *ctx, int handle,
131 void *newstart, size_t new_size)
132{
133 struct buflib_malloc_handle *h = get_handle(ctx, handle);
134 if (newstart < h->user || new_size > h->size - (newstart - h->user))
135 return false;
136
137 /* XXX: this might be allowed, but what would be the point... */
138 if (new_size == 0)
139 {
140 panicf("weird shrink");
141 return false;
142 }
143
144 /* due to buflib semantics we must not realloc */
145 h->user = newstart;
146 h->size = new_size;
147 return true;
148}
149
150void buflib_pin(struct buflib_context *ctx, int handle)
151{
152 struct buflib_malloc_handle *h = get_handle(ctx, handle);
153
154 h->pin_count++;
155}
156
157void buflib_unpin(struct buflib_context *ctx, int handle)
158{
159 struct buflib_malloc_handle *h = get_handle(ctx, handle);
160
161 h->pin_count--;
162}
163
164unsigned buflib_pin_count(struct buflib_context *ctx, int handle)
165{
166 struct buflib_malloc_handle *h = get_handle(ctx, handle);
167
168 return h->pin_count;
169}
170
171int buflib_free(struct buflib_context *ctx, int handle)
172{
173 if (handle <= 0)
174 return 0;
175
176 struct buflib_malloc_handle *h = get_handle(ctx, handle);
177
178 free(h->data);
179 h->size = 0;
180
181 return 0;
182}
183
184#ifdef BUFLIB_DEBUG_GET_DATA
185void *buflib_get_data(struct buflib_context *ctx, int handle)
186{
187 /* kind of silly since it's better for ASAN to catch this but... */
188 if (handle <= 0 || handle > ctx->num_allocs)
189 panicf("buflib %p: invalid handle %d", ctx, handle);
190
191 struct buflib_malloc_handle *h = get_handle(ctx, handle);
192 if (h->user == NULL)
193 panicf("buflib %p: handle %d use after free", ctx, handle);
194
195 return h->user;
196}
197#endif
198
199void *buflib_buffer_out(struct buflib_context *ctx, size_t *size)
200{
201 if (*size == 0)
202 *size = ctx->bufsize;
203
204 void *ret = ctx->buf;
205
206 ctx->buf += *size;
207 return ret;
208}
209
210void buflib_buffer_in(struct buflib_context *ctx, int size)
211{
212 ctx->buf -= size;
213}
214
215#ifdef BUFLIB_DEBUG_PRINT
216int buflib_get_num_blocks(struct buflib_context *ctx)
217{
218 return ctx->num_allocs;
219}
220
221bool buflib_print_block_at(struct buflib_context *ctx, int block_num,
222 char *buf, size_t bufsize)
223{
224 if (block_num >= ctx->num_allocs)
225 {
226 if (bufsize > 0)
227 *buf = '\0';
228 return false;
229 }
230
231 struct buflib_malloc_handle *handle = &ctx->allocs[block_num];
232 if (handle->data)
233 {
234 snprintf(buf, bufsize, "%03d addr:%8p length:%zu",
235 block_num, handle->data, handle->size);
236 }
237 else
238 {
239 snprintf(buf, bufsize, "%03d (unallocated)", block_num);
240 }
241
242 return true;
243}
244#endif
245
246#ifdef BUFLIB_DEBUG_CHECK_VALID
247void buflib_check_valid(struct buflib_context *ctx)
248{
249 (void)ctx;
250}
251#endif
diff --git a/firmware/export/config.h b/firmware/export/config.h
index d8674c40f2..2ec0b7878f 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -382,6 +382,7 @@ Lyre prototype 1 */
382 382
383/* CONFIG_BUFLIB_BACKEND */ 383/* CONFIG_BUFLIB_BACKEND */
384#define BUFLIB_BACKEND_MEMPOOL 0 /* Default memory pool backed buflib */ 384#define BUFLIB_BACKEND_MEMPOOL 0 /* Default memory pool backed buflib */
385#define BUFLIB_BACKEND_MALLOC 1 /* malloc() buflib (for debugging) */
385 386
386/* now go and pick yours */ 387/* now go and pick yours */
387#if defined(IRIVER_H100) 388#if defined(IRIVER_H100)
diff --git a/firmware/include/buflib.h b/firmware/include/buflib.h
index 32a5a6abe0..c4865b6d9b 100644
--- a/firmware/include/buflib.h
+++ b/firmware/include/buflib.h
@@ -380,6 +380,8 @@ void buflib_check_valid(struct buflib_context *ctx);
380 380
381#if CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MEMPOOL 381#if CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MEMPOOL
382#include "buflib_mempool.h" 382#include "buflib_mempool.h"
383#elif CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MALLOC
384#include "buflib_malloc.h"
383#endif 385#endif
384 386
385#ifndef BUFLIB_ALLOC_OVERHEAD 387#ifndef BUFLIB_ALLOC_OVERHEAD
diff --git a/firmware/include/buflib_malloc.h b/firmware/include/buflib_malloc.h
new file mode 100644
index 0000000000..32c837e7b7
--- /dev/null
+++ b/firmware/include/buflib_malloc.h
@@ -0,0 +1,53 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2023 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#ifndef _BUFLIB_MALLOC_H_
22#define _BUFLIB_MALLOC_H_
23
24#ifndef _BUFLIB_H_
25# error "include buflib.h instead"
26#endif
27
28struct buflib_malloc_handle
29{
30 void *data;
31 void *user;
32 size_t size;
33 unsigned int pin_count;
34 struct buflib_callbacks *ops;
35};
36
37struct buflib_context
38{
39 struct buflib_malloc_handle *allocs;
40 size_t num_allocs;
41
42 void *buf;
43 size_t bufsize;
44};
45
46#ifndef BUFLIB_DEBUG_GET_DATA
47static inline void *buflib_get_data(struct buflib_context *ctx, int handle)
48{
49 return ctx->allocs[handle - 1].user;
50}
51#endif
52
53#endif /* _BUFLIB_MALLOC_H_ */