Skip to content

Commit 5327487

Browse files
authored
Merge pull request #8446 from tannewt/rgbmatrix_memory_fix
Improve RGBMatrix allocation tracking
2 parents 73292f6 + 4c21f22 commit 5327487

File tree

6 files changed

+69
-19
lines changed

6 files changed

+69
-19
lines changed

ports/espressif/boards/adafruit_matrixportal_s3/pins.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ STATIC const mp_rom_obj_tuple_t matrix_addr_tuple = {
55
{&mp_type_tuple},
66
5,
77
{
8-
MP_ROM_PTR(&pin_GPIO35),
8+
MP_ROM_PTR(&pin_GPIO45),
99
MP_ROM_PTR(&pin_GPIO36),
1010
MP_ROM_PTR(&pin_GPIO48),
11-
MP_ROM_PTR(&pin_GPIO45),
11+
MP_ROM_PTR(&pin_GPIO35),
1212
MP_ROM_PTR(&pin_GPIO21),
1313
}
1414
};

ports/espressif/common-hal/rgbmatrix/RGBMatrix.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ void common_hal_rgbmatrix_timer_enable(void *ptr) {
6161
}
6262

6363
void common_hal_rgbmatrix_timer_disable(void *ptr) {
64+
if (ptr == NULL) {
65+
return;
66+
}
6467
timer_index_t *timer = (timer_index_t *)ptr;
6568
if (timer->idx == TIMER_MAX) {
6669
return;

shared-bindings/rgbmatrix/RGBMatrix.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -376,9 +376,7 @@ STATIC const mp_rom_map_elem_t rgbmatrix_rgbmatrix_locals_dict_table[] = {
376376
STATIC MP_DEFINE_CONST_DICT(rgbmatrix_rgbmatrix_locals_dict, rgbmatrix_rgbmatrix_locals_dict_table);
377377

378378
STATIC void rgbmatrix_rgbmatrix_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t *bufinfo) {
379-
rgbmatrix_rgbmatrix_obj_t *self = (rgbmatrix_rgbmatrix_obj_t *)self_in;
380-
381-
*bufinfo = self->bufinfo;
379+
common_hal_rgbmatrix_rgbmatrix_get_bufinfo(self_in, bufinfo);
382380
}
383381

384382
// These version exists so that the prototype matches the protocol,
@@ -442,7 +440,7 @@ STATIC mp_int_t rgbmatrix_rgbmatrix_get_buffer(mp_obj_t self_in, mp_buffer_info_
442440
if ((flags & MP_BUFFER_WRITE) && !(self->bufinfo.typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {
443441
return 1;
444442
}
445-
*bufinfo = self->bufinfo;
443+
common_hal_rgbmatrix_rgbmatrix_get_bufinfo(self_in, bufinfo);
446444
bufinfo->typecode = 'H';
447445
return 0;
448446
}

shared-bindings/rgbmatrix/RGBMatrix.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ extern const mp_obj_type_t rgbmatrix_RGBMatrix_type;
3434
void common_hal_rgbmatrix_rgbmatrix_construct(rgbmatrix_rgbmatrix_obj_t *self, int width, int bit_depth, uint8_t rgb_count, uint8_t *rgb_pins, uint8_t addr_count, uint8_t *addr_pins, uint8_t clock_pin, uint8_t latch_pin, uint8_t oe_pin, bool doublebuffer, mp_obj_t framebuffer, int8_t tile, bool serpentine, void *timer);
3535
void common_hal_rgbmatrix_rgbmatrix_deinit(rgbmatrix_rgbmatrix_obj_t *);
3636
void rgbmatrix_rgbmatrix_collect_ptrs(rgbmatrix_rgbmatrix_obj_t *);
37+
void common_hal_rgbmatrix_rgbmatrix_get_bufinfo(rgbmatrix_rgbmatrix_obj_t *self, mp_buffer_info_t *bufinfo);
3738
void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t *self);
3839
void common_hal_rgbmatrix_rgbmatrix_set_paused(rgbmatrix_rgbmatrix_obj_t *self, bool paused);
3940
bool common_hal_rgbmatrix_rgbmatrix_get_paused(rgbmatrix_rgbmatrix_obj_t *self);

shared-module/rgbmatrix/RGBMatrix.c

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,12 @@ STATIC void common_hal_rgbmatrix_rgbmatrix_construct1(rgbmatrix_rgbmatrix_obj_t
7979
}
8080
// verify that the matrix is big enough
8181
mp_get_index(mp_obj_get_type(self->framebuffer), self->bufinfo.len, MP_OBJ_NEW_SMALL_INT(self->bufsize - 1), false);
82+
self->allocation = NULL;
8283
} else {
83-
self->bufinfo.buf = common_hal_rgbmatrix_allocator_impl(self->bufsize);
84+
// The supervisor allocation can move memory by changing self->allocation->ptr.
85+
// So we hold onto it and update bufinfo every time we use it.
86+
self->allocation = allocate_memory(align32_size(self->bufsize), false, true);
87+
self->bufinfo.buf = self->allocation->ptr;
8488
self->bufinfo.len = self->bufsize;
8589
self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW;
8690
}
@@ -146,7 +150,9 @@ STATIC void free_pin_seq(uint8_t *seq, int count) {
146150

147151
extern int pm_row_count;
148152
STATIC void common_hal_rgbmatrix_rgbmatrix_deinit1(rgbmatrix_rgbmatrix_obj_t *self) {
149-
common_hal_rgbmatrix_timer_disable(self->timer);
153+
if (self->timer != NULL) {
154+
common_hal_rgbmatrix_timer_disable(self->timer);
155+
}
150156

151157
if (_PM_protoPtr == &self->protomatter) {
152158
_PM_protoPtr = NULL;
@@ -160,15 +166,15 @@ STATIC void common_hal_rgbmatrix_rgbmatrix_deinit1(rgbmatrix_rgbmatrix_obj_t *se
160166

161167
// If it was supervisor-allocated, it is supervisor-freed and the pointer
162168
// is zeroed, otherwise the pointer is just zeroed
163-
if (self->bufinfo.buf) {
164-
common_hal_rgbmatrix_free_impl(self->bufinfo.buf);
165-
self->bufinfo.buf = NULL;
169+
if (self->allocation != NULL) {
170+
free_memory(self->allocation);
166171
}
167172

168-
169173
// If a framebuffer was passed in to the constructor, clear the reference
170174
// here so that it will become GC'able
171175
self->framebuffer = mp_const_none;
176+
177+
self->bufinfo.buf = NULL;
172178
}
173179

174180
void common_hal_rgbmatrix_rgbmatrix_deinit(rgbmatrix_rgbmatrix_obj_t *self) {
@@ -187,6 +193,13 @@ void common_hal_rgbmatrix_rgbmatrix_deinit(rgbmatrix_rgbmatrix_obj_t *self) {
187193
self->base.type = &mp_type_NoneType;
188194
}
189195

196+
void common_hal_rgbmatrix_rgbmatrix_get_bufinfo(rgbmatrix_rgbmatrix_obj_t *self, mp_buffer_info_t *bufinfo) {
197+
if (self->allocation != NULL) {
198+
self->bufinfo.buf = self->allocation->ptr;
199+
}
200+
*bufinfo = self->bufinfo;
201+
}
202+
190203
void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t *self) {
191204
if (self->framebuffer != mp_const_none) {
192205
memset(&self->bufinfo, 0, sizeof(self->bufinfo));
@@ -196,11 +209,6 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t *self)
196209
common_hal_rgbmatrix_rgbmatrix_deinit1(self);
197210
common_hal_rgbmatrix_rgbmatrix_construct1(self, mp_const_none);
198211
#endif
199-
if (self->bufinfo.buf == NULL) {
200-
self->bufinfo.buf = common_hal_rgbmatrix_allocator_impl(self->bufsize);
201-
self->bufinfo.len = self->bufsize;
202-
self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW;
203-
}
204212
memset(self->bufinfo.buf, 0, self->bufinfo.len);
205213
common_hal_rgbmatrix_rgbmatrix_set_paused(self, false);
206214
}
@@ -214,6 +222,9 @@ void common_hal_rgbmatrix_rgbmatrix_set_paused(rgbmatrix_rgbmatrix_obj_t *self,
214222
_PM_stop(&self->protomatter);
215223
} else if (!paused && self->paused) {
216224
_PM_resume(&self->protomatter);
225+
if (self->allocation) {
226+
self->bufinfo.buf = self->allocation->ptr;
227+
}
217228
_PM_convert_565(&self->protomatter, self->bufinfo.buf, self->width);
218229
_PM_swapbuffer_maybe(&self->protomatter);
219230
}
@@ -226,6 +237,9 @@ bool common_hal_rgbmatrix_rgbmatrix_get_paused(rgbmatrix_rgbmatrix_obj_t *self)
226237

227238
void common_hal_rgbmatrix_rgbmatrix_refresh(rgbmatrix_rgbmatrix_obj_t *self) {
228239
if (!self->paused) {
240+
if (self->allocation != NULL) {
241+
self->bufinfo.buf = self->allocation->ptr;
242+
}
229243
_PM_convert_565(&self->protomatter, self->bufinfo.buf, self->width);
230244
_PM_swapbuffer_maybe(&self->protomatter);
231245
}
@@ -240,11 +254,43 @@ int common_hal_rgbmatrix_rgbmatrix_get_height(rgbmatrix_rgbmatrix_obj_t *self) {
240254
return computed_height;
241255
}
242256

257+
// Track the returned pointers and their matching allocation so that we can free
258+
// them even when the memory was moved by the supervisor. This prevents leaks
259+
// but doesn't protect against the memory being used after its been freed! The
260+
// long term fix is to utilize a permanent heap that can be shared with MP's
261+
// split heap.
262+
typedef struct matrix_allocation {
263+
void *original_pointer;
264+
supervisor_allocation *allocation;
265+
} matrix_allocation_t;
266+
267+
// Four should be more than we ever need. ProtoMatter does 3 allocations currently.
268+
static matrix_allocation_t allocations[4];
269+
243270
void *common_hal_rgbmatrix_allocator_impl(size_t sz) {
244271
supervisor_allocation *allocation = allocate_memory(align32_size(sz), false, true);
245-
return allocation ? allocation->ptr : NULL;
272+
if (allocation == NULL) {
273+
return NULL;
274+
}
275+
for (size_t i = 0; i < sizeof(allocations); i++) {
276+
matrix_allocation_t *matrix_allocation = &allocations[i];
277+
if (matrix_allocation->original_pointer == NULL) {
278+
matrix_allocation->original_pointer = allocation->ptr;
279+
matrix_allocation->allocation = allocation;
280+
return allocation->ptr;
281+
}
282+
}
283+
return NULL;
246284
}
247285

248286
void common_hal_rgbmatrix_free_impl(void *ptr_in) {
249-
free_memory(allocation_from_ptr(ptr_in));
287+
for (size_t i = 0; i < sizeof(allocations); i++) {
288+
matrix_allocation_t *matrix_allocation = &allocations[i];
289+
if (matrix_allocation->original_pointer == ptr_in) {
290+
matrix_allocation->original_pointer = NULL;
291+
free_memory(matrix_allocation->allocation);
292+
matrix_allocation->allocation = NULL;
293+
return;
294+
}
295+
}
250296
}

shared-module/rgbmatrix/RGBMatrix.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,14 @@
2828

2929
#include "py/obj.h"
3030
#include "lib/protomatter/src/core.h"
31+
#include "supervisor/memory.h"
3132

3233
extern const mp_obj_type_t rgbmatrix_RGBMatrix_type;
3334
typedef struct {
3435
mp_obj_base_t base;
3536
mp_obj_t framebuffer;
3637
mp_buffer_info_t bufinfo;
38+
supervisor_allocation *allocation;
3739
Protomatter_core protomatter;
3840
void *timer;
3941
uint16_t bufsize, width;

0 commit comments

Comments
 (0)