Description
noncompliant02.py code example in the README.md does not match the file and is also doing the wrong thing.
# current code in 02.py:
currtime = [tm for tm in time.localtime()]
print(currtime)
# here what it does:
currtime = [print(tm) for tm in time.localtime()]
# here what it should be doing to add hours:
currtime = [print(tm) for tm in time.localtime().tm_hour]
All x02 code examples would not work when given a input within range such as 12
hours in the future starting from 11:28 ends in ValueError: hour out of range
.
the code in the noncompliant02.py
file is closer to reality but very obscure the actually issue occurs when using time.asctime()
alternative example02.py
code:
# SPDX-FileCopyrightText: OpenSSF project contributors
# SPDX-License-Identifier: MIT
"""Compliant Code Example"""
from datetime import datetime, timedelta
import re
import sys
def get_time_in_future(hours_in_future: int):
"""Gets the time n hours in the future"""
# TODO: input sanitation
# TODO: proper logging
currtime = datetime.now()
return currtime + timedelta(hours=hours_in_future)
#####################
# attempting to exploit above code example
#####################
print("-------- adding 23**5 ---------")
print(get_time_in_future(23**5))
print("=" * 60)
print("-------- adding 23**74 ---------")
print(get_time_in_future(23**74))
Example output:
-------- adding 23**5 ---------
2759-06-28 14:59:08.021771
============================================================
-------- adding 23**74 ---------
Traceback (most recent call last):
File "example02.py", line 26, in <module>
print(get_time_in_future(23**74))
File "example02.py", line 16, in get_time_in_future
return currtime + timedelta(hours=hours_in_future)
OverflowError: Python int too large to convert to C int
Once cleaned up we end up with re-throwing.
That is a unsatisfactory as a compliant solution. Naturally we should be guarding boundaries before we hit them. There are a few of those:
from datetime import datetime, timedelta
sometime = datetime.fromtimestamp(0)
hours_list = [
70389526,
70389527,
24000000001,
51539700001,
-17259889,
-17259890,
-23999999999,
-51539699999,
]
for hours in hours_list:
try:
result = sometime + timedelta(hours=hours)
print(f"{hours} OK, datetime='{result}'")
except Exception as exception:
print(f"{hours} {repr(exception)}")
example output:
70389526 OK, datetime='9999-12-31 23:00:00'
70389527 OverflowError('date value out of range')
24000000001 OverflowError('days=1000000000; must have magnitude <= 999999999')
51539700001 OverflowError('Python int too large to convert to C int')
-17259889 OK, datetime='0001-01-01 00:00:00'
-17259890 OverflowError('date value out of range')
-23999999999 OverflowError('days=-1000000000; must have magnitude <= 999999999')
-51539699999 OverflowError('Python int too large to convert to C int')
Specifically:
date value out of range
OverflowError('Python int too large to convert to C int')
'days=1000000000; must have magnitude <= 999999999')
Unfortunately the first date value out of range
is a moving target that changes according to start datetime in use. When we start with datetime.fromtimestamp(0)
or '1970-01-01 01:00:00we have the 'date value out of range' in beyond
-17259889and
70389526`. Those numbers change depending on the datetime we start with.
The Python int too large to convert to C int
beyond -23999999999
and 24000000001
is more predictable.