[Python-checkins] bpo-40170: PyObject_NEW() becomes an alias to PyObject_New() (GH-19379)

Victor Stinner webhook-mailer at python.org
Tue Apr 7 18:38:20 EDT 2020


https://github.com/python/cpython/commit/9205520d8c43488696d66cbdd9aefbb21871c508
commit: 9205520d8c43488696d66cbdd9aefbb21871c508
branch: master
author: Victor Stinner <vstinner at python.org>
committer: GitHub <noreply at github.com>
date: 2020-04-08T00:38:15+02:00
summary:

bpo-40170: PyObject_NEW() becomes an alias to PyObject_New() (GH-19379)

The PyObject_NEW() macro becomes an alias to the PyObject_New()
macro, and the PyObject_NEW_VAR() macro becomes an alias to the
PyObject_NewVar() macro, to hide implementation details. They no
longer access directly the PyTypeObject.tp_basicsize member.

Exclude _PyObject_SIZE() and _PyObject_VAR_SIZE() macros from
the limited C API.

Replace PyObject_NEW() with PyObject_New() and replace
PyObject_NEW_VAR() with PyObject_NewVar().

files:
A Misc/NEWS.d/next/C API/2020-04-05-00-37-34.bpo-40170.Seuh3D.rst
M Include/cpython/objimpl.h
M Include/objimpl.h
M Modules/_curses_panel.c
M Modules/_cursesmodule.c
M Modules/_sre.c
M Objects/capsule.c
M Objects/codeobject.c
M Objects/object.c
M PC/_msi.c
M PC/winreg.c

