@@ -156,7 +156,15 @@ mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type, size_t n_args, con
156
156
157
157
// Populate the exception object
158
158
o_exc -> base .type = type ;
159
- o_exc -> traceback_data = NULL ;
159
+
160
+ // Try to allocate memory for the traceback, with fallback to emergency traceback object
161
+ o_exc -> traceback = m_new_obj_maybe (mp_obj_traceback_t );
162
+ if (o_exc -> traceback == NULL ) {
163
+ o_exc -> traceback = & MP_STATE_VM (mp_emergency_traceback_obj );
164
+ }
165
+
166
+ // Populate the traceback object
167
+ * o_exc -> traceback = mp_const_empty_traceback_obj ;
160
168
161
169
mp_obj_tuple_t * o_tuple ;
162
170
if (n_args == 0 ) {
@@ -208,22 +216,25 @@ void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
208
216
mp_obj_exception_t * self = MP_OBJ_TO_PTR (self_in );
209
217
if (dest [0 ] != MP_OBJ_NULL ) {
210
218
// store/delete attribute
211
- if (attr == MP_QSTR___traceback__ && dest [1 ] == mp_const_none ) {
212
- // We allow 'exc.__traceback__ = None' assignment as low-level
213
- // optimization of pre-allocating exception instance and raising
214
- // it repeatedly - this avoids memory allocation during raise.
215
- // However, uPy will keep adding traceback entries to such
216
- // exception instance, so before throwing it, traceback should
217
- // be cleared like above.
218
- self -> traceback_len = 0 ;
219
+ if (attr == MP_QSTR___traceback__ ) {
220
+ if (dest [1 ] == mp_const_none ) {
221
+ self -> traceback -> data = NULL ;
222
+ } else {
223
+ if (!mp_obj_is_type (dest [1 ], & mp_type_traceback )) {
224
+ mp_raise_TypeError (MP_ERROR_TEXT ("invalid traceback" ));
225
+ }
226
+ self -> traceback = MP_OBJ_TO_PTR (dest [1 ]);
227
+ }
219
228
dest [0 ] = MP_OBJ_NULL ; // indicate success
220
229
}
221
230
return ;
222
231
}
223
232
if (attr == MP_QSTR_args ) {
224
233
dest [0 ] = MP_OBJ_FROM_PTR (self -> args );
225
- } else if (self -> base . type == & mp_type_StopIteration && attr == MP_QSTR_value ) {
234
+ } else if (attr == MP_QSTR_value && self -> base . type == & mp_type_StopIteration ) {
226
235
dest [0 ] = mp_obj_exception_get_value (self_in );
236
+ } else if (attr == MP_QSTR___traceback__ ) {
237
+ dest [0 ] = (self -> traceback -> data ) ? MP_OBJ_FROM_PTR (self -> traceback ) : mp_const_none ;
227
238
#if MICROPY_CPYTHON_COMPAT
228
239
} else if (mp_obj_is_subclass_fast (MP_OBJ_FROM_PTR (self -> base .type ), MP_OBJ_FROM_PTR (& mp_type_OSError ))) {
229
240
if (attr == MP_QSTR_errno ) {
@@ -552,7 +563,7 @@ void mp_obj_exception_clear_traceback(mp_obj_t self_in) {
552
563
GET_NATIVE_EXCEPTION (self , self_in );
553
564
// just set the traceback to the null object
554
565
// we don't want to call any memory management functions here
555
- self -> traceback_data = NULL ;
566
+ self -> traceback -> data = NULL ;
556
567
}
557
568
558
569
void mp_obj_exception_add_traceback (mp_obj_t self_in , qstr file , size_t line , qstr block ) {
@@ -561,16 +572,16 @@ void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qs
561
572
// append this traceback info to traceback data
562
573
// if memory allocation fails (eg because gc is locked), just return
563
574
564
- if (self -> traceback_data == NULL ) {
565
- self -> traceback_data = m_new_maybe (size_t , TRACEBACK_ENTRY_LEN );
566
- if (self -> traceback_data == NULL ) {
575
+ if (self -> traceback -> data == NULL ) {
576
+ self -> traceback -> data = m_new_maybe (size_t , TRACEBACK_ENTRY_LEN );
577
+ if (self -> traceback -> data == NULL ) {
567
578
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
568
579
if (mp_emergency_exception_buf_size >= (mp_int_t )(EMG_BUF_TRACEBACK_OFFSET + EMG_BUF_TRACEBACK_SIZE )) {
569
580
// There is room in the emergency buffer for traceback data
570
581
size_t * tb = (size_t * )((uint8_t * )MP_STATE_VM (mp_emergency_exception_buf )
571
582
+ EMG_BUF_TRACEBACK_OFFSET );
572
- self -> traceback_data = tb ;
573
- self -> traceback_alloc = EMG_BUF_TRACEBACK_SIZE / sizeof (size_t );
583
+ self -> traceback -> data = tb ;
584
+ self -> traceback -> alloc = EMG_BUF_TRACEBACK_SIZE / sizeof (size_t );
574
585
} else {
575
586
// Can't allocate and no room in emergency buffer
576
587
return ;
@@ -581,28 +592,28 @@ void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qs
581
592
#endif
582
593
} else {
583
594
// Allocated the traceback data on the heap
584
- self -> traceback_alloc = TRACEBACK_ENTRY_LEN ;
595
+ self -> traceback -> alloc = TRACEBACK_ENTRY_LEN ;
585
596
}
586
- self -> traceback_len = 0 ;
587
- } else if (self -> traceback_len + TRACEBACK_ENTRY_LEN > self -> traceback_alloc ) {
597
+ self -> traceback -> len = 0 ;
598
+ } else if (self -> traceback -> len + TRACEBACK_ENTRY_LEN > self -> traceback -> alloc ) {
588
599
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
589
- if (self -> traceback_data == (size_t * )MP_STATE_VM (mp_emergency_exception_buf )) {
600
+ if (self -> traceback -> data == (size_t * )MP_STATE_VM (mp_emergency_exception_buf )) {
590
601
// Can't resize the emergency buffer
591
602
return ;
592
603
}
593
604
#endif
594
605
// be conservative with growing traceback data
595
- size_t * tb_data = m_renew_maybe (size_t , self -> traceback_data , self -> traceback_alloc ,
596
- self -> traceback_alloc + TRACEBACK_ENTRY_LEN , true);
606
+ size_t * tb_data = m_renew_maybe (size_t , self -> traceback -> data , self -> traceback -> alloc ,
607
+ self -> traceback -> alloc + TRACEBACK_ENTRY_LEN , true);
597
608
if (tb_data == NULL ) {
598
609
return ;
599
610
}
600
- self -> traceback_data = tb_data ;
601
- self -> traceback_alloc += TRACEBACK_ENTRY_LEN ;
611
+ self -> traceback -> data = tb_data ;
612
+ self -> traceback -> alloc += TRACEBACK_ENTRY_LEN ;
602
613
}
603
614
604
- size_t * tb_data = & self -> traceback_data [self -> traceback_len ];
605
- self -> traceback_len += TRACEBACK_ENTRY_LEN ;
615
+ size_t * tb_data = & self -> traceback -> data [self -> traceback -> len ];
616
+ self -> traceback -> len += TRACEBACK_ENTRY_LEN ;
606
617
tb_data [0 ] = file ;
607
618
tb_data [1 ] = line ;
608
619
tb_data [2 ] = block ;
@@ -611,12 +622,12 @@ void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qs
611
622
void mp_obj_exception_get_traceback (mp_obj_t self_in , size_t * n , size_t * * values ) {
612
623
GET_NATIVE_EXCEPTION (self , self_in );
613
624
614
- if (self -> traceback_data == NULL ) {
625
+ if (self -> traceback -> data == NULL ) {
615
626
* n = 0 ;
616
627
* values = NULL ;
617
628
} else {
618
- * n = self -> traceback_len ;
619
- * values = self -> traceback_data ;
629
+ * n = self -> traceback -> len ;
630
+ * values = self -> traceback -> data ;
620
631
}
621
632
}
622
633
0 commit comments