summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>2017-02-24 13:03:54 +0000
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>2017-02-24 13:23:56 +0000
commit691df4952ba9132f6af012f021c0db04c8681d9e (patch)
treec60bf3f3cf3561a8a3c784d808923d7b787e462e
parent3b665d35d5948eab4f3001eb2e2c1f8810e10905 (diff)
downloadpsycopg2-691df4952ba9132f6af012f021c0db04c8681d9e.tar.gz
Handle overflow in interval parsing
-rw-r--r--psycopg/typecast_datetime.c16
-rwxr-xr-xtests/test_dates.py18
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'):