Skip to content

Commit d9f8544

Browse files
committed
Fix refleaks
1 parent f2373f4 commit d9f8544

2 files changed

Lines changed: 153 additions & 71 deletions

File tree

Lib/test/datetimetester.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7324,6 +7324,11 @@ def gen():
73247324
res = script_helper.assert_python_ok('-c', script)
73257325
self.assertFalse(res.err)
73267326

7327+
if support.Py_DEBUG:
7328+
with self.subTest('Refleak'):
7329+
res = script_helper.assert_python_ok('-X', 'showrefcount', '-c', script)
7330+
self.assertIn(b'[0 refs, 0 blocks]', res.err)
7331+
73277332

73287333
def load_tests(loader, standard_tests, pattern):
73297334
standard_tests.addTest(ZoneInfoCompleteTest())

Modules/_datetimemodule.c

Lines changed: 148 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -100,54 +100,17 @@ typedef struct {
100100

101101
#define PyIsoCalendarDate_CAST(op) ((PyDateTime_IsoCalendarDate *)(op))
102102

103-
static inline PyObject *
104-
get_const_us_per_ms(datetime_state *st) {
105-
return st ? st->us_per_ms : PyLong_FromLong(1000);
106-
}
107-
108-
static inline PyObject *
109-
get_const_us_per_second(datetime_state *st) {
110-
return st ? st->us_per_second : PyLong_FromLong(1000000);
111-
}
112-
113-
static inline PyObject *
114-
get_const_us_per_minute(datetime_state *st) {
115-
return st ? st->us_per_minute : PyLong_FromLong(60000000);
116-
}
117-
118-
static inline PyObject *
119-
get_const_us_per_hour(datetime_state *st) {
120-
return st ? st->us_per_hour : PyLong_FromDouble(3600000000.0);
121-
}
122-
123-
static inline PyObject *
124-
get_const_us_per_day(datetime_state *st) {
125-
return st ? st->us_per_day : PyLong_FromDouble(86400000000.0);
126-
}
127-
128-
static inline PyObject *
129-
get_const_us_per_week(datetime_state *st) {
130-
return st ? st->us_per_week : PyLong_FromDouble(604800000000.0);
131-
}
132-
133-
static inline PyObject *
134-
get_const_sec_per_day(datetime_state *st) {
135-
return st ? st->seconds_per_day : PyLong_FromLong(24 * 3600);
136-
}
137-
138-
#define CONST_US_PER_MS(st) get_const_us_per_ms(st)
139-
#define CONST_US_PER_SECOND(st) get_const_us_per_second(st)
140-
#define CONST_US_PER_MINUTE(st) get_const_us_per_minute(st)
141-
#define CONST_US_PER_HOUR(st) get_const_us_per_hour(st)
142-
#define CONST_US_PER_DAY(st) get_const_us_per_day(st)
143-
#define CONST_US_PER_WEEK(st) get_const_us_per_week(st)
144-
#define CONST_SEC_PER_DAY(st) get_const_sec_per_day(st)
145103
#define CONST_UTC(st) ((PyObject *)&utc_timezone)
146-
#define CONST_EPOCH(st) \
147-
(st ? ((datetime_state *)st)->epoch \
148-
: new_datetime(1970, 1, 1, 0, 0, 0, 0, (PyObject *)&utc_timezone, 0))
149-
150-
static datetime_state *
104+
static inline PyObject *get_const_us_per_ms(datetime_state *st);
105+
static inline PyObject *get_const_us_per_second(datetime_state *st);
106+
static inline PyObject *get_const_us_per_minute(datetime_state *st);
107+
static inline PyObject *get_const_us_per_hour(datetime_state *st);
108+
static inline PyObject *get_const_us_per_day(datetime_state *st);
109+
static inline PyObject *get_const_us_per_week(datetime_state *st);
110+
static inline PyObject *get_const_sec_per_day(datetime_state *st);
111+
static inline PyObject *get_const_epoch(datetime_state *st);
112+
113+
static inline datetime_state *
151114
get_module_state(PyObject *module)
152115
{
153116
void *state = _PyModule_GetState(module);
@@ -2149,7 +2112,12 @@ delta_to_microseconds(PyDateTime_Delta *self)
21492112
x1 = PyLong_FromLong(GET_TD_DAYS(self));
21502113
if (x1 == NULL)
21512114
goto Done;
2152-
x2 = PyNumber_Multiply(x1, CONST_SEC_PER_DAY(st)); /* days in seconds */
2115+
PyObject *sec_per_day = get_const_sec_per_day(st);
2116+
if (sec_per_day == NULL) {
2117+
goto Done;
2118+
}
2119+
x2 = PyNumber_Multiply(x1, sec_per_day); /* days in seconds */
2120+
Py_DECREF(sec_per_day);
21532121
if (x2 == NULL)
21542122
goto Done;
21552123
Py_SETREF(x1, NULL);
@@ -2166,7 +2134,12 @@ delta_to_microseconds(PyDateTime_Delta *self)
21662134
/* x1 = */ x2 = NULL;
21672135

21682136
/* x3 has days+seconds in seconds */
2169-
x1 = PyNumber_Multiply(x3, CONST_US_PER_SECOND(st)); /* us */
2137+
PyObject *us_per_sec = get_const_us_per_second(st);
2138+
if (us_per_sec == NULL) {
2139+
goto Done;
2140+
}
2141+
x1 = PyNumber_Multiply(x3, us_per_sec); /* us */
2142+
Py_DECREF(us_per_sec);
21702143
if (x1 == NULL)
21712144
goto Done;
21722145
Py_SETREF(x3, NULL);
@@ -2225,7 +2198,12 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type)
22252198
PyObject *current_mod = NULL;
22262199
datetime_state *st = GET_CURRENT_STATE(current_mod);
22272200

2228-
tuple = checked_divmod(pyus, CONST_US_PER_SECOND(st));
2201+
PyObject *us_per_sec = get_const_us_per_second(st);
2202+
if (us_per_sec == NULL) {
2203+
goto Done;
2204+
}
2205+
tuple = checked_divmod(pyus, us_per_sec);
2206+
Py_DECREF(us_per_sec);
22292207
if (tuple == NULL) {
22302208
goto Done;
22312209
}
@@ -2243,7 +2221,12 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type)
22432221
num = Py_NewRef(PyTuple_GET_ITEM(tuple, 0)); /* leftover seconds */
22442222
Py_DECREF(tuple);
22452223