diff --git a/Include/cpython/objimpl.h b/Include/cpython/objimpl.h
index 2f802e92a6cdf..832622cb61921 100644
--- a/Include/cpython/objimpl.h
+++ b/Include/cpython/objimpl.h
@@ -6,6 +6,56 @@
 extern "C" {
 #endif
 
+#define _PyObject_SIZE(typeobj) ( (typeobj)->tp_basicsize )
+
+/* _PyObject_VAR_SIZE returns the number of bytes (as size_t) allocated for a
+   vrbl-size object with nitems items, exclusive of gc overhead (if any).  The
+   value is rounded up to the closest multiple of sizeof(void *), in order to
+   ensure that pointer fields at the end of the object are correctly aligned
+   for the platform (this is of special importance for subclasses of, e.g.,
+   str or int, so that pointers can be stored after the embedded data).
+
+   Note that there's no memory wastage in doing this, as malloc has to
+   return (at worst) pointer-aligned memory anyway.
+*/
+#if ((SIZEOF_VOID_P - 1) & SIZEOF_VOID_P) != 0
+#   error "_PyObject_VAR_SIZE requires SIZEOF_VOID_P be a power of 2"
+#endif
+
+#define _PyObject_VAR_SIZE(typeobj, nitems)     \
+    _Py_SIZE_ROUND_UP((typeobj)->tp_basicsize + \
+        (nitems)*(typeobj)->tp_itemsize,        \
+        SIZEOF_VOID_P)
+
+
+/* This example code implements an object constructor with a custom
+   allocator, where PyObject_New is inlined, and shows the important
+   distinction between two steps (at least):
+       1) the actual allocation of the object storage;
+       2) the initialization of the Python specific fields
+      in this storage with PyObject_{Init, InitVar}.
+
+   PyObject *
+   YourObject_New(...)
+   {
+       PyObject *op;
+
+       op = (PyObject *) Your_Allocator(_PyObject_SIZE(YourTypeStruct));
+       if (op == NULL)
+       return PyErr_NoMemory();
+
+       PyObject_Init(op, &YourTypeStruct);
+
+       op->ob_field = value;
+       ...
+       return op;
+   }
+
+   Note that in C++, the use of the new operator usually implies that
+   the 1st step is performed automatically for you, so in a C++ class
+   constructor you would start directly with PyObject_Init/InitVar. */
+
+
 /* Inline functions trading binary compatibility for speed:
    PyObject_INIT() is the fast version of PyObject_Init(), and
    PyObject_INIT_VAR() is the fast version of PyObject_InitVar().
diff --git a/Include/objimpl.h b/Include/objimpl.h
index 45919251f43a5..6e7549c90d210 100644
--- a/Include/objimpl.h
+++ b/Include/objimpl.h
@@ -122,12 +122,18 @@ PyAPI_FUNC(PyVarObject *) PyObject_InitVar(PyVarObject *,
 PyAPI_FUNC(PyObject *) _PyObject_New(PyTypeObject *);
 PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t);
 
-#define PyObject_New(type, typeobj) \
-                ( (type *) _PyObject_New(typeobj) )
+#define PyObject_New(type, typeobj) ((type *)_PyObject_New(typeobj))
+
+// Alias to PyObject_New(). In Python 3.8, PyObject_NEW() called directly
+// PyObject_MALLOC() with _PyObject_SIZE().
+#define PyObject_NEW(type, typeobj) PyObject_New(type, typeobj)
+
 #define PyObject_NewVar(type, typeobj, n) \
                 ( (type *) _PyObject_NewVar((typeobj), (n)) )
 
-#define _PyObject_SIZE(typeobj) ( (typeobj)->tp_basicsize )
+// Alias to PyObject_New(). In Python 3.8, PyObject_NEW() called directly
+// PyObject_MALLOC() with _PyObject_VAR_SIZE().
+#define PyObject_NEW_VAR(type, typeobj, n) PyObject_NewVar(type, typeobj, n)
 
 
 #ifdef Py_LIMITED_API
@@ -143,64 +149,6 @@ PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t);
 #endif
 
 
-/* _PyObject_VAR_SIZE returns the number of bytes (as size_t) allocated for a
-   vrbl-size object with nitems items, exclusive of gc overhead (if any).  The
-   value is rounded up to the closest multiple of sizeof(void *), in order to
-   ensure that pointer fields at the end of the object are correctly aligned
-   for the platform (this is of special importance for subclasses of, e.g.,
-   str or int, so that pointers can be stored after the embedded data).
-
-   Note that there's no memory wastage in doing this, as malloc has to
-   return (at worst) pointer-aligned memory anyway.
-*/
-#if ((SIZEOF_VOID_P - 1) & SIZEOF_VOID_P) != 0
-#   error "_PyObject_VAR_SIZE requires SIZEOF_VOID_P be a power of 2"
-#endif
-
-#define _PyObject_VAR_SIZE(typeobj, nitems)     \
-    _Py_SIZE_ROUND_UP((typeobj)->tp_basicsize + \
-        (nitems)*(typeobj)->tp_itemsize,        \
-        SIZEOF_VOID_P)
-
-#define PyObject_NEW(type, typeobj) \
-( (type *) PyObject_Init( \
-    (PyObject *) PyObject_MALLOC( _PyObject_SIZE(typeobj) ), (typeobj)) )
-
-#define PyObject_NEW_VAR(type, typeobj, n) \
-( (type *) PyObject_InitVar( \
-      (PyVarObject *) PyObject_MALLOC(_PyObject_VAR_SIZE((typeobj),(n)) ),\
-      (typeobj), (n)) )
-
-/* This example code implements an object constructor with a custom
-   allocator, where PyObject_New is inlined, and shows the important
-   distinction between two steps (at least):
-       1) the actual allocation of the object storage;
-       2) the initialization of the Python specific fields
-      in this storage with PyObject_{Init, InitVar}.
-
-   PyObject *
-   YourObject_New(...)
-   {
-       PyObject *op;
-
-       op = (PyObject *) Your_Allocator(_PyObject_SIZE(YourTypeStruct));
-       if (op == NULL)
-       return PyErr_NoMemory();
-
-       PyObject_Init(op, &YourTypeStruct);
-
-       op->ob_field = value;
-       ...
-       return op;
-   }
-
-   Note that in C++, the use of the new operator usually implies that
-   the 1st step is performed automatically for you, so in a C++ class
-   constructor you would start directly with PyObject_Init/InitVar
-*/
-
-
-
 /*
  * Garbage Collection Support
  * ==========================
diff --git a/Misc/NEWS.d/next/C API/2020-04-05-00-37-34.bpo-40170.Seuh3D.rst b/Misc/NEWS.d/next/C API/2020-04-05-00-37-34.bpo-40170.Seuh3D.rst
new file mode 100644
index 0000000000000..2c31cca7f7ecf
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2020-04-05-00-37-34.bpo-40170.Seuh3D.rst	
@@ -0,0 +1,4 @@
+The :c:func:`PyObject_NEW` macro becomes an alias to the :c:func:`PyObject_New`
+macro, and the :c:func:`PyObject_NEW_VAR` macro becomes an alias to the
+:c:func:`PyObject_NewVar` macro, to hide implementation details. They no longer
+access directly the :c:member:`PyTypeObject.tp_basicsize` member.
diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c
index 77a6a14ed20ab..7ca91f641617a 100644
--- a/Modules/_curses_panel.c
+++ b/Modules/_curses_panel.c
@@ -239,7 +239,7 @@ PyCursesPanel_New(PANEL *pan, PyCursesWindowObject *wo)
 {
     PyCursesPanelObject *po;
 
-    po = PyObject_NEW(PyCursesPanelObject,
+    po = PyObject_New(PyCursesPanelObject,
                       (PyTypeObject *)(_curses_panelstate_global)->PyCursesPanel_Type);
     if (po == NULL) return NULL;
     po->pan = pan;
diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c
index 3d16af7f0a34f..ca6a89f1dbeb3 100644
--- a/Modules/_cursesmodule.c
+++ b/Modules/_cursesmodule.c
@@ -547,7 +547,7 @@ PyCursesWindow_New(WINDOW *win, const char *encoding)
             encoding = "utf-8";
     }
 
-    wo = PyObject_NEW(PyCursesWindowObject, &PyCursesWindow_Type);
+    wo = PyObject_New(PyCursesWindowObject, &PyCursesWindow_Type);
     if (wo == NULL) return NULL;
     wo->win = win;
     wo->encoding = _PyMem_Strdup(encoding);
diff --git a/Modules/_sre.c b/Modules/_sre.c
index 52ed42099ba86..bee2e1284d68b 100644
--- a/Modules/_sre.c
+++ b/Modules/_sre.c
@@ -1338,7 +1338,7 @@ _sre_compile_impl(PyObject *module, PyObject *pattern, int flags,
 
     n = PyList_GET_SIZE(code);
     /* coverity[ampersand_in_size] */
-    self = PyObject_NEW_VAR(PatternObject, &Pattern_Type, n);
+    self = PyObject_NewVar(PatternObject, &Pattern_Type, n);
     if (!self)
         return NULL;
     self->weakreflist = NULL;
@@ -2327,8 +2327,8 @@ pattern_new_match(PatternObject* pattern, SRE_STATE* state, Py_ssize_t status)
 
         /* create match object (with room for extra group marks) */
         /* coverity[ampersand_in_size] */
-        match = PyObject_NEW_VAR(MatchObject, &Match_Type,
-                                 2*(pattern->groups+1));
+        match = PyObject_NewVar(MatchObject, &Match_Type,
+                                2*(pattern->groups+1));
         if (!match)
             return NULL;
 
@@ -2468,7 +2468,7 @@ pattern_scanner(PatternObject *self, PyObject *string, Py_ssize_t pos, Py_ssize_
     ScannerObject* scanner;
 
     /* create scanner object */
-    scanner = PyObject_NEW(ScannerObject, &Scanner_Type);
+    scanner = PyObject_New(ScannerObject, &Scanner_Type);
     if (!scanner)
         return NULL;
     scanner->pattern = NULL;
diff --git a/Objects/capsule.c b/Objects/capsule.c
index 599893a320dba..ed24cc1d6a2eb 100644
--- a/Objects/capsule.c
+++ b/Objects/capsule.c
@@ -50,7 +50,7 @@ PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor)
         return NULL;
     }
 
