Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions Include/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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
Expand Down
35 changes: 21 additions & 14 deletions Modules/_datetimemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}

Expand Down
7 changes: 4 additions & 3 deletions Modules/_io/bufferedio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
72 changes: 42 additions & 30 deletions Modules/_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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");
Expand Down
15 changes: 7 additions & 8 deletions Modules/_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 2 additions & 4 deletions Modules/_struct.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
25 changes: 14 additions & 11 deletions Modules/arraymodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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__

Expand All @@ -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)) {
Expand Down
6 changes: 4 additions & 2 deletions Modules/gcmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down
4 changes: 2 additions & 2 deletions Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
{
Expand Down
7 changes: 4 additions & 3 deletions Modules/zipimport.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
20 changes: 13 additions & 7 deletions Objects/boolobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"))) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If make _PY_ONCEVAR_INIT() returning the value (NULL in case of error) the code would be simpler.

if (self == Py_True) {
    s = _PY_ONCEVAR_INIT(true_str, PyUnicode_InternFromString("True"));
}
else {
    s = _PY_ONCEVAR_INIT(false_str, PyUnicode_InternFromString("False"));
}
Py_XINCREF(s);
return s;

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;
}

Expand Down
14 changes: 5 additions & 9 deletions Objects/codeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading