mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...) { // check that the given type is an exception type assert(exc_type->make_new == mp_obj_exception_make_new); // make exception object mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 0); if (o == NULL) { // Couldn't allocate heap memory; use local data instead. // Unfortunately, we won't be able to format the string... o = &mp_emergency_exception_obj; o->base.type = exc_type; o->traceback = MP_OBJ_NULL; o->args = mp_const_empty_tuple; } else { o->base.type = exc_type; o->traceback = MP_OBJ_NULL; o->args = mp_obj_new_tuple(1, NULL); if (fmt == NULL) { // no message assert(0); } else { // render exception message and store as .args[0] // TODO: optimize bufferbloat vstr_t *vstr = vstr_new(); va_list ap; va_start(ap, fmt); vstr_vprintf(vstr, fmt, ap); va_end(ap); o->args->items[0] = mp_obj_new_str((byte*)vstr->buf, vstr->len, false); vstr_free(vstr); } } return o; }
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...) { // check that the given type is an exception type assert(exc_type->make_new == mp_obj_exception_make_new); // make exception object mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 0); if (o == NULL) { // Couldn't allocate heap memory; use local data instead. // Unfortunately, we won't be able to format the string... o = &mp_emergency_exception_obj; o->base.type = exc_type; o->traceback = MP_OBJ_NULL; o->args = mp_const_empty_tuple; #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF // If the user has provided a buffer, then we try to create a tuple // of length 1, which has a string object and the string data. if (mp_emergency_exception_buf_size > (sizeof(mp_obj_tuple_t) + sizeof(mp_obj_str_t) + sizeof(mp_obj_t))) { mp_obj_tuple_t *tuple = (mp_obj_tuple_t *)mp_emergency_exception_buf; mp_obj_str_t *str = (mp_obj_str_t *)&tuple->items[1]; tuple->base.type = &mp_type_tuple; tuple->len = 1; tuple->items[0] = str; byte *str_data = (byte *)&str[1]; uint max_len = mp_emergency_exception_buf + mp_emergency_exception_buf_size - str_data; va_list ap; va_start(ap, fmt); str->len = vsnprintf((char *)str_data, max_len, fmt, ap); va_end(ap); str->base.type = &mp_type_str; str->hash = qstr_compute_hash(str_data, str->len); str->data = str_data; o->args = tuple; uint offset = &str_data[str->len] - mp_emergency_exception_buf; offset += sizeof(void *) - 1; offset &= ~(sizeof(void *) - 1); if ((mp_emergency_exception_buf_size - offset) > (sizeof(mp_obj_list_t) + sizeof(mp_obj_t) * 3)) { // We have room to store some traceback. mp_obj_list_t *list = (mp_obj_list_t *)((byte *)mp_emergency_exception_buf + offset); list->base.type = &mp_type_list; list->items = (mp_obj_t)&list[1]; list->alloc = (mp_emergency_exception_buf + mp_emergency_exception_buf_size - (byte *)list->items) / sizeof(list->items[0]); list->len = 0; o->traceback = list; } } #endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF } else { o->base.type = exc_type; o->traceback = MP_OBJ_NULL; o->args = mp_obj_new_tuple(1, NULL); if (fmt == NULL) { // no message assert(0); } else { // render exception message and store as .args[0] // TODO: optimize bufferbloat vstr_t *vstr = vstr_new(); va_list ap; va_start(ap, fmt); vstr_vprintf(vstr, fmt, ap); va_end(ap); o->args->items[0] = mp_obj_new_str(vstr->buf, vstr->len, false); vstr_free(vstr); } } return o; }
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...) { // check that the given type is an exception type assert(exc_type->make_new == mp_obj_exception_make_new); // make exception object mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 0); if (o == NULL) { // Couldn't allocate heap memory; use local data instead. // Unfortunately, we won't be able to format the string... o = &MP_STATE_VM(mp_emergency_exception_obj); o->base.type = exc_type; o->traceback_data = NULL; o->args = (mp_obj_tuple_t*)&mp_const_empty_tuple_obj; #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF // If the user has provided a buffer, then we try to create a tuple // of length 1, which has a string object and the string data. if (mp_emergency_exception_buf_size > (sizeof(mp_obj_tuple_t) + sizeof(mp_obj_str_t) + sizeof(mp_obj_t))) { mp_obj_tuple_t *tuple = (mp_obj_tuple_t *)MP_STATE_VM(mp_emergency_exception_buf); mp_obj_str_t *str = (mp_obj_str_t *)&tuple->items[1]; tuple->base.type = &mp_type_tuple; tuple->len = 1; tuple->items[0] = MP_OBJ_FROM_PTR(str); byte *str_data = (byte *)&str[1]; uint max_len = MP_STATE_VM(mp_emergency_exception_buf) + mp_emergency_exception_buf_size - str_data; vstr_t vstr; vstr_init_fixed_buf(&vstr, max_len, (char *)str_data); va_list ap; va_start(ap, fmt); vstr_vprintf(&vstr, fmt, ap); va_end(ap); str->base.type = &mp_type_str; str->hash = qstr_compute_hash(str_data, str->len); str->len = vstr.len; str->data = str_data; o->args = tuple; uint offset = &str_data[str->len] - MP_STATE_VM(mp_emergency_exception_buf); offset += sizeof(void *) - 1; offset &= ~(sizeof(void *) - 1); if ((mp_emergency_exception_buf_size - offset) > (sizeof(o->traceback_data[0]) * 3)) { // We have room to store some traceback. o->traceback_data = (size_t*)((byte *)MP_STATE_VM(mp_emergency_exception_buf) + offset); o->traceback_alloc = (MP_STATE_VM(mp_emergency_exception_buf) + mp_emergency_exception_buf_size - (byte *)o->traceback_data) / sizeof(o->traceback_data[0]); o->traceback_len = 0; } } #endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF } else { o->base.type = exc_type; o->traceback_data = NULL; o->args = MP_OBJ_TO_PTR(mp_obj_new_tuple(1, NULL)); assert(fmt != NULL); { if (strchr(fmt, '%') == NULL) { // no formatting substitutions, avoid allocating vstr. o->args->items[0] = mp_obj_new_str(fmt, strlen(fmt), false); } else { // render exception message and store as .args[0] va_list ap; vstr_t vstr; vstr_init(&vstr, 16); va_start(ap, fmt); vstr_vprintf(&vstr, fmt, ap); va_end(ap); o->args->items[0] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } } } return MP_OBJ_FROM_PTR(o); }