diff options
author | Victor Stinner <vstinner@python.org> | 2021-09-21 21:43:09 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-21 21:43:09 (GMT) |
commit | 86f28372b17c8c56539e9543bea9f125ab11b8aa (patch) | |
tree | 729bdf678008eeafa8934225c2f02c372d8586db /Objects | |
parent | 06e1773c8d8fe375423bb7fcf5922b49bc737b75 (diff) | |
download | cpython-86f28372b17c8c56539e9543bea9f125ab11b8aa.zip cpython-86f28372b17c8c56539e9543bea9f125ab11b8aa.tar.gz cpython-86f28372b17c8c56539e9543bea9f125ab11b8aa.tar.bz2 |
bpo-45061: Detect refcount bug on empty string singleton (GH-28504)
Detect refcount bugs in C extensions when the empty Unicode string
singleton is destroyed by mistake.
* Move forward declarations to the top of unicodeobject.c.
* Simplifiy unicode_is_singleton().
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/unicodeobject.c | 55 |
1 files changed, 37 insertions, 18 deletions
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 3e6b70b..9b0b869 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -48,6 +48,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "pycore_interp.h" // PyInterpreterState.fs_codec #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_pathconfig.h" // _Py_DumpPathConfig() +#include "pycore_pyerrors.h" // _Py_FatalRefcountError() #include "pycore_pylifecycle.h" // _Py_SetFileSystemEncoding() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI @@ -212,6 +213,24 @@ extern "C" { #endif +/* Forward declaration */ +static inline int +_PyUnicodeWriter_WriteCharInline(_PyUnicodeWriter *writer, Py_UCS4 ch); +static inline void +_PyUnicodeWriter_InitWithBuffer(_PyUnicodeWriter *writer, PyObject *buffer); +static PyObject * +unicode_encode_utf8(PyObject *unicode, _Py_error_handler error_handler, + const char *errors); +static PyObject * +unicode_decode_utf8(const char *s, Py_ssize_t size, + _Py_error_handler error_handler, const char *errors, + Py_ssize_t *consumed); +#ifdef Py_DEBUG +static inline int unicode_is_finalizing(void); +static int unicode_is_singleton(PyObject *unicode); +#endif + + static struct _Py_unicode_state* get_unicode_state(void) { @@ -279,19 +298,6 @@ unicode_fill(enum PyUnicode_Kind kind, void *data, Py_UCS4 value, } -/* Forward declaration */ -static inline int -_PyUnicodeWriter_WriteCharInline(_PyUnicodeWriter *writer, Py_UCS4 ch); -static inline void -_PyUnicodeWriter_InitWithBuffer(_PyUnicodeWriter *writer, PyObject *buffer); -static PyObject * -unicode_encode_utf8(PyObject *unicode, _Py_error_handler error_handler, - const char *errors); -static PyObject * -unicode_decode_utf8(const char *s, Py_ssize_t size, - _Py_error_handler error_handler, const char *errors, - Py_ssize_t *consumed); - /* Fast detection of the most frequent whitespace characters */ const unsigned char _Py_ascii_whitespace[] = { 0, 0, 0, 0, 0, 0, 0, 0, @@ -1930,6 +1936,12 @@ _PyUnicode_Ready(PyObject *unicode) static void unicode_dealloc(PyObject *unicode) { +#ifdef Py_DEBUG + if (!unicode_is_finalizing() && unicode_is_singleton(unicode)) { + _Py_FatalRefcountError("deallocating an Unicode singleton"); + } +#endif + switch (PyUnicode_CHECK_INTERNED(unicode)) { case SSTATE_NOT_INTERNED: break; @@ -1982,11 +1994,8 @@ unicode_is_singleton(PyObject *unicode) if (unicode == state->empty_string) { return 1; } - PyASCIIObject *ascii = (PyASCIIObject *)unicode; - if (ascii->state.kind != PyUnicode_WCHAR_KIND && ascii->length == 1) - { - Py_UCS4 ch = PyUnicode_READ_CHAR(unicode, 0); - if (ch < 256 && state->latin1[ch] == unicode) { + for (Py_ssize_t i = 0; i < 256; i++) { + if (unicode == state->latin1[i]) { return 1; } } @@ -15984,6 +15993,16 @@ _PyUnicode_EnableLegacyWindowsFSEncoding(void) #endif +#ifdef Py_DEBUG +static inline int +unicode_is_finalizing(void) +{ + struct _Py_unicode_state *state = get_unicode_state(); + return (state->interned == NULL); +} +#endif + + void _PyUnicode_Fini(PyInterpreterState *interp) { |