From 6965379a065ed29ea0dfed503bedbd49edfeb407 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 22 Mar 2017 17:09:44 +0100 Subject: [PATCH 1/3] bpo-29881: Add new C API for variables init once New C API for variables only initialized once to be able to clear them at exit: * New macro _PY_ONCEVAR_INIT(var, expr) to initialize a variable once * New function _PyOnceVar_Set() to explicitly set a variable once to initialize it * New _PyOnceVar_Fini() function clearing all variables (initialized once) at exit --- Include/object.h | 11 +++++++ Objects/object.c | 68 ++++++++++++++++++++++++++++++++++++++++++++ Python/pylifecycle.c | 7 +++++ 3 files changed, 86 insertions(+) diff --git a/Include/object.h b/Include/object.h index 63e37b8d33a68c..bc70d7779e781f 100644 --- a/Include/object.h +++ b/Include/object.h @@ -1071,6 +1071,17 @@ PyAPI_FUNC(void) _PyObject_DebugTypeStats(FILE *out); #endif /* ifndef Py_LIMITED_API */ +#ifndef Py_LIMITED_API +/* Don't this this function (implementation detail), but _PY_ONCEVAR_INIT() */ +PyAPI_FUNC(int) _PyOnceVar_Set(PyObject **var, PyObject *value); + +/* Initialized the variable 'var' with the expression 'expr'. + The variable is only initialized once: do nothing if *var is not NULL. + Return 0 on success, return -1 on failure. */ +#define _PY_ONCEVAR_INIT(var, expr) \ + ((var) == NULL ? _PyOnceVar_Set(&(var), (expr)) : 0) +#endif /* ifndef Py_LIMITED_API */ + #ifdef __cplusplus } #endif diff --git a/Objects/object.c b/Objects/object.c index 40061b1b3c175d..66267a7d840c6e 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2129,3 +2129,71 @@ _Py_Dealloc(PyObject *op) #ifdef __cplusplus } #endif + + +static struct { + PyObject ***array; + Py_ssize_t len; + Py_ssize_t alloc; +} once_variables = {NULL, 0, 0}; + +int +_PyOnceVar_Set(PyObject **var, PyObject *value) +{ + assert(var != NULL); + assert(*var == NULL); + + if (value == NULL) { + return -1; + } + + if (once_variables.len + 1 > once_variables.alloc) { + Py_ssize_t alloc, size; + + alloc = once_variables.len + 1; + /* Overallocate 1.5x and allocate at least 16 items + to reduce number of required realloc() */ + alloc = alloc * 3 / 2; + alloc = Py_MAX(alloc, 16); + if (alloc > PY_SSIZE_T_MAX / (Py_ssize_t)sizeof(PyObject *)) { + PyErr_NoMemory(); + goto error; + } + size = alloc * sizeof(once_variables.array[0]); + + PyObject ***array2 = PyMem_Realloc(once_variables.array, size); + if (array2 == NULL) { + PyErr_NoMemory(); + goto error; + } + once_variables.array = array2; + once_variables.alloc = alloc; + } + + *var = value; + once_variables.array[once_variables.len] = var; + once_variables.len++; + return 0; + +error: + Py_DECREF(value); + return -1; +} + +void +_PyOnceVar_Fini(void) +{ + PyObject ***array = once_variables.array; + Py_ssize_t len = once_variables.len; + + once_variables.array = NULL; + once_variables.len = 0; + once_variables.alloc = 0; + + /* clear variables in the reversed order of their initialization */ + for (Py_ssize_t i = len - 1; i >= 0; i--) { + PyObject **var = array[i]; + Py_CLEAR(*var); + } + PyMem_Free(array); +} diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index afd4eb8f55d7af..a1f107d5fdf262 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -62,6 +62,7 @@ static void call_ll_exitfuncs(void); extern int _PyUnicode_Init(void); extern int _PyStructSequence_Init(void); extern void _PyUnicode_Fini(void); +extern void _PyOnceVar_Fini(void); extern int _PyLong_Init(void); extern void PyLong_Fini(void); extern int _PyFaulthandler_Init(void); @@ -671,6 +672,9 @@ Py_FinalizeEx(void) /* Clear interpreter state and all thread states. */ PyInterpreterState_Clear(interp); + /* Clear private variables (first try) */ + _PyOnceVar_Fini(); + /* Now we decref the exception classes. After this point nothing can raise an exception. That's okay, because each Fini() method below has been checked to make sure no exceptions are ever @@ -700,6 +704,9 @@ Py_FinalizeEx(void) /* Cleanup Unicode implementation */ _PyUnicode_Fini(); + /* Clear private variables (second try) */ + _PyOnceVar_Fini(); + /* reset file system default encoding */ if (!Py_HasFileSystemDefaultEncoding && Py_FileSystemDefaultEncoding) { PyMem_RawFree((char*)Py_FileSystemDefaultEncoding); From 51de95aa31c37337a84afc9116193c7e9b31f552 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 23 Mar 2017 15:50:03 +0100 Subject: [PATCH 2/3] Remove _Py_Identifier.next and static_strings Rewrite _PyUnicode_FromId() using _PY_ONCEVAR_INIT(). --- Include/object.h | 5 ++--- Objects/typeobject.c | 12 ++++++------ Objects/unicodeobject.c | 30 +++--------------------------- 3 files changed, 11 insertions(+), 36 deletions(-) diff --git a/Include/object.h b/Include/object.h index bc70d7779e781f..8432bd59005dde 100644 --- a/Include/object.h +++ b/Include/object.h @@ -140,12 +140,11 @@ typedef struct { _PyObject_{Get,Set,Has}AttrId are __getattr__ versions using _Py_Identifier*. */ typedef struct _Py_Identifier { - struct _Py_Identifier *next; const char* string; PyObject *object; } _Py_Identifier; -#define _Py_static_string_init(value) { .next = NULL, .string = value, .object = NULL } +#define _Py_static_string_init(value) { .string = value, .object = NULL } #define _Py_static_string(varname, value) static _Py_Identifier varname = _Py_static_string_init(value) #define _Py_IDENTIFIER(varname) _Py_static_string(PyId_##varname, #varname) @@ -1072,7 +1071,7 @@ _PyObject_DebugTypeStats(FILE *out); #endif /* ifndef Py_LIMITED_API */ #ifndef Py_LIMITED_API -/* Don't this this function (implementation detail), but _PY_ONCEVAR_INIT() */ +/* Don't use this function directly, but _PY_ONCEVAR_INIT() */ PyAPI_FUNC(int) _PyOnceVar_Set(PyObject **var, PyObject *value); /* Initialized the variable 'var' with the expression 'expr'. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 64a72d2f146612..c7b45ed455e3ef 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6384,12 +6384,12 @@ slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value) } static _Py_Identifier name_op[] = { - {0, "__lt__", 0}, - {0, "__le__", 0}, - {0, "__eq__", 0}, - {0, "__ne__", 0}, - {0, "__gt__", 0}, - {0, "__ge__", 0} + {"__lt__", 0}, + {"__le__", 0}, + {"__eq__", 0}, + {"__ne__", 0}, + {"__gt__", 0}, + {"__ge__", 0} }; static PyObject * diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index d3a7f54d0e705b..4d73cd68408eb3 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -221,9 +221,6 @@ static PyObject *unicode_empty = NULL; static inline int _PyUnicodeWriter_WriteCharInline(_PyUnicodeWriter *writer, Py_UCS4 ch); -/* List of static strings. */ -static _Py_Identifier *static_strings = NULL; - /* Single character Unicode strings in the Latin-1 range are being shared as well. */ static PyObject *unicode_latin1[256] = {NULL}; @@ -2111,33 +2108,13 @@ PyUnicode_FromString(const char *u) PyObject * _PyUnicode_FromId(_Py_Identifier *id) { - if (!id->object) { - id->object = PyUnicode_DecodeUTF8Stateful(id->string, - strlen(id->string), - NULL, NULL); - if (!id->object) - return NULL; - PyUnicode_InternInPlace(&id->object); - assert(!id->next); - id->next = static_strings; - static_strings = id; + if (_PY_ONCEVAR_INIT(id->object, + PyUnicode_InternFromString(id->string))) { + return NULL; } return id->object; } -void -_PyUnicode_ClearStaticStrings() -{ - _Py_Identifier *tmp, *s = static_strings; - while (s) { - Py_CLEAR(s->object); - tmp = s->next; - s->next = NULL; - s = tmp; - } - static_strings = NULL; -} - /* Internal function, doesn't check maximum character */ PyObject* @@ -15246,7 +15223,6 @@ _PyUnicode_Fini(void) for (i = 0; i < 256; i++) Py_CLEAR(unicode_latin1[i]); - _PyUnicode_ClearStaticStrings(); (void)PyUnicode_ClearFreeList(); } From 31be490c680c5c91d8024b138db96f25c70bf363 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 23 Mar 2017 18:43:59 +0100 Subject: [PATCH 3/3] Use _PY_ONCEVAR_INIT() in modules --- Modules/_datetimemodule.c | 39 +++++++++++++-------- Modules/_io/bufferedio.c | 7 ++-- Modules/_json.c | 72 +++++++++++++++++++++++---------------- Modules/_ssl.c | 15 ++++---- Modules/_struct.c | 6 ++-- Modules/arraymodule.c | 25 ++++++++------ Modules/gcmodule.c | 6 ++-- Modules/posixmodule.c | 4 +-- Modules/zipimport.c | 7 ++-- Objects/boolobject.c | 20 +++++++---- Objects/codeobject.c | 14 +++----- Objects/exceptions.c | 14 +++----- Objects/funcobject.c | 6 ++-- Objects/listobject.c | 16 ++++----- Objects/typeobject.c | 11 +++--- Python/_warnings.c | 55 ++++++++++++------------------ Python/compile.c | 35 +++++++++---------- Python/import.c | 28 +++++++-------- Python/sysmodule.c | 15 +++----- 19 files changed, 193 insertions(+), 202 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 1803d85a7123f1..0f1b6b763408e5 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4445,10 +4445,8 @@ datetime_strptime(PyObject *cls, PyObject *args) if (!PyArg_ParseTuple(args, "UU:strptime", &string, &format)) return NULL; - if (module == NULL) { - module = PyImport_ImportModuleNoBlock("_strptime"); - if (module == NULL) - return NULL; + if (_PY_ONCEVAR_INIT(module, PyImport_ImportModule("_strptime"))) { + return NULL; } return _PyObject_CallMethodIdObjArgs(module, &PyId__strptime_datetime, cls, string, format, NULL); @@ -5839,23 +5837,34 @@ PyInit__datetime(void) Py_BUILD_ASSERT(DI100Y == 25 * DI4Y - 1); assert(DI100Y == days_before_year(100+1)); - one = PyLong_FromLong(1); - us_per_ms = PyLong_FromLong(1000); - us_per_second = PyLong_FromLong(1000000); - us_per_minute = PyLong_FromLong(60000000); - seconds_per_day = PyLong_FromLong(24 * 3600); - if (one == NULL || us_per_ms == NULL || us_per_second == NULL || - us_per_minute == NULL || seconds_per_day == NULL) + if (_PY_ONCEVAR_INIT(one, PyLong_FromLong(1))) { + return NULL; + } + if (_PY_ONCEVAR_INIT(us_per_ms, PyLong_FromLong(1000))) { + return NULL; + } + if (_PY_ONCEVAR_INIT(us_per_second, PyLong_FromLong(1000000))) { + return NULL; + } + if (_PY_ONCEVAR_INIT(us_per_minute , PyLong_FromLong(60000000))) { return NULL; + } + if (_PY_ONCEVAR_INIT(seconds_per_day, PyLong_FromLong(24 * 3600))) { + return NULL; + } /* The rest are too big for 32-bit ints, but even * us_per_week fits in 40 bits, so doubles should be exact. */ - us_per_hour = PyLong_FromDouble(3600000000.0); - us_per_day = PyLong_FromDouble(86400000000.0); - us_per_week = PyLong_FromDouble(604800000000.0); - if (us_per_hour == NULL || us_per_day == NULL || us_per_week == NULL) + if (_PY_ONCEVAR_INIT(us_per_hour, PyLong_FromDouble(3600000000.0))) { + return NULL; + } + if (_PY_ONCEVAR_INIT(us_per_day, PyLong_FromDouble(86400000000.0))) { + return NULL; + } + if (_PY_ONCEVAR_INIT(us_per_week, PyLong_FromDouble(604800000000.0))) { return NULL; + } return m; } diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 4f6dddb3a31054..db2967225135af 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -794,9 +794,10 @@ _PyIO_trap_eintr(void) PyObject *typ, *val, *tb; PyEnvironmentErrorObject *env_err; - if (eintr_int == NULL) { - eintr_int = PyLong_FromLong(EINTR); - assert(eintr_int != NULL); + if (_PY_ONCEVAR_INIT(eintr_int, PyLong_FromLong(EINTR))) { + /* ignore the exception! the function doesn't support + reporting a new error. */ + return 0; } if (!PyErr_ExceptionMatches(PyExc_EnvironmentError)) return 0; diff --git a/Modules/_json.c b/Modules/_json.c index 28fdc79834f731..62a7143880493b 100644 --- a/Modules/_json.c +++ b/Modules/_json.c @@ -68,10 +68,8 @@ join_list_unicode(PyObject *lst) { /* return u''.join(lst) */ static PyObject *sep = NULL; - if (sep == NULL) { - sep = PyUnicode_FromStringAndSize("", 0); - if (sep == NULL) - return NULL; + if (_PY_ONCEVAR_INIT(sep, PyUnicode_FromStringAndSize("", 0))) { + return NULL; } return PyUnicode_Join(sep, lst); } @@ -320,21 +318,28 @@ escape_unicode(PyObject *pystr) return rval; } +static PyObject* +get_json_decode_error(void) +{ + PyObject *decoder = PyImport_ImportModule("json.decoder"); + if (decoder == NULL) + return NULL; + + PyObject *err = PyObject_GetAttrString(decoder, "JSONDecodeError"); + Py_DECREF(decoder); + return err; +} + static void raise_errmsg(const char *msg, PyObject *s, Py_ssize_t end) { /* Use JSONDecodeError exception to raise a nice looking ValueError subclass */ static PyObject *JSONDecodeError = NULL; PyObject *exc; - if (JSONDecodeError == NULL) { - PyObject *decoder = PyImport_ImportModule("json.decoder"); - if (decoder == NULL) - return; - JSONDecodeError = PyObject_GetAttrString(decoder, "JSONDecodeError"); - Py_DECREF(decoder); - if (JSONDecodeError == NULL) - return; + if (_PY_ONCEVAR_INIT(JSONDecodeError, get_json_decode_error())) { + return; } + exc = PyObject_CallFunction(JSONDecodeError, "zOn", msg, s, end); if (exc) { PyErr_SetObject(JSONDecodeError, exc); @@ -1413,24 +1418,27 @@ _encoded_const(PyObject *obj) /* Return the JSON string representation of None, True, False */ if (obj == Py_None) { static PyObject *s_null = NULL; - if (s_null == NULL) { - s_null = PyUnicode_InternFromString("null"); + if (_PY_ONCEVAR_INIT(s_null, + PyUnicode_InternFromString("null"))) { + return NULL; } Py_INCREF(s_null); return s_null; } else if (obj == Py_True) { static PyObject *s_true = NULL; - if (s_true == NULL) { - s_true = PyUnicode_InternFromString("true"); + if (_PY_ONCEVAR_INIT(s_true, + PyUnicode_InternFromString("true"))) { + return NULL; } Py_INCREF(s_true); return s_true; } else if (obj == Py_False) { static PyObject *s_false = NULL; - if (s_false == NULL) { - s_false = PyUnicode_InternFromString("false"); + if (_PY_ONCEVAR_INIT(s_false, + PyUnicode_InternFromString("false"))) { + return NULL; } Py_INCREF(s_false); return s_false; @@ -1599,12 +1607,14 @@ encoder_listencode_dict(PyEncoderObject *s, _PyAccu *acc, int sortkeys; Py_ssize_t idx; - if (open_dict == NULL || close_dict == NULL || empty_dict == NULL) { - open_dict = PyUnicode_InternFromString("{"); - close_dict = PyUnicode_InternFromString("}"); - empty_dict = PyUnicode_InternFromString("{}"); - if (open_dict == NULL || close_dict == NULL || empty_dict == NULL) - return -1; + if (_PY_ONCEVAR_INIT(open_dict, PyUnicode_InternFromString("{"))) { + return -1; + } + if (_PY_ONCEVAR_INIT(close_dict, PyUnicode_InternFromString("}"))) { + return -1; + } + if (_PY_ONCEVAR_INIT(empty_dict, PyUnicode_InternFromString("{}"))) { + return -1; } if (PyDict_GET_SIZE(dct) == 0) /* Fast path */ return _PyAccu_Accumulate(acc, empty_dict); @@ -1754,12 +1764,14 @@ encoder_listencode_list(PyEncoderObject *s, _PyAccu *acc, PyObject *s_fast = NULL; Py_ssize_t i; - if (open_array == NULL || close_array == NULL || empty_array == NULL) { - open_array = PyUnicode_InternFromString("["); - close_array = PyUnicode_InternFromString("]"); - empty_array = PyUnicode_InternFromString("[]"); - if (open_array == NULL || close_array == NULL || empty_array == NULL) - return -1; + if (_PY_ONCEVAR_INIT(open_array, PyUnicode_InternFromString("["))) { + return -1; + } + if (_PY_ONCEVAR_INIT(close_array, PyUnicode_InternFromString("]"))) { + return -1; + } + if (_PY_ONCEVAR_INIT(empty_array, PyUnicode_InternFromString("[]"))) { + return -1; } ident = NULL; s_fast = PySequence_Fast(seq, "_iterencode_list needs a sequence"); diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 421e0b671667e1..49e79b6136a0ea 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -4756,16 +4756,15 @@ certEncodingType(DWORD encodingType) static PyObject *x509_asn = NULL; static PyObject *pkcs_7_asn = NULL; - if (x509_asn == NULL) { - x509_asn = PyUnicode_InternFromString("x509_asn"); - if (x509_asn == NULL) - return NULL; + if (_PY_ONCEVAR_INIT(x509_asn, + PyUnicode_InternFromString("x509_asn"))) { + return NULL; } - if (pkcs_7_asn == NULL) { - pkcs_7_asn = PyUnicode_InternFromString("pkcs_7_asn"); - if (pkcs_7_asn == NULL) - return NULL; + if (_PY_ONCEVAR_INIT(pkcs_7_asn, + PyUnicode_InternFromString("pkcs_7_asn"))) { + return NULL; } + switch(encodingType) { case X509_ASN_ENCODING: Py_INCREF(x509_asn); diff --git a/Modules/_struct.c b/Modules/_struct.c index f66ee18bc49fd6..2b3b3a21c48657 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -2060,10 +2060,8 @@ cache_struct_converter(PyObject *fmt, PyObject **ptr) return 1; } - if (cache == NULL) { - cache = PyDict_New(); - if (cache == NULL) - return 0; + if (_PY_ONCEVAR_INIT(cache, PyDict_New())) { + return 0; } s_object = PyDict_GetItem(cache, fmt); diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index b30f7594c25a24..bb57ab27921b3e 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -2106,6 +2106,18 @@ array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype, return result; } +static PyObject* +get_array_reconstructor(void) +{ + PyObject *array_module = PyImport_ImportModule("array"); + if (array_module == NULL) + return NULL; + + PyObject *meth = PyObject_GetAttrString(array_module, "_array_reconstructor"); + Py_DECREF(array_module); + return meth; +} + /*[clinic input] array.array.__reduce_ex__ @@ -2126,19 +2138,10 @@ array_array___reduce_ex__(arrayobject *self, PyObject *value) int mformat_code; static PyObject *array_reconstructor = NULL; long protocol; - _Py_IDENTIFIER(_array_reconstructor); _Py_IDENTIFIER(__dict__); - if (array_reconstructor == NULL) { - PyObject *array_module = PyImport_ImportModule("array"); - if (array_module == NULL) - return NULL; - array_reconstructor = _PyObject_GetAttrId( - array_module, - &PyId__array_reconstructor); - Py_DECREF(array_module); - if (array_reconstructor == NULL) - return NULL; + if (_PY_ONCEVAR_INIT(array_reconstructor, get_array_reconstructor())) { + return NULL; } if (!PyLong_Check(value)) { diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 4e5acf305b9f4b..ae1580bd32ff00 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1065,8 +1065,10 @@ collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable, PyErr_Clear(); } else { - if (gc_str == NULL) - gc_str = PyUnicode_FromString("garbage collection"); + /* if PyUnicode_FromString() fails: pass NULL + to PyErr_WriteUnraisable() */ + (void)_PY_ONCEVAR_INIT(gc_str, + PyUnicode_FromString("garbage collection")); PyErr_WriteUnraisable(gc_str); Py_FatalError("unexpected exception during garbage collection"); } diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 0ae06eb53eaef9..693e0aeb5f8181 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -13077,9 +13077,9 @@ INITFUNC(void) Py_INCREF(&TerminalSizeType); PyModule_AddObject(m, "terminal_size", (PyObject*) &TerminalSizeType); - billion = PyLong_FromLong(1000000000); - if (!billion) + if (_PY_ONCEVAR_INIT(billion, PyLong_FromLong(1000000000))) { return NULL; + } /* suppress "function not used" warnings */ { diff --git a/Modules/zipimport.c b/Modules/zipimport.c index a74f6c7da993e5..65a5b513d36602 100644 --- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -1574,9 +1574,10 @@ PyInit_zipimport(void) (PyObject *)&ZipImporter_Type) < 0) return NULL; - zip_directory_cache = PyDict_New(); - if (zip_directory_cache == NULL) - return NULL; + if (_PY_ONCEVAR_INIT(zip_directory_cache, PyDict_New())) { + return 0; + } + Py_INCREF(zip_directory_cache); if (PyModule_AddObject(mod, "_zip_directory_cache", zip_directory_cache) < 0) diff --git a/Objects/boolobject.c b/Objects/boolobject.c index becdfcbbb47723..ecdb39e85cedbc 100644 --- a/Objects/boolobject.c +++ b/Objects/boolobject.c @@ -13,13 +13,19 @@ bool_repr(PyObject *self) { PyObject *s; - if (self == Py_True) - s = true_str ? true_str : - (true_str = PyUnicode_InternFromString("True")); - else - s = false_str ? false_str : - (false_str = PyUnicode_InternFromString("False")); - Py_XINCREF(s); + if (self == Py_True) { + if (_PY_ONCEVAR_INIT(true_str, PyUnicode_InternFromString("True"))) { + return NULL; + } + s = true_str; + } + else { + if (_PY_ONCEVAR_INIT(false_str, PyUnicode_InternFromString("False"))) { + return NULL; + } + s = false_str; + } + Py_INCREF(s); return s; } diff --git a/Objects/codeobject.c b/Objects/codeobject.c index ebc70669fecb61..18ad4272789572 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -217,15 +217,11 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno) PyObject *filename_ob = NULL; PyObject *funcname_ob = NULL; PyCodeObject *result = NULL; - if (emptystring == NULL) { - emptystring = PyBytes_FromString(""); - if (emptystring == NULL) - goto failed; - } - if (nulltuple == NULL) { - nulltuple = PyTuple_New(0); - if (nulltuple == NULL) - goto failed; + if (_PY_ONCEVAR_INIT(emptystring, PyBytes_FromString(""))) { + goto failed; + } + if (_PY_ONCEVAR_INIT(nulltuple, PyTuple_New(0))) { + goto failed; } funcname_ob = PyUnicode_FromString(funcname); if (funcname_ob == NULL) diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 35a8b66e01265f..43d144f06be537 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -2843,11 +2843,8 @@ _check_for_legacy_statements(PySyntaxErrorObject *self, Py_ssize_t start) } /* Check for legacy print statements */ - if (print_prefix == NULL) { - print_prefix = PyUnicode_InternFromString("print "); - if (print_prefix == NULL) { - return -1; - } + if (_PY_ONCEVAR_INIT(print_prefix, PyUnicode_InternFromString("print "))) { + return -1; } if (PyUnicode_Tailmatch(self->text, print_prefix, start, text_len, -1)) { @@ -2857,11 +2854,8 @@ _check_for_legacy_statements(PySyntaxErrorObject *self, Py_ssize_t start) } /* Check for legacy exec statements */ - if (exec_prefix == NULL) { - exec_prefix = PyUnicode_InternFromString("exec "); - if (exec_prefix == NULL) { - return -1; - } + if (_PY_ONCEVAR_INIT(exec_prefix, PyUnicode_InternFromString("exec "))) { + return -1; } if (PyUnicode_Tailmatch(self->text, exec_prefix, start, text_len, -1)) { diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 841000152f79a6..41568e2f988bb5 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -12,10 +12,8 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname PyObject *doc, *consts, *module; static PyObject *__name__ = NULL; - if (__name__ == NULL) { - __name__ = PyUnicode_InternFromString("__name__"); - if (__name__ == NULL) - return NULL; + if (_PY_ONCEVAR_INIT(__name__, PyUnicode_InternFromString("__name__"))) { + return NULL; } op = PyObject_GC_New(PyFunctionObject, &PyFunction_Type); diff --git a/Objects/listobject.c b/Objects/listobject.c index 9b42106e30b064..60edfba0334f8e 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -205,11 +205,9 @@ PyList_GetItem(PyObject *op, Py_ssize_t i) return NULL; } if (i < 0 || i >= Py_SIZE(op)) { - if (indexerr == NULL) { - indexerr = PyUnicode_FromString( - "list index out of range"); - if (indexerr == NULL) - return NULL; + if (_PY_ONCEVAR_INIT(indexerr, + PyUnicode_FromString("list index out of range"))) { + return NULL; } PyErr_SetObject(PyExc_IndexError, indexerr); return NULL; @@ -417,11 +415,9 @@ static PyObject * list_item(PyListObject *a, Py_ssize_t i) { if (i < 0 || i >= Py_SIZE(a)) { - if (indexerr == NULL) { - indexerr = PyUnicode_FromString( - "list index out of range"); - if (indexerr == NULL) - return NULL; + if (_PY_ONCEVAR_INIT(indexerr, + PyUnicode_FromString("list index out of range"))) { + return NULL; } PyErr_SetObject(PyExc_IndexError, indexerr); return NULL; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index c7b45ed455e3ef..e93c8bcb938db4 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4419,15 +4419,14 @@ static PyObject * object___reduce_ex___impl(PyObject *self, int protocol) /*[clinic end generated code: output=2e157766f6b50094 input=8dd6a9602a12749e]*/ { - static PyObject *objreduce; + static PyObject *objreduce = NULL; PyObject *reduce, *res; _Py_IDENTIFIER(__reduce__); - if (objreduce == NULL) { - objreduce = _PyDict_GetItemId(PyBaseObject_Type.tp_dict, - &PyId___reduce__); - if (objreduce == NULL) - return NULL; + if (_PY_ONCEVAR_INIT(objreduce, + _PyDict_GetItemId(PyBaseObject_Type.tp_dict, + &PyId___reduce__))) { + return NULL; } reduce = _PyObject_GetAttrId(self, &PyId___reduce__); diff --git a/Python/_warnings.c b/Python/_warnings.c index 67f4c6bbe023be..c3963640b74da4 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -47,10 +47,9 @@ get_warnings_attr(const char *attr, int try_import) PyObject *all_modules; PyObject *warnings_module, *obj; - if (warnings_str == NULL) { - warnings_str = PyUnicode_InternFromString("warnings"); - if (warnings_str == NULL) - return NULL; + if (_PY_ONCEVAR_INIT(warnings_str, + PyUnicode_InternFromString("warnings"))) { + return NULL; } /* don't try to import after the start of the Python finallization */ @@ -576,19 +575,13 @@ is_internal_frame(PyFrameObject *frame) PyObject *filename; int contains; - if (importlib_string == NULL) { - importlib_string = PyUnicode_FromString("importlib"); - if (importlib_string == NULL) { - return 0; - } - - bootstrap_string = PyUnicode_FromString("_bootstrap"); - if (bootstrap_string == NULL) { - Py_DECREF(importlib_string); - return 0; - } - Py_INCREF(importlib_string); - Py_INCREF(bootstrap_string); + if (_PY_ONCEVAR_INIT(importlib_string, + PyUnicode_FromString("importlib"))) { + return 0; + } + if (_PY_ONCEVAR_INIT(bootstrap_string, + PyUnicode_FromString("_bootstrap"))) { + return 0; } if (frame == NULL || frame->f_code == NULL || @@ -1133,34 +1126,30 @@ create_filter(PyObject *category, const char *action) PyObject *lineno, *result; if (!strcmp(action, "ignore")) { - if (ignore_str == NULL) { - ignore_str = PyUnicode_InternFromString("ignore"); - if (ignore_str == NULL) - return NULL; + if (_PY_ONCEVAR_INIT(ignore_str, + PyUnicode_InternFromString("ignore"))) { + return NULL; } action_obj = ignore_str; } else if (!strcmp(action, "error")) { - if (error_str == NULL) { - error_str = PyUnicode_InternFromString("error"); - if (error_str == NULL) - return NULL; + if (_PY_ONCEVAR_INIT(error_str, + PyUnicode_InternFromString("error"))) { + return NULL; } action_obj = error_str; } else if (!strcmp(action, "default")) { - if (default_str == NULL) { - default_str = PyUnicode_InternFromString("default"); - if (default_str == NULL) - return NULL; + if (_PY_ONCEVAR_INIT(default_str, + PyUnicode_InternFromString("default"))) { + return NULL; } action_obj = default_str; } else if (!strcmp(action, "always")) { - if (always_str == NULL) { - always_str = PyUnicode_InternFromString("always"); - if (always_str == NULL) - return NULL; + if (_PY_ONCEVAR_INIT(always_str, + PyUnicode_InternFromString("always"))) { + return NULL; } action_obj = always_str; } diff --git a/Python/compile.c b/Python/compile.c index 064364ea28cb11..17bc150c269aa0 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -213,7 +213,7 @@ static int compiler_async_comprehension_generator( expr_ty elt, expr_ty val, int type); static PyCodeObject *assemble(struct compiler *, int addNone); -static PyObject *__doc__; +static PyObject *__doc__ = NULL; #define CAPSULE_NAME "compile.c compiler unit" @@ -306,10 +306,8 @@ PyAST_CompileObject(mod_ty mod, PyObject *filename, PyCompilerFlags *flags, PyCompilerFlags local_flags; int merged; - if (!__doc__) { - __doc__ = PyUnicode_InternFromString("__doc__"); - if (!__doc__) - return NULL; + if (_PY_ONCEVAR_INIT(__doc__, PyUnicode_InternFromString("__doc__"))) { + return NULL; } if (!compiler_init(&c)) @@ -1452,12 +1450,12 @@ compiler_mod(struct compiler *c, mod_ty mod) { PyCodeObject *co; int addNone = 1; - static PyObject *module; - if (!module) { - module = PyUnicode_InternFromString(""); - if (!module) - return NULL; + static PyObject *module = NULL; + + if (_PY_ONCEVAR_INIT(module, PyUnicode_InternFromString(""))) { + return NULL; } + /* Use 0 for firstlineno initially, will fixup in assemble(). */ if (!compiler_enter_scope(c, module, COMPILER_SCOPE_MODULE, mod, 0)) return NULL; @@ -2639,12 +2637,10 @@ compiler_from_import(struct compiler *c, stmt_ty s) PyObject *names = PyTuple_New(n); PyObject *level; - static PyObject *empty_string; + static PyObject *empty_string = NULL; - if (!empty_string) { - empty_string = PyUnicode_FromString(""); - if (!empty_string) - return 0; + if (_PY_ONCEVAR_INIT(empty_string, PyUnicode_FromString(""))) { + return 0; } if (!names) @@ -2715,11 +2711,12 @@ compiler_assert(struct compiler *c, stmt_ty s) if (c->c_optimize) return 1; - if (assertion_error == NULL) { - assertion_error = PyUnicode_InternFromString("AssertionError"); - if (assertion_error == NULL) - return 0; + + if (_PY_ONCEVAR_INIT(assertion_error, + PyUnicode_InternFromString("AssertionError"))) { + return 0; } + if (s->v.Assert.test->kind == Tuple_kind && asdl_seq_LEN(s->v.Assert.test->v.Tuple.elts) > 0) { msg = PyUnicode_FromString("assertion is always true, " diff --git a/Python/import.c b/Python/import.c index 0fc4d1da547459..79204593c96246 100644 --- a/Python/import.c +++ b/Python/import.c @@ -29,7 +29,6 @@ extern struct _inittab _PyImport_Inittab[]; struct _inittab *PyImport_Inittab = _PyImport_Inittab; -static PyObject *initstr = NULL; /*[clinic input] module _imp @@ -44,9 +43,6 @@ void _PyImport_Init(void) { PyInterpreterState *interp = PyThreadState_Get()->interp; - initstr = PyUnicode_InternFromString("__init__"); - if (initstr == NULL) - Py_FatalError("Can't initialize import variables"); interp->builtins_copy = PyDict_Copy(interp->builtins); if (interp->builtins_copy == NULL) Py_FatalError("Can't backup builtins dict"); @@ -1721,7 +1717,7 @@ PyImport_ReloadModule(PyObject *m) PyObject * PyImport_Import(PyObject *module_name) { - static PyObject *silly_list = NULL; + static PyObject *empty_list = NULL; static PyObject *builtins_str = NULL; static PyObject *import_str = NULL; PyObject *globals = NULL; @@ -1731,16 +1727,16 @@ PyImport_Import(PyObject *module_name) PyObject *r = NULL; /* Initialize constant string objects */ - if (silly_list == NULL) { - import_str = PyUnicode_InternFromString("__import__"); - if (import_str == NULL) - return NULL; - builtins_str = PyUnicode_InternFromString("__builtins__"); - if (builtins_str == NULL) - return NULL; - silly_list = PyList_New(0); - if (silly_list == NULL) - return NULL; + if (_PY_ONCEVAR_INIT(empty_list, PyList_New(0))) { + return NULL; + } + if (_PY_ONCEVAR_INIT(builtins_str, + PyUnicode_InternFromString("__builtins__"))) { + return NULL; + } + if (_PY_ONCEVAR_INIT(import_str, + PyUnicode_InternFromString("__import__"))) { + return NULL; } /* Get the builtins from current globals */ @@ -1777,7 +1773,7 @@ PyImport_Import(PyObject *module_name) Always use absolute import here. Calling for side-effect of import. */ r = PyObject_CallFunction(import, "OOOOi", module_name, globals, - globals, silly_list, 0, NULL); + globals, empty_list, 0, NULL); if (r == NULL) goto err; Py_DECREF(r); diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 2da77025b01497..4b0645430ffc50 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -197,10 +197,8 @@ sys_displayhook(PyObject *self, PyObject *o) return NULL; } } - if (newline == NULL) { - newline = PyUnicode_FromString("\n"); - if (newline == NULL) - return NULL; + if (_PY_ONCEVAR_INIT(newline, PyUnicode_FromString("\n"))) { + return NULL; } if (PyFile_WriteObject(newline, outf, Py_PRINT_RAW) != 0) return NULL; @@ -360,14 +358,11 @@ trace_init(void) "call", "exception", "line", "return", "c_call", "c_exception", "c_return" }; - PyObject *name; int i; for (i = 0; i < 7; ++i) { - if (whatstrings[i] == NULL) { - name = PyUnicode_InternFromString(whatnames[i]); - if (name == NULL) - return -1; - whatstrings[i] = name; + if (_PY_ONCEVAR_INIT(whatstrings[i], + PyUnicode_InternFromString(whatnames[i]))) { + return -1; } } return 0;