From 90ae263033c616efa907b5eafdb5814ae4e2060a Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 7 Sep 2019 07:53:13 -0700 Subject: [PATCH 1/7] Add a note to the PyModule_AddObject docs. --- Doc/c-api/module.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 68cbda2938f3f0..935be0ec633068 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -419,6 +419,21 @@ state: be used from the module's initialization function. This steals a reference to *value*. Return ``-1`` on error, ``0`` on success. + .. note:: + + Unlike other functions which steal references, ``PyModule_AddObject`` only + decrements the reference count of *value* **on success**. + + This means you must check this function's return value and + :c:func:`Py_DECREF` *value* manually on error. Example usage:: + + Py_INCREF(spam); + if (PyModule_AddObject(module, "spam", spam)) { + Py_DECREF(module); + Py_DECREF(spam); + return NULL; + } + .. c:function:: int PyModule_AddIntConstant(PyObject *module, const char *name, long value) Add an integer constant to *module* as *name*. This convenience function can be From 4b08887dac35a9afaf135de2f55d845547be1e7f Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 7 Sep 2019 08:20:22 -0700 Subject: [PATCH 2/7] Correct example usages of PyModule_AddObject. --- Doc/extending/extending.rst | 19 ++++++++++++++++--- Doc/extending/newtypes_tutorial.rst | 14 ++++++++++++-- Doc/includes/custom.c | 7 ++++++- Doc/includes/custom2.c | 7 ++++++- Doc/includes/custom3.c | 7 ++++++- Doc/includes/custom4.c | 7 ++++++- Doc/includes/sublist.c | 7 ++++++- 7 files changed, 58 insertions(+), 10 deletions(-) diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index e459514b2b5853..794387dc0e06c5 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -222,7 +222,11 @@ with an exception object (leaving out the error checking for now):: SpamError = PyErr_NewException("spam.error", NULL, NULL); Py_INCREF(SpamError); - PyModule_AddObject(m, "error", SpamError); + if (PyModule_AddObject(m, "error", SpamError)) { + Py_DECREF(SpamError); + Py_DECREF(m); + return NULL; + } return m; } @@ -1261,8 +1265,17 @@ function must take care of initializing the C API pointer array:: /* Create a Capsule containing the API pointer array's address */ c_api_object = PyCapsule_New((void *)PySpam_API, "spam._C_API", NULL); - if (c_api_object != NULL) - PyModule_AddObject(m, "_C_API", c_api_object); + if (c_api_object == NULL) { + Py_DECREF(m); + return NULL; + } + + if (PyModule_AddObject(m, "_C_API", c_api_object)) { + Py_DECREF(c_api_object); + Py_DECREF(m); + return NULL; + } + return m; } diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst index 59c8cc01222b2c..3bc841111a2ff4 100644 --- a/Doc/extending/newtypes_tutorial.rst +++ b/Doc/extending/newtypes_tutorial.rst @@ -179,7 +179,12 @@ This initializes the :class:`Custom` type, filling in a number of members to the appropriate default values, including :attr:`ob_type` that we initially set to *NULL*. :: - PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + Py_INCREF(&CustomType); + if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType)) { + Py_DECREF(&CustomType); + PY_DECREF(m); + return NULL; + } This adds the type to the module dictionary. This allows us to create :class:`Custom` instances by calling the :class:`Custom` class: @@ -864,7 +869,12 @@ function:: return NULL; Py_INCREF(&SubListType); - PyModule_AddObject(m, "SubList", (PyObject *) &SubListType); + if (PyModule_AddObject(m, "SubList", (PyObject *) &SubListType)) { + Py_DECREF(&SubListType); + Py_DECREF(m); + return NULL; + } + return m; } diff --git a/Doc/includes/custom.c b/Doc/includes/custom.c index 13d16f5424ae4d..c899412b0adcec 100644 --- a/Doc/includes/custom.c +++ b/Doc/includes/custom.c @@ -35,6 +35,11 @@ PyInit_custom(void) return NULL; Py_INCREF(&CustomType); - PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType)) { + Py_DECREF(&CustomType); + PY_DECREF(m); + return NULL; + } + return m; } diff --git a/Doc/includes/custom2.c b/Doc/includes/custom2.c index 6477a19dafed75..6df6623d12b0e5 100644 --- a/Doc/includes/custom2.c +++ b/Doc/includes/custom2.c @@ -128,6 +128,11 @@ PyInit_custom2(void) return NULL; Py_INCREF(&CustomType); - PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType)) { + Py_DECREF(&CustomType); + Py_DECREF(m); + return NULL; + } + return m; } diff --git a/Doc/includes/custom3.c b/Doc/includes/custom3.c index 213d0864ce1ca8..db1bcdb6b89726 100644 --- a/Doc/includes/custom3.c +++ b/Doc/includes/custom3.c @@ -179,6 +179,11 @@ PyInit_custom3(void) return NULL; Py_INCREF(&CustomType); - PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType)) { + Py_DECREF(&CustomType); + Py_DECREF(m); + return NULL; + } + return m; } diff --git a/Doc/includes/custom4.c b/Doc/includes/custom4.c index b0b2906dbdc863..cf1c87045e108c 100644 --- a/Doc/includes/custom4.c +++ b/Doc/includes/custom4.c @@ -193,6 +193,11 @@ PyInit_custom4(void) return NULL; Py_INCREF(&CustomType); - PyModule_AddObject(m, "Custom", (PyObject *) &CustomType); + if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType)) { + Py_DECREF(&CustomType); + Py_DECREF(m); + return NULL; + } + return m; } diff --git a/Doc/includes/sublist.c b/Doc/includes/sublist.c index 76ff93948cfd67..6855030956e783 100644 --- a/Doc/includes/sublist.c +++ b/Doc/includes/sublist.c @@ -59,6 +59,11 @@ PyInit_sublist(void) return NULL; Py_INCREF(&SubListType); - PyModule_AddObject(m, "SubList", (PyObject *) &SubListType); + if ((m, "SubList", (PyObject *) &SubListType)) { + Py_DECREF(&SubListType); + Py_DECREF(m); + return NULL; + } + return m; } From aef02b877a552f8b4d7a7f87f5b531f2c920aeb7 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 7 Sep 2019 08:42:29 -0700 Subject: [PATCH 3/7] Whitespace. --- Doc/extending/extending.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index 794387dc0e06c5..a16a5d17c6c046 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -227,6 +227,7 @@ with an exception object (leaving out the error checking for now):: Py_DECREF(m); return NULL; } + return m; } From 474a266df3a4c6ae69d4aecb549d6feac0113b5f Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 7 Sep 2019 08:50:36 -0700 Subject: [PATCH 4/7] Clean up wording. --- Doc/c-api/module.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 935be0ec633068..6afcfd9fbffa50 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -421,10 +421,10 @@ state: .. note:: - Unlike other functions which steal references, ``PyModule_AddObject`` only + Unlike other functions that steal references, ``PyModule_AddObject`` only decrements the reference count of *value* **on success**. - This means you must check this function's return value and + This means that its return value must be checked, and calling code must :c:func:`Py_DECREF` *value* manually on error. Example usage:: Py_INCREF(spam); From a0058237c63ccdb522bb9f4b2f8f8f1b7646828c Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 7 Sep 2019 15:55:50 +0000 Subject: [PATCH 5/7] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Documentation/2019-09-07-15-55-46.bpo-26868.Raw0Gd.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Documentation/2019-09-07-15-55-46.bpo-26868.Raw0Gd.rst diff --git a/Misc/NEWS.d/next/Documentation/2019-09-07-15-55-46.bpo-26868.Raw0Gd.rst b/Misc/NEWS.d/next/Documentation/2019-09-07-15-55-46.bpo-26868.Raw0Gd.rst new file mode 100644 index 00000000000000..c668092b41a663 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2019-09-07-15-55-46.bpo-26868.Raw0Gd.rst @@ -0,0 +1 @@ +Fix example usage of :c:func:`PyModule_AddObject` to properly handle errors. \ No newline at end of file From bb345d994148c7626ad19dd045045ce1469882b0 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Mon, 9 Sep 2019 08:57:47 -0700 Subject: [PATCH 6/7] First code review. --- Doc/c-api/module.rst | 6 +++--- Doc/extending/extending.rst | 14 +++++--------- Doc/includes/sublist.c | 2 +- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 6afcfd9fbffa50..feca1ec2a057ad 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -417,18 +417,18 @@ state: Add an object to *module* as *name*. This is a convenience function which can be used from the module's initialization function. This steals a reference to - *value*. Return ``-1`` on error, ``0`` on success. + *value* on success. Return ``-1`` on error, ``0`` on success. .. note:: - Unlike other functions that steal references, ``PyModule_AddObject`` only + Unlike other functions that steal references, ``PyModule_AddObject()`` only decrements the reference count of *value* **on success**. This means that its return value must be checked, and calling code must :c:func:`Py_DECREF` *value* manually on error. Example usage:: Py_INCREF(spam); - if (PyModule_AddObject(module, "spam", spam)) { + if (PyModule_AddObject(module, "spam", spam) < 0) { Py_DECREF(module); Py_DECREF(spam); return NULL; diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index a16a5d17c6c046..800acc04517a23 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -209,7 +209,7 @@ usually declare a static object variable at the beginning of your file:: static PyObject *SpamError; and initialize it in your module's initialization function (:c:func:`PyInit_spam`) -with an exception object (leaving out the error checking for now):: +with an exception object:: PyMODINIT_FUNC PyInit_spam(void) @@ -221,9 +221,10 @@ with an exception object (leaving out the error checking for now):: return NULL; SpamError = PyErr_NewException("spam.error", NULL, NULL); - Py_INCREF(SpamError); + Py_XINCREF(SpamError); if (PyModule_AddObject(m, "error", SpamError)) { - Py_DECREF(SpamError); + Py_XDECREF(SpamError); + Py_CLEAR(SpamError); Py_DECREF(m); return NULL; } @@ -1266,13 +1267,8 @@ function must take care of initializing the C API pointer array:: /* Create a Capsule containing the API pointer array's address */ c_api_object = PyCapsule_New((void *)PySpam_API, "spam._C_API", NULL); - if (c_api_object == NULL) { - Py_DECREF(m); - return NULL; - } - if (PyModule_AddObject(m, "_C_API", c_api_object)) { - Py_DECREF(c_api_object); + Py_XDECREF(c_api_object); Py_DECREF(m); return NULL; } diff --git a/Doc/includes/sublist.c b/Doc/includes/sublist.c index 6855030956e783..c837a82972e41a 100644 --- a/Doc/includes/sublist.c +++ b/Doc/includes/sublist.c @@ -59,7 +59,7 @@ PyInit_sublist(void) return NULL; Py_INCREF(&SubListType); - if ((m, "SubList", (PyObject *) &SubListType)) { + if (PyModule_AddObject(m, "SubList", (PyObject *) &SubListType)) { Py_DECREF(&SubListType); Py_DECREF(m); return NULL; From 37b6b37e6cab098c42cd461241fc491d7df7589e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 12 Sep 2019 13:42:41 +0200 Subject: [PATCH 7/7] Add < 0 in the tests with PyModule_AddObject --- Doc/extending/extending.rst | 4 ++-- Doc/extending/newtypes_tutorial.rst | 4 ++-- Doc/includes/custom.c | 2 +- Doc/includes/custom2.c | 2 +- Doc/includes/custom3.c | 2 +- Doc/includes/custom4.c | 2 +- Doc/includes/sublist.c | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index 800acc04517a23..5b4ea8220e237e 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -222,7 +222,7 @@ with an exception object:: SpamError = PyErr_NewException("spam.error", NULL, NULL); Py_XINCREF(SpamError); - if (PyModule_AddObject(m, "error", SpamError)) { + if (PyModule_AddObject(m, "error", SpamError) < 0) { Py_XDECREF(SpamError); Py_CLEAR(SpamError); Py_DECREF(m); @@ -1267,7 +1267,7 @@ function must take care of initializing the C API pointer array:: /* Create a Capsule containing the API pointer array's address */ c_api_object = PyCapsule_New((void *)PySpam_API, "spam._C_API", NULL); - if (PyModule_AddObject(m, "_C_API", c_api_object)) { + if (PyModule_AddObject(m, "_C_API", c_api_object) < 0) { Py_XDECREF(c_api_object); Py_DECREF(m); return NULL; diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst index 3bc841111a2ff4..94ca747c7aeb85 100644 --- a/Doc/extending/newtypes_tutorial.rst +++ b/Doc/extending/newtypes_tutorial.rst @@ -180,7 +180,7 @@ to the appropriate default values, including :attr:`ob_type` that we initially set to *NULL*. :: Py_INCREF(&CustomType); - if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType)) { + if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType) < 0) { Py_DECREF(&CustomType); PY_DECREF(m); return NULL; @@ -869,7 +869,7 @@ function:: return NULL; Py_INCREF(&SubListType); - if (PyModule_AddObject(m, "SubList", (PyObject *) &SubListType)) { + if (PyModule_AddObject(m, "SubList", (PyObject *) &SubListType) < 0) { Py_DECREF(&SubListType); Py_DECREF(m); return NULL; diff --git a/Doc/includes/custom.c b/Doc/includes/custom.c index c899412b0adcec..bda32e2ad81d46 100644 --- a/Doc/includes/custom.c +++ b/Doc/includes/custom.c @@ -35,7 +35,7 @@ PyInit_custom(void) return NULL; Py_INCREF(&CustomType); - if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType)) { + if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType) < 0) { Py_DECREF(&CustomType); PY_DECREF(m); return NULL; diff --git a/Doc/includes/custom2.c b/Doc/includes/custom2.c index 6df6623d12b0e5..5bacab7a2a9714 100644 --- a/Doc/includes/custom2.c +++ b/Doc/includes/custom2.c @@ -128,7 +128,7 @@ PyInit_custom2(void) return NULL; Py_INCREF(&CustomType); - if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType)) { + if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType) < 0) { Py_DECREF(&CustomType); Py_DECREF(m); return NULL; diff --git a/Doc/includes/custom3.c b/Doc/includes/custom3.c index db1bcdb6b89726..2b7a99ecf96c76 100644 --- a/Doc/includes/custom3.c +++ b/Doc/includes/custom3.c @@ -179,7 +179,7 @@ PyInit_custom3(void) return NULL; Py_INCREF(&CustomType); - if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType)) { + if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType) < 0) { Py_DECREF(&CustomType); Py_DECREF(m); return NULL; diff --git a/Doc/includes/custom4.c b/Doc/includes/custom4.c index cf1c87045e108c..584992fc5f1a8a 100644 --- a/Doc/includes/custom4.c +++ b/Doc/includes/custom4.c @@ -193,7 +193,7 @@ PyInit_custom4(void) return NULL; Py_INCREF(&CustomType); - if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType)) { + if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType) < 0) { Py_DECREF(&CustomType); Py_DECREF(m); return NULL; diff --git a/Doc/includes/sublist.c b/Doc/includes/sublist.c index c837a82972e41a..b2c26e73ebaf7e 100644 --- a/Doc/includes/sublist.c +++ b/Doc/includes/sublist.c @@ -59,7 +59,7 @@ PyInit_sublist(void) return NULL; Py_INCREF(&SubListType); - if (PyModule_AddObject(m, "SubList", (PyObject *) &SubListType)) { + if (PyModule_AddObject(m, "SubList", (PyObject *) &SubListType) < 0) { Py_DECREF(&SubListType); Py_DECREF(m); return NULL;