From 47b9809d231c4359c56316130a76f13de2b907f7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 3 May 2015 23:23:18 +0100 Subject: [PATCH] py: Check that arg to object.__new__ is a user-defined type. Addresses issue #1203. --- py/objobject.c | 9 ++++++--- py/objtype.c | 19 ++++++++----------- py/objtype.h | 5 +++++ tests/basics/object_new.py | 10 ++++++++++ 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/py/objobject.c b/py/objobject.c index c5675c07196f..7288ac946edb 100644 --- a/py/objobject.c +++ b/py/objobject.c @@ -26,10 +26,9 @@ #include +#include "py/objtype.h" #include "py/runtime.h" -mp_obj_t instance_make_new(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args); - typedef struct _mp_obj_object_t { mp_obj_base_t base; } mp_obj_object_t; @@ -50,8 +49,12 @@ STATIC mp_obj_t object___init__(mp_obj_t self) { 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*)cls)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, + "__new__ arg must be a user-type")); + } mp_obj_t o = MP_OBJ_SENTINEL; - mp_obj_t res = instance_make_new(cls, 1, 0, &o); + mp_obj_t res = mp_obj_instance_make_new(cls, 1, 0, &o); return res; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___new___fun_obj, object___new__); diff --git a/py/objtype.c b/py/objtype.c index ed2d688cacf2..c2c8d2e6dfc7 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -48,10 +48,6 @@ STATIC mp_obj_t static_class_method_make_new(mp_obj_t self_in, mp_uint_t n_args, /******************************************************************************/ // instance object -#define is_instance_type(type) ((type)->make_new == instance_make_new) -#define is_native_type(type) ((type)->make_new != instance_make_new) -mp_obj_t instance_make_new(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args); - STATIC mp_obj_t mp_obj_new_instance(mp_obj_t class, uint subobjs) { mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, subobjs); o->base.type = class; @@ -73,7 +69,7 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t // Not a "real" type continue; } - if (is_native_type(bt)) { + if (mp_obj_is_native_type(bt)) { *last_native_base = bt; count++; } else { @@ -114,7 +110,7 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_ // This avoids extra method_name => slot lookup. On the other hand, // this should not be applied to class types, as will result in extra // lookup either. - if (lookup->meth_offset != 0 && is_native_type(type)) { + if (lookup->meth_offset != 0 && mp_obj_is_native_type(type)) { if (*(void**)((char*)type + lookup->meth_offset) != NULL) { DEBUG_printf("mp_obj_class_lookup: matched special meth slot for %s\n", qstr_str(lookup->attr)); lookup->dest[0] = MP_OBJ_SENTINEL; @@ -135,7 +131,7 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_ mp_convert_member_lookup(NULL, org_type, elem->value, lookup->dest); } else { mp_obj_instance_t *obj = lookup->obj; - if (obj != MP_OBJ_NULL && is_native_type(type) && type != &mp_type_object /* object is not a real type */) { + if (obj != MP_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->subobj[0]; } @@ -153,7 +149,7 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_ // Previous code block takes care about attributes defined in .locals_dict, // but some attributes of native types may be handled using .load_attr method, // so make sure we try to lookup those too. - if (lookup->obj != MP_OBJ_NULL && !lookup->is_type && is_native_type(type) && type != &mp_type_object /* object is not a real type */) { + if (lookup->obj != MP_OBJ_NULL && !lookup->is_type && mp_obj_is_native_type(type) && type != &mp_type_object /* object is not a real type */) { mp_load_method_maybe(lookup->obj->subobj[0], lookup->attr, lookup->dest); if (lookup->dest[0] != MP_OBJ_NULL) { return; @@ -238,9 +234,10 @@ STATIC void instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k mp_printf(print, "<%s object at %p>", mp_obj_get_type_str(self_in), self_in); } -mp_obj_t instance_make_new(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { +mp_obj_t mp_obj_instance_make_new(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type)); mp_obj_type_t *self = self_in; + assert(mp_obj_is_instance_type(self)); const mp_obj_type_t *native_base; uint num_native_bases = instance_count_native_bases(self, &native_base); @@ -442,7 +439,7 @@ STATIC mp_obj_t instance_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_i STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { // logic: look in instance members then class locals - assert(is_instance_type(mp_obj_get_type(self_in))); + assert(mp_obj_is_instance_type(mp_obj_get_type(self_in))); mp_obj_instance_t *self = self_in; mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); @@ -870,7 +867,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) o->base.type = &mp_type_type; o->name = name; o->print = instance_print; - o->make_new = instance_make_new; + o->make_new = mp_obj_instance_make_new; o->call = mp_obj_instance_call; o->unary_op = instance_unary_op; o->binary_op = instance_binary_op; diff --git a/py/objtype.h b/py/objtype.h index de1909b1e156..6023e8dfe51f 100644 --- a/py/objtype.h +++ b/py/objtype.h @@ -44,4 +44,9 @@ void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest); bool mp_obj_instance_is_callable(mp_obj_t self_in); mp_obj_t mp_obj_instance_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args); +#define mp_obj_is_instance_type(type) ((type)->make_new == mp_obj_instance_make_new) +#define mp_obj_is_native_type(type) ((type)->make_new != mp_obj_instance_make_new) +// this needs to be exposed for the above macros to work correctly +mp_obj_t mp_obj_instance_make_new(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args); + #endif // __MICROPY_INCLUDED_PY_OBJTYPE_H__ diff --git a/tests/basics/object_new.py b/tests/basics/object_new.py index 6131ed337e00..befb5bfc27bd 100644 --- a/tests/basics/object_new.py +++ b/tests/basics/object_new.py @@ -18,3 +18,13 @@ def __init__(self): #print(dir(o)) print(hasattr(o, "attr")) print(o.attr) + +# should only be able to call __new__ on user types +try: + object.__new__(1) +except TypeError: + print("TypeError") +try: + object.__new__(int) +except TypeError: + print("TypeError")