diff options
author | Petr Viktorin <encukou@gmail.com> | 2024-06-21 15:19:31 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-21 15:19:31 (GMT) |
commit | 6f1d448bc110633eda110310fd833bd46e7b30f2 (patch) | |
tree | 39555edee103339beea386042b7ffcbcd56ddcda /Python/clinic | |
parent | 7595e6743ac78ac0dd19418176f66d251668fafc (diff) | |
download | cpython-6f1d448bc110633eda110310fd833bd46e7b30f2.zip cpython-6f1d448bc110633eda110310fd833bd46e7b30f2.tar.gz cpython-6f1d448bc110633eda110310fd833bd46e7b30f2.tar.bz2 |
gh-113993: Allow interned strings to be mortal, and fix related issues (GH-120520)
* Add an InternalDocs file describing how interning should work and how to use it.
* Add internal functions to *explicitly* request what kind of interning is done:
- `_PyUnicode_InternMortal`
- `_PyUnicode_InternImmortal`
- `_PyUnicode_InternStatic`
* Switch uses of `PyUnicode_InternInPlace` to those.
* Disallow using `_Py_SetImmortal` on strings directly.
You should use `_PyUnicode_InternImmortal` instead:
- Strings should be interned before immortalization, otherwise you're possibly
interning a immortalizing copy.
- `_Py_SetImmortal` doesn't handle the `SSTATE_INTERNED_MORTAL` to
`SSTATE_INTERNED_IMMORTAL` update, and those flags can't be changed in
backports, as they are now part of public API and version-specific ABI.
* Add private `_only_immortal` argument for `sys.getunicodeinternedsize`, used in refleak test machinery.
* Make sure the statically allocated string singletons are unique. This means these sets are now disjoint:
- `_Py_ID`
- `_Py_STR` (including the empty string)
- one-character latin-1 singletons
Now, when you intern a singleton, that exact singleton will be interned.
* Add a `_Py_LATIN1_CHR` macro, use it instead of `_Py_ID`/`_Py_STR` for one-character latin-1 singletons everywhere (including Clinic).
* Intern `_Py_STR` singletons at startup.
* For free-threaded builds, intern `_Py_LATIN1_CHR` singletons at startup.
* Beef up the tests. Cover internal details (marked with `@cpython_only`).
* Add lots of assertions
Co-Authored-By: Eric Snow <ericsnowcurrently@gmail.com>
Diffstat (limited to 'Python/clinic')
-rw-r--r-- | Python/clinic/sysmodule.c.h | 52 |
1 files changed, 46 insertions, 6 deletions
diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index 56a831e..8277d28 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -968,24 +968,64 @@ exit: } PyDoc_STRVAR(sys_getunicodeinternedsize__doc__, -"getunicodeinternedsize($module, /)\n" +"getunicodeinternedsize($module, /, *, _only_immortal=False)\n" "--\n" "\n" "Return the number of elements of the unicode interned dictionary"); #define SYS_GETUNICODEINTERNEDSIZE_METHODDEF \ - {"getunicodeinternedsize", (PyCFunction)sys_getunicodeinternedsize, METH_NOARGS, sys_getunicodeinternedsize__doc__}, + {"getunicodeinternedsize", _PyCFunction_CAST(sys_getunicodeinternedsize), METH_FASTCALL|METH_KEYWORDS, sys_getunicodeinternedsize__doc__}, static Py_ssize_t -sys_getunicodeinternedsize_impl(PyObject *module); +sys_getunicodeinternedsize_impl(PyObject *module, int _only_immortal); static PyObject * -sys_getunicodeinternedsize(PyObject *module, PyObject *Py_UNUSED(ignored)) +sys_getunicodeinternedsize(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(_only_immortal), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"_only_immortal", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "getunicodeinternedsize", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + int _only_immortal = 0; Py_ssize_t _return_value; - _return_value = sys_getunicodeinternedsize_impl(module); + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_kwonly; + } + _only_immortal = PyObject_IsTrue(args[0]); + if (_only_immortal < 0) { + goto exit; + } +skip_optional_kwonly: + _return_value = sys_getunicodeinternedsize_impl(module, _only_immortal); if ((_return_value == -1) && PyErr_Occurred()) { goto exit; } @@ -1574,4 +1614,4 @@ exit: #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=ef7c35945443d300 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9cc9069aef1482bc input=a9049054013a1b77]*/ |