Skip to content
Merged
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
48 changes: 48 additions & 0 deletions pandas/_libs/include/pandas/portable.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,51 @@ The full license is in the LICENSE file, distributed with this software.
do { \
} while (0) /* fallthrough */
#endif

#if defined(_WIN32)
#ifndef ENABLE_INTSAFE_SIGNED_FUNCTIONS
#define ENABLE_INTSAFE_SIGNED_FUNCTIONS
#endif
#include <intsafe.h>
#define checked_add(a, b, res) \
_Generic((res), \
int *: IntAdd, \
unsigned int *: UIntAdd, \
long *: LongAdd, \
unsigned long *: ULongAdd, \
long long *: LongLongAdd, \
unsigned long long *: ULongLongAdd, \
short *: ShortAdd, \
unsigned short *: UShortAdd)(a, b, res)

#define checked_sub(a, b, res) \
_Generic((res), \
int *: IntSub, \
unsigned int *: UIntSub, \
long *: LongSub, \
unsigned long *: ULongSub, \
long long *: LongLongSub, \
unsigned long long *: ULongLongSub, \
short *: ShortSub, \
unsigned short *: UShortSub)(a, b, res)

#define checked_mul(a, b, res) \
_Generic((res), \
int *: IntMult, \
unsigned int *: UIntMult, \
long *: LongMult, \
unsigned long *: ULongMult, \
long long *: LongLongMult, \
unsigned long long *: ULongLongMult, \
short *: ShortMult, \
unsigned short *: UShortMult)(a, b, res)

#elif (defined(__has_builtin) && __has_builtin(__builtin_add_overflow)) || \
__GNUC__ > 7
#define checked_add(a, b, res) __builtin_add_overflow(a, b, res)
#define checked_sub(a, b, res) __builtin_sub_overflow(a, b, res)
#define checked_mul(a, b, res) __builtin_mul_overflow(a, b, res)
#else
_Static_assert(0,
"Overflow checking not detected; please try a newer compiler");
#endif
111 changes: 40 additions & 71 deletions pandas/_libs/src/vendored/numpy/datetime/np_datetime.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,39 +23,11 @@ This file is derived from NumPy 1.7. See NUMPY_LICENSE.txt
#include "pandas/vendored/numpy/datetime/np_datetime.h"
#define NO_IMPORT_ARRAY
#define PY_ARRAY_UNIQUE_SYMBOL PANDAS_DATETIME_NUMPY
#include "pandas/portable.h"
#include <numpy/ndarrayobject.h>
#include <numpy/npy_common.h>
#include <stdbool.h>

#if defined(_WIN32)
#ifndef ENABLE_INTSAFE_SIGNED_FUNCTIONS
#define ENABLE_INTSAFE_SIGNED_FUNCTIONS
#endif
#include <intsafe.h>
#define checked_int64_add(a, b, res) LongLongAdd(a, b, res)
#define checked_int64_sub(a, b, res) LongLongSub(a, b, res)
#define checked_int64_mul(a, b, res) LongLongMult(a, b, res)
#else
#if defined __has_builtin
#if __has_builtin(__builtin_add_overflow)
#define checked_int64_add(a, b, res) __builtin_add_overflow(a, b, res)
#define checked_int64_sub(a, b, res) __builtin_sub_overflow(a, b, res)
#define checked_int64_mul(a, b, res) __builtin_mul_overflow(a, b, res)
#else
_Static_assert(0,
"Overflow checking not detected; please try a newer compiler");
#endif
// __has_builtin was added in gcc 10, but our muslinux_1_1 build environment
// only has gcc-9.3, so fall back to __GNUC__ macro as long as we have that
#elif __GNUC__ > 7
#define checked_int64_add(a, b, res) __builtin_add_overflow(a, b, res)
#define checked_int64_sub(a, b, res) __builtin_sub_overflow(a, b, res)
#define checked_int64_mul(a, b, res) __builtin_mul_overflow(a, b, res)
#else
_Static_assert(0, "__has_builtin not detected; please try a newer compiler");
#endif
#endif

#define XSTR(a) STR(a)
#define STR(a) #a

Expand Down Expand Up @@ -140,53 +112,53 @@ npy_int64 get_datetimestruct_days(const npy_datetimestruct *dts) {
npy_int64 year, days = 0;
const int *month_lengths;

PD_CHECK_OVERFLOW(checked_int64_sub(dts->year, 1970, &year));
PD_CHECK_OVERFLOW(checked_int64_mul(year, 365, &days));
PD_CHECK_OVERFLOW(checked_sub(dts->year, 1970, &year));
PD_CHECK_OVERFLOW(checked_mul(year, 365, &days));

/* Adjust for leap years */
if (days >= 0) {
/*
* 1968 is the closest leap year before 1970.
* Exclude the current year, so add 1.
*/
PD_CHECK_OVERFLOW(checked_int64_add(year, 1, &year));
PD_CHECK_OVERFLOW(checked_add(year, 1, &year));
/* Add one day for each 4 years */
PD_CHECK_OVERFLOW(checked_int64_add(days, year / 4, &days));
PD_CHECK_OVERFLOW(checked_add(days, year / 4, &days));
/* 1900 is the closest previous year divisible by 100 */
PD_CHECK_OVERFLOW(checked_int64_add(year, 68, &year));
PD_CHECK_OVERFLOW(checked_add(year, 68, &year));
/* Subtract one day for each 100 years */
PD_CHECK_OVERFLOW(checked_int64_sub(days, year / 100, &days));
PD_CHECK_OVERFLOW(checked_sub(days, year / 100, &days));
/* 1600 is the closest previous year divisible by 400 */
PD_CHECK_OVERFLOW(checked_int64_add(year, 300, &year));
PD_CHECK_OVERFLOW(checked_add(year, 300, &year));
/* Add one day for each 400 years */
PD_CHECK_OVERFLOW(checked_int64_add(days, year / 400, &days));
PD_CHECK_OVERFLOW(checked_add(days, year / 400, &days));
} else {
/*
* 1972 is the closest later year after 1970.
* Include the current year, so subtract 2.
*/
PD_CHECK_OVERFLOW(checked_int64_sub(year, 2, &year));
PD_CHECK_OVERFLOW(checked_sub(year, 2, &year));
/* Subtract one day for each 4 years */
PD_CHECK_OVERFLOW(checked_int64_add(days, year / 4, &days));
PD_CHECK_OVERFLOW(checked_add(days, year / 4, &days));
/* 2000 is the closest later year divisible by 100 */
PD_CHECK_OVERFLOW(checked_int64_sub(year, 28, &year));
PD_CHECK_OVERFLOW(checked_sub(year, 28, &year));
/* Add one day for each 100 years */
PD_CHECK_OVERFLOW(checked_int64_sub(days, year / 100, &days));
PD_CHECK_OVERFLOW(checked_sub(days, year / 100, &days));
/* 2000 is also the closest later year divisible by 400 */
/* Subtract one day for each 400 years */
PD_CHECK_OVERFLOW(checked_int64_add(days, year / 400, &days));
PD_CHECK_OVERFLOW(checked_add(days, year / 400, &days));
}

month_lengths = days_per_month_table[is_leapyear(dts->year)];
month = dts->month - 1;

/* Add the months */
for (i = 0; i < month; ++i) {
PD_CHECK_OVERFLOW(checked_int64_add(days, month_lengths[i], &days));
PD_CHECK_OVERFLOW(checked_add(days, month_lengths[i], &days));
}

/* Add the days */
PD_CHECK_OVERFLOW(checked_int64_add(days, dts->day - 1, &days));
PD_CHECK_OVERFLOW(checked_add(days, dts->day - 1, &days));

return days;
}
Expand Down Expand Up @@ -341,11 +313,11 @@ PyObject *extract_utc_offset(PyObject *obj) {
}

static inline int scaleYearToEpoch(int64_t year, int64_t *result) {
return checked_int64_sub(year, 1970, result);
return checked_sub(year, 1970, result);
}

static inline int scaleYearsToMonths(int64_t years, int64_t *result) {
return checked_int64_mul(years, 12, result);
return checked_mul(years, 12, result);
}

static inline int scaleDaysToWeeks(int64_t days, int64_t *result) {
Expand All @@ -355,7 +327,7 @@ static inline int scaleDaysToWeeks(int64_t days, int64_t *result) {
} else {
int res;
int64_t checked_days;
if ((res = checked_int64_sub(days, 6, &checked_days))) {
if ((res = checked_sub(days, 6, &checked_days))) {
return res;
}

Expand All @@ -365,43 +337,43 @@ static inline int scaleDaysToWeeks(int64_t days, int64_t *result) {
}

static inline int scaleDaysToHours(int64_t days, int64_t *result) {
return checked_int64_mul(days, 24, result);
return checked_mul(days, 24, result);
}

static inline int scaleHoursToMinutes(int64_t hours, int64_t *result) {
return checked_int64_mul(hours, 60, result);
return checked_mul(hours, 60, result);
}

static inline int scaleMinutesToSeconds(int64_t minutes, int64_t *result) {
return checked_int64_mul(minutes, 60, result);
return checked_mul(minutes, 60, result);
}

static inline int scaleSecondsToMilliseconds(int64_t seconds, int64_t *result) {
return checked_int64_mul(seconds, 1000, result);
return checked_mul(seconds, 1000, result);
}

static inline int scaleSecondsToMicroseconds(int64_t seconds, int64_t *result) {
return checked_int64_mul(seconds, 1000000, result);
return checked_mul(seconds, 1000000, result);
}

static inline int scaleMicrosecondsToNanoseconds(int64_t microseconds,
int64_t *result) {
return checked_int64_mul(microseconds, 1000, result);
return checked_mul(microseconds, 1000, result);
}

static inline int scaleMicrosecondsToPicoseconds(int64_t microseconds,
int64_t *result) {
return checked_int64_mul(microseconds, 1000000, result);
return checked_mul(microseconds, 1000000, result);
}

static inline int64_t scalePicosecondsToFemtoseconds(int64_t picoseconds,
int64_t *result) {
return checked_int64_mul(picoseconds, 1000, result);
return checked_mul(picoseconds, 1000, result);
}

static inline int64_t scalePicosecondsToAttoseconds(int64_t picoseconds,
int64_t *result) {
return checked_int64_mul(picoseconds, 1000000, result);
return checked_mul(picoseconds, 1000000, result);
}

/*
Expand All @@ -422,8 +394,8 @@ npy_datetime npy_datetimestruct_to_datetime(NPY_DATETIMEUNIT base,
PD_CHECK_OVERFLOW(scaleYearsToMonths(years, &months));

int64_t months_adder;
PD_CHECK_OVERFLOW(checked_int64_sub(dts->month, 1, &months_adder));
PD_CHECK_OVERFLOW(checked_int64_add(months, months_adder, &months));
PD_CHECK_OVERFLOW(checked_sub(dts->month, 1, &months_adder));
PD_CHECK_OVERFLOW(checked_add(months, months_adder, &months));

if (base == NPY_FR_M) {
return months;
Expand Down Expand Up @@ -452,23 +424,23 @@ npy_datetime npy_datetimestruct_to_datetime(NPY_DATETIMEUNIT base,

int64_t hours;
PD_CHECK_OVERFLOW(scaleDaysToHours(days, &hours));
PD_CHECK_OVERFLOW(checked_int64_add(hours, dts->hour, &hours));
PD_CHECK_OVERFLOW(checked_add(hours, dts->hour, &hours));

if (base == NPY_FR_h) {
return hours;
}

int64_t minutes;
PD_CHECK_OVERFLOW(scaleHoursToMinutes(hours, &minutes));
PD_CHECK_OVERFLOW(checked_int64_add(minutes, dts->min, &minutes));
PD_CHECK_OVERFLOW(checked_add(minutes, dts->min, &minutes));

if (base == NPY_FR_m) {
return minutes;
}

int64_t seconds;
PD_CHECK_OVERFLOW(scaleMinutesToSeconds(minutes, &seconds));
PD_CHECK_OVERFLOW(checked_int64_add(seconds, dts->sec, &seconds));
PD_CHECK_OVERFLOW(checked_add(seconds, dts->sec, &seconds));

if (base == NPY_FR_s) {
return seconds;
Expand All @@ -477,15 +449,14 @@ npy_datetime npy_datetimestruct_to_datetime(NPY_DATETIMEUNIT base,
if (base == NPY_FR_ms) {
int64_t milliseconds;
PD_CHECK_OVERFLOW(scaleSecondsToMilliseconds(seconds, &milliseconds));
PD_CHECK_OVERFLOW(
checked_int64_add(milliseconds, dts->us / 1000, &milliseconds));
PD_CHECK_OVERFLOW(checked_add(milliseconds, dts->us / 1000, &milliseconds));

return milliseconds;
}

int64_t microseconds;
PD_CHECK_OVERFLOW(scaleSecondsToMicroseconds(seconds, &microseconds));
PD_CHECK_OVERFLOW(checked_int64_add(microseconds, dts->us, &microseconds));
PD_CHECK_OVERFLOW(checked_add(microseconds, dts->us, &microseconds));

if (base == NPY_FR_us) {
return microseconds;
Expand All @@ -499,21 +470,20 @@ npy_datetime npy_datetimestruct_to_datetime(NPY_DATETIMEUNIT base,
if (microseconds == min_nanoseconds / 1000 - 1) {
// For values within one microsecond of min_nanoseconds, use it as base
// and offset it with nanosecond delta to avoid overflow during scaling.
PD_CHECK_OVERFLOW(checked_int64_add(
PD_CHECK_OVERFLOW(checked_add(
min_nanoseconds, (dts->ps - _NS_MIN_DTS.ps) / 1000, &nanoseconds));
} else {
PD_CHECK_OVERFLOW(
scaleMicrosecondsToNanoseconds(microseconds, &nanoseconds));
PD_CHECK_OVERFLOW(
checked_int64_add(nanoseconds, dts->ps / 1000, &nanoseconds));
PD_CHECK_OVERFLOW(checked_add(nanoseconds, dts->ps / 1000, &nanoseconds));
}

return nanoseconds;
}

int64_t picoseconds;
PD_CHECK_OVERFLOW(scaleMicrosecondsToPicoseconds(microseconds, &picoseconds));
PD_CHECK_OVERFLOW(checked_int64_add(picoseconds, dts->ps, &picoseconds));
PD_CHECK_OVERFLOW(checked_add(picoseconds, dts->ps, &picoseconds));

if (base == NPY_FR_ps) {
return picoseconds;
Expand All @@ -523,15 +493,14 @@ npy_datetime npy_datetimestruct_to_datetime(NPY_DATETIMEUNIT base,
int64_t femtoseconds;
PD_CHECK_OVERFLOW(
scalePicosecondsToFemtoseconds(picoseconds, &femtoseconds));
PD_CHECK_OVERFLOW(
checked_int64_add(femtoseconds, dts->as / 1000, &femtoseconds));
PD_CHECK_OVERFLOW(checked_add(femtoseconds, dts->as / 1000, &femtoseconds));
return femtoseconds;
}

if (base == NPY_FR_as) {
int64_t attoseconds;
PD_CHECK_OVERFLOW(scalePicosecondsToAttoseconds(picoseconds, &attoseconds));
PD_CHECK_OVERFLOW(checked_int64_add(attoseconds, dts->as, &attoseconds));
PD_CHECK_OVERFLOW(checked_add(attoseconds, dts->as, &attoseconds));
return attoseconds;
}

Expand Down
Loading