diff --git a/src/capi/typeobject.cpp b/src/capi/typeobject.cpp index 135e7e2966dc9a758ccbc1b06065e6eb994253f1..6d124c99443beaf043a05c84cce992aaf951cd96 100644 --- a/src/capi/typeobject.cpp +++ b/src/capi/typeobject.cpp @@ -872,7 +872,7 @@ static PyObject* call_attribute(PyObject* self, PyObject* attr, PyObject* name) template <ExceptionStyle S, Rewritable rewritable> Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* rewrite_args, bool for_call, - Box** bind_obj_out, RewriterVar** r_bind_obj_out) noexcept(S == CAPI) { + BORROWED(Box**) bind_obj_out, RewriterVar** r_bind_obj_out) noexcept(S == CAPI) { if (rewritable == NOT_REWRITABLE) { assert(!rewrite_args); rewrite_args = NULL; diff --git a/src/capi/typeobject.h b/src/capi/typeobject.h index d63ef31e5079c220b82c373827656bd598aadaad..c34c240499086d90f827e15d67a1061783fe23e9 100644 --- a/src/capi/typeobject.h +++ b/src/capi/typeobject.h @@ -58,7 +58,7 @@ int compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, const ch class GetattrRewriteArgs; template <ExceptionStyle S, Rewritable rewritable> Box* slotTpGetattrHookInternal(Box* self, BoxedString* attr, GetattrRewriteArgs* rewrite_args, bool for_call, - Box** bind_obj_out, RewriterVar** r_bind_obj_out) noexcept(S == CAPI); + BORROWED(Box**) bind_obj_out, RewriterVar** r_bind_obj_out) noexcept(S == CAPI); } #endif diff --git a/src/runtime/objmodel.cpp b/src/runtime/objmodel.cpp index 34a0463a6b5618bd69ec27e40255cc714ee01095..de55d6ab828865b76895ee05c565a47101778671 100644 --- a/src/runtime/objmodel.cpp +++ b/src/runtime/objmodel.cpp @@ -1807,7 +1807,7 @@ bool isNondataDescriptorInstanceSpecialCase(Box* descr) { template <Rewritable rewritable> Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box* obj, Box* descr, RewriterVar* r_descr, - bool for_call, Box** bind_obj_out, RewriterVar** r_bind_obj_out) { + bool for_call, BORROWED(Box**) bind_obj_out, RewriterVar** r_bind_obj_out) { if (rewritable == NOT_REWRITABLE) { assert(!rewrite_args); rewrite_args = NULL; @@ -1888,7 +1888,7 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box } return boxInstanceMethod(im_self, im_func, im_class); } else { - *bind_obj_out = incref(im_self); + *bind_obj_out = im_self; if (rewrite_args) { rewrite_args->setReturn(r_im_func, ReturnConvention::HAS_RETURN); *r_bind_obj_out = r_im_self; @@ -1915,7 +1915,7 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box rewrite_args->setReturn(r_descr, ReturnConvention::HAS_RETURN); *r_bind_obj_out = rewrite_args->obj; } - *bind_obj_out = incref(obj); + *bind_obj_out = obj; return incref(descr); } else { BoxedWrapperDescriptor* self = static_cast<BoxedWrapperDescriptor*>(descr); @@ -1944,7 +1944,7 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box // r_descr must represent a valid object. template <Rewritable rewritable> Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls, Box* descr, RewriterVar* r_descr, - bool for_call, Box** bind_obj_out, RewriterVar** r_bind_obj_out) { + bool for_call, BORROWED(Box**) bind_obj_out, RewriterVar** r_bind_obj_out) { if (rewritable == NOT_REWRITABLE) { assert(!rewrite_args); rewrite_args = NULL; @@ -1999,7 +1999,7 @@ Box* boxChar(char c) { // r_descr needs to represent a valid object template <Rewritable rewritable> Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedString* attr_name, Box* obj, Box* descr, - RewriterVar* r_descr, bool for_call, Box** bind_obj_out, + RewriterVar* r_descr, bool for_call, BORROWED(Box**) bind_obj_out, RewriterVar** r_bind_obj_out) { if (rewritable == NOT_REWRITABLE) { assert(!rewrite_args); @@ -2214,7 +2214,7 @@ static void ensureValidCapiReturn(Box* r) { template <ExceptionStyle S, Rewritable rewritable> Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_args, bool cls_only, bool for_call, - Box** bind_obj_out, RewriterVar** r_bind_obj_out) noexcept(S == CAPI) { + BORROWED(Box**) bind_obj_out, RewriterVar** r_bind_obj_out) noexcept(S == CAPI) { if (rewritable == NOT_REWRITABLE) { assert(!rewrite_args); rewrite_args = NULL; @@ -2431,7 +2431,7 @@ Box* processDescriptor(Box* obj, Box* inst, Box* owner) { template <bool IsType, Rewritable rewritable> Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_args, bool cls_only, bool for_call, - Box** bind_obj_out, RewriterVar** r_bind_obj_out) { + BORROWED(Box**) bind_obj_out, RewriterVar** r_bind_obj_out) { if (rewritable == NOT_REWRITABLE) { assert(!rewrite_args); rewrite_args = NULL; @@ -3745,8 +3745,6 @@ Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallattrRe return val; } - AUTO_XDECREF(bind_obj); - if (bind_obj != NULL) { Box** new_args = NULL; if (npassed_args >= 3) { diff --git a/src/runtime/objmodel.h b/src/runtime/objmodel.h index a97a34144407160ed5250fa819478784175cf12d..d44fbda333c237e4d5bdbb9d7afce4fe643a4138 100644 --- a/src/runtime/objmodel.h +++ b/src/runtime/objmodel.h @@ -168,7 +168,7 @@ template <ExceptionStyle S> inline Box* getattrInternal(Box* obj, BoxedString* a // __getattribute__. template <bool IsType, Rewritable rewritable> Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_args, bool cls_only, bool for_call, - Box** bind_obj_out, RewriterVar** r_bind_obj_out); + BORROWED(Box**) bind_obj_out, RewriterVar** r_bind_obj_out); extern "C" PyObject* type_getattro(PyObject* o, PyObject* name) noexcept; diff --git a/test/tests/arg_refs.py b/test/tests/arg_refs.py index 787115aceffc28d851b95a5996f0cdcc1c82b00d..ed5a497b889a8f6fc03d860741b1553e0cf8f1a8 100644 --- a/test/tests/arg_refs.py +++ b/test/tests/arg_refs.py @@ -1,3 +1,4 @@ +# skip-if: '-n' in EXTRA_JIT_ARGS or '-O' in EXTRA_JIT_ARGS # Tests to see if we add any extra refs to function arguments. import sys @@ -7,4 +8,13 @@ def f(o): print sys.getrefcount(o) # This gives 3 for CPython and our interpreter, but 2 for the llvm tier: -# f(object()) +f(object()) + +import sys +class C(object): + def foo(self, *args): + print sys.getrefcount(self) +c = C() +a = (c.foo) +print sys.getrefcount(c) +c.foo() diff --git a/test/tests/cpython_oldstyle_getattr_crash.py b/test/tests/cpython_oldstyle_getattr_crash.py index 1a2641407c8e02bff28684e5e26bf92dc2c8ed34..9dbfeb82a524eb658b9bf4b8e5fce56db3e5b18c 100644 --- a/test/tests/cpython_oldstyle_getattr_crash.py +++ b/test/tests/cpython_oldstyle_getattr_crash.py @@ -1,3 +1,6 @@ +# skip-if: True +# - sadly, we have now inherited CPython's buggy behavior here + # This segfaults under python-dbg # (In a release build it "works" since the use-after-free happens without penalty.)