-
-
Notifications
You must be signed in to change notification settings - Fork 30.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
C API: Add PyModule_Add() function #86493
Comments
There is a design flaw in PyModule_AddObject(). It steals reference of its value only if the result is success. To avoid leaks it should be used in the following form: PyObject *tmp = <new reference>;
if (PyModule_AddObject(name, name, tmp) < 0) {
Py_XDECREF(tmp);
goto error;
} It is inconvenient and many code forgot to use a temporary variable and call Py_XDECREF(). It was not intention, but it is too late to change this behavior now, because some code calls Py_XDECREF() if PyModule_AddObject() fails. Fixing PyModule_AddObject() now will break hard such code. There was an idea to make the change gradual, controlled by a special macro (see bpo-26871). But it still has significant risk. I propose to add new function PyModule_Add() which always steals reference to its argument. It is more convenient and allows to get rid of temporary variable: if (PyModule_Add(name, name, <new reference>) < 0) {
goto error;
} I choose name PyModule_Add because it is short, and allow to write the call in one line with moderately long expression <new reference> (like PyFloat_FromDouble(...) or PyLong_FromUnsignedLong(...)). |
See also: |
Oh, I just rejected PR 17298. Copy of my message: I also enhanced the documentation to show concrete examples: I modified a few extension to use PyModule_AddObjectRef(). Sometimes, PyModule_AddObject() is more appropriate. Sometimes, PyModule_AddObjectRef() is more appropriate. Both functions are relevant, and I don't see a clear winner. I agree than fixing existing code is painful, but I hope that new code using mostly PyModule_AddObjectRef() would be simpler to review. I'm not sure that it's simpler to write new code using PyModule_AddObjectRef(), since you might need more Py_DECREF() calls. My intent is to have more "regular" code about reference counting. See also: https://bugs.python.org/issue42294 Since you wrote that this API is a band aid on a broken API, I consider that you are fine with rejecting it and move on to the new PyModule_AddObjectRef(). Anyway, thanks for you attempt to make the C API less broken :-) I added PyModule_AddObjectRef() in bpo-163574. |
I'm using more and more often such macro: #define MOD_ADD(name, expr) \
do { \
PyObject *obj = (expr); \
if (obj == NULL) { \
return -1; \
} \
if (PyModule_AddObjectRef(mod, name, obj) < 0) { \
Py_DECREF(obj); \
return -1; \
} \
Py_DECREF(obj); \
} while (0) Would PyModule_Add() replace such macro? |
If PyModule_Add() is added, I would suggest to rename PyModule_AddObjectRef() to PyModule_AddRef() for consistency. IMHO PyModule_AddObjectRef() remains useful even if PyModule_Add() is added. |
In practice, PyModule_AddRef(mod, obj) behaves as PyModule_Add(mod, Py_NewRef(obj)) if I understood correctly. |
PyModule_Add() allows to make such macro much simpler: #define MOD_ADD(name, expr) \
do { \
if (PyModule_Add(mod, name, expr) < 0) { \
return -1; \
} \
} while (0) PyModule_AddObjectRef() is just Py_XINCREF() followed by PyModule_Add(). But since most values added to the module are new references, Py_XINCREF() is usually not needed. The PyModule_Add* API is a convenient API. It is not necessary, you can use PyModule_GetDict() + PyDict_SetItemString(), but with this API it is easier. And PyModule_Add() is a correct PyModule_AddObject() (which was broken a long time ago and cannot be fixed now) and is more convenient than PyModule_AddObjectRef(). PyModule_AddIntConstant() and PyModule_AddStringConstant() can be easily expressed in terms of PyModule_Add(): PyModule_Add(m, name, PyLong_FromLong(value))
PyModule_Add(m, name, PyUnicode_FromString(value)) And it is easy to combine it with other functions: PyLong_FromLongLong(), PyLong_FromUnsignedLong(), PyLong_FromVoidPtr(), PyFloat_FromDouble(), PyCapsule_New(), PyType_FromSpec(), etc. |
There is no general rule. I saw two main cases. (A) Create an object only to add it into the module. PyModule_Add() and PyModule_AddObject() are good for that case. Example in the array module: PyObject *typecodes = PyUnicode_DecodeASCII(buffer, p - buffer, NULL);
if (PyModule_AddObject(m, "typecodes", typecodes) < 0) {
Py_XDECREF(typecodes);
return -1;
} This code can be rewritten with PyModule_Add(): PyObject *typecodes = PyUnicode_DecodeASCII(buffer, p - buffer, NULL);
if (PyModule_Add(m, "typecodes", typecodes) < 0) {
return -1;
} Py_XDECREF(typecodes) is no longer needed using PyModule_Add(). (B) Add an existing object into the module, but the objet is already stored elsewhere. PyModule_AddObjectRef() is good for that case. It became common to have this case when an object is also stored in the module state. Example in _ast: state->AST_type = PyType_FromSpec(&AST_type_spec);
if (!state->AST_type) {
return 0;
}
(...)
if (PyModule_AddObjectRef(m, "AST", state->AST_type) < 0) {
return -1;
} state->AST_type and module attribute both hold a strong reference to the type. |
Note for myself: I added PyModule_AddObjectRef() to https://github.com/pythoncapi/pythoncapi_compat If it's renamed, pythoncapi_compat must also be updated. |
@serhiy-storchaka: So what's the status of this API? |
…_panel, _decimal, xxsubtype
…_panel, _decimal, posix, xxsubtype
Fix _ssl, _stat, _testinternalcapi, _threadmodule, cmath, math, posix, time.
Fix _ssl, _stat, _testinternalcapi, _threadmodule, cmath, math, posix, time.
I extracted some changes in two separate PRs: #106767 fixes some bugs by using |
…, _decimal, posix, xxsubtype (GH-106767)
…_curses_panel, _decimal, posix, xxsubtype (pythonGH-106767). (cherry picked from commit 7454923) Co-authored-by: Serhiy Storchaka <[email protected]>
…ation: _curses_panel, _decimal, posix, xxsubtype (pythonGH-106767) (pythonGH-106849) (cherry picked from commit 7454923). (cherry picked from commit 970cb8e) Co-authored-by: Serhiy Storchaka <[email protected]>
Fix _ssl, _stat, _testinternalcapi, _threadmodule, cmath, math, posix, time.
…ion (pythonGH-106768) Fix _ssl, _stat, _testinternalcapi, _threadmodule, cmath, math, posix, time.. (cherry picked from commit 3e65bae) Co-authored-by: Serhiy Storchaka <[email protected]>
Use PyModule_Add() or PyModule_AddObjectRef() instead of soft deprecated PyModule_AddObject().
…ialization (pythonGH-106768) (pythonGH-106855) Fix _ssl, _stat, _testinternalcapi, _threadmodule, cmath, math, posix, time. (cherry picked from commit 3e65bae). (cherry picked from commit a423ddb) Co-authored-by: Serhiy Storchaka <[email protected]>
Use PyModule_Add() or PyModule_AddObjectRef() instead of soft deprecated PyModule_AddObject().
Nice job, thanks. |
Use PyModule_Add() or PyModule_AddObjectRef() instead of soft deprecated PyModule_AddObject().
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
Linked PRs
The text was updated successfully, but these errors were encountered: