summaryrefslogtreecommitdiff
path: root/py/obj.c
diff options
context:
space:
mode:
authorYonatan Goldschmidt <yon.goldschmidt@gmail.com>2020-01-22 13:34:19 +0100
committerDamien George <damien@micropython.org>2022-07-18 11:17:46 +1000
commit2a6ba47110be88ff1e1f5abd1bd76c353447884c (patch)
treebfcbdca7337b6e47d1315dbf14cb339833d0e944 /py/obj.c
parent6670281472aa3c931b08e623488a02c335aeda20 (diff)
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>
Diffstat (limited to 'py/obj.c')
-rw-r--r--py/obj.c8
1 files changed, 4 insertions, 4 deletions
diff --git a/py/obj.c b/py/obj.c
index 024de3c96..51f6d85de 100644
--- a/py/obj.c
+++ b/py/obj.c
@@ -304,7 +304,7 @@ mp_int_t mp_obj_get_int(mp_const_obj_t arg) {
return 1;
} else if (mp_obj_is_small_int(arg)) {
return MP_OBJ_SMALL_INT_VALUE(arg);
- } else if (mp_obj_is_type(arg, &mp_type_int)) {
+ } else if (mp_obj_is_exact_type(arg, &mp_type_int)) {
return mp_obj_int_get_checked(arg);
} else {
mp_obj_t res = mp_unary_op(MP_UNARY_OP_INT, (mp_obj_t)arg);
@@ -330,7 +330,7 @@ bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value) {
*value = 1;
} else if (mp_obj_is_small_int(arg)) {
*value = MP_OBJ_SMALL_INT_VALUE(arg);
- } else if (mp_obj_is_type(arg, &mp_type_int)) {
+ } else if (mp_obj_is_exact_type(arg, &mp_type_int)) {
*value = mp_obj_int_get_checked(arg);
} else {
return false;
@@ -349,7 +349,7 @@ bool mp_obj_get_float_maybe(mp_obj_t arg, mp_float_t *value) {
} else if (mp_obj_is_small_int(arg)) {
val = (mp_float_t)MP_OBJ_SMALL_INT_VALUE(arg);
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
- } else if (mp_obj_is_type(arg, &mp_type_int)) {
+ } else if (mp_obj_is_exact_type(arg, &mp_type_int)) {
val = mp_obj_int_as_float_impl(arg);
#endif
} else if (mp_obj_is_float(arg)) {
@@ -389,7 +389,7 @@ bool mp_obj_get_complex_maybe(mp_obj_t arg, mp_float_t *real, mp_float_t *imag)
*real = (mp_float_t)MP_OBJ_SMALL_INT_VALUE(arg);
*imag = 0;
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
- } else if (mp_obj_is_type(arg, &mp_type_int)) {
+ } else if (mp_obj_is_exact_type(arg, &mp_type_int)) {
*real = mp_obj_int_as_float_impl(arg);
*imag = 0;
#endif