@@ -20,6 +20,9 @@ typedef struct _mp_obj_exception_t {
2020// Instance of MemoryError exception - needed by mp_malloc_fail
2121const mp_obj_exception_t mp_const_MemoryError_obj = {{& mp_type_MemoryError }, MP_OBJ_NULL , {{& mp_type_tuple }, 0 }};
2222
23+ // Local non-heap memory for allocating an exception when we run out of RAM
24+ STATIC mp_obj_exception_t mp_emergency_exception_obj ;
25+
2326// Instance of GeneratorExit exception - needed by generator.close()
2427// This would belong to objgenerator.c, but to keep mp_obj_exception_t
2528// definition module-private so far, have it here.
@@ -51,7 +54,13 @@ STATIC mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_
5154 nlr_raise (mp_obj_new_exception_msg_varg (& mp_type_TypeError , "%s does not take keyword arguments" , mp_obj_get_type_str (type_in )));
5255 }
5356
54- mp_obj_exception_t * o = m_new_obj_var (mp_obj_exception_t , mp_obj_t , n_args );
57+ mp_obj_exception_t * o = m_malloc_maybe (sizeof (mp_obj_exception_t ) + n_args * sizeof (mp_obj_t ));
58+ if (o == NULL ) {
59+ // Couldn't allocate heap memory; use local data instead.
60+ o = & mp_emergency_exception_obj ;
61+ // We can't store any args.
62+ n_args = 0 ;
63+ }
5564 o -> base .type = type ;
5665 o -> traceback = MP_OBJ_NULL ;
5766 o -> args .base .type = & mp_type_tuple ;
@@ -196,25 +205,35 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char
196205 assert (exc_type -> make_new == mp_obj_exception_make_new );
197206
198207 // make exception object
199- mp_obj_exception_t * o = m_new_obj_var ( mp_obj_exception_t , mp_obj_t , 1 );
200- o -> base . type = exc_type ;
201- o -> traceback = MP_OBJ_NULL ;
202- o -> args . base . type = & mp_type_tuple ;
203- o -> args . len = 1 ;
204-
205- if ( fmt == NULL ) {
206- // no message
207- assert ( 0 ) ;
208+ mp_obj_exception_t * o = m_malloc_maybe ( sizeof ( mp_obj_exception_t ) + 1 * sizeof ( mp_obj_t ) );
209+ if ( o == NULL ) {
210+ // Couldn't allocate heap memory; use local data instead.
211+ // Unfortunately, we won't be able to format the string...
212+ o = & mp_emergency_exception_obj ;
213+ o -> base . type = exc_type ;
214+ o -> traceback = MP_OBJ_NULL ;
215+ o -> args . base . type = & mp_type_tuple ;
216+ o -> args . len = 0 ;
208217 } else {
209- // render exception message and store as .args[0]
210- // TODO: optimize bufferbloat
211- vstr_t * vstr = vstr_new ();
212- va_list ap ;
213- va_start (ap , fmt );
214- vstr_vprintf (vstr , fmt , ap );
215- va_end (ap );
216- o -> args .items [0 ] = mp_obj_new_str ((byte * )vstr -> buf , vstr -> len , false);
217- vstr_free (vstr );
218+ o -> base .type = exc_type ;
219+ o -> traceback = MP_OBJ_NULL ;
220+ o -> args .base .type = & mp_type_tuple ;
221+ o -> args .len = 1 ;
222+
223+ if (fmt == NULL ) {
224+ // no message
225+ assert (0 );
226+ } else {
227+ // render exception message and store as .args[0]
228+ // TODO: optimize bufferbloat
229+ vstr_t * vstr = vstr_new ();
230+ va_list ap ;
231+ va_start (ap , fmt );
232+ vstr_vprintf (vstr , fmt , ap );
233+ va_end (ap );
234+ o -> args .items [0 ] = mp_obj_new_str ((byte * )vstr -> buf , vstr -> len , false);
235+ vstr_free (vstr );
236+ }
218237 }
219238
220239 return o ;
@@ -259,7 +278,7 @@ void mp_obj_exception_clear_traceback(mp_obj_t self_in) {
259278void mp_obj_exception_add_traceback (mp_obj_t self_in , qstr file , machine_uint_t line , qstr block ) {
260279 // make sure self_in is an exception instance
261280 // TODO add traceback information to user-defined exceptions (need proper builtin subclassing for that)
262- if (mp_obj_get_type (self_in )-> make_new == mp_obj_exception_make_new ) {
281+ if (mp_obj_get_type (self_in )-> make_new == mp_obj_exception_make_new && self_in != & mp_emergency_exception_obj ) {
263282 mp_obj_exception_t * self = self_in ;
264283
265284 // for traceback, we are just using the list object for convenience, it's not really a list of Python objects
0 commit comments