Assorted UBSAN cleanups (#55112) · pandas-dev/pandas@f00efd0 (original) (raw)
1
``
`-
cimport cython
`
2
1
`from cpython.datetime cimport (
`
3
2
` PyDateTime_CheckExact,
`
4
3
` PyDateTime_DATE_GET_HOUR,
`
`@@ -18,6 +17,7 @@ from cpython.object cimport (
`
18
17
` Py_LT,
`
19
18
` Py_NE,
`
20
19
`)
`
``
20
`+
from libc.stdint cimport INT64_MAX
`
21
21
``
22
22
`import_datetime()
`
23
23
`PandasDateTime_IMPORT
`
`@@ -545,14 +545,14 @@ cdef ndarray astype_round_check(
`
545
545
`return iresult
`
546
546
``
547
547
``
548
``
`-
@cython.overflowcheck(True)
`
549
548
`cdef int64_t get_conversion_factor(
`
550
549
` NPY_DATETIMEUNIT from_unit,
`
551
550
` NPY_DATETIMEUNIT to_unit
`
552
551
`) except? -1:
`
553
552
`"""
`
554
553
` Find the factor by which we need to multiply to convert from from_unit to to_unit.
`
555
554
`"""
`
``
555
`+
cdef int64_t value, overflow_limit, factor
`
556
556
`if (
`
557
557
` from_unit == NPY_DATETIMEUNIT.NPY_FR_GENERIC
`
558
558
`or to_unit == NPY_DATETIMEUNIT.NPY_FR_GENERIC
`
`@@ -565,28 +565,44 @@ cdef int64_t get_conversion_factor(
`
565
565
`return 1
`
566
566
``
567
567
`if from_unit == NPY_DATETIMEUNIT.NPY_FR_W:
`
568
``
`-
return 7 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_D, to_unit)
`
``
568
`+
value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_D, to_unit)
`
``
569
`+
factor = 7
`
569
570
`elif from_unit == NPY_DATETIMEUNIT.NPY_FR_D:
`
570
``
`-
return 24 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_h, to_unit)
`
``
571
`+
value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_h, to_unit)
`
``
572
`+
factor = 24
`
571
573
`elif from_unit == NPY_DATETIMEUNIT.NPY_FR_h:
`
572
``
`-
return 60 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_m, to_unit)
`
``
574
`+
value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_m, to_unit)
`
``
575
`+
factor = 60
`
573
576
`elif from_unit == NPY_DATETIMEUNIT.NPY_FR_m:
`
574
``
`-
return 60 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_s, to_unit)
`
``
577
`+
value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_s, to_unit)
`
``
578
`+
factor = 60
`
575
579
`elif from_unit == NPY_DATETIMEUNIT.NPY_FR_s:
`
576
``
`-
return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_ms, to_unit)
`
``
580
`+
value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_ms, to_unit)
`
``
581
`+
factor = 1000
`
577
582
`elif from_unit == NPY_DATETIMEUNIT.NPY_FR_ms:
`
578
``
`-
return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_us, to_unit)
`
``
583
`+
value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_us, to_unit)
`
``
584
`+
factor = 1000
`
579
585
`elif from_unit == NPY_DATETIMEUNIT.NPY_FR_us:
`
580
``
`-
return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_ns, to_unit)
`
``
586
`+
value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_ns, to_unit)
`
``
587
`+
factor = 1000
`
581
588
`elif from_unit == NPY_DATETIMEUNIT.NPY_FR_ns:
`
582
``
`-
return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_ps, to_unit)
`
``
589
`+
value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_ps, to_unit)
`
``
590
`+
factor = 1000
`
583
591
`elif from_unit == NPY_DATETIMEUNIT.NPY_FR_ps:
`
584
``
`-
return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_fs, to_unit)
`
``
592
`+
value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_fs, to_unit)
`
``
593
`+
factor = 1000
`
585
594
`elif from_unit == NPY_DATETIMEUNIT.NPY_FR_fs:
`
586
``
`-
return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_as, to_unit)
`
``
595
`+
value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_as, to_unit)
`
``
596
`+
factor = 1000
`
587
597
`else:
`
588
598
`raise ValueError("Converting from M or Y units is not supported.")
`
589
599
``
``
600
`+
overflow_limit = INT64_MAX // factor
`
``
601
`+
if value > overflow_limit or value < -overflow_limit:
`
``
602
`+
raise OverflowError("result would overflow")
`
``
603
+
``
604
`+
return factor * value
`
``
605
+
590
606
``
591
607
`cdef int64_t convert_reso(
`
592
608
` int64_t value,
`
`@@ -595,7 +611,7 @@ cdef int64_t convert_reso(
`
595
611
` bint round_ok,
`
596
612
`) except? -1:
`
597
613
` cdef:
`
598
``
`-
int64_t res_value, mult, div, mod
`
``
614
`+
int64_t res_value, mult, div, mod, overflow_limit
`
599
615
``
600
616
`if from_reso == to_reso:
`
601
617
`return value
`
`@@ -624,9 +640,12 @@ cdef int64_t convert_reso(
`
624
640
`else:
`
625
641
`# e.g. ns -> us, risk of overflow, but no risk of lossy rounding
`
626
642
` mult = get_conversion_factor(from_reso, to_reso)
`
627
``
`-
with cython.overflowcheck(True):
`
``
643
`+
overflow_limit = INT64_MAX // mult
`
``
644
`+
if value > overflow_limit or value < -overflow_limit:
`
628
645
`# Note: caller is responsible for re-raising as OutOfBoundsTimedelta
`
629
``
`-
res_value = value * mult
`
``
646
`+
raise OverflowError("result would overflow")
`
``
647
+
``
648
`+
res_value = value * mult
`
630
649
``
631
650
`return res_value
`
632
651
``