diff options
author | Daniele Varrazzo <daniele.varrazzo@gmail.com> | 2017-02-24 13:03:54 +0000 |
---|---|---|
committer | Daniele Varrazzo <daniele.varrazzo@gmail.com> | 2017-02-24 13:23:56 +0000 |
commit | 691df4952ba9132f6af012f021c0db04c8681d9e (patch) | |
tree | c60bf3f3cf3561a8a3c784d808923d7b787e462e | |
parent | 3b665d35d5948eab4f3001eb2e2c1f8810e10905 (diff) | |
download | psycopg2-691df4952ba9132f6af012f021c0db04c8681d9e.tar.gz |
Handle overflow in interval parsing
-rw-r--r-- | psycopg/typecast_datetime.c | 16 | ||||
-rwxr-xr-x | tests/test_dates.py | 18 |
2 files changed, 32 insertions, 2 deletions
diff --git a/psycopg/typecast_datetime.c b/psycopg/typecast_datetime.c index 29406c1..a833d86 100644 --- a/psycopg/typecast_datetime.c +++ b/psycopg/typecast_datetime.c @@ -237,7 +237,19 @@ typecast_PYINTERVAL_cast(const char *str, Py_ssize_t len, PyObject *curs) case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - v = v * 10 + (*str - '0'); + { + long v1; + v1 = v * 10 + (*str - '0'); + /* detect either a rollover, happening if v is really too short, + * or too big value. On Win where long == int the 2nd check + * is useless. */ + if (v1 < v || v1 > (long)INT_MAX) { + PyErr_SetString( + PyExc_OverflowError, "interval component too big"); + return NULL; + } + v = v1; + } if (part == 6) { denom *= 10; } @@ -308,7 +320,7 @@ typecast_PYINTERVAL_cast(const char *str, Py_ssize_t len, PyObject *curs) } while (denom < 1000000L); } else if (denom > 1000000L) { - micros = (long)((double)micros * 1000000.0 / denom); + micros = (long)round((double)micros / denom * 1000000.0); } } diff --git a/tests/test_dates.py b/tests/test_dates.py index bffd05d..9b71905 100755 --- a/tests/test_dates.py +++ b/tests/test_dates.py @@ -373,6 +373,24 @@ class DatetimeTests(ConnectingTestCase, CommonDatetimeTestsMixin): t = self.execute("select '0.0000006'::interval") self.assertEqual(total_seconds(t), 1e-6) + def test_interval_overflow(self): + cur = self.conn.cursor() + # hack a cursor to receive values too extreme to be represented + # but still I want an error, not a random number + psycopg2.extensions.register_type( + psycopg2.extensions.new_type( + psycopg2.STRING.values, 'WAT', psycopg2.extensions.INTERVAL), + cur) + + def f(val): + cur.execute("select '%s'::text" % val) + return cur.fetchone()[0] + + self.assertRaises(OverflowError, f, '100000000000000000:00:00') + self.assertRaises(OverflowError, f, '00:100000000000000000:00:00') + self.assertRaises(OverflowError, f, '00:00:100000000000000000:00') + self.assertRaises(OverflowError, f, '00:00:00.100000000000000000') + # Only run the datetime tests if psycopg was compiled with support. if not hasattr(psycopg2.extensions, 'PYDATETIME'): |