Commit 9ca668f8 authored by Laurens Valk's avatar Laurens Valk Committed by Damien George

py/objtype: Avoid crash on calling members of uninitialized native type.

When subclassing a native type, calling native members in `__init__` before
`super().__init__()` has been called could cause a crash.  In this
situation, `self` in `mp_convert_member_lookup` is the
`native_base_init_wrapper_obj`.  The check added in this commit ensures
that an `AttributeError` is raised before this happens, which is consistent
with other failed lookups.

Also fix a typo in a related comment.
Signed-off-by: default avatarLaurens Valk <laurens@pybricks.com>
parent 19b1333c
......@@ -82,7 +82,7 @@ static int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t
}
}
// This wrapper function is allows a subclass of a native type to call the
// This wrapper function allows a subclass of a native type to call the
// __init__() method (corresponding to type->make_new) of the native type.
static mp_obj_t native_base_init_wrapper(size_t n_args, const mp_obj_t *args) {
mp_obj_instance_t *self = MP_OBJ_TO_PTR(args[0]);
......@@ -170,6 +170,12 @@ static void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_t
if (obj != NULL && mp_obj_is_native_type(type) && type != &mp_type_object /* object is not a real type */) {
// If we're dealing with native base class, then it applies to native sub-object
obj_obj = obj->subobj[0];
#if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG
if (obj_obj == MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj)) {
// But we shouldn't attempt lookups on object that is not yet instantiated.
mp_raise_msg(&mp_type_AttributeError, MP_ERROR_TEXT("call super().__init__() first"));
}
#endif // MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG
} else {
obj_obj = MP_OBJ_FROM_PTR(obj);
}
......
# test subclassing custom native class
try:
from cexample import AdvancedTimer
except ImportError:
print("SKIP")
raise SystemExit
class SubTimer(AdvancedTimer):
def __init__(self):
# At this point, self does not yet represent a AdvancedTimer instance.
print(self)
# So lookups via type.attr handler will fail.
try:
self.seconds
except AttributeError:
print("AttributeError")
# Also applies to builtin methods.
try:
self.time()
except AttributeError:
print("AttributeError")
# Initialize base class.
super().__init__(self)
# Now you can access methods and attributes normally.
self.time()
print(self.seconds)
self.seconds = 123
print(self.seconds)
watch = SubTimer()
<function>
AttributeError
AttributeError
0
123
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment