@@ -20,14 +20,12 @@ This file is derived from NumPy 1.7. See NUMPY_LICENSE.txt
20
20
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
21
21
#endif // NPY_NO_DEPRECATED_API
22
22
23
- #include <Python.h>
24
-
25
23
#include "pandas/vendored/numpy/datetime/np_datetime.h"
26
-
27
24
#define NO_IMPORT_ARRAY
28
25
#define PY_ARRAY_UNIQUE_SYMBOL PANDAS_DATETIME_NUMPY
29
26
#include <numpy/ndarrayobject.h>
30
27
#include <numpy/npy_common.h>
28
+ #include <stdbool.h>
31
29
32
30
#if defined(_WIN32 )
33
31
#ifndef ENABLE_INTSAFE_SIGNED_FUNCTIONS
@@ -58,12 +56,15 @@ _Static_assert(0, "__has_builtin not detected; please try a newer compiler");
58
56
#endif
59
57
#endif
60
58
59
+ #define XSTR (a ) STR(a)
60
+ #define STR (a ) #a
61
+
61
62
#define PD_CHECK_OVERFLOW (FUNC ) \
62
63
do { \
63
64
if ((FUNC) != 0) { \
64
65
PyGILState_STATE gstate = PyGILState_Ensure(); \
65
66
PyErr_SetString(PyExc_OverflowError, \
66
- "Overflow occurred in npy_datetimestruct_to_datetime"); \
67
+ "Overflow occurred at " __FILE__ ":" XSTR(__LINE__)); \
67
68
PyGILState_Release(gstate); \
68
69
return -1; \
69
70
} \
@@ -139,53 +140,53 @@ npy_int64 get_datetimestruct_days(const npy_datetimestruct *dts) {
139
140
npy_int64 year , days = 0 ;
140
141
const int * month_lengths ;
141
142
142
- year = dts -> year - 1970 ;
143
- days = year * 365 ;
143
+ PD_CHECK_OVERFLOW ( checked_int64_sub ( dts -> year , 1970 , & year )) ;
144
+ PD_CHECK_OVERFLOW ( checked_int64_mul ( year , 365 , & days )) ;
144
145
145
146
/* Adjust for leap years */
146
147
if (days >= 0 ) {
147
148
/*
148
149
* 1968 is the closest leap year before 1970.
149
150
* Exclude the current year, so add 1.
150
151
*/
151
- year += 1 ;
152
+ PD_CHECK_OVERFLOW ( checked_int64_add ( year , 1 , & year )) ;
152
153
/* Add one day for each 4 years */
153
- days += year / 4 ;
154
+ PD_CHECK_OVERFLOW ( checked_int64_add ( days , year / 4 , & days )) ;
154
155
/* 1900 is the closest previous year divisible by 100 */
155
- year += 68 ;
156
+ PD_CHECK_OVERFLOW ( checked_int64_add ( year , 68 , & year )) ;
156
157
/* Subtract one day for each 100 years */
157
- days -= year / 100 ;
158
+ PD_CHECK_OVERFLOW ( checked_int64_sub ( days , year / 100 , & days )) ;
158
159
/* 1600 is the closest previous year divisible by 400 */
159
- year += 300 ;
160
+ PD_CHECK_OVERFLOW ( checked_int64_add ( year , 300 , & year )) ;
160
161
/* Add one day for each 400 years */
161
- days += year / 400 ;
162
+ PD_CHECK_OVERFLOW ( checked_int64_add ( days , year / 400 , & days )) ;
162
163
} else {
163
164
/*
164
165
* 1972 is the closest later year after 1970.
165
166
* Include the current year, so subtract 2.
166
167
*/
167
- year -= 2 ;
168
+ PD_CHECK_OVERFLOW ( checked_int64_sub ( year , 2 , & year )) ;
168
169
/* Subtract one day for each 4 years */
169
- days += year / 4 ;
170
+ PD_CHECK_OVERFLOW ( checked_int64_add ( days , year / 4 , & days )) ;
170
171
/* 2000 is the closest later year divisible by 100 */
171
- year -= 28 ;
172
+ PD_CHECK_OVERFLOW ( checked_int64_sub ( year , 28 , & year )) ;
172
173
/* Add one day for each 100 years */
173
- days -= year / 100 ;
174
+ PD_CHECK_OVERFLOW ( checked_int64_sub ( days , year / 100 , & days )) ;
174
175
/* 2000 is also the closest later year divisible by 400 */
175
176
/* Subtract one day for each 400 years */
176
- days += year / 400 ;
177
+ PD_CHECK_OVERFLOW ( checked_int64_add ( days , year / 400 , & days )) ;
177
178
}
178
179
179
180
month_lengths = days_per_month_table [is_leapyear (dts -> year )];
180
181
month = dts -> month - 1 ;
181
182
182
183
/* Add the months */
183
184
for (i = 0 ; i < month ; ++ i ) {
184
- days += month_lengths [i ];
185
+ PD_CHECK_OVERFLOW ( checked_int64_add ( days , month_lengths [i ], & days )) ;
185
186
}
186
187
187
188
/* Add the days */
188
- days += dts -> day - 1 ;
189
+ PD_CHECK_OVERFLOW ( checked_int64_add ( days , dts -> day - 1 , & days )) ;
189
190
190
191
return days ;
191
192
}
@@ -430,6 +431,15 @@ npy_datetime npy_datetimestruct_to_datetime(NPY_DATETIMEUNIT base,
430
431
}
431
432
432
433
const int64_t days = get_datetimestruct_days (dts );
434
+ if (days == -1 ) {
435
+ PyGILState_STATE gstate = PyGILState_Ensure ();
436
+ bool did_error = PyErr_Occurred () == NULL ? false : true;
437
+ PyGILState_Release (gstate );
438
+ if (did_error ) {
439
+ return -1 ;
440
+ }
441
+ }
442
+
433
443
if (base == NPY_FR_D ) {
434
444
return days ;
435
445
}
0 commit comments