From c3d96d387c461c25ca3298dfa73d2a4efb45f1e7 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 14 Nov 2016 02:23:30 +0300 Subject: [PATCH] py/objexcept: Allow clearing traceback with 'exc.__traceback__ = None'. We allow 'exc.__traceback__ = None' assignment as a low-level optimization of pre-allocating exception instance and raising it repeatedly - this avoids memory allocation during raise. However, uPy will keep adding traceback entries to such exception instance, so before throwing it, traceback should be cleared like above. 'exc.__traceback__ = None' syntax is CPython compatible. However, unlike it, reading that attribute or setting it to any other value is not supported (and not intended to be supported, again, the only reason for adding this feature is to allow zero-memalloc exception raising). --- py/objexcept.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/py/objexcept.c b/py/objexcept.c index 9ccc9288c..c1b992d27 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -152,11 +152,21 @@ mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in) { } STATIC void exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in); if (dest[0] != MP_OBJ_NULL) { - // not load attribute + // store/delete attribute + if (attr == MP_QSTR___traceback__ && dest[1] == mp_const_none) { + // We allow 'exc.__traceback__ = None' assignment as low-level + // optimization of pre-allocating exception instance and raising + // it repeatedly - this avoids memory allocation during raise. + // However, uPy will keep adding traceback entries to such + // exception instance, so before throwing it, traceback should + // be cleared like above. + self->traceback_len = 0; + dest[0] = MP_OBJ_NULL; // indicate success + } return; } - mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in); if (attr == MP_QSTR_args) { dest[0] = MP_OBJ_FROM_PTR(self->args); } else if (self->base.type == &mp_type_StopIteration && attr == MP_QSTR_value) {