From 178ce7ce89ddd36aaa1d092ab04b7d87d3e25ac5 Mon Sep 17 00:00:00 2001 From: Chia-Hsiang Cheng Date: Sun, 15 Jan 2023 23:28:47 +0800 Subject: [PATCH 1/4] Raise TypeError when calling __new__ unsafely --- vm/src/builtins/type.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index a4db53225b..ee9d6f2d41 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -1120,6 +1120,24 @@ pub(crate) fn call_slot_new( args: FuncArgs, vm: &VirtualMachine, ) -> PyResult { + let mut static_base = Some(subtype.clone()); + while let Some(ref basetype) = static_base { + if (basetype.flags() & PyTypeFlags::HEAPTYPE.bits()) != 0 { + static_base = basetype.base().clone(); + } else { + break; + } + } + if let Some(ref basetype) = static_base { + if !PyType::subclasscheck(basetype.to_owned(), typ.to_owned()) { + return Err(vm.new_type_error(format!( + "{}.__new__({}) is not safe, use {}.__new__()", + typ.name(), + subtype.name(), + basetype.name() + ))); + } + } for cls in typ.deref().iter_mro() { if let Some(slot_new) = cls.slots.new.load() { return slot_new(subtype, args, vm); From b7bf3de491aaed7569fe9aa4d5657bd6b1a13bec Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 17 Feb 2023 22:55:07 +0900 Subject: [PATCH 2/4] Another trial --- vm/src/builtins/type.rs | 50 +++++++++++++++++++++++++---------------- vm/src/types/slot.rs | 3 ++- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index ee9d6f2d41..9251c2af45 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -383,7 +383,36 @@ impl PyType { subtype = subtype.name(), ))); } - call_slot_new(zelf, subtype, args, vm) + + let typ = zelf; + // Check that the use doesn't do something silly and unsafe like + // object.__new__(dict). To do this, we check that the + // most derived base that's not a heap type is this type. */ + let mut static_base = subtype.clone(); + loop { + if static_base + .slots + .new + .load() + .map_or(false, |f| f as usize == crate::types::new_wrapper as usize) + { + static_base = static_base.base().unwrap(); + } else { + break; + } + } + if static_base.slots.new.load().map_or(0, |f| f as usize) + != typ.slots.new.load().map_or(0, |f| f as usize) + { + return Err(vm.new_type_error(format!( + "{}.__new__({}) is not safe, use {}.__new__()", + typ.name(), + subtype.name(), + static_base.name() + ))); + } + + call_slot_new(typ, subtype, args, vm) } #[pygetset(name = "__mro__")] @@ -1114,30 +1143,13 @@ pub(crate) fn init(ctx: &Context) { PyType::extend_class(ctx, ctx.types.type_type); } +// part of tp_new_wrapper *after* subtype check pub(crate) fn call_slot_new( typ: PyTypeRef, subtype: PyTypeRef, args: FuncArgs, vm: &VirtualMachine, ) -> PyResult { - let mut static_base = Some(subtype.clone()); - while let Some(ref basetype) = static_base { - if (basetype.flags() & PyTypeFlags::HEAPTYPE.bits()) != 0 { - static_base = basetype.base().clone(); - } else { - break; - } - } - if let Some(ref basetype) = static_base { - if !PyType::subclasscheck(basetype.to_owned(), typ.to_owned()) { - return Err(vm.new_type_error(format!( - "{}.__new__({}) is not safe, use {}.__new__()", - typ.name(), - subtype.name(), - basetype.name() - ))); - } - } for cls in typ.deref().iter_mro() { if let Some(slot_new) = cls.slots.new.load() { return slot_new(subtype, args, vm); diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index 1be87b4f14..8521a719e2 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -334,7 +334,8 @@ fn init_wrapper(obj: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResu Ok(()) } -fn new_wrapper(cls: PyTypeRef, mut args: FuncArgs, vm: &VirtualMachine) -> PyResult { +// = slot_tp_new +pub(crate) fn new_wrapper(cls: PyTypeRef, mut args: FuncArgs, vm: &VirtualMachine) -> PyResult { let new = cls.get_attr(identifier!(vm, __new__)).unwrap(); args.prepend_arg(cls.into()); vm.invoke(&new, args) From 0f2478e719a595f383c532f27dfa5e3d25e7e71d Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 17 Feb 2023 22:55:00 +0900 Subject: [PATCH 3/4] Add a few comments --- vm/src/builtins/type.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index 9251c2af45..015811ac4d 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -358,6 +358,7 @@ impl Py { /// Determines if `subclass` is actually a subclass of `cls`, this doesn't call __subclasscheck__, /// so only use this if `cls` is known to have not overridden the base __subclasscheck__ magic /// method. + /// Similar to CPython PyType_IsSubtype pub fn fast_issubclass(&self, cls: &impl Borrow) -> bool { self.as_object().is(cls.borrow()) || self.mro.iter().any(|c| c.is(cls.borrow())) } From 6b01bfa5661200fe6c149e3561aa25601b8ec5b1 Mon Sep 17 00:00:00 2001 From: Chia-Hsiang Cheng Date: Mon, 16 Jan 2023 13:18:04 +0800 Subject: [PATCH 4/4] Update the test --- Lib/test/test_bool.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lib/test/test_bool.py b/Lib/test/test_bool.py index f413b7aaaf..4b32aad241 100644 --- a/Lib/test/test_bool.py +++ b/Lib/test/test_bool.py @@ -7,8 +7,6 @@ class BoolTest(unittest.TestCase): - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_subclass(self): try: class C(bool):