Skip to content

Commit 03b077d

Browse files
committed
Add deinit() to _bleio.Characteristic
Espressif's Characteristics allocate memory that may be on the supervisor heap. We need to free it when stopping BLE workflow. Otherwise, we leak the memory and eventually safe mode. Fixes #9599
1 parent 4d88d73 commit 03b077d

File tree

11 files changed

+113
-33
lines changed

11 files changed

+113
-33
lines changed

devices/ble_hci/common-hal/_bleio/Characteristic.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,17 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self,
5050
}
5151
}
5252

53+
bool common_hal_bleio_characteristic_deinited(bleio_characteristic_obj_t *self) {
54+
return self->handle == BLE_GATT_HANDLE_INVALID;
55+
}
56+
57+
void common_hal_bleio_characteristic_deinit(bleio_characteristic_obj_t *self) {
58+
if (common_hal_bleio_characteristic_deinited(self)) {
59+
return;
60+
}
61+
self->handle = BLE_GATT_HANDLE_INVALID;
62+
}
63+
5364
mp_obj_tuple_t *common_hal_bleio_characteristic_get_descriptors(bleio_characteristic_obj_t *self) {
5465
return mp_obj_new_tuple(self->descriptor_list->len, self->descriptor_list->items);
5566
}

ports/espressif/common-hal/_bleio/Characteristic.c

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "shared-bindings/_bleio/PacketBuffer.h"
1717
#include "shared-bindings/_bleio/Service.h"
1818
#include "shared-bindings/time/__init__.h"
19+
#include "supervisor/shared/safe_mode.h"
1920

2021
#include "common-hal/_bleio/Adapter.h"
2122
#include "common-hal/_bleio/Service.h"
@@ -100,27 +101,20 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self,
100101
self->flags |= BLE_GATT_CHR_F_WRITE_AUTHEN;
101102
}
102103

103-
if (initial_value_bufinfo != NULL) {
104-
// Copy the initial value if it's on the heap. Otherwise it's internal and we may not be able
105-
// to allocate.
106-
self->current_value_len = initial_value_bufinfo->len;
107-
if (gc_alloc_possible()) {
108-
self->current_value = m_malloc(max_length);
109-
self->current_value_alloc = max_length;
110-
if (gc_nbytes(initial_value_bufinfo->buf) > 0) {
111-
memcpy(self->current_value, initial_value_bufinfo->buf, self->current_value_len);
112-
}
113-
} else {
114-
self->current_value = initial_value_bufinfo->buf;
115-
assert(self->current_value_len == max_length);
116-
}
104+
if (gc_alloc_possible()) {
105+
self->current_value = m_malloc(max_length);
117106
} else {
118107
self->current_value = port_malloc(max_length, false);
119-
if (self->current_value != NULL) {
120-
self->current_value_alloc = max_length;
121-
self->current_value_len = 0;
108+
if (self->current_value == NULL) {
109+
reset_into_safe_mode(SAFE_MODE_NO_HEAP);
122110
}
123111
}
112+
self->current_value_alloc = max_length;
113+
self->current_value_len = 0;
114+
115+
if (initial_value_bufinfo != NULL) {
116+
common_hal_bleio_characteristic_set_value(self, initial_value_bufinfo);
117+
}
124118

125119
if (gc_alloc_possible()) {
126120
self->descriptor_list = mp_obj_new_list(0, NULL);
@@ -140,6 +134,26 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self,
140134
}
141135
}
142136

137+
bool common_hal_bleio_characteristic_deinited(bleio_characteristic_obj_t *self) {
138+
return self->current_value == NULL;
139+
}
140+
141+
void common_hal_bleio_characteristic_deinit(bleio_characteristic_obj_t *self) {
142+
if (common_hal_bleio_characteristic_deinited(self)) {
143+
return;
144+
}
145+
if (self->current_value == NULL) {
146+
return;
147+
}
148+
149+
if (gc_nbytes(self->current_value) > 0) {
150+
m_free(self->current_value);
151+
} else {
152+
port_free(self->current_value);
153+
}
154+
self->current_value = NULL;
155+
}
156+
143157
mp_obj_tuple_t *common_hal_bleio_characteristic_get_descriptors(bleio_characteristic_obj_t *self) {
144158
if (self->descriptor_list == NULL) {
145159
return mp_const_empty_tuple;
@@ -245,21 +259,7 @@ void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self,
245259
}
246260

247261
self->current_value_len = bufinfo->len;
248-
// If we've already allocated an internal buffer or the provided buffer
249-
// is on the heap, then copy into the internal buffer.
250-
if (self->current_value_alloc > 0 || gc_nbytes(bufinfo->buf) > 0) {
251-
if (self->current_value_alloc < bufinfo->len) {
252-
self->current_value = m_realloc(self->current_value, bufinfo->len);
253-
// Get the number of bytes from the heap because it may be more
254-
// than the len due to gc block size.
255-
self->current_value_alloc = gc_nbytes(self->current_value);
256-
}
257-
memcpy(self->current_value, bufinfo->buf, bufinfo->len);
258-
} else {
259-
// Otherwise, use the provided buffer to delay any heap allocation.
260-
self->current_value = bufinfo->buf;
261-
self->current_value_alloc = 0;
262-
}
262+
memcpy(self->current_value, bufinfo->buf, self->current_value_len);
263263

264264
ble_gatts_chr_updated(self->handle);
265265
}

ports/espressif/common-hal/_bleio/PacketBuffer.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) {
436436
return;
437437
}
438438
bleio_characteristic_clear_observer(self->characteristic);
439+
self->characteristic = NULL;
439440
ble_event_remove_handler(packet_buffer_on_ble_client_evt, self);
440441
ringbuf_deinit(&self->ringbuf);
441442
}

