From 0e09c6f86ef34f4903d23f1baf3929dcf43fa8fb Mon Sep 17 00:00:00 2001 From: Xuanteng Huang <44627253+xuantengh@users.noreply.github.com> Date: Thu, 6 Feb 2025 22:40:50 +0800 Subject: [PATCH 1/2] gh-128714: Fix function object races in `__annotate__`, `__annotations__` and `__type_params__` in free-threading build (#129016) (cherry picked from commit 55f17b77c305be877ac856d6426b13591cbc7fc8) --- .../test_func_annotations.py | 67 +++++++ ...-01-19-09-07-44.gh-issue-128714.m1fyCB.rst | 1 + Objects/clinic/funcobject.c.h | 174 +++++++++++++++++- Objects/funcobject.c | 152 +++++++++++---- 4 files changed, 358 insertions(+), 36 deletions(-) create mode 100644 Lib/test/test_free_threading/test_func_annotations.py create mode 100644 Misc/NEWS.d/next/Core and Builtins/2025-01-19-09-07-44.gh-issue-128714.m1fyCB.rst diff --git a/Lib/test/test_free_threading/test_func_annotations.py b/Lib/test/test_free_threading/test_func_annotations.py new file mode 100644 index 00000000000000..1a6461953d4aec --- /dev/null +++ b/Lib/test/test_free_threading/test_func_annotations.py @@ -0,0 +1,67 @@ +import concurrent.futures +import unittest +import inspect +from threading import Thread, Barrier +from unittest import TestCase + +from test.support import threading_helper, Py_GIL_DISABLED + +threading_helper.requires_working_threading(module=True) + + +def get_func_annotation(f, b): + b.wait() + return inspect.get_annotations(f) + + +def get_func_annotation_dunder(f, b): + b.wait() + return f.__annotations__ + + +def set_func_annotation(f, b): + b.wait() + f.__annotations__ = {'x': int, 'y': int, 'return': int} + return f.__annotations__ + + +@unittest.skipUnless(Py_GIL_DISABLED, "Enable only in FT build") +class TestFTFuncAnnotations(TestCase): + NUM_THREADS = 8 + + def test_concurrent_read(self): + def f(x: int) -> int: + return x + 1 + + for _ in range(100): + with concurrent.futures.ThreadPoolExecutor(max_workers=self.NUM_THREADS) as executor: + b = Barrier(self.NUM_THREADS) + futures = {executor.submit(get_func_annotation, f, b): i for i in range(self.NUM_THREADS)} + for fut in concurrent.futures.as_completed(futures): + annotate = fut.result() + self.assertIsNotNone(annotate) + self.assertEqual(annotate, {'x': int, 'return': int}) + + with concurrent.futures.ThreadPoolExecutor(max_workers=self.NUM_THREADS) as executor: + b = Barrier(self.NUM_THREADS) + futures = {executor.submit(get_func_annotation_dunder, f, b): i for i in range(self.NUM_THREADS)} + for fut in concurrent.futures.as_completed(futures): + annotate = fut.result() + self.assertIsNotNone(annotate) + self.assertEqual(annotate, {'x': int, 'return': int}) + + def test_concurrent_write(self): + def bar(x: int, y: float) -> float: + return y ** x + + for _ in range(100): + with concurrent.futures.ThreadPoolExecutor(max_workers=self.NUM_THREADS) as executor: + b = Barrier(self.NUM_THREADS) + futures = {executor.submit(set_func_annotation, bar, b): i for i in range(self.NUM_THREADS)} + for fut in concurrent.futures.as_completed(futures): + annotate = fut.result() + self.assertIsNotNone(annotate) + self.assertEqual(annotate, {'x': int, 'y': int, 'return': int}) + + # func_get_annotations returns in-place dict, so bar.__annotations__ should be modified as well + self.assertEqual(bar.__annotations__, {'x': int, 'y': int, 'return': int}) diff --git a/Misc/NEWS.d/next/Core and Builtins/2025-01-19-09-07-44.gh-issue-128714.m1fyCB.rst b/Misc/NEWS.d/next/Core and Builtins/2025-01-19-09-07-44.gh-issue-128714.m1fyCB.rst new file mode 100644 index 00000000000000..431032241e9157 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2025-01-19-09-07-44.gh-issue-128714.m1fyCB.rst @@ -0,0 +1 @@ +Fix the potential races in get/set dunder methods ``__annotations__``, ``__annotate__`` and ``__type_params__`` for function object, and add related tests. diff --git a/Objects/clinic/funcobject.c.h b/Objects/clinic/funcobject.c.h index 8f20bda26438cf..505f20c74c002e 100644 --- a/Objects/clinic/funcobject.c.h +++ b/Objects/clinic/funcobject.c.h @@ -6,8 +6,180 @@ preserve # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif +#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() +PyDoc_STRVAR(function___annotate____doc__, +"Get the code object for a function."); +#if defined(function___annotate___DOCSTR) +# undef function___annotate___DOCSTR +#endif +#define function___annotate___DOCSTR function___annotate____doc__ + +#if !defined(function___annotate___DOCSTR) +# define function___annotate___DOCSTR NULL +#endif +#if defined(FUNCTION___ANNOTATE___GETSETDEF) +# undef FUNCTION___ANNOTATE___GETSETDEF +# define FUNCTION___ANNOTATE___GETSETDEF {"__annotate__", (getter)function___annotate___get, (setter)function___annotate___set, function___annotate___DOCSTR}, +#else +# define FUNCTION___ANNOTATE___GETSETDEF {"__annotate__", (getter)function___annotate___get, NULL, function___annotate___DOCSTR}, +#endif + +static PyObject * +function___annotate___get_impl(PyFunctionObject *self); + +static PyObject * +function___annotate___get(PyObject *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = function___annotate___get_impl((PyFunctionObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if !defined(function___annotate___DOCSTR) +# define function___annotate___DOCSTR NULL +#endif +#if defined(FUNCTION___ANNOTATE___GETSETDEF) +# undef FUNCTION___ANNOTATE___GETSETDEF +# define FUNCTION___ANNOTATE___GETSETDEF {"__annotate__", (getter)function___annotate___get, (setter)function___annotate___set, function___annotate___DOCSTR}, +#else +# define FUNCTION___ANNOTATE___GETSETDEF {"__annotate__", NULL, (setter)function___annotate___set, NULL}, +#endif + +static int +function___annotate___set_impl(PyFunctionObject *self, PyObject *value); + +static int +function___annotate___set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) +{ + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = function___annotate___set_impl((PyFunctionObject *)self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(function___annotations____doc__, +"Dict of annotations in a function object."); +#if defined(function___annotations___DOCSTR) +# undef function___annotations___DOCSTR +#endif +#define function___annotations___DOCSTR function___annotations____doc__ + +#if !defined(function___annotations___DOCSTR) +# define function___annotations___DOCSTR NULL +#endif +#if defined(FUNCTION___ANNOTATIONS___GETSETDEF) +# undef FUNCTION___ANNOTATIONS___GETSETDEF +# define FUNCTION___ANNOTATIONS___GETSETDEF {"__annotations__", (getter)function___annotations___get, (setter)function___annotations___set, function___annotations___DOCSTR}, +#else +# define FUNCTION___ANNOTATIONS___GETSETDEF {"__annotations__", (getter)function___annotations___get, NULL, function___annotations___DOCSTR}, +#endif + +static PyObject * +function___annotations___get_impl(PyFunctionObject *self); + +static PyObject * +function___annotations___get(PyObject *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = function___annotations___get_impl((PyFunctionObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if !defined(function___annotations___DOCSTR) +# define function___annotations___DOCSTR NULL +#endif +#if defined(FUNCTION___ANNOTATIONS___GETSETDEF) +# undef FUNCTION___ANNOTATIONS___GETSETDEF +# define FUNCTION___ANNOTATIONS___GETSETDEF {"__annotations__", (getter)function___annotations___get, (setter)function___annotations___set, function___annotations___DOCSTR}, +#else +# define FUNCTION___ANNOTATIONS___GETSETDEF {"__annotations__", NULL, (setter)function___annotations___set, NULL}, +#endif + +static int +function___annotations___set_impl(PyFunctionObject *self, PyObject *value); + +static int +function___annotations___set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) +{ + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = function___annotations___set_impl((PyFunctionObject *)self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(function___type_params____doc__, +"Get the declared type parameters for a function."); +#if defined(function___type_params___DOCSTR) +# undef function___type_params___DOCSTR +#endif +#define function___type_params___DOCSTR function___type_params____doc__ + +#if !defined(function___type_params___DOCSTR) +# define function___type_params___DOCSTR NULL +#endif +#if defined(FUNCTION___TYPE_PARAMS___GETSETDEF) +# undef FUNCTION___TYPE_PARAMS___GETSETDEF +# define FUNCTION___TYPE_PARAMS___GETSETDEF {"__type_params__", (getter)function___type_params___get, (setter)function___type_params___set, function___type_params___DOCSTR}, +#else +# define FUNCTION___TYPE_PARAMS___GETSETDEF {"__type_params__", (getter)function___type_params___get, NULL, function___type_params___DOCSTR}, +#endif + +static PyObject * +function___type_params___get_impl(PyFunctionObject *self); + +static PyObject * +function___type_params___get(PyObject *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = function___type_params___get_impl((PyFunctionObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if !defined(function___type_params___DOCSTR) +# define function___type_params___DOCSTR NULL +#endif +#if defined(FUNCTION___TYPE_PARAMS___GETSETDEF) +# undef FUNCTION___TYPE_PARAMS___GETSETDEF +# define FUNCTION___TYPE_PARAMS___GETSETDEF {"__type_params__", (getter)function___type_params___get, (setter)function___type_params___set, function___type_params___DOCSTR}, +#else +# define FUNCTION___TYPE_PARAMS___GETSETDEF {"__type_params__", NULL, (setter)function___type_params___set, NULL}, +#endif + +static int +function___type_params___set_impl(PyFunctionObject *self, PyObject *value); + +static int +function___type_params___set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) +{ + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = function___type_params___set_impl((PyFunctionObject *)self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + PyDoc_STRVAR(func_new__doc__, "function(code, globals, name=None, argdefs=None, closure=None,\n" " kwdefaults=None)\n" @@ -115,4 +287,4 @@ func_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=10947342188f38a9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=3cdce22867efe617 input=a9049054013a1b77]*/ diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 12d60f991534ab..ff3025208fe03d 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -2,10 +2,11 @@ /* Function object implementation */ #include "Python.h" -#include "pycore_ceval.h" // _PyEval_BuiltinsFromGlobals() -#include "pycore_modsupport.h" // _PyArg_NoKeywords() -#include "pycore_object.h" // _PyObject_GC_UNTRACK() -#include "pycore_pyerrors.h" // _PyErr_Occurred() +#include "pycore_dict.h" // _Py_INCREF_DICT() +#include "pycore_long.h" // _PyLong_GetOne() +#include "pycore_modsupport.h" // _PyArg_NoKeywords() +#include "pycore_object.h" // _PyObject_GC_UNTRACK() +#include "pycore_pyerrors.h" // _PyErr_Occurred() static const char * @@ -582,6 +583,13 @@ static PyMemberDef func_memberlist[] = { {NULL} /* Sentinel */ }; +/*[clinic input] +class function "PyFunctionObject *" "&PyFunction_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=70af9c90aa2e71b0]*/ + +#include "clinic/funcobject.c.h" + static PyObject * func_get_code(PyFunctionObject *op, void *Py_UNUSED(ignored)) { @@ -763,20 +771,87 @@ func_set_kwdefaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignor return 0; } +/*[clinic input] +@critical_section +@getter +function.__annotate__ + +Get the code object for a function. +[clinic start generated code]*/ + static PyObject * -func_get_annotations(PyFunctionObject *op, void *Py_UNUSED(ignored)) +function___annotate___get_impl(PyFunctionObject *self) +/*[clinic end generated code: output=5ec7219ff2bda9e6 input=7f3db11e3c3329f3]*/ { - if (op->func_annotations == NULL) { - op->func_annotations = PyDict_New(); - if (op->func_annotations == NULL) + if (self->func_annotate == NULL) { + Py_RETURN_NONE; + } + return Py_NewRef(self->func_annotate); +} + +/*[clinic input] +@critical_section +@setter +function.__annotate__ +[clinic start generated code]*/ + +static int +function___annotate___set_impl(PyFunctionObject *self, PyObject *value) +/*[clinic end generated code: output=05b7dfc07ada66cd input=eb6225e358d97448]*/ +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, + "__annotate__ cannot be deleted"); + return -1; + } + if (Py_IsNone(value)) { + Py_XSETREF(self->func_annotate, value); + return 0; + } + else if (PyCallable_Check(value)) { + Py_XSETREF(self->func_annotate, Py_XNewRef(value)); + Py_CLEAR(self->func_annotations); + return 0; + } + else { + PyErr_SetString(PyExc_TypeError, + "__annotate__ must be callable or None"); + return -1; + } +} + +/*[clinic input] +@critical_section +@getter +function.__annotations__ + +Dict of annotations in a function object. +[clinic start generated code]*/ + +static PyObject * +function___annotations___get_impl(PyFunctionObject *self) +/*[clinic end generated code: output=a4cf4c884c934cbb input=92643d7186c1ad0c]*/ +{ + PyObject *d = NULL; + if (self->func_annotations == NULL && + (self->func_annotate == NULL || !PyCallable_Check(self->func_annotate))) { + self->func_annotations = PyDict_New(); + if (self->func_annotations == NULL) return NULL; } - PyObject *d = func_get_annotation_dict(op); + d = func_get_annotation_dict(self); return Py_XNewRef(d); } +/*[clinic input] +@critical_section +@setter +function.__annotations__ +[clinic start generated code]*/ + static int -func_set_annotations(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) +function___annotations___set_impl(PyFunctionObject *self, PyObject *value) +/*[clinic end generated code: output=a61795d4a95eede4 input=5302641f686f0463]*/ { if (value == Py_None) value = NULL; @@ -788,23 +863,40 @@ func_set_annotations(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(igno "__annotations__ must be set to a dict object"); return -1; } - Py_XSETREF(op->func_annotations, Py_XNewRef(value)); + Py_XSETREF(self->func_annotations, Py_XNewRef(value)); + Py_CLEAR(self->func_annotate); return 0; } +/*[clinic input] +@critical_section +@getter +function.__type_params__ + +Get the declared type parameters for a function. +[clinic start generated code]*/ + static PyObject * -func_get_type_params(PyFunctionObject *op, void *Py_UNUSED(ignored)) +function___type_params___get_impl(PyFunctionObject *self) +/*[clinic end generated code: output=eb844d7ffca517a8 input=0864721484293724]*/ { - if (op->func_typeparams == NULL) { + if (self->func_typeparams == NULL) { return PyTuple_New(0); } - assert(PyTuple_Check(op->func_typeparams)); - return Py_NewRef(op->func_typeparams); + assert(PyTuple_Check(self->func_typeparams)); + return Py_NewRef(self->func_typeparams); } +/*[clinic input] +@critical_section +@setter +function.__type_params__ +[clinic start generated code]*/ + static int -func_set_type_params(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) +function___type_params___set_impl(PyFunctionObject *self, PyObject *value) +/*[clinic end generated code: output=038b4cda220e56fb input=3862fbd4db2b70e8]*/ { /* Not legal to del f.__type_params__ or to set it to anything * other than a tuple object. */ @@ -813,7 +905,7 @@ func_set_type_params(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(igno "__type_params__ must be set to a tuple"); return -1; } - Py_XSETREF(op->func_typeparams, Py_NewRef(value)); + Py_XSETREF(self->func_typeparams, Py_NewRef(value)); return 0; } @@ -829,28 +921,18 @@ _Py_set_function_type_params(PyThreadState *Py_UNUSED(ignored), PyObject *func, } static PyGetSetDef func_getsetlist[] = { - {"__code__", (getter)func_get_code, (setter)func_set_code}, - {"__defaults__", (getter)func_get_defaults, - (setter)func_set_defaults}, - {"__kwdefaults__", (getter)func_get_kwdefaults, - (setter)func_set_kwdefaults}, - {"__annotations__", (getter)func_get_annotations, - (setter)func_set_annotations}, + {"__code__", func_get_code, func_set_code}, + {"__defaults__", func_get_defaults, func_set_defaults}, + {"__kwdefaults__", func_get_kwdefaults, func_set_kwdefaults}, + FUNCTION___ANNOTATIONS___GETSETDEF + FUNCTION___ANNOTATE___GETSETDEF {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}, - {"__name__", (getter)func_get_name, (setter)func_set_name}, - {"__qualname__", (getter)func_get_qualname, (setter)func_set_qualname}, - {"__type_params__", (getter)func_get_type_params, - (setter)func_set_type_params}, + {"__name__", func_get_name, func_set_name}, + {"__qualname__", func_get_qualname, func_set_qualname}, + FUNCTION___TYPE_PARAMS___GETSETDEF {NULL} /* Sentinel */ }; -/*[clinic input] -class function "PyFunctionObject *" "&PyFunction_Type" -[clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=70af9c90aa2e71b0]*/ - -#include "clinic/funcobject.c.h" - /* function.__new__() maintains the following invariants for closures. The closure must correspond to the free variables of the code object. From 2b822aa57b46058418468e35b562c3de7a28736d Mon Sep 17 00:00:00 2001 From: Xuanteng Huang Date: Tue, 18 Feb 2025 12:50:32 +0800 Subject: [PATCH 2/2] fix ci --- Objects/clinic/funcobject.c.h | 75 ++++--------------------------- Objects/funcobject.c | 84 +++++++++-------------------------- 2 files changed, 31 insertions(+), 128 deletions(-) diff --git a/Objects/clinic/funcobject.c.h b/Objects/clinic/funcobject.c.h index 505f20c74c002e..2dfa489927f242 100644 --- a/Objects/clinic/funcobject.c.h +++ b/Objects/clinic/funcobject.c.h @@ -9,63 +9,6 @@ preserve #include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() -PyDoc_STRVAR(function___annotate____doc__, -"Get the code object for a function."); -#if defined(function___annotate___DOCSTR) -# undef function___annotate___DOCSTR -#endif -#define function___annotate___DOCSTR function___annotate____doc__ - -#if !defined(function___annotate___DOCSTR) -# define function___annotate___DOCSTR NULL -#endif -#if defined(FUNCTION___ANNOTATE___GETSETDEF) -# undef FUNCTION___ANNOTATE___GETSETDEF -# define FUNCTION___ANNOTATE___GETSETDEF {"__annotate__", (getter)function___annotate___get, (setter)function___annotate___set, function___annotate___DOCSTR}, -#else -# define FUNCTION___ANNOTATE___GETSETDEF {"__annotate__", (getter)function___annotate___get, NULL, function___annotate___DOCSTR}, -#endif - -static PyObject * -function___annotate___get_impl(PyFunctionObject *self); - -static PyObject * -function___annotate___get(PyObject *self, void *Py_UNUSED(context)) -{ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); - return_value = function___annotate___get_impl((PyFunctionObject *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -} - -#if !defined(function___annotate___DOCSTR) -# define function___annotate___DOCSTR NULL -#endif -#if defined(FUNCTION___ANNOTATE___GETSETDEF) -# undef FUNCTION___ANNOTATE___GETSETDEF -# define FUNCTION___ANNOTATE___GETSETDEF {"__annotate__", (getter)function___annotate___get, (setter)function___annotate___set, function___annotate___DOCSTR}, -#else -# define FUNCTION___ANNOTATE___GETSETDEF {"__annotate__", NULL, (setter)function___annotate___set, NULL}, -#endif - -static int -function___annotate___set_impl(PyFunctionObject *self, PyObject *value); - -static int -function___annotate___set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) -{ - int return_value; - - Py_BEGIN_CRITICAL_SECTION(self); - return_value = function___annotate___set_impl((PyFunctionObject *)self, value); - Py_END_CRITICAL_SECTION(); - - return return_value; -} - PyDoc_STRVAR(function___annotations____doc__, "Dict of annotations in a function object."); #if defined(function___annotations___DOCSTR) @@ -87,12 +30,12 @@ static PyObject * function___annotations___get_impl(PyFunctionObject *self); static PyObject * -function___annotations___get(PyObject *self, void *Py_UNUSED(context)) +function___annotations___get(PyFunctionObject *self, void *Py_UNUSED(context)) { PyObject *return_value = NULL; Py_BEGIN_CRITICAL_SECTION(self); - return_value = function___annotations___get_impl((PyFunctionObject *)self); + return_value = function___annotations___get_impl(self); Py_END_CRITICAL_SECTION(); return return_value; @@ -112,12 +55,12 @@ static int function___annotations___set_impl(PyFunctionObject *self, PyObject *value); static int -function___annotations___set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) +function___annotations___set(PyFunctionObject *self, PyObject *value, void *Py_UNUSED(context)) { int return_value; Py_BEGIN_CRITICAL_SECTION(self); - return_value = function___annotations___set_impl((PyFunctionObject *)self, value); + return_value = function___annotations___set_impl(self, value); Py_END_CRITICAL_SECTION(); return return_value; @@ -144,12 +87,12 @@ static PyObject * function___type_params___get_impl(PyFunctionObject *self); static PyObject * -function___type_params___get(PyObject *self, void *Py_UNUSED(context)) +function___type_params___get(PyFunctionObject *self, void *Py_UNUSED(context)) { PyObject *return_value = NULL; Py_BEGIN_CRITICAL_SECTION(self); - return_value = function___type_params___get_impl((PyFunctionObject *)self); + return_value = function___type_params___get_impl(self); Py_END_CRITICAL_SECTION(); return return_value; @@ -169,12 +112,12 @@ static int function___type_params___set_impl(PyFunctionObject *self, PyObject *value); static int -function___type_params___set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) +function___type_params___set(PyFunctionObject *self, PyObject *value, void *Py_UNUSED(context)) { int return_value; Py_BEGIN_CRITICAL_SECTION(self); - return_value = function___type_params___set_impl((PyFunctionObject *)self, value); + return_value = function___type_params___set_impl(self, value); Py_END_CRITICAL_SECTION(); return return_value; @@ -287,4 +230,4 @@ func_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=3cdce22867efe617 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=93e052c0f1ebb5f3 input=a9049054013a1b77]*/ diff --git a/Objects/funcobject.c b/Objects/funcobject.c index ff3025208fe03d..3d93673e1863d8 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -2,6 +2,7 @@ /* Function object implementation */ #include "Python.h" +#include "pycore_ceval.h" // _PyEval_BuiltinsFromGlobals() #include "pycore_dict.h" // _Py_INCREF_DICT() #include "pycore_long.h" // _PyLong_GetOne() #include "pycore_modsupport.h" // _PyArg_NoKeywords() @@ -591,8 +592,9 @@ class function "PyFunctionObject *" "&PyFunction_Type" #include "clinic/funcobject.c.h" static PyObject * -func_get_code(PyFunctionObject *op, void *Py_UNUSED(ignored)) +func_get_code(PyObject *self, void *Py_UNUSED(ignored)) { + PyFunctionObject* op = _PyFunction_CAST(self); if (PySys_Audit("object.__getattr__", "Os", op, "__code__") < 0) { return NULL; } @@ -601,8 +603,9 @@ func_get_code(PyFunctionObject *op, void *Py_UNUSED(ignored)) } static int -func_set_code(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) +func_set_code(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) { + PyFunctionObject* op = _PyFunction_CAST(self); Py_ssize_t nclosure; int nfree; @@ -651,14 +654,16 @@ func_set_code(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) } static PyObject * -func_get_name(PyFunctionObject *op, void *Py_UNUSED(ignored)) +func_get_name(PyObject *self, void *Py_UNUSED(ignored)) { + PyFunctionObject* op = _PyFunction_CAST(self); return Py_NewRef(op->func_name); } static int -func_set_name(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) +func_set_name(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) { + PyFunctionObject * op = _PyFunction_CAST(self); /* Not legal to del f.func_name or to set it to anything * other than a string object. */ if (value == NULL || !PyUnicode_Check(value)) { @@ -671,14 +676,16 @@ func_set_name(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) } static PyObject * -func_get_qualname(PyFunctionObject *op, void *Py_UNUSED(ignored)) +func_get_qualname(PyObject *self, void *Py_UNUSED(ignored)) { + PyFunctionObject *op = _PyFunction_CAST(self); return Py_NewRef(op->func_qualname); } static int -func_set_qualname(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) +func_set_qualname(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) { + PyFunctionObject *op = _PyFunction_CAST(self); /* Not legal to del f.__qualname__ or to set it to anything * other than a string object. */ if (value == NULL || !PyUnicode_Check(value)) { @@ -691,8 +698,9 @@ func_set_qualname(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored } static PyObject * -func_get_defaults(PyFunctionObject *op, void *Py_UNUSED(ignored)) +func_get_defaults(PyObject *self, void *Py_UNUSED(ignored)) { + PyFunctionObject * op = _PyFunction_CAST(self); if (PySys_Audit("object.__getattr__", "Os", op, "__defaults__") < 0) { return NULL; } @@ -703,8 +711,9 @@ func_get_defaults(PyFunctionObject *op, void *Py_UNUSED(ignored)) } static int -func_set_defaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) +func_set_defaults(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) { + PyFunctionObject *op = _PyFunction_CAST(self); /* Legal to del f.func_defaults. * Can only set func_defaults to NULL or a tuple. */ if (value == Py_None) @@ -731,8 +740,9 @@ func_set_defaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored } static PyObject * -func_get_kwdefaults(PyFunctionObject *op, void *Py_UNUSED(ignored)) +func_get_kwdefaults(PyObject *self, void *Py_UNUSED(ignored)) { + PyFunctionObject * op = _PyFunction_CAST(self); if (PySys_Audit("object.__getattr__", "Os", op, "__kwdefaults__") < 0) { return NULL; @@ -744,8 +754,9 @@ func_get_kwdefaults(PyFunctionObject *op, void *Py_UNUSED(ignored)) } static int -func_set_kwdefaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) +func_set_kwdefaults(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) { + PyFunctionObject* op = _PyFunction_CAST(self); if (value == Py_None) value = NULL; /* Legal to del f.func_kwdefaults. @@ -771,54 +782,6 @@ func_set_kwdefaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignor return 0; } -/*[clinic input] -@critical_section -@getter -function.__annotate__ - -Get the code object for a function. -[clinic start generated code]*/ - -static PyObject * -function___annotate___get_impl(PyFunctionObject *self) -/*[clinic end generated code: output=5ec7219ff2bda9e6 input=7f3db11e3c3329f3]*/ -{ - if (self->func_annotate == NULL) { - Py_RETURN_NONE; - } - return Py_NewRef(self->func_annotate); -} - -/*[clinic input] -@critical_section -@setter -function.__annotate__ -[clinic start generated code]*/ - -static int -function___annotate___set_impl(PyFunctionObject *self, PyObject *value) -/*[clinic end generated code: output=05b7dfc07ada66cd input=eb6225e358d97448]*/ -{ - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, - "__annotate__ cannot be deleted"); - return -1; - } - if (Py_IsNone(value)) { - Py_XSETREF(self->func_annotate, value); - return 0; - } - else if (PyCallable_Check(value)) { - Py_XSETREF(self->func_annotate, Py_XNewRef(value)); - Py_CLEAR(self->func_annotations); - return 0; - } - else { - PyErr_SetString(PyExc_TypeError, - "__annotate__ must be callable or None"); - return -1; - } -} /*[clinic input] @critical_section @@ -833,8 +796,7 @@ function___annotations___get_impl(PyFunctionObject *self) /*[clinic end generated code: output=a4cf4c884c934cbb input=92643d7186c1ad0c]*/ { PyObject *d = NULL; - if (self->func_annotations == NULL && - (self->func_annotate == NULL || !PyCallable_Check(self->func_annotate))) { + if (self->func_annotations == NULL) { self->func_annotations = PyDict_New(); if (self->func_annotations == NULL) return NULL; @@ -864,7 +826,6 @@ function___annotations___set_impl(PyFunctionObject *self, PyObject *value) return -1; } Py_XSETREF(self->func_annotations, Py_XNewRef(value)); - Py_CLEAR(self->func_annotate); return 0; } @@ -925,7 +886,6 @@ static PyGetSetDef func_getsetlist[] = { {"__defaults__", func_get_defaults, func_set_defaults}, {"__kwdefaults__", func_get_kwdefaults, func_set_kwdefaults}, FUNCTION___ANNOTATIONS___GETSETDEF - FUNCTION___ANNOTATE___GETSETDEF {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}, {"__name__", func_get_name, func_set_name}, {"__qualname__", func_get_qualname, func_set_qualname},