Skip to content

Commit 2db8e35

Browse files
authored
bpo-1635741: Enhance _datetime error handling (GH-23139)
1 parent 5c36da7 commit 2db8e35

File tree

1 file changed

+103
-117
lines changed

1 file changed

+103
-117
lines changed

Modules/_datetimemodule.c

+103-117
Original file line numberDiff line numberDiff line change
@@ -6494,32 +6494,9 @@ static PyDateTime_CAPI CAPI = {
64946494
new_time_ex2
64956495
};
64966496

6497-
6498-
6499-
static struct PyModuleDef datetimemodule = {
6500-
PyModuleDef_HEAD_INIT,
6501-
"_datetime",
6502-
"Fast implementation of the datetime type.",
6503-
-1,
6504-
module_methods,
6505-
NULL,
6506-
NULL,
6507-
NULL,
6508-
NULL
6509-
};
6510-
6511-
PyMODINIT_FUNC
6512-
PyInit__datetime(void)
6497+
static int
6498+
_datetime_exec(PyObject *module)
65136499
{
6514-
PyObject *m; /* a module object */
6515-
PyObject *d; /* its dict */
6516-
PyObject *x;
6517-
PyObject *delta;
6518-
6519-
m = PyModule_Create(&datetimemodule);
6520-
if (m == NULL)
6521-
return NULL;
6522-
65236500
// `&...` is not a constant expression according to a strict reading
65246501
// of C standards. Fill tp_base at run-time rather than statically.
65256502
// See https://bugs.python.org/issue40777
@@ -6537,136 +6514,120 @@ PyInit__datetime(void)
65376514
};
65386515

