Skip to content

Commit 18807f2

Browse files
committed
pybricks/tools/pb_type_async: Don't close if already scheduled.
When forgetting <await> in one or more tasks that use the same resource, the resource could be scheduled for cancellation but the awaitable is not awaited and closed, so race=True will trigger the other task to stop and thus try to cancel it again. But the parent object is already set to MP_OBJ_SENTINEL at this point, so evaluating close(parent) segfaults. The block code generator should be fixed to include await, but we also shouldn't segfault in case the user forgets await in their own user code. See pybricks/support#2621
1 parent 9ffaf56 commit 18807f2

3 files changed

Lines changed: 8 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@
1515
### Fixed
1616
- Fixed EV3 light animation stopping when screen is used ([support#2599]).
1717
- Fixed Powered Up motors not resetting to the absolute value ([support#2620]).
18+
- Fixed segfault when user or block code generator forgets `await` in one or
19+
more tasks that use the same resource (like a `DriveBase`) along
20+
with `race=True` ([support#2621]).
1821

1922
[support#2599]: https://github.com/pybricks/support/issues/2599
2023
[support#2603]: https://github.com/pybricks/support/issues/2603
2124
[support#2620]: https://github.com/pybricks/support/issues/2620
25+
[support#2621]: https://github.com/pybricks/support/issues/2621
2226

2327
## [4.0.0b7] - 2026-02-19
2428

pybricks/tools/pb_type_async.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ void pb_type_async_schedule_stop_iteration(pb_type_async_t *iter) {
3636

3737
mp_obj_t pb_type_async_close(mp_obj_t iter_in) {
3838
pb_type_async_t *iter = MP_OBJ_TO_PTR(iter_in);
39-
if (iter->close && iter->parent_obj != MP_OBJ_NULL) {
39+
// Close only if there is a close function and we aren't already closing
40+
// or scheduled it to close next time.
41+
if (iter->close && iter->parent_obj != MP_OBJ_NULL && iter->parent_obj != MP_OBJ_SENTINEL) {
4042
iter->close(iter->parent_obj);
4143
}
4244
// Closing is stronger than cancellation. In case of close, we expect that

pybricks/tools/pb_type_async.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ typedef struct {
4949
*
5050
* Special values:
5151
* MP_OBJ_NULL: This iterable has been fully exhausted and can be reused.
52-
* MP_OBJ_SENTINEL: This iterable is will raise StopIteration when it is iterated again.
52+
* MP_OBJ_SENTINEL: This iterable will raise StopIteration when it is iterated again.
5353
*/
5454
mp_obj_t parent_obj;
5555
/**

0 commit comments

Comments
 (0)