classification
Title: PyType_FromSpec() should accept tp_doc=NULL
Type: Stage: resolved
Components: Interpreter Core Versions: Python 3.10
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: corona10, kj, petr.viktorin, shihai1991, vstinner
Priority: normal Keywords: patch

Created on 2020-09-22 10:29 by vstinner, last changed 2021-05-03 14:06 by kj. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 23123 merged shihai1991, 2020-11-03 12:44
PR 23243 merged shihai1991, 2020-11-12 04:39
PR 25852 closed kj, 2021-05-03 14:06
Messages (13)
msg377308 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-09-22 10:29
When a Python type is defined in a C extension module as a static type, its documentation can be a NULL string (NULL pointer). But PyType_FromSpec() does crash if tp_doc is NULL, since this change:

commit 032400b2d83ba1c2e4ee1cd33f51e9a598b2cf6c
Author: Georg Brandl <georg@python.org>
Date:   Sat Feb 19 21:47:02 2011 +0000

    #11249: in PyType_FromSpec, copy tp_doc slot since it usually will point to a static string literal which should not be deallocated together with the type.

(...)
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index e9c7591b81..b1fe44ebe4 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -2347,6 +2347,17 @@ PyObject* PyType_FromSpec(PyType_Spec *spec)
            goto fail;
        }
        *(void**)(res_start + slotoffsets[slot->slot]) = slot->pfunc;
+
+        /* need to make a copy of the docstring slot, which usually
+           points to a static string literal */
+        if (slot->slot == Py_tp_doc) {
+            ssize_t len = strlen(slot->pfunc)+1;
+            char *tp_doc = PyObject_MALLOC(len);
+            if (tp_doc == NULL)
+               goto fail;
+            memcpy(tp_doc, slot->pfunc, len);
+            res->ht_type.tp_doc = tp_doc;
+        }
     }
 
     return (PyObject*)res;


I propose to accept tp_doc=NULL in PyType_FromSpec(), as we do in static types.

I noticed this difference while reviewing PR 22220 which convert _lsprof extension static types to heap types.
msg380238 - (view) Author: hai shi (shihai1991) * (Python triager) Date: 2020-11-02 17:00
I will take a look in this weekend :)
msg380302 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2020-11-03 21:58
The PyType_Slot documentation says that the pointer may not be NULL: https://docs.python.org/3/c-api/type.html?highlight=pytype_fromspec#c.PyType_Slot.PyType_Slot.pfunc

If you change this, why do it only for tp_doc, but for all the slots? NULL should *always* mean that the slot is set to NULL instead of inherited. (Except maybe in cases where this is dangerous; then it should result in an error?)
See: https://bugs.python.org/issue26979

If you want to only change this for tp_doc, please also update the PyType_Slot documentation to cover the exception.
msg380316 - (view) Author: hai shi (shihai1991) * (Python triager) Date: 2020-11-04 12:07
> If you change this, why do it only for tp_doc, but for all the slots? NULL should *always* mean that the slot is set to NULL instead of inherited. (Except maybe in cases where this is dangerous; then it should result in an error?

IMO, it's a proper user case.
From bpo-26978: "I'll also try making an explicit `{Py_tp_dealloc, NULL}` override the inherited value, as per Serhiy's suggestion."
Petr, do you have a PR about it?

> If you want to only change this for tp_doc, please also update the PyType_Slot documentation to cover the exception.

Copy that, I will update it soon.
msg380452 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-11-06 16:04
New changeset 88c2cfd9ffbcfc43fd1364f2984852a819547d43 by Hai Shi in branch 'master':
bpo-41832: PyType_FromModuleAndSpec() now accepts NULL tp_doc (GH-23123)
https://github.com/python/cpython/commit/88c2cfd9ffbcfc43fd1364f2984852a819547d43
msg380453 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-11-06 16:05
Thanks Hai Shi.
msg380488 - (view) Author: hai shi (shihai1991) * (Python triager) Date: 2020-11-07 02:11
Thank you all:)
msg380709 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2020-11-10 20:20
The PR entirely removed the note that a slot's value "May not be NULL".
In fact, only tp_doc may be NULL. AFAIK, the restriction is still there for other slots.
Can that note be added back?
msg380767 - (view) Author: hai shi (shihai1991) * (Python triager) Date: 2020-11-11 15:13
> The PR entirely removed the note that a slot's value "May not be NULL".
> In fact, only tp_doc may be NULL. AFAIK, the restriction is still there > for other slots.
> Can that note be added back?

`May not be NULL` means everthing is possible, so I decided removed it:(
Before, I updated an old commit in PR23123 to describe this fact in https://github.com/python/cpython/pull/23123/commits/cca7bc7edf11a7d212ae70dcff6f10cf96fab470.
msg380779 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2020-11-11 17:43
> `May not be NULL` means everthing is possible

No, it does not. It only means a slot's value may not be NULL, which is an important difference between slots and entries in the PyTypeObject structure.

It's OK that it's mentioned elsewhere, but can we please put it back in the docs of PyType_Slot?
msg380976 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2020-11-14 12:03
New changeset 2b39da49974bda523c5c1a8777bbe30dbafdcd12 by Hai Shi in branch 'master':
bpo-41832: Restore note about NULL in PyType_Slot.pfunc (GH-23243)
https://github.com/python/cpython/commit/2b39da49974bda523c5c1a8777bbe30dbafdcd12
msg381006 - (view) Author: hai shi (shihai1991) * (Python triager) Date: 2020-11-15 09:09
Hi, petr. If there is no other doubt about this bpo, I suggest close this bpo.
msg381022 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-11-15 16:56
Sorry Petr, I didn't notice that the note was fully removed in the first change. Thanks for restoring the note!
History
Date User Action Args
2021-05-03 14:06:50kjsetnosy: + kj

pull_requests: + pull_request24535
2020-11-15 16:56:07vstinnersetmessages: + msg381022
2020-11-15 09:09:14shihai1991setstatus: open -> closed
stage: patch review -> resolved
2020-11-15 09:09:05shihai1991setmessages: + msg381006
2020-11-14 12:03:45petr.viktorinsetmessages: + msg380976
2020-11-12 04:39:39shihai1991setstage: resolved -> patch review
pull_requests: + pull_request22140
2020-11-11 17:43:58petr.viktorinsetmessages: + msg380779
2020-11-11 15:13:21shihai1991setmessages: + msg380767
2020-11-10 20:20:47petr.viktorinsetstatus: closed -> open

messages: + msg380709
2020-11-07 02:11:25shihai1991setmessages: + msg380488
2020-11-06 16:05:26vstinnersetstatus: open -> closed
resolution: fixed
messages: + msg380453

stage: patch review -> resolved
2020-11-06 16:04:59vstinnersetmessages: + msg380452
2020-11-04 12:07:31shihai1991setmessages: + msg380316
2020-11-03 21:58:50petr.viktorinsetnosy: + petr.viktorin
messages: + msg380302
2020-11-03 12:44:58shihai1991setkeywords: + patch
stage: patch review
pull_requests: + pull_request22039
2020-11-02 17:00:40shihai1991setmessages: + msg380238
2020-09-23 13:06:25corona10setnosy: + corona10
2020-09-22 14:55:19shihai1991setnosy: + shihai1991
2020-09-22 10:29:31vstinnercreate