ports/nordic/common-hal/_bleio/Characteristic.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,19 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self,
109109
}
110110
}
111111

112+
bool common_hal_bleio_characteristic_deinited(bleio_characteristic_obj_t *self) {
113+
return self->handle == BLE_GATT_HANDLE_INVALID;
114+
}
115+
116+
void common_hal_bleio_characteristic_deinit(bleio_characteristic_obj_t *self) {
117+
if (common_hal_bleio_characteristic_deinited(self)) {
118+
return;
119+
}
120+
self->handle = BLE_GATT_HANDLE_INVALID;
121+
// TODO: Can we remove this from the soft device? Right now we assume the
122+
// reset clears things.
123+
}
124+
112125
mp_obj_tuple_t *common_hal_bleio_characteristic_get_descriptors(bleio_characteristic_obj_t *self) {
113126
if (self->descriptor_list == NULL) {
114127
return mp_const_empty_tuple;

ports/silabs/common-hal/_bleio/Characteristic.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,13 @@ void common_hal_bleio_characteristic_construct(
155155
}
156156
}
157157

158+
bool common_hal_bleio_characteristic_deinited(bleio_characteristic_obj_t *self) {
159+
return false;
160+
}
161+
162+
void common_hal_bleio_characteristic_deinit(bleio_characteristic_obj_t *self) {
163+
}
164+
158165
// A tuple of Descriptor that describe this characteristic
159166
mp_obj_tuple_t *common_hal_bleio_characteristic_get_descriptors(
160167
bleio_characteristic_obj_t *self) {

shared-bindings/_bleio/Characteristic.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include "shared-bindings/_bleio/Characteristic.h"
1313
#include "shared-bindings/_bleio/Service.h"
1414
#include "shared-bindings/_bleio/UUID.h"
15+
#include "shared-bindings/util.h"
16+
1517

1618
//| class Characteristic:
1719
//| """Stores information about a BLE service characteristic and allows reading
@@ -137,14 +139,29 @@ static mp_obj_t bleio_characteristic_add_to_service(size_t n_args, const mp_obj_
137139
static MP_DEFINE_CONST_FUN_OBJ_KW(bleio_characteristic_add_to_service_fun_obj, 1, bleio_characteristic_add_to_service);
138140
static MP_DEFINE_CONST_CLASSMETHOD_OBJ(bleio_characteristic_add_to_service_obj, MP_ROM_PTR(&bleio_characteristic_add_to_service_fun_obj));
139141

142+
//| def deinit(self) -> None:
143+
//| """Deinitialises the Characteristic and releases any hardware resources for reuse."""
144+
//| ...
145+
static mp_obj_t bleio_characteristic_deinit(mp_obj_t self_in) {
146+
bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
147+
common_hal_bleio_characteristic_deinit(self);
148+
return mp_const_none;
149+
}
150+
static MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_deinit_obj, bleio_characteristic_deinit);
140151

152+
static void check_for_deinit(bleio_characteristic_obj_t *self) {
153+
if (common_hal_bleio_characteristic_deinited(self)) {
154+
raise_deinited_error();
155+
}
156+
}
141157

142158
//| properties: int
143159
//| """An int bitmask representing which properties are set, specified as bitwise or'ing of
144160
//| of these possible values.
145161
//| `BROADCAST`, `INDICATE`, `NOTIFY`, `READ`, `WRITE`, `WRITE_NO_RESPONSE`."""
146162
static mp_obj_t bleio_characteristic_get_properties(mp_obj_t self_in) {
147163
bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
164+
check_for_deinit(self);
148165

149166
return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_characteristic_get_properties(self));
150167
}
@@ -159,6 +176,7 @@ MP_PROPERTY_GETTER(bleio_characteristic_properties_obj,
159176
//| Will be ``None`` if the 128-bit UUID for this characteristic is not known."""
160177
static mp_obj_t bleio_characteristic_get_uuid(mp_obj_t self_in) {
161178
bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
179+
check_for_deinit(self);
162180

163181
bleio_uuid_obj_t *uuid = common_hal_bleio_characteristic_get_uuid(self);
164182
return uuid ? MP_OBJ_FROM_PTR(uuid) : mp_const_none;
@@ -172,6 +190,7 @@ MP_PROPERTY_GETTER(bleio_characteristic_uuid_obj,
172190
//| """The value of this characteristic."""
173191
static mp_obj_t bleio_characteristic_get_value(mp_obj_t self_in) {
174192
bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
193+
check_for_deinit(self);
175194

176195
uint8_t temp[512];
177196
size_t actual_len = common_hal_bleio_characteristic_get_value(self, temp, sizeof(temp));
@@ -181,6 +200,7 @@ static MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_value_obj, bleio_chara
181200

182201
static mp_obj_t bleio_characteristic_set_value(mp_obj_t self_in, mp_obj_t value_in) {
183202
bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
203+
check_for_deinit(self);
184204

185205
mp_buffer_info_t bufinfo;
186206
mp_get_buffer_raise(value_in, &bufinfo, MP_BUFFER_READ);
@@ -199,6 +219,7 @@ MP_PROPERTY_GETSET(bleio_characteristic_value_obj,
199219
//| """The max length of this characteristic."""
200220
static mp_obj_t bleio_characteristic_get_max_length(mp_obj_t self_in) {
201221
bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
222+
check_for_deinit(self);
202223

203224
return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_characteristic_get_max_length(self));
204225
}
@@ -211,6 +232,8 @@ MP_PROPERTY_GETTER(bleio_characteristic_max_length_obj,
211232
//| """A tuple of :py:class:`Descriptor` objects related to this characteristic. (read-only)"""
212233
static mp_obj_t bleio_characteristic_get_descriptors(mp_obj_t self_in) {
213234
bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
235+
check_for_deinit(self);
236+
214237
// Return list as a tuple so user won't be able to change it.
215238
return MP_OBJ_FROM_PTR(common_hal_bleio_characteristic_get_descriptors(self));
216239
}
@@ -224,6 +247,7 @@ MP_PROPERTY_GETTER(bleio_characteristic_descriptors_obj,
224247
//| """The Service this Characteristic is a part of."""
225248
static mp_obj_t bleio_characteristic_get_service(mp_obj_t self_in) {
226249
bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
250+
check_for_deinit(self);
227251

228252
return common_hal_bleio_characteristic_get_service(self);
229253
}
@@ -241,6 +265,7 @@ MP_PROPERTY_GETTER(bleio_characteristic_service_obj,
241265
//| ...
242266
static mp_obj_t bleio_characteristic_set_cccd(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
243267
bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
268+
check_for_deinit(self);
244269

245270
enum { ARG_notify, ARG_indicate };
246271
static const mp_arg_t allowed_args[] = {
@@ -258,6 +283,9 @@ static mp_obj_t bleio_characteristic_set_cccd(mp_uint_t n_args, const mp_obj_t *
258283
static MP_DEFINE_CONST_FUN_OBJ_KW(bleio_characteristic_set_cccd_obj, 1, bleio_characteristic_set_cccd);
259284

260285
static const mp_rom_map_elem_t bleio_characteristic_locals_dict_table[] = {
286+
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&bleio_characteristic_deinit_obj) },
287+
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&bleio_characteristic_deinit_obj) },
288+
261289
{ MP_ROM_QSTR(MP_QSTR_add_to_service), MP_ROM_PTR(&bleio_characteristic_add_to_service_obj) },
262290
{ MP_ROM_QSTR(MP_QSTR_descriptors), MP_ROM_PTR(&bleio_characteristic_descriptors_obj) },
263291
{ MP_ROM_QSTR(MP_QSTR_properties), MP_ROM_PTR(&bleio_characteristic_properties_obj) },

shared-bindings/_bleio/Characteristic.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,7 @@ extern size_t common_hal_bleio_characteristic_get_max_length(bleio_characteristi
2424
extern size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self, uint8_t *buf, size_t len);
2525
extern void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *self, bleio_descriptor_obj_t *descriptor);
2626
extern void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_service_obj_t *service, uint16_t handle, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo, const char *user_description);
27+
extern bool common_hal_bleio_characteristic_deinited(bleio_characteristic_obj_t *self);
28+
extern void common_hal_bleio_characteristic_deinit(bleio_characteristic_obj_t *self);
2729
extern void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate);
2830
extern void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo);

supervisor/shared/bluetooth/bluetooth.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,10 @@ void supervisor_stop_bluetooth(void) {
339339

340340
ble_started = false;
341341

342+
#if CIRCUITPY_BLE_FILE_SERVICE
343+
supervisor_stop_bluetooth_file_transfer();
344+
#endif
345+
342346
#if CIRCUITPY_SERIAL_BLE
343347
supervisor_stop_bluetooth_serial();
344348
#endif

supervisor/shared/bluetooth/file_transfer.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,13 @@ void supervisor_start_bluetooth_file_transfer(void) {
101101
&static_handler_entry);
102102
}
103103

104+
void supervisor_stop_bluetooth_file_transfer(void) {
105+
common_hal_bleio_packet_buffer_deinit(&_transfer_packet_buffer);
106+
common_hal_bleio_characteristic_deinit(&supervisor_ble_transfer_characteristic);
107+
common_hal_bleio_characteristic_deinit(&supervisor_ble_version_characteristic);
108+
common_hal_bleio_service_deinit(&supervisor_ble_service);
109+
}
110+
104111
#define COMMAND_SIZE 1024
105112

106113
#define ANY_COMMAND 0x00

supervisor/shared/bluetooth/file_transfer.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#include <stdbool.h>
1010

11-
void supervisor_bluetooth_file_transfer_background(void);
1211
void supervisor_start_bluetooth_file_transfer(void);
12+
void supervisor_stop_bluetooth_file_transfer(void);
13+
14+
void supervisor_bluetooth_file_transfer_background(void);
1315
void supervisor_bluetooth_file_transfer_disconnected(void);

supervisor/shared/bluetooth/serial.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,11 @@ void supervisor_stop_bluetooth_serial(void) {
148148
return;
149149
}
150150
common_hal_bleio_packet_buffer_flush(&_tx_packet_buffer);
151+
common_hal_bleio_packet_buffer_deinit(&_tx_packet_buffer);
152+
common_hal_bleio_characteristic_deinit(&supervisor_ble_circuitpython_rx_characteristic);
153+
common_hal_bleio_characteristic_deinit(&supervisor_ble_circuitpython_tx_characteristic);
154+
common_hal_bleio_characteristic_deinit(&supervisor_ble_circuitpython_version_characteristic);
155+
common_hal_bleio_service_deinit(&supervisor_ble_circuitpython_service);
151156
}
152157

153158
bool ble_serial_connected(void) {

0 commit comments

Comments
 (0)