2014-05-03 18:27:38 -04:00
/*
2017-06-30 03:22:17 -04:00
* This file is part of the MicroPython project , http : //micropython.org/
2014-05-03 18:27:38 -04:00
*
* The MIT License ( MIT )
*
* Copyright ( c ) 2013 , 2014 Damien P . George
2019-05-14 08:51:57 -04:00
* Copyright ( c ) 2014 - 2016 Paul Sokolovsky
2014-05-03 18:27:38 -04:00
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
*/
2013-12-21 13:17:45 -05:00
# include <string.h>
2014-01-08 13:11:23 -05:00
# include <stdarg.h>
2013-12-21 13:17:45 -05:00
# include <assert.h>
2014-07-02 02:46:53 -04:00
# include <stdio.h>
2013-12-21 13:17:45 -05:00
2015-01-01 15:27:54 -05:00
# include "py/objlist.h"
2023-09-22 15:26:13 -04:00
# include "py/objnamedtuple.h"
2015-01-01 15:27:54 -05:00
# include "py/objstr.h"
# include "py/objtuple.h"
# include "py/objtype.h"
2015-01-20 09:11:27 -05:00
# include "py/runtime.h"
2015-01-01 15:27:54 -05:00
# include "py/gc.h"
2016-05-12 08:20:40 -04:00
# include "py/mperrno.h"
2013-12-21 13:17:45 -05:00
2020-04-13 00:52:10 -04:00
# if MICROPY_ROM_TEXT_COMPRESSION && !defined(NO_QSTR)
// Extract the MP_MAX_UNCOMPRESSED_TEXT_LEN macro from "genhdr/compressed.data.h".
// Only need this if compression enabled and in a regular build (i.e. not during QSTR extraction).
2020-01-28 22:27:33 -05:00
# define MP_MATCH_COMPRESSED(...) // Ignore
# define MP_COMPRESSED_DATA(...) // Ignore
# include "genhdr/compressed.data.h"
# undef MP_MATCH_COMPRESSED
# undef MP_COMPRESSED_DATA
# endif
2018-08-08 21:24:49 -04:00
2017-09-21 01:24:57 -04:00
// Number of items per traceback entry (file, line, block)
# define TRACEBACK_ENTRY_LEN (3)
2018-12-07 09:50:20 -05:00
// Optionally allocated buffer for storing some traceback, the tuple argument,
// and possible string object and data, for when the heap is locked.
2014-07-02 02:46:53 -04:00
# if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
2018-12-07 09:50:20 -05:00
// When used the layout of the emergency exception buffer is:
// - traceback entry (file, line, block)
// - traceback entry (file, line, block)
// - mp_obj_tuple_t object
// - n_args * mp_obj_t for tuple
// - mp_obj_str_t object
// - string data
# define EMG_BUF_TRACEBACK_OFFSET (0)
# define EMG_BUF_TRACEBACK_SIZE (2 * TRACEBACK_ENTRY_LEN * sizeof(size_t))
# define EMG_BUF_TUPLE_OFFSET (EMG_BUF_TRACEBACK_OFFSET + EMG_BUF_TRACEBACK_SIZE)
# define EMG_BUF_TUPLE_SIZE(n_args) (sizeof(mp_obj_tuple_t) + n_args * sizeof(mp_obj_t))
# define EMG_BUF_STR_OFFSET (EMG_BUF_TUPLE_OFFSET + EMG_BUF_TUPLE_SIZE(1))
2020-01-28 22:27:33 -05:00
# define EMG_BUF_STR_BUF_OFFSET (EMG_BUF_STR_OFFSET + sizeof(mp_obj_str_t))
2018-12-07 09:50:20 -05:00
2021-03-15 09:57:36 -04:00
# if MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE > 0
2014-07-02 02:46:53 -04:00
# define mp_emergency_exception_buf_size MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE
void mp_init_emergency_exception_buf ( void ) {
// Nothing to do since the buffer was declared statically. We put this
// definition here so that the calling code can call this function
// regardless of how its configured (makes the calling code a bit cleaner).
}
# else
2015-01-01 18:30:53 -05:00
# define mp_emergency_exception_buf_size MP_STATE_VM(mp_emergency_exception_buf_size)
2014-07-02 02:46:53 -04:00
void mp_init_emergency_exception_buf ( void ) {
mp_emergency_exception_buf_size = 0 ;
2015-01-01 18:30:53 -05:00
MP_STATE_VM ( mp_emergency_exception_buf ) = NULL ;
2014-07-02 02:46:53 -04:00
}
mp_obj_t mp_alloc_emergency_exception_buf ( mp_obj_t size_in ) {
mp_int_t size = mp_obj_get_int ( size_in ) ;
void * buf = NULL ;
if ( size > 0 ) {
2015-02-27 04:34:51 -05:00
buf = m_new ( byte , size ) ;
2014-07-02 02:46:53 -04:00
}
int old_size = mp_emergency_exception_buf_size ;
2015-01-01 18:30:53 -05:00
void * old_buf = MP_STATE_VM ( mp_emergency_exception_buf ) ;
2014-07-02 02:46:53 -04:00
// Update the 2 variables atomically so that an interrupt can't occur
// between the assignments.
2014-10-15 13:33:24 -04:00
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION ( ) ;
2014-07-02 02:46:53 -04:00
mp_emergency_exception_buf_size = size ;
2015-01-01 18:30:53 -05:00
MP_STATE_VM ( mp_emergency_exception_buf ) = buf ;
2014-10-15 13:33:24 -04:00
MICROPY_END_ATOMIC_SECTION ( atomic_state ) ;
2014-07-02 02:46:53 -04:00
if ( old_buf ! = NULL ) {
2015-02-27 04:34:51 -05:00
m_del ( byte , old_buf , old_size ) ;
2014-07-02 02:46:53 -04:00
}
return mp_const_none ;
}
# endif
# endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
2022-09-17 08:22:32 -04:00
bool mp_obj_is_native_exception_instance ( mp_obj_t self_in ) {
return MP_OBJ_TYPE_GET_SLOT_OR_NULL ( mp_obj_get_type ( self_in ) , make_new ) = = mp_obj_exception_make_new ;
}
2023-09-22 14:42:19 -04:00
mp_obj_exception_t * mp_obj_exception_get_native ( mp_obj_t self_in ) {
2021-06-29 03:32:18 -04:00
assert ( mp_obj_is_exception_instance ( self_in ) ) ;
if ( mp_obj_is_native_exception_instance ( self_in ) ) {
return MP_OBJ_TO_PTR ( self_in ) ;
} else {
return MP_OBJ_TO_PTR ( ( ( mp_obj_instance_t * ) MP_OBJ_TO_PTR ( self_in ) ) - > subobj [ 0 ] ) ;
}
}
2020-01-28 22:27:33 -05:00
STATIC void decompress_error_text_maybe ( mp_obj_exception_t * o ) {
# if MICROPY_ROM_TEXT_COMPRESSION
py/obj: Add static safety checks to mp_obj_is_type().
Commit d96cfd13e3a464862c introduced a regression by breaking existing
users of mp_obj_is_type(.., &mp_obj_bool). This function (and associated
helpers like mp_obj_is_int()) have some specific nuances, and mistakes like
this one can happen again.
This commit adds mp_obj_is_exact_type() which behaves like the the old
mp_obj_is_type(). The new mp_obj_is_type() has the same prototype but it
attempts to statically assert that it's not called with types which should
be checked using mp_obj_is_type(). If called with any of these types: int,
str, bool, NoneType - it will cause a compilation error. Additional
checked types (e.g function types) can be added in the future.
Existing users of mp_obj_is_type() with the now "invalid" types, were
translated to use mp_obj_is_exact_type().
The use of MP_STATIC_ASSERT() is not bulletproof - usually GCC (and other
compilers) can't statically check conditions that are only known during
link-time (like variables' addresses comparison). However, in this case,
GCC is able to statically detect these conditions, probably because it's
the exact same object - `&mp_type_int == &mp_type_int` is detected.
Misuses of this function with runtime-chosen types (e.g:
`mp_obj_type_t *x = ...; mp_obj_is_type(..., x);` won't be detected. MSC
is unable to detect this, so we use MP_STATIC_ASSERT_NOT_MSC().
Compiling with this commit and without the fix for d96cfd13e3a464862c shows
that it detects the problem.
Signed-off-by: Yonatan Goldschmidt <yon.goldschmidt@gmail.com>
2020-01-22 07:34:19 -05:00
if ( o - > args - > len = = 1 & & mp_obj_is_exact_type ( o - > args - > items [ 0 ] , & mp_type_str ) ) {
2020-01-28 22:27:33 -05:00
mp_obj_str_t * o_str = MP_OBJ_TO_PTR ( o - > args - > items [ 0 ] ) ;
if ( MP_IS_COMPRESSED_ROM_STRING ( o_str - > data ) ) {
byte * buf = m_new_maybe ( byte , MP_MAX_UNCOMPRESSED_TEXT_LEN + 1 ) ;
if ( ! buf ) {
# if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
// Try and use the emergency exception buf if enough space is available.
buf = ( byte * ) ( ( uint8_t * ) MP_STATE_VM ( mp_emergency_exception_buf ) + EMG_BUF_STR_BUF_OFFSET ) ;
size_t avail = ( uint8_t * ) MP_STATE_VM ( mp_emergency_exception_buf ) + mp_emergency_exception_buf_size - buf ;
if ( avail < MP_MAX_UNCOMPRESSED_TEXT_LEN + 1 ) {
// No way to decompress, fallback to no message text.
o - > args = ( mp_obj_tuple_t * ) & mp_const_empty_tuple_obj ;
return ;
}
# else
o - > args = ( mp_obj_tuple_t * ) & mp_const_empty_tuple_obj ;
return ;
# endif
}
mp_decompress_rom_string ( buf , ( mp_rom_error_text_t ) o_str - > data ) ;
o_str - > data = buf ;
o_str - > len = strlen ( ( const char * ) buf ) ;
o_str - > hash = 0 ;
}
// Lazily compute the string hash.
if ( o_str - > hash = = 0 ) {
o_str - > hash = qstr_compute_hash ( o_str - > data , o_str - > len ) ;
}
}
# endif
}
2018-03-16 09:31:40 -04:00
void mp_obj_exception_print ( const mp_print_t * print , mp_obj_t o_in , mp_print_kind_t kind ) {
2015-11-27 12:01:44 -05:00
mp_obj_exception_t * o = MP_OBJ_TO_PTR ( o_in ) ;
2014-05-01 18:51:25 -04:00
mp_print_kind_t k = kind & ~ PRINT_EXC_SUBCLASS ;
bool is_subclass = kind & PRINT_EXC_SUBCLASS ;
if ( ! is_subclass & & ( k = = PRINT_REPR | | k = = PRINT_EXC ) ) {
2015-04-11 08:03:37 -04:00
mp_print_str ( print , qstr_str ( o - > base . type - > name ) ) ;
2014-03-30 18:10:10 -04:00
}
2014-05-01 18:51:25 -04:00
if ( k = = PRINT_EXC ) {
2015-04-09 18:56:15 -04:00
mp_print_str ( print , " : " ) ;
2014-05-01 18:51:25 -04:00
}
2020-01-28 22:27:33 -05:00
decompress_error_text_maybe ( o ) ;
2014-05-01 18:51:25 -04:00
if ( k = = PRINT_STR | | k = = PRINT_EXC ) {
2014-04-22 19:19:18 -04:00
if ( o - > args = = NULL | | o - > args - > len = = 0 ) {
2015-04-09 18:56:15 -04:00
mp_print_str ( print , " " ) ;
2014-03-30 18:10:10 -04:00
return ;
2020-02-04 16:41:25 -05:00
}
2020-04-08 13:17:28 -04:00
# if MICROPY_PY_UERRNO
// try to provide a nice OSError error message
if ( o - > base . type = = & mp_type_OSError & & o - > args - > len > 0 & & o - > args - > len < 3 & & mp_obj_is_small_int ( o - > args - > items [ 0 ] ) ) {
2023-09-19 11:10:12 -04:00
// CIRCUITPY can print a whole string, not just the errno qstr
2020-02-04 16:41:25 -05:00
char decompressed [ 50 ] ;
const char * msg = mp_common_errno_to_str ( o - > args - > items [ 0 ] , decompressed , sizeof ( decompressed ) ) ;
if ( msg ! = NULL ) {
mp_printf ( print , " [Errno " INT_FMT " ] %s " , MP_OBJ_SMALL_INT_VALUE ( o - > args - > items [ 0 ] ) , msg ) ;
2020-04-08 13:17:28 -04:00
if ( o - > args - > len > 1 ) {
mp_print_str ( print , " : " ) ;
mp_obj_print_helper ( print , o - > args - > items [ 1 ] , PRINT_STR ) ;
2016-05-12 09:27:52 -04:00
}
2020-02-04 16:41:25 -05:00
return ;
2016-05-12 09:27:52 -04:00
}
2020-02-04 16:55:56 -05:00
}
2020-04-08 13:17:28 -04:00
# endif
2020-02-04 16:55:56 -05:00
if ( o - > args - > len = = 1 ) {
2015-04-09 18:56:15 -04:00
mp_obj_print_helper ( print , o - > args - > items [ 0 ] , PRINT_STR ) ;
2014-03-30 18:10:10 -04:00
return ;
2014-01-13 12:19:16 -05:00
}
2013-12-21 13:17:45 -05:00
}
2020-01-28 22:27:33 -05:00
2015-11-27 12:01:44 -05:00
mp_obj_tuple_print ( print , MP_OBJ_FROM_PTR ( o - > args ) , kind ) ;
2013-12-21 13:17:45 -05:00
}
2023-09-19 11:10:12 -04:00
// CIRCUITPY
2023-02-10 09:44:58 -05:00
void mp_obj_exception_initialize0 ( mp_obj_exception_t * o_exc , const mp_obj_type_t * type ) {
o_exc - > base . type = type ;
o_exc - > args = ( mp_obj_tuple_t * ) & mp_const_empty_tuple_obj ;
mp_obj_exception_clear_traceback ( o_exc ) ;
}
2016-01-03 10:55:55 -05:00
mp_obj_t mp_obj_exception_make_new ( const mp_obj_type_t * type , size_t n_args , size_t n_kw , const mp_obj_t * args ) {
2015-01-20 09:11:27 -05:00
mp_arg_check_num ( n_args , n_kw , 0 , MP_OBJ_FUN_ARGS_MAX , false ) ;
2017-09-21 01:24:57 -04:00
// Try to allocate memory for the exception, with fallback to emergency exception object
mp_obj_exception_t * o_exc = m_new_obj_maybe ( mp_obj_exception_t ) ;
if ( o_exc = = NULL ) {
o_exc = & MP_STATE_VM ( mp_emergency_exception_obj ) ;
}
// Populate the exception object
o_exc - > base . type = type ;
2021-11-10 05:42:42 -05:00
o_exc - > traceback = ( mp_obj_traceback_t * ) & mp_const_empty_traceback_obj ;
2017-09-21 01:24:57 -04:00
mp_obj_tuple_t * o_tuple ;
if ( n_args = = 0 ) {
2023-03-18 11:17:02 -04:00
// No args, can use the empty tuple straight away
2021-03-15 09:57:36 -04:00
o_tuple = ( mp_obj_tuple_t * ) & mp_const_empty_tuple_obj ;
2014-04-22 19:19:18 -04:00
} else {
2017-09-21 01:24:57 -04:00
// Try to allocate memory for the tuple containing the args
o_tuple = m_new_obj_var_maybe ( mp_obj_tuple_t , mp_obj_t , n_args ) ;
# if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
// If we are called by mp_obj_new_exception_msg_varg then it will have
// reserved room (after the traceback data) for a tuple with 1 element.
// Otherwise we are free to use the whole buffer after the traceback data.
if ( o_tuple = = NULL & & mp_emergency_exception_buf_size > =
2019-12-13 02:24:18 -05:00
( mp_int_t ) ( EMG_BUF_TUPLE_OFFSET + EMG_BUF_TUPLE_SIZE ( n_args ) ) ) {
2021-03-15 09:57:36 -04:00
o_tuple = ( mp_obj_tuple_t * )
2021-04-20 01:22:44 -04:00
( ( uint8_t * ) MP_STATE_VM ( mp_emergency_exception_buf ) + EMG_BUF_TUPLE_OFFSET ) ;
2017-09-21 01:24:57 -04:00
}
# endif
if ( o_tuple = = NULL ) {
// No memory for a tuple, fallback to an empty tuple
2021-03-15 09:57:36 -04:00
o_tuple = ( mp_obj_tuple_t * ) & mp_const_empty_tuple_obj ;
2017-09-21 01:24:57 -04:00
} else {
// Have memory for a tuple so populate it
o_tuple - > base . type = & mp_type_tuple ;
o_tuple - > len = n_args ;
memcpy ( o_tuple - > items , args , n_args * sizeof ( mp_obj_t ) ) ;
}
2014-04-10 09:38:25 -04:00
}
2017-09-21 01:24:57 -04:00
// Store the tuple of args in the exception object
o_exc - > args = o_tuple ;
return MP_OBJ_FROM_PTR ( o_exc ) ;
2014-01-12 16:30:20 -05:00
}
2014-03-26 13:17:20 -04:00
// Get exception "value" - that is, first argument, or None
mp_obj_t mp_obj_exception_get_value ( mp_obj_t self_in ) {
2023-09-22 14:42:19 -04:00
mp_obj_exception_t * self = mp_obj_exception_get_native ( self_in ) ;
2014-04-22 19:19:18 -04:00
if ( self - > args - > len = = 0 ) {
2014-03-26 13:17:20 -04:00
return mp_const_none ;
} else {
2020-01-28 22:27:33 -05:00
decompress_error_text_maybe ( self ) ;
2014-04-22 19:19:18 -04:00
return self - > args - > items [ 0 ] ;
2014-03-26 13:17:20 -04:00
}
}
2018-03-16 09:31:40 -04:00
void mp_obj_exception_attr ( mp_obj_t self_in , qstr attr , mp_obj_t * dest ) {
2016-11-13 18:23:30 -05:00
mp_obj_exception_t * self = MP_OBJ_TO_PTR ( self_in ) ;
2015-04-01 10:10:50 -04:00
if ( dest [ 0 ] ! = MP_OBJ_NULL ) {
2016-11-13 18:23:30 -05:00
// store/delete attribute
2022-10-17 10:08:17 -04:00
# if MICROPY_CONST_GENERATOREXIT_OBJ
2023-09-22 11:45:49 -04:00
if ( self = = & mp_const_GeneratorExit_obj ) {
2022-10-17 10:08:17 -04:00
mp_raise_AttributeError ( MP_ERROR_TEXT ( " can't set attribute " ) ) ;
}
2022-10-17 10:08:17 -04:00
# endif
2021-08-02 02:30:48 -04:00
if ( attr = = MP_QSTR___traceback__ ) {
if ( dest [ 1 ] = = mp_const_none ) {
2021-11-10 05:42:42 -05:00
self - > traceback = ( mp_obj_traceback_t * ) & mp_const_empty_traceback_obj ;
2021-08-02 02:30:48 -04:00
} else {
if ( ! mp_obj_is_type ( dest [ 1 ] , & mp_type_traceback ) ) {
2023-01-10 13:39:10 -05:00
mp_raise_TypeError_varg ( MP_ERROR_TEXT ( " %q must be of type %q or %q, not %q " ) , MP_QSTR___context__ , MP_QSTR_traceback , MP_QSTR_None , mp_obj_get_type ( dest [ 1 ] ) - > name ) ;
2021-08-02 02:30:48 -04:00
}
self - > traceback = MP_OBJ_TO_PTR ( dest [ 1 ] ) ;
}
2016-11-13 18:23:30 -05:00
dest [ 0 ] = MP_OBJ_NULL ; // indicate success
2022-10-16 16:58:44 -04:00
# if MICROPY_CPYTHON_EXCEPTION_CHAIN
} else if ( attr = = MP_QSTR___cause__ ) {
if ( dest [ 1 ] = = mp_const_none ) {
self - > cause = NULL ;
} else if ( ! mp_obj_is_type ( dest [ 1 ] , & mp_type_BaseException ) ) {
self - > cause = dest [ 1 ] ;
} else {
2023-01-10 13:39:10 -05:00
mp_raise_TypeError_varg ( MP_ERROR_TEXT ( " %q must be of type %q or %q, not %q " ) , attr , MP_QSTR_BaseException , MP_QSTR_None , mp_obj_get_type ( dest [ 1 ] ) - > name ) ;
2022-10-16 16:58:44 -04:00
}
self - > suppress_context = true ;
dest [ 0 ] = MP_OBJ_NULL ; // indicate success
} else if ( attr = = MP_QSTR___context__ ) {
if ( dest [ 1 ] = = mp_const_none ) {
self - > context = NULL ;
} else if ( ! mp_obj_is_type ( dest [ 1 ] , & mp_type_BaseException ) ) {
self - > context = dest [ 1 ] ;
} else {
2023-01-10 13:39:10 -05:00
mp_raise_TypeError_varg ( MP_ERROR_TEXT ( " %q must be of type %q or %q, not %q " ) , attr , MP_QSTR_BaseException , MP_QSTR_None , mp_obj_get_type ( dest [ 1 ] ) - > name ) ;
2022-10-16 16:58:44 -04:00
}
dest [ 0 ] = MP_OBJ_NULL ; // indicate success
} else if ( attr = = MP_QSTR___suppress_context__ ) {
self - > suppress_context = mp_obj_is_true ( dest [ 1 ] ) ;
dest [ 0 ] = MP_OBJ_NULL ; // indicate success
# endif
2016-11-13 18:23:30 -05:00
}
2015-04-01 10:10:50 -04:00
return ;
}
2014-03-24 19:29:09 -04:00
if ( attr = = MP_QSTR_args ) {
2020-01-28 22:27:33 -05:00
decompress_error_text_maybe ( self ) ;
2015-11-27 12:01:44 -05:00
dest [ 0 ] = MP_OBJ_FROM_PTR ( self - > args ) ;
2021-08-02 02:30:48 -04:00
} else if ( attr = = MP_QSTR_value & & self - > base . type = = & mp_type_StopIteration ) {
2015-11-27 12:01:44 -05:00
dest [ 0 ] = mp_obj_exception_get_value ( self_in ) ;
2021-08-02 02:30:48 -04:00
} else if ( attr = = MP_QSTR___traceback__ ) {
2021-11-10 05:42:42 -05:00
dest [ 0 ] = ( self - > traceback ) ? MP_OBJ_FROM_PTR ( self - > traceback ) : mp_const_none ;
2022-10-16 16:58:44 -04:00
# if MICROPY_CPYTHON_EXCEPTION_CHAIN
} else if ( attr = = MP_QSTR___cause__ ) {
dest [ 0 ] = ( self - > cause ) ? MP_OBJ_FROM_PTR ( self - > cause ) : mp_const_none ;
} else if ( attr = = MP_QSTR___context__ ) {
dest [ 0 ] = ( self - > context ) ? MP_OBJ_FROM_PTR ( self - > context ) : mp_const_none ;
} else if ( attr = = MP_QSTR___suppress_context__ ) {
dest [ 0 ] = mp_obj_new_bool ( self - > suppress_context ) ;
# endif
2018-11-12 10:16:47 -05:00
# if MICROPY_CPYTHON_COMPAT
} else if ( mp_obj_is_subclass_fast ( MP_OBJ_FROM_PTR ( self - > base . type ) , MP_OBJ_FROM_PTR ( & mp_type_OSError ) ) ) {
if ( attr = = MP_QSTR_errno ) {
dest [ 0 ] = mp_obj_exception_get_value ( self_in ) ;
} else if ( attr = = MP_QSTR_strerror ) {
if ( self - > args - > len > 1 ) {
dest [ 0 ] = self - > args - > items [ 1 ] ;
} else if ( self - > args - > len > 0 ) {
char decompressed [ 50 ] ;
const char * msg = mp_common_errno_to_str ( self - > args - > items [ 0 ] , decompressed , sizeof ( decompressed ) ) ;
if ( msg ! = NULL ) {
dest [ 0 ] = mp_obj_new_str ( msg , strlen ( msg ) ) ;
} else {
dest [ 0 ] = mp_const_none ;
}
} else {
dest [ 0 ] = mp_const_none ;
}
} else if ( attr = = MP_QSTR_filename ) {
dest [ 0 ] = self - > args - > len > 2 ? self - > args - > items [ 2 ] : mp_const_none ;
2021-03-15 09:57:36 -04:00
// skip winerror
2018-11-12 10:16:47 -05:00
} else if ( attr = = MP_QSTR_filename2 ) {
dest [ 0 ] = self - > args - > len > 4 ? self - > args - > items [ 4 ] : mp_const_none ;
}
# endif
2014-03-24 19:29:09 -04:00
}
}
2021-07-14 00:38:38 -04:00
MP_DEFINE_CONST_OBJ_TYPE (
mp_type_BaseException ,
MP_QSTR_BaseException ,
MP_TYPE_FLAG_NONE ,
2022-09-16 10:31:23 -04:00
make_new , mp_obj_exception_make_new ,
2021-07-14 00:38:38 -04:00
print , mp_obj_exception_print ,
attr , mp_obj_exception_attr
) ;
2014-02-15 11:10:44 -05:00
2020-02-25 19:58:42 -05:00
// *FORMAT-OFF*
2014-03-22 11:28:16 -04:00
// List of all exceptions, arranged as in the table at:
2014-06-05 13:51:03 -04:00
// http://docs.python.org/3/library/exceptions.html
2014-05-24 18:32:19 -04:00
MP_DEFINE_EXCEPTION ( SystemExit , BaseException )
2014-10-25 13:19:55 -04:00
MP_DEFINE_EXCEPTION ( KeyboardInterrupt , BaseException )
2023-09-19 11:10:12 -04:00
// CIRCUITPY
2018-05-14 16:57:50 -04:00
MP_DEFINE_EXCEPTION ( ReloadException , BaseException )
2014-03-22 11:28:16 -04:00
MP_DEFINE_EXCEPTION ( GeneratorExit , BaseException )
MP_DEFINE_EXCEPTION ( Exception , BaseException )
2016-01-27 15:23:11 -05:00
# if MICROPY_PY_ASYNC_AWAIT
MP_DEFINE_EXCEPTION ( StopAsyncIteration , Exception )
# endif
2014-03-22 11:28:16 -04:00
MP_DEFINE_EXCEPTION ( StopIteration , Exception )
MP_DEFINE_EXCEPTION ( ArithmeticError , Exception )
2014-03-27 19:49:06 -04:00
//MP_DEFINE_EXCEPTION(FloatingPointError, ArithmeticError)
2014-03-22 11:28:16 -04:00
MP_DEFINE_EXCEPTION ( OverflowError , ArithmeticError )
MP_DEFINE_EXCEPTION ( ZeroDivisionError , ArithmeticError )
MP_DEFINE_EXCEPTION ( AssertionError , Exception )
MP_DEFINE_EXCEPTION ( AttributeError , Exception )
2014-03-27 19:49:06 -04:00
//MP_DEFINE_EXCEPTION(BufferError, Exception)
2014-03-22 11:28:16 -04:00
MP_DEFINE_EXCEPTION ( EOFError , Exception )
MP_DEFINE_EXCEPTION ( ImportError , Exception )
MP_DEFINE_EXCEPTION ( LookupError , Exception )
MP_DEFINE_EXCEPTION ( IndexError , LookupError )
MP_DEFINE_EXCEPTION ( KeyError , LookupError )
MP_DEFINE_EXCEPTION ( MemoryError , Exception )
MP_DEFINE_EXCEPTION ( NameError , Exception )
2014-05-11 18:21:50 -04:00
/*
MP_DEFINE_EXCEPTION ( UnboundLocalError , NameError )
*/
2014-03-22 11:28:16 -04:00
MP_DEFINE_EXCEPTION ( OSError , Exception )
2015-06-29 16:45:39 -04:00
/*
2014-03-27 19:49:06 -04:00
MP_DEFINE_EXCEPTION ( BlockingIOError , OSError )
2014-03-22 11:28:16 -04:00
MP_DEFINE_EXCEPTION ( ChildProcessError , OSError )
2023-09-22 15:25:50 -04:00
*/
2014-03-22 11:28:16 -04:00
MP_DEFINE_EXCEPTION ( ConnectionError , OSError )
MP_DEFINE_EXCEPTION ( BrokenPipeError , ConnectionError )
2023-09-22 15:25:50 -04:00
/*
2014-03-22 11:28:16 -04:00
MP_DEFINE_EXCEPTION ( ConnectionAbortedError , ConnectionError )
MP_DEFINE_EXCEPTION ( ConnectionRefusedError , ConnectionError )
MP_DEFINE_EXCEPTION ( ConnectionResetError , ConnectionError )
MP_DEFINE_EXCEPTION ( InterruptedError , OSError )
MP_DEFINE_EXCEPTION ( IsADirectoryError , OSError )
MP_DEFINE_EXCEPTION ( NotADirectoryError , OSError )
MP_DEFINE_EXCEPTION ( PermissionError , OSError )
MP_DEFINE_EXCEPTION ( ProcessLookupError , OSError )
2023-09-22 15:25:50 -04:00
*/
2023-08-09 15:20:10 -04:00
MP_DEFINE_EXCEPTION ( TimeoutError , OSError )
2023-09-22 15:25:50 -04:00
/*
2014-03-22 19:40:02 -04:00
MP_DEFINE_EXCEPTION ( FileExistsError , OSError )
MP_DEFINE_EXCEPTION ( FileNotFoundError , OSError )
2014-03-27 19:49:06 -04:00
MP_DEFINE_EXCEPTION ( ReferenceError , Exception )
*/
2014-03-22 11:28:16 -04:00
MP_DEFINE_EXCEPTION ( RuntimeError , Exception )
MP_DEFINE_EXCEPTION ( NotImplementedError , RuntimeError )
MP_DEFINE_EXCEPTION ( SyntaxError , Exception )
MP_DEFINE_EXCEPTION ( IndentationError , SyntaxError )
2014-03-27 19:49:06 -04:00
/*
MP_DEFINE_EXCEPTION ( TabError , IndentationError )
*/
2014-10-22 14:42:55 -04:00
//MP_DEFINE_EXCEPTION(SystemError, Exception)
2014-03-22 11:28:16 -04:00
MP_DEFINE_EXCEPTION ( TypeError , Exception )
2015-04-20 09:29:31 -04:00
# if MICROPY_EMIT_NATIVE
MP_DEFINE_EXCEPTION ( ViperTypeError , TypeError )
# endif
2014-03-22 11:28:16 -04:00
MP_DEFINE_EXCEPTION ( ValueError , Exception )
2015-02-23 16:18:36 -05:00
# if MICROPY_PY_BUILTINS_STR_UNICODE
MP_DEFINE_EXCEPTION ( UnicodeError , ValueError )
//TODO: Implement more UnicodeError subclasses which take arguments
2020-12-01 20:01:14 -05:00
# endif
# if CIRCUITPY_ALARM
2021-03-15 09:57:36 -04:00
MP_DEFINE_EXCEPTION ( DeepSleepRequest , BaseException )
2015-02-23 16:18:36 -05:00
# endif
2021-03-15 09:57:36 -04:00
/*
2014-03-22 11:28:16 -04:00
MP_DEFINE_EXCEPTION ( Warning , Exception )
MP_DEFINE_EXCEPTION ( DeprecationWarning , Warning )
MP_DEFINE_EXCEPTION ( PendingDeprecationWarning , Warning )
MP_DEFINE_EXCEPTION ( RuntimeWarning , Warning )
MP_DEFINE_EXCEPTION ( SyntaxWarning , Warning )
MP_DEFINE_EXCEPTION ( UserWarning , Warning )
MP_DEFINE_EXCEPTION ( FutureWarning , Warning )
MP_DEFINE_EXCEPTION ( ImportWarning , Warning )
MP_DEFINE_EXCEPTION ( UnicodeWarning , Warning )
MP_DEFINE_EXCEPTION ( BytesWarning , Warning )
MP_DEFINE_EXCEPTION ( ResourceWarning , Warning )
2014-03-22 19:40:02 -04:00
*/
2014-02-15 11:10:44 -05:00
2020-02-25 19:58:42 -05:00
// *FORMAT-ON*
2014-02-15 11:10:44 -05:00
mp_obj_t mp_obj_new_exception ( const mp_obj_type_t * exc_type ) {
2022-09-16 10:31:23 -04:00
assert ( MP_OBJ_TYPE_GET_SLOT_OR_NULL ( exc_type , make_new ) = = mp_obj_exception_make_new ) ;
2020-01-22 21:03:00 -05:00
return mp_obj_exception_make_new ( exc_type , 0 , 0 , NULL ) ;
2013-12-21 13:17:45 -05:00
}
2017-02-16 00:38:14 -05:00
mp_obj_t mp_obj_new_exception_args ( const mp_obj_type_t * exc_type , size_t n_args , const mp_obj_t * args ) {
2022-09-16 10:31:23 -04:00
assert ( MP_OBJ_TYPE_GET_SLOT_OR_NULL ( exc_type , make_new ) = = mp_obj_exception_make_new ) ;
2020-01-22 21:03:00 -05:00
return mp_obj_exception_make_new ( exc_type , n_args , 0 , args ) ;
2014-03-23 15:48:29 -04:00
}
2021-04-21 22:13:58 -04:00
# if MICROPY_ERROR_REPORTING != MICROPY_ERROR_REPORTING_NONE
2018-08-15 21:32:37 -04:00
mp_obj_t mp_obj_new_exception_msg ( const mp_obj_type_t * exc_type , const compressed_string_t * msg ) {
2014-02-15 11:10:44 -05:00
return mp_obj_new_exception_msg_varg ( exc_type , msg ) ;
2013-12-21 13:17:45 -05:00
}
2017-09-21 01:24:57 -04:00
// The following struct and function implement a simple printer that conservatively
// allocates memory and truncates the output data if no more memory can be obtained.
// It leaves room for a null byte at the end of the buffer.
2014-07-02 02:46:53 -04:00
2017-09-21 01:24:57 -04:00
struct _exc_printer_t {
bool allow_realloc ;
size_t alloc ;
size_t len ;
byte * buf ;
} ;
2014-07-02 02:46:53 -04:00
2017-09-21 01:24:57 -04:00
STATIC void exc_add_strn ( void * data , const char * str , size_t len ) {
struct _exc_printer_t * pr = data ;
if ( pr - > len + len > = pr - > alloc ) {
// Not enough room for data plus a null byte so try to grow the buffer
if ( pr - > allow_realloc ) {
size_t new_alloc = pr - > alloc + len + 16 ;
byte * new_buf = m_renew_maybe ( byte , pr - > buf , pr - > alloc , new_alloc , true ) ;
if ( new_buf = = NULL ) {
pr - > allow_realloc = false ;
len = pr - > alloc - pr - > len - 1 ;
} else {
pr - > alloc = new_alloc ;
pr - > buf = new_buf ;
}
} else {
len = pr - > alloc - pr - > len - 1 ;
}
}
memcpy ( pr - > buf + pr - > len , str , len ) ;
pr - > len + = len ;
}
2015-04-11 08:03:37 -04:00
2023-09-20 12:24:07 -04:00
mp_obj_t mp_obj_new_exception_msg_varg ( const mp_obj_type_t * exc_type , const compressed_string_t * fmt , . . . ) {
2020-02-10 19:48:28 -05:00
va_list args ;
va_start ( args , fmt ) ;
2020-02-18 05:00:42 -05:00
mp_obj_t exc = mp_obj_new_exception_msg_vlist ( exc_type , fmt , args ) ;
2020-02-10 19:48:28 -05:00
va_end ( args ) ;
return exc ;
2017-02-24 11:47:02 -05:00
}
2023-09-20 12:24:07 -04:00
mp_obj_t mp_obj_new_exception_msg_vlist ( const mp_obj_type_t * exc_type , const compressed_string_t * fmt , va_list ap ) {
2017-09-21 01:24:57 -04:00
assert ( fmt ! = NULL ) ;
2014-02-15 11:10:44 -05:00
2017-09-21 01:24:57 -04:00
// Check that the given type is an exception type
2022-09-16 10:31:23 -04:00
assert ( MP_OBJ_TYPE_GET_SLOT_OR_NULL ( exc_type , make_new ) = = mp_obj_exception_make_new ) ;
2014-07-02 02:46:53 -04:00
2017-09-21 01:24:57 -04:00
// Try to allocate memory for the message
mp_obj_str_t * o_str = m_new_obj_maybe ( mp_obj_str_t ) ;
2020-05-28 08:40:56 -04:00
size_t o_str_alloc = decompress_length ( fmt ) ;
2017-09-21 01:24:57 -04:00
byte * o_str_buf = m_new_maybe ( byte , o_str_alloc ) ;
bool used_emg_buf = false ;
# if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
// If memory allocation failed and there is an emergency buffer then try to use
// that buffer to store the string object and its data (at least 16 bytes for
// the string data), reserving room at the start for the traceback and 1-tuple.
if ( ( o_str = = NULL | | o_str_buf = = NULL )
2019-12-13 02:24:18 -05:00
& & mp_emergency_exception_buf_size > = ( mp_int_t ) ( EMG_BUF_STR_OFFSET + sizeof ( mp_obj_str_t ) + 16 ) ) {
2017-09-21 01:24:57 -04:00
used_emg_buf = true ;
2021-03-15 09:57:36 -04:00
o_str = ( mp_obj_str_t * ) ( ( uint8_t * ) MP_STATE_VM ( mp_emergency_exception_buf )
2018-12-07 09:50:20 -05:00
+ EMG_BUF_STR_OFFSET ) ;
2021-03-15 09:57:36 -04:00
o_str_buf = ( byte * ) & o_str [ 1 ] ;
o_str_alloc = ( uint8_t * ) MP_STATE_VM ( mp_emergency_exception_buf )
2017-09-21 01:24:57 -04:00
+ mp_emergency_exception_buf_size - o_str_buf ;
}
# endif
2014-07-02 02:46:53 -04:00
2017-09-21 01:24:57 -04:00
if ( o_str = = NULL ) {
2020-01-28 22:27:33 -05:00
// No memory for the string object so create the exception with no args.
// The exception will only have a type and no message (compression is irrelevant).
2017-09-21 01:24:57 -04:00
return mp_obj_exception_make_new ( exc_type , 0 , 0 , NULL ) ;
}
2014-07-02 02:46:53 -04:00
2017-09-21 01:24:57 -04:00
if ( o_str_buf = = NULL ) {
2018-08-15 21:32:37 -04:00
// No memory for the string buffer: the string is compressed so don't add it.
o_str - > len = 0 ;
o_str - > data = NULL ;
2014-01-12 16:30:20 -05:00
} else {
2020-01-28 22:27:33 -05:00
// We have some memory to format the string.
2017-09-21 01:24:57 -04:00
struct _exc_printer_t exc_pr = { ! used_emg_buf , o_str_alloc , 0 , o_str_buf } ;
mp_print_t print = { & exc_pr , exc_add_strn } ;
2021-08-08 11:27:50 -04:00
mp_vcprintf ( & print , fmt , ap ) ;
2017-09-21 01:24:57 -04:00
exc_pr . buf [ exc_pr . len ] = ' \0 ' ;
o_str - > len = exc_pr . len ;
o_str - > data = exc_pr . buf ;
2014-01-08 13:11:23 -05:00
}
2017-09-21 01:24:57 -04:00
// Create the string object and call mp_obj_exception_make_new to create the exception
o_str - > base . type = & mp_type_str ;
2020-01-28 22:27:33 -05:00
# if MICROPY_ROM_TEXT_COMPRESSION
o_str - > hash = 0 ; // will be computed only if string object is accessed
# else
2017-09-21 01:24:57 -04:00
o_str - > hash = qstr_compute_hash ( o_str - > data , o_str - > len ) ;
2023-09-20 12:24:07 -04:00
# endif
2017-09-21 01:24:57 -04:00
mp_obj_t arg = MP_OBJ_FROM_PTR ( o_str ) ;
return mp_obj_exception_make_new ( exc_type , 1 , 0 , & arg ) ;
2021-04-23 15:26:42 -04:00
}
2021-04-21 22:13:58 -04:00
# endif
2014-02-15 11:10:44 -05:00
// return true if the given object is an exception type
bool mp_obj_is_exception_type ( mp_obj_t self_in ) {
2021-04-22 20:55:39 -04:00
if ( mp_obj_is_type ( self_in , & mp_type_type ) ) {
2014-03-26 14:37:06 -04:00
// optimisation when self_in is a builtin exception
2015-11-27 12:01:44 -05:00
mp_obj_type_t * self = MP_OBJ_TO_PTR ( self_in ) ;
2022-09-16 10:31:23 -04:00
if ( MP_OBJ_TYPE_GET_SLOT_OR_NULL ( self , make_new ) = = mp_obj_exception_make_new ) {
2014-03-26 14:37:06 -04:00
return true ;
}
2014-02-15 11:10:44 -05:00
}
2015-11-27 12:01:44 -05:00
return mp_obj_is_subclass_fast ( self_in , MP_OBJ_FROM_PTR ( & mp_type_BaseException ) ) ;
2014-02-15 11:10:44 -05:00
}
// return true if the given object is an instance of an exception type
bool mp_obj_is_exception_instance ( mp_obj_t self_in ) {
2015-11-27 12:01:44 -05:00
return mp_obj_is_exception_type ( MP_OBJ_FROM_PTR ( mp_obj_get_type ( self_in ) ) ) ;
2014-02-15 11:10:44 -05:00
}
2014-09-24 09:05:40 -04:00
// Return true if exception (type or instance) is a subclass of given
// exception type. Assumes exc_type is a subclass of BaseException, as
// defined by mp_obj_is_exception_type(exc_type).
bool mp_obj_exception_match ( mp_obj_t exc , mp_const_obj_t exc_type ) {
// if exc is an instance of an exception, then extract and use its type
if ( mp_obj_is_exception_instance ( exc ) ) {
2015-11-27 12:01:44 -05:00
exc = MP_OBJ_FROM_PTR ( mp_obj_get_type ( exc ) ) ;
2014-09-24 09:05:40 -04:00
}
return mp_obj_is_subclass_fast ( exc , exc_type ) ;
2014-03-23 15:48:29 -04:00
}
2014-05-01 19:27:00 -04:00
// traceback handling functions
void mp_obj_exception_clear_traceback ( mp_obj_t self_in ) {
2023-09-22 14:42:19 -04:00
mp_obj_exception_t * self = mp_obj_exception_get_native ( self_in ) ;
2021-11-10 05:42:42 -05:00
// just set the traceback to the empty traceback object
2014-05-01 19:27:00 -04:00
// we don't want to call any memory management functions here
2021-11-10 05:42:42 -05:00
self - > traceback = ( mp_obj_traceback_t * ) & mp_const_empty_traceback_obj ;
2023-02-10 09:44:58 -05:00
# if MICROPY_CPYTHON_EXCEPTION_CHAIN
self - > cause = 0 ;
self - > context = 0 ;
self - > suppress_context = false ;
self - > marked = false ;
# endif
2013-12-29 12:17:43 -05:00
}
2014-01-18 18:24:36 -05:00
2016-01-02 17:04:12 -05:00
void mp_obj_exception_add_traceback ( mp_obj_t self_in , qstr file , size_t line , qstr block ) {
2023-09-22 14:42:19 -04:00
mp_obj_exception_t * self = mp_obj_exception_get_native ( self_in ) ;
2014-07-02 02:46:53 -04:00
2015-02-26 19:36:39 -05:00
// append this traceback info to traceback data
// if memory allocation fails (eg because gc is locked), just return
2014-07-02 02:46:53 -04:00
2023-08-15 14:10:31 -04:00
# if MICROPY_PY_SYS_TRACEBACKLIMIT
mp_int_t max_traceback = MP_OBJ_SMALL_INT_VALUE ( MP_STATE_VM ( sys_mutable [ MP_SYS_MUTABLE_TRACEBACKLIMIT ] ) ) ;
if ( max_traceback < = 0 ) {
return ;
} else if ( self - > traceback ! = NULL & & self - > traceback - > len > = max_traceback * TRACEBACK_ENTRY_LEN ) {
self - > traceback - > len - = TRACEBACK_ENTRY_LEN ;
memmove ( self - > traceback - > data , self - > traceback - > data + TRACEBACK_ENTRY_LEN , self - > traceback - > len * sizeof ( self - > traceback - > data [ 0 ] ) ) ;
}
# endif
2021-11-10 05:42:42 -05:00
// Try to allocate memory for the traceback, with fallback to emergency traceback object
if ( self - > traceback = = NULL | | self - > traceback = = ( mp_obj_traceback_t * ) & mp_const_empty_traceback_obj ) {
self - > traceback = m_new_obj_maybe ( mp_obj_traceback_t ) ;
if ( self - > traceback = = NULL ) {
self - > traceback = & MP_STATE_VM ( mp_emergency_traceback_obj ) ;
}
2021-11-22 09:30:02 -05:00
// populate traceback object
* self - > traceback = mp_const_empty_traceback_obj ;
2021-11-10 05:42:42 -05:00
}
2021-11-12 08:02:44 -05:00
// append the provided traceback info to traceback data
// if memory allocation fails (eg because gc is locked), just return
2021-08-02 02:30:48 -04:00
if ( self - > traceback - > data = = NULL ) {
self - > traceback - > data = m_new_maybe ( size_t , TRACEBACK_ENTRY_LEN ) ;
if ( self - > traceback - > data = = NULL ) {
2017-09-21 01:24:57 -04:00
# if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
2019-12-13 02:24:18 -05:00
if ( mp_emergency_exception_buf_size > = ( mp_int_t ) ( EMG_BUF_TRACEBACK_OFFSET + EMG_BUF_TRACEBACK_SIZE ) ) {
2017-09-21 01:24:57 -04:00
// There is room in the emergency buffer for traceback data
2021-04-20 01:22:44 -04:00
size_t * tb = ( size_t * ) ( ( uint8_t * ) MP_STATE_VM ( mp_emergency_exception_buf )
2018-12-07 09:50:20 -05:00
+ EMG_BUF_TRACEBACK_OFFSET ) ;
2021-08-02 02:30:48 -04:00
self - > traceback - > data = tb ;
self - > traceback - > alloc = EMG_BUF_TRACEBACK_SIZE / sizeof ( size_t ) ;
2017-09-21 01:24:57 -04:00
} else {
// Can't allocate and no room in emergency buffer
return ;
}
# else
// Can't allocate
2014-07-02 02:46:53 -04:00
return ;
2017-09-21 01:24:57 -04:00
# endif
} else {
// Allocated the traceback data on the heap
2021-08-02 02:30:48 -04:00
self - > traceback - > alloc = TRACEBACK_ENTRY_LEN ;
2014-07-02 02:46:53 -04:00
}
2021-08-02 02:30:48 -04:00
self - > traceback - > len = 0 ;
} else if ( self - > traceback - > len + TRACEBACK_ENTRY_LEN > self - > traceback - > alloc ) {
2017-09-21 01:24:57 -04:00
# if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
2021-08-02 02:30:48 -04:00
if ( self - > traceback - > data = = ( size_t * ) MP_STATE_VM ( mp_emergency_exception_buf ) ) {
2017-09-21 01:24:57 -04:00
// Can't resize the emergency buffer
return ;
}
# endif
2015-02-26 19:36:39 -05:00
// be conservative with growing traceback data
2021-08-02 02:30:48 -04:00
size_t * tb_data = m_renew_maybe ( size_t , self - > traceback - > data , self - > traceback - > alloc ,
self - > traceback - > alloc + TRACEBACK_ENTRY_LEN , true ) ;
2015-02-26 19:36:39 -05:00
if ( tb_data = = NULL ) {
2014-07-02 02:46:53 -04:00
return ;
}
2021-08-02 02:30:48 -04:00
self - > traceback - > data = tb_data ;
self - > traceback - > alloc + = TRACEBACK_ENTRY_LEN ;
2014-07-01 01:49:21 -04:00
}
2014-07-01 09:28:09 -04:00
2021-08-02 02:30:48 -04:00
size_t * tb_data = & self - > traceback - > data [ self - > traceback - > len ] ;
self - > traceback - > len + = TRACEBACK_ENTRY_LEN ;
2016-01-02 17:04:12 -05:00
tb_data [ 0 ] = file ;
tb_data [ 1 ] = line ;
tb_data [ 2 ] = block ;
2014-01-18 18:24:36 -05:00
}
2016-01-02 17:04:12 -05:00
void mp_obj_exception_get_traceback ( mp_obj_t self_in , size_t * n , size_t * * values ) {
2021-12-15 01:41:21 -05:00
mp_obj_exception_t * self = mp_obj_exception_get_native ( self_in ) ;
2014-02-15 11:10:44 -05:00
2021-11-10 05:42:42 -05:00
if ( self - > traceback = = NULL ) {
2014-01-19 07:38:49 -05:00
* n = 0 ;
* values = NULL ;
} else {
2021-08-02 02:30:48 -04:00
* n = self - > traceback - > len ;
* values = self - > traceback - > data ;
2014-01-19 07:38:49 -05:00
}
2014-01-18 18:24:36 -05:00
}
2023-09-22 15:26:13 -04:00
# if MICROPY_PY_SYS_EXC_INFO
STATIC const mp_obj_namedtuple_type_t code_type_obj = {
NAMEDTUPLE_TYPE_BASE_AND_SLOTS ( MP_QSTR_code ) ,
. n_fields = 15 ,
. fields = {
MP_QSTR_co_argcount ,
MP_QSTR_co_kwonlyargcount ,
MP_QSTR_co_nlocals ,
MP_QSTR_co_stacksize ,
MP_QSTR_co_flags ,
MP_QSTR_co_code ,
MP_QSTR_co_consts ,
MP_QSTR_co_names ,
MP_QSTR_co_varnames ,
MP_QSTR_co_freevars ,
MP_QSTR_co_cellvars ,
MP_QSTR_co_filename ,
MP_QSTR_co_name ,
MP_QSTR_co_firstlineno ,
MP_QSTR_co_lnotab ,
} ,
} ;
STATIC mp_obj_t code_make_new ( qstr file , qstr block ) {
mp_obj_t elems [ 15 ] = {
mp_obj_new_int ( 0 ) , // co_argcount
mp_obj_new_int ( 0 ) , // co_kwonlyargcount
mp_obj_new_int ( 0 ) , // co_nlocals
mp_obj_new_int ( 0 ) , // co_stacksize
mp_obj_new_int ( 0 ) , // co_flags
mp_obj_new_bytearray ( 0 , NULL ) , // co_code
mp_obj_new_tuple ( 0 , NULL ) , // co_consts
mp_obj_new_tuple ( 0 , NULL ) , // co_names
mp_obj_new_tuple ( 0 , NULL ) , // co_varnames
mp_obj_new_tuple ( 0 , NULL ) , // co_freevars
mp_obj_new_tuple ( 0 , NULL ) , // co_cellvars
MP_OBJ_NEW_QSTR ( file ) , // co_filename
MP_OBJ_NEW_QSTR ( block ) , // co_name
mp_obj_new_int ( 1 ) , // co_firstlineno
mp_obj_new_bytearray ( 0 , NULL ) , // co_lnotab
} ;
return namedtuple_make_new ( ( const mp_obj_type_t * ) & code_type_obj , 15 , 0 , elems ) ;
}
STATIC const mp_obj_namedtuple_type_t frame_type_obj = {
NAMEDTUPLE_TYPE_BASE_AND_SLOTS ( MP_QSTR_frame ) ,
. n_fields = 8 ,
. fields = {
MP_QSTR_f_back ,
MP_QSTR_f_builtins ,
MP_QSTR_f_code ,
MP_QSTR_f_globals ,
MP_QSTR_f_lasti ,
MP_QSTR_f_lineno ,
MP_QSTR_f_locals ,
MP_QSTR_f_trace ,
} ,
} ;
STATIC mp_obj_t frame_make_new ( mp_obj_t f_code , int f_lineno ) {
mp_obj_t elems [ 8 ] = {
mp_const_none , // f_back
mp_obj_new_dict ( 0 ) , // f_builtins
f_code , // f_code
mp_obj_new_dict ( 0 ) , // f_globals
mp_obj_new_int ( 0 ) , // f_lasti
mp_obj_new_int ( f_lineno ) , // f_lineno
mp_obj_new_dict ( 0 ) , // f_locals
mp_const_none , // f_trace
} ;
return namedtuple_make_new ( ( const mp_obj_type_t * ) & frame_type_obj , 8 , 0 , elems ) ;
}
STATIC const mp_obj_namedtuple_type_t traceback_type_obj = {
NAMEDTUPLE_TYPE_BASE_AND_SLOTS ( MP_QSTR_traceback ) ,
. n_fields = 4 ,
. fields = {
MP_QSTR_tb_frame ,
MP_QSTR_tb_lasti ,
MP_QSTR_tb_lineno ,
MP_QSTR_tb_next ,
} ,
} ;
STATIC mp_obj_t traceback_from_values ( size_t * values , mp_obj_t tb_next ) {
int lineno = values [ 1 ] ;
mp_obj_t elems [ 4 ] = {
frame_make_new ( code_make_new ( values [ 0 ] , values [ 2 ] ) , lineno ) ,
mp_obj_new_int ( 0 ) ,
mp_obj_new_int ( lineno ) ,
tb_next ,
} ;
return namedtuple_make_new ( ( const mp_obj_type_t * ) & traceback_type_obj , 4 , 0 , elems ) ;
} ;
mp_obj_t mp_obj_exception_get_traceback_obj ( mp_obj_t self_in ) {
mp_obj_exception_t * self = MP_OBJ_TO_PTR ( self_in ) ;
if ( ! mp_obj_is_exception_instance ( self ) ) {
return mp_const_none ;
}
size_t n , * values ;
mp_obj_exception_get_traceback ( self , & n , & values ) ;
if ( n = = 0 ) {
return mp_const_none ;
}
mp_obj_t tb_next = mp_const_none ;
for ( size_t i = 0 ; i < n ; i + = 3 ) {
tb_next = traceback_from_values ( & values [ i ] , tb_next ) ;
}
return tb_next ;
}
# endif