diff --git a/extmod/machine_mem.c b/extmod/machine_mem.c index b9f16507c4b76..376d3652ac786 100644 --- a/extmod/machine_mem.c +++ b/extmod/machine_mem.c @@ -42,7 +42,7 @@ STATIC uintptr_t machine_mem_get_addr(mp_obj_t addr_o, uint align) { uintptr_t addr = mp_obj_int_get_truncated(addr_o); if ((addr & (align - 1)) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "address %08x is not aligned to %d bytes", addr, align)); + mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "address %08x is not aligned to %d bytes", addr, align)); } return addr; } @@ -69,6 +69,9 @@ STATIC mp_obj_t machine_mem_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t va } else if (value == MP_OBJ_SENTINEL) { // load uintptr_t addr = MICROPY_MACHINE_MEM_GET_READ_ADDR(index, self->elem_size); + if (MP_STATE_THREAD(active_exception) != NULL) { + return MP_OBJ_NULL; + } uint32_t val; switch (self->elem_size) { case 1: val = (*(uint8_t*)addr); break; @@ -79,6 +82,9 @@ STATIC mp_obj_t machine_mem_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t va } else { // store uintptr_t addr = MICROPY_MACHINE_MEM_GET_WRITE_ADDR(index, self->elem_size); + if (MP_STATE_THREAD(active_exception) != NULL) { + return MP_OBJ_NULL; + } uint32_t val = mp_obj_get_int_truncated(value); switch (self->elem_size) { case 1: (*(uint8_t*)addr) = val; break; diff --git a/extmod/machine_signal.c b/extmod/machine_signal.c index 8204ef174a23c..95d1c81831e3a 100644 --- a/extmod/machine_signal.c +++ b/extmod/machine_signal.c @@ -105,7 +105,7 @@ STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t } } else { error: - mp_raise_TypeError(NULL); + return mp_raise_TypeError_o(NULL); } } diff --git a/extmod/modbtree.c b/extmod/modbtree.c index a1d576fda970e..89ee6d32c3670 100644 --- a/extmod/modbtree.c +++ b/extmod/modbtree.c @@ -58,7 +58,7 @@ STATIC const mp_obj_type_t btree_type; #define CHECK_ERROR(res) \ if (res == RET_ERROR) { \ - mp_raise_OSError(errno); \ + return mp_raise_OSError_o(errno); \ } void __dbpanic(DB *db) { @@ -256,7 +256,7 @@ STATIC mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { key.data = (void*)mp_obj_str_get_data(index, &key.size); int res = __bt_delete(self->db, &key, 0); if (res == RET_SPECIAL) { - nlr_raise(mp_obj_new_exception(&mp_type_KeyError)); + return mp_raise_o(mp_obj_new_exception(&mp_type_KeyError)); } CHECK_ERROR(res); return mp_const_none; @@ -266,7 +266,7 @@ STATIC mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { key.data = (void*)mp_obj_str_get_data(index, &key.size); int res = __bt_get(self->db, &key, &val, 0); if (res == RET_SPECIAL) { - nlr_raise(mp_obj_new_exception(&mp_type_KeyError)); + return mp_raise_o(mp_obj_new_exception(&mp_type_KeyError)); } CHECK_ERROR(res); return mp_obj_new_bytes(val.data, val.size); @@ -359,7 +359,7 @@ STATIC mp_obj_t mod_btree_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t DB *db = __bt_open(MP_OBJ_TO_PTR(pos_args[0]), &btree_stream_fvtable, &openinfo, /*dflags*/0); if (db == NULL) { - mp_raise_OSError(errno); + return mp_raise_OSError_o(errno); } return MP_OBJ_FROM_PTR(btree_new(db)); } diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index 416431cd61bc7..8952ce9c001fa 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -296,7 +296,7 @@ STATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size case FRAMEBUF_GS8: break; default: - mp_raise_ValueError("invalid format"); + return mp_raise_ValueError_o("invalid format"); } return MP_OBJ_FROM_PTR(o); diff --git a/extmod/modubinascii.c b/extmod/modubinascii.c index 8256a50cf2042..6ffe282dbe9c0 100644 --- a/extmod/modubinascii.c +++ b/extmod/modubinascii.c @@ -78,7 +78,7 @@ mp_obj_t mod_binascii_unhexlify(mp_obj_t data) { mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); if ((bufinfo.len & 1) != 0) { - mp_raise_ValueError("odd-length string"); + return mp_raise_ValueError_o("odd-length string"); } vstr_t vstr; vstr_init_len(&vstr, bufinfo.len / 2); @@ -89,7 +89,7 @@ mp_obj_t mod_binascii_unhexlify(mp_obj_t data) { if (unichar_isxdigit(hex_ch)) { hex_byte += unichar_xdigit_value(hex_ch); } else { - mp_raise_ValueError("non-hex digit found"); + return mp_raise_ValueError_o("non-hex digit found"); } if (i & 1) { hex_byte <<= 4; @@ -157,7 +157,7 @@ mp_obj_t mod_binascii_a2b_base64(mp_obj_t data) { } if (nbits) { - mp_raise_ValueError("incorrect padding"); + return mp_raise_ValueError_o("incorrect padding"); } return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); diff --git a/extmod/moducryptolib.c b/extmod/moducryptolib.c index fd487a816c738..879631926fec8 100644 --- a/extmod/moducryptolib.c +++ b/extmod/moducryptolib.c @@ -225,7 +225,7 @@ STATIC mp_obj_t ucryptolib_aes_make_new(const mp_obj_type_t *type, size_t n_args break; default: - mp_raise_ValueError("mode"); + return mp_raise_ValueError_o("mode"); } mp_obj_aes_t *o = m_new_obj_var(mp_obj_aes_t, struct ctr_params, !!is_ctr_mode(block_mode)); @@ -237,7 +237,7 @@ STATIC mp_obj_t ucryptolib_aes_make_new(const mp_obj_type_t *type, size_t n_args mp_buffer_info_t keyinfo; mp_get_buffer_raise(args[0], &keyinfo, MP_BUFFER_READ); if (32 != keyinfo.len && 16 != keyinfo.len) { - mp_raise_ValueError("key"); + return mp_raise_ValueError_o("key"); } mp_buffer_info_t ivinfo; @@ -246,10 +246,10 @@ STATIC mp_obj_t ucryptolib_aes_make_new(const mp_obj_type_t *type, size_t n_args mp_get_buffer_raise(args[2], &ivinfo, MP_BUFFER_READ); if (16 != ivinfo.len) { - mp_raise_ValueError("IV"); + return mp_raise_ValueError_o("IV"); } } else if (o->block_mode == UCRYPTOLIB_MODE_CBC || is_ctr_mode(o->block_mode)) { - mp_raise_ValueError("IV"); + return mp_raise_ValueError_o("IV"); } if (is_ctr_mode(block_mode)) { @@ -274,7 +274,7 @@ STATIC mp_obj_t aes_process(size_t n_args, const mp_obj_t *args, bool encrypt) { mp_get_buffer_raise(in_buf, &in_bufinfo, MP_BUFFER_READ); if (!is_ctr_mode(self->block_mode) && in_bufinfo.len % 16 != 0) { - mp_raise_ValueError("blksize % 16"); + return mp_raise_ValueError_o("blksize % 16"); } vstr_t vstr; @@ -284,7 +284,7 @@ STATIC mp_obj_t aes_process(size_t n_args, const mp_obj_t *args, bool encrypt) { if (out_buf != MP_OBJ_NULL) { mp_get_buffer_raise(out_buf, &out_bufinfo, MP_BUFFER_WRITE); if (out_bufinfo.len < in_bufinfo.len) { - mp_raise_ValueError("output too small"); + return mp_raise_ValueError_o("output too small"); } out_buf_ptr = out_bufinfo.buf; } else { @@ -301,7 +301,7 @@ STATIC mp_obj_t aes_process(size_t n_args, const mp_obj_t *args, bool encrypt) { if ((encrypt && self->key_type == AES_KEYTYPE_DEC) || (!encrypt && self->key_type == AES_KEYTYPE_ENC)) { - mp_raise_ValueError("can't encrypt & decrypt"); + return mp_raise_ValueError_o("can't encrypt & decrypt"); } } diff --git a/extmod/moductypes.c b/extmod/moductypes.c index 62bbcbac224f4..9b55f467caeac 100644 --- a/extmod/moductypes.c +++ b/extmod/moductypes.c @@ -116,8 +116,8 @@ typedef struct _mp_obj_uctypes_struct_t { uint32_t flags; } mp_obj_uctypes_struct_t; -STATIC NORETURN void syntax_error(void) { - mp_raise_TypeError("syntax error in uctypes descriptor"); +STATIC mp_obj_t syntax_error(void) { + return mp_raise_TypeError_o("syntax error in uctypes descriptor"); } STATIC mp_obj_t uctypes_struct_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { @@ -222,9 +222,11 @@ STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_ // but scalar structure field is lowered into native Python int, so all // type info is lost. So, we cannot say if it's scalar type description, // or such lowered scalar. - mp_raise_TypeError("Cannot unambiguously get sizeof scalar"); + mp_raise_TypeError_o("Cannot unambiguously get sizeof scalar"); + return (mp_uint_t)-1; } syntax_error(); + return (mp_uint_t)-1; } mp_obj_dict_t *d = MP_OBJ_TO_PTR(desc_in); @@ -250,6 +252,7 @@ STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_ } else { if (!mp_obj_is_type(v, &mp_type_tuple)) { syntax_error(); + return (mp_uint_t)-1; } mp_obj_tuple_t *t = MP_OBJ_TO_PTR(v); mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]); @@ -280,7 +283,7 @@ STATIC mp_obj_t uctypes_struct_sizeof(size_t n_args, const mp_obj_t *args) { // or to instantiated structure if (mp_obj_is_type(obj_in, &uctypes_struct_type)) { if (n_args != 1) { - mp_raise_TypeError(NULL); + return mp_raise_TypeError_o(NULL); } // Extract structure definition mp_obj_uctypes_struct_t *obj = MP_OBJ_TO_PTR(obj_in); @@ -292,6 +295,9 @@ STATIC mp_obj_t uctypes_struct_sizeof(size_t n_args, const mp_obj_t *args) { } } mp_uint_t size = uctypes_struct_size(obj_in, layout_type, &max_field_size); + if (size == (mp_uint_t)-1) { + return MP_OBJ_NULL; + } return MP_OBJ_NEW_SMALL_INT(size); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uctypes_struct_sizeof_obj, 1, 2, uctypes_struct_sizeof); @@ -411,7 +417,7 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set && !mp_obj_is_type(self->desc, &mp_type_ordereddict) #endif ) { - mp_raise_TypeError("struct: no fields"); + return mp_raise_TypeError_o("struct: no fields"); } mp_obj_t deref = mp_obj_dict_get(self->desc, MP_OBJ_NEW_QSTR(attr)); @@ -477,12 +483,12 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set } if (!mp_obj_is_type(deref, &mp_type_tuple)) { - syntax_error(); + return syntax_error(); } if (set_val != MP_OBJ_NULL) { // Cannot assign to aggregate - syntax_error(); + return syntax_error(); } mp_obj_tuple_t *sub = MP_OBJ_TO_PTR(deref); @@ -544,7 +550,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_ob } else { // load / store if (!mp_obj_is_type(self->desc, &mp_type_tuple)) { - mp_raise_TypeError("struct: cannot index"); + return mp_raise_TypeError_o("struct: cannot index"); } mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc); @@ -558,7 +564,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_ob uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS); arr_sz &= VALUE_MASK(VAL_TYPE_BITS); if (index >= arr_sz) { - mp_raise_msg(&mp_type_IndexError, "struct: index out of range"); + return mp_raise_msg_o(&mp_type_IndexError, "struct: index out of range"); } if (t->len == 2) { diff --git a/extmod/moduheapq.c b/extmod/moduheapq.c index 2e8010143d718..59b70909147de 100644 --- a/extmod/moduheapq.c +++ b/extmod/moduheapq.c @@ -33,7 +33,8 @@ STATIC mp_obj_list_t *uheapq_get_heap(mp_obj_t heap_in) { if (!mp_obj_is_type(heap_in, &mp_type_list)) { - mp_raise_TypeError("heap must be a list"); + mp_raise_TypeError_o("heap must be a list"); + return NULL; } return MP_OBJ_TO_PTR(heap_in); } @@ -72,6 +73,9 @@ STATIC void uheapq_heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) { STATIC mp_obj_t mod_uheapq_heappush(mp_obj_t heap_in, mp_obj_t item) { mp_obj_list_t *heap = uheapq_get_heap(heap_in); + if (heap == NULL) { + return MP_OBJ_NULL; + } mp_obj_list_append(heap_in, item); uheapq_heap_siftdown(heap, 0, heap->len - 1); return mp_const_none; @@ -80,8 +84,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_uheapq_heappush_obj, mod_uheapq_heappush); STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) { mp_obj_list_t *heap = uheapq_get_heap(heap_in); + if (heap == NULL) { + return MP_OBJ_NULL; + } if (heap->len == 0) { - mp_raise_msg(&mp_type_IndexError, "empty heap"); + return mp_raise_msg_o(&mp_type_IndexError, "empty heap"); } mp_obj_t item = heap->items[0]; heap->len -= 1; @@ -96,6 +103,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heappop_obj, mod_uheapq_heappop); STATIC mp_obj_t mod_uheapq_heapify(mp_obj_t heap_in) { mp_obj_list_t *heap = uheapq_get_heap(heap_in); + if (heap == NULL) { + return MP_OBJ_NULL; + } for (mp_uint_t i = heap->len / 2; i > 0;) { uheapq_heap_siftup(heap, --i); } diff --git a/extmod/modujson.c b/extmod/modujson.c index 15ed2f38d828b..b4ef657f18f3d 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -35,7 +35,9 @@ #if MICROPY_PY_UJSON STATIC mp_obj_t mod_ujson_dump(mp_obj_t obj, mp_obj_t stream) { - mp_get_stream_raise(stream, MP_STREAM_OP_WRITE); + if (mp_get_stream_raise(stream, MP_STREAM_OP_WRITE) == NULL) { + return MP_OBJ_NULL; + } mp_print_t print = {MP_OBJ_TO_PTR(stream), mp_stream_write_adaptor}; mp_obj_print_helper(&print, obj, PRINT_JSON); return mp_const_none; @@ -79,7 +81,9 @@ typedef struct _ujson_stream_t { STATIC byte ujson_stream_next(ujson_stream_t *s) { mp_uint_t ret = s->read(s->stream_obj, &s->cur, 1, &s->errcode); if (s->errcode != 0) { - mp_raise_OSError(s->errcode); + // TODO deal with raising exception + mp_raise_OSError_o(s->errcode); + return 0xff; } if (ret == 0) { s->cur = S_EOF; @@ -276,7 +280,7 @@ STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) { return stack_top; fail: - mp_raise_ValueError("syntax error in JSON"); + return mp_raise_ValueError_o("syntax error in JSON"); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_load_obj, mod_ujson_load); diff --git a/extmod/modurandom.c b/extmod/modurandom.c index e3c7fc7f5974c..e71f1dc941e78 100644 --- a/extmod/modurandom.c +++ b/extmod/modurandom.c @@ -75,7 +75,7 @@ STATIC uint32_t yasmarang_randbelow(uint32_t n) { STATIC mp_obj_t mod_urandom_getrandbits(mp_obj_t num_in) { int n = mp_obj_get_int(num_in); if (n > 32 || n == 0) { - mp_raise_ValueError(NULL); + return mp_raise_ValueError_o(NULL); } uint32_t mask = ~0; // Beware of C undefined behavior when shifting by >= than bit size @@ -134,7 +134,7 @@ STATIC mp_obj_t mod_urandom_randrange(size_t n_args, const mp_obj_t *args) { } error: - mp_raise_ValueError(NULL); + return mp_raise_ValueError_o(NULL); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_urandom_randrange_obj, 1, 3, mod_urandom_randrange); @@ -144,7 +144,7 @@ STATIC mp_obj_t mod_urandom_randint(mp_obj_t a_in, mp_obj_t b_in) { if (a <= b) { return mp_obj_new_int(a + yasmarang_randbelow(b - a + 1)); } else { - mp_raise_ValueError(NULL); + return mp_raise_ValueError_o(NULL); } } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_urandom_randint_obj, mod_urandom_randint); @@ -154,7 +154,7 @@ STATIC mp_obj_t mod_urandom_choice(mp_obj_t seq) { if (len > 0) { return mp_obj_subscr(seq, mp_obj_new_int(yasmarang_randbelow(len)), MP_OBJ_SENTINEL); } else { - nlr_raise(mp_obj_new_exception(&mp_type_IndexError)); + return mp_raise_o(mp_obj_new_exception(&mp_type_IndexError)); } } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_choice_obj, mod_urandom_choice); diff --git a/extmod/modure.c b/extmod/modure.c index f3a9d88f7db10..60de18faedee7 100644 --- a/extmod/modure.c +++ b/extmod/modure.c @@ -64,7 +64,7 @@ STATIC mp_obj_t match_group(mp_obj_t self_in, mp_obj_t no_in) { mp_obj_match_t *self = MP_OBJ_TO_PTR(self_in); mp_int_t no = mp_obj_get_int(no_in); if (no < 0 || no >= self->num_matches) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, no_in)); + return mp_raise_o(mp_obj_new_exception_arg1(&mp_type_IndexError, no_in)); } const char *start = self->caps[no * 2]; @@ -96,14 +96,15 @@ MP_DEFINE_CONST_FUN_OBJ_1(match_groups_obj, match_groups); #if MICROPY_PY_URE_MATCH_SPAN_START_END -STATIC void match_span_helper(size_t n_args, const mp_obj_t *args, mp_obj_t span[2]) { +STATIC int match_span_helper(size_t n_args, const mp_obj_t *args, mp_obj_t span[2]) { mp_obj_match_t *self = MP_OBJ_TO_PTR(args[0]); mp_int_t no = 0; if (n_args == 2) { no = mp_obj_get_int(args[1]); if (no < 0 || no >= self->num_matches) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, args[1])); + mp_raise_o(mp_obj_new_exception_arg1(&mp_type_IndexError, args[1])); + return 1; } } @@ -119,25 +120,33 @@ STATIC void match_span_helper(size_t n_args, const mp_obj_t *args, mp_obj_t span span[0] = mp_obj_new_int(s); span[1] = mp_obj_new_int(e); + + return 0; } STATIC mp_obj_t match_span(size_t n_args, const mp_obj_t *args) { mp_obj_t span[2]; - match_span_helper(n_args, args, span); + if (match_span_helper(n_args, args, span)) { + return MP_OBJ_NULL; + } return mp_obj_new_tuple(2, span); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_span_obj, 1, 2, match_span); STATIC mp_obj_t match_start(size_t n_args, const mp_obj_t *args) { mp_obj_t span[2]; - match_span_helper(n_args, args, span); + if (match_span_helper(n_args, args, span)) { + return MP_OBJ_NULL; + } return span[0]; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_start_obj, 1, 2, match_start); STATIC mp_obj_t match_end(size_t n_args, const mp_obj_t *args) { mp_obj_t span[2]; - match_span_helper(n_args, args, span); + if (match_span_helper(n_args, args, span)) { + return MP_OBJ_NULL; + } return span[1]; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_end_obj, 1, 2, match_end); @@ -185,6 +194,10 @@ STATIC mp_obj_t ure_exec(bool is_anchored, uint n_args, const mp_obj_t *args) { // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char memset((char*)match->caps, 0, caps_num * sizeof(char*)); int res = re1_5_recursiveloopprog(&self->re, &subj, match->caps, caps_num, is_anchored); + if (res == -1) { + // exception + return MP_OBJ_NULL; + } if (res == 0) { m_del_var(mp_obj_match_t, char*, caps_num, match); return mp_const_none; @@ -226,6 +239,10 @@ STATIC mp_obj_t re_split(size_t n_args, const mp_obj_t *args) { // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char memset((char**)caps, 0, caps_num * sizeof(char*)); int res = re1_5_recursiveloopprog(&self->re, &subj, caps, caps_num, false); + if (res == -1) { + // exception + return MP_OBJ_NULL; + } // if we didn't have a match, or had an empty match, it's time to stop if (!res || caps[0] == caps[1]) { @@ -235,7 +252,7 @@ STATIC mp_obj_t re_split(size_t n_args, const mp_obj_t *args) { mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte*)subj.begin, caps[0] - subj.begin); mp_obj_list_append(retval, s); if (self->re.sub > 0) { - mp_raise_NotImplementedError("Splitting with sub-captures"); + return mp_raise_NotImplementedError_o("Splitting with sub-captures"); } subj.begin = caps[1]; if (maxsplit > 0 && --maxsplit == 0) { @@ -281,6 +298,10 @@ STATIC mp_obj_t re_sub_helper(mp_obj_t self_in, size_t n_args, const mp_obj_t *a // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char memset((char*)match->caps, 0, caps_num * sizeof(char*)); int res = re1_5_recursiveloopprog(&self->re, &subj, match->caps, caps_num, false); + if (res == -1) { + // exception + return MP_OBJ_NULL; + } // If we didn't have a match, or had an empty match, it's time to stop if (!res || match->caps[0] == match->caps[1]) { @@ -320,7 +341,7 @@ STATIC mp_obj_t re_sub_helper(mp_obj_t self_in, size_t n_args, const mp_obj_t *a } if (match_no >= (unsigned int)match->num_matches) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, MP_OBJ_NEW_SMALL_INT(match_no))); + return mp_raise_o(mp_obj_new_exception_arg1(&mp_type_IndexError, MP_OBJ_NEW_SMALL_INT(match_no))); } const char *start_match = match->caps[match_no * 2]; @@ -403,7 +424,7 @@ STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) { int error = re1_5_compilecode(&o->re, re_str); if (error != 0) { error: - mp_raise_ValueError("Error in regex"); + return mp_raise_ValueError_o("Error in regex"); } #if MICROPY_PY_URE_DEBUG if (flags & FLAG_DEBUG) { diff --git a/extmod/modussl_axtls.c b/extmod/modussl_axtls.c index 2ea175728728f..751449a992465 100644 --- a/extmod/modussl_axtls.c +++ b/extmod/modussl_axtls.c @@ -54,7 +54,7 @@ struct ssl_args { STATIC const mp_obj_type_t ussl_socket_type; -STATIC mp_obj_ssl_socket_t *ussl_socket_new(mp_obj_t sock, struct ssl_args *args) { +STATIC mp_obj_t ussl_socket_new(mp_obj_t sock, struct ssl_args *args) { #if MICROPY_PY_USSL_FINALISER mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t); #else @@ -74,7 +74,7 @@ STATIC mp_obj_ssl_socket_t *ussl_socket_new(mp_obj_t sock, struct ssl_args *args options |= SSL_NO_DEFAULT_KEY; } if ((o->ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS)) == NULL) { - mp_raise_OSError(MP_EINVAL); + return mp_raise_OSError_o(MP_EINVAL); } if (args->key.u_obj != mp_const_none) { @@ -82,13 +82,16 @@ STATIC mp_obj_ssl_socket_t *ussl_socket_new(mp_obj_t sock, struct ssl_args *args const byte *data = (const byte*)mp_obj_str_get_data(args->key.u_obj, &len); int res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_RSA_KEY, data, len, NULL); if (res != SSL_OK) { - mp_raise_ValueError("invalid key"); + return mp_raise_ValueError_o("invalid key"); } data = (const byte*)mp_obj_str_get_data(args->cert.u_obj, &len); + if (data == NULL) { + return MP_OBJ_NULL; + } res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_X509_CERT, data, len, NULL); if (res != SSL_OK) { - mp_raise_ValueError("invalid cert"); + return mp_raise_ValueError_o("invalid cert"); } } @@ -109,13 +112,13 @@ STATIC mp_obj_ssl_socket_t *ussl_socket_new(mp_obj_t sock, struct ssl_args *args if (res != SSL_OK) { printf("ssl_handshake_status: %d\n", res); ssl_display_error(res); - mp_raise_OSError(MP_EIO); + return mp_raise_OSError_o(MP_EIO); } } } - return o; + return MP_OBJ_FROM_PTR(o); } STATIC void ussl_socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { @@ -260,7 +263,7 @@ STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); - return MP_OBJ_FROM_PTR(ussl_socket_new(sock, &args)); + return ussl_socket_new(sock, &args); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket); diff --git a/extmod/modutimeq.c b/extmod/modutimeq.c index 0183a0f4b45e5..7063e266ad5ed 100644 --- a/extmod/modutimeq.c +++ b/extmod/modutimeq.c @@ -126,7 +126,7 @@ STATIC mp_obj_t mod_utimeq_heappush(size_t n_args, const mp_obj_t *args) { mp_obj_t heap_in = args[0]; mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in); if (heap->len == heap->alloc) { - mp_raise_msg(&mp_type_IndexError, "queue overflow"); + return mp_raise_msg_o(&mp_type_IndexError, "queue overflow"); } mp_uint_t l = heap->len; heap->items[l].time = MP_OBJ_SMALL_INT_VALUE(args[1]); @@ -142,11 +142,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_utimeq_heappush_obj, 4, 4, mod_ut STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) { mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in); if (heap->len == 0) { - mp_raise_msg(&mp_type_IndexError, "empty heap"); + return mp_raise_msg_o(&mp_type_IndexError, "empty heap"); } mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref); if (!mp_obj_is_type(list_ref, &mp_type_list) || ret->len < 3) { - mp_raise_TypeError(NULL); + return mp_raise_TypeError_o(NULL); } struct qentry *item = &heap->items[0]; @@ -167,7 +167,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_utimeq_heappop_obj, mod_utimeq_heappop); STATIC mp_obj_t mod_utimeq_peektime(mp_obj_t heap_in) { mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in); if (heap->len == 0) { - mp_raise_msg(&mp_type_IndexError, "empty heap"); + return mp_raise_msg_o(&mp_type_IndexError, "empty heap"); } struct qentry *item = &heap->items[0]; diff --git a/extmod/moduzlib.c b/extmod/moduzlib.c index 64327f1f7cd93..af14aa4471dfa 100644 --- a/extmod/moduzlib.c +++ b/extmod/moduzlib.c @@ -58,10 +58,14 @@ STATIC int read_src_stream(TINF_DATA *data) { byte c; mp_uint_t out_sz = stream->read(self->src_stream, &c, 1, &err); if (out_sz == MP_STREAM_ERROR) { - mp_raise_OSError(err); + // TODO deal with raising exception + mp_raise_OSError_o(err); + return -1; } if (out_sz == 0) { - nlr_raise(mp_obj_new_exception(&mp_type_EOFError)); + // TODO deal with raising exception + mp_raise_o(mp_obj_new_exception(&mp_type_EOFError)); + return -1; } return c; } @@ -92,7 +96,7 @@ STATIC mp_obj_t decompio_make_new(const mp_obj_type_t *type, size_t n_args, size dict_opt = uzlib_zlib_parse_header(&o->decomp); if (dict_opt < 0) { header_error: - mp_raise_ValueError("compression header"); + return mp_raise_ValueError_o("compression header"); } dict_sz = 1 << dict_opt; } else { @@ -201,7 +205,7 @@ STATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) { return res; error: - nlr_raise(mp_obj_new_exception_arg1(&mp_type_ValueError, MP_OBJ_NEW_SMALL_INT(st))); + return mp_raise_o(mp_obj_new_exception_arg1(&mp_type_ValueError, MP_OBJ_NEW_SMALL_INT(st))); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_uzlib_decompress_obj, 1, 3, mod_uzlib_decompress); diff --git a/extmod/re1.5/recursiveloop.c b/extmod/re1.5/recursiveloop.c index bb337decfbc95..da4141cd1aaf1 100644 --- a/extmod/re1.5/recursiveloop.c +++ b/extmod/re1.5/recursiveloop.c @@ -9,8 +9,9 @@ recursiveloop(char *pc, const char *sp, Subject *input, const char **subp, int n { const char *old; int off; + int ret; - re1_5_stack_chk(); + if (re1_5_stack_chk()) return -1; for(;;) { if(inst_is_consumer(*pc)) { @@ -46,14 +47,14 @@ recursiveloop(char *pc, const char *sp, Subject *input, const char **subp, int n continue; case Split: off = (signed char)*pc++; - if(recursiveloop(pc, sp, input, subp, nsubp)) - return 1; + if((ret = recursiveloop(pc, sp, input, subp, nsubp))) + return ret; pc = pc + off; continue; case RSplit: off = (signed char)*pc++; - if(recursiveloop(pc + off, sp, input, subp, nsubp)) - return 1; + if((ret = recursiveloop(pc + off, sp, input, subp, nsubp))) + return ret; continue; case Save: off = (unsigned char)*pc++; @@ -62,8 +63,8 @@ recursiveloop(char *pc, const char *sp, Subject *input, const char **subp, int n } old = subp[off]; subp[off] = sp; - if(recursiveloop(pc, sp, input, subp, nsubp)) - return 1; + if((ret = recursiveloop(pc, sp, input, subp, nsubp))) + return ret; subp[off] = old; return 0; case Bol: diff --git a/extmod/vfs.c b/extmod/vfs.c index 5f5fc633d8c5a..9f2c0e5835847 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -112,11 +112,11 @@ STATIC mp_obj_t mp_vfs_proxy_call(mp_vfs_mount_t *vfs, qstr meth_name, size_t n_ assert(n_args <= PROXY_MAX_ARGS); if (vfs == MP_VFS_NONE) { // mount point not found - mp_raise_OSError(MP_ENODEV); + return mp_raise_OSError_o(MP_ENODEV); } if (vfs == MP_VFS_ROOT) { // can't do operation on root dir - mp_raise_OSError(MP_EPERM); + return mp_raise_OSError_o(MP_EPERM); } mp_obj_t meth[2 + PROXY_MAX_ARGS]; mp_load_method(vfs->obj, meth_name, meth); @@ -141,13 +141,10 @@ mp_import_stat_t mp_vfs_import_stat(const char *path) { // delegate to vfs.stat() method mp_obj_t path_o = mp_obj_new_str(path_out, strlen(path_out)); - mp_obj_t stat; - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - stat = mp_vfs_proxy_call(vfs, MP_QSTR_stat, 1, &path_o); - nlr_pop(); - } else { + mp_obj_t stat = mp_vfs_proxy_call(vfs, MP_QSTR_stat, 1, &path_o); + if (stat == MP_OBJ_NULL) { // assume an exception means that the path is not found + MP_STATE_THREAD(active_exception) = NULL; return MP_IMPORT_STAT_NO_EXIST; } mp_obj_t *items; @@ -241,7 +238,7 @@ mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args // if root dir is mounted, still allow to mount something within a subdir of root } else { // mount point in use - mp_raise_OSError(MP_EPERM); + return mp_raise_OSError_o(MP_EPERM); } } @@ -278,7 +275,7 @@ mp_obj_t mp_vfs_umount(mp_obj_t mnt_in) { } if (vfs == NULL) { - mp_raise_OSError(MP_EINVAL); + return mp_raise_OSError_o(MP_EINVAL); } // if we unmounted the current device then set current to root @@ -444,7 +441,7 @@ mp_obj_t mp_vfs_mkdir(mp_obj_t path_in) { mp_obj_t path_out; mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out); if (vfs == MP_VFS_ROOT || (vfs != MP_VFS_NONE && !strcmp(mp_obj_str_get_str(path_out), "/"))) { - mp_raise_OSError(MP_EEXIST); + return mp_raise_OSError_o(MP_EEXIST); } return mp_vfs_proxy_call(vfs, MP_QSTR_mkdir, 1, &path_out); } @@ -463,7 +460,7 @@ mp_obj_t mp_vfs_rename(mp_obj_t old_path_in, mp_obj_t new_path_in) { mp_vfs_mount_t *new_vfs = lookup_path(new_path_in, &args[1]); if (old_vfs != new_vfs) { // can't rename across filesystems - mp_raise_OSError(MP_EPERM); + return mp_raise_OSError_o(MP_EPERM); } return mp_vfs_proxy_call(old_vfs, MP_QSTR_rename, 2, args); } diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index f8cb1f5a52a32..756e5637bad5e 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -81,7 +81,7 @@ STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_ // don't error out if no filesystem, to let mkfs()/mount() create one if wanted vfs->blockdev.flags |= MP_BLOCKDEV_FLAG_NO_FILESYSTEM; } else if (res != FR_OK) { - mp_raise_OSError(fresult_to_errno_table[res]); + return mp_raise_OSError_o(fresult_to_errno_table[res]); } return MP_OBJ_FROM_PTR(vfs); @@ -108,7 +108,7 @@ STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) { res = f_mkfs(&vfs->fatfs, FM_FAT32, 0, working_buf, sizeof(working_buf)); } if (res != FR_OK) { - mp_raise_OSError(fresult_to_errno_table[res]); + return mp_raise_OSError_o(fresult_to_errno_table[res]); } return mp_const_none; @@ -183,7 +183,7 @@ STATIC mp_obj_t fat_vfs_ilistdir_func(size_t n_args, const mp_obj_t *args) { iter->is_str = is_str_type; FRESULT res = f_opendir(&self->fatfs, &iter->dir, path); if (res != FR_OK) { - mp_raise_OSError(fresult_to_errno_table[res]); + return mp_raise_OSError_o(fresult_to_errno_table[res]); } return MP_OBJ_FROM_PTR(iter); @@ -198,7 +198,7 @@ STATIC mp_obj_t fat_vfs_remove_internal(mp_obj_t vfs_in, mp_obj_t path_in, mp_in FRESULT res = f_stat(&self->fatfs, path, &fno); if (res != FR_OK) { - mp_raise_OSError(fresult_to_errno_table[res]); + return mp_raise_OSError_o(fresult_to_errno_table[res]); } // check if path is a file or directory @@ -206,11 +206,11 @@ STATIC mp_obj_t fat_vfs_remove_internal(mp_obj_t vfs_in, mp_obj_t path_in, mp_in res = f_unlink(&self->fatfs, path); if (res != FR_OK) { - mp_raise_OSError(fresult_to_errno_table[res]); + return mp_raise_OSError_o(fresult_to_errno_table[res]); } return mp_const_none; } else { - mp_raise_OSError(attr ? MP_ENOTDIR : MP_EISDIR); + return mp_raise_OSError_o(attr ? MP_ENOTDIR : MP_EISDIR); } } @@ -238,7 +238,7 @@ STATIC mp_obj_t fat_vfs_rename(mp_obj_t vfs_in, mp_obj_t path_in, mp_obj_t path_ if (res == FR_OK) { return mp_const_none; } else { - mp_raise_OSError(fresult_to_errno_table[res]); + return mp_raise_OSError_o(fresult_to_errno_table[res]); } } @@ -251,7 +251,7 @@ STATIC mp_obj_t fat_vfs_mkdir(mp_obj_t vfs_in, mp_obj_t path_o) { if (res == FR_OK) { return mp_const_none; } else { - mp_raise_OSError(fresult_to_errno_table[res]); + return mp_raise_OSError_o(fresult_to_errno_table[res]); } } STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_mkdir_obj, fat_vfs_mkdir); @@ -265,7 +265,7 @@ STATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) { FRESULT res = f_chdir(&self->fatfs, path); if (res != FR_OK) { - mp_raise_OSError(fresult_to_errno_table[res]); + return mp_raise_OSError_o(fresult_to_errno_table[res]); } return mp_const_none; @@ -278,7 +278,7 @@ STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) { char buf[MICROPY_ALLOC_PATH_MAX + 1]; FRESULT res = f_getcwd(&self->fatfs, buf, sizeof(buf)); if (res != FR_OK) { - mp_raise_OSError(fresult_to_errno_table[res]); + return mp_raise_OSError_o(fresult_to_errno_table[res]); } return mp_obj_new_str(buf, strlen(buf)); } @@ -300,7 +300,7 @@ STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) { } else { FRESULT res = f_stat(&self->fatfs, path, &fno); if (res != FR_OK) { - mp_raise_OSError(fresult_to_errno_table[res]); + return mp_raise_OSError_o(fresult_to_errno_table[res]); } } @@ -343,7 +343,7 @@ STATIC mp_obj_t fat_vfs_statvfs(mp_obj_t vfs_in, mp_obj_t path_in) { FATFS *fatfs = &self->fatfs; FRESULT res = f_getfree(fatfs, &nclst); if (FR_OK != res) { - mp_raise_OSError(fresult_to_errno_table[res]); + return mp_raise_OSError_o(fresult_to_errno_table[res]); } mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); @@ -381,7 +381,7 @@ STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs res = f_mkfs(&self->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf)); } if (res != FR_OK) { - mp_raise_OSError(fresult_to_errno_table[res]); + return mp_raise_OSError_o(fresult_to_errno_table[res]); } self->blockdev.flags &= ~MP_BLOCKDEV_FLAG_NO_FILESYSTEM; diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index fb1e582f27f9c..2763ee8ddab8d 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -193,6 +193,9 @@ STATIC mp_obj_t file_open(fs_user_mount_t *vfs, const mp_obj_type_t *type, mp_ar } pyb_file_obj_t *o = m_new_obj_with_finaliser(pyb_file_obj_t); + if (o == NULL) { + return MP_OBJ_NULL; + } o->base.type = type; const char *fname = mp_obj_str_get_str(args[0].u_obj); @@ -200,7 +203,7 @@ STATIC mp_obj_t file_open(fs_user_mount_t *vfs, const mp_obj_type_t *type, mp_ar FRESULT res = f_open(&vfs->fatfs, &o->fp, fname, mode); if (res != FR_OK) { m_del_obj(pyb_file_obj_t, o); - mp_raise_OSError(fresult_to_errno_table[res]); + return mp_raise_OSError_o(fresult_to_errno_table[res]); } // for 'a' mode, we must begin at the end of the file diff --git a/extmod/vfs_lfsx.c b/extmod/vfs_lfsx.c index 4f5ad5fdf7b46..878a88608e65c 100644 --- a/extmod/vfs_lfsx.c +++ b/extmod/vfs_lfsx.c @@ -123,7 +123,7 @@ STATIC mp_obj_t MP_VFS_LFSx(make_new)(const mp_obj_type_t *type, size_t n_args, args[LFS_MAKE_ARG_readsize].u_int, args[LFS_MAKE_ARG_progsize].u_int, args[LFS_MAKE_ARG_lookahead].u_int); int ret = LFSx_API(mount)(&self->lfs, &self->config); if (ret < 0) { - mp_raise_OSError(-ret); + return mp_raise_OSError_o(-ret); } return MP_OBJ_FROM_PTR(self); } @@ -137,7 +137,7 @@ STATIC mp_obj_t MP_VFS_LFSx(mkfs)(size_t n_args, const mp_obj_t *pos_args, mp_ma args[LFS_MAKE_ARG_readsize].u_int, args[LFS_MAKE_ARG_progsize].u_int, args[LFS_MAKE_ARG_lookahead].u_int); int ret = LFSx_API(format)(&self.lfs, &self.config); if (ret < 0) { - mp_raise_OSError(-ret); + return mp_raise_OSError_o(-ret); } return mp_const_none; } @@ -205,7 +205,7 @@ STATIC mp_obj_t MP_VFS_LFSx(ilistdir_func)(size_t n_args, const mp_obj_t *args) iter->vfs = self; int ret = LFSx_API(dir_open)(&self->lfs, &iter->dir, path); if (ret < 0) { - mp_raise_OSError(-ret); + return mp_raise_OSError_o(-ret); } return MP_OBJ_FROM_PTR(iter); } @@ -216,7 +216,7 @@ STATIC mp_obj_t MP_VFS_LFSx(remove)(mp_obj_t self_in, mp_obj_t path_in) { const char *path = MP_VFS_LFSx(make_path)(self, path_in); int ret = LFSx_API(remove)(&self->lfs, path); if (ret < 0) { - mp_raise_OSError(-ret); + return mp_raise_OSError_o(-ret); } return mp_const_none; } @@ -227,7 +227,7 @@ STATIC mp_obj_t MP_VFS_LFSx(rmdir)(mp_obj_t self_in, mp_obj_t path_in) { const char *path = MP_VFS_LFSx(make_path)(self, path_in); int ret = LFSx_API(remove)(&self->lfs, path); if (ret < 0) { - mp_raise_OSError(-ret); + return mp_raise_OSError_o(-ret); } return mp_const_none; } @@ -243,7 +243,7 @@ STATIC mp_obj_t MP_VFS_LFSx(rename)(mp_obj_t self_in, mp_obj_t path_old_in, mp_o int ret = LFSx_API(rename)(&self->lfs, path_old, vstr_null_terminated_str(&path_new)); vstr_clear(&path_new); if (ret < 0) { - mp_raise_OSError(-ret); + return mp_raise_OSError_o(-ret); } return mp_const_none; } @@ -254,7 +254,7 @@ STATIC mp_obj_t MP_VFS_LFSx(mkdir)(mp_obj_t self_in, mp_obj_t path_o) { const char *path = MP_VFS_LFSx(make_path)(self, path_o); int ret = LFSx_API(mkdir)(&self->lfs, path); if (ret < 0) { - mp_raise_OSError(-ret); + return mp_raise_OSError_o(-ret); } return mp_const_none; } @@ -270,7 +270,7 @@ STATIC mp_obj_t MP_VFS_LFSx(chdir)(mp_obj_t self_in, mp_obj_t path_in) { struct LFSx_API(info) info; int ret = LFSx_API(stat)(&self->lfs, path, &info); if (ret < 0 || info.type != LFSx_MACRO(_TYPE_DIR)) { - mp_raise_OSError(-MP_ENOENT); + return mp_raise_OSError_o(-MP_ENOENT); } } @@ -308,7 +308,7 @@ STATIC mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) { struct LFSx_API(info) info; int ret = LFSx_API(stat)(&self->lfs, path, &info); if (ret < 0) { - mp_raise_OSError(-ret); + return mp_raise_OSError_o(-ret); } mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); @@ -344,7 +344,7 @@ STATIC mp_obj_t MP_VFS_LFSx(statvfs)(mp_obj_t self_in, mp_obj_t path_in) { int ret = LFSx_API(fs_traverse)(&self->lfs, LFSx_API(traverse_cb), &n_used_blocks); #endif if (ret < 0) { - mp_raise_OSError(-ret); + return mp_raise_OSError_o(-ret); } mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); diff --git a/extmod/vfs_lfsx_file.c b/extmod/vfs_lfsx_file.c index 113c3ec990c86..2274d7630a8d5 100644 --- a/extmod/vfs_lfsx_file.c +++ b/extmod/vfs_lfsx_file.c @@ -105,7 +105,7 @@ mp_obj_t MP_VFS_LFSx(file_open)(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mod int ret = LFSx_API(file_opencfg)(&self->lfs, &o->file, path, flags, &o->cfg); if (ret < 0) { o->vfs = NULL; - mp_raise_OSError(-ret); + return mp_raise_OSError_o(-ret); } return MP_OBJ_FROM_PTR(o); diff --git a/extmod/vfs_posix.c b/extmod/vfs_posix.c index d943e0c80371d..331e59ca6d135 100644 --- a/extmod/vfs_posix.c +++ b/extmod/vfs_posix.c @@ -67,7 +67,7 @@ STATIC mp_obj_t vfs_posix_fun1_helper(mp_obj_t self_in, mp_obj_t path_in, int (* mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); int ret = f(vfs_posix_get_path_str(self, path_in)); if (ret != 0) { - mp_raise_OSError(errno); + return mp_raise_OSError_o(errno); } return mp_const_none; } @@ -112,7 +112,7 @@ STATIC mp_obj_t vfs_posix_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mk self->readonly = true; } if (mp_obj_is_true(mkfs)) { - mp_raise_OSError(MP_EPERM); + return mp_raise_OSError_o(MP_EPERM); } return mp_const_none; } @@ -129,7 +129,7 @@ STATIC mp_obj_t vfs_posix_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode const char *mode = mp_obj_str_get_str(mode_in); if (self->readonly && (strchr(mode, 'w') != NULL || strchr(mode, 'a') != NULL || strchr(mode, '+') != NULL)) { - mp_raise_OSError(MP_EROFS); + return mp_raise_OSError_o(MP_EROFS); } if (!mp_obj_is_small_int(path_in)) { path_in = vfs_posix_get_path_obj(self, path_in); @@ -148,7 +148,7 @@ STATIC mp_obj_t vfs_posix_getcwd(mp_obj_t self_in) { char buf[MICROPY_ALLOC_PATH_MAX + 1]; const char *ret = getcwd(buf, sizeof(buf)); if (ret == NULL) { - mp_raise_OSError(errno); + return mp_raise_OSError_o(errno); } ret += self->root_len; return mp_obj_new_str(ret, strlen(ret)); @@ -231,7 +231,7 @@ STATIC mp_obj_t vfs_posix_ilistdir(mp_obj_t self_in, mp_obj_t path_in) { } iter->dir = opendir(path); if (iter->dir == NULL) { - mp_raise_OSError(errno); + return mp_raise_OSError_o(errno); } return MP_OBJ_FROM_PTR(iter); } @@ -247,7 +247,7 @@ STATIC mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) { mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); int ret = mkdir(vfs_posix_get_path_str(self, path_in), 0777); if (ret != 0) { - mp_raise_OSError(errno); + return mp_raise_OSError_o(errno); } return mp_const_none; } @@ -264,7 +264,7 @@ STATIC mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_ const char *new_path = vfs_posix_get_path_str(self, new_path_in); int ret = rename(old_path, new_path); if (ret != 0) { - mp_raise_OSError(errno); + return mp_raise_OSError_o(errno); } return mp_const_none; } @@ -280,7 +280,7 @@ STATIC mp_obj_t vfs_posix_stat(mp_obj_t self_in, mp_obj_t path_in) { struct stat sb; int ret = stat(vfs_posix_get_path_str(self, path_in), &sb); if (ret != 0) { - mp_raise_OSError(errno); + return mp_raise_OSError_o(errno); } mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.st_mode); @@ -323,7 +323,7 @@ STATIC mp_obj_t vfs_posix_statvfs(mp_obj_t self_in, mp_obj_t path_in) { const char *path = vfs_posix_get_path_str(self, path_in); int ret = STATVFS(path, &sb); if (ret != 0) { - mp_raise_OSError(errno); + return mp_raise_OSError_o(errno); } mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.f_bsize); diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c index 30fde818ebc93..943a01c4608bc 100644 --- a/extmod/vfs_posix_file.c +++ b/extmod/vfs_posix_file.c @@ -42,13 +42,15 @@ typedef struct _mp_obj_vfs_posix_file_t { } mp_obj_vfs_posix_file_t; #ifdef MICROPY_CPYTHON_COMPAT -STATIC void check_fd_is_open(const mp_obj_vfs_posix_file_t *o) { +STATIC int check_fd_is_open(const mp_obj_vfs_posix_file_t *o) { if (o->fd < 0) { - mp_raise_msg(&mp_type_ValueError, "I/O operation on closed file"); + mp_raise_msg_o(&mp_type_ValueError, "I/O operation on closed file"); + return 1; } + return 0; } #else -#define check_fd_is_open(o) +#define check_fd_is_open(o) 0 #endif STATIC void vfs_posix_file_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { @@ -102,7 +104,7 @@ mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_ const char *fname = mp_obj_str_get_str(fid); int fd = open(fname, mode_x | mode_rw, 0644); if (fd == -1) { - mp_raise_OSError(errno); + return mp_raise_OSError_o(errno); } o->fd = fd; return MP_OBJ_FROM_PTR(o); @@ -121,7 +123,9 @@ STATIC mp_obj_t vfs_posix_file_make_new(const mp_obj_type_t *type, size_t n_args STATIC mp_obj_t vfs_posix_file_fileno(mp_obj_t self_in) { mp_obj_vfs_posix_file_t *self = MP_OBJ_TO_PTR(self_in); - check_fd_is_open(self); + if (check_fd_is_open(self)) { + return MP_OBJ_NULL; + } return MP_OBJ_NEW_SMALL_INT(self->fd); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_file_fileno_obj, vfs_posix_file_fileno); @@ -134,7 +138,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(vfs_posix_file___exit___obj, 4, 4, vf STATIC mp_uint_t vfs_posix_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); - check_fd_is_open(o); + if (check_fd_is_open(o)) { + return MP_STREAM_ERROR; + } mp_int_t r = read(o->fd, buf, size); if (r == -1) { *errcode = errno; @@ -145,7 +151,9 @@ STATIC mp_uint_t vfs_posix_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, i STATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); - check_fd_is_open(o); + if (check_fd_is_open(o)) { + return MP_STREAM_ERROR; + } #if MICROPY_PY_OS_DUPTERM if (o->fd <= STDERR_FILENO) { mp_hal_stdout_tx_strn(buf, size); @@ -157,7 +165,8 @@ STATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { mp_obj_t obj = MP_STATE_VM(mp_pending_exception); MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; - nlr_raise(obj); + mp_raise_o(obj); + return MP_STREAM_ERROR; } r = write(o->fd, buf, size); } @@ -170,7 +179,9 @@ STATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); - check_fd_is_open(o); + if (check_fd_is_open(o)) { + return MP_STREAM_ERROR; + } switch (request) { case MP_STREAM_FLUSH: if (fsync(o->fd) < 0) { diff --git a/lib/upytesthelper/upytesthelper.c b/lib/upytesthelper/upytesthelper.c index 326172be658c0..e72ef825b01d4 100644 --- a/lib/upytesthelper/upytesthelper.c +++ b/lib/upytesthelper/upytesthelper.c @@ -96,16 +96,15 @@ void upytest_execute_test(const char *src) { mp_obj_list_init(mp_sys_path, 0); mp_obj_list_init(mp_sys_argv, 0); - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); - qstr source_name = lex->source_name; - mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); - mp_obj_t module_fun = mp_compile(&parse_tree, source_name, false); + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); + qstr source_name = lex->source_name; + mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, false); + if (module_fun != MP_OBJ_NULL) { mp_call_function_0(module_fun); - nlr_pop(); - } else { - mp_obj_t exc = (mp_obj_t)nlr.ret_val; + } + if (MP_STATE_THREAD(active_exception) != NULL) { + mp_obj_t exc = MP_OBJ_FROM_PTR(MP_STATE_THREAD(active_exception)); if (mp_obj_is_subclass_fast(mp_obj_get_type(exc), &mp_type_SystemExit)) { // Assume that sys.exit() is called to skip the test. // TODO: That can be always true, we should set up convention to diff --git a/ports/esp8266/boards/GENERIC_512K/mpconfigboard.mk b/ports/esp8266/boards/GENERIC_512K/mpconfigboard.mk index 32fd4e0077a0f..2f72c8355b593 100644 --- a/ports/esp8266/boards/GENERIC_512K/mpconfigboard.mk +++ b/ports/esp8266/boards/GENERIC_512K/mpconfigboard.mk @@ -1,3 +1,4 @@ MICROPY_PY_BTREE = 0 MICROPY_VFS_FAT = 0 LD_FILES = boards/esp8266_512k.ld +FROZEN_MANIFEST = boards/manifest_minimal.py diff --git a/ports/esp8266/boards/manifest_minimal.py b/ports/esp8266/boards/manifest_minimal.py new file mode 100644 index 0000000000000..99bea919975ab --- /dev/null +++ b/ports/esp8266/boards/manifest_minimal.py @@ -0,0 +1,5 @@ +freeze('$(PORT_DIR)/modules', ( + '_boot.py', 'flashbdev.py', 'inisetup.py', 'port_diag.py', + 'webrepl.py', 'webrepl_setup.py', 'websocket_helper.py' +)) +freeze('$(MPY_DIR)/tools', ('upip.py', 'upip_utarfile.py')) diff --git a/ports/qemu-arm/main.c b/ports/qemu-arm/main.c index 41bf9457bac01..6dc8ea2f99dbb 100644 --- a/ports/qemu-arm/main.c +++ b/ports/qemu-arm/main.c @@ -13,17 +13,16 @@ #include "py/mperrno.h" void do_str(const char *src, mp_parse_input_kind_t input_kind) { - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); - qstr source_name = lex->source_name; - mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); - mp_obj_t module_fun = mp_compile(&parse_tree, source_name, true); + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); + qstr source_name = lex->source_name; + mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, true); + if (module_fun != MP_OBJ_NULL) { mp_call_function_0(module_fun); - nlr_pop(); - } else { + } + if (MP_STATE_THREAD(active_exception) != NULL) { // uncaught exception - mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(MP_STATE_THREAD(active_exception))); } } diff --git a/ports/qemu-arm/test_main.c b/ports/qemu-arm/test_main.c index 3a85d65f38c6a..f894850dede7b 100644 --- a/ports/qemu-arm/test_main.c +++ b/ports/qemu-arm/test_main.c @@ -44,7 +44,8 @@ void gc_collect(void) { } mp_lexer_t *mp_lexer_new_from_file(const char *filename) { - mp_raise_OSError(MP_ENOENT); + mp_raise_OSError_o(MP_ENOENT); + return NULL; } mp_import_stat_t mp_import_stat(const char *path) { diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 6623cb4642bc2..d6a3b9b140d0f 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -206,20 +206,15 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "%.*s\n", (int)vstr->len, vstr->buf); VSTR_FIXED(fix, 4); - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - vstr_add_str(&fix, "large"); - nlr_pop(); - } else { - mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + if (vstr_add_str(&fix, "large")) { + mp_obj_print_exception(&mp_plat_print, MP_STATE_THREAD(active_exception)); + MP_STATE_THREAD(active_exception) = NULL; } fix.len = fix.alloc; - if (nlr_push(&nlr) == 0) { - vstr_null_terminated_str(&fix); - nlr_pop(); - } else { - mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + if (vstr_null_terminated_str(&fix) == NULL) { + mp_obj_print_exception(&mp_plat_print, MP_STATE_THREAD(active_exception)); + MP_STATE_THREAD(active_exception) = NULL; } } diff --git a/ports/unix/file.c b/ports/unix/file.c index bb841da209cae..081419405a573 100644 --- a/ports/unix/file.c +++ b/ports/unix/file.c @@ -44,10 +44,12 @@ #endif #ifdef MICROPY_CPYTHON_COMPAT -STATIC void check_fd_is_open(const mp_obj_fdfile_t *o) { +STATIC int check_fd_is_open(const mp_obj_fdfile_t *o) { if (o->fd < 0) { - mp_raise_ValueError("I/O operation on closed file"); + mp_raise_ValueError_o("I/O operation on closed file"); + return 1; } + return 0; } #else #define check_fd_is_open(o) @@ -64,7 +66,9 @@ STATIC void fdfile_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kin STATIC mp_uint_t fdfile_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { mp_obj_fdfile_t *o = MP_OBJ_TO_PTR(o_in); - check_fd_is_open(o); + if (check_fd_is_open(o)) { + return MP_STREAM_ERROR; + } mp_int_t r = read(o->fd, buf, size); if (r == -1) { *errcode = errno; @@ -75,7 +79,9 @@ STATIC mp_uint_t fdfile_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc STATIC mp_uint_t fdfile_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { mp_obj_fdfile_t *o = MP_OBJ_TO_PTR(o_in); - check_fd_is_open(o); + if (check_fd_is_open(o)) { + return MP_STREAM_ERROR; + } #if MICROPY_PY_OS_DUPTERM if (o->fd <= STDERR_FILENO) { mp_hal_stdout_tx_strn(buf, size); @@ -87,7 +93,8 @@ STATIC mp_uint_t fdfile_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { mp_obj_t obj = MP_STATE_VM(mp_pending_exception); MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; - nlr_raise(obj); + mp_raise_o(obj); + return MP_STREAM_ERROR; } r = write(o->fd, buf, size); } @@ -100,7 +107,9 @@ STATIC mp_uint_t fdfile_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in STATIC mp_uint_t fdfile_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { mp_obj_fdfile_t *o = MP_OBJ_TO_PTR(o_in); - check_fd_is_open(o); + if (check_fd_is_open(o)) { + return MP_STREAM_ERROR; + } switch (request) { case MP_STREAM_SEEK: { struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)arg; @@ -140,7 +149,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fdfile___exit___obj, 4, 4, fdfile___e STATIC mp_obj_t fdfile_fileno(mp_obj_t self_in) { mp_obj_fdfile_t *self = MP_OBJ_TO_PTR(self_in); - check_fd_is_open(self); + if (check_fd_is_open(self)) { + return MP_OBJ_NULL; + } return MP_OBJ_NEW_SMALL_INT(self->fd); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_fileno_obj, fdfile_fileno); @@ -200,7 +211,7 @@ STATIC mp_obj_t fdfile_open(const mp_obj_type_t *type, mp_arg_val_t *args) { const char *fname = mp_obj_str_get_str(fid); int fd = open(fname, mode_x | mode_rw, 0644); if (fd == -1) { - mp_raise_OSError(errno); + return mp_raise_OSError_o(errno); } o->fd = fd; return MP_OBJ_FROM_PTR(o); diff --git a/ports/unix/main.c b/ports/unix/main.c index 9147feb32d9c3..e0af348237ba9 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -75,7 +75,9 @@ const mp_print_t mp_stderr_print = {NULL, stderr_print_strn}; // If exc is SystemExit, return value where FORCED_EXIT bit set, // and lower 8 bits are SystemExit value. For all other exceptions, // return 1. -STATIC int handle_uncaught_exception(mp_obj_base_t *exc) { +STATIC int handle_uncaught_exception(void) { + mp_obj_base_t *exc = MP_STATE_THREAD(active_exception); + MP_STATE_THREAD(active_exception) = NULL; // check for SystemExit if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { // None is an exit value of 0; an int is its value; anything else is 1 @@ -103,8 +105,7 @@ STATIC int handle_uncaught_exception(mp_obj_base_t *exc) { STATIC int execute_from_lexer(int source_kind, const void *source, mp_parse_input_kind_t input_kind, bool is_repl) { mp_hal_set_interrupt_char(CHAR_CTRL_C); - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { + { // create lexer based on source kind mp_lexer_t *lex; if (source_kind == LEX_SRC_STR) { @@ -119,6 +120,10 @@ STATIC int execute_from_lexer(int source_kind, const void *source, mp_parse_inpu lex = mp_lexer_new_from_fd(MP_QSTR__lt_stdin_gt_, 0, false); } + if (lex == NULL) { + return handle_uncaught_exception(); + } + qstr source_name = lex->source_name; #if MICROPY_PY___FILE__ @@ -140,25 +145,25 @@ STATIC int execute_from_lexer(int source_kind, const void *source, mp_parse_inpu mp_obj_t module_fun = mp_compile(&parse_tree, source_name, is_repl); - if (!compile_only) { + if (!compile_only && module_fun != MP_OBJ_NULL) { // execute it - mp_call_function_0(module_fun); + mp_obj_t ret = mp_call_function_0(module_fun); // check for pending exception - if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { + if (ret != MP_OBJ_NULL && MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { mp_obj_t obj = MP_STATE_VM(mp_pending_exception); MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; - nlr_raise(obj); + mp_raise_o(obj); } } - mp_hal_set_interrupt_char(-1); - nlr_pop(); - return 0; + if (MP_STATE_THREAD(active_exception) != NULL) { + // uncaught exception + mp_hal_set_interrupt_char(-1); + return handle_uncaught_exception(); + } - } else { - // uncaught exception mp_hal_set_interrupt_char(-1); - return handle_uncaught_exception(nlr.ret_val); + return 0; } } @@ -386,6 +391,13 @@ STATIC void pre_process_options(int argc, char **argv) { if (heap_size < 700) { goto invalid_arg; } + } else if (strncmp(argv[a + 1], "alloc-max=", sizeof("alloc-max=") - 1) == 0) { + char *end; + extern unsigned gc_alloc_count_max; + gc_alloc_count_max = strtol(argv[a + 1] + sizeof("alloc-max=") - 1, &end, 0); + if (*end != 0) { + goto invalid_arg; + } #endif } else { invalid_arg: @@ -455,6 +467,9 @@ MP_NOINLINE int main_(int argc, char **argv) { #endif mp_init(); + if (MP_STATE_THREAD(active_exception) != NULL) { + return handle_uncaught_exception(); + } #if MICROPY_EMIT_NATIVE // Set default emitter options @@ -495,6 +510,9 @@ MP_NOINLINE int main_(int argc, char **argv) { } } mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), path_num); + if (MP_STATE_THREAD(active_exception) != NULL) { + return handle_uncaught_exception(); + } mp_obj_t *path_items; mp_obj_list_get(mp_sys_path, &path_num, &path_items); path_items[0] = MP_OBJ_NEW_QSTR(MP_QSTR_); @@ -512,6 +530,9 @@ MP_NOINLINE int main_(int argc, char **argv) { vstr_init(&vstr, home_l + (p1 - p - 1) + 1); vstr_add_strn(&vstr, home, home_l); vstr_add_strn(&vstr, p + 1, p1 - p - 1); + if (MP_STATE_THREAD(active_exception) != NULL) { + return handle_uncaught_exception(); + } path_items[i] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } else { path_items[i] = mp_obj_new_str_via_qstr(p, p1 - p); @@ -521,6 +542,9 @@ MP_NOINLINE int main_(int argc, char **argv) { } mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0); + if (MP_STATE_THREAD(active_exception) != NULL) { + return handle_uncaught_exception(); + } #if defined(MICROPY_UNIX_COVERAGE) { @@ -583,16 +607,13 @@ MP_NOINLINE int main_(int argc, char **argv) { set_sys_argv(argv, argc, a + 1); mp_obj_t mod; - nlr_buf_t nlr; bool subpkg_tried = false; reimport: - if (nlr_push(&nlr) == 0) { - mod = mp_builtin___import__(MP_ARRAY_SIZE(import_args), import_args); - nlr_pop(); - } else { + mod = mp_builtin___import__(MP_ARRAY_SIZE(import_args), import_args); + if (mod == MP_OBJ_NULL) { // uncaught exception - return handle_uncaught_exception(nlr.ret_val) & 0xff; + return handle_uncaught_exception() & 0xff; } if (mp_obj_is_package(mod) && !subpkg_tried) { @@ -708,5 +729,5 @@ uint mp_import_stat(const char *path) { void nlr_jump_fail(void *val) { printf("FATAL: uncaught NLR %p\n", val); - exit(1); + exit(2); } diff --git a/ports/unix/modffi.c b/ports/unix/modffi.c index 75d70e202bfe9..de4f9244770a4 100644 --- a/ports/unix/modffi.c +++ b/ports/unix/modffi.c @@ -135,7 +135,8 @@ STATIC ffi_type *get_ffi_type(mp_obj_t o_in) } // TODO: Support actual libffi type objects - mp_raise_TypeError("Unknown type"); + mp_raise_TypeError_o("Unknown type"); + return NULL; } STATIC mp_obj_t return_ffi_value(ffi_arg val, char type) @@ -200,11 +201,14 @@ STATIC mp_obj_t make_func(mp_obj_t rettype_in, void *func, mp_obj_t argtypes_in) int i = 0; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { o->params[i++] = get_ffi_type(item); + if (o->params[i - 1] == NULL) { + return MP_OBJ_NULL; + } } int res = ffi_prep_cif(&o->cif, FFI_DEFAULT_ABI, nparams, char2ffi_type(*rettype), o->params); if (res != FFI_OK) { - mp_raise_ValueError("Error in ffi_prep_cif"); + return mp_raise_ValueError_o("Error in ffi_prep_cif"); } return MP_OBJ_FROM_PTR(o); @@ -217,7 +221,7 @@ STATIC mp_obj_t ffimod_func(size_t n_args, const mp_obj_t *args) { void *sym = dlsym(self->handle, symname); if (sym == NULL) { - mp_raise_OSError(MP_ENOENT); + return mp_raise_OSError_o(MP_ENOENT); } return make_func(args[1], sym, args[3]); } @@ -258,16 +262,19 @@ STATIC mp_obj_t mod_ffi_callback(mp_obj_t rettype_in, mp_obj_t func_in, mp_obj_t int i = 0; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { o->params[i++] = get_ffi_type(item); + if (o->params[i - 1] == NULL) { + return MP_OBJ_NULL; + } } int res = ffi_prep_cif(&o->cif, FFI_DEFAULT_ABI, nparams, char2ffi_type(*rettype), o->params); if (res != FFI_OK) { - mp_raise_ValueError("Error in ffi_prep_cif"); + return mp_raise_ValueError_o("Error in ffi_prep_cif"); } res = ffi_prep_closure_loc(o->clo, &o->cif, call_py_func, MP_OBJ_TO_PTR(func_in), o->func); if (res != FFI_OK) { - mp_raise_ValueError("ffi_prep_closure_loc"); + return mp_raise_ValueError_o("ffi_prep_closure_loc"); } return MP_OBJ_FROM_PTR(o); @@ -281,7 +288,7 @@ STATIC mp_obj_t ffimod_var(mp_obj_t self_in, mp_obj_t vartype_in, mp_obj_t symna void *sym = dlsym(self->handle, symname); if (sym == NULL) { - mp_raise_OSError(MP_ENOENT); + return mp_raise_OSError_o(MP_ENOENT); } mp_obj_ffivar_t *o = m_new_obj(mp_obj_ffivar_t); o->base.type = &ffivar_type; @@ -298,7 +305,7 @@ STATIC mp_obj_t ffimod_addr(mp_obj_t self_in, mp_obj_t symname_in) { void *sym = dlsym(self->handle, symname); if (sym == NULL) { - mp_raise_OSError(MP_ENOENT); + return mp_raise_OSError_o(MP_ENOENT); } return mp_obj_new_int((uintptr_t)sym); } @@ -315,7 +322,7 @@ STATIC mp_obj_t ffimod_make_new(const mp_obj_type_t *type, size_t n_args, size_t void *mod = dlopen(fname, RTLD_NOW | RTLD_LOCAL); if (mod == NULL) { - mp_raise_OSError(errno); + return mp_raise_OSError_o(errno); } mp_obj_ffimod_t *o = m_new_obj(mp_obj_ffimod_t); o->base.type = type; @@ -411,7 +418,7 @@ STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const } error: - mp_raise_TypeError("Don't know how to pass object to native function"); + return mp_raise_TypeError_o("Don't know how to pass object to native function"); } STATIC const mp_obj_type_t ffifunc_type = { diff --git a/ports/unix/modmachine.c b/ports/unix/modmachine.c index 392ce492584e1..58d0e9bba7883 100644 --- a/ports/unix/modmachine.c +++ b/ports/unix/modmachine.c @@ -49,7 +49,8 @@ uintptr_t mod_machine_mem_get_addr(mp_obj_t addr_o, uint align) { uintptr_t addr = mp_obj_int_get_truncated(addr_o); if ((addr & (align - 1)) != 0) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "address %08x is not aligned to %d bytes", addr, align)); + mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "address %08x is not aligned to %d bytes", addr, align)); + return 0; } #if MICROPY_PLAT_DEV_MEM { @@ -60,7 +61,8 @@ uintptr_t mod_machine_mem_get_addr(mp_obj_t addr_o, uint align) { if (!fd) { int _fd = open("/dev/mem", O_RDWR | O_SYNC); if (_fd == -1) { - mp_raise_OSError(errno); + mp_raise_OSError_o(errno); + return 0; } fd = _fd; } diff --git a/ports/unix/modos.c b/ports/unix/modos.c index 161918d4dcec4..4dff9cbb45bd9 100644 --- a/ports/unix/modos.c +++ b/ports/unix/modos.c @@ -49,7 +49,7 @@ STATIC mp_obj_t mod_os_stat(mp_obj_t path_in) { const char *path = mp_obj_str_get_str(path_in); int res = stat(path, &sb); - RAISE_ERRNO(res, errno); + RAISE_ERRNO_O(res, errno); mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.st_mode); @@ -89,7 +89,7 @@ STATIC mp_obj_t mod_os_statvfs(mp_obj_t path_in) { const char *path = mp_obj_str_get_str(path_in); int res = STATVFS(path, &sb); - RAISE_ERRNO(res, errno); + RAISE_ERRNO_O(res, errno); mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.f_bsize); @@ -117,7 +117,7 @@ STATIC mp_obj_t mod_os_remove(mp_obj_t path_in) { // call POSIX unlink() here. int r = unlink(path); - RAISE_ERRNO(r, errno); + RAISE_ERRNO_O(r, errno); return mp_const_none; } @@ -128,7 +128,7 @@ STATIC mp_obj_t mod_os_system(mp_obj_t cmd_in) { int r = system(cmd); - RAISE_ERRNO(r, errno); + RAISE_ERRNO_O(r, errno); return MP_OBJ_NEW_SMALL_INT(r); } @@ -151,7 +151,7 @@ STATIC mp_obj_t mod_os_mkdir(mp_obj_t path_in) { #else int r = mkdir(path, 0777); #endif - RAISE_ERRNO(r, errno); + RAISE_ERRNO_O(r, errno); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_mkdir_obj, mod_os_mkdir); diff --git a/ports/unix/modtermios.c b/ports/unix/modtermios.c index 85eabf399d9f7..11cf0a82fc3c3 100644 --- a/ports/unix/modtermios.c +++ b/ports/unix/modtermios.c @@ -38,7 +38,7 @@ STATIC mp_obj_t mod_termios_tcgetattr(mp_obj_t fd_in) { int fd = mp_obj_get_int(fd_in); int res = tcgetattr(fd, &term); - RAISE_ERRNO(res, errno); + RAISE_ERRNO_O(res, errno); mp_obj_list_t *r = MP_OBJ_TO_PTR(mp_obj_new_list(7, NULL)); r->items[0] = MP_OBJ_NEW_SMALL_INT(term.c_iflag); @@ -95,12 +95,12 @@ STATIC mp_obj_t mod_termios_tcsetattr(mp_obj_t fd_in, mp_obj_t when_in, mp_obj_t } int res = cfsetispeed(&term, mp_obj_get_int(attrs->items[4])); - RAISE_ERRNO(res, errno); + RAISE_ERRNO_O(res, errno); res = cfsetospeed(&term, mp_obj_get_int(attrs->items[5])); - RAISE_ERRNO(res, errno); + RAISE_ERRNO_O(res, errno); res = tcsetattr(fd, when, &term); - RAISE_ERRNO(res, errno); + RAISE_ERRNO_O(res, errno); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_termios_tcsetattr_obj, mod_termios_tcsetattr); @@ -109,7 +109,7 @@ STATIC mp_obj_t mod_termios_setraw(mp_obj_t fd_in) { struct termios term; int fd = mp_obj_get_int(fd_in); int res = tcgetattr(fd, &term); - RAISE_ERRNO(res, errno); + RAISE_ERRNO_O(res, errno); term.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); term.c_oflag = 0; @@ -118,7 +118,7 @@ STATIC mp_obj_t mod_termios_setraw(mp_obj_t fd_in) { term.c_cc[VMIN] = 1; term.c_cc[VTIME] = 0; res = tcsetattr(fd, TCSAFLUSH, &term); - RAISE_ERRNO(res, errno); + RAISE_ERRNO_O(res, errno); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_termios_setraw_obj, mod_termios_setraw); diff --git a/ports/unix/modtime.c b/ports/unix/modtime.c index 0a463014dc0cb..9803968675bec 100644 --- a/ports/unix/modtime.c +++ b/ports/unix/modtime.c @@ -115,7 +115,7 @@ STATIC mp_obj_t mod_time_sleep(mp_obj_t arg) { break; #endif } - RAISE_ERRNO(res, errno); + RAISE_ERRNO_O(res, errno); #else // TODO: Handle EINTR MP_THREAD_GIL_EXIT(); diff --git a/ports/unix/moduselect.c b/ports/unix/moduselect.c index d9b02ddc62cef..3f45c0c4ac71d 100644 --- a/ports/unix/moduselect.c +++ b/ports/unix/moduselect.c @@ -164,7 +164,7 @@ STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmas } // obj doesn't exist in poller - mp_raise_OSError(MP_ENOENT); + return mp_raise_OSError_o(MP_ENOENT); } MP_DEFINE_CONST_FUN_OBJ_3(poll_modify_obj, poll_modify); @@ -189,7 +189,7 @@ STATIC int poll_poll_internal(size_t n_args, const mp_obj_t *args) { self->flags = flags; int n_ready = poll(self->entries, self->len, timeout); - RAISE_ERRNO(n_ready, errno); + RAISE_ERRNO_R(n_ready, errno, -1); return n_ready; } @@ -198,6 +198,10 @@ STATIC int poll_poll_internal(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t poll_poll(size_t n_args, const mp_obj_t *args) { int n_ready = poll_poll_internal(n_args, args); + if (n_ready < 0) { + return MP_OBJ_NULL; + } + if (n_ready == 0) { return mp_const_empty_tuple; } @@ -236,6 +240,10 @@ STATIC mp_obj_t poll_ipoll(size_t n_args, const mp_obj_t *args) { } int n_ready = poll_poll_internal(n_args, args); + if (n_ready < 0) { + return MP_OBJ_NULL; + } + self->iter_cnt = n_ready; self->iter_idx = 0; diff --git a/ports/unix/modusocket.c b/ports/unix/modusocket.c index 9b82378bb4b35..40dd56e38e11c 100644 --- a/ports/unix/modusocket.c +++ b/ports/unix/modusocket.c @@ -165,7 +165,7 @@ STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { // EINPROGRESS on a blocking socket means the operation timed out err = MP_ETIMEDOUT; } - RAISE_ERRNO(r, err); + RAISE_ERRNO_O(r, err); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect); @@ -175,7 +175,7 @@ STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(addr_in, &bufinfo, MP_BUFFER_READ); int r = bind(self->fd, (const struct sockaddr *)bufinfo.buf, bufinfo.len); - RAISE_ERRNO(r, errno); + RAISE_ERRNO_O(r, errno); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind); @@ -183,7 +183,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind); STATIC mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) { mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); int r = listen(self->fd, MP_OBJ_SMALL_INT_VALUE(backlog_in)); - RAISE_ERRNO(r, errno); + RAISE_ERRNO_O(r, errno); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen); @@ -200,7 +200,7 @@ STATIC mp_obj_t socket_accept(mp_obj_t self_in) { // EAGAIN on a blocking socket means the operation timed out err = MP_ETIMEDOUT; } - RAISE_ERRNO(fd, err); + RAISE_ERRNO_O(fd, err); mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); t->items[0] = MP_OBJ_FROM_PTR(socket_new(fd)); @@ -224,7 +224,7 @@ STATIC mp_obj_t socket_recv(size_t n_args, const mp_obj_t *args) { byte *buf = m_new(byte, sz); int out_sz = recv(self->fd, buf, sz, flags); - RAISE_ERRNO(out_sz, errno); + RAISE_ERRNO_O(out_sz, errno); mp_obj_t ret = mp_obj_new_str_of_type(&mp_type_bytes, buf, out_sz); m_del(char, buf, sz); @@ -246,7 +246,7 @@ STATIC mp_obj_t socket_recvfrom(size_t n_args, const mp_obj_t *args) { byte *buf = m_new(byte, sz); int out_sz = recvfrom(self->fd, buf, sz, flags, (struct sockaddr*)&addr, &addr_len); - RAISE_ERRNO(out_sz, errno); + RAISE_ERRNO_O(out_sz, errno); mp_obj_t buf_o = mp_obj_new_str_of_type(&mp_type_bytes, buf, out_sz); m_del(char, buf, sz); @@ -273,7 +273,7 @@ STATIC mp_obj_t socket_send(size_t n_args, const mp_obj_t *args) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); int out_sz = send(self->fd, bufinfo.buf, bufinfo.len, flags); - RAISE_ERRNO(out_sz, errno); + RAISE_ERRNO_O(out_sz, errno); return MP_OBJ_NEW_SMALL_INT(out_sz); } @@ -294,7 +294,7 @@ STATIC mp_obj_t socket_sendto(size_t n_args, const mp_obj_t *args) { mp_get_buffer_raise(dst_addr, &addr_bi, MP_BUFFER_READ); int out_sz = sendto(self->fd, bufinfo.buf, bufinfo.len, flags, (struct sockaddr *)addr_bi.buf, addr_bi.len); - RAISE_ERRNO(out_sz, errno); + RAISE_ERRNO_O(out_sz, errno); return MP_OBJ_NEW_SMALL_INT(out_sz); } @@ -320,7 +320,7 @@ STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { optlen = bufinfo.len; } int r = setsockopt(self->fd, level, option, optval, optlen); - RAISE_ERRNO(r, errno); + RAISE_ERRNO_O(r, errno); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt); @@ -329,14 +329,14 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); int val = mp_obj_is_true(flag_in); int flags = fcntl(self->fd, F_GETFL, 0); - RAISE_ERRNO(flags, errno); + RAISE_ERRNO_O(flags, errno); if (val) { flags &= ~O_NONBLOCK; } else { flags |= O_NONBLOCK; } flags = fcntl(self->fd, F_SETFL, flags); - RAISE_ERRNO(flags, errno); + RAISE_ERRNO_O(flags, errno); self->blocking = val; return mp_const_none; } @@ -369,9 +369,9 @@ STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) { if (new_blocking) { int r; r = setsockopt(self->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)); - RAISE_ERRNO(r, errno); + RAISE_ERRNO_O(r, errno); r = setsockopt(self->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval)); - RAISE_ERRNO(r, errno); + RAISE_ERRNO_O(r, errno); } if (self->blocking != new_blocking) { @@ -416,7 +416,7 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type_in, size_t n_args, siz } int fd = socket(family, type, proto); - RAISE_ERRNO(fd, errno); + RAISE_ERRNO_O(fd, errno); return MP_OBJ_FROM_PTR(socket_new(fd)); } @@ -465,9 +465,9 @@ STATIC mp_obj_t mod_socket_inet_pton(mp_obj_t family_in, mp_obj_t addr_in) { int family = mp_obj_get_int(family_in); byte binaddr[BINADDR_MAX_LEN]; int r = inet_pton(family, mp_obj_str_get_str(addr_in), binaddr); - RAISE_ERRNO(r, errno); + RAISE_ERRNO_O(r, errno); if (r == 0) { - mp_raise_OSError(MP_EINVAL); + return mp_raise_OSError_o(MP_EINVAL); } int binaddr_len = 0; switch (family) { @@ -489,7 +489,7 @@ STATIC mp_obj_t mod_socket_inet_ntop(mp_obj_t family_in, mp_obj_t binaddr_in) { vstr_t vstr; vstr_init_len(&vstr, family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN); if (inet_ntop(family, bufinfo.buf, vstr.buf, vstr.len) == NULL) { - mp_raise_OSError(errno); + return mp_raise_OSError_o(errno); } vstr.len = strlen(vstr.buf); return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); diff --git a/ports/unix/mphalport.h b/ports/unix/mphalport.h index e3e045aed1921..aa12e35623aef 100644 --- a/ports/unix/mphalport.h +++ b/ports/unix/mphalport.h @@ -54,6 +54,9 @@ static inline void mp_hal_delay_ms(mp_uint_t ms) { usleep((ms) * 1000); } static inline void mp_hal_delay_us(mp_uint_t us) { usleep(us); } #define mp_hal_ticks_cpu() 0 -#define RAISE_ERRNO(err_flag, error_val) \ +#define RAISE_ERRNO_O(err_flag, error_val) \ { if (err_flag == -1) \ - { mp_raise_OSError(error_val); } } + { return mp_raise_OSError_o(error_val); } } +#define RAISE_ERRNO_R(err_flag, error_val, ret_on_err) \ + { if (err_flag == -1) \ + { mp_raise_OSError_o(error_val); return ret_on_err; } } diff --git a/ports/unix/mpthreadport.c b/ports/unix/mpthreadport.c index 4fe5fa9218811..de4324675cca2 100644 --- a/ports/unix/mpthreadport.c +++ b/ports/unix/mpthreadport.c @@ -228,7 +228,8 @@ void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) { return; er: - mp_raise_OSError(ret); + mp_raise_OSError_o(ret); + // TODO how to indicate error to caller? } void mp_thread_finish(void) { diff --git a/py/argcheck.c b/py/argcheck.c index c2b1b6c079284..2adaf21a8b15e 100644 --- a/py/argcheck.c +++ b/py/argcheck.c @@ -29,7 +29,7 @@ #include "py/runtime.h" -void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) { +int mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) { // TODO maybe take the function name as an argument so we can print nicer error messages // The reverse of MP_OBJ_FUN_MAKE_SIG @@ -41,8 +41,9 @@ void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { - mp_raise_TypeError("function doesn't take keyword arguments"); + mp_raise_TypeError_o("function doesn't take keyword arguments"); } + return 1; } if (n_args_min == n_args_max) { @@ -50,33 +51,38 @@ void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", n_args_min, n_args)); } + return 1; } } else { if (n_args < n_args_min) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function missing %d required positional arguments", n_args_min - n_args)); } + return 1; } else if (n_args > n_args_max) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function expected at most %d arguments, got %d", n_args_max, n_args)); } + return 1; } } + + return 0; } -void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals) { +int mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals) { size_t pos_found = 0, kws_found = 0; for (size_t i = 0; i < n_allowed; i++) { mp_obj_t given_arg; @@ -93,9 +99,10 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%q' argument required", allowed[i].qst)); } + return 1; } out_vals[i] = allowed[i].defval; continue; @@ -119,7 +126,8 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n mp_arg_error_terse_mismatch(); } else { // TODO better error message - mp_raise_TypeError("extra positional arguments given"); + mp_raise_TypeError_o("extra positional arguments given"); + return 1; } } if (kws_found < kws->used) { @@ -127,23 +135,25 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n mp_arg_error_terse_mismatch(); } else { // TODO better error message - mp_raise_TypeError("extra keyword arguments given"); + mp_raise_TypeError_o("extra keyword arguments given"); + return 1; } } + return 0; } -void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals) { +int mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals) { mp_map_t kw_args; mp_map_init_fixed_table(&kw_args, n_kw, args + n_pos); - mp_arg_parse_all(n_pos, args, &kw_args, n_allowed, allowed, out_vals); + return mp_arg_parse_all(n_pos, args, &kw_args, n_allowed, allowed, out_vals); } -NORETURN void mp_arg_error_terse_mismatch(void) { - mp_raise_TypeError("argument num/types mismatch"); +void mp_arg_error_terse_mismatch(void) { + mp_raise_TypeError_o("argument num/types mismatch"); } #if MICROPY_CPYTHON_COMPAT -NORETURN void mp_arg_error_unimpl_kw(void) { - mp_raise_NotImplementedError("keyword argument(s) not yet implemented - use normal args instead"); +void mp_arg_error_unimpl_kw(void) { + mp_raise_NotImplementedError_o("keyword argument(s) not yet implemented - use normal args instead"); } #endif diff --git a/py/bc.c b/py/bc.c index 7dd4b2246a69a..75c576d39fecb 100644 --- a/py/bc.c +++ b/py/bc.c @@ -74,19 +74,20 @@ const byte *mp_decode_uint_skip(const byte *ptr) { #endif -STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) { +STATIC mp_obj_t fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) { #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE // generic message, used also for other argument issues (void)f; (void)expected; (void)given; mp_arg_error_terse_mismatch(); + return MP_OBJ_NULL; #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL (void)f; - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", expected, given)); #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%q() takes %d positional arguments but %d were given", mp_obj_fun_get_name(MP_OBJ_FROM_PTR(f)), expected, given)); #endif @@ -109,7 +110,7 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) { // - code_state->fun_bc should contain a pointer to the function object // - code_state->ip should contain the offset in bytes from the pointer // code_state->fun_bc->bytecode to the entry n_state (0 for bytecode, non-zero for native) -void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args) { +mp_obj_t mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args) { // This function is pretty complicated. It's main aim is to be efficient in speed and RAM // usage for the common case of positional only args. @@ -153,7 +154,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw if (n_args > n_pos_args) { // given more than enough arguments if ((scope_flags & MP_SCOPE_FLAG_VARARGS) == 0) { - fun_pos_args_mismatch(self, n_pos_args, n_args); + return fun_pos_args_mismatch(self, n_pos_args, n_args); } // put extra arguments in varargs tuple *var_pos_kw_args-- = mp_obj_new_tuple(n_args - n_pos_args, args + n_pos_args); @@ -172,7 +173,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw code_state->state[n_state - 1 - i] = self->extra_args[i - (n_pos_args - n_def_pos_args)]; } } else { - fun_pos_args_mismatch(self, n_pos_args - n_def_pos_args, n_args); + return fun_pos_args_mismatch(self, n_pos_args - n_def_pos_args, n_args); } } } @@ -203,7 +204,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw for (size_t j = 0; j < n_pos_args + n_kwonly_args; j++) { if (wanted_arg_name == arg_names[j]) { if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function got multiple values for argument '%q'", MP_OBJ_QSTR_VALUE(wanted_arg_name))); } code_state->state[n_state - 1 - j] = kwargs[2 * i + 1]; @@ -213,9 +214,9 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw // Didn't find name match with positional args if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) == 0) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("unexpected keyword argument"); + return mp_raise_TypeError_o("unexpected keyword argument"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unexpected keyword argument '%q'", MP_OBJ_QSTR_VALUE(wanted_arg_name))); } } @@ -241,7 +242,7 @@ continue2:; // Check that all mandatory positional args are specified while (d < &code_state->state[n_state]) { if (*d++ == MP_OBJ_NULL) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function missing required positional argument #%d", &code_state->state[n_state] - d)); } } @@ -257,7 +258,7 @@ continue2:; if (elem != NULL) { code_state->state[n_state - 1 - n_pos_args - i] = elem->value; } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function missing required keyword argument '%q'", MP_OBJ_QSTR_VALUE(arg_names[n_pos_args + i]))); } } @@ -266,7 +267,7 @@ continue2:; } else { // no keyword arguments given if (n_kwonly_args != 0) { - mp_raise_TypeError("function missing keyword-only argument"); + return mp_raise_TypeError_o("function missing keyword-only argument"); } if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) { *var_pos_kw_args = mp_obj_new_dict(0); @@ -298,6 +299,8 @@ continue2:; DEBUG_printf("Calling: n_pos_args=%d, n_kwonly_args=%d\n", n_pos_args, n_kwonly_args); dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args); dump_args(code_state->state, n_state); + + return MP_OBJ_SENTINEL; // success } #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE diff --git a/py/bc.h b/py/bc.h index a96d17a0db682..20f82793aaa80 100644 --- a/py/bc.h +++ b/py/bc.h @@ -225,7 +225,7 @@ const byte *mp_decode_uint_skip(const byte *ptr); mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc); mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t func, size_t n_args, size_t n_kw, const mp_obj_t *args); -void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args); +mp_obj_t mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args); void mp_bytecode_print(const void *descr, const byte *code, mp_uint_t len, const mp_uint_t *const_table); void mp_bytecode_print2(const byte *code, size_t len, const mp_uint_t *const_table); const byte *mp_bytecode_print_str(const byte *ip); diff --git a/py/binary.c b/py/binary.c index 83f28db91a007..2236a462a8586 100644 --- a/py/binary.c +++ b/py/binary.c @@ -104,7 +104,8 @@ size_t mp_binary_get_size(char struct_type, char val_type, size_t *palign) { } if (size == 0) { - mp_raise_ValueError("bad typecode"); + mp_raise_ValueError_o("bad typecode"); + return 0; } if (palign != NULL) { diff --git a/py/builtinevex.c b/py/builtinevex.c index 819e3e1c63053..a291caf34cda7 100644 --- a/py/builtinevex.c +++ b/py/builtinevex.c @@ -58,19 +58,10 @@ STATIC mp_obj_t code_execute(mp_obj_code_t *self, mp_obj_dict_t *globals, mp_obj } // execute code - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_obj_t ret = mp_call_function_0(self->module_fun); - nlr_pop(); - mp_globals_set(old_globals); - mp_locals_set(old_locals); - return ret; - } else { - // exception; restore context and re-raise same exception - mp_globals_set(old_globals); - mp_locals_set(old_locals); - nlr_jump(nlr.ret_val); - } + mp_obj_t ret = mp_call_function_0(self->module_fun); + mp_globals_set(old_globals); + mp_locals_set(old_locals); + return ret; } STATIC mp_obj_t mp_builtin_compile(size_t n_args, const mp_obj_t *args) { @@ -94,12 +85,15 @@ STATIC mp_obj_t mp_builtin_compile(size_t n_args, const mp_obj_t *args) { case MP_QSTR_exec: parse_input_kind = MP_PARSE_FILE_INPUT; break; case MP_QSTR_eval: parse_input_kind = MP_PARSE_EVAL_INPUT; break; default: - mp_raise_ValueError("bad compile mode"); + return mp_raise_ValueError_o("bad compile mode"); } mp_obj_code_t *code = m_new_obj(mp_obj_code_t); code->base.type = &mp_type_code; code->module_fun = mp_parse_compile_execute(lex, parse_input_kind, NULL, NULL); + if (code->module_fun == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } return MP_OBJ_FROM_PTR(code); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_compile_obj, 3, 6, mp_builtin_compile); @@ -115,7 +109,7 @@ STATIC mp_obj_t eval_exec_helper(size_t n_args, const mp_obj_t *args, mp_parse_i for (size_t i = 1; i < 3 && i < n_args; ++i) { if (args[i] != mp_const_none) { if (!mp_obj_is_type(args[i], &mp_type_dict)) { - mp_raise_TypeError(NULL); + return mp_raise_TypeError_o(NULL); } locals = MP_OBJ_TO_PTR(args[i]); if (i == 1) { @@ -143,6 +137,10 @@ STATIC mp_obj_t eval_exec_helper(size_t n_args, const mp_obj_t *args, mp_parse_i lex = mp_lexer_new_from_str_len(MP_QSTR__lt_string_gt_, str, str_len, 0); } + if (lex == NULL) { + return MP_OBJ_NULL; + } + return mp_parse_compile_execute(lex, parse_input_kind, globals, locals); } diff --git a/py/builtinimport.c b/py/builtinimport.c index 9d91b20599955..3cb32534c517a 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -132,7 +132,7 @@ STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *d } #if MICROPY_MODULE_FROZEN_STR || MICROPY_ENABLE_COMPILER -STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex) { +STATIC int do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex) { #if MICROPY_PY___FILE__ qstr source_name = lex->source_name; mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); @@ -140,12 +140,12 @@ STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex) { // parse, compile and execute the module in its context mp_obj_dict_t *mod_globals = mp_obj_module_get_globals(module_obj); - mp_parse_compile_execute(lex, MP_PARSE_FILE_INPUT, mod_globals, mod_globals); + return mp_parse_compile_execute(lex, MP_PARSE_FILE_INPUT, mod_globals, mod_globals) == MP_OBJ_NULL; } #endif #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_MODULE_FROZEN_MPY -STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code, const char* source_name) { +STATIC int do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code, const char* source_name) { (void)source_name; #if MICROPY_PY___FILE__ @@ -163,25 +163,18 @@ STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code, co mp_globals_set(mod_globals); mp_locals_set(mod_globals); - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_obj_t module_fun = mp_make_function_from_raw_code(raw_code, MP_OBJ_NULL, MP_OBJ_NULL); - mp_call_function_0(module_fun); + mp_obj_t module_fun = mp_make_function_from_raw_code(raw_code, MP_OBJ_NULL, MP_OBJ_NULL); + module_fun = mp_call_function_0(module_fun); - // finish nlr block, restore context - nlr_pop(); - mp_globals_set(old_globals); - mp_locals_set(old_locals); - } else { - // exception; restore context and re-raise same exception - mp_globals_set(old_globals); - mp_locals_set(old_locals); - nlr_jump(nlr.ret_val); - } + // restore context + mp_globals_set(old_globals); + mp_locals_set(old_locals); + + return module_fun == MP_OBJ_NULL; } #endif -STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { +STATIC int do_load(mp_obj_t module_obj, vstr_t *file) { #if MICROPY_MODULE_FROZEN || MICROPY_ENABLE_COMPILER || (MICROPY_PERSISTENT_CODE_LOAD && MICROPY_HAS_FILE_READER) char *file_str = vstr_null_terminated_str(file); #endif @@ -197,8 +190,7 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { // found the filename in the list of frozen files, then load and execute it. #if MICROPY_MODULE_FROZEN_STR if (frozen_type == MP_FROZEN_STR) { - do_load_from_lexer(module_obj, modref); - return; + return do_load_from_lexer(module_obj, modref); } #endif @@ -206,8 +198,7 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { // its data) in the list of frozen files, execute it. #if MICROPY_MODULE_FROZEN_MPY if (frozen_type == MP_FROZEN_MPY) { - do_execute_raw_code(module_obj, modref, file_str); - return; + return do_execute_raw_code(module_obj, modref, file_str); } #endif @@ -216,8 +207,10 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { #if MICROPY_HAS_FILE_READER && MICROPY_PERSISTENT_CODE_LOAD if (file_str[file->len - 3] == 'm') { mp_raw_code_t *raw_code = mp_raw_code_load_file(file_str); - do_execute_raw_code(module_obj, raw_code, file_str); - return; + if (raw_code == NULL) { + return 1; + } + return do_execute_raw_code(module_obj, raw_code, file_str); } #endif @@ -225,12 +218,12 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { #if MICROPY_ENABLE_COMPILER { mp_lexer_t *lex = mp_lexer_new_from_file(file_str); - do_load_from_lexer(module_obj, lex); - return; + return do_load_from_lexer(module_obj, lex); } #else // If we get here then the file was not frozen and we can't compile scripts. - mp_raise_msg(&mp_type_ImportError, "script compilation not supported"); + mp_raise_msg_o(&mp_type_ImportError, "script compilation not supported"); + return 1; #endif } @@ -263,13 +256,16 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { if (n_args >= 5) { level = MP_OBJ_SMALL_INT_VALUE(args[4]); if (level < 0) { - mp_raise_ValueError(NULL); + return mp_raise_ValueError_o(NULL); } } } size_t mod_len; const char *mod_str = mp_obj_str_get_data(module_name, &mod_len); + if (mod_str == NULL) { + return MP_OBJ_NULL; + } if (level != 0) { // What we want to do here is to take name of current module, @@ -281,11 +277,17 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { // module's position in the package hierarchy." level--; mp_obj_t this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___name__)); + if (this_name_q == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } assert(this_name_q != MP_OBJ_NULL); #if MICROPY_CPYTHON_COMPAT if (MP_OBJ_QSTR_VALUE(this_name_q) == MP_QSTR___main__) { // This is a module run by -m command-line switch, get its real name from backup attribute this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); + if (this_name_q == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } } #endif mp_map_t *globals_map = &mp_globals_get()->map; @@ -315,7 +317,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { // We must have some component left over to import from if (p == this_name) { - mp_raise_ValueError("cannot perform relative import"); + return mp_raise_ValueError_o("cannot perform relative import"); } uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len); @@ -335,7 +337,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { } if (mod_len == 0) { - mp_raise_ValueError(NULL); + return mp_raise_ValueError_o(NULL); } // check if module already exists @@ -399,9 +401,9 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { if (module_obj == MP_OBJ_NULL) { // couldn't find the file, so fail if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_ImportError, "module not found"); + return mp_raise_msg_o(&mp_type_ImportError, "module not found"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "no module named '%q'", mod_name)); } } @@ -445,11 +447,17 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { if (stat_file_py_or_mpy(&path) != MP_IMPORT_STAT_FILE) { //mp_warning("%s is imported as namespace package", vstr_str(&path)); } else { - do_load(module_obj, &path); + if (do_load(module_obj, &path)) { + // exception + return MP_OBJ_NULL; + } } path.len = orig_path_len; } else { // MP_IMPORT_STAT_FILE - do_load(module_obj, &path); + if (do_load(module_obj, &path)) { + // exception + return MP_OBJ_NULL; + } // This should be the last component in the import path. If there are // remaining components then it's an ImportError because the current path // (the module that was just loaded) is not a package. This will be caught @@ -481,11 +489,14 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { // Check that it's not a relative import if (n_args >= 5 && MP_OBJ_SMALL_INT_VALUE(args[4]) != 0) { - mp_raise_NotImplementedError("relative import"); + return mp_raise_NotImplementedError_o("relative import"); } // Check if module already exists, and return it if it does qstr module_name_qstr = mp_obj_str_get_qstr(args[0]); + if (module_name_qstr == MP_QSTR_NULL) { + return MP_OBJ_NULL; + } mp_obj_t module_obj = mp_module_get(module_name_qstr); if (module_obj != MP_OBJ_NULL) { return module_obj; @@ -503,9 +514,9 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { // Couldn't find the module, so fail if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_ImportError, "module not found"); + return mp_raise_msg_o(&mp_type_ImportError, "module not found"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "no module named '%q'", module_name_qstr)); } } diff --git a/py/compile.c b/py/compile.c index 0d36aef8b35ba..c56be798a8831 100644 --- a/py/compile.c +++ b/py/compile.c @@ -241,6 +241,9 @@ STATIC void compile_decrease_except_level(compiler_t *comp) { STATIC scope_t *scope_new_and_link(compiler_t *comp, scope_kind_t kind, mp_parse_node_t pn, uint emit_options) { scope_t *scope = scope_new(kind, pn, comp->source_file, emit_options); + if (scope == NULL) { + return NULL; + } scope->parent = comp->scope_cur; scope->next = NULL; if (comp->scope_head == NULL) { @@ -3444,6 +3447,9 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f // create standard emitter; it's used at least for MP_PASS_SCOPE emit_t *emit_bc = emit_bc_new(); + if (module_scope == NULL || emit_bc == NULL) { + return NULL; + } // compile pass 1 comp->emit = emit_bc; #if MICROPY_EMIT_NATIVE @@ -3459,6 +3465,10 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f { compile_scope(comp, s, MP_PASS_SCOPE); + if (MP_STATE_THREAD(active_exception) != NULL) { + return NULL; + } + // Check if any implicitly declared variables should be closed over for (size_t i = 0; i < s->id_info_len; ++i) { id_info_t *id = &s->id_info[i]; @@ -3481,6 +3491,9 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f // set max number of labels now that it's calculated emit_bc_set_max_num_labels(emit_bc, max_num_labels); + if (MP_STATE_THREAD(active_exception) != NULL) { + return NULL; + } // compile pass 2 and 3 #if MICROPY_EMIT_NATIVE @@ -3541,12 +3554,12 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f compile_scope(comp, s, MP_PASS_STACK_SIZE); // second last pass: compute code size - if (comp->compile_error == MP_OBJ_NULL) { + if (MP_STATE_THREAD(active_exception) == NULL && comp->compile_error == MP_OBJ_NULL) { compile_scope(comp, s, MP_PASS_CODE_SIZE); } // final pass: emit code - if (comp->compile_error == MP_OBJ_NULL) { + if (MP_STATE_THREAD(active_exception) == NULL && comp->compile_error == MP_OBJ_NULL) { compile_scope(comp, s, MP_PASS_EMIT); } } @@ -3587,14 +3600,22 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f } if (comp->compile_error != MP_OBJ_NULL) { - nlr_raise(comp->compile_error); + mp_raise_o(comp->compile_error); + return NULL; } else { return outer_raw_code; } } mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl) { + if (MP_STATE_THREAD(active_exception) != NULL) { + // parser had an exception + return MP_OBJ_NULL; + } mp_raw_code_t *rc = mp_compile_to_raw_code(parse_tree, source_file, is_repl); + if (rc == NULL) { + return MP_OBJ_NULL; + } // return function that executes the outer module return mp_make_function_from_raw_code(rc, MP_OBJ_NULL, MP_OBJ_NULL); } diff --git a/py/emitcommon.c b/py/emitcommon.c index 791bf398ab906..19da9c94252c9 100644 --- a/py/emitcommon.c +++ b/py/emitcommon.c @@ -33,6 +33,9 @@ void mp_emit_common_get_id_for_modification(scope_t *scope, qstr qst) { // name adding/lookup id_info_t *id = scope_find_or_add_id(scope, qst, ID_INFO_KIND_GLOBAL_IMPLICIT); + if (id == NULL) { + return; + } if (SCOPE_IS_FUNC_LIKE(scope->kind) && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { // rebind as a local variable id->kind = ID_INFO_KIND_LOCAL; diff --git a/py/emitglue.c b/py/emitglue.c index d30a1e6741f4e..e806a491e6eb2 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -52,6 +52,9 @@ mp_uint_t mp_verbose_flag = 0; mp_raw_code_t *mp_emit_glue_new_raw_code(void) { mp_raw_code_t *rc = m_new0(mp_raw_code_t, 1); + if (rc == NULL) { + return NULL; + } rc->kind = MP_CODE_RESERVED; #if MICROPY_PY_SYS_SETTRACE rc->line_of_definition = 0; diff --git a/py/emitnative.c b/py/emitnative.c index 07b984b780f70..8b4050abe0fdc 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -137,6 +137,9 @@ *emit->error_slot = mp_obj_new_exception_msg_varg(&mp_type_ViperTypeError, __VA_ARGS__); \ } while (0) +#define JUMP_EXC(emit) ASM_JUMP((emit)->as, (emit)->exit_label + 3); +#define CHECK_EXC(emit) ASM_JUMP_IF_REG_ZERO((emit)->as, REG_RET, (emit)->exit_label + 3, false) + typedef enum { STACK_VALUE, STACK_REG, @@ -576,6 +579,8 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop #else ASM_CALL_IND(emit->as, MP_F_SETUP_CODE_STATE); #endif + // Jump to ASM_EXIT if exception (MP_OBJ_NULL returned) + ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, *emit->label_slot + 4, false); } emit_native_global_exc_entry(emit); @@ -831,7 +836,7 @@ STATIC vtype_kind_t load_reg_stack_imm(emit_t *emit, int reg_dest, const stack_i } else if (si->vtype == VTYPE_PTR_NONE) { emit_native_mov_reg_const(emit, reg_dest, MP_F_CONST_NONE_OBJ); } else { - mp_raise_NotImplementedError("conversion to object"); + *emit->error_slot = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "conversion to object"); } return VTYPE_PYOBJ; } @@ -998,6 +1003,7 @@ STATIC void emit_call_with_qstr_arg(emit_t *emit, mp_fun_kind_t fun_kind, qstr q need_reg_all(emit); emit_native_mov_reg_qstr(emit, arg_reg, qst); ASM_CALL_IND(emit->as, fun_kind); + CHECK_EXC(emit); } // vtype of all n_pop objects is VTYPE_PYOBJ @@ -1176,19 +1182,8 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) { } if (emit->scope->exc_stack_size == 0) { - if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) { - // Optimisation: if globals didn't change don't push the nlr context - ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, start_label, false); - } - - // Wrap everything in an nlr context - ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 0); - emit_call(emit, MP_F_NLR_PUSH); - #if N_NLR_SETJMP - ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 2); - emit_call(emit, MP_F_SETJMP); - #endif - ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, start_label, true); + ASM_JUMP(emit->as, start_label); + emit_native_label_assign(emit, global_except_label); } else { // Clear the unwind state ASM_XOR_REG_REG(emit->as, REG_TEMP0, REG_TEMP0); @@ -1199,15 +1194,7 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) { // Wrap everything in an nlr context emit_native_label_assign(emit, nlr_label); - ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_2, LOCAL_IDX_EXC_HANDLER_UNWIND(emit)); - ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 0); - emit_call(emit, MP_F_NLR_PUSH); - #if N_NLR_SETJMP - ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 2); - emit_call(emit, MP_F_SETJMP); - #endif - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_LOCAL_2); - ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, global_except_label, true); + emit_call(emit, MP_F_NATIVE_CLR_EXC); // clear active_exception because we are handling it (may need to re-raise it later) // Clear PC of current code block, and jump there to resume execution ASM_XOR_REG_REG(emit->as, REG_TEMP0, REG_TEMP0); @@ -1216,22 +1203,12 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) { // Global exception handler: check for valid exception handler emit_native_label_assign(emit, global_except_label); - #if N_NLR_SETJMP - // Reload REG_FUN_TABLE, since it may be clobbered by longjmp - emit_native_mov_reg_state(emit, REG_LOCAL_1, LOCAL_IDX_FUN_OBJ(emit)); - ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_1, REG_LOCAL_1, offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t)); - ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_LOCAL_1, emit->scope->num_pos_args + emit->scope->num_kwonly_args); - #endif + emit_call(emit, MP_F_NATIVE_GET_EXC); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_RET); // get active_exception and store it locally; TODO could perhaps change this so we load it on demand ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_1, LOCAL_IDX_EXC_HANDLER_PC(emit)); ASM_JUMP_IF_REG_NONZERO(emit->as, REG_LOCAL_1, nlr_label, false); } - if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) { - // Restore old globals - emit_native_mov_reg_state(emit, REG_ARG_1, LOCAL_IDX_OLD_GLOBALS(emit)); - emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS); - } - if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) { // Store return value in state[0] ASM_MOV_REG_LOCAL(emit->as, REG_TEMP0, LOCAL_IDX_EXC_VAL(emit)); @@ -1240,11 +1217,13 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) { // Load return kind ASM_MOV_REG_IMM(emit->as, REG_PARENT_RET, MP_VM_RETURN_EXCEPTION); + // TODO optimise with a jump to last ASM_EXIT? ASM_EXIT(emit->as); } else { // Re-raise exception out to caller - ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); - emit_call(emit, MP_F_NATIVE_RAISE); + ASM_MOV_REG_IMM(emit->as, REG_RET, (mp_uint_t)MP_OBJ_NULL); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_RET_VAL(emit), REG_RET); + ASM_JUMP(emit->as, emit->exit_label); } // Label for start of function @@ -1259,7 +1238,8 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) { // Check LOCAL_IDX_EXC_VAL for any injected value ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); - emit_call(emit, MP_F_NATIVE_RAISE); + emit_call(emit, MP_F_NATIVE_RAISE); // returns MP_OBJ_NULL if there's something to raise + CHECK_EXC(emit); } } } @@ -1274,18 +1254,13 @@ STATIC void emit_native_global_exc_exit(emit_t *emit) { emit_native_mov_reg_state(emit, REG_ARG_1, LOCAL_IDX_OLD_GLOBALS(emit)); if (emit->scope->exc_stack_size == 0) { - // Optimisation: if globals didn't change then don't restore them and don't do nlr_pop + // Optimisation: if globals didn't change then don't restore them ASM_JUMP_IF_REG_ZERO(emit->as, REG_ARG_1, emit->exit_label + 1, false); } // Restore old globals emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS); - } - - // Pop the nlr context - emit_call(emit, MP_F_NLR_POP); - if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) { if (emit->scope->exc_stack_size == 0) { // Destination label for above optimisation emit_native_label_assign(emit, emit->exit_label + 1); @@ -1294,6 +1269,17 @@ STATIC void emit_native_global_exc_exit(emit_t *emit) { // Load return value ASM_MOV_REG_LOCAL(emit->as, REG_PARENT_RET, LOCAL_IDX_RET_VAL(emit)); + } else { + // Without a global except handler there may still be exceptions but there is + // no special handling needed, just exit with REG_RET=MP_OBJ_NULL, which must + // be the case for all jumps that end up here. + mp_uint_t global_except_label = emit->exit_label + 3; + emit_native_label_assign(emit, global_except_label); + } + + if (!emit->do_viper_types) { + // Add a label for ASM_EXIT to reduce generated code size (only used for non-viper) + emit_native_label_assign(emit, emit->exit_label + 4); } ASM_EXIT(emit->as); @@ -1511,6 +1497,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) { } emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, (mp_uint_t)MP_OBJ_SENTINEL, REG_ARG_3); + CHECK_EXC(emit); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } else { // viper load @@ -1720,6 +1707,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) { } emit_pre_pop_reg_reg_reg(emit, &vtype_index, REG_ARG_2, &vtype_base, REG_ARG_1, &vtype_value, REG_ARG_3); emit_call(emit, MP_F_OBJ_SUBSCR); + CHECK_EXC(emit); } else { // viper store // TODO The different machine architectures have very different @@ -1912,6 +1900,7 @@ STATIC void emit_native_delete_subscr(emit_t *emit) { assert(vtype_index == VTYPE_PYOBJ); assert(vtype_base == VTYPE_PYOBJ); emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3); + CHECK_EXC(emit); } STATIC void emit_native_subscr(emit_t *emit, int kind) { @@ -2095,6 +2084,7 @@ STATIC void emit_native_setup_with(emit_t *emit, mp_uint_t label) { // call __enter__ method emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 2); // pointer to items, including meth and self emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, 0, REG_ARG_1, 0, REG_ARG_2); + CHECK_EXC(emit); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // push return value of __enter__ // stack: (..., __exit__, self, as_value) @@ -2136,6 +2126,7 @@ STATIC void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) { emit_post_push_imm(emit, VTYPE_PTR_NONE, 0); emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 5); emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, 3, REG_ARG_1, 0, REG_ARG_2); + CHECK_EXC(emit); // Replace exc with None and finish emit_native_jump(emit, *emit->label_slot); @@ -2166,6 +2157,7 @@ STATIC void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) { // call __exit__ method emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 5); emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, 3, REG_ARG_1, 0, REG_ARG_2); + // TODO write test for when the above MP_F_CALL_METHOD_N_KW fails // Stack: (...) // If REG_RET is true then we need to replace exception with None (swallow exception) @@ -2184,9 +2176,13 @@ STATIC void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) { emit_native_label_assign(emit, *emit->label_slot + 1); // Exception is in nlr_buf.ret_val slot + + ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); // get exc + emit_call(emit, MP_F_NATIVE_RAISE); // re-raise (won't do anything if it's None from swallowed above) } STATIC void emit_native_end_finally(emit_t *emit) { + // TODO rewrite this comment // logic: // exc = pop_stack // if exc == None: pass @@ -2194,7 +2190,8 @@ STATIC void emit_native_end_finally(emit_t *emit) { // the check if exc is None is done in the MP_F_NATIVE_RAISE stub emit_native_pre(emit); ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); - emit_call(emit, MP_F_NATIVE_RAISE); + emit_call(emit, MP_F_NATIVE_RAISE); // returns MP_OBJ_NULL if there's something to raise + CHECK_EXC(emit); // Get state for this finally and see if we need to unwind exc_stack_entry_t *e = emit_native_pop_exc_stack(emit); @@ -2222,10 +2219,12 @@ STATIC void emit_native_get_iter(emit_t *emit, bool use_stack) { if (use_stack) { emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_2, MP_OBJ_ITER_BUF_NSLOTS); emit_call(emit, MP_F_NATIVE_GETITER); + CHECK_EXC(emit); } else { // mp_getiter will allocate the iter_buf on the heap ASM_MOV_REG_IMM(emit->as, REG_ARG_2, 0); emit_call(emit, MP_F_NATIVE_GETITER); + CHECK_EXC(emit); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } } @@ -2235,6 +2234,7 @@ STATIC void emit_native_for_iter(emit_t *emit, mp_uint_t label) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_1, MP_OBJ_ITER_BUF_NSLOTS); adjust_stack(emit, MP_OBJ_ITER_BUF_NSLOTS); emit_call(emit, MP_F_NATIVE_ITERNEXT); + CHECK_EXC(emit); #if MICROPY_DEBUG_MP_OBJ_SENTINELS ASM_MOV_REG_IMM(emit->as, REG_TEMP1, (mp_uint_t)MP_OBJ_STOP_ITERATION); ASM_JUMP_IF_REG_EQ(emit->as, REG_RET, REG_TEMP1, label); @@ -2268,6 +2268,7 @@ STATIC void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) { emit_pre_pop_reg(emit, &vtype, REG_ARG_2); if (vtype == VTYPE_PYOBJ) { emit_call_with_imm_arg(emit, MP_F_UNARY_OP, op, REG_ARG_1); + CHECK_EXC(emit); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } else { adjust_stack(emit, 1); @@ -2440,9 +2441,11 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) { op = MP_BINARY_OP_IS; } emit_call_with_imm_arg(emit, MP_F_BINARY_OP, op, REG_ARG_1); + CHECK_EXC(emit); if (invert) { ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET); emit_call_with_imm_arg(emit, MP_F_UNARY_OP, MP_UNARY_OP_NOT, REG_ARG_1); + CHECK_EXC(emit); } emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } else { @@ -2475,6 +2478,7 @@ STATIC void emit_native_build(emit_t *emit, mp_uint_t n_args, int kind) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items } emit_call_with_imm_arg(emit, MP_F_BUILD_TUPLE + kind, n_args, REG_ARG_1); + CHECK_EXC(emit); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new tuple/list/map/set } @@ -2485,6 +2489,7 @@ STATIC void emit_native_store_map(emit_t *emit) { assert(vtype_value == VTYPE_PYOBJ); assert(vtype_map == VTYPE_PYOBJ); emit_call(emit, MP_F_STORE_MAP); + CHECK_EXC(emit); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // map } @@ -2506,6 +2511,7 @@ STATIC void emit_native_build_slice(emit_t *emit, mp_uint_t n_args) { assert(vtype_step == VTYPE_PYOBJ); } emit_call(emit, MP_F_NEW_SLICE); + CHECK_EXC(emit); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } #endif @@ -2536,6 +2542,7 @@ STATIC void emit_native_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t co emit_access_stack(emit, collection_index, &vtype_collection, REG_ARG_1); assert(vtype_collection == VTYPE_PYOBJ); emit_call(emit, f); + // TODO write test for failure here emit_post(emit); } @@ -2546,6 +2553,7 @@ STATIC void emit_native_unpack_sequence(emit_t *emit, mp_uint_t n_args) { assert(vtype_base == VTYPE_PYOBJ); emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_args); // arg3 = dest ptr emit_call_with_imm_arg(emit, MP_F_UNPACK_SEQUENCE, n_args, REG_ARG_2); // arg2 = n_args + CHECK_EXC(emit); } STATIC void emit_native_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right) { @@ -2555,6 +2563,7 @@ STATIC void emit_native_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_ri assert(vtype_base == VTYPE_PYOBJ); emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_left + n_right + 1); // arg3 = dest ptr emit_call_with_imm_arg(emit, MP_F_UNPACK_EX, n_left | (n_right << 8), REG_ARG_2); // arg2 = n_left + n_right + CHECK_EXC(emit); } STATIC void emit_native_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) { @@ -2626,13 +2635,16 @@ STATIC void emit_native_call_function(emit_t *emit, mp_uint_t n_positional, mp_u break; default: // this can happen when casting a cast: int(int) - mp_raise_NotImplementedError("casting"); + adjust_stack(emit, -1); + *emit->error_slot = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "casting"); + break; } } else { assert(vtype_fun == VTYPE_PYOBJ); if (star_flags) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional + 2 * n_keyword + 3); // pointer to args emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW_VAR, 0, REG_ARG_1, n_positional | (n_keyword << 8), REG_ARG_2); + CHECK_EXC(emit); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } else { if (n_positional != 0 || n_keyword != 0) { @@ -2640,6 +2652,7 @@ STATIC void emit_native_call_function(emit_t *emit, mp_uint_t n_positional, mp_u } emit_pre_pop_reg(emit, &vtype_fun, REG_ARG_1); // the function emit_call_with_imm_arg(emit, MP_F_NATIVE_CALL_FUNCTION_N_KW, n_positional | (n_keyword << 8), REG_ARG_2); + CHECK_EXC(emit); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } } @@ -2649,11 +2662,13 @@ STATIC void emit_native_call_method(emit_t *emit, mp_uint_t n_positional, mp_uin if (star_flags) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional + 2 * n_keyword + 4); // pointer to args emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW_VAR, 1, REG_ARG_1, n_positional | (n_keyword << 8), REG_ARG_2); + CHECK_EXC(emit); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } else { emit_native_pre(emit); emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 2 + n_positional + 2 * n_keyword); // pointer to items, including meth and self emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, n_positional, REG_ARG_1, n_keyword, REG_ARG_2); + CHECK_EXC(emit); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } } @@ -2722,14 +2737,15 @@ STATIC void emit_native_raise_varargs(emit_t *emit, mp_uint_t n_args) { EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "must raise an object"); } // TODO probably make this 1 call to the runtime (which could even call convert, native_raise(obj, type)) - emit_call(emit, MP_F_NATIVE_RAISE); + emit_call(emit, MP_F_NATIVE_RAISE); // returns MP_OBJ_NULL if there's something to raise + JUMP_EXC(emit); } STATIC void emit_native_yield(emit_t *emit, int kind) { // Note: 1 (yield) or 3 (yield from) labels are reserved for this function, starting at *emit->label_slot if (emit->do_viper_types) { - mp_raise_NotImplementedError("native yield"); + *emit->error_slot = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "native yield"); } emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; @@ -2784,7 +2800,8 @@ STATIC void emit_native_yield(emit_t *emit, int kind) { if (kind == MP_EMIT_YIELD_VALUE) { // Check LOCAL_IDX_EXC_VAL for any injected value ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); - emit_call(emit, MP_F_NATIVE_RAISE); + emit_call(emit, MP_F_NATIVE_RAISE); // returns MP_OBJ_NULL if there's something to raise + CHECK_EXC(emit); } else { // Label loop entry emit_native_label_assign(emit, *emit->label_slot + 2); @@ -2801,6 +2818,11 @@ STATIC void emit_native_yield(emit_t *emit, int kind) { // If returned non-zero then generator continues ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, *emit->label_slot + 1, true); + // Check if native yield from raised an exception + // TODO could improve by having three options for return value of native yield from + emit_call(emit, MP_F_NATIVE_IS_EXC); // returns MP_OBJ_NULL if there's something to raise + CHECK_EXC(emit); + // Pop exhausted gen, replace with ret_value emit_native_adjust_stack_size(emit, 1); // ret_value emit_fold_stack_top(emit, REG_ARG_1); diff --git a/py/gc.c b/py/gc.c index c763a839ec231..55e7ea99e303a 100644 --- a/py/gc.c +++ b/py/gc.c @@ -434,6 +434,9 @@ void gc_info(gc_info_t *info) { GC_EXIT(); } +unsigned gc_alloc_count_max = (unsigned)-1; +static unsigned gc_alloc_count = 0; + void *gc_alloc(size_t n_bytes, unsigned int alloc_flags) { bool has_finaliser = alloc_flags & GC_ALLOC_FLAG_HAS_FINALISER; size_t n_blocks = ((n_bytes + BYTES_PER_BLOCK - 1) & (~(BYTES_PER_BLOCK - 1))) / BYTES_PER_BLOCK; @@ -452,6 +455,16 @@ void *gc_alloc(size_t n_bytes, unsigned int alloc_flags) { return NULL; } + if (gc_alloc_count_max != (unsigned)-1) { + if (gc_alloc_count == gc_alloc_count_max) { + GC_EXIT(); + printf("** gc_alloc: %u force fail n_bytes=%u\n", gc_alloc_count, (unsigned)n_bytes); + return NULL; + } + printf("** gc_alloc: %u\n", gc_alloc_count); + ++gc_alloc_count; + } + size_t i; size_t end_block; size_t start_block; diff --git a/py/lexer.c b/py/lexer.c index 5f8adda918039..ea3bd7b198a3b 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -342,7 +342,8 @@ STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw) { // 3MB of text; even gzip-compressed and with minimal structure, it'll take // roughly half a meg of storage. This form of Unicode escape may be added // later on, but it's definitely not a priority right now. -- CJA 20140607 - mp_raise_NotImplementedError("unicode name escapes"); + mp_raise_NotImplementedError_o("unicode name escapes"); + // TODO can we just safely break and expect caller to handle exception? break; default: if (c >= '0' && c <= '7') { @@ -671,6 +672,9 @@ void mp_lexer_to_next(mp_lexer_t *lex) { mp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader) { mp_lexer_t *lex = m_new_obj(mp_lexer_t); + if (lex == NULL) { + return NULL; + } lex->source_name = src_name; lex->reader = reader; @@ -681,6 +685,9 @@ mp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader) { lex->alloc_indent_level = MICROPY_ALLOC_LEXER_INDENT_INIT; lex->num_indent_level = 1; lex->indent_level = m_new(uint16_t, lex->alloc_indent_level); + if (lex->indent_level == NULL) { + return NULL; + } vstr_init(&lex->vstr, 32); // store sentinel for first indentation level @@ -702,6 +709,10 @@ mp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader) { lex->tok_kind = MP_TOKEN_INDENT; } + if (MP_STATE_THREAD(active_exception) != NULL) { + return NULL; + } + return lex; } @@ -716,6 +727,9 @@ mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, size_t len mp_lexer_t *mp_lexer_new_from_file(const char *filename) { mp_reader_t reader; mp_reader_new_file(&reader, filename); + if (MP_STATE_THREAD(active_exception) != NULL) { + return NULL; + } return mp_lexer_new(qstr_from_str(filename), reader); } diff --git a/py/malloc.c b/py/malloc.c index f8ed1487a5b8c..d8d30afbe520a 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -85,7 +85,7 @@ STATIC void *realloc_ext(void *ptr, size_t n_bytes, bool allow_move) { void *m_malloc(size_t num_bytes) { void *ptr = malloc(num_bytes); if (ptr == NULL && num_bytes != 0) { - m_malloc_fail(num_bytes); + return m_malloc_fail(num_bytes); } #if MICROPY_MEM_STATS MP_STATE_MEM(total_bytes_allocated) += num_bytes; @@ -111,7 +111,7 @@ void *m_malloc_maybe(size_t num_bytes) { void *m_malloc_with_finaliser(size_t num_bytes) { void *ptr = malloc_with_finaliser(num_bytes); if (ptr == NULL && num_bytes != 0) { - m_malloc_fail(num_bytes); + return m_malloc_fail(num_bytes); } #if MICROPY_MEM_STATS MP_STATE_MEM(total_bytes_allocated) += num_bytes; @@ -139,7 +139,7 @@ void *m_realloc(void *ptr, size_t new_num_bytes) { #endif void *new_ptr = realloc(ptr, new_num_bytes); if (new_ptr == NULL && new_num_bytes != 0) { - m_malloc_fail(new_num_bytes); + return m_malloc_fail(new_num_bytes); } #if MICROPY_MEM_STATS // At first thought, "Total bytes allocated" should only grow, diff --git a/py/map.c b/py/map.c index 5f3c6e5473359..c2c2d84744314 100644 --- a/py/map.c +++ b/py/map.c @@ -118,12 +118,15 @@ void mp_map_clear(mp_map_t *map) { map->table = NULL; } -STATIC void mp_map_rehash(mp_map_t *map) { +STATIC int mp_map_rehash(mp_map_t *map) { size_t old_alloc = map->alloc; size_t new_alloc = get_hash_alloc_greater_or_equal_to(map->alloc + 1); DEBUG_printf("mp_map_rehash(%p): " UINT_FMT " -> " UINT_FMT "\n", map, old_alloc, new_alloc); mp_map_elem_t *old_table = map->table; mp_map_elem_t *new_table = m_new0(mp_map_elem_t, new_alloc); + if (new_table == NULL) { + return -1; + } // If we reach this point, table resizing succeeded, now we can edit the old map. map->alloc = new_alloc; map->used = 0; @@ -135,6 +138,7 @@ STATIC void mp_map_rehash(mp_map_t *map) { } } m_del(mp_map_elem_t, old_table, old_alloc); + return 0; // success } // MP_MAP_LOOKUP behaviour: @@ -143,6 +147,7 @@ STATIC void mp_map_rehash(mp_map_t *map) { // - returns slot, with key non-null and value=MP_OBJ_NULL if it was added // MP_MAP_LOOKUP_REMOVE_IF_FOUND behaviour: // - returns NULL if not found, else the slot if was found in with key null and value non-null +// TODO: NULL return can mean 1) not found; 2) exception mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) { // If the map is a fixed array then we must only be called for a lookup assert(!map->is_fixed || lookup_kind == MP_MAP_LOOKUP); @@ -210,7 +215,10 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t if (map->alloc == 0) { if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { - mp_map_rehash(map); + if (mp_map_rehash(map)) { + // exception + return NULL; + } } else { return NULL; } @@ -221,7 +229,11 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t if (mp_obj_is_qstr(index)) { hash = qstr_hash(MP_OBJ_QSTR_VALUE(index)); } else { - hash = MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, index)); + mp_obj_t hash_o = mp_unary_op(MP_UNARY_OP_HASH, index); + if (hash_o == MP_OBJ_NULL) { + return NULL; + } + hash = MP_OBJ_SMALL_INT_VALUE(hash_o); } size_t pos = hash % map->alloc; @@ -284,7 +296,10 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t return avail_slot; } else { // not enough room in table, rehash it - mp_map_rehash(map); + if (mp_map_rehash(map)) { + // exception + return NULL; + } // restart the search for the new element start_pos = pos = hash % map->alloc; } @@ -320,6 +335,7 @@ STATIC void mp_set_rehash(mp_set_t *set) { m_del(mp_obj_t, old_table, old_alloc); } +// TODO: MP_OBJ_NULL return can mean 1) not found; 2) exception mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) { // Note: lookup_kind can be MP_MAP_LOOKUP_ADD_IF_NOT_FOUND_OR_REMOVE_IF_FOUND which // is handled by using bitwise operations. @@ -331,7 +347,11 @@ mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t looku return MP_OBJ_NULL; } } - mp_uint_t hash = MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, index)); + mp_obj_t hash_o = mp_unary_op(MP_UNARY_OP_HASH, index); + if (hash_o == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } + mp_uint_t hash = MP_OBJ_SMALL_INT_VALUE(hash_o); size_t pos = hash % set->alloc; size_t start_pos = pos; mp_obj_t *avail_slot = NULL; diff --git a/py/misc.h b/py/misc.h index 0aa4a5d2c6c91..7cbab29e9a715 100644 --- a/py/misc.h +++ b/py/misc.h @@ -97,7 +97,7 @@ void *m_realloc(void *ptr, size_t new_num_bytes); void *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move); void m_free(void *ptr); #endif -NORETURN void m_malloc_fail(size_t num_bytes); +void *m_malloc_fail(size_t num_bytes); #if MICROPY_MEM_STATS size_t m_get_total_bytes_allocated(void); @@ -177,8 +177,8 @@ char *vstr_add_len(vstr_t *vstr, size_t len); char *vstr_null_terminated_str(vstr_t *vstr); void vstr_add_byte(vstr_t *vstr, byte v); void vstr_add_char(vstr_t *vstr, unichar chr); -void vstr_add_str(vstr_t *vstr, const char *str); -void vstr_add_strn(vstr_t *vstr, const char *str, size_t len); +int vstr_add_str(vstr_t *vstr, const char *str); +int vstr_add_strn(vstr_t *vstr, const char *str, size_t len); void vstr_ins_byte(vstr_t *vstr, size_t byte_pos, byte b); void vstr_ins_char(vstr_t *vstr, size_t char_pos, unichar chr); void vstr_cut_head_bytes(vstr_t *vstr, size_t bytes_to_cut); diff --git a/py/modbuiltins.c b/py/modbuiltins.c index a65f3beecfa8b..89f6311e1870f 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -97,11 +97,14 @@ STATIC mp_obj_t mp_builtin_all(mp_obj_t o_in) { mp_obj_iter_buf_t iter_buf; mp_obj_t iterable = mp_getiter(o_in, &iter_buf); mp_obj_t item; - while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + while ((item = mp_iternext2(iterable)) != MP_OBJ_NULL) { if (!mp_obj_is_true(item)) { return mp_const_false; } } + if (mp_iternext_had_exc()) { + return MP_OBJ_NULL; + } return mp_const_true; } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_all_obj, mp_builtin_all); @@ -110,11 +113,14 @@ STATIC mp_obj_t mp_builtin_any(mp_obj_t o_in) { mp_obj_iter_buf_t iter_buf; mp_obj_t iterable = mp_getiter(o_in, &iter_buf); mp_obj_t item; - while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + while ((item = mp_iternext2(iterable)) != MP_OBJ_NULL) { if (mp_obj_is_true(item)) { return mp_const_true; } } + if (mp_iternext_had_exc()) { + return MP_OBJ_NULL; + } return mp_const_false; } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_any_obj, mp_builtin_any); @@ -157,7 +163,7 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { str[3] = (c & 0x3F) | 0x80; len = 4; } else { - mp_raise_ValueError("chr() arg not in range(0x110000)"); + return mp_raise_ValueError_o("chr() arg not in range(0x110000)"); } return mp_obj_new_str_via_qstr((char*)str, len); #else @@ -166,7 +172,7 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { uint8_t str[1] = {ord}; return mp_obj_new_str_via_qstr((char*)str, 1); } else { - mp_raise_ValueError("chr() arg not in range(256)"); + return mp_raise_ValueError_o("chr() arg not in range(256)"); } #endif } @@ -273,19 +279,22 @@ STATIC mp_obj_t mp_builtin_min_max(size_t n_args, const mp_obj_t *args, mp_map_t mp_obj_t best_key = MP_OBJ_NULL; mp_obj_t best_obj = MP_OBJ_NULL; mp_obj_t item; - while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + while ((item = mp_iternext2(iterable)) != MP_OBJ_NULL) { mp_obj_t key = key_fn == MP_OBJ_NULL ? item : mp_call_function_1(key_fn, item); if (best_obj == MP_OBJ_NULL || (mp_binary_op(op, key, best_key) == mp_const_true)) { best_key = key; best_obj = item; } } + if (mp_iternext_had_exc()) { + return MP_OBJ_NULL; + } if (best_obj == MP_OBJ_NULL) { default_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_default), MP_MAP_LOOKUP); if (default_elem != NULL) { best_obj = default_elem->value; } else { - mp_raise_ValueError("arg is an empty sequence"); + return mp_raise_ValueError_o("arg is an empty sequence"); } } return best_obj; @@ -321,7 +330,7 @@ STATIC mp_obj_t mp_builtin_next(size_t n_args, const mp_obj_t *args) { if (n_args == 1) { mp_obj_t ret = mp_iternext_allow_raise(args[0]); if (ret == MP_OBJ_STOP_ITERATION) { - nlr_raise(mp_obj_new_exception(&mp_type_StopIteration)); + return mp_raise_o(mp_obj_new_exception(&mp_type_StopIteration)); } else { return ret; } @@ -335,7 +344,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_next_obj, 1, 2, mp_builtin_next); STATIC mp_obj_t mp_builtin_next(mp_obj_t o) { mp_obj_t ret = mp_iternext_allow_raise(o); if (ret == MP_OBJ_STOP_ITERATION) { - nlr_raise(mp_obj_new_exception(&mp_type_StopIteration)); + return mp_raise_o(mp_obj_new_exception(&mp_type_StopIteration)); } else { return ret; } @@ -356,6 +365,10 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_oct_obj, mp_builtin_oct); STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) { size_t len; const byte *str = (const byte*)mp_obj_str_get_data(o_in, &len); + if (str == NULL) { + // exception + return MP_OBJ_NULL; + } #if MICROPY_PY_BUILTINS_STR_UNICODE if (mp_obj_is_str(o_in)) { len = utf8_charlen(str, len); @@ -372,9 +385,9 @@ STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) { } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("ord expects a character"); + return mp_raise_TypeError_o("ord expects a character"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "ord() expected a character, but string of length %d found", (int)len)); } } @@ -385,7 +398,7 @@ STATIC mp_obj_t mp_builtin_pow(size_t n_args, const mp_obj_t *args) { case 2: return mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]); default: #if !MICROPY_PY_BUILTINS_POW3 - mp_raise_msg(&mp_type_NotImplementedError, "3-arg pow() not supported"); + return mp_raise_msg_o(&mp_type_NotImplementedError, "3-arg pow() not supported"); #elif MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_MPZ return mp_binary_op(MP_BINARY_OP_MODULO, mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]), args[2]); #else @@ -413,7 +426,9 @@ STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *pos_args, mp_map mp_arg_parse_all(0, NULL, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, u.args); #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES - mp_get_stream_raise(u.args[ARG_file].u_obj, MP_STREAM_OP_WRITE); + if (mp_get_stream_raise(u.args[ARG_file].u_obj, MP_STREAM_OP_WRITE) == NULL) { + return MP_OBJ_NULL; + } mp_print_t print = {MP_OBJ_TO_PTR(u.args[ARG_file].u_obj), mp_stream_write_adaptor}; #endif @@ -442,6 +457,10 @@ STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *pos_args, mp_map #else mp_print_strn(&mp_plat_print, end_data, u.len[1], 0, 0, 0); #endif + if (MP_STATE_THREAD(active_exception) != NULL) { + // some printing function above had an exception + return MP_OBJ_NULL; + } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_print_obj, 0, mp_builtin_print); @@ -477,7 +496,7 @@ STATIC mp_obj_t mp_builtin_round(size_t n_args, const mp_obj_t *args) { } #if !MICROPY_PY_BUILTINS_ROUND_INT - mp_raise_NotImplementedError(NULL); + return mp_raise_NotImplementedError_o(NULL); #else mp_int_t num_dig = mp_obj_get_int(args[1]); if (num_dig >= 0) { @@ -530,16 +549,19 @@ STATIC mp_obj_t mp_builtin_sum(size_t n_args, const mp_obj_t *args) { mp_obj_iter_buf_t iter_buf; mp_obj_t iterable = mp_getiter(args[0], &iter_buf); mp_obj_t item; - while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + while ((item = mp_iternext2(iterable)) != MP_OBJ_NULL) { value = mp_binary_op(MP_BINARY_OP_ADD, value, item); } + if (mp_iternext_had_exc()) { + return MP_OBJ_NULL; + } return value; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj, 1, 2, mp_builtin_sum); STATIC mp_obj_t mp_builtin_sorted(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { if (n_args > 1) { - mp_raise_TypeError("must use keyword argument for key function"); + return mp_raise_TypeError_o("must use keyword argument for key function"); } mp_obj_t self = mp_type_list.make_new(&mp_type_list, 1, 0, args); mp_obj_list_sort(1, &self, kwargs); @@ -574,7 +596,9 @@ STATIC mp_obj_t mp_builtin_getattr(size_t n_args, const mp_obj_t *args) { MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_getattr_obj, 2, 3, mp_builtin_getattr); STATIC mp_obj_t mp_builtin_setattr(mp_obj_t base, mp_obj_t attr, mp_obj_t value) { - mp_store_attr(base, mp_obj_str_get_qstr(attr), value); + if (mp_store_attr(base, mp_obj_str_get_qstr(attr), value) == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_3(mp_builtin_setattr_obj, mp_builtin_setattr); @@ -588,8 +612,14 @@ MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_delattr_obj, mp_builtin_delattr); STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) { qstr attr = mp_obj_str_get_qstr(attr_in); + if (attr == MP_QSTR_NULL) { + // exception + return MP_OBJ_NULL; + } mp_obj_t dest[2]; - mp_load_method_protected(object_in, attr, dest, false); + if (mp_load_method_protected(object_in, attr, dest, false) == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } return mp_obj_new_bool(dest[0] != MP_OBJ_NULL); } MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj, mp_builtin_hasattr); diff --git a/py/modmath.c b/py/modmath.c index 35bb44bea37c7..88bc8806d9f04 100644 --- a/py/modmath.c +++ b/py/modmath.c @@ -35,15 +35,15 @@ // And by defining our own we can ensure it uses the correct const format. #define MP_PI MICROPY_FLOAT_CONST(3.14159265358979323846) -STATIC NORETURN void math_error(void) { - mp_raise_ValueError("math domain error"); +STATIC mp_obj_t math_error(void) { + return mp_raise_ValueError_o("math domain error"); } STATIC mp_obj_t math_generic_1(mp_obj_t x_obj, mp_float_t (*f)(mp_float_t)) { mp_float_t x = mp_obj_get_float(x_obj); mp_float_t ans = f(x); if ((isnan(ans) && !isnan(x)) || (isinf(ans) && !isinf(x))) { - math_error(); + return math_error(); } return mp_obj_new_float(ans); } @@ -53,7 +53,7 @@ STATIC mp_obj_t math_generic_2(mp_obj_t x_obj, mp_obj_t y_obj, mp_float_t (*f)(m mp_float_t y = mp_obj_get_float(y_obj); mp_float_t ans = f(x, y); if ((isnan(ans) && !isnan(x) && !isnan(y)) || (isinf(ans) && !isinf(x))) { - math_error(); + return math_error(); } return mp_obj_new_float(ans); } @@ -188,7 +188,7 @@ STATIC mp_obj_t mp_math_isclose(size_t n_args, const mp_obj_t *pos_args, mp_map_ ? (mp_float_t)1e-9 : mp_obj_get_float(args[ARG_rel_tol].u_obj); const mp_float_t abs_tol = mp_obj_get_float(args[ARG_abs_tol].u_obj); if (rel_tol < (mp_float_t)0.0 || abs_tol < (mp_float_t)0.0) { - math_error(); + return math_error(); } if (a == b) { return mp_const_true; @@ -213,7 +213,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(mp_math_isclose_obj, 2, mp_math_isclose); STATIC mp_obj_t mp_math_log(size_t n_args, const mp_obj_t *args) { mp_float_t x = mp_obj_get_float(args[0]); if (x <= (mp_float_t)0.0) { - math_error(); + return math_error(); } mp_float_t l = MICROPY_FLOAT_C_FUN(log)(x); if (n_args == 1) { @@ -221,9 +221,9 @@ STATIC mp_obj_t mp_math_log(size_t n_args, const mp_obj_t *args) { } else { mp_float_t base = mp_obj_get_float(args[1]); if (base <= (mp_float_t)0.0) { - math_error(); + return math_error(); } else if (base == (mp_float_t)1.0) { - mp_raise_msg(&mp_type_ZeroDivisionError, "divide by zero"); + return mp_raise_msg_o(&mp_type_ZeroDivisionError, "divide by zero"); } return mp_obj_new_float(l / MICROPY_FLOAT_C_FUN(log)(base)); } @@ -294,7 +294,7 @@ STATIC mp_obj_t mp_math_factorial_inner(mp_uint_t start, mp_uint_t end) { STATIC mp_obj_t mp_math_factorial(mp_obj_t x_obj) { mp_int_t max = mp_obj_get_int(x_obj); if (max < 0) { - mp_raise_msg(&mp_type_ValueError, "negative factorial"); + return mp_raise_msg_o(&mp_type_ValueError, "negative factorial"); } else if (max == 0) { return MP_OBJ_NEW_SMALL_INT(1); } @@ -308,7 +308,7 @@ STATIC mp_obj_t mp_math_factorial(mp_obj_t x_obj) { STATIC mp_obj_t mp_math_factorial(mp_obj_t x_obj) { mp_int_t max = mp_obj_get_int(x_obj); if (max < 0) { - mp_raise_msg(&mp_type_ValueError, "negative factorial"); + return mp_raise_msg_o(&mp_type_ValueError, "negative factorial"); } else if (max <= 1) { return MP_OBJ_NEW_SMALL_INT(1); } diff --git a/py/modmicropython.c b/py/modmicropython.c index 8d36697f15dd3..7aff2b3cbc54d 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -150,7 +150,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_micropython_kbd_intr_obj, mp_micropython_kbd #if MICROPY_ENABLE_SCHEDULER STATIC mp_obj_t mp_micropython_schedule(mp_obj_t function, mp_obj_t arg) { if (!mp_sched_schedule(function, arg)) { - mp_raise_msg(&mp_type_RuntimeError, "schedule queue full"); + return mp_raise_msg_o(&mp_type_RuntimeError, "schedule queue full"); } return mp_const_none; } diff --git a/py/modstruct.c b/py/modstruct.c index 36af4260eef37..7c80458cd9424 100644 --- a/py/modstruct.c +++ b/py/modstruct.c @@ -99,6 +99,9 @@ STATIC size_t calc_size_items(const char *fmt, size_t *total_sz) { total_cnt += cnt; size_t align; size_t sz = mp_binary_get_size(fmt_type, *fmt, &align); + if (sz == 0) { + return (size_t)-1; + } while (cnt--) { // Apply alignment size = (size + align - 1) & ~(align - 1); @@ -112,8 +115,13 @@ STATIC size_t calc_size_items(const char *fmt, size_t *total_sz) { STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) { const char *fmt = mp_obj_str_get_str(fmt_in); + if (fmt == NULL) { + return MP_OBJ_NULL; + } size_t size; - calc_size_items(fmt, &size); + if (calc_size_items(fmt, &size) == (size_t)-1) { + return MP_OBJ_NULL; + } return MP_OBJ_NEW_SMALL_INT(size); } MP_DEFINE_CONST_FUN_OBJ_1(struct_calcsize_obj, struct_calcsize); @@ -126,6 +134,9 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) { const char *fmt = mp_obj_str_get_str(args[0]); size_t total_sz; size_t num_items = calc_size_items(fmt, &total_sz); + if (num_items == (size_t)-1) { + return MP_OBJ_NULL; + } char fmt_type = get_fmt_type(&fmt); mp_obj_tuple_t *res = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_items, NULL)); mp_buffer_info_t bufinfo; @@ -141,7 +152,7 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) { // negative offsets are relative to the end of the buffer offset = bufinfo.len + offset; if (offset < 0) { - mp_raise_ValueError("buffer too small"); + return mp_raise_ValueError_o("buffer too small"); } } p += offset; @@ -150,7 +161,7 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) { // Check that the input buffer is big enough to unpack all the values if (p + total_sz > end_p) { - mp_raise_ValueError("buffer too small"); + return mp_raise_ValueError_o("buffer too small"); } for (size_t i = 0; i < num_items;) { @@ -214,7 +225,11 @@ STATIC void struct_pack_into_internal(mp_obj_t fmt_in, byte *p, size_t n_args, c STATIC mp_obj_t struct_pack(size_t n_args, const mp_obj_t *args) { // TODO: "The arguments must match the values required by the format exactly." - mp_int_t size = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0])); + mp_obj_t size_obj = struct_calcsize(args[0]); + if (size_obj == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } + mp_int_t size = MP_OBJ_SMALL_INT_VALUE(size_obj); vstr_t vstr; vstr_init_len(&vstr, size); byte *p = (byte*)vstr.buf; @@ -232,7 +247,7 @@ STATIC mp_obj_t struct_pack_into(size_t n_args, const mp_obj_t *args) { // negative offsets are relative to the end of the buffer offset = (mp_int_t)bufinfo.len + offset; if (offset < 0) { - mp_raise_ValueError("buffer too small"); + return mp_raise_ValueError_o("buffer too small"); } } byte *p = (byte *)bufinfo.buf; @@ -240,9 +255,13 @@ STATIC mp_obj_t struct_pack_into(size_t n_args, const mp_obj_t *args) { p += offset; // Check that the output buffer is big enough to hold all the values - mp_int_t sz = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0])); + mp_obj_t sz_obj = struct_calcsize(args[0]); + if (sz_obj == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } + mp_int_t sz = MP_OBJ_SMALL_INT_VALUE(sz_obj); if (p + sz > end_p) { - mp_raise_ValueError("buffer too small"); + return mp_raise_ValueError_o("buffer too small"); } struct_pack_into_internal(args[0], p, n_args - 3, &args[3]); diff --git a/py/modsys.c b/py/modsys.c index 29fac7c319340..16f3152b3de04 100644 --- a/py/modsys.c +++ b/py/modsys.c @@ -116,7 +116,7 @@ STATIC mp_obj_t mp_sys_exit(size_t n_args, const mp_obj_t *args) { } else { exc = mp_obj_new_exception_arg1(&mp_type_SystemExit, args[0]); } - nlr_raise(exc); + return mp_raise_o(exc); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_exit_obj, 0, 1, mp_sys_exit); @@ -124,7 +124,9 @@ STATIC mp_obj_t mp_sys_print_exception(size_t n_args, const mp_obj_t *args) { #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES void *stream_obj = &mp_sys_stdout_obj; if (n_args > 1) { - mp_get_stream_raise(args[1], MP_STREAM_OP_WRITE); + if (mp_get_stream_raise(args[1], MP_STREAM_OP_WRITE) == NULL) { + return MP_OBJ_NULL; + } stream_obj = MP_OBJ_TO_PTR(args[1]); } diff --git a/py/modthread.c b/py/modthread.c index 91237a72b3758..309ad8b09ded1 100644 --- a/py/modthread.c +++ b/py/modthread.c @@ -77,7 +77,7 @@ STATIC mp_obj_t thread_lock_acquire(size_t n_args, const mp_obj_t *args) { self->locked = true; return mp_const_true; } else { - mp_raise_OSError(-ret); + return mp_raise_OSError_o(-ret); } } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(thread_lock_acquire_obj, 1, 3, thread_lock_acquire); @@ -85,7 +85,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(thread_lock_acquire_obj, 1, 3, thread STATIC mp_obj_t thread_lock_release(mp_obj_t self_in) { mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(self_in); if (!self->locked) { - mp_raise_msg(&mp_type_RuntimeError, NULL); + return mp_raise_msg_o(&mp_type_RuntimeError, NULL); } self->locked = false; MP_THREAD_GIL_EXIT(); @@ -175,6 +175,8 @@ STATIC void *thread_entry(void *args_in) { mp_locals_set(args->dict_locals); mp_globals_set(args->dict_globals); + MP_STATE_THREAD(active_exception) = NULL; + MP_THREAD_GIL_ENTER(); // signal that we are set up and running @@ -186,14 +188,11 @@ STATIC void *thread_entry(void *args_in) { DEBUG_printf("[thread] start ts=%p args=%p stack=%p\n", &ts, &args, MP_STATE_THREAD(stack_top)); - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_call_function_n_kw(args->fun, args->n_args, args->n_kw, args->args); - nlr_pop(); - } else { + mp_call_function_n_kw(args->fun, args->n_args, args->n_kw, args->args); + if (MP_STATE_THREAD(active_exception) != NULL) { // uncaught exception // check for SystemExit - mp_obj_base_t *exc = (mp_obj_base_t*)nlr.ret_val; + mp_obj_base_t *exc = (mp_obj_base_t*)MP_STATE_THREAD(active_exception); if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { // swallow exception silently } else { @@ -235,7 +234,7 @@ STATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args) } else { // positional and keyword arguments if (mp_obj_get_type(args[2]) != &mp_type_dict) { - mp_raise_TypeError("expecting a dict for keyword args"); + return mp_raise_TypeError_o("expecting a dict for keyword args"); } mp_map_t *map = &((mp_obj_dict_t*)MP_OBJ_TO_PTR(args[2]))->map; th_args = m_new_obj_var(thread_entry_args_t, mp_obj_t, pos_args_len + 2 * map->used); @@ -271,7 +270,7 @@ STATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args) STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_thread_start_new_thread_obj, 2, 3, mod_thread_start_new_thread); STATIC mp_obj_t mod_thread_exit(void) { - nlr_raise(mp_obj_new_exception(&mp_type_SystemExit)); + return mp_raise_o(mp_obj_new_exception(&mp_type_SystemExit)); } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_exit_obj, mod_thread_exit); diff --git a/py/mpconfig.h b/py/mpconfig.h index e46da3e83c721..443efd3203ebb 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -427,8 +427,9 @@ #endif // Whether to enable debugging versions of MP_OBJ_NULL/STOP_ITERATION/SENTINEL +// Note: this is currently required for no NLR, to distinguish MP_OBJ_NULL (exception) from MP_OBJ_STOP_ITERATION #ifndef MICROPY_DEBUG_MP_OBJ_SENTINELS -#define MICROPY_DEBUG_MP_OBJ_SENTINELS (0) +#define MICROPY_DEBUG_MP_OBJ_SENTINELS (1) #endif // Whether to enable a simple VM stack overflow check diff --git a/py/mpstate.h b/py/mpstate.h index ab7d8c51b95bc..a335b0341395b 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -257,6 +257,8 @@ typedef struct _mp_state_thread_t { mp_obj_dict_t *dict_locals; mp_obj_dict_t *dict_globals; + mp_obj_base_t *active_exception; + nlr_buf_t *nlr_top; #if MICROPY_PY_SYS_SETTRACE diff --git a/py/nativeglue.c b/py/nativeglue.c index 1a7f92f94517f..29e67c3eab951 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -143,10 +143,27 @@ STATIC mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, size_t n_args_kw, // wrapper that makes raise obj and raises it // END_FINALLY opcode requires that we don't raise if o==None -STATIC void mp_native_raise(mp_obj_t o) { +STATIC mp_obj_t mp_native_raise(mp_obj_t o) { if (o != MP_OBJ_NULL && o != mp_const_none) { - nlr_raise(mp_make_raise_obj(o)); + return mp_raise_o(mp_make_raise_obj(o)); } + return MP_OBJ_SENTINEL; +} + +STATIC mp_obj_t mp_native_is_exc(void) { + if (MP_STATE_THREAD(active_exception) == NULL) { + return MP_OBJ_SENTINEL; + } else { + return MP_OBJ_NULL; + } +} + +STATIC mp_obj_t mp_native_get_exc(void) { + return MP_STATE_THREAD(active_exception); +} + +STATIC void mp_native_clr_exc(void) { + MP_STATE_THREAD(active_exception) = NULL; } // wrapper that handles iterator buffer @@ -155,12 +172,15 @@ STATIC mp_obj_t mp_native_getiter(mp_obj_t obj, mp_obj_iter_buf_t *iter) { return mp_getiter(obj, NULL); } else { obj = mp_getiter(obj, iter); + if (obj == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } if (obj != MP_OBJ_FROM_PTR(iter)) { // Iterator didn't use the stack so indicate that with MP_OBJ_NULL. iter->base.type = MP_OBJ_NULL; iter->buf[0] = obj; } - return NULL; + return MP_OBJ_SENTINEL; } } @@ -176,19 +196,11 @@ STATIC mp_obj_t mp_native_iternext(mp_obj_iter_buf_t *iter) { } STATIC bool mp_native_yield_from(mp_obj_t gen, mp_obj_t send_value, mp_obj_t *ret_value) { - mp_vm_return_kind_t ret_kind; - nlr_buf_t nlr_buf; mp_obj_t throw_value = *ret_value; - if (nlr_push(&nlr_buf) == 0) { - if (throw_value != MP_OBJ_NULL) { - send_value = MP_OBJ_NULL; - } - ret_kind = mp_resume(gen, send_value, throw_value, ret_value); - nlr_pop(); - } else { - ret_kind = MP_VM_RETURN_EXCEPTION; - *ret_value = nlr_buf.ret_val; + if (throw_value != MP_OBJ_NULL) { + send_value = MP_OBJ_NULL; } + mp_vm_return_kind_t ret_kind = mp_resume(gen, send_value, throw_value, ret_value); if (ret_kind == MP_VM_RETURN_YIELD) { return true; @@ -199,16 +211,18 @@ STATIC bool mp_native_yield_from(mp_obj_t gen, mp_obj_t send_value, mp_obj_t *re } else { assert(ret_kind == MP_VM_RETURN_EXCEPTION); if (!mp_obj_exception_match(*ret_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { - nlr_raise(*ret_value); + mp_raise_o(*ret_value); + return false; // caller must also check active_exception } *ret_value = mp_obj_exception_get_value(*ret_value); } if (throw_value != MP_OBJ_NULL && mp_obj_exception_match(throw_value, MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) { - nlr_raise(mp_make_raise_obj(throw_value)); + mp_raise_o(mp_make_raise_obj(throw_value)); + return false; // caller must also check active_exception } - return false; + return false; // caller must also check active_exception (should be NULL) } #if MICROPY_PY_BUILTINS_FLOAT @@ -294,6 +308,9 @@ const mp_fun_table_t mp_fun_table = { #endif nlr_pop, mp_native_raise, + mp_native_is_exc, + mp_native_get_exc, + mp_native_clr_exc, mp_import_name, mp_import_from, mp_import_all, @@ -313,7 +330,7 @@ const mp_fun_table_t mp_fun_table = { #else NULL, #endif - // Additional entries for dynamic runtime, starts at index 50 + // Additional entries for dynamic runtime, starts at index 53 memset, memmove, gc_realloc, diff --git a/py/nativeglue.h b/py/nativeglue.h index 021e7a8ecb7ea..f4cc86f9e62a9 100644 --- a/py/nativeglue.h +++ b/py/nativeglue.h @@ -67,6 +67,9 @@ typedef enum { MP_F_NLR_PUSH, MP_F_NLR_POP, MP_F_NATIVE_RAISE, + MP_F_NATIVE_IS_EXC, + MP_F_NATIVE_GET_EXC, + MP_F_NATIVE_CLR_EXC, MP_F_IMPORT_NAME, MP_F_IMPORT_FROM, MP_F_IMPORT_ALL, @@ -96,11 +99,11 @@ typedef struct _mp_fun_table_t { mp_obj_t (*load_global)(qstr qst); mp_obj_t (*load_build_class)(void); mp_obj_t (*load_attr)(mp_obj_t base, qstr attr); - void (*load_method)(mp_obj_t base, qstr attr, mp_obj_t *dest); - void (*load_super_method)(qstr attr, mp_obj_t *dest); + mp_obj_t (*load_method)(mp_obj_t base, qstr attr, mp_obj_t *dest); + mp_obj_t (*load_super_method)(qstr attr, mp_obj_t *dest); void (*store_name)(qstr qst, mp_obj_t obj); void (*store_global)(qstr qst, mp_obj_t obj); - void (*store_attr)(mp_obj_t base, qstr attr, mp_obj_t val); + mp_obj_t (*store_attr)(mp_obj_t base, qstr attr, mp_obj_t val); mp_obj_t (*obj_subscr)(mp_obj_t base, mp_obj_t index, mp_obj_t val); bool (*obj_is_true)(mp_obj_t arg); mp_obj_t (*unary_op)(mp_unary_op_t op, mp_obj_t arg); @@ -120,23 +123,26 @@ typedef struct _mp_fun_table_t { mp_obj_t (*iternext)(mp_obj_iter_buf_t *iter); unsigned int (*nlr_push)(nlr_buf_t *); void (*nlr_pop)(void); - void (*raise)(mp_obj_t o); + mp_obj_t (*raise)(mp_obj_t o); + mp_obj_t (*mp_native_is_exc)(void); + mp_obj_t (*mp_native_get_exc)(void); + void (*mp_native_clr_exc)(void); mp_obj_t (*import_name)(qstr name, mp_obj_t fromlist, mp_obj_t level); mp_obj_t (*import_from)(mp_obj_t module, qstr name); void (*import_all)(mp_obj_t module); mp_obj_t (*new_slice)(mp_obj_t start, mp_obj_t stop, mp_obj_t step); - void (*unpack_sequence)(mp_obj_t seq, size_t num, mp_obj_t *items); - void (*unpack_ex)(mp_obj_t seq, size_t num, mp_obj_t *items); - void (*delete_name)(qstr qst); - void (*delete_global)(qstr qst); + mp_obj_t (*unpack_sequence)(mp_obj_t seq, size_t num, mp_obj_t *items); + mp_obj_t (*unpack_ex)(mp_obj_t seq, size_t num, mp_obj_t *items); + mp_obj_t (*delete_name)(qstr qst); + mp_obj_t (*delete_global)(qstr qst); mp_obj_t (*make_closure_from_raw_code)(const mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args); - void (*arg_check_num_sig)(size_t n_args, size_t n_kw, uint32_t sig); - void (*setup_code_state)(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args); + int (*arg_check_num_sig)(size_t n_args, size_t n_kw, uint32_t sig); + mp_obj_t (*setup_code_state)(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args); mp_int_t (*small_int_floor_divide)(mp_int_t num, mp_int_t denom); mp_int_t (*small_int_modulo)(mp_int_t dividend, mp_int_t divisor); bool (*yield_from)(mp_obj_t gen, mp_obj_t send_value, mp_obj_t *ret_value); void *setjmp; - // Additional entries for dynamic runtime, starts at index 50 + // Additional entries for dynamic runtime, starts at index 53 void *(*memset_)(void *s, int c, size_t n); void *(*memmove_)(void *dest, const void *src, size_t n); void *(*realloc_)(void *ptr, size_t n_bytes, bool allow_move); @@ -154,7 +160,7 @@ typedef struct _mp_fun_table_t { mp_obj_t (*obj_new_float_from_d)(double d); float (*obj_get_float_to_f)(mp_obj_t o); double (*obj_get_float_to_d)(mp_obj_t o); - void (*get_buffer_raise)(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); + bool (*get_buffer_raise)(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); const mp_stream_p_t *(*get_stream_raise)(mp_obj_t self_in, int flags); const mp_print_t *plat_print; const mp_obj_type_t *type_type; diff --git a/py/nlr.h b/py/nlr.h index 3be3eb58cc794..5946b7dd3a64a 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -115,6 +115,7 @@ struct _nlr_buf_t { // Helper macro to use at the start of a specific nlr_jump implementation #define MP_NLR_JUMP_HEAD(val, top) \ + nlr_jump_fail(val); \ nlr_buf_t **_top_ptr = &MP_STATE_THREAD(nlr_top); \ nlr_buf_t *top = *_top_ptr; \ if (top == NULL) { \ diff --git a/py/obj.c b/py/obj.c index 4588d896a5200..340ba0a954f0f 100644 --- a/py/obj.c +++ b/py/obj.c @@ -58,7 +58,9 @@ const char *mp_obj_get_type_str(mp_const_obj_t o_in) { void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { // There can be data structures nested too deep, or just recursive - MP_STACK_CHECK(); + if (MP_STACK_CHECK()) { + return; + } #ifndef NDEBUG if (o_in == MP_OBJ_NULL) { mp_print_str(print, "(nil)"); @@ -236,6 +238,9 @@ mp_int_t mp_obj_get_int(mp_const_obj_t arg) { return mp_obj_int_get_checked(arg); } else { mp_obj_t res = mp_unary_op(MP_UNARY_OP_INT, (mp_obj_t)arg); + if (res == MP_OBJ_NULL) { + return 0; // TODO caller should check for error + } return mp_obj_int_get_checked(res); } } @@ -295,18 +300,19 @@ mp_float_t mp_obj_get_float(mp_obj_t arg) { if (!mp_obj_get_float_maybe(arg, &val)) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("can't convert to float"); + mp_raise_TypeError_o("can't convert to float"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to float", mp_obj_get_type_str(arg))); } + return 0; } return val; } #if MICROPY_PY_BUILTINS_COMPLEX -void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { +int mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { if (arg == mp_const_false) { *real = 0; *imag = 0; @@ -328,29 +334,34 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { mp_obj_complex_get(arg, real, imag); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("can't convert to complex"); + mp_raise_TypeError_o("can't convert to complex"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to complex", mp_obj_get_type_str(arg))); } + return 1; } + return 0; } #endif #endif // note: returned value in *items may point to the interior of a GC block -void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items) { +int mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items) { if (mp_obj_is_type(o, &mp_type_tuple)) { mp_obj_tuple_get(o, len, items); + return 0; } else if (mp_obj_is_type(o, &mp_type_list)) { mp_obj_list_get(o, len, items); + return 0; } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("expected tuple/list"); + mp_raise_TypeError_o("expected tuple/list"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' isn't a tuple or list", mp_obj_get_type_str(o))); } + return 1; } } @@ -375,12 +386,13 @@ size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool i = MP_OBJ_SMALL_INT_VALUE(index); } else if (!mp_obj_get_int_maybe(index, &i)) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("indices must be integers"); + mp_raise_TypeError_o("indices must be integers"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%q indices must be integers, not %s", type->name, mp_obj_get_type_str(index))); } + return (size_t)-1; } if (i < 0) { @@ -395,11 +407,12 @@ size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool } else { if (i < 0 || (mp_uint_t)i >= len) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_IndexError, "index out of range"); + mp_raise_msg_o(&mp_type_IndexError, "index out of range"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, + mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "%q index out of range", type->name)); } + return (size_t)-1; } } @@ -430,9 +443,9 @@ mp_obj_t mp_obj_len(mp_obj_t o_in) { mp_obj_t len = mp_obj_len_maybe(o_in); if (len == MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("object has no len"); + return mp_raise_TypeError_o("object has no len"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in))); } } else { @@ -467,27 +480,31 @@ mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) { if (ret != MP_OBJ_NULL) { return ret; } + // MP_OBJ_NULL return can mean either unsupported or exception + if (MP_STATE_THREAD(active_exception) != NULL) { + return MP_OBJ_NULL; + } // TODO: call base classes here? } if (value == MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("object doesn't support item deletion"); + return mp_raise_TypeError_o("object doesn't support item deletion"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object doesn't support item deletion", mp_obj_get_type_str(base))); } } else if (value == MP_OBJ_SENTINEL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("object isn't subscriptable"); + return mp_raise_TypeError_o("object isn't subscriptable"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object isn't subscriptable", mp_obj_get_type_str(base))); } } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("object doesn't support item assignment"); + return mp_raise_TypeError_o("object doesn't support item assignment"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object doesn't support item assignment", mp_obj_get_type_str(base))); } } @@ -517,10 +534,12 @@ bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) { return true; } -void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) { +bool mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) { if (!mp_get_buffer(obj, bufinfo, flags)) { - mp_raise_TypeError("object with buffer protocol required"); + mp_raise_TypeError_o("object with buffer protocol required"); + return false; } + return true; } mp_obj_t mp_generic_unary_op(mp_unary_op_t op, mp_obj_t o_in) { diff --git a/py/obj.h b/py/obj.h index 5b54892ce8090..7c635383f79a6 100644 --- a/py/obj.h +++ b/py/obj.h @@ -455,7 +455,7 @@ typedef struct _mp_buffer_p_t { mp_int_t (*get_buffer)(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); } mp_buffer_p_t; bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); -void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); +bool mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); struct _mp_obj_type_t { // A type is an object so must start with this entry, which points to mp_type_type. @@ -689,9 +689,9 @@ bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value); #if MICROPY_PY_BUILTINS_FLOAT mp_float_t mp_obj_get_float(mp_obj_t self_in); bool mp_obj_get_float_maybe(mp_obj_t arg, mp_float_t *value); -void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag); +int mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag); #endif -void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items); // *items may point inside a GC block +int mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items); // *items may point inside a GC block void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items); // *items may point inside a GC block size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool is_slice); mp_obj_t mp_obj_id(mp_obj_t o_in); @@ -845,7 +845,7 @@ typedef struct { void mp_seq_multiply(const void *items, size_t item_sz, size_t len, size_t times, void *dest); #if MICROPY_PY_BUILTINS_SLICE -bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes); +int mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes); #endif #define mp_seq_copy(dest, src, len, item_t) memcpy(dest, src, len * sizeof(item_t)) #define mp_seq_cat(dest, src1, len1, src2, len2, item_t) { memcpy(dest, src1, (len1) * sizeof(item_t)); memcpy(dest + (len1), src2, (len2) * sizeof(item_t)); } diff --git a/py/objarray.c b/py/objarray.c index c19617d4e1dd6..22ef4d3a4e864 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -95,7 +95,13 @@ STATIC void array_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY STATIC mp_obj_array_t *array_new(char typecode, size_t n) { int typecode_size = mp_binary_get_size('@', typecode, NULL); + if (typecode_size == 0) { + return NULL; + } mp_obj_array_t *o = m_new_obj(mp_obj_array_t); + if (o == NULL) { + return NULL; + } #if MICROPY_PY_BUILTINS_BYTEARRAY && MICROPY_PY_ARRAY o->base.type = (typecode == BYTEARRAY_TYPECODE) ? &mp_type_bytearray : &mp_type_array; #elif MICROPY_PY_BUILTINS_BYTEARRAY @@ -112,6 +118,7 @@ STATIC mp_obj_array_t *array_new(char typecode, size_t n) { #endif #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY +#include STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) { // bytearrays can be raw-initialised from anything with the buffer protocol // other arrays can only be raw-initialised from bytes and bytearray objects @@ -127,6 +134,9 @@ STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) { size_t sz = mp_binary_get_size('@', typecode, NULL); size_t len = bufinfo.len / sz; mp_obj_array_t *o = array_new(typecode, len); + if (o == NULL) { + return MP_OBJ_NULL; + } memcpy(o->items, bufinfo.buf, len * sz); return MP_OBJ_FROM_PTR(o); } @@ -141,17 +151,23 @@ STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) { } mp_obj_array_t *array = array_new(typecode, len); + if (array == NULL) { + return MP_OBJ_NULL; + } mp_obj_t iterable = mp_getiter(initializer, NULL); mp_obj_t item; size_t i = 0; - while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + while ((item = mp_iternext2(iterable)) != MP_OBJ_NULL) { if (len == 0) { array_append(MP_OBJ_FROM_PTR(array), item); } else { mp_binary_set_val_array(typecode, array->items, i++, item); } } + if (mp_iternext_had_exc()) { + return MP_OBJ_NULL; + } return MP_OBJ_FROM_PTR(array); } @@ -187,7 +203,13 @@ STATIC mp_obj_t bytearray_make_new(const mp_obj_type_t *type_in, size_t n_args, } else if (mp_obj_is_int(args[0])) { // 1 arg, an integer: construct a blank bytearray of that length mp_uint_t len = mp_obj_get_int(args[0]); + if (MP_STATE_THREAD(active_exception) != NULL) { + return MP_OBJ_NULL; + } mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, len); + if (o == NULL) { + return MP_OBJ_NULL; + } memset(o->items, 0, len); return MP_OBJ_FROM_PTR(o); } else { @@ -201,6 +223,9 @@ STATIC mp_obj_t bytearray_make_new(const mp_obj_type_t *type_in, size_t n_args, mp_obj_t mp_obj_new_memoryview(byte typecode, size_t nitems, void *items) { mp_obj_array_t *self = m_new_obj(mp_obj_array_t); + if (self == NULL) { + return MP_OBJ_NULL; + } self->base.type = &mp_type_memoryview; self->typecode = typecode; self->memview_offset = 0; @@ -263,7 +288,9 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs mp_buffer_info_t lhs_bufinfo; mp_buffer_info_t rhs_bufinfo; array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ); - mp_get_buffer_raise(rhs_in, &rhs_bufinfo, MP_BUFFER_READ); + if (!mp_get_buffer_raise(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) { + return MP_OBJ_NULL; + } size_t sz = mp_binary_get_size('@', lhs_bufinfo.typecode, NULL); @@ -272,6 +299,9 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs // note: lhs->len is element count of lhs, lhs_bufinfo.len is byte count mp_obj_array_t *res = array_new(lhs_bufinfo.typecode, lhs->len + rhs_len); + if (res == NULL) { + return MP_OBJ_NULL; + } mp_seq_cat((byte*)res->items, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_len * sz, byte); return MP_OBJ_FROM_PTR(res); } @@ -282,7 +312,9 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs return MP_OBJ_NULL; // op not supported } #endif - array_extend(lhs_in, rhs_in); + if (array_extend(lhs_in, rhs_in) == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } return lhs_in; } @@ -303,7 +335,7 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs // Otherwise, can only look for a scalar numeric value in an array if (mp_obj_is_int(rhs_in) || mp_obj_is_float(rhs_in)) { - mp_raise_NotImplementedError(NULL); + return mp_raise_NotImplementedError_o(NULL); } return mp_const_false; @@ -334,11 +366,18 @@ STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) { if (self->free == 0) { size_t item_sz = mp_binary_get_size('@', self->typecode, NULL); // TODO: alloc policy + byte *new_items = m_renew(byte, self->items, item_sz * self->len, item_sz * (self->len + 8)); + if (new_items == NULL) { + return MP_OBJ_NULL; + } self->free = 8; - self->items = m_renew(byte, self->items, item_sz * self->len, item_sz * (self->len + self->free)); + self->items = new_items; mp_seq_clear(self->items, self->len + 1, self->len + self->free, item_sz); } mp_binary_set_val_array(self->typecode, self->items, self->len, arg); + if (MP_STATE_THREAD(active_exception) != NULL) { + return MP_OBJ_NULL; + } // only update length/free if set succeeded self->len++; self->free--; @@ -364,7 +403,11 @@ STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in) { // make sure we have enough room to extend // TODO: alloc policy; at the moment we go conservative if (self->free < len) { - self->items = m_renew(byte, self->items, (self->len + self->free) * sz, (self->len + len) * sz); + byte *new_items = m_renew(byte, self->items, (self->len + self->free) * sz, (self->len + len) * sz); + if (new_items == NULL) { + return MP_OBJ_NULL; + } + self->items = new_items; self->free = 0; } else { self->free -= len; @@ -392,7 +435,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value if (mp_obj_is_type(index_in, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &slice)) { - mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported"); + return mp_raise_NotImplementedError_o("only slices with step=1 (aka None) are supported"); } if (value != MP_OBJ_SENTINEL) { #if MICROPY_PY_ARRAY_SLICE_ASSIGN @@ -405,7 +448,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value mp_obj_array_t *src_slice = MP_OBJ_TO_PTR(value); if (item_sz != mp_binary_get_size('@', src_slice->typecode & TYPECODE_MASK, NULL)) { compat_error: - mp_raise_ValueError("lhs and rhs should be compatible"); + return mp_raise_ValueError_o("lhs and rhs should be compatible"); } src_len = src_slice->len; src_items = src_slice->items; @@ -423,7 +466,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value src_len = bufinfo.len; src_items = bufinfo.buf; } else { - mp_raise_NotImplementedError("array/bytes required on right side"); + return mp_raise_NotImplementedError_o("array/bytes required on right side"); } // TODO: check src/dst compat @@ -444,9 +487,12 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value if (len_adj > 0) { if (len_adj > o->free) { // TODO: alloc policy; at the moment we go conservative - o->items = m_renew(byte, o->items, (o->len + o->free) * item_sz, (o->len + len_adj) * item_sz); + dest_items = m_renew(byte, o->items, (o->len + o->free) * item_sz, (o->len + len_adj) * item_sz); + if (dest_items == NULL) { + return MP_OBJ_NULL; + } + o->items = dest_items; o->free = len_adj; - dest_items = o->items; } mp_seq_replace_slice_grow_inplace(dest_items, o->len, slice.start, slice.stop, src_items, src_len, len_adj, item_sz); @@ -472,6 +518,9 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value #if MICROPY_PY_BUILTINS_MEMORYVIEW if (o->base.type == &mp_type_memoryview) { res = m_new_obj(mp_obj_array_t); + if (res == NULL) { + return MP_OBJ_NULL; + } *res = *o; res->memview_offset += slice.start; res->len = slice.stop - slice.start; @@ -479,6 +528,9 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value #endif { res = array_new(o->typecode, slice.stop - slice.start); + if (res == NULL) { + return MP_OBJ_NULL; + } memcpy(res->items, (uint8_t*)o->items + slice.start * sz, (slice.stop - slice.start) * sz); } return MP_OBJ_FROM_PTR(res); @@ -486,6 +538,9 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value #endif { size_t index = mp_get_index(o->base.type, o->len, index_in, false); + if (index == (size_t)-1) { + return MP_OBJ_NULL; + } #if MICROPY_PY_BUILTINS_MEMORYVIEW if (o->base.type == &mp_type_memoryview) { index += o->memview_offset; diff --git a/py/objcomplex.c b/py/objcomplex.c index bf6fb51dc558e..774c9877fcca1 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -172,7 +172,9 @@ void mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag) { mp_obj_t mp_obj_complex_binary_op(mp_binary_op_t op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in) { mp_float_t rhs_real, rhs_imag; - mp_obj_get_complex(rhs_in, &rhs_real, &rhs_imag); // can be any type, this function will convert to float (if possible) + if (mp_obj_get_complex(rhs_in, &rhs_real, &rhs_imag)) { // can be any type, this function will convert to float (if possible) + return MP_OBJ_NULL; + } switch (op) { case MP_BINARY_OP_ADD: case MP_BINARY_OP_INPLACE_ADD: @@ -195,13 +197,13 @@ mp_obj_t mp_obj_complex_binary_op(mp_binary_op_t op, mp_float_t lhs_real, mp_flo } case MP_BINARY_OP_FLOOR_DIVIDE: case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: - mp_raise_TypeError("can't truncate-divide a complex number"); + return mp_raise_TypeError_o("can't truncate-divide a complex number"); case MP_BINARY_OP_TRUE_DIVIDE: case MP_BINARY_OP_INPLACE_TRUE_DIVIDE: if (rhs_imag == 0) { if (rhs_real == 0) { - mp_raise_msg(&mp_type_ZeroDivisionError, "complex divide by zero"); + return mp_raise_msg_o(&mp_type_ZeroDivisionError, "complex divide by zero"); } lhs_real /= rhs_real; lhs_imag /= rhs_real; @@ -229,7 +231,7 @@ mp_obj_t mp_obj_complex_binary_op(mp_binary_op_t op, mp_float_t lhs_real, mp_flo if (rhs_imag == 0 && rhs_real >= 0) { lhs_real = (rhs_real == 0); } else { - mp_raise_msg(&mp_type_ZeroDivisionError, "0.0 to a complex power"); + return mp_raise_msg_o(&mp_type_ZeroDivisionError, "0.0 to a complex power"); } } else { mp_float_t ln1 = MICROPY_FLOAT_C_FUN(log)(abs1); diff --git a/py/objdeque.c b/py/objdeque.c index 1cff1f8d3b411..e6e77e3cbcfd6 100644 --- a/py/objdeque.c +++ b/py/objdeque.c @@ -43,18 +43,20 @@ typedef struct _mp_obj_deque_t { } mp_obj_deque_t; STATIC mp_obj_t deque_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 2, 3, false); + if (mp_arg_check_num(n_args, n_kw, 2, 3, false)) { + return MP_OBJ_NULL; + } /* Initialization from existing sequence is not supported, so an empty tuple must be passed as such. */ if (args[0] != mp_const_empty_tuple) { - mp_raise_ValueError(NULL); + return mp_raise_ValueError_o(NULL); } // Protect against -1 leading to zero-length allocation and bad array access mp_int_t maxlen = mp_obj_get_int(args[1]); if (maxlen < 0) { - mp_raise_ValueError(NULL); + return mp_raise_ValueError_o(NULL); } mp_obj_deque_t *o = m_new_obj(mp_obj_deque_t); @@ -102,7 +104,7 @@ STATIC mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg) { } if (self->flags & FLAG_CHECK_OVERFLOW && new_i_put == self->i_get) { - mp_raise_msg(&mp_type_IndexError, "full"); + return mp_raise_msg_o(&mp_type_IndexError, "full"); } self->items[self->i_put] = arg; @@ -122,7 +124,7 @@ STATIC mp_obj_t deque_popleft(mp_obj_t self_in) { mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); if (self->i_get == self->i_put) { - mp_raise_msg(&mp_type_IndexError, "empty"); + return mp_raise_msg_o(&mp_type_IndexError, "empty"); } mp_obj_t ret = self->items[self->i_get]; diff --git a/py/objdict.c b/py/objdict.c index 7a43a85485ccb..ab01037e7be66 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -101,7 +101,9 @@ STATIC mp_obj_t dict_make_new(const mp_obj_type_t *type, size_t n_args, size_t n mp_obj_t args2[2] = {dict_out, args[0]}; // args[0] is always valid, even if it's not a positional arg mp_map_t kwargs; mp_map_init_fixed_table(&kwargs, n_kw, args + n_args); - dict_update(n_args + 1, args2, &kwargs); // dict_update will check that n_args + 1 == 1 or 2 + if (dict_update(n_args + 1, args2, &kwargs) == MP_OBJ_NULL) { // dict_update will check that n_args + 1 == 1 or 2 + return MP_OBJ_NULL; + } } return dict_out; } @@ -174,7 +176,7 @@ mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index) { mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP); if (elem == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, index)); + return mp_raise_o(mp_obj_new_exception_arg1(&mp_type_KeyError, index)); } else { return elem->value; } @@ -183,20 +185,24 @@ mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index) { STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (value == MP_OBJ_NULL) { // delete - mp_obj_dict_delete(self_in, index); + if (mp_obj_dict_delete(self_in, index) == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } return mp_const_none; } else if (value == MP_OBJ_SENTINEL) { // load mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP); if (elem == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, index)); + return mp_raise_o(mp_obj_new_exception_arg1(&mp_type_KeyError, index)); } else { return elem->value; } } else { // store - mp_obj_dict_store(self_in, index, value); + if (mp_obj_dict_store(self_in, index, value) == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } return mp_const_none; } } @@ -204,16 +210,20 @@ STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { /******************************************************************************/ /* dict methods */ -STATIC void mp_ensure_not_fixed(const mp_obj_dict_t *dict) { +STATIC int mp_ensure_not_fixed(const mp_obj_dict_t *dict) { if (dict->map.is_fixed) { - mp_raise_TypeError(NULL); + mp_raise_TypeError_o(NULL); + return 1; } + return 0; } STATIC mp_obj_t dict_clear(mp_obj_t self_in) { mp_check_self(mp_obj_is_dict_type(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); - mp_ensure_not_fixed(self); + if (mp_ensure_not_fixed(self)) { + return MP_OBJ_NULL; + } mp_map_clear(&self->map); @@ -272,14 +282,16 @@ STATIC mp_obj_t dict_get_helper(size_t n_args, const mp_obj_t *args, mp_map_look mp_check_self(mp_obj_is_dict_type(args[0])); mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); if (lookup_kind != MP_MAP_LOOKUP) { - mp_ensure_not_fixed(self); + if (mp_ensure_not_fixed(self)) { + return MP_OBJ_NULL; + } } mp_map_elem_t *elem = mp_map_lookup(&self->map, args[1], lookup_kind); mp_obj_t value; if (elem == NULL || elem->value == MP_OBJ_NULL) { if (n_args == 2) { if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, args[1])); + return mp_raise_o(mp_obj_new_exception_arg1(&mp_type_KeyError, args[1])); } else { value = mp_const_none; } @@ -316,11 +328,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_setdefault_obj, 2, 3, dict_setde STATIC mp_obj_t dict_popitem(mp_obj_t self_in) { mp_check_self(mp_obj_is_dict_type(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); - mp_ensure_not_fixed(self); + if (mp_ensure_not_fixed(self)) { + return MP_OBJ_NULL; + } size_t cur = 0; mp_map_elem_t *next = dict_iter_next(self, &cur); if (next == NULL) { - mp_raise_msg(&mp_type_KeyError, "popitem(): dictionary is empty"); + return mp_raise_msg_o(&mp_type_KeyError, "popitem(): dictionary is empty"); } self->map.used--; mp_obj_t items[] = {next->key, next->value}; @@ -335,9 +349,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem); STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { mp_check_self(mp_obj_is_dict_type(args[0])); mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); - mp_ensure_not_fixed(self); + if (mp_ensure_not_fixed(self)) { + return MP_OBJ_NULL; + } - mp_arg_check_num(n_args, kwargs->used, 1, 2, true); + if (mp_arg_check_num(n_args, kwargs->used, 1, 2, true)) { + return MP_OBJ_NULL; + } if (n_args == 2) { // given a positional argument @@ -363,7 +381,7 @@ STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwarg if (key == MP_OBJ_STOP_ITERATION || value == MP_OBJ_STOP_ITERATION || stop != MP_OBJ_STOP_ITERATION) { - mp_raise_ValueError("dict update sequence has wrong length"); + return mp_raise_ValueError_o("dict update sequence has wrong length"); } else { mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; } @@ -493,6 +511,9 @@ STATIC const mp_obj_type_t dict_view_type = { STATIC mp_obj_t mp_obj_new_dict_view(mp_obj_t dict, mp_dict_view_kind_t kind) { mp_obj_dict_view_t *o = m_new_obj(mp_obj_dict_view_t); + if (o == NULL) { + return MP_OBJ_NULL; + } o->base.type = &dict_view_type; o->dict = dict; o->kind = kind; @@ -591,6 +612,9 @@ void mp_obj_dict_init(mp_obj_dict_t *dict, size_t n_args) { mp_obj_t mp_obj_new_dict(size_t n_args) { mp_obj_dict_t *o = m_new_obj(mp_obj_dict_t); + if (o == NULL) { + return MP_OBJ_NULL; + } mp_obj_dict_init(o, n_args); return MP_OBJ_FROM_PTR(o); } @@ -603,13 +627,22 @@ size_t mp_obj_dict_len(mp_obj_t self_in) { mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) { mp_check_self(mp_obj_is_dict_type(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); - mp_ensure_not_fixed(self); - mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; + if (mp_ensure_not_fixed(self)) { + return MP_OBJ_NULL; + } + mp_map_elem_t *elem = mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + if (elem == NULL) { + // exception + return MP_OBJ_NULL; + } + elem->value = value; return self_in; } mp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key) { mp_obj_t args[2] = {self_in, key}; - dict_get_helper(2, args, MP_MAP_LOOKUP_REMOVE_IF_FOUND); + if (dict_get_helper(2, args, MP_MAP_LOOKUP_REMOVE_IF_FOUND) == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } return self_in; } diff --git a/py/objenumerate.c b/py/objenumerate.c index 243c9f83aa8f8..4ce4f3e144ba0 100644 --- a/py/objenumerate.c +++ b/py/objenumerate.c @@ -50,8 +50,10 @@ STATIC mp_obj_t enumerate_make_new(const mp_obj_type_t *type, size_t n_args, siz struct { mp_arg_val_t iterable, start; } arg_vals; - mp_arg_parse_all_kw_array(n_args, n_kw, args, - MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&arg_vals); + if (mp_arg_parse_all_kw_array(n_args, n_kw, args, + MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&arg_vals)) { + return MP_OBJ_NULL; + } // create enumerate object mp_obj_enumerate_t *o = m_new_obj(mp_obj_enumerate_t); @@ -81,6 +83,9 @@ STATIC mp_obj_t enumerate_iternext(mp_obj_t self_in) { assert(mp_obj_is_type(self_in, &mp_type_enumerate)); mp_obj_enumerate_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t next = mp_iternext(self->iter); + if (next == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } if (next == MP_OBJ_STOP_ITERATION) { return MP_OBJ_STOP_ITERATION; } else { diff --git a/py/objfilter.c b/py/objfilter.c index 41b2a3bc5f227..543f6b73a93ac 100644 --- a/py/objfilter.c +++ b/py/objfilter.c @@ -47,7 +47,7 @@ STATIC mp_obj_t filter_iternext(mp_obj_t self_in) { mp_check_self(mp_obj_is_type(self_in, &mp_type_filter)); mp_obj_filter_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t next; - while ((next = mp_iternext(self->iter)) != MP_OBJ_STOP_ITERATION) { + while ((next = mp_iternext2(self->iter)) != MP_OBJ_NULL) { mp_obj_t val; if (self->fun != mp_const_none) { val = mp_call_function_n_kw(self->fun, 1, 0, &next); @@ -58,6 +58,9 @@ STATIC mp_obj_t filter_iternext(mp_obj_t self_in) { return next; } } + if (mp_iternext_had_exc()) { + return MP_OBJ_NULL; + } return MP_OBJ_STOP_ITERATION; } diff --git a/py/objfloat.c b/py/objfloat.c index 3da549bb25a5c..ef13606fa76e5 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -130,7 +130,9 @@ STATIC void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t STATIC mp_obj_t float_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)type_in; - mp_arg_check_num(n_args, n_kw, 0, 1, false); + if (mp_arg_check_num(n_args, n_kw, 0, 1, false)) { + return MP_OBJ_NULL; + } switch (n_args) { case 0: @@ -147,7 +149,11 @@ STATIC mp_obj_t float_make_new(const mp_obj_type_t *type_in, size_t n_args, size return args[0]; } else { // something else, try to cast it to a float - return mp_obj_new_float(mp_obj_get_float(args[0])); + mp_float_t val = mp_obj_get_float(args[0]); + if (MP_STATE_THREAD(active_exception) != NULL) { + return MP_OBJ_NULL; + } + return mp_obj_new_float(val); } } } @@ -261,7 +267,7 @@ mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: if (rhs_val == 0) { zero_division_error: - mp_raise_msg(&mp_type_ZeroDivisionError, "divide by zero"); + return mp_raise_msg_o(&mp_type_ZeroDivisionError, "divide by zero"); } // Python specs require that x == (x//y)*y + (x%y) so we must // call divmod to compute the correct floor division, which @@ -299,7 +305,7 @@ mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t #if MICROPY_PY_BUILTINS_COMPLEX return mp_obj_complex_binary_op(MP_BINARY_OP_POWER, lhs_val, 0, rhs_in); #else - mp_raise_ValueError("complex values not supported"); + return mp_raise_ValueError_o("complex values not supported"); #endif } lhs_val = MICROPY_FLOAT_C_FUN(pow)(lhs_val, rhs_val); diff --git a/py/objfun.c b/py/objfun.c index 7051f3476d456..5349d220fc039 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -52,7 +52,9 @@ STATIC mp_obj_t fun_builtin_0_call(mp_obj_t self_in, size_t n_args, size_t n_kw, (void)args; assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_0)); mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); - mp_arg_check_num(n_args, n_kw, 0, 0, false); + if (mp_arg_check_num(n_args, n_kw, 0, 0, false)) { + return MP_OBJ_NULL; + } return self->fun._0(); } @@ -66,7 +68,9 @@ const mp_obj_type_t mp_type_fun_builtin_0 = { STATIC mp_obj_t fun_builtin_1_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_1)); mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); - mp_arg_check_num(n_args, n_kw, 1, 1, false); + if (mp_arg_check_num(n_args, n_kw, 1, 1, false)) { + return MP_OBJ_NULL; + } return self->fun._1(args[0]); } @@ -80,7 +84,9 @@ const mp_obj_type_t mp_type_fun_builtin_1 = { STATIC mp_obj_t fun_builtin_2_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_2)); mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); - mp_arg_check_num(n_args, n_kw, 2, 2, false); + if (mp_arg_check_num(n_args, n_kw, 2, 2, false)) { + return MP_OBJ_NULL; + } return self->fun._2(args[0], args[1]); } @@ -94,7 +100,9 @@ const mp_obj_type_t mp_type_fun_builtin_2 = { STATIC mp_obj_t fun_builtin_3_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_3)); mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); - mp_arg_check_num(n_args, n_kw, 3, 3, false); + if (mp_arg_check_num(n_args, n_kw, 3, 3, false)) { + return MP_OBJ_NULL; + } return self->fun._3(args[0], args[1], args[2]); } @@ -110,7 +118,9 @@ STATIC mp_obj_t fun_builtin_var_call(mp_obj_t self_in, size_t n_args, size_t n_k mp_obj_fun_builtin_var_t *self = MP_OBJ_TO_PTR(self_in); // check number of arguments - mp_arg_check_num_sig(n_args, n_kw, self->sig); + if (mp_arg_check_num_sig(n_args, n_kw, self->sig)) { + return MP_OBJ_NULL; + } if (self->sig & 1) { // function allows keywords @@ -201,16 +211,21 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) { + n_exc_stack * sizeof(mp_exc_stack_t); \ } -#define INIT_CODESTATE(code_state, _fun_bc, _n_state, n_args, n_kw, args) \ +static inline mp_obj_t INIT_CODESTATE(mp_code_state_t *code_state, mp_obj_fun_bc_t *_fun_bc, size_t _n_state, size_t n_args, size_t n_kw, const mp_obj_t *args) { code_state->fun_bc = _fun_bc; \ code_state->ip = 0; \ code_state->n_state = _n_state; \ - mp_setup_code_state(code_state, n_args, n_kw, args); \ + // TODO can we save old_globals before this call? + mp_obj_t ret = mp_setup_code_state(code_state, n_args, n_kw, args); \ code_state->old_globals = mp_globals_get(); + return ret; +} #if MICROPY_STACKLESS mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - MP_STACK_CHECK(); + if (MP_STACK_CHECK()) { + return NULL; + } mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); size_t n_state, state_size; @@ -231,7 +246,16 @@ mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args } #endif - INIT_CODESTATE(code_state, self, n_state, n_args, n_kw, args); + // TODO write test where this fails + if (INIT_CODESTATE(code_state, self, n_state, n_args, n_kw, args) == MP_OBJ_NULL) { + #if MICROPY_ENABLE_PYSTACK + mp_nonlocal_free(code_state, sizeof(mp_code_state_t)); + #else + m_del_var(mp_code_state_t, byte, state_size, code_state); + #endif + // exception + return NULL; + } // execute the byte code with the correct globals context mp_globals_set(self->globals); @@ -241,7 +265,9 @@ mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args #endif STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - MP_STACK_CHECK(); + if (MP_STACK_CHECK()) { + return MP_OBJ_NULL; + } DEBUG_printf("Input n_args: " UINT_FMT ", n_kw: " UINT_FMT "\n", n_args, n_kw); DEBUG_printf("Input pos args: "); @@ -276,7 +302,18 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const } #endif - INIT_CODESTATE(code_state, self, n_state, n_args, n_kw, args); + if (INIT_CODESTATE(code_state, self, n_state, n_args, n_kw, args) == MP_OBJ_NULL) { + // exception + #if MICROPY_ENABLE_PYSTACK + mp_pystack_free(code_state); + #else + // free the state if it was allocated on the heap + if (state_size != 0) { + m_del_var(mp_code_state_t, byte, state_size, code_state); + } + #endif + return MP_OBJ_NULL; + } // execute the byte code with the correct globals context mp_globals_set(self->globals); @@ -337,7 +374,7 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const if (vm_return_kind == MP_VM_RETURN_NORMAL) { return result; } else { // MP_VM_RETURN_EXCEPTION - nlr_raise(result); + return mp_raise_o(result); } } @@ -379,6 +416,9 @@ mp_obj_t mp_obj_new_fun_bc(mp_obj_t def_args_in, mp_obj_t def_kw_args, const byt n_extra_args += 1; } mp_obj_fun_bc_t *o = m_new_obj_var(mp_obj_fun_bc_t, mp_obj_t, n_extra_args); + if (o == NULL) { + return MP_OBJ_NULL; + } o->base.type = &mp_type_fun_bc; o->globals = mp_globals_get(); o->bytecode = code; @@ -398,7 +438,9 @@ mp_obj_t mp_obj_new_fun_bc(mp_obj_t def_args_in, mp_obj_t def_kw_args, const byt #if MICROPY_EMIT_NATIVE STATIC mp_obj_t fun_native_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - MP_STACK_CHECK(); + if (MP_STACK_CHECK()) { + return MP_OBJ_NULL; + } mp_obj_fun_bc_t *self = self_in; mp_call_fun_t fun = MICROPY_MAKE_POINTER_CALLABLE((void*)self->bytecode); return fun(self_in, n_args, n_kw, args); diff --git a/py/objgenerator.c b/py/objgenerator.c index 903a6469cccd4..9e4017fc224f5 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -67,6 +67,7 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons o->code_state.fun_bc = self_fun; o->code_state.ip = 0; o->code_state.n_state = n_state; + // TODO write test where this call fails mp_setup_code_state(&o->code_state, n_args, n_kw, args); return MP_OBJ_FROM_PTR(o); } @@ -112,6 +113,7 @@ STATIC mp_obj_t native_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_k o->code_state.fun_bc = self_fun; o->code_state.ip = (const byte*)prelude_offset; o->code_state.n_state = n_state; + // TODO write test where this call fails mp_setup_code_state(&o->code_state, n_args, n_kw, args); // Indicate we are a native function, which doesn't use this variable @@ -146,7 +148,11 @@ STATIC void gen_instance_print(const mp_print_t *print, mp_obj_t self_in, mp_pri } mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) { - MP_STACK_CHECK(); + if (MP_STACK_CHECK()) { + *ret_val = MP_OBJ_FROM_PTR(MP_STATE_THREAD(active_exception)); + MP_STATE_THREAD(active_exception) = NULL; + return MP_VM_RETURN_EXCEPTION; + } mp_check_self(mp_obj_is_type(self_in, &mp_type_gen_instance)); mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in); if (self->code_state.ip == 0) { @@ -157,7 +163,10 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ // Ensure the generator cannot be reentered during execution if (self->pend_exc == MP_OBJ_NULL) { - mp_raise_ValueError("generator already executing"); + mp_raise_ValueError_o("generator already executing"); + *ret_val = MP_OBJ_FROM_PTR(MP_STATE_THREAD(active_exception)); + MP_STATE_THREAD(active_exception) = NULL; + return MP_VM_RETURN_EXCEPTION; } #if MICROPY_PY_GENERATOR_PEND_THROW @@ -170,7 +179,10 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ // If the generator is started, allow sending a value. if (self->code_state.sp == self->code_state.state - 1) { if (send_value != mp_const_none) { - mp_raise_TypeError("can't send non-None value to a just-started generator"); + mp_raise_TypeError_o("can't send non-None value to a just-started generator"); + *ret_val = MP_OBJ_FROM_PTR(MP_STATE_THREAD(active_exception)); + MP_STATE_THREAD(active_exception) = NULL; + return MP_VM_RETURN_EXCEPTION; } } else { *self->code_state.sp = send_value; @@ -222,7 +234,16 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ case MP_VM_RETURN_EXCEPTION: { self->code_state.ip = 0; + // TODO probably makes sense to have bytecode also place exception in active_exception + #if MICROPY_EMIT_NATIVE + if (self->code_state.exc_sp_idx == MP_CODE_STATE_EXC_SP_IDX_SENTINEL) { + *ret_val = MP_STATE_THREAD(active_exception); + MP_STATE_THREAD(active_exception) = NULL; // clear it + } else + #endif + { *ret_val = self->code_state.state[0]; + } // PEP479: if StopIteration is raised inside a generator it is replaced with RuntimeError if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(*ret_val)), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { *ret_val = mp_obj_new_exception_msg(&mp_type_RuntimeError, "generator raised StopIteration"); @@ -243,14 +264,14 @@ STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_o if (ret == mp_const_none || ret == MP_OBJ_STOP_ITERATION) { return MP_OBJ_STOP_ITERATION; } else { - nlr_raise(mp_obj_new_exception_args(&mp_type_StopIteration, 1, &ret)); + return mp_raise_o(mp_obj_new_exception_args(&mp_type_StopIteration, 1, &ret)); } case MP_VM_RETURN_YIELD: return ret; case MP_VM_RETURN_EXCEPTION: - nlr_raise(ret); + return mp_raise_o(ret); } } @@ -261,7 +282,7 @@ STATIC mp_obj_t gen_instance_iternext(mp_obj_t self_in) { STATIC mp_obj_t gen_instance_send(mp_obj_t self_in, mp_obj_t send_value) { mp_obj_t ret = gen_resume_and_raise(self_in, send_value, MP_OBJ_NULL); if (ret == MP_OBJ_STOP_ITERATION) { - nlr_raise(mp_obj_new_exception(&mp_type_StopIteration)); + return mp_raise_o(mp_obj_new_exception(&mp_type_StopIteration)); } else { return ret; } @@ -288,7 +309,7 @@ STATIC mp_obj_t gen_instance_throw(size_t n_args, const mp_obj_t *args) { mp_obj_t ret = gen_resume_and_raise(args[0], mp_const_none, exc); if (ret == MP_OBJ_STOP_ITERATION) { - nlr_raise(mp_obj_new_exception(&mp_type_StopIteration)); + return mp_raise_o(mp_obj_new_exception(&mp_type_StopIteration)); } else { return ret; } @@ -299,7 +320,7 @@ STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) { mp_obj_t ret; switch (mp_obj_gen_resume(self_in, mp_const_none, MP_OBJ_FROM_PTR(&mp_const_GeneratorExit_obj), &ret)) { case MP_VM_RETURN_YIELD: - mp_raise_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit"); + return mp_raise_msg_o(&mp_type_RuntimeError, "generator ignored GeneratorExit"); // Swallow GeneratorExit (== successful close), and re-raise any other case MP_VM_RETURN_EXCEPTION: @@ -307,7 +328,7 @@ STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) { if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(ret)), MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) { return mp_const_none; } - nlr_raise(ret); + return mp_raise_o(ret); default: // The only choice left is MP_VM_RETURN_NORMAL which is successful close @@ -320,7 +341,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_close_obj, gen_instance_close); STATIC mp_obj_t gen_instance_pend_throw(mp_obj_t self_in, mp_obj_t exc_in) { mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in); if (self->pend_exc == MP_OBJ_NULL) { - mp_raise_ValueError("generator already executing"); + return mp_raise_ValueError_o("generator already executing"); } mp_obj_t prev = self->pend_exc; self->pend_exc = exc_in; diff --git a/py/objgetitemiter.c b/py/objgetitemiter.c index ec41c2c5b11e5..70afa23bccce6 100644 --- a/py/objgetitemiter.c +++ b/py/objgetitemiter.c @@ -37,24 +37,22 @@ typedef struct _mp_obj_getitem_iter_t { STATIC mp_obj_t it_iternext(mp_obj_t self_in) { mp_obj_getitem_iter_t *self = MP_OBJ_TO_PTR(self_in); - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - // try to get next item - mp_obj_t value = mp_call_method_n_kw(1, 0, self->args); - self->args[2] = MP_OBJ_NEW_SMALL_INT(MP_OBJ_SMALL_INT_VALUE(self->args[2]) + 1); - nlr_pop(); - return value; - } else { + // try to get next item + mp_obj_t value = mp_call_method_n_kw(1, 0, self->args); + if (value == MP_OBJ_NULL) { // an exception was raised - mp_obj_type_t *t = (mp_obj_type_t*)((mp_obj_base_t*)nlr.ret_val)->type; + mp_obj_type_t *t = (mp_obj_type_t*)MP_STATE_THREAD(active_exception)->type; if (t == &mp_type_StopIteration || t == &mp_type_IndexError) { // return MP_OBJ_STOP_ITERATION instead of raising + MP_STATE_THREAD(active_exception) = NULL; return MP_OBJ_STOP_ITERATION; } else { // re-raise exception - nlr_jump(nlr.ret_val); + return MP_OBJ_NULL; } } + self->args[2] = MP_OBJ_NEW_SMALL_INT(MP_OBJ_SMALL_INT_VALUE(self->args[2]) + 1); + return value; } STATIC const mp_obj_type_t it_type = { diff --git a/py/objint.c b/py/objint.c index 2fdcf5864f288..8d7e14f3633e0 100644 --- a/py/objint.c +++ b/py/objint.c @@ -137,9 +137,9 @@ STATIC mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { int cl = fpclassify(val); if (cl == FP_INFINITE) { - mp_raise_msg(&mp_type_OverflowError, "can't convert inf to int"); + return mp_raise_msg_o(&mp_type_OverflowError, "can't convert inf to int"); } else if (cl == FP_NAN) { - mp_raise_ValueError("can't convert NaN to int"); + return mp_raise_ValueError_o("can't convert NaN to int"); } else { mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val); if (icl == MP_FP_CLASS_FIT_SMALLINT) { @@ -156,7 +156,7 @@ mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { return mp_obj_new_int_from_ll((long long)val); #endif } else { - mp_raise_ValueError("float too big"); + return mp_raise_ValueError_o("float too big"); } #endif } @@ -321,20 +321,17 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i // This is called only with strings whose value doesn't fit in SMALL_INT mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { - mp_raise_msg(&mp_type_OverflowError, "long int not supported in this build"); - return mp_const_none; + return mp_raise_msg_o(&mp_type_OverflowError, "long int not supported in this build"); } // This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT) mp_obj_t mp_obj_new_int_from_ll(long long val) { - mp_raise_msg(&mp_type_OverflowError, "small int overflow"); - return mp_const_none; + return mp_raise_msg_o(&mp_type_OverflowError, "small int overflow"); } // This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT) mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { - mp_raise_msg(&mp_type_OverflowError, "small int overflow"); - return mp_const_none; + return mp_raise_msg_o(&mp_type_OverflowError, "small int overflow"); } mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { @@ -343,16 +340,14 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) { return MP_OBJ_NEW_SMALL_INT(value); } - mp_raise_msg(&mp_type_OverflowError, "small int overflow"); - return mp_const_none; + return mp_raise_msg_o(&mp_type_OverflowError, "small int overflow"); } mp_obj_t mp_obj_new_int(mp_int_t value) { if (MP_SMALL_INT_FITS(value)) { return MP_OBJ_NEW_SMALL_INT(value); } - mp_raise_msg(&mp_type_OverflowError, "small int overflow"); - return mp_const_none; + return mp_raise_msg_o(&mp_type_OverflowError, "small int overflow"); } mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { @@ -422,7 +417,7 @@ STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *args) { mp_int_t len = mp_obj_get_int(args[1]); if (len < 0) { - mp_raise_ValueError(NULL); + return mp_raise_ValueError_o(NULL); } bool big_endian = args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little); diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 121fd03424893..997486843a1d8 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -225,7 +225,7 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: { if (mpz_is_zero(zrhs)) { zero_division_error: - mp_raise_msg(&mp_type_ZeroDivisionError, "divide by zero"); + return mp_raise_msg_o(&mp_type_ZeroDivisionError, "divide by zero"); } mpz_t rem; mpz_init_zero(&rem); mpz_divmod_inpl(&res->mpz, &rem, zlhs, zrhs); @@ -261,8 +261,11 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i case MP_BINARY_OP_RSHIFT: case MP_BINARY_OP_INPLACE_RSHIFT: { mp_int_t irhs = mp_obj_int_get_checked(rhs_in); + if (MP_STATE_THREAD(active_exception) != NULL) { + return MP_OBJ_NULL; + } if (irhs < 0) { - mp_raise_ValueError("negative shift count"); + return mp_raise_ValueError_o("negative shift count"); } if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) { mpz_shl_inpl(&res->mpz, zlhs, irhs); @@ -331,7 +334,7 @@ STATIC mpz_t *mp_mpz_for_int(mp_obj_t arg, mpz_t *temp) { mp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent, mp_obj_t modulus) { if (!mp_obj_is_int(base) || !mp_obj_is_int(exponent) || !mp_obj_is_int(modulus)) { - mp_raise_TypeError("pow() with 3 arguments requires integers"); + return mp_raise_TypeError_o("pow() with 3 arguments requires integers"); } else { mp_obj_t result = mp_obj_new_int_from_ull(0); // Use the _from_ull version as this forces an mpz int mp_obj_int_t *res_p = (mp_obj_int_t *) MP_OBJ_TO_PTR(result); @@ -406,7 +409,8 @@ mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { return value; } else { // overflow - mp_raise_msg(&mp_type_OverflowError, "overflow converting long int to machine word"); + mp_raise_msg_o(&mp_type_OverflowError, "overflow converting long int to machine word"); + return 0; // TODO callers must handle exceptions } } } diff --git a/py/objlist.c b/py/objlist.c index ec9d57fc7bdab..b984732679a3b 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -60,8 +60,13 @@ STATIC void list_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t k STATIC mp_obj_t list_extend_from_iter(mp_obj_t list, mp_obj_t iterable) { mp_obj_t iter = mp_getiter(iterable, NULL); mp_obj_t item; - while ((item = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { - mp_obj_list_append(list, item); + while ((item = mp_iternext2(iter)) != MP_OBJ_NULL) { + if (mp_obj_list_append(list, item) == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } + } + if (mp_iternext_had_exc()) { + return MP_OBJ_NULL; } return list; } @@ -100,6 +105,7 @@ STATIC mp_obj_t list_unary_op(mp_unary_op_t op, mp_obj_t self_in) { } } +#include STATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_list_t *o = MP_OBJ_TO_PTR(lhs); switch (op) { @@ -125,6 +131,9 @@ STATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { n = 0; } mp_obj_list_t *s = list_new(o->len * n); + if (s == NULL) { + return MP_OBJ_NULL; + } mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); return MP_OBJ_FROM_PTR(s); } @@ -157,8 +166,11 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (mp_obj_is_type(index, &mp_type_slice)) { mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); mp_bound_slice_t slice; - if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { - mp_raise_NotImplementedError(NULL); + int ret = mp_seq_get_fast_slice_indexes(self->len, index, &slice); + if (ret < 0) { + return MP_OBJ_NULL; + } else if (!ret) { + return mp_raise_NotImplementedError_o(NULL); } mp_int_t len_adj = slice.start - slice.stop; @@ -180,25 +192,40 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { #if MICROPY_PY_BUILTINS_SLICE if (mp_obj_is_type(index, &mp_type_slice)) { mp_bound_slice_t slice; - if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { + int ret = mp_seq_get_fast_slice_indexes(self->len, index, &slice); + if (ret < 0) { + return MP_OBJ_NULL; + } else if (!ret) { return mp_seq_extract_slice(self->len, self->items, &slice); } mp_obj_list_t *res = list_new(slice.stop - slice.start); + if (res == NULL) { + return MP_OBJ_NULL; + } mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t); return MP_OBJ_FROM_PTR(res); } #endif size_t index_val = mp_get_index(self->base.type, self->len, index, false); + if (index_val == (size_t)-1) { + // exception + return MP_OBJ_NULL; + } return self->items[index_val]; } else { #if MICROPY_PY_BUILTINS_SLICE if (mp_obj_is_type(index, &mp_type_slice)) { mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); size_t value_len; mp_obj_t *value_items; - mp_obj_get_array(value, &value_len, &value_items); + if (mp_obj_get_array(value, &value_len, &value_items)) { + return MP_OBJ_NULL; + } mp_bound_slice_t slice_out; - if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice_out)) { - mp_raise_NotImplementedError(NULL); + int ret = mp_seq_get_fast_slice_indexes(self->len, index, &slice_out); + if (ret < 0) { + return MP_OBJ_NULL; + } else if (!ret) { + return mp_raise_NotImplementedError_o(NULL); } mp_int_t len_adj = value_len - (slice_out.stop - slice_out.start); //printf("Len adj: %d\n", len_adj); @@ -206,7 +233,11 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (self->len + len_adj > self->alloc) { // TODO: Might optimize memory copies here by checking if block can // be grown inplace or not - self->items = m_renew(mp_obj_t, self->items, self->alloc, self->len + len_adj); + mp_obj_t *new_items = m_renew(mp_obj_t, self->items, self->alloc, self->len + len_adj); + if (new_items == NULL) { + return MP_OBJ_NULL; + } + self->items = new_items; self->alloc = self->len + len_adj; } mp_seq_replace_slice_grow_inplace(self->items, self->len, @@ -235,7 +266,11 @@ mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); if (self->len >= self->alloc) { - self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc * 2); + mp_obj_t *items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc * 2); + if (items == NULL) { + return MP_OBJ_NULL; + } + self->items = items; self->alloc *= 2; mp_seq_clear(self->items, self->len + 1, self->alloc, sizeof(*self->items)); } @@ -251,7 +286,11 @@ STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) { if (self->len + arg->len > self->alloc) { // TODO: use alloc policy for "4" - self->items = m_renew(mp_obj_t, self->items, self->alloc, self->len + arg->len + 4); + mp_obj_t *items = m_renew(mp_obj_t, self->items, self->alloc, self->len + arg->len + 4); + if (items == NULL) { + return MP_OBJ_NULL; + } + self->items = items; self->alloc = self->len + arg->len + 4; mp_seq_clear(self->items, self->len + arg->len, self->alloc, sizeof(*self->items)); } @@ -259,7 +298,9 @@ STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) { memcpy(self->items + self->len, arg->items, sizeof(mp_obj_t) * arg->len); self->len += arg->len; } else { - list_extend_from_iter(self_in, arg_in); + if (list_extend_from_iter(self_in, arg_in) == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } } return mp_const_none; // return None, as per CPython } @@ -268,7 +309,7 @@ STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) { mp_check_self(mp_obj_is_type(args[0], &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(args[0]); if (self->len == 0) { - mp_raise_msg(&mp_type_IndexError, "pop from empty list"); + return mp_raise_msg_o(&mp_type_IndexError, "pop from empty list"); } size_t index = mp_get_index(self->base.type, self->len, n_args == 1 ? MP_OBJ_NEW_SMALL_INT(-1) : args[1], false); mp_obj_t ret = self->items[index]; @@ -284,7 +325,10 @@ STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) { } STATIC void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, mp_obj_t binop_less_result) { - MP_STACK_CHECK(); + if (MP_STACK_CHECK()) { + // TODO propagate exception + return; + } while (head < tail) { mp_obj_t *h = head - 1; mp_obj_t *t = tail; @@ -322,8 +366,10 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ struct { mp_arg_val_t key, reverse; } args; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, - MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); + if (mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, + MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args)) { + return MP_OBJ_NULL; + } mp_check_self(mp_obj_is_type(pos_args[0], &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(pos_args[0]); @@ -394,6 +440,10 @@ mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); mp_obj_t args[] = {self_in, value}; args[1] = list_index(2, args); + if (args[1] == MP_OBJ_NULL) { + // exception + return MP_OBJ_NULL; + } list_pop(2, args); return mp_const_none; @@ -453,23 +503,29 @@ const mp_obj_type_t mp_type_list = { .locals_dict = (mp_obj_dict_t*)&list_locals_dict, }; -void mp_obj_list_init(mp_obj_list_t *o, size_t n) { +mp_obj_list_t *mp_obj_list_init(mp_obj_list_t *o, size_t n) { o->base.type = &mp_type_list; o->alloc = n < LIST_MIN_ALLOC ? LIST_MIN_ALLOC : n; o->len = n; o->items = m_new(mp_obj_t, o->alloc); + if (o->items == NULL) { + return NULL; + } mp_seq_clear(o->items, n, o->alloc, sizeof(*o->items)); + return o; } STATIC mp_obj_list_t *list_new(size_t n) { mp_obj_list_t *o = m_new_obj(mp_obj_list_t); - mp_obj_list_init(o, n); - return o; + if (o == NULL) { + return NULL; + } + return mp_obj_list_init(o, n); } mp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items) { mp_obj_list_t *o = list_new(n); - if (items != NULL) { + if (o != NULL && items != NULL) { for (size_t i = 0; i < n; i++) { o->items[i] = items[i]; } diff --git a/py/objlist.h b/py/objlist.h index a43663db76f8d..1e09387e0a361 100644 --- a/py/objlist.h +++ b/py/objlist.h @@ -35,6 +35,6 @@ typedef struct _mp_obj_list_t { mp_obj_t *items; } mp_obj_list_t; -void mp_obj_list_init(mp_obj_list_t *o, size_t n); +mp_obj_list_t *mp_obj_list_init(mp_obj_list_t *o, size_t n); #endif // MICROPY_INCLUDED_PY_OBJLIST_H diff --git a/py/objmap.c b/py/objmap.c index 78c52c8925782..288f4379e47bf 100644 --- a/py/objmap.c +++ b/py/objmap.c @@ -59,6 +59,10 @@ STATIC mp_obj_t map_iternext(mp_obj_t self_in) { m_del(mp_obj_t, nextses, self->n_iters); return MP_OBJ_STOP_ITERATION; } + if (next == MP_OBJ_NULL) { + // exception + return MP_OBJ_NULL; + } nextses[i] = next; } return mp_call_function_n_kw(self->fun, self->n_iters, 0, nextses); diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index 54d8493c37fb1..5d81e6cf32f89 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -87,7 +87,7 @@ STATIC void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { } else { // delete/store attribute // provide more detailed error message than we'd get by just returning - mp_raise_msg(&mp_type_AttributeError, "can't set attribute"); + mp_raise_msg_o(&mp_type_AttributeError, "can't set attribute"); } } @@ -97,12 +97,13 @@ STATIC mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, if (n_args + n_kw != num_fields) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); + return MP_OBJ_NULL; } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", num_fields, n_args + n_kw)); } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%q() takes %d positional arguments but %d were given", type->base.name, num_fields, n_args + n_kw)); } @@ -123,16 +124,18 @@ STATIC mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, if (id == (size_t)-1) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); + return MP_OBJ_NULL; } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unexpected keyword argument '%q'", kw)); } } if (tuple->items[id] != MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); + return MP_OBJ_NULL; } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function got multiple values for argument '%q'", kw)); } } @@ -176,7 +179,9 @@ STATIC mp_obj_t new_namedtuple_type(mp_obj_t name_in, mp_obj_t fields_in) { fields_in = mp_obj_str_split(1, &fields_in); } #endif - mp_obj_get_array(fields_in, &n_fields, &fields); + if (mp_obj_get_array(fields_in, &n_fields, &fields)) { + return MP_OBJ_NULL; + } return mp_obj_new_namedtuple_type(name, n_fields, fields); } MP_DEFINE_CONST_FUN_OBJ_2(mp_namedtuple_obj, new_namedtuple_type); diff --git a/py/objobject.c b/py/objobject.c index 45228347e965a..faca8fd49ea84 100644 --- a/py/objobject.c +++ b/py/objobject.c @@ -50,7 +50,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___init___obj, object___init__); STATIC mp_obj_t object___new__(mp_obj_t cls) { if (!mp_obj_is_type(cls, &mp_type_type) || !mp_obj_is_instance_type((mp_obj_type_t*)MP_OBJ_TO_PTR(cls))) { - mp_raise_TypeError("__new__ arg must be a user-type"); + return mp_raise_TypeError_o("__new__ arg must be a user-type"); } // This executes only "__new__" part of instance creation. // TODO: This won't work well for classes with native bases. diff --git a/py/objrange.c b/py/objrange.c index 6c3097abd4f67..c2658da0d5a44 100644 --- a/py/objrange.c +++ b/py/objrange.c @@ -90,7 +90,9 @@ STATIC void range_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind } STATIC mp_obj_t range_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 1, 3, false); + if (mp_arg_check_num(n_args, n_kw, 1, 3, false)) { + return MP_OBJ_NULL; + } mp_obj_range_t *o = m_new_obj(mp_obj_range_t); o->base.type = type; @@ -105,11 +107,16 @@ STATIC mp_obj_t range_make_new(const mp_obj_type_t *type, size_t n_args, size_t if (n_args == 3) { o->step = mp_obj_get_int(args[2]); if (o->step == 0) { - mp_raise_ValueError("zero step"); + return mp_raise_ValueError_o("zero step"); } } } + // check for errors from mp_obj_get_int + if (MP_STATE_THREAD(active_exception) != NULL) { + return MP_OBJ_NULL; + } + return MP_OBJ_FROM_PTR(o); } diff --git a/py/objset.c b/py/objset.c index 6f5bcc032a9a5..cfd254f8548c1 100644 --- a/py/objset.c +++ b/py/objset.c @@ -175,6 +175,9 @@ STATIC mp_obj_t set_copy(mp_obj_t self_in) { check_set_or_frozenset(self_in); mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_set_t *other = m_new_obj(mp_obj_set_t); + if (other == NULL) { + return MP_OBJ_NULL; + } other->base.type = self->base.type; mp_set_init(&other->set, self->set.alloc); other->set.used = self->set.used; @@ -362,7 +365,7 @@ STATIC mp_obj_t set_pop(mp_obj_t self_in) { mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t obj = mp_set_remove_first(&self->set); if (obj == MP_OBJ_NULL) { - mp_raise_msg(&mp_type_KeyError, "pop from an empty set"); + return mp_raise_msg_o(&mp_type_KeyError, "pop from an empty set"); } return obj; } @@ -372,7 +375,7 @@ STATIC mp_obj_t set_remove(mp_obj_t self_in, mp_obj_t item) { check_set(self_in); mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); if (mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_REMOVE_IF_FOUND) == MP_OBJ_NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, item)); + return mp_raise_o(mp_obj_new_exception_arg1(&mp_type_KeyError, item)); } return mp_const_none; } @@ -575,6 +578,9 @@ const mp_obj_type_t mp_type_frozenset = { mp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items) { mp_obj_set_t *o = m_new_obj(mp_obj_set_t); + if (o == NULL) { + return MP_OBJ_NULL; + } o->base.type = &mp_type_set; mp_set_init(&o->set, n_args); for (size_t i = 0; i < n_args; i++) { diff --git a/py/objslice.c b/py/objslice.c index cfc819edccb25..e0f9c486b2913 100644 --- a/py/objslice.c +++ b/py/objslice.c @@ -81,6 +81,9 @@ const mp_obj_type_t mp_type_slice = { mp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) { mp_obj_slice_t *o = m_new_obj(mp_obj_slice_t); + if (o == NULL) { + return MP_OBJ_NULL; + } o->base.type = &mp_type_slice; o->start = ostart; o->stop = ostop; diff --git a/py/objstr.c b/py/objstr.c index e221982c576e0..75f28b662cf9b 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -39,7 +39,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ #endif STATIC mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf); -STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in); +STATIC mp_obj_t bad_implicit_conversion(mp_obj_t self_in); /******************************************************************************/ /* str */ @@ -139,7 +139,9 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ } #endif - mp_arg_check_num(n_args, n_kw, 0, 3, false); + if (mp_arg_check_num(n_args, n_kw, 0, 3, false)) { + return MP_OBJ_NULL; + } switch (n_args) { case 0: @@ -163,7 +165,7 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ } #if MICROPY_PY_BUILTINS_STR_UNICODE_CHECK if (!utf8_check(str_data, str_len)) { - mp_raise_msg(&mp_type_UnicodeError, NULL); + return mp_raise_msg_o(&mp_type_UnicodeError, NULL); } #endif @@ -182,7 +184,7 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); #if MICROPY_PY_BUILTINS_STR_UNICODE_CHECK if (!utf8_check(bufinfo.buf, bufinfo.len)) { - mp_raise_msg(&mp_type_UnicodeError, NULL); + return mp_raise_msg_o(&mp_type_UnicodeError, NULL); } #endif return mp_obj_new_str(bufinfo.buf, bufinfo.len); @@ -227,7 +229,7 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size if (mp_obj_is_small_int(args[0])) { mp_int_t len = MP_OBJ_SMALL_INT_VALUE(args[0]); if (len < 0) { - mp_raise_ValueError(NULL); + return mp_raise_ValueError_o(NULL); } vstr_t vstr; vstr_init_len(&vstr, len); @@ -254,20 +256,23 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size mp_obj_iter_buf_t iter_buf; mp_obj_t iterable = mp_getiter(args[0], &iter_buf); mp_obj_t item; - while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + while ((item = mp_iternext2(iterable)) != MP_OBJ_NULL) { mp_int_t val = mp_obj_get_int(item); #if MICROPY_FULL_CHECKS if (val < 0 || val > 255) { - mp_raise_ValueError("bytes value out of range"); + return mp_raise_ValueError_o("bytes value out of range"); } #endif vstr_add_byte(&vstr, val); } + if (mp_iternext_had_exc()) { + return MP_OBJ_NULL; + } return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); wrong_args: - mp_raise_TypeError("wrong number of arguments"); + return mp_raise_TypeError_o("wrong number of arguments"); } // like strstr but with specified length and allows \0 bytes @@ -373,7 +378,7 @@ mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i } else { // LHS is str and RHS has an incompatible type // (except if operation is EQUAL, but that's handled by mp_obj_equal) - bad_implicit_conversion(rhs_in); + return bad_implicit_conversion(rhs_in); } switch (op) { @@ -428,12 +433,15 @@ STATIC mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (mp_obj_is_type(index, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(self_len, index, &slice)) { - mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported"); + return mp_raise_NotImplementedError_o("only slices with step=1 (aka None) are supported"); } return mp_obj_new_str_of_type(type, self_data + slice.start, slice.stop - slice.start); } #endif size_t index_val = mp_get_index(type, self_len, index, false); + if (index_val == (size_t)-1) { + return MP_OBJ_NULL; // exception + } // If we have unicode enabled the type will always be bytes, so take the short cut. if (MICROPY_PY_BUILTINS_STR_UNICODE || type == &mp_type_bytes) { return MP_OBJ_NEW_SMALL_INT(self_data[index_val]); @@ -460,6 +468,9 @@ STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) { // arg is not a list nor a tuple, try to convert it to a list // TODO: Try to optimize? arg = mp_type_list.make_new(&mp_type_list, 1, 0, &arg); + if (arg == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } } mp_obj_get_array(arg, &seq_len, &seq_items); @@ -467,7 +478,7 @@ STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) { size_t required_len = 0; for (size_t i = 0; i < seq_len; i++) { if (mp_obj_get_type(seq_items[i]) != self_type) { - mp_raise_TypeError( + return mp_raise_TypeError_o( "join expects a list of str/bytes objects consistent with self object"); } if (i > 0) { @@ -536,14 +547,14 @@ mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args) { } else { // sep given if (mp_obj_get_type(sep) != self_type) { - bad_implicit_conversion(sep); + return bad_implicit_conversion(sep); } size_t sep_len; const char *sep_str = mp_obj_str_get_data(sep, &sep_len); if (sep_len == 0) { - mp_raise_ValueError("empty separator"); + return mp_raise_ValueError_o("empty separator"); } for (;;) { @@ -642,13 +653,13 @@ STATIC mp_obj_t str_rsplit(size_t n_args, const mp_obj_t *args) { mp_int_t idx = splits; if (sep == mp_const_none) { - mp_raise_NotImplementedError("rsplit(None,n)"); + return mp_raise_NotImplementedError_o("rsplit(None,n)"); } else { size_t sep_len; const char *sep_str = mp_obj_str_get_data(sep, &sep_len); if (sep_len == 0) { - mp_raise_ValueError("empty separator"); + return mp_raise_ValueError_o("empty separator"); } const byte *beg = s; @@ -690,7 +701,7 @@ STATIC mp_obj_t str_finder(size_t n_args, const mp_obj_t *args, int direction, b // check argument type if (mp_obj_get_type(args[1]) != self_type) { - bad_implicit_conversion(args[1]); + return bad_implicit_conversion(args[1]); } GET_STR_DATA_LEN(args[0], haystack, haystack_len); @@ -714,7 +725,7 @@ STATIC mp_obj_t str_finder(size_t n_args, const mp_obj_t *args, int direction, b out_error: // not found if (is_index) { - mp_raise_ValueError("substring not found"); + return mp_raise_ValueError_o("substring not found"); } else { return MP_OBJ_NEW_SMALL_INT(-1); } @@ -755,6 +766,10 @@ STATIC mp_obj_t str_startswith(size_t n_args, const mp_obj_t *args) { GET_STR_DATA_LEN(args[0], str, str_len); size_t prefix_len; const char *prefix = mp_obj_str_get_data(args[1], &prefix_len); + if (prefix == NULL) { + // exception + return MP_OBJ_NULL; + } const byte *start = str; if (n_args > 2) { start = str_index_to_ptr(self_type, str, str_len, args[2], true); @@ -770,8 +785,11 @@ STATIC mp_obj_t str_endswith(size_t n_args, const mp_obj_t *args) { GET_STR_DATA_LEN(args[0], str, str_len); size_t suffix_len; const char *suffix = mp_obj_str_get_data(args[1], &suffix_len); + if (suffix == NULL) { + return MP_OBJ_NULL; + } if (n_args > 2) { - mp_raise_NotImplementedError("start/end indices"); + return mp_raise_NotImplementedError_o("start/end indices"); } if (suffix_len > str_len) { @@ -796,7 +814,7 @@ STATIC mp_obj_t str_uni_strip(int type, size_t n_args, const mp_obj_t *args) { chars_to_del_len = sizeof(whitespace) - 1; } else { if (mp_obj_get_type(args[1]) != self_type) { - bad_implicit_conversion(args[1]); + return bad_implicit_conversion(args[1]); } GET_STR_DATA_LEN(args[1], s, l); chars_to_del = s; @@ -933,12 +951,14 @@ STATIC mp_obj_t arg_as_int(mp_obj_t arg) { #endif #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE -STATIC NORETURN void terse_str_format_value_error(void) { - mp_raise_ValueError("bad format string"); +STATIC mp_obj_t terse_str_format_value_error(void) { + return mp_raise_ValueError_o("bad format string"); } #else // define to nothing to improve coverage -#define terse_str_format_value_error() +static inline mp_obj_t terse_str_format_value_error(void) { + return MP_OBJ_NULL; +} #endif STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *arg_i, size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { @@ -956,7 +976,9 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - mp_raise_ValueError("single '}' encountered in format string"); + mp_raise_ValueError_o("single '}' encountered in format string"); + vstr.buf = NULL; + return vstr; } } if (*str != '{') { @@ -995,16 +1017,18 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL) { - mp_raise_ValueError("bad conversion specifier"); - } else { + mp_raise_ValueError_o("bad conversion specifier"); + } else { if (str >= top) { - mp_raise_ValueError( + mp_raise_ValueError_o( "end of format while looking for conversion specifier"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unknown conversion specifier %c", *str)); } } + vstr.buf = NULL; + return vstr; } } @@ -1033,15 +1057,19 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - mp_raise_ValueError("unmatched '{' in format"); + mp_raise_ValueError_o("unmatched '{' in format"); } + vstr.buf = NULL; + return vstr; } if (*str != '}') { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - mp_raise_ValueError("expected ':' after format specifier"); + mp_raise_ValueError_o("expected ':' after format specifier"); } + vstr.buf = NULL; + return vstr; } mp_obj_t arg = mp_const_none; @@ -1053,13 +1081,17 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - mp_raise_ValueError( + mp_raise_ValueError_o( "can't switch from automatic field numbering to manual field specification"); } + vstr.buf = NULL; + return vstr; } field_name = str_to_int(field_name, field_name_top, &index); if ((uint)index >= n_args - 1) { - mp_raise_msg(&mp_type_IndexError, "tuple index out of range"); + mp_raise_msg_o(&mp_type_IndexError, "tuple index out of range"); + vstr.buf = NULL; + return vstr; } arg = args[index + 1]; *arg_i = -1; @@ -1067,27 +1099,39 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar const char *lookup; for (lookup = field_name; lookup < field_name_top && *lookup != '.' && *lookup != '['; lookup++); mp_obj_t field_q = mp_obj_new_str_via_qstr(field_name, lookup - field_name); // should it be via qstr? + if (field_q == MP_OBJ_NULL) { + vstr.buf = NULL; + return vstr; + } field_name = lookup; mp_map_elem_t *key_elem = mp_map_lookup(kwargs, field_q, MP_MAP_LOOKUP); if (key_elem == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, field_q)); + mp_raise_o(mp_obj_new_exception_arg1(&mp_type_KeyError, field_q)); + vstr.buf = NULL; + return vstr; } arg = key_elem->value; } if (field_name < field_name_top) { - mp_raise_NotImplementedError("attributes not supported yet"); + mp_raise_NotImplementedError_o("attributes not supported yet"); + vstr.buf = NULL; + return vstr; } } else { if (*arg_i < 0) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - mp_raise_ValueError( + mp_raise_ValueError_o( "can't switch from manual field specification to automatic field numbering"); } + vstr.buf = NULL; + return vstr; } if ((uint)*arg_i >= n_args - 1) { - mp_raise_msg(&mp_type_IndexError, "tuple index out of range"); + mp_raise_msg_o(&mp_type_IndexError, "tuple index out of range"); + vstr.buf = NULL; + return vstr; } arg = args[(*arg_i) + 1]; (*arg_i)++; @@ -1129,8 +1173,14 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar // type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%" // recursively call the formatter to format any nested specifiers - MP_STACK_CHECK(); + if (MP_STACK_CHECK()) { + vstr.buf = NULL; + return vstr; + } vstr_t format_spec_vstr = mp_obj_str_format_helper(format_spec, str, arg_i, n_args, args, kwargs); + if (format_spec_vstr.buf == NULL) { + return format_spec_vstr; + } const char *s = vstr_null_terminated_str(&format_spec_vstr); const char *stop = s + format_spec_vstr.len; if (isalignment(*s)) { @@ -1175,8 +1225,10 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - mp_raise_ValueError("invalid format specifier"); + mp_raise_ValueError_o("invalid format specifier"); } + vstr.buf = NULL; + return vstr; } vstr_clear(&format_spec_vstr); } @@ -1196,16 +1248,20 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - mp_raise_ValueError("sign not allowed in string format specifier"); + mp_raise_ValueError_o("sign not allowed in string format specifier"); } + vstr.buf = NULL; + return vstr; } if (type == 'c') { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - mp_raise_ValueError( + mp_raise_ValueError_o( "sign not allowed with integer format specifier 'c'"); } + vstr.buf = NULL; + return vstr; } } @@ -1262,10 +1318,12 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unknown format code '%c' for object of type '%s'", type, mp_obj_get_type_str(arg))); } + vstr.buf = NULL; + return vstr; } } @@ -1334,10 +1392,12 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unknown format code '%c' for object of type '%s'", type, mp_obj_get_type_str(arg))); } + vstr.buf = NULL; + return vstr; } } else { // arg doesn't look like a number @@ -1346,9 +1406,11 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - mp_raise_ValueError( + mp_raise_ValueError_o( "'=' alignment not allowed in string format specifier"); } + vstr.buf = NULL; + return vstr; } switch (type) { @@ -1370,11 +1432,13 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unknown format code '%c' for object of type '%s'", type, mp_obj_get_type_str(arg))); } - } + vstr.buf = NULL; + return vstr; + } } } @@ -1387,6 +1451,9 @@ mp_obj_t mp_obj_str_format(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs GET_STR_DATA_LEN(args[0], str, len); int arg_i = 0; vstr_t vstr = mp_obj_str_format_helper((const char*)str, (const char*)str + len, &arg_i, n_args, args, kwargs); + if (vstr.buf == NULL) { + return MP_OBJ_NULL; + } return mp_obj_new_str_from_vstr(mp_obj_get_type(args[0]), &vstr); } MP_DEFINE_CONST_FUN_OBJ_KW(str_format_obj, 1, mp_obj_str_format); @@ -1420,22 +1487,28 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ // Dictionary value lookup if (*str == '(') { if (dict == MP_OBJ_NULL) { - mp_raise_TypeError("format needs a dict"); + return mp_raise_TypeError_o("format needs a dict"); } arg_i = 1; // we used up the single dict argument const byte *key = ++str; while (*str != ')') { if (str >= top) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - terse_str_format_value_error(); + return terse_str_format_value_error(); } else { - mp_raise_ValueError("incomplete format key"); + return mp_raise_ValueError_o("incomplete format key"); } } ++str; } mp_obj_t k_obj = mp_obj_new_str_via_qstr((const char*)key, str - key); + if (k_obj == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } arg = mp_obj_dict_get(dict, k_obj); + if (arg == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } str++; } @@ -1485,9 +1558,9 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ if (str >= top) { incomplete_format: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - terse_str_format_value_error(); + return terse_str_format_value_error(); } else { - mp_raise_ValueError("incomplete format"); + return mp_raise_ValueError_o("incomplete format"); } } @@ -1495,7 +1568,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ if (arg == MP_OBJ_NULL) { if (arg_i >= n_args) { not_enough_args: - mp_raise_TypeError("format string needs more arguments"); + return mp_raise_TypeError_o("format string needs more arguments"); } arg = args[arg_i++]; } @@ -1505,14 +1578,14 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ size_t slen; const char *s = mp_obj_str_get_data(arg, &slen); if (slen != 1) { - mp_raise_TypeError("%%c needs int or char"); + return mp_raise_TypeError_o("%%c needs int or char"); } mp_print_strn(&print, s, 1, flags, ' ', width); } else if (arg_looks_integer(arg)) { char ch = mp_obj_get_int(arg); mp_print_strn(&print, &ch, 1, flags, ' ', width); } else { - mp_raise_TypeError("integer needed"); + return mp_raise_TypeError_o("integer needed"); } break; @@ -1572,9 +1645,9 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ default: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - terse_str_format_value_error(); + return terse_str_format_value_error(); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unsupported format character '%c' (0x%x) at index %d", *str, *str, str - start_str)); } @@ -1582,7 +1655,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ } if (arg_i != n_args) { - mp_raise_TypeError("format string didn't convert all arguments"); + return mp_raise_TypeError_o("format string didn't convert all arguments"); } return mp_obj_new_str_from_vstr(is_bytes ? &mp_type_bytes : &mp_type_str, &vstr); @@ -1611,11 +1684,11 @@ STATIC mp_obj_t str_replace(size_t n_args, const mp_obj_t *args) { const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); if (mp_obj_get_type(args[1]) != self_type) { - bad_implicit_conversion(args[1]); + return bad_implicit_conversion(args[1]); } if (mp_obj_get_type(args[2]) != self_type) { - bad_implicit_conversion(args[2]); + return bad_implicit_conversion(args[2]); } // extract string data @@ -1704,7 +1777,7 @@ STATIC mp_obj_t str_count(size_t n_args, const mp_obj_t *args) { // check argument type if (mp_obj_get_type(args[1]) != self_type) { - bad_implicit_conversion(args[1]); + return bad_implicit_conversion(args[1]); } GET_STR_DATA_LEN(args[0], haystack, haystack_len); @@ -1745,14 +1818,14 @@ STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, int direction) { mp_check_self(mp_obj_is_str_or_bytes(self_in)); mp_obj_type_t *self_type = mp_obj_get_type(self_in); if (self_type != mp_obj_get_type(arg)) { - bad_implicit_conversion(arg); + return bad_implicit_conversion(arg); } GET_STR_DATA_LEN(self_in, str, str_len); GET_STR_DATA_LEN(arg, sep, sep_len); if (sep_len == 0) { - mp_raise_ValueError("empty separator"); + return mp_raise_ValueError_o("empty separator"); } mp_obj_t result[3]; @@ -2029,7 +2102,12 @@ mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, siz // Create a str using a qstr to store the data; may use existing or new qstr. mp_obj_t mp_obj_new_str_via_qstr(const char* data, size_t len) { - return MP_OBJ_NEW_QSTR(qstr_from_strn(data, len)); + qstr qst = qstr_from_strn(data, len); + if (qst == MP_QSTRnull) { + return MP_OBJ_NULL; + } else { + return MP_OBJ_NEW_QSTR(qst); + } } // Create a str/bytes object from the given vstr. The vstr buffer is resized to @@ -2048,6 +2126,9 @@ mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr) { // make a new str/bytes object mp_obj_str_t *o = m_new_obj(mp_obj_str_t); + if (o == NULL) { + return MP_OBJ_NULL; + } o->base.type = type; o->len = vstr->len; o->hash = qstr_compute_hash((byte*)vstr->buf, vstr->len); @@ -2055,6 +2136,9 @@ mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr) { o->data = (byte*)vstr->buf; } else { o->data = (byte*)m_renew(char, vstr->buf, vstr->alloc, vstr->len + 1); + if (o->data == NULL) { + return MP_OBJ_NULL; + } } ((byte*)o->data)[o->len] = '\0'; // add null byte vstr->buf = NULL; @@ -2081,6 +2165,10 @@ mp_obj_t mp_obj_str_intern(mp_obj_t str) { mp_obj_t mp_obj_str_intern_checked(mp_obj_t obj) { size_t len; const char *data = mp_obj_str_get_data(obj, &len); + if (data == NULL) { + // exception + return MP_OBJ_NULL; + } return mp_obj_new_str_via_qstr((const char*)data, len); } @@ -2107,12 +2195,12 @@ bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) { } } -STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in) { +STATIC mp_obj_t bad_implicit_conversion(mp_obj_t self_in) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("can't convert to str implicitly"); + return mp_raise_TypeError_o("can't convert to str implicitly"); } else { const qstr src_name = mp_obj_get_type(self_in)->name; - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert '%q' object to %q implicitly", src_name, src_name == MP_QSTR_str ? MP_QSTR_bytes : MP_QSTR_str)); } @@ -2128,6 +2216,7 @@ qstr mp_obj_str_get_qstr(mp_obj_t self_in) { return qstr_from_strn((char*)self->data, self->len); } else { bad_implicit_conversion(self_in); + return MP_QSTR_NULL; // TODO callers should handle this case } } @@ -2140,6 +2229,7 @@ const char *mp_obj_str_get_str(mp_obj_t self_in) { return (const char*)s; } else { bad_implicit_conversion(self_in); + return NULL; // TODO callers should handle this case } } @@ -2150,6 +2240,7 @@ const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len) { return (const char*)s; } else { bad_implicit_conversion(self_in); + return NULL; // TODO callers should handle this case } } diff --git a/py/objstringio.c b/py/objstringio.c index cca4a81297dab..2c00334df86a6 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -36,13 +36,15 @@ #if MICROPY_PY_IO #if MICROPY_CPYTHON_COMPAT -STATIC void check_stringio_is_open(const mp_obj_stringio_t *o) { +STATIC int check_stringio_is_open(const mp_obj_stringio_t *o) { if (o->vstr == NULL) { - mp_raise_ValueError("I/O operation on closed file"); + mp_raise_ValueError_o("I/O operation on closed file"); + return 1; } + return 0; } #else -#define check_stringio_is_open(o) +#define check_stringio_is_open(o) 0 #endif STATIC void stringio_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { @@ -54,7 +56,9 @@ STATIC void stringio_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k STATIC mp_uint_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { (void)errcode; mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in); - check_stringio_is_open(o); + if (check_stringio_is_open(o)) { + return MP_STREAM_ERROR; + } if (o->vstr->len <= o->pos) { // read to EOF, or seeked to EOF or beyond return 0; } @@ -78,7 +82,9 @@ STATIC void stringio_copy_on_write(mp_obj_stringio_t *o) { STATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { (void)errcode; mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in); - check_stringio_is_open(o); + if (check_stringio_is_open(o)) { + return MP_STREAM_ERROR; + } if (o->vstr->fixed_buf) { stringio_copy_on_write(o); @@ -164,7 +170,9 @@ STATIC mp_uint_t stringio_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) { mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in); - check_stringio_is_open(self); + if (check_stringio_is_open(self)) { + return MP_OBJ_NULL; + } // TODO: Try to avoid copying string return mp_obj_new_str_of_type(STREAM_TO_CONTENT_TYPE(self), (byte*)self->vstr->buf, self->vstr->len); } diff --git a/py/objstrunicode.c b/py/objstrunicode.c index 78d0b5006ef73..1f7ed92fb65b5 100644 --- a/py/objstrunicode.c +++ b/py/objstrunicode.c @@ -129,7 +129,8 @@ const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, s if (mp_obj_is_small_int(index)) { i = MP_OBJ_SMALL_INT_VALUE(index); } else if (!mp_obj_get_int_maybe(index, &i)) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "string indices must be integers, not %s", mp_obj_get_type_str(index))); + mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "string indices must be integers, not %s", mp_obj_get_type_str(index))); + return NULL; } const byte *s, *top = self_data + self_len; if (i < 0) @@ -140,7 +141,8 @@ const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, s if (is_slice) { return self_data; } - mp_raise_msg(&mp_type_IndexError, "string index out of range"); + mp_raise_msg_o(&mp_type_IndexError, "string index out of range"); + return NULL; } if (!UTF8_IS_CONT(*s)) { ++i; @@ -159,7 +161,8 @@ const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, s if (is_slice) { return top; } - mp_raise_msg(&mp_type_IndexError, "string index out of range"); + mp_raise_msg_o(&mp_type_IndexError, "string index out of range"); + return NULL; } // Then check completion if (i-- == 0) { @@ -186,7 +189,7 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_obj_t ostart, ostop, ostep; mp_obj_slice_get(index, &ostart, &ostop, &ostep); if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { - mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported"); + return mp_raise_NotImplementedError_o("only slices with step=1 (aka None) are supported"); } const byte *pstart, *pstop; @@ -209,6 +212,9 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { } #endif const byte *s = str_index_to_ptr(type, self_data, self_len, index, false); + if (s == NULL) { + return MP_OBJ_NULL; + } int len = 1; if (UTF8_IS_NONASCII(*s)) { // Count the number of 1 bits (after the first) diff --git a/py/objtuple.c b/py/objtuple.c index 740e0795b3328..0df56ed7bb1fd 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -86,13 +86,16 @@ STATIC mp_obj_t mp_obj_tuple_make_new(const mp_obj_type_t *type_in, size_t n_arg mp_obj_t iterable = mp_getiter(args[0], NULL); mp_obj_t item; - while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + while ((item = mp_iternext2(iterable)) != MP_OBJ_NULL) { if (len >= alloc) { items = m_renew(mp_obj_t, items, alloc, alloc * 2); alloc *= 2; } items[len++] = item; } + if (mp_iternext_had_exc()) { + return MP_OBJ_NULL; + } mp_obj_t tuple = mp_obj_new_tuple(len, items); m_del(mp_obj_t, items, alloc); @@ -185,7 +188,8 @@ mp_obj_t mp_obj_tuple_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (mp_obj_is_type(index, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { - mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported"); + mp_raise_NotImplementedError_o("only slices with step=1 (aka None) are supported"); + return MP_OBJ_NULL; } mp_obj_tuple_t *res = MP_OBJ_TO_PTR(mp_obj_new_tuple(slice.stop - slice.start, NULL)); mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t); @@ -193,6 +197,10 @@ mp_obj_t mp_obj_tuple_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { } #endif size_t index_value = mp_get_index(self->base.type, self->len, index, false); + if (index_value == (size_t)-1) { + // exception + return MP_OBJ_NULL; + } return self->items[index_value]; } else { return MP_OBJ_NULL; // op not supported @@ -240,6 +248,9 @@ mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items) { return mp_const_empty_tuple; } mp_obj_tuple_t *o = m_new_obj_var(mp_obj_tuple_t, mp_obj_t, n); + if (o == NULL) { + return MP_OBJ_NULL; + } o->base.type = &mp_type_tuple; o->len = n; if (items) { diff --git a/py/objtype.c b/py/objtype.c index bf089dc490db9..c7bd1795d5355 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -352,9 +352,9 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size } if (init_ret != mp_const_none) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("__init__() should return None"); + return mp_raise_TypeError_o("__init__() should return None"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "__init__() should return None, not '%s'", mp_obj_get_type_str(init_ret))); } } @@ -422,16 +422,18 @@ STATIC mp_obj_t instance_unary_op(mp_unary_op_t op, mp_obj_t self_in) { return mp_unary_op(op, self->subobj[0]); } else if (member[0] != MP_OBJ_NULL) { mp_obj_t val = mp_call_function_1(member[0], self_in); - switch (op) { case MP_UNARY_OP_HASH: // __hash__ must return a small int val = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int_truncated(val)); + if (MP_STATE_THREAD(active_exception) != NULL) { + return MP_OBJ_NULL; + } break; case MP_UNARY_OP_INT: // Must return int if (!mp_obj_is_int(val)) { - mp_raise_TypeError(NULL); + return mp_raise_TypeError_o(NULL); } break; default: @@ -631,7 +633,7 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des // the code. const mp_obj_t *proxy = mp_obj_property_get(member); if (proxy[0] == mp_const_none) { - mp_raise_msg(&mp_type_AttributeError, "unreadable attribute"); + mp_raise_msg_o(&mp_type_AttributeError, "unreadable attribute"); } else { dest[0] = mp_call_function_n_kw(proxy[0], 1, 0, &self_in); } @@ -868,9 +870,9 @@ mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons mp_obj_t call = mp_obj_instance_get_call(self_in, member); if (call == MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("object not callable"); + return mp_raise_TypeError_o("object not callable"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object isn't callable", mp_obj_get_type_str(self_in))); } } @@ -978,7 +980,7 @@ STATIC mp_obj_t type_make_new(const mp_obj_type_t *type_in, size_t n_args, size_ return mp_obj_new_type(mp_obj_str_get_qstr(args[0]), args[1], args[2]); default: - mp_raise_TypeError("type takes 1 or 3 arguments"); + return mp_raise_TypeError_o("type takes 1 or 3 arguments"); } } @@ -989,9 +991,9 @@ STATIC mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp if (self->make_new == NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("cannot create instance"); + return mp_raise_TypeError_o("cannot create instance"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "cannot create '%q' instances", self->name)); } } @@ -1061,7 +1063,8 @@ STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (check_for_special_accessors(MP_OBJ_NEW_QSTR(attr), dest[1])) { if (self->flags & TYPE_FLAG_IS_SUBCLASSED) { // This class is already subclassed so can't have special accessors added - mp_raise_msg(&mp_type_AttributeError, "can't add special method to already-subclassed class"); + mp_raise_msg_o(&mp_type_AttributeError, "can't add special method to already-subclassed class"); + return; } self->flags |= TYPE_FLAG_HAS_SPECIAL_ACCESSORS; } @@ -1090,10 +1093,10 @@ const mp_obj_type_t mp_type_type = { mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) { // Verify input objects have expected type if (!mp_obj_is_type(bases_tuple, &mp_type_tuple)) { - mp_raise_TypeError(NULL); + return mp_raise_TypeError_o(NULL); } if (!mp_obj_is_type(locals_dict, &mp_type_dict)) { - mp_raise_TypeError(NULL); + return mp_raise_TypeError_o(NULL); } // TODO might need to make a copy of locals_dict; at least that's how CPython does it @@ -1105,15 +1108,15 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) mp_obj_tuple_get(bases_tuple, &bases_len, &bases_items); for (size_t i = 0; i < bases_len; i++) { if (!mp_obj_is_type(bases_items[i], &mp_type_type)) { - mp_raise_TypeError(NULL); + return mp_raise_TypeError_o(NULL); } mp_obj_type_t *t = MP_OBJ_TO_PTR(bases_items[i]); // TODO: Verify with CPy, tested on function type if (t->make_new == NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("type isn't an acceptable base type"); + return mp_raise_TypeError_o("type isn't an acceptable base type"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "type '%q' isn't an acceptable base type", t->name)); } } @@ -1151,7 +1154,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) #if MICROPY_MULTIPLE_INHERITANCE o->parent = MP_OBJ_TO_PTR(bases_tuple); #else - mp_raise_NotImplementedError("multiple inheritance not supported"); + return mp_raise_NotImplementedError_o("multiple inheritance not supported"); #endif } else { o->parent = MP_OBJ_TO_PTR(bases_items[0]); @@ -1178,7 +1181,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) const mp_obj_type_t *native_base; size_t num_native_bases = instance_count_native_bases(o, &native_base); if (num_native_bases > 1) { - mp_raise_TypeError("multiple bases have instance lay-out conflict"); + return mp_raise_TypeError_o("multiple bases have instance lay-out conflict"); } mp_map_t *locals_map = &o->locals_dict->map; @@ -1219,7 +1222,7 @@ STATIC mp_obj_t super_make_new(const mp_obj_type_t *type_in, size_t n_args, size // 1 argument is not yet implemented mp_arg_check_num(n_args, n_kw, 2, 2, false); if (!mp_obj_is_type(args[0], &mp_type_type)) { - mp_raise_TypeError(NULL); + return mp_raise_TypeError_o(NULL); } mp_obj_super_t *o = m_new_obj(mp_obj_super_t); *o = (mp_obj_super_t){{type_in}, args[0], args[1]}; @@ -1300,9 +1303,9 @@ const mp_obj_type_t mp_type_super = { .attr = super_attr, }; -void mp_load_super_method(qstr attr, mp_obj_t *dest) { +mp_obj_t mp_load_super_method(qstr attr, mp_obj_t *dest) { mp_obj_super_t super = {{&mp_type_super}, dest[1], dest[2]}; - mp_load_method(MP_OBJ_FROM_PTR(&super), attr, dest); + return mp_load_method(MP_OBJ_FROM_PTR(&super), attr, dest); } /******************************************************************************/ @@ -1361,7 +1364,7 @@ STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) { } else if (mp_obj_is_type(classinfo, &mp_type_tuple)) { mp_obj_tuple_get(classinfo, &len, &items); } else { - mp_raise_TypeError("issubclass() arg 2 must be a class or a tuple of classes"); + return mp_raise_TypeError_o("issubclass() arg 2 must be a class or a tuple of classes"); } for (size_t i = 0; i < len; i++) { @@ -1375,7 +1378,7 @@ STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) { STATIC mp_obj_t mp_builtin_issubclass(mp_obj_t object, mp_obj_t classinfo) { if (!mp_obj_is_type(object, &mp_type_type)) { - mp_raise_TypeError("issubclass() arg 1 must be a class"); + return mp_raise_TypeError_o("issubclass() arg 1 must be a class"); } return mp_obj_is_subclass(object, classinfo); } diff --git a/py/objzip.c b/py/objzip.c index 4abc917c3f525..e2455a02c2552 100644 --- a/py/objzip.c +++ b/py/objzip.c @@ -58,6 +58,10 @@ STATIC mp_obj_t zip_iternext(mp_obj_t self_in) { for (size_t i = 0; i < self->n_iters; i++) { mp_obj_t next = mp_iternext(self->iters[i]); + if (next == MP_OBJ_NULL) { + // exception + return MP_OBJ_NULL; + } if (next == MP_OBJ_STOP_ITERATION) { mp_obj_tuple_del(MP_OBJ_FROM_PTR(tuple)); return MP_OBJ_STOP_ITERATION; diff --git a/py/parse.c b/py/parse.c index 82b5413e592a9..4d6e6b702332d 100644 --- a/py/parse.c +++ b/py/parse.c @@ -280,6 +280,9 @@ STATIC void *parser_alloc(parser_t *parser, size_t num_bytes) { alloc = num_bytes; } chunk = (mp_parse_chunk_t*)m_new(byte, sizeof(mp_parse_chunk_t) + alloc); + if (chunk == NULL) { + return NULL; + } chunk->alloc = alloc; chunk->union_.used = 0; parser->cur_chunk = chunk; @@ -442,6 +445,9 @@ STATIC void push_result_node(parser_t *parser, mp_parse_node_t pn) { STATIC mp_parse_node_t make_node_const_object(parser_t *parser, size_t src_line, mp_obj_t obj) { mp_parse_node_struct_t *pn = parser_alloc(parser, sizeof(mp_parse_node_struct_t) + sizeof(mp_obj_t)); + if (pn == NULL) { + return MP_PARSE_NODE_NULL; + } pn->source_line = src_line; #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D // nodes are 32-bit pointers, but need to store 64-bit object @@ -600,7 +606,7 @@ STATIC bool fold_logical_constants(parser_t *parser, uint8_t rule_id, size_t *nu return false; } -STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { +STATIC int fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { // this code does folding of arbitrary integer expressions, eg 1 + 2 * 3 + 4 // it does not do partial folding, eg 1 + 2 + x -> 3 + x @@ -706,7 +712,8 @@ STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { "constant must be an integer"); mp_obj_exception_add_traceback(exc, parser->lexer->source_name, ((mp_parse_node_struct_t*)pn1)->source_line, MP_QSTRnull); - nlr_raise(exc); + mp_raise_o(exc); + return -1; } // store the value in the table of dynamic constants @@ -807,6 +814,9 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, #endif mp_parse_node_struct_t *pn = parser_alloc(parser, sizeof(mp_parse_node_struct_t) + sizeof(mp_parse_node_t) * num_args); + if (pn == NULL) { + return; + } pn->source_line = src_line; pn->kind_num_nodes = (rule_id & 0xff) | (num_args << 8); for (size_t i = num_args; i > 0; i--) { @@ -829,6 +839,10 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { parser.result_stack_top = 0; parser.result_stack = m_new(mp_parse_node_t, parser.result_stack_alloc); + if (MP_STATE_THREAD(active_exception) != NULL) { + return parser.tree; + } + parser.lexer = lex; parser.tree.chunk = NULL; @@ -1103,6 +1117,10 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { break; } } + + if (MP_STATE_THREAD(active_exception) != NULL) { + return parser.tree; + } } #if MICROPY_COMP_CONST @@ -1139,7 +1157,8 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // add traceback to give info about file name and location // we don't have a 'block' name, so just pass the NULL qstr to indicate this mp_obj_exception_add_traceback(exc, lex->source_name, lex->tok_line, MP_QSTRnull); - nlr_raise(exc); + mp_raise_o(exc); + return parser.tree; } // get the root parse node that we created diff --git a/py/parsenum.c b/py/parsenum.c index 2b01b7259aec6..2a536aa6c7c95 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -36,14 +36,14 @@ #include #endif -STATIC NORETURN void raise_exc(mp_obj_t exc, mp_lexer_t *lex) { +STATIC mp_obj_t raise_exc(mp_obj_t exc, mp_lexer_t *lex) { // if lex!=NULL then the parser called us and we need to convert the // exception's type from ValueError to SyntaxError and add traceback info if (lex != NULL) { ((mp_obj_base_t*)MP_OBJ_TO_PTR(exc))->type = &mp_type_SyntaxError; mp_obj_exception_add_traceback(exc, lex->source_name, lex->tok_line, MP_QSTRnull); } - nlr_raise(exc); + return mp_raise_o(exc); } mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, mp_lexer_t *lex) { @@ -55,7 +55,7 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m // check radix base if ((base != 0 && base < 2) || base > 36) { // this won't be reached if lex!=NULL - mp_raise_ValueError("int() arg 2 must be >= 2 and <= 36"); + return mp_raise_ValueError_o("int() arg 2 must be >= 2 and <= 36"); } // skip leading space @@ -147,11 +147,11 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_ValueError, "invalid syntax for integer"); - raise_exc(exc, lex); + return raise_exc(exc, lex); } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL) { mp_obj_t exc = mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid syntax for integer with base %d", base); - raise_exc(exc, lex); + return raise_exc(exc, lex); } else { vstr_t vstr; mp_print_t print; @@ -160,7 +160,7 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m mp_str_print_quoted(&print, str_val_start, top - str_val_start, true); mp_obj_t exc = mp_obj_new_exception_arg1(&mp_type_ValueError, mp_obj_new_str_from_vstr(&mp_type_str, &vstr)); - raise_exc(exc, lex); + return raise_exc(exc, lex); } } @@ -342,7 +342,7 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool } #else if (imag || force_complex) { - raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, "complex values not supported"), lex); + return raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, "complex values not supported"), lex); } #endif else { @@ -350,9 +350,9 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool } value_error: - raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid syntax for number"), lex); + return raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid syntax for number"), lex); #else - raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, "decimal numbers not supported"), lex); + return raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, "decimal numbers not supported"), lex); #endif } diff --git a/py/persistentcode.c b/py/persistentcode.c index 8bf46202ba63a..c7a8704047a7d 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -524,12 +524,14 @@ mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader) { || MPY_FEATURE_DECODE_FLAGS(header[2]) != MPY_FEATURE_FLAGS || header[3] > mp_small_int_bits() || read_uint(reader, NULL) > QSTR_WINDOW_SIZE) { - mp_raise_ValueError("incompatible .mpy file"); + mp_raise_ValueError_o("incompatible .mpy file"); + return NULL; } if (MPY_FEATURE_DECODE_ARCH(header[2]) != MP_NATIVE_ARCH_NONE) { byte arch = MPY_FEATURE_DECODE_ARCH(header[2]); if (!MPY_FEATURE_ARCH_TEST(arch)) { - mp_raise_ValueError("incompatible .mpy arch"); + mp_raise_ValueError_o("incompatible .mpy arch"); + return NULL; } } qstr_window_t qw; diff --git a/py/qstr.c b/py/qstr.c index 29ffcae4081b6..bcc2a47c3e722 100644 --- a/py/qstr.c +++ b/py/qstr.c @@ -155,6 +155,7 @@ STATIC qstr qstr_add(const byte *q_ptr) { if (pool == NULL) { QSTR_EXIT(); m_malloc_fail(new_alloc); + return 0; } pool->prev = MP_STATE_VM(last_pool); pool->total_prev_len = MP_STATE_VM(last_pool)->total_prev_len + MP_STATE_VM(last_pool)->len; @@ -201,7 +202,8 @@ qstr qstr_from_strn(const char *str, size_t len) { // check that len is not too big if (len >= (1 << (8 * MICROPY_QSTR_BYTES_IN_LEN))) { QSTR_EXIT(); - mp_raise_msg(&mp_type_RuntimeError, "name too long"); + mp_raise_msg_o(&mp_type_RuntimeError, "name too long"); + return MP_QSTRnull; } // compute number of bytes needed to intern this string @@ -233,6 +235,7 @@ qstr qstr_from_strn(const char *str, size_t len) { if (MP_STATE_VM(qstr_last_chunk) == NULL) { QSTR_EXIT(); m_malloc_fail(n_bytes); + return 0; } al = n_bytes; } diff --git a/py/reader.c b/py/reader.c index 80364104bb12b..591caea74a1d5 100644 --- a/py/reader.c +++ b/py/reader.c @@ -108,6 +108,9 @@ STATIC void mp_reader_posix_close(void *data) { void mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd) { mp_reader_posix_t *rp = m_new_obj(mp_reader_posix_t); + if (rp == NULL) { + return; + } rp->close_fd = close_fd; rp->fd = fd; int n = read(rp->fd, rp->buf, sizeof(rp->buf)); @@ -115,7 +118,8 @@ void mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd) { if (close_fd) { close(fd); } - mp_raise_OSError(errno); + mp_raise_OSError_o(errno); + return; } rp->len = n; rp->pos = 0; @@ -129,7 +133,8 @@ void mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd) { void mp_reader_new_file(mp_reader_t *reader, const char *filename) { int fd = open(filename, O_RDONLY, 0644); if (fd < 0) { - mp_raise_OSError(errno); + mp_raise_OSError_o(errno); + return; } mp_reader_new_file_from_fd(reader, fd, true); } diff --git a/py/runtime.c b/py/runtime.c index deb82e9355096..f72b4426a68b8 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -57,6 +57,8 @@ const mp_obj_module_t mp_module___main__ = { }; void mp_init(void) { + MP_STATE_THREAD(active_exception) = NULL; + qstr_init(); // no pending exceptions to start with @@ -95,9 +97,15 @@ void mp_init(void) { // init global module dict mp_obj_dict_init(&MP_STATE_VM(mp_loaded_modules_dict), 3); + if (MP_STATE_THREAD(active_exception) != NULL) { + return; + } // initialise the __main__ module mp_obj_dict_init(&MP_STATE_VM(dict_main), 1); + if (MP_STATE_THREAD(active_exception) != NULL) { + return; + } mp_obj_dict_store(MP_OBJ_FROM_PTR(&MP_STATE_VM(dict_main)), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); // locals = globals for outer module (see Objects/frameobject.c/PyFrame_New()) @@ -184,9 +192,9 @@ mp_obj_t mp_load_global(qstr qst) { elem = mp_map_lookup((mp_map_t*)&mp_module_builtins_globals.map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); if (elem == NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_NameError, "name not defined"); + return mp_raise_msg_o(&mp_type_NameError, "name not defined"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_NameError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_NameError, "name '%q' isn't defined", qst)); } } @@ -213,10 +221,10 @@ void mp_store_name(qstr qst, mp_obj_t obj) { mp_obj_dict_store(MP_OBJ_FROM_PTR(mp_locals_get()), MP_OBJ_NEW_QSTR(qst), obj); } -void mp_delete_name(qstr qst) { +mp_obj_t mp_delete_name(qstr qst) { DEBUG_OP_printf("delete name %s\n", qstr_str(qst)); // TODO convert KeyError to NameError if qst not found - mp_obj_dict_delete(MP_OBJ_FROM_PTR(mp_locals_get()), MP_OBJ_NEW_QSTR(qst)); + return mp_obj_dict_delete(MP_OBJ_FROM_PTR(mp_locals_get()), MP_OBJ_NEW_QSTR(qst)); } void mp_store_global(qstr qst, mp_obj_t obj) { @@ -224,10 +232,10 @@ void mp_store_global(qstr qst, mp_obj_t obj) { mp_obj_dict_store(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(qst), obj); } -void mp_delete_global(qstr qst) { +mp_obj_t mp_delete_global(qstr qst) { DEBUG_OP_printf("delete global %s\n", qstr_str(qst)); // TODO convert KeyError to NameError if qst not found - mp_obj_dict_delete(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(qst)); + return mp_obj_dict_delete(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(qst)); } mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) { @@ -286,16 +294,16 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) { // In this case provide a more focused error message to not confuse, e.g. chr(1.0) if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { if (op == MP_UNARY_OP_INT) { - mp_raise_TypeError("can't convert to int"); + return mp_raise_TypeError_o("can't convert to int"); } else { - mp_raise_TypeError("unsupported type for operator"); + return mp_raise_TypeError_o("unsupported type for operator"); } } else { if (op == MP_UNARY_OP_INT) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg))); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unsupported type for %q: '%s'", mp_unary_op_method_name[op], mp_obj_get_type_str(arg))); } @@ -386,7 +394,7 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { case MP_BINARY_OP_INPLACE_LSHIFT: { if (rhs_val < 0) { // negative shift not allowed - mp_raise_ValueError("negative shift count"); + return mp_raise_ValueError_o("negative shift count"); } else if (rhs_val >= (mp_int_t)BITS_PER_WORD || lhs_val > (MP_SMALL_INT_MAX >> rhs_val) || lhs_val < (MP_SMALL_INT_MIN >> rhs_val)) { // left-shift will overflow, so use higher precision integer lhs = mp_obj_new_int_from_ll(lhs_val); @@ -401,7 +409,7 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { case MP_BINARY_OP_INPLACE_RSHIFT: if (rhs_val < 0) { // negative shift not allowed - mp_raise_ValueError("negative shift count"); + return mp_raise_ValueError_o("negative shift count"); } else { // standard precision is enough for right-shift if (rhs_val >= (mp_int_t)BITS_PER_WORD) { @@ -567,6 +575,9 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { if (result != MP_OBJ_NULL) { return result; } + if (MP_STATE_THREAD(active_exception) != NULL) { + return MP_OBJ_NULL; + } } #if MICROPY_PY_REVERSE_SPECIAL_METHODS @@ -590,6 +601,10 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { // mp_getiter will raise the appropriate exception if lhs is not iterable. mp_obj_iter_buf_t iter_buf; mp_obj_t iter = mp_getiter(lhs, &iter_buf); + if (iter == MP_OBJ_NULL) { + // exception + return MP_OBJ_NULL; + } mp_obj_t next; while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { if (mp_obj_equal(next, rhs)) { @@ -601,15 +616,15 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { unsupported_op: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("unsupported type for operator"); + return mp_raise_TypeError_o("unsupported type for operator"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unsupported types for %q: '%s', '%s'", mp_binary_op_method_name[op], mp_obj_get_type_str(lhs), mp_obj_get_type_str(rhs))); } zero_division: - mp_raise_msg(&mp_type_ZeroDivisionError, "divide by zero"); + return mp_raise_msg_o(&mp_type_ZeroDivisionError, "divide by zero"); } mp_obj_t mp_call_function_0(mp_obj_t fun) { @@ -643,9 +658,9 @@ mp_obj_t mp_call_function_n_kw(mp_obj_t fun_in, size_t n_args, size_t n_kw, cons } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("object not callable"); + return mp_raise_TypeError_o("object not callable"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object isn't callable", mp_obj_get_type_str(fun_in))); } } @@ -662,7 +677,7 @@ mp_obj_t mp_call_method_n_kw(size_t n_args, size_t n_kw, const mp_obj_t *args) { #if !MICROPY_STACKLESS STATIC #endif -void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args, mp_call_args_t *out_args) { +int mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args, mp_call_args_t *out_args) { mp_obj_t fun = *args++; mp_obj_t self = MP_OBJ_NULL; if (have_self) { @@ -779,6 +794,10 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ mp_obj_t key = map->table[i].key; if (!mp_obj_is_qstr(key)) { key = mp_obj_str_intern_checked(key); + if (key == MP_OBJ_NULL) { + // exception + return 1; + } } args2[args2_len++] = key; args2[args2_len++] = map->table[i].value; @@ -827,11 +846,15 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ out_args->n_args = pos_args_len; out_args->n_kw = (args2_len - pos_args_len) / 2; out_args->n_alloc = args2_alloc; + + return 0; } mp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args) { mp_call_args_t out_args; - mp_call_prepare_args_n_kw_var(have_self, n_args_n_kw, args, &out_args); + if (mp_call_prepare_args_n_kw_var(have_self, n_args_n_kw, args, &out_args)) { + return MP_OBJ_NULL; + } mp_obj_t res = mp_call_function_n_kw(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t)); @@ -840,7 +863,7 @@ mp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ob } // unpacked items are stored in reverse order into the array pointed to by items -void mp_unpack_sequence(mp_obj_t seq_in, size_t num, mp_obj_t *items) { +mp_obj_t mp_unpack_sequence(mp_obj_t seq_in, size_t num, mp_obj_t *items) { size_t seq_len; if (mp_obj_is_type(seq_in, &mp_type_tuple) || mp_obj_is_type(seq_in, &mp_type_list)) { mp_obj_t *seq_items; @@ -868,26 +891,26 @@ void mp_unpack_sequence(mp_obj_t seq_in, size_t num, mp_obj_t *items) { goto too_long; } } - return; + return MP_OBJ_SENTINEL; // success too_short: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_ValueError("wrong number of values to unpack"); + return mp_raise_ValueError_o("wrong number of values to unpack"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "need more than %d values to unpack", (int)seq_len)); } too_long: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_ValueError("wrong number of values to unpack"); + return mp_raise_ValueError_o("wrong number of values to unpack"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "too many values to unpack (expected %d)", (int)num)); } } // unpacked items are stored in reverse order into the array pointed to by items -void mp_unpack_ex(mp_obj_t seq_in, size_t num_in, mp_obj_t *items) { +mp_obj_t mp_unpack_ex(mp_obj_t seq_in, size_t num_in, mp_obj_t *items) { size_t num_left = num_in & 0xff; size_t num_right = (num_in >> 8) & 0xff; DEBUG_OP_printf("unpack ex " UINT_FMT " " UINT_FMT "\n", num_left, num_right); @@ -937,13 +960,13 @@ void mp_unpack_ex(mp_obj_t seq_in, size_t num_in, mp_obj_t *items) { } mp_obj_list_set_len(MP_OBJ_FROM_PTR(rest), rest->len - num_right); } - return; + return MP_OBJ_SENTINEL; // success too_short: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_ValueError("wrong number of values to unpack"); + return mp_raise_ValueError_o("wrong number of values to unpack"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "need more than %d values to unpack", (int)seq_len)); } } @@ -952,7 +975,9 @@ mp_obj_t mp_load_attr(mp_obj_t base, qstr attr) { DEBUG_OP_printf("load attr %p.%s\n", base, qstr_str(attr)); // use load_method mp_obj_t dest[2]; - mp_load_method(base, attr, dest); + if (mp_load_method(base, attr, dest) == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } if (dest[1] == MP_OBJ_NULL) { // load_method returned just a normal attribute return dest[0]; @@ -980,9 +1005,9 @@ STATIC mp_obj_t checked_fun_call(mp_obj_t self_in, size_t n_args, size_t n_kw, c const mp_obj_type_t *arg0_type = mp_obj_get_type(args[0]); if (arg0_type != self->type) { if (MICROPY_ERROR_REPORTING != MICROPY_ERROR_REPORTING_DETAILED) { - mp_raise_TypeError("argument has wrong type"); + return mp_raise_TypeError_o("argument has wrong type"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "argument should be a '%q' not a '%q'", self->type->name, arg0_type->name)); } } @@ -1058,7 +1083,7 @@ void mp_convert_member_lookup(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t // no attribute found, returns: dest[0] == MP_OBJ_NULL, dest[1] == MP_OBJ_NULL // normal attribute found, returns: dest[0] == , dest[1] == MP_OBJ_NULL // method attribute found, returns: dest[0] == , dest[1] == -void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) { +mp_obj_t mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) { // clear output to indicate no attribute/method found yet dest[0] = MP_OBJ_NULL; dest[1] = MP_OBJ_NULL; @@ -1080,6 +1105,9 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) { } else if (type->attr != NULL) { // this type can do its own load, so call it type->attr(obj, attr, dest); + if (MP_STATE_THREAD(active_exception) != NULL) { + return MP_OBJ_NULL; + } } else if (type->locals_dict != NULL) { // generic method lookup @@ -1091,63 +1119,74 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) { mp_convert_member_lookup(obj, type, elem->value, dest); } } + + return MP_OBJ_SENTINEL; // success } -void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) { +mp_obj_t mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) { DEBUG_OP_printf("load method %p.%s\n", base, qstr_str(attr)); - mp_load_method_maybe(base, attr, dest); + if (mp_load_method_maybe(base, attr, dest) == MP_OBJ_NULL) { + // exception + return MP_OBJ_NULL; + } if (dest[0] == MP_OBJ_NULL) { // no attribute/method called attr if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_AttributeError, "no such attribute"); + return mp_raise_msg_o(&mp_type_AttributeError, "no such attribute"); } else { // following CPython, we give a more detailed error message for type objects if (mp_obj_is_type(base, &mp_type_type)) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "type object '%q' has no attribute '%q'", ((mp_obj_type_t*)MP_OBJ_TO_PTR(base))->name, attr)); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "'%s' object has no attribute '%q'", mp_obj_get_type_str(base), attr)); } } } + + return MP_OBJ_SENTINEL; // success } // Acts like mp_load_method_maybe but catches AttributeError, and all other exceptions if requested -void mp_load_method_protected(mp_obj_t obj, qstr attr, mp_obj_t *dest, bool catch_all_exc) { - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_load_method_maybe(obj, attr, dest); - nlr_pop(); - } else { +mp_obj_t mp_load_method_protected(mp_obj_t obj, qstr attr, mp_obj_t *dest, bool catch_all_exc) { + if (mp_load_method_maybe(obj, attr, dest) == MP_OBJ_NULL) { + // exception + mp_obj_base_t *exc = MP_STATE_THREAD(active_exception); + MP_STATE_THREAD(active_exception) = NULL; if (!catch_all_exc - && !mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), + && !mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_AttributeError))) { // Re-raise the exception - nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val)); + return mp_raise_o(MP_OBJ_FROM_PTR(exc)); } } + return MP_OBJ_SENTINEL; // success } -void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) { +mp_obj_t mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) { DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), value); mp_obj_type_t *type = mp_obj_get_type(base); if (type->attr != NULL) { mp_obj_t dest[2] = {MP_OBJ_SENTINEL, value}; type->attr(base, attr, dest); + if (MP_STATE_THREAD(active_exception) != NULL) { + // exception + return MP_OBJ_NULL; + } if (dest[0] == MP_OBJ_NULL) { // success - return; + return MP_OBJ_SENTINEL; } } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_AttributeError, "no such attribute"); + return mp_raise_msg_o(&mp_type_AttributeError, "no such attribute"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "'%s' object has no attribute '%q'", mp_obj_get_type_str(base), attr)); } @@ -1186,9 +1225,9 @@ mp_obj_t mp_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { // object not iterable if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("object not iterable"); + return mp_raise_TypeError_o("object not iterable"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object isn't iterable", mp_obj_get_type_str(o_in))); } } @@ -1208,9 +1247,9 @@ mp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) { return mp_call_method_n_kw(0, 0, dest); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("object not an iterator"); + return mp_raise_TypeError_o("object not an iterator"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object isn't an iterator", mp_obj_get_type_str(o_in))); } } @@ -1220,7 +1259,9 @@ mp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) { // will always return MP_OBJ_STOP_ITERATION instead of raising StopIteration() (or any subclass thereof) // may raise other exceptions mp_obj_t mp_iternext(mp_obj_t o_in) { - MP_STACK_CHECK(); // enumerate, filter, map and zip can recursively call mp_iternext + if (MP_STACK_CHECK()) { // enumerate, filter, map and zip can recursively call mp_iternext + return MP_OBJ_NULL; + } mp_obj_type_t *type = mp_obj_get_type(o_in); if (type->iternext != NULL) { return type->iternext(o_in); @@ -1230,29 +1271,50 @@ mp_obj_t mp_iternext(mp_obj_t o_in) { mp_load_method_maybe(o_in, MP_QSTR___next__, dest); if (dest[0] != MP_OBJ_NULL) { // __next__ exists, call it and return its result - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_obj_t ret = mp_call_method_n_kw(0, 0, dest); - nlr_pop(); + mp_obj_t ret = mp_call_method_n_kw(0, 0, dest); + if (ret != MP_OBJ_NULL) { return ret; } else { - if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { + // exception + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(MP_STATE_THREAD(active_exception)->type), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { + MP_STATE_THREAD(active_exception) = NULL; return MP_OBJ_STOP_ITERATION; } else { - nlr_jump(nlr.ret_val); + // reraise + return MP_OBJ_NULL; } } } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("object not an iterator"); + return mp_raise_TypeError_o("object not an iterator"); } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object isn't an iterator", mp_obj_get_type_str(o_in))); } } } } +mp_obj_t mp_iternext2(mp_obj_t o) { + if (o == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } + o = mp_iternext(o); + if (o == MP_OBJ_STOP_ITERATION) { + MP_STATE_THREAD(active_exception) = (void*)1; + return MP_OBJ_NULL; + } + return o; +} + +bool mp_iternext_had_exc(void) { + if (MP_STATE_THREAD(active_exception) == (void*)1) { + MP_STATE_THREAD(active_exception) = NULL; + return false; + } + return MP_STATE_THREAD(active_exception) != NULL; +} + // TODO: Unclear what to do with StopIterarion exception here. mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) { assert((send_value != MP_OBJ_NULL) ^ (throw_value != MP_OBJ_NULL)); @@ -1264,6 +1326,12 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th if (type->iternext != NULL && send_value == mp_const_none) { mp_obj_t ret = type->iternext(self_in); + if (ret == MP_OBJ_NULL) { + // exception + *ret_val = MP_OBJ_FROM_PTR(MP_STATE_THREAD(active_exception)); + MP_STATE_THREAD(active_exception) = NULL; + return MP_VM_RETURN_EXCEPTION; + } *ret_val = ret; if (ret != MP_OBJ_STOP_ITERATION) { return MP_VM_RETURN_YIELD; @@ -1281,6 +1349,11 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th mp_load_method_maybe(self_in, MP_QSTR___next__, dest); if (dest[0] != MP_OBJ_NULL) { *ret_val = mp_call_method_n_kw(0, 0, dest); + if (*ret_val == MP_OBJ_NULL) { + *ret_val = MP_OBJ_FROM_PTR(MP_STATE_THREAD(active_exception)); + MP_STATE_THREAD(active_exception) = NULL; + return MP_VM_RETURN_EXCEPTION; + } return MP_VM_RETURN_YIELD; } } @@ -1382,7 +1455,7 @@ mp_obj_t mp_import_from(mp_obj_t module, qstr name) { if (dest[1] != MP_OBJ_NULL) { // Hopefully we can't import bound method from an object import_error: - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "cannot import name %q", name)); + return mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "cannot import name %q", name)); } if (dest[0] != MP_OBJ_NULL) { @@ -1449,13 +1522,12 @@ mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_i mp_globals_set(globals); mp_locals_set(locals); - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - qstr source_name = lex->source_name; - mp_parse_tree_t parse_tree = mp_parse(lex, parse_input_kind); - mp_obj_t module_fun = mp_compile(&parse_tree, source_name, false); + qstr source_name = lex->source_name; + mp_parse_tree_t parse_tree = mp_parse(lex, parse_input_kind); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, false); - mp_obj_t ret; + mp_obj_t ret = MP_OBJ_NULL; + if (module_fun != MP_OBJ_NULL) { if (MICROPY_PY_BUILTINS_COMPILE && globals == NULL) { // for compile only, return value is the module function ret = module_fun; @@ -1463,31 +1535,27 @@ mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_i // execute module function and get return value ret = mp_call_function_0(module_fun); } - - // finish nlr block, restore context and return value - nlr_pop(); - mp_globals_set(old_globals); - mp_locals_set(old_locals); - return ret; - } else { - // exception; restore context and re-raise same exception - mp_globals_set(old_globals); - mp_locals_set(old_locals); - nlr_jump(nlr.ret_val); } + + // restore context and return value + mp_globals_set(old_globals); + mp_locals_set(old_locals); + return ret; } #endif // MICROPY_ENABLE_COMPILER -NORETURN void m_malloc_fail(size_t num_bytes) { +void *m_malloc_fail(size_t num_bytes) { DEBUG_printf("memory allocation failed, allocating %u bytes\n", (uint)num_bytes); #if MICROPY_ENABLE_GC if (gc_is_locked()) { - mp_raise_msg(&mp_type_MemoryError, "memory allocation failed, heap is locked"); + mp_raise_msg_o(&mp_type_MemoryError, "memory allocation failed, heap is locked"); + return NULL; } #endif - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, + mp_raise_o(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, "memory allocation failed, allocating %u bytes", (uint)num_bytes)); + return NULL; } NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const char *msg) { @@ -1515,8 +1583,41 @@ NORETURN void mp_raise_NotImplementedError(const char *msg) { } #if MICROPY_STACK_CHECK || MICROPY_ENABLE_PYSTACK -NORETURN void mp_raise_recursion_depth(void) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError, +void mp_raise_recursion_depth(void) { + mp_raise_o(mp_obj_new_exception_arg1(&mp_type_RuntimeError, MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded))); } #endif + +mp_obj_t mp_raise_o(mp_obj_t exc) { + //printf("mp_raise_o(%p)\n", MP_OBJ_TO_PTR(exc)); + // don't overwrite an existing exception + if (MP_STATE_THREAD(active_exception) == NULL) { + MP_STATE_THREAD(active_exception) = MP_OBJ_TO_PTR(exc); + } + return MP_OBJ_NULL; +} + +mp_obj_t mp_raise_msg_o(const mp_obj_type_t *exc_type, const char *msg) { + if (msg == NULL) { + return mp_raise_o(mp_obj_new_exception(exc_type)); + } else { + return mp_raise_o(mp_obj_new_exception_msg(exc_type, msg)); + } +} + +mp_obj_t mp_raise_ValueError_o(const char *msg) { + return mp_raise_msg_o(&mp_type_ValueError, msg); +} + +mp_obj_t mp_raise_TypeError_o(const char *msg) { + return mp_raise_msg_o(&mp_type_TypeError, msg); +} + +mp_obj_t mp_raise_NotImplementedError_o(const char *msg) { + return mp_raise_msg_o(&mp_type_NotImplementedError, msg); +} + +mp_obj_t mp_raise_OSError_o(int errno_) { + return mp_raise_o(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno_))); +} diff --git a/py/runtime.h b/py/runtime.h index b54b17b683951..694e003a37964 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -77,14 +77,14 @@ bool mp_sched_schedule(mp_obj_t function, mp_obj_t arg); // extra printing method specifically for mp_obj_t's which are integral type int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char, int flags, char fill, int width, int prec); -void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig); -static inline void mp_arg_check_num(size_t n_args, size_t n_kw, size_t n_args_min, size_t n_args_max, bool takes_kw) { - mp_arg_check_num_sig(n_args, n_kw, MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, takes_kw)); +int mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig); +static inline int mp_arg_check_num(size_t n_args, size_t n_kw, size_t n_args_min, size_t n_args_max, bool takes_kw) { + return mp_arg_check_num_sig(n_args, n_kw, MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, takes_kw)); } -void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals); -void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals); -NORETURN void mp_arg_error_terse_mismatch(void); -NORETURN void mp_arg_error_unimpl_kw(void); +int mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals); +int mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals); +void mp_arg_error_terse_mismatch(void); +void mp_arg_error_unimpl_kw(void); static inline mp_obj_dict_t *mp_locals_get(void) { return MP_STATE_THREAD(dict_locals); } static inline void mp_locals_set(mp_obj_dict_t *d) { MP_STATE_THREAD(dict_locals) = d; } @@ -96,8 +96,8 @@ mp_obj_t mp_load_global(qstr qst); mp_obj_t mp_load_build_class(void); void mp_store_name(qstr qst, mp_obj_t obj); void mp_store_global(qstr qst, mp_obj_t obj); -void mp_delete_name(qstr qst); -void mp_delete_global(qstr qst); +mp_obj_t mp_delete_name(qstr qst); +mp_obj_t mp_delete_global(qstr qst); mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg); mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs); @@ -125,23 +125,25 @@ typedef struct _mp_call_args_t { // prepares argument array suitable for passing to ->call() method of a // function object (and mp_call_function_n_kw()). // (Only needed in stackless mode.) -void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args, mp_call_args_t *out_args); +int mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args, mp_call_args_t *out_args); #endif -void mp_unpack_sequence(mp_obj_t seq, size_t num, mp_obj_t *items); -void mp_unpack_ex(mp_obj_t seq, size_t num, mp_obj_t *items); +mp_obj_t mp_unpack_sequence(mp_obj_t seq, size_t num, mp_obj_t *items); +mp_obj_t mp_unpack_ex(mp_obj_t seq, size_t num, mp_obj_t *items); mp_obj_t mp_store_map(mp_obj_t map, mp_obj_t key, mp_obj_t value); mp_obj_t mp_load_attr(mp_obj_t base, qstr attr); void mp_convert_member_lookup(mp_obj_t obj, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest); -void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest); -void mp_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest); -void mp_load_method_protected(mp_obj_t obj, qstr attr, mp_obj_t *dest, bool catch_all_exc); -void mp_load_super_method(qstr attr, mp_obj_t *dest); -void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t val); +mp_obj_t mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest); +mp_obj_t mp_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest); +mp_obj_t mp_load_method_protected(mp_obj_t obj, qstr attr, mp_obj_t *dest, bool catch_all_exc); +mp_obj_t mp_load_super_method(qstr attr, mp_obj_t *dest); +mp_obj_t mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t val); mp_obj_t mp_getiter(mp_obj_t o, mp_obj_iter_buf_t *iter_buf); mp_obj_t mp_iternext_allow_raise(mp_obj_t o); // may return MP_OBJ_STOP_ITERATION instead of raising StopIteration() mp_obj_t mp_iternext(mp_obj_t o); // will always return MP_OBJ_STOP_ITERATION instead of raising StopIteration(...) +mp_obj_t mp_iternext2(mp_obj_t o); +bool mp_iternext_had_exc(void); mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val); mp_obj_t mp_make_raise_obj(mp_obj_t o); @@ -155,7 +157,14 @@ NORETURN void mp_raise_ValueError(const char *msg); NORETURN void mp_raise_TypeError(const char *msg); NORETURN void mp_raise_NotImplementedError(const char *msg); NORETURN void mp_raise_OSError(int errno_); -NORETURN void mp_raise_recursion_depth(void); +void mp_raise_recursion_depth(void); + +mp_obj_t mp_raise_o(mp_obj_t exc); +mp_obj_t mp_raise_msg_o(const mp_obj_type_t *exc_type, const char *msg); +mp_obj_t mp_raise_ValueError_o(const char *msg); +mp_obj_t mp_raise_TypeError_o(const char *msg); +mp_obj_t mp_raise_NotImplementedError_o(const char *msg); +mp_obj_t mp_raise_OSError_o(int errno_); #if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG #undef mp_check_self diff --git a/py/runtime_utils.c b/py/runtime_utils.c index b92c6bd767cd8..693e5fbacf639 100644 --- a/py/runtime_utils.c +++ b/py/runtime_utils.c @@ -28,25 +28,19 @@ #include "py/runtime.h" mp_obj_t mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg) { - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_obj_t ret = mp_call_function_1(fun, arg); - nlr_pop(); - return ret; - } else { - mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); - return MP_OBJ_NULL; + mp_obj_t ret = mp_call_function_1(fun, arg); + if (ret == MP_OBJ_NULL) { + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(MP_STATE_THREAD(active_exception))); + MP_STATE_THREAD(active_exception) = NULL; } + return ret; } mp_obj_t mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2) { - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_obj_t ret = mp_call_function_2(fun, arg1, arg2); - nlr_pop(); - return ret; - } else { - mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); - return MP_OBJ_NULL; + mp_obj_t ret = mp_call_function_2(fun, arg1, arg2); + if (ret == MP_OBJ_NULL) { + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(MP_STATE_THREAD(active_exception))); + MP_STATE_THREAD(active_exception) = NULL; } + return ret; } diff --git a/py/scope.c b/py/scope.c index d996731f85d6b..f419d8e6b0e2f 100644 --- a/py/scope.c +++ b/py/scope.c @@ -42,6 +42,9 @@ STATIC const uint8_t scope_simple_name_table[] = { scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, mp_uint_t emit_options) { scope_t *scope = m_new0(scope_t, 1); + if (scope == NULL) { + return NULL; + } scope->kind = kind; scope->pn = pn; scope->source_file = source_file; @@ -56,6 +59,10 @@ scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, mp_u scope->id_info_alloc = MICROPY_ALLOC_SCOPE_ID_INIT; scope->id_info = m_new(id_info_t, scope->id_info_alloc); + if (scope->raw_code == NULL || scope->id_info == NULL) { + return NULL; + } + return scope; } @@ -73,6 +80,9 @@ id_info_t *scope_find_or_add_id(scope_t *scope, qstr qst, scope_kind_t kind) { // make sure we have enough memory if (scope->id_info_len >= scope->id_info_alloc) { scope->id_info = m_renew(id_info_t, scope->id_info, scope->id_info_alloc, scope->id_info_alloc + MICROPY_ALLOC_SCOPE_ID_INC); + if (scope->id_info == NULL) { + return NULL; + } scope->id_info_alloc += MICROPY_ALLOC_SCOPE_ID_INC; } @@ -89,6 +99,9 @@ id_info_t *scope_find_or_add_id(scope_t *scope, qstr qst, scope_kind_t kind) { } id_info_t *scope_find(scope_t *scope, qstr qst) { + if (scope->id_info == NULL) { + return NULL; + } for (mp_uint_t i = 0; i < scope->id_info_len; i++) { if (scope->id_info[i].qst == qst) { return &scope->id_info[i]; diff --git a/py/sequence.c b/py/sequence.c index 4c19fc69ea3d5..83c966b3ad847 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -45,7 +45,7 @@ void mp_seq_multiply(const void *items, size_t item_sz, size_t len, size_t times #if MICROPY_PY_BUILTINS_SLICE -bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes) { +int mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes) { mp_obj_t ostart, ostop, ostep; mp_int_t start, stop; mp_obj_slice_get(slice, &ostart, &ostop, &ostep); @@ -53,7 +53,8 @@ bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { indexes->step = mp_obj_get_int(ostep); if (indexes->step == 0) { - mp_raise_ValueError("slice step cannot be zero"); + mp_raise_ValueError_o("slice step cannot be zero"); + return -1; } } else { indexes->step = 1; @@ -260,7 +261,7 @@ mp_obj_t mp_seq_index_obj(const mp_obj_t *items, size_t len, size_t n_args, cons } } - mp_raise_ValueError("object not in sequence"); + return mp_raise_ValueError_o("object not in sequence"); } mp_obj_t mp_seq_count_obj(const mp_obj_t *items, size_t len, mp_obj_t value) { diff --git a/py/stackctrl.c b/py/stackctrl.c index 5c07796bde399..013a6cd2e4c32 100644 --- a/py/stackctrl.c +++ b/py/stackctrl.c @@ -48,10 +48,12 @@ void mp_stack_set_limit(mp_uint_t limit) { MP_STATE_THREAD(stack_limit) = limit; } -void mp_stack_check(void) { +int mp_stack_check(void) { if (mp_stack_usage() >= MP_STATE_THREAD(stack_limit)) { mp_raise_recursion_depth(); + return 1; } + return 0; } #endif // MICROPY_STACK_CHECK diff --git a/py/stackctrl.h b/py/stackctrl.h index ff8da0ab138c3..35629ccaa8acd 100644 --- a/py/stackctrl.h +++ b/py/stackctrl.h @@ -35,13 +35,15 @@ mp_uint_t mp_stack_usage(void); #if MICROPY_STACK_CHECK void mp_stack_set_limit(mp_uint_t limit); -void mp_stack_check(void); +int mp_stack_check(void); #define MP_STACK_CHECK() mp_stack_check() #else #define mp_stack_set_limit(limit) -#define MP_STACK_CHECK() +static inline int MP_STACK_CHECK(void) { + return 0; +} #endif diff --git a/py/stream.c b/py/stream.c index 762cd0fc08cf1..96769d2ae6573 100644 --- a/py/stream.c +++ b/py/stream.c @@ -92,7 +92,8 @@ const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) { || ((flags & MP_STREAM_OP_WRITE) && stream_p->write == NULL) || ((flags & MP_STREAM_OP_IOCTL) && stream_p->ioctl == NULL)) { // CPython: io.UnsupportedOperation, OSError subclass - mp_raise_msg(&mp_type_OSError, "stream operation not supported"); + mp_raise_msg_o(&mp_type_OSError, "stream operation not supported"); + return NULL; } return stream_p; } @@ -140,7 +141,7 @@ STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte fl } break; } - mp_raise_OSError(error); + return mp_raise_OSError_o(error); } if (out_sz < more_bytes) { @@ -208,7 +209,7 @@ STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte fl // this as EOF. return mp_const_none; } - mp_raise_OSError(error); + return mp_raise_OSError_o(error); } else { vstr.len = out_sz; return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr); @@ -235,7 +236,7 @@ mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte fla // no single byte could be readily written to it." return mp_const_none; } - mp_raise_OSError(error); + return mp_raise_OSError_o(error); } else { return MP_OBJ_NEW_SMALL_INT(out_sz); } @@ -293,7 +294,7 @@ STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) { if (mp_is_nonblocking_error(error)) { return mp_const_none; } - mp_raise_OSError(error); + return mp_raise_OSError_o(error); } else { return MP_OBJ_NEW_SMALL_INT(out_sz); } @@ -312,6 +313,9 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) { int error; mp_uint_t out_sz = stream_p->read(self_in, p, current_read, &error); if (out_sz == MP_STREAM_ERROR) { + if (MP_STATE_THREAD(active_exception) != NULL) { + return MP_OBJ_NULL; + } if (mp_is_nonblocking_error(error)) { // With non-blocking streams, we read as much as we can. // If we read nothing, return None, just like read(). @@ -321,7 +325,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) { } break; } - mp_raise_OSError(error); + return mp_raise_OSError_o(error); } if (out_sz == 0) { break; @@ -361,6 +365,9 @@ STATIC mp_obj_t stream_unbuffered_readline(size_t n_args, const mp_obj_t *args) int error; mp_uint_t out_sz = stream_p->read(args[0], p, 1, &error); if (out_sz == MP_STREAM_ERROR) { + if (MP_STATE_THREAD(active_exception) != NULL) { + return MP_OBJ_NULL; + } if (mp_is_nonblocking_error(error)) { if (vstr.len == 1) { // We just incremented it, but otherwise we read nothing @@ -375,7 +382,7 @@ STATIC mp_obj_t stream_unbuffered_readline(size_t n_args, const mp_obj_t *args) goto done; } } - mp_raise_OSError(error); + return mp_raise_OSError_o(error); } if (out_sz == 0) { done: @@ -421,7 +428,10 @@ mp_obj_t mp_stream_close(mp_obj_t stream) { int error; mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error); if (res == MP_STREAM_ERROR) { - mp_raise_OSError(error); + if (MP_STATE_THREAD(active_exception) != NULL) { + return MP_OBJ_NULL; + } + return mp_raise_OSError_o(error); } return mp_const_none; } @@ -438,14 +448,17 @@ STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) { // In POSIX, it's error to seek before end of stream, we enforce it here. if (seek_s.whence == SEEK_SET && seek_s.offset < 0) { - mp_raise_OSError(MP_EINVAL); + return mp_raise_OSError_o(MP_EINVAL); } const mp_stream_p_t *stream_p = mp_get_stream(args[0]); int error; mp_uint_t res = stream_p->ioctl(args[0], MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &error); if (res == MP_STREAM_ERROR) { - mp_raise_OSError(error); + if (MP_STATE_THREAD(active_exception) != NULL) { + return MP_OBJ_NULL; + } + return mp_raise_OSError_o(error); } // TODO: Could be uint64 @@ -466,7 +479,10 @@ STATIC mp_obj_t stream_flush(mp_obj_t self) { int error; mp_uint_t res = stream_p->ioctl(self, MP_STREAM_FLUSH, 0, &error); if (res == MP_STREAM_ERROR) { - mp_raise_OSError(error); + if (MP_STATE_THREAD(active_exception) != NULL) { + return MP_OBJ_NULL; + } + return mp_raise_OSError_o(error); } return mp_const_none; } @@ -487,7 +503,10 @@ STATIC mp_obj_t stream_ioctl(size_t n_args, const mp_obj_t *args) { int error; mp_uint_t res = stream_p->ioctl(args[0], mp_obj_get_int(args[1]), val, &error); if (res == MP_STREAM_ERROR) { - mp_raise_OSError(error); + if (MP_STATE_THREAD(active_exception) != NULL) { + return MP_OBJ_NULL; + } + return mp_raise_OSError_o(error); } return mp_obj_new_int(res); diff --git a/py/vm.c b/py/vm.c index 7c702f3863cfc..e771fcbb2168d 100644 --- a/py/vm.c +++ b/py/vm.c @@ -227,7 +227,8 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp // sees that it's possible for us to jump from the dispatch loop to the exception // handler. Without this, the code may have a different stack layout in the dispatch // loop and the exception handler, leading to very obscure bugs. - #define RAISE(o) do { nlr_pop(); nlr.ret_val = MP_OBJ_TO_PTR(o); goto exception_handler; } while (0) + #define RAISE(o) do { MP_STATE_THREAD(active_exception) = MP_OBJ_TO_PTR(o); goto exception_handler; } while (0) + #define RAISE_IT() do { goto exception_handler; } while (0) #if MICROPY_STACKLESS run_code_state: ; @@ -259,9 +260,7 @@ FRAME_SETUP(); // outer exception handling loop for (;;) { - nlr_buf_t nlr; -outer_dispatch_loop: - if (nlr_push(&nlr) == 0) { + { // local variables that are not visible to the exception handler const byte *ip = code_state->ip; mp_obj_t *sp = code_state->sp; @@ -359,6 +358,9 @@ FRAME_SETUP(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; PUSH(mp_load_name(qst)); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } #else @@ -371,6 +373,9 @@ FRAME_SETUP(); obj = elem->value; } else { obj = mp_load_name(qst); + if (obj == MP_OBJ_NULL) { + RAISE_IT(); + } } PUSH(obj); ip++; @@ -383,6 +388,9 @@ FRAME_SETUP(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; PUSH(mp_load_global(qst)); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } #else @@ -395,6 +403,9 @@ FRAME_SETUP(); obj = elem->value; } else { obj = mp_load_global(qst); + if (obj == MP_OBJ_NULL) { + RAISE_IT(); + } } PUSH(obj); ip++; @@ -408,6 +419,9 @@ FRAME_SETUP(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; SET_TOP(mp_load_attr(TOP(), qst)); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } #else @@ -426,6 +440,9 @@ FRAME_SETUP(); obj = elem->value; } else { obj = mp_load_attr(top, qst); + if (obj == MP_OBJ_NULL) { + RAISE_IT(); + } } SET_TOP(obj); ip++; @@ -436,7 +453,9 @@ FRAME_SETUP(); ENTRY(MP_BC_LOAD_METHOD): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; - mp_load_method(*sp, qst, sp); + if (mp_load_method(*sp, qst, sp) == MP_OBJ_NULL) { + RAISE_IT(); + } sp += 1; DISPATCH(); } @@ -445,7 +464,9 @@ FRAME_SETUP(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; sp -= 1; - mp_load_super_method(qst, sp - 1); + if (mp_load_super_method(qst, sp - 1) == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } @@ -458,6 +479,9 @@ FRAME_SETUP(); MARK_EXC_IP_SELECTIVE(); mp_obj_t index = POP(); SET_TOP(mp_obj_subscr(TOP(), index, MP_OBJ_SENTINEL)); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } @@ -492,7 +516,9 @@ FRAME_SETUP(); FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; - mp_store_attr(sp[0], qst, sp[-1]); + if (mp_store_attr(sp[0], qst, sp[-1]) == MP_OBJ_NULL) { + RAISE_IT(); + } sp -= 2; DISPATCH(); } @@ -515,7 +541,9 @@ FRAME_SETUP(); if (elem != NULL) { elem->value = sp[-1]; } else { - mp_store_attr(sp[0], qst, sp[-1]); + if (mp_store_attr(sp[0], qst, sp[-1]) == MP_OBJ_NULL) { + RAISE_IT(); + } } sp -= 2; ip++; @@ -525,7 +553,9 @@ FRAME_SETUP(); ENTRY(MP_BC_STORE_SUBSCR): MARK_EXC_IP_SELECTIVE(); - mp_obj_subscr(sp[-1], sp[0], sp[-2]); + if (mp_obj_subscr(sp[-1], sp[0], sp[-2]) == MP_OBJ_NULL) { + RAISE_IT(); + } sp -= 3; DISPATCH(); @@ -552,14 +582,18 @@ FRAME_SETUP(); ENTRY(MP_BC_DELETE_NAME): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; - mp_delete_name(qst); + if (mp_delete_name(qst) == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } ENTRY(MP_BC_DELETE_GLOBAL): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; - mp_delete_global(qst); + if (mp_delete_global(qst) == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } @@ -640,9 +674,16 @@ FRAME_SETUP(); MARK_EXC_IP_SELECTIVE(); // stack: (..., ctx_mgr) mp_obj_t obj = TOP(); - mp_load_method(obj, MP_QSTR___exit__, sp); - mp_load_method(obj, MP_QSTR___enter__, sp + 2); + if (mp_load_method(obj, MP_QSTR___exit__, sp) == MP_OBJ_NULL) { + RAISE_IT(); + } + if (mp_load_method(obj, MP_QSTR___enter__, sp + 2) == MP_OBJ_NULL) { + RAISE_IT(); + } mp_obj_t ret = mp_call_method_n_kw(0, 0, sp + 2); + if (ret == MP_OBJ_NULL) { + RAISE_IT(); + } sp += 1; PUSH_EXC_BLOCK(1); PUSH(ret); @@ -663,7 +704,9 @@ FRAME_SETUP(); sp[1] = mp_const_none; sp[2] = mp_const_none; sp -= 2; - mp_call_method_n_kw(3, 0, sp); + if (mp_call_method_n_kw(3, 0, sp) == MP_OBJ_NULL) { + RAISE_IT(); + } SET_TOP(mp_const_none); } else if (mp_obj_is_small_int(TOP())) { // Getting here there are two distinct cases: @@ -788,6 +831,9 @@ unwind_jump:; ENTRY(MP_BC_GET_ITER): MARK_EXC_IP_SELECTIVE(); SET_TOP(mp_getiter(TOP(), NULL)); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); // An iterator for a for-loop takes MP_OBJ_ITER_BUF_NSLOTS slots on @@ -800,6 +846,9 @@ unwind_jump:; mp_obj_iter_buf_t *iter_buf = (mp_obj_iter_buf_t*)sp; sp += MP_OBJ_ITER_BUF_NSLOTS - 1; obj = mp_getiter(obj, iter_buf); + if (obj == MP_OBJ_NULL) { + RAISE_IT(); + } if (obj != MP_OBJ_FROM_PTR(iter_buf)) { // Iterator didn't use the stack so indicate that with MP_OBJ_NULL. sp[-MP_OBJ_ITER_BUF_NSLOTS + 1] = MP_OBJ_NULL; @@ -823,6 +872,15 @@ unwind_jump:; if (value == MP_OBJ_STOP_ITERATION) { sp -= MP_OBJ_ITER_BUF_NSLOTS; // pop the exhausted iterator ip += ulab; // jump to after for-block + } else if (value == MP_OBJ_NULL) { + // raised an exception + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(MP_STATE_THREAD(active_exception)->type), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { + MP_STATE_THREAD(active_exception) = NULL; + sp -= MP_OBJ_ITER_BUF_NSLOTS; // pop the exhausted iterator + ip += ulab; // jump to after for-block + } else { + RAISE_IT(); + } } else { PUSH(value); // push the next iteration value #if MICROPY_PY_SYS_SETTRACE @@ -848,6 +906,9 @@ unwind_jump:; DECODE_UINT; sp -= unum - 1; SET_TOP(mp_obj_new_tuple(unum, sp)); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } @@ -856,6 +917,9 @@ unwind_jump:; DECODE_UINT; sp -= unum - 1; SET_TOP(mp_obj_new_list(unum, sp)); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } @@ -863,13 +927,18 @@ unwind_jump:; MARK_EXC_IP_SELECTIVE(); DECODE_UINT; PUSH(mp_obj_new_dict(unum)); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } ENTRY(MP_BC_STORE_MAP): MARK_EXC_IP_SELECTIVE(); sp -= 2; - mp_obj_dict_store(sp[0], sp[2], sp[1]); + if (mp_obj_dict_store(sp[0], sp[2], sp[1]) == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); #if MICROPY_PY_BUILTINS_SET @@ -878,6 +947,9 @@ unwind_jump:; DECODE_UINT; sp -= unum - 1; SET_TOP(mp_obj_new_set(unum, sp)); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } #endif @@ -893,6 +965,9 @@ unwind_jump:; mp_obj_t stop = POP(); mp_obj_t start = TOP(); SET_TOP(mp_obj_new_slice(start, stop, step)); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } #endif @@ -919,7 +994,9 @@ unwind_jump:; ENTRY(MP_BC_UNPACK_SEQUENCE): { MARK_EXC_IP_SELECTIVE(); DECODE_UINT; - mp_unpack_sequence(sp[0], unum, sp); + if (mp_unpack_sequence(sp[0], unum, sp) == MP_OBJ_NULL) { + RAISE_IT(); + } sp += unum - 1; DISPATCH(); } @@ -927,7 +1004,9 @@ unwind_jump:; ENTRY(MP_BC_UNPACK_EX): { MARK_EXC_IP_SELECTIVE(); DECODE_UINT; - mp_unpack_ex(sp[0], unum, sp); + if (mp_unpack_ex(sp[0], unum, sp) == MP_OBJ_NULL) { + RAISE_IT(); + } sp += (unum & 0xff) + ((unum >> 8) & 0xff); DISPATCH(); } @@ -984,18 +1063,21 @@ unwind_jump:; #if MICROPY_STACKLESS_STRICT deep_recursion_error: mp_raise_recursion_depth(); + RAISE_IT(); #endif } else #endif { new_state->prev = code_state; code_state = new_state; - nlr_pop(); goto run_code_state; } } #endif SET_TOP(mp_call_function_n_kw(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1)); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } @@ -1015,7 +1097,9 @@ unwind_jump:; code_state->exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp); mp_call_args_t out_args; - mp_call_prepare_args_n_kw_var(false, unum, sp, &out_args); + if (mp_call_prepare_args_n_kw_var(false, unum, sp, &out_args)) { + RAISE_IT(); + } mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); @@ -1036,12 +1120,14 @@ unwind_jump:; { new_state->prev = code_state; code_state = new_state; - nlr_pop(); goto run_code_state; } } #endif SET_TOP(mp_call_method_n_kw_var(false, unum, sp)); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } @@ -1075,12 +1161,14 @@ unwind_jump:; { new_state->prev = code_state; code_state = new_state; - nlr_pop(); goto run_code_state; } } #endif SET_TOP(mp_call_method_n_kw(unum & 0xff, (unum >> 8) & 0xff, sp)); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } @@ -1100,7 +1188,9 @@ unwind_jump:; code_state->exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp); mp_call_args_t out_args; - mp_call_prepare_args_n_kw_var(true, unum, sp, &out_args); + if (mp_call_prepare_args_n_kw_var(true, unum, sp, &out_args)) { + RAISE_IT(); + } mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); @@ -1121,12 +1211,14 @@ unwind_jump:; { new_state->prev = code_state; code_state = new_state; - nlr_pop(); goto run_code_state; } } #endif SET_TOP(mp_call_method_n_kw_var(true, unum, sp)); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } @@ -1164,7 +1256,6 @@ unwind_jump:; } POP_EXC_BLOCK(); } - nlr_pop(); code_state->sp = sp; assert(exc_sp == exc_stack - 1); MICROPY_VM_HOOK_RETURN @@ -1220,7 +1311,6 @@ unwind_jump:; ENTRY(MP_BC_YIELD_VALUE): yield: - nlr_pop(); code_state->ip = ip; code_state->sp = sp; code_state->exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp); @@ -1236,7 +1326,6 @@ unwind_jump:; mp_obj_t send_value = POP(); mp_obj_t t_exc = MP_OBJ_NULL; mp_obj_t ret_value; - code_state->sp = sp; // Save sp because it's needed if mp_resume raises StopIteration if (inject_exc != MP_OBJ_NULL) { t_exc = inject_exc; inject_exc = MP_OBJ_NULL; @@ -1266,9 +1355,14 @@ unwind_jump:; DISPATCH(); } else { assert(ret_kind == MP_VM_RETURN_EXCEPTION); - assert(!EXC_MATCH(ret_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration))); // Pop exhausted gen sp--; + if (EXC_MATCH(ret_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { + // StopIteration inside yield from call means return a value of + // yield from, so inject exception's value as yield from's result + PUSH(mp_obj_exception_get_value(MP_OBJ_FROM_PTR(ret_value))); + DISPATCH(); + } RAISE(ret_value); } } @@ -1279,6 +1373,9 @@ unwind_jump:; DECODE_QSTR; mp_obj_t obj = POP(); SET_TOP(mp_import_name(qst, obj, TOP())); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } @@ -1287,6 +1384,9 @@ unwind_jump:; MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t obj = mp_import_from(TOP(), qst); + if (obj == MP_OBJ_NULL) { + RAISE_IT(); + } PUSH(obj); DISPATCH(); } @@ -1312,6 +1412,9 @@ unwind_jump:; ENTRY(MP_BC_UNARY_OP_MULTI): MARK_EXC_IP_SELECTIVE(); SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP())); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); ENTRY(MP_BC_BINARY_OP_MULTI): { @@ -1319,6 +1422,9 @@ unwind_jump:; mp_obj_t rhs = POP(); mp_obj_t lhs = TOP(); SET_TOP(mp_binary_op(ip[-1] - MP_BC_BINARY_OP_MULTI, lhs, rhs)); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } @@ -1337,18 +1443,22 @@ unwind_jump:; DISPATCH(); } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_BC_UNARY_OP_MULTI_NUM) { SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP())); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BC_BINARY_OP_MULTI_NUM) { mp_obj_t rhs = POP(); mp_obj_t lhs = TOP(); SET_TOP(mp_binary_op(ip[-1] - MP_BC_BINARY_OP_MULTI, lhs, rhs)); + if (TOP() == MP_OBJ_NULL) { + RAISE_IT(); + } DISPATCH(); } else #endif { - mp_obj_t obj = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "opcode"); - nlr_pop(); code_state->state[0] = obj; FRAME_LEAVE(); return MP_VM_RETURN_EXCEPTION; @@ -1408,12 +1518,18 @@ unwind_jump:; } // for loop - } else { + } + { exception_handler: // exception occurred + assert(MP_STATE_THREAD(active_exception) != NULL); + + // clear exception because we caught it + mp_obj_base_t *the_exc = MP_STATE_THREAD(active_exception); + MP_STATE_THREAD(active_exception) = NULL; #if MICROPY_PY_SYS_EXC_INFO - MP_STATE_VM(cur_exception) = nlr.ret_val; + MP_STATE_VM(cur_exception) = the_exc; #endif #if SELECTIVE_EXC_IP @@ -1421,29 +1537,9 @@ unwind_jump:; code_state->ip -= 1; #endif - if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { - if (code_state->ip) { - // check if it's a StopIteration within a for block - if (*code_state->ip == MP_BC_FOR_ITER) { - const byte *ip = code_state->ip + 1; - DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward - code_state->ip = ip + ulab; // jump to after for-block - code_state->sp -= MP_OBJ_ITER_BUF_NSLOTS; // pop the exhausted iterator - goto outer_dispatch_loop; // continue with dispatch loop - } else if (*code_state->ip == MP_BC_YIELD_FROM) { - // StopIteration inside yield from call means return a value of - // yield from, so inject exception's value as yield from's result - // (Instead of stack pop then push we just replace exhausted gen with value) - *code_state->sp = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val)); - code_state->ip++; // yield from is over, move to next instruction - goto outer_dispatch_loop; // continue with dispatch loop - } - } - } - #if MICROPY_PY_SYS_SETTRACE // Exceptions are traced here - if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_Exception))) { + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)the_exc)->type), MP_OBJ_FROM_PTR(&mp_type_Exception))) { TRACE_TICK(code_state->ip, code_state->sp, true /* yes, it's an exception */); } #endif @@ -1455,7 +1551,7 @@ unwind_jump:; // - constant GeneratorExit object, because it's const // - exceptions re-raised by END_FINALLY // - exceptions re-raised explicitly by "raise" - if (nlr.ret_val != &mp_const_GeneratorExit_obj + if (the_exc != &mp_const_GeneratorExit_obj.base && *code_state->ip != MP_BC_END_FINALLY && *code_state->ip != MP_BC_RAISE_LAST) { const byte *ip = code_state->fun_bc->bytecode; @@ -1478,7 +1574,7 @@ unwind_jump:; ip = mp_decode_uint_skip(ip); #endif size_t source_line = mp_bytecode_get_source_line(ip, bc); - mp_obj_exception_add_traceback(MP_OBJ_FROM_PTR(nlr.ret_val), source_file, source_line, block_name); + mp_obj_exception_add_traceback(MP_OBJ_FROM_PTR(the_exc), source_file, source_line, block_name); } while (exc_sp >= exc_stack && exc_sp->handler <= code_state->ip) { @@ -1499,9 +1595,9 @@ unwind_jump:; code_state->ip = exc_sp->handler; mp_obj_t *sp = MP_TAGPTR_PTR(exc_sp->val_sp); // save this exception in the stack so it can be used in a reraise, if needed - exc_sp->prev_exc = nlr.ret_val; + exc_sp->prev_exc = the_exc; // push exception object so it can be handled by bytecode - PUSH(MP_OBJ_FROM_PTR(nlr.ret_val)); + PUSH(MP_OBJ_FROM_PTR(the_exc)); code_state->sp = sp; #if MICROPY_STACKLESS @@ -1527,7 +1623,7 @@ unwind_jump:; } else { // propagate exception to higher level // Note: ip and sp don't have usable values at this point - code_state->state[0] = MP_OBJ_FROM_PTR(nlr.ret_val); // put exception here because sp is invalid + code_state->state[0] = MP_OBJ_FROM_PTR(the_exc); // put exception here because sp is invalid FRAME_LEAVE(); return MP_VM_RETURN_EXCEPTION; } diff --git a/py/vstr.c b/py/vstr.c index 6f480186e1d5f..8792c0e329ff3 100644 --- a/py/vstr.c +++ b/py/vstr.c @@ -95,7 +95,8 @@ char *vstr_extend(vstr_t *vstr, size_t size) { if (vstr->fixed_buf) { // We can't reallocate, and the caller is expecting the space to // be there, so the only safe option is to raise an exception. - mp_raise_msg(&mp_type_RuntimeError, NULL); + mp_raise_msg_o(&mp_type_RuntimeError, NULL); + return NULL; } char *new_buf = m_renew(char, vstr->buf, vstr->alloc, vstr->alloc + size); char *p = new_buf + vstr->alloc; @@ -104,18 +105,24 @@ char *vstr_extend(vstr_t *vstr, size_t size) { return p; } -STATIC void vstr_ensure_extra(vstr_t *vstr, size_t size) { +STATIC int vstr_ensure_extra(vstr_t *vstr, size_t size) { + if (vstr->buf == NULL) { + // could not allocate a buffer + return -1; + } if (vstr->len + size > vstr->alloc) { if (vstr->fixed_buf) { // We can't reallocate, and the caller is expecting the space to // be there, so the only safe option is to raise an exception. - mp_raise_msg(&mp_type_RuntimeError, NULL); + mp_raise_msg_o(&mp_type_RuntimeError, NULL); + return -1; } size_t new_alloc = ROUND_ALLOC((vstr->len + size) + 16); char *new_buf = m_renew(char, vstr->buf, vstr->alloc, new_alloc); vstr->alloc = new_alloc; vstr->buf = new_buf; } + return 0; } void vstr_hint_size(vstr_t *vstr, size_t size) { @@ -133,7 +140,9 @@ char *vstr_add_len(vstr_t *vstr, size_t len) { char *vstr_null_terminated_str(vstr_t *vstr) { // If there's no more room, add single byte if (vstr->alloc == vstr->len) { - vstr_extend(vstr, 1); + if (vstr_extend(vstr, 1) == NULL) { + return NULL; + } } vstr->buf[vstr->len] = '\0'; return vstr->buf; @@ -173,14 +182,17 @@ void vstr_add_char(vstr_t *vstr, unichar c) { #endif } -void vstr_add_str(vstr_t *vstr, const char *str) { - vstr_add_strn(vstr, str, strlen(str)); +int vstr_add_str(vstr_t *vstr, const char *str) { + return vstr_add_strn(vstr, str, strlen(str)); } -void vstr_add_strn(vstr_t *vstr, const char *str, size_t len) { - vstr_ensure_extra(vstr, len); +int vstr_add_strn(vstr_t *vstr, const char *str, size_t len) { + if (vstr_ensure_extra(vstr, len)) { + return -1; + } memmove(vstr->buf + vstr->len, str, len); vstr->len += len; + return 0; // success } STATIC char *vstr_ins_blank_bytes(vstr_t *vstr, size_t byte_pos, size_t byte_len) { diff --git a/tests/run-tests b/tests/run-tests index 77667c271153f..5c6f8b129dda9 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -49,7 +49,7 @@ def convert_regex_escapes(line): return bytes(''.join(cs), 'utf8') -def run_micropython(pyb, args, test_file, is_special=False): +def run_micropython(pyb, args, test_file, is_special=False, crash_info=None): special_tests = ( 'micropython/meminfo.py', 'basics/bytes_compare3.py', 'basics/builtin_help.py', 'thread/thread_exc2.py', @@ -128,6 +128,9 @@ def run_micropython(pyb, args, test_file, is_special=False): if args.heapsize is not None: cmdlist.extend(['-X', 'heapsize=' + args.heapsize]) + if hasattr(args, 'alloc_max'): + cmdlist.extend(['-X', 'alloc-max=' + str(args.alloc_max)]) + # if running via .mpy, first compile the .py file if args.via_mpy: subprocess.check_output([MPYCROSS, '-mcache-lookup-bc', '-o', 'mpytest.mpy', '-X', 'emit=' + args.emit, test_file]) @@ -140,7 +143,10 @@ def run_micropython(pyb, args, test_file, is_special=False): output_mupy = subprocess.check_output(cmdlist, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as er: had_crash = True + #print(er, dir(er), er.args, er.cmd, er.output, er.returncode) output_mupy = er.output + b'CRASH' + if crash_info is not None: + crash_info[0] = er.returncode # clean up if we had an intermediate .mpy file if args.via_mpy: @@ -460,6 +466,34 @@ def run_tests(pyb, tests, args, base_path="."): skipped_tests.append(test_name) continue + # set to True to run special OOM testing + if False: + print("run", test_file) + got_success = 0 + args.alloc_max = 0 + while True: + rc = [0] + output_mupy = run_micropython(pyb, args, test_file, crash_info=rc) + if rc[0] == 2 and 0 <= args.alloc_max <= 5: + # accept uncaught NLR for first 6 allocs (not handled properly by unix port) + continue + elif output_mupy == b'SKIP\n': + print("skip ", test_file) + skipped_tests.append(test_name) + break + elif args.alloc_max > 1000: + print("no success", args.alloc_max, test_file) + break + elif rc[0] == 0: + got_success += 1 + if got_success >= 3: + break + elif rc[0] != 1: + print(args.alloc_max, rc[0]) + args.alloc_max += 1 + + continue + # get expected output test_file_expected = test_file + '.exp' if os.path.isfile(test_file_expected): pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy