diff --git a/Include/object.h b/Include/object.h index f5ed70b1129682..2ca2435f88f97a 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) @@ -1071,6 +1070,17 @@ PyAPI_FUNC(void) _PyObject_DebugTypeStats(FILE *out); #endif /* ifndef Py_LIMITED_API */ +#ifndef Py_LIMITED_API +/* 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'. + 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/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 3439040d2d91b9..b5d52ab7949b40 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4444,10 +4444,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); @@ -5837,22 +5835,31 @@ PyInit__datetime(void) Py_BUILD_ASSERT(DI100Y == 25 * DI4Y - 1); assert(DI100Y == days_before_year(100+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 (us_per_ms == NULL || us_per_second == NULL || - us_per_minute == NULL || seconds_per_day == 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 189b1cd8442827..982238630ecada 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -787,9 +787,10 @@ _PyIO_trap_eintr(void) PyObject *typ, *val, *tb; PyOSErrorObject *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_OSError)) return 0; diff --git a/Modules/_json.c b/Modules/_json.c index f574004b38e002..c2726fea70c5c0 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); } @@ -316,21 +314,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); @@ -1363,24 +1368,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; @@ -1547,12 +1555,14 @@ encoder_listencode_dict(PyEncoderObject *s, _PyAccu *acc, PyObject *item = NULL; 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); @@ -1698,12 +1708,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 d318b252e83058..8dd606994c953d 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -4715,16 +4715,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 5b74ec5b4923b3..14bd2e03aa57af 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -2062,10 +2062,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 06461c380365bf..8c154e507db402 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 f4a21679d0b202..b393481f74c619 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -13290,9 +13290,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 fad1b1f5abb954..085080b7c9c8c9 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 b92fafe620c102..bc57b7b8e58ca0 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 46bc45d5ac186d..a93105e2df66b5 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 858eff5fc26c34..5ffa3806b16a9c 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -2889,11 +2889,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)) { @@ -2903,11 +2900,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 314a13c4c8fa5a..e622c0b6a08447 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/object.c b/Objects/object.c index 2ba6e572ea61ff..03e22b03b34a15 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2142,3 +2142,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/Objects/typeobject.c b/Objects/typeobject.c index 3b3148fe8f5fc6..11c9d1b1a470a9 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4425,15 +4425,14 @@ static PyObject * object___reduce_ex___impl(PyObject *self, int protocol) /*[clinic end generated code: output=2e157766f6b50094 input=f326b43fb8a4c5ff]*/ { - 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__); @@ -6366,12 +6365,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 b68042179f0903..65d97abe9d2b48 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* @@ -15256,7 +15233,6 @@ _PyUnicode_Fini(void) for (i = 0; i < 256; i++) Py_CLEAR(unicode_latin1[i]); - _PyUnicode_ClearStaticStrings(); (void)PyUnicode_ClearFreeList(); } diff --git a/Python/_warnings.c b/Python/_warnings.c index add72e4ebb38af..1972656b71d952 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 */ @@ -571,19 +570,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 || @@ -1127,34 +1120,30 @@ create_filter(PyObject *category, const char *action) PyObject *action_obj = NULL; 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 dad7404a85f3f4..3832aaf8733ae2 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)) @@ -1445,12 +1443,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; @@ -2626,12 +2624,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) @@ -2702,11 +2698,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 9a78d6adc7a2af..1aab9477071840 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"); @@ -1722,7 +1718,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; @@ -1732,16 +1728,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 */ @@ -1778,7 +1774,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/pylifecycle.c b/Python/pylifecycle.c index ec26824f839eee..933bdd71351089 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); @@ -863,6 +864,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 @@ -892,6 +896,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); diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 424a88f7086b3e..dcc9e2687790cb 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;