2246-
tuple = checked_divmod(num, CONST_SEC_PER_DAY(st));
2224+
PyObject *sec_per_day = get_const_sec_per_day(st);
2225+
if (sec_per_day == NULL) {
2226+
goto Done;
2227+
}
2228+
tuple = checked_divmod(num, sec_per_day);
2229+
Py_DECREF(sec_per_day);
22472230
if (tuple == NULL)
22482231
goto Done;
22492232
Py_DECREF(num);
@@ -2849,27 +2832,57 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw)
28492832
CLEANUP;
28502833
}
28512834
if (ms) {
2852-
y = accum("milliseconds", x, ms, CONST_US_PER_MS(st), &leftover_us);
2835+
PyObject *us_per_ms = get_const_us_per_ms(st);
2836+
if (us_per_ms == NULL) {
2837+
goto Done;
2838+
}
2839+
y = accum("milliseconds", x, ms, us_per_ms, &leftover_us);
2840+
Py_DECREF(us_per_ms);
28532841
CLEANUP;
28542842
}
28552843
if (second) {
2856-
y = accum("seconds", x, second, CONST_US_PER_SECOND(st), &leftover_us);
2844+
PyObject *us_per_sec = get_const_us_per_second(st);
2845+
if (us_per_sec == NULL) {
2846+
goto Done;
2847+
}
2848+
y = accum("seconds", x, second, us_per_sec, &leftover_us);
2849+
Py_DECREF(us_per_sec);
28572850
CLEANUP;
28582851
}
28592852
if (minute) {
2860-
y = accum("minutes", x, minute, CONST_US_PER_MINUTE(st), &leftover_us);
2853+
PyObject *us_per_min = get_const_us_per_minute(st);
2854+
if (us_per_min == NULL) {
2855+
goto Done;
2856+
}
2857+
y = accum("minutes", x, minute, us_per_min, &leftover_us);
2858+
Py_DECREF(us_per_min);
28612859
CLEANUP;
28622860
}
28632861
if (hour) {
2864-
y = accum("hours", x, hour, CONST_US_PER_HOUR(st), &leftover_us);
2862+
PyObject *us_per_hour = get_const_us_per_hour(st);
2863+
if (us_per_hour == NULL) {
2864+
goto Done;
2865+
}
2866+
y = accum("hours", x, hour, us_per_hour, &leftover_us);
2867+
Py_DECREF(us_per_hour);
28652868
CLEANUP;
28662869
}
28672870
if (day) {
2868-
y = accum("days", x, day, CONST_US_PER_DAY(st), &leftover_us);
2871+
PyObject *us_per_day = get_const_us_per_day(st);
2872+
if (us_per_day == NULL) {
2873+
goto Done;
2874+
}
2875+
y = accum("days", x, day, us_per_day, &leftover_us);
2876+
Py_DECREF(us_per_day);
28692877
CLEANUP;
28702878
}
28712879
if (week) {
2872-
y = accum("weeks", x, week, CONST_US_PER_WEEK(st), &leftover_us);
2880+
PyObject *us_per_week = get_const_us_per_week(st);
2881+
if (us_per_week == NULL) {
2882+
goto Done;
2883+
}
2884+
y = accum("weeks", x, week, us_per_week, &leftover_us);
2885+
Py_DECREF(us_per_week);
28732886
CLEANUP;
28742887
}
28752888
if (leftover_us) {
@@ -3019,7 +3032,7 @@ delta_getstate(PyDateTime_Delta *self)
30193032
static PyObject *
30203033
delta_total_seconds(PyObject *op, PyObject *Py_UNUSED(dummy))
30213034
{
3022-
PyObject *total_seconds;
3035+
PyObject *total_seconds = NULL;
30233036
PyObject *total_microseconds;
30243037

30253038
total_microseconds = delta_to_microseconds(PyDelta_CAST(op));
@@ -3029,8 +3042,13 @@ delta_total_seconds(PyObject *op, PyObject *Py_UNUSED(dummy))
30293042
PyObject *current_mod = NULL;
30303043
datetime_state *st = GET_CURRENT_STATE(current_mod);
30313044

3032-
total_seconds = PyNumber_TrueDivide(total_microseconds, CONST_US_PER_SECOND(st));
3033-
3045+
PyObject *us_per_sec = get_const_us_per_second(st);
3046+
if (us_per_sec == NULL) {
3047+
goto finally;
3048+
}
3049+
total_seconds = PyNumber_TrueDivide(total_microseconds, us_per_sec);
3050+
Py_DECREF(us_per_sec);
3051+
finally:
30343052
RELEASE_CURRENT_STATE(st, current_mod);
30353053
Py_DECREF(total_microseconds);
30363054
return total_seconds;
@@ -6612,7 +6630,12 @@ local_timezone(PyDateTime_DateTime *utc_time)
66126630
PyObject *current_mod = NULL;
66136631
datetime_state *st = GET_CURRENT_STATE(current_mod);
66146632

6615-
delta = datetime_subtract((PyObject *)utc_time, CONST_EPOCH(st));
6633+
PyObject *epoch = get_const_epoch(st);
6634+
if (epoch == NULL) {
6635+
return NULL;
6636+
}
6637+
delta = datetime_subtract((PyObject *)utc_time, epoch);
6638+
Py_DECREF(epoch);
66166639
RELEASE_CURRENT_STATE(st, current_mod);
66176640
if (delta == NULL)
66186641
return NULL;
@@ -6856,8 +6879,12 @@ datetime_timestamp(PyObject *op, PyObject *Py_UNUSED(dummy))
68566879
PyObject *current_mod = NULL;
68576880
datetime_state *st = GET_CURRENT_STATE(current_mod);
68586881

6859-
PyObject *delta;
6860-
delta = datetime_subtract(op, CONST_EPOCH(st));
6882+
PyObject *epoch = get_const_epoch(st);
6883+
if (epoch == NULL) {
6884+
return NULL;
6885+
}
6886+
PyObject *delta = datetime_subtract(op, epoch);
6887+
Py_DECREF(epoch);
68616888
RELEASE_CURRENT_STATE(st, current_mod);
68626889
if (delta == NULL)
68636890
return NULL;
@@ -7224,6 +7251,56 @@ create_timezone_from_delta(int days, int sec, int ms, int normalize)
72247251
* Module state lifecycle.
72257252
*/
72267253

7254+
static inline PyObject *
7255+
get_const_us_per_ms(datetime_state *st) {
7256+
return st && st->us_per_ms ? Py_NewRef(st->us_per_ms)
7257+
: PyLong_FromLong(1000);
7258+
}
7259+
7260+
static inline PyObject *
7261+
get_const_us_per_second(datetime_state *st) {
7262+
return st && st->us_per_second ? Py_NewRef(st->us_per_second)
7263+
: PyLong_FromLong(1000000);
7264+
}
7265+
7266+
static inline PyObject *
7267+
get_const_us_per_minute(datetime_state *st) {
7268+
return st && st->us_per_minute ? Py_NewRef(st->us_per_minute)
7269+
: PyLong_FromLong(60000000);
7270+
}
7271+
7272+
static inline PyObject *
7273+
get_const_us_per_hour(datetime_state *st) {
7274+
return st && st->us_per_hour ? Py_NewRef(st->us_per_hour)
7275+
: PyLong_FromDouble(3600000000.0);
7276+
}
7277+
7278+
static inline PyObject *
7279+
get_const_us_per_day(datetime_state *st) {
7280+
return st && st->us_per_day ? Py_NewRef(st->us_per_day)
7281+
: PyLong_FromDouble(86400000000.0);
7282+
}
7283+
7284+
static inline PyObject *
7285+
get_const_us_per_week(datetime_state *st) {
7286+
return st && st->us_per_week ? Py_NewRef(st->us_per_week)
7287+
: PyLong_FromDouble(604800000000.0);
7288+
}
7289+
7290+
static inline PyObject *
7291+
get_const_sec_per_day(datetime_state *st) {
7292+
return st && st->seconds_per_day ? Py_NewRef(st->seconds_per_day)
7293+
: PyLong_FromLong(24 * 3600);
7294+
}
7295+
7296+
static inline PyObject *
7297+
get_const_epoch(datetime_state *st) {
7298+
return st && st->epoch ? Py_NewRef(st->epoch)
7299+
: new_datetime(1970, 1, 1, 0, 0, 0, 0,
7300+
(PyObject *)&utc_timezone, 0);
7301+
}
7302+
7303+
72277304
static int
72287305
init_state(datetime_state *st, PyObject *module, PyObject *old_module)
72297306
{
@@ -7243,41 +7320,41 @@ init_state(datetime_state *st, PyObject *module, PyObject *old_module)
72437320
return 0;
72447321
}
72457322

7246-
st->us_per_ms = CONST_US_PER_MS(NULL);
7323+
st->us_per_ms = get_const_us_per_ms(NULL);
72477324
if (st->us_per_ms == NULL) {
72487325
return -1;
72497326
}
7250-
st->us_per_second = CONST_US_PER_SECOND(NULL);
7327+
st->us_per_second = get_const_us_per_second(NULL);
72517328
if (st->us_per_second == NULL) {
72527329
return -1;
72537330
}
7254-
st->us_per_minute = CONST_US_PER_MINUTE(NULL);
7331+
st->us_per_minute = get_const_us_per_minute(NULL);
72557332
if (st->us_per_minute == NULL) {
72567333
return -1;
72577334
}
7258-
st->seconds_per_day = CONST_SEC_PER_DAY(NULL);
7335+
st->seconds_per_day = get_const_sec_per_day(NULL);
72597336
if (st->seconds_per_day == NULL) {
72607337
return -1;
72617338
}
72627339

72637340
/* The rest are too big for 32-bit ints, but even
72647341
* us_per_week fits in 40 bits, so doubles should be exact.
72657342
*/
7266-
st->us_per_hour = CONST_US_PER_HOUR(NULL);
7343+
st->us_per_hour = get_const_us_per_hour(NULL);
72677344
if (st->us_per_hour == NULL) {
72687345
return -1;
72697346
}
7270-
st->us_per_day = CONST_US_PER_DAY(NULL);
7347+
st->us_per_day = get_const_us_per_day(NULL);
72717348
if (st->us_per_day == NULL) {
72727349
return -1;
72737350
}
7274-
st->us_per_week = CONST_US_PER_WEEK(NULL);
7351+
st->us_per_week = get_const_us_per_week(NULL);
72757352
if (st->us_per_week == NULL) {
72767353
return -1;
72777354
}
72787355

72797356
/* Init Unix epoch */
7280-
st->epoch = CONST_EPOCH(NULL);
7357+
st->epoch = get_const_epoch(NULL);
72817358
if (st->epoch == NULL) {
72827359
return -1;
72837360
}

0 commit comments

Comments
 (0)