65396516
for (size_t i = 0; i < Py_ARRAY_LENGTH(types); i++) {
6540-
if (PyModule_AddType(m, types[i]) < 0) {
6541-
return NULL;
6517+
if (PyModule_AddType(module, types[i]) < 0) {
6518+
return -1;
65426519
}
65436520
}
65446521

65456522
if (PyType_Ready(&PyDateTime_IsoCalendarDateType) < 0) {
6546-
return NULL;
6523+
return -1;
65476524
}
6548-
Py_INCREF(&PyDateTime_IsoCalendarDateType);
6549-
6550-
/* timedelta values */
6551-
d = PyDateTime_DeltaType.tp_dict;
6552-
6553-
x = new_delta(0, 0, 1, 0);
6554-
if (x == NULL || PyDict_SetItemString(d, "resolution", x) < 0)
6555-
return NULL;
6556-
Py_DECREF(x);
65576525

6558-
x = new_delta(-MAX_DELTA_DAYS, 0, 0, 0);
6559-
if (x == NULL || PyDict_SetItemString(d, "min", x) < 0)
6560-
return NULL;
6561-
Py_DECREF(x);
6526+
#define DATETIME_ADD_MACRO(dict, c, value_expr) \
6527+
do { \
6528+
PyObject *value = (value_expr); \
6529+
if (value == NULL) { \
6530+
return -1; \
6531+
} \
6532+
if (PyDict_SetItemString(dict, c, value) < 0) { \
6533+
Py_DECREF(value); \
6534+
return -1; \
6535+
} \
6536+
Py_DECREF(value); \
6537+
} while(0)
65626538

6563-
x = new_delta(MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0);
6564-
if (x == NULL || PyDict_SetItemString(d, "max", x) < 0)
6565-
return NULL;
6566-
Py_DECREF(x);
6539+
/* timedelta values */
6540+
PyObject *d = PyDateTime_DeltaType.tp_dict;
6541+
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
6542+
DATETIME_ADD_MACRO(d, "min", new_delta(-MAX_DELTA_DAYS, 0, 0, 0));
6543+
DATETIME_ADD_MACRO(d, "max",
6544+
new_delta(MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0));
65676545

65686546
/* date values */
65696547
d = PyDateTime_DateType.tp_dict;
6570-
6571-
x = new_date(1, 1, 1);
6572-
if (x == NULL || PyDict_SetItemString(d, "min", x) < 0)
6573-
return NULL;
6574-
Py_DECREF(x);
6575-
6576-
x = new_date(MAXYEAR, 12, 31);
6577-
if (x == NULL || PyDict_SetItemString(d, "max", x) < 0)
6578-
return NULL;
6579-
Py_DECREF(x);
6580-
6581-
x = new_delta(1, 0, 0, 0);
6582-
if (x == NULL || PyDict_SetItemString(d, "resolution", x) < 0)
6583-
return NULL;
6584-
Py_DECREF(x);
6548+
DATETIME_ADD_MACRO(d, "min", new_date(1, 1, 1));
6549+
DATETIME_ADD_MACRO(d, "max", new_date(MAXYEAR, 12, 31));
6550+
DATETIME_ADD_MACRO(d, "resolution", new_delta(1, 0, 0, 0));
65856551

65866552
/* time values */
65876553
d = PyDateTime_TimeType.tp_dict;
6588-
6589-
x = new_time(0, 0, 0, 0, Py_None, 0);
6590-
if (x == NULL || PyDict_SetItemString(d, "min", x) < 0)
6591-
return NULL;
6592-
Py_DECREF(x);
6593-
6594-
x = new_time(23, 59, 59, 999999, Py_None, 0);
6595-
if (x == NULL || PyDict_SetItemString(d, "max", x) < 0)
6596-
return NULL;
6597-
Py_DECREF(x);
6598-
6599-
x = new_delta(0, 0, 1, 0);
6600-
if (x == NULL || PyDict_SetItemString(d, "resolution", x) < 0)
6601-
return NULL;
6602-
Py_DECREF(x);
6554+
DATETIME_ADD_MACRO(d, "min", new_time(0, 0, 0, 0, Py_None, 0));
6555+
DATETIME_ADD_MACRO(d, "max", new_time(23, 59, 59, 999999, Py_None, 0));
6556+
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
66036557

66046558
/* datetime values */
66056559
d = PyDateTime_DateTimeType.tp_dict;
6606-
6607-
x = new_datetime(1, 1, 1, 0, 0, 0, 0, Py_None, 0);
6608-
if (x == NULL || PyDict_SetItemString(d, "min", x) < 0)
6609-
return NULL;
6610-
Py_DECREF(x);
6611-
6612-
x = new_datetime(MAXYEAR, 12, 31, 23, 59, 59, 999999, Py_None, 0);
6613-
if (x == NULL || PyDict_SetItemString(d, "max", x) < 0)
6614-
return NULL;
6615-
Py_DECREF(x);
6616-
6617-
x = new_delta(0, 0, 1, 0);
6618-
if (x == NULL || PyDict_SetItemString(d, "resolution", x) < 0)
6619-
return NULL;
6620-
Py_DECREF(x);
6560+
DATETIME_ADD_MACRO(d, "min",
6561+
new_datetime(1, 1, 1, 0, 0, 0, 0, Py_None, 0));
6562+
DATETIME_ADD_MACRO(d, "max", new_datetime(MAXYEAR, 12, 31, 23, 59, 59,
6563+
999999, Py_None, 0));
6564+
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
66216565

66226566
/* timezone values */
66236567
d = PyDateTime_TimeZoneType.tp_dict;
6568+
PyObject *delta = new_delta(0, 0, 0, 0);
6569+
if (delta == NULL) {
6570+
return -1;
6571+
}
66246572

6625-
delta = new_delta(0, 0, 0, 0);
6626-
if (delta == NULL)
6627-
return NULL;
6628-
x = create_timezone(delta, NULL);
6573+
PyObject *x = create_timezone(delta, NULL);
66296574
Py_DECREF(delta);
6630-
if (x == NULL || PyDict_SetItemString(d, "utc", x) < 0)
6631-
return NULL;
6575+
if (x == NULL) {
6576+
return -1;
6577+
}
6578+
if (PyDict_SetItemString(d, "utc", x) < 0) {
6579+
Py_DECREF(x);
6580+
return -1;
6581+
}
6582+
66326583
PyDateTime_TimeZone_UTC = x;
66336584
CAPI.TimeZone_UTC = PyDateTime_TimeZone_UTC;
66346585

66356586
/* bpo-37642: These attributes are rounded to the nearest minute for backwards
66366587
* compatibility, even though the constructor will accept a wider range of
66376588
* values. This may change in the future.*/
66386589
delta = new_delta(-1, 60, 0, 1); /* -23:59 */
6639-
if (delta == NULL)
6640-
return NULL;
6590+
if (delta == NULL) {
6591+
return -1;
6592+
}
6593+
66416594
x = create_timezone(delta, NULL);
66426595
Py_DECREF(delta);
6643-
if (x == NULL || PyDict_SetItemString(d, "min", x) < 0)
6644-
return NULL;
6645-
Py_DECREF(x);
6596+
DATETIME_ADD_MACRO(d, "min", x);
66466597

66476598
delta = new_delta(0, (23 * 60 + 59) * 60, 0, 0); /* +23:59 */
6648-
if (delta == NULL)
6649-
return NULL;
6599+
if (delta == NULL) {
6600+
return -1;
6601+
}
6602+
66506603
x = create_timezone(delta, NULL);
66516604
Py_DECREF(delta);
6652-
if (x == NULL || PyDict_SetItemString(d, "max", x) < 0)
6653-
return NULL;
6654-
Py_DECREF(x);
6605+
DATETIME_ADD_MACRO(d, "max", x);
66556606

66566607
/* Epoch */
66576608
PyDateTime_Epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0,
66586609
PyDateTime_TimeZone_UTC, 0);
6659-
if (PyDateTime_Epoch == NULL)
6660-
return NULL;
6610+
if (PyDateTime_Epoch == NULL) {
6611+
return -1;
6612+
}
66616613

66626614
/* module initialization */
6663-
PyModule_AddIntMacro(m, MINYEAR);
6664-
PyModule_AddIntMacro(m, MAXYEAR);
6615+
if (PyModule_AddIntMacro(module, MINYEAR) < 0) {
6616+
return -1;
6617+
}
6618+
if (PyModule_AddIntMacro(module, MAXYEAR) < 0) {
6619+
return -1;
6620+
}
66656621

66666622
x = PyCapsule_New(&CAPI, PyDateTime_CAPSULE_NAME, NULL);
6667-
if (x == NULL)
6668-
return NULL;
6669-
PyModule_AddObject(m, "datetime_CAPI", x);
6623+
if (x == NULL) {
6624+
return -1;
6625+
}
6626+
6627+
if (PyModule_AddObject(module, "datetime_CAPI", x) < 0) {
6628+
Py_DECREF(x);
6629+
return -1;
6630+
}
66706631

66716632
/* A 4-year cycle has an extra leap day over what we'd get from
66726633
* pasting together 4 single years.
@@ -6691,18 +6652,43 @@ PyInit__datetime(void)
66916652
us_per_minute = PyLong_FromLong(60000000);
66926653
seconds_per_day = PyLong_FromLong(24 * 3600);
66936654
if (us_per_ms == NULL || us_per_second == NULL ||
6694-
us_per_minute == NULL || seconds_per_day == NULL)
6695-
return NULL;
6655+
us_per_minute == NULL || seconds_per_day == NULL) {
6656+
return -1;
6657+
}
66966658

66976659
/* The rest are too big for 32-bit ints, but even
66986660
* us_per_week fits in 40 bits, so doubles should be exact.
66996661
*/
67006662
us_per_hour = PyLong_FromDouble(3600000000.0);
67016663
us_per_day = PyLong_FromDouble(86400000000.0);
67026664
us_per_week = PyLong_FromDouble(604800000000.0);
6703-
if (us_per_hour == NULL || us_per_day == NULL || us_per_week == NULL)
6665+
if (us_per_hour == NULL || us_per_day == NULL || us_per_week == NULL) {
6666+
return -1;
6667+
}
6668+
return 0;
6669+
}
6670+
6671+
static struct PyModuleDef datetimemodule = {
6672+
PyModuleDef_HEAD_INIT,
6673+
.m_name = "_datetime",
6674+
.m_doc = "Fast implementation of the datetime type.",
6675+
.m_size = -1,
6676+
.m_methods = module_methods,
6677+
};
6678+
6679+
PyMODINIT_FUNC
6680+
PyInit__datetime(void)
6681+
{
6682+
PyObject *mod = PyModule_Create(&datetimemodule);
6683+
if (mod == NULL)
67046684
return NULL;
6705-
return m;
6685+
6686+
if (_datetime_exec(mod) < 0) {
6687+
Py_DECREF(mod);
6688+
return NULL;
6689+
}
6690+
6691+
return mod;
67066692
}
67076693

67086694
/* ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)