-    capsule = PyObject_NEW(PyCapsule, &PyCapsule_Type);
+    capsule = PyObject_New(PyCapsule, &PyCapsule_Type);
     if (capsule == NULL) {
         return NULL;
     }
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index fd64393c235c5..1820d8c8a5688 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -219,7 +219,7 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
             cell2arg = NULL;
         }
     }
-    co = PyObject_NEW(PyCodeObject, &PyCode_Type);
+    co = PyObject_New(PyCodeObject, &PyCode_Type);
     if (co == NULL) {
         if (cell2arg)
             PyMem_FREE(cell2arg);
diff --git a/Objects/object.c b/Objects/object.c
index 05241e8a740d1..069afc0ac9933 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -161,11 +161,12 @@ PyObject_InitVar(PyVarObject *op, PyTypeObject *tp, Py_ssize_t size)
 PyObject *
 _PyObject_New(PyTypeObject *tp)
 {
-    PyObject *op;
-    op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp));
-    if (op == NULL)
+    PyObject *op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp));
+    if (op == NULL) {
         return PyErr_NoMemory();
-    return PyObject_INIT(op, tp);
+    }
+    PyObject_INIT(op, tp);
+    return op;
 }
 
 PyVarObject *
diff --git a/PC/_msi.c b/PC/_msi.c
index accbe7a720694..6ed8724f77f95 100644
--- a/PC/_msi.c
+++ b/PC/_msi.c
@@ -531,7 +531,7 @@ static PyTypeObject record_Type = {
 static PyObject*
 record_new(MSIHANDLE h)
 {
-    msiobj *result = PyObject_NEW(struct msiobj, &record_Type);
+    msiobj *result = PyObject_New(struct msiobj, &record_Type);
 
     if (!result) {
         MsiCloseHandle(h);
@@ -882,7 +882,7 @@ msidb_openview(msiobj *msidb, PyObject *args)
     if ((status = MsiDatabaseOpenView(msidb->h, sql, &hView)) != ERROR_SUCCESS)
         return msierror(status);
 
-    result = PyObject_NEW(struct msiobj, &msiview_Type);
+    result = PyObject_New(struct msiobj, &msiview_Type);
     if (!result) {
         MsiCloseHandle(hView);
         return NULL;
@@ -918,7 +918,7 @@ msidb_getsummaryinformation(msiobj *db, PyObject *args)
     if (status != ERROR_SUCCESS)
         return msierror(status);
 
-    oresult = PyObject_NEW(struct msiobj, &summary_Type);
+    oresult = PyObject_New(struct msiobj, &summary_Type);
     if (!oresult) {
         MsiCloseHandle(result);
         return NULL;
@@ -1013,7 +1013,7 @@ static PyObject* msiopendb(PyObject *obj, PyObject *args)
     if (status != ERROR_SUCCESS)
         return msierror(status);
 
-    result = PyObject_NEW(struct msiobj, &msidb_Type);
+    result = PyObject_New(struct msiobj, &msidb_Type);
     if (!result) {
         MsiCloseHandle(h);
         return NULL;
diff --git a/PC/winreg.c b/PC/winreg.c
index 5dff7deadf767..ec2f607d4a818 100644
--- a/PC/winreg.c
+++ b/PC/winreg.c
@@ -390,7 +390,7 @@ PyTypeObject PyHKEY_Type =
 PyObject *
 PyHKEY_New(HKEY hInit)
 {
-    PyHKEYObject *key = PyObject_NEW(PyHKEYObject, &PyHKEY_Type);
+    PyHKEYObject *key = PyObject_New(PyHKEYObject, &PyHKEY_Type);
     if (key)
         key->hkey = hInit;
     return (PyObject *)key;



More information about the Python-checkins mailing list