Skip to content

Commit dfcf135

Browse files
vitaly-burovoyelprans
authored andcommitted
Correct boundaries check for int; raise OverflowError for such cases
Since there is no error in a value representation and PyLong_AsLong(-Long) raises exactly that exception if the value exceed the destination range, it should be OverflowError instead of ValueError. Also make error message be similar to one from the original OverflowError raised by PyLong_AsLong.
1 parent e082910 commit dfcf135

File tree

2 files changed

+59
-9
lines changed

2 files changed

+59
-9
lines changed

asyncpg/protocol/codecs/int.pyx

+40-8
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,17 @@ cdef bool_decode(ConnectionSettings settings, FastReadBuffer buf):
1919

2020

2121
cdef int2_encode(ConnectionSettings settings, WriteBuffer buf, obj):
22-
cdef long val = cpython.PyLong_AsLong(obj)
23-
if val < -32768 or val > 32767:
24-
raise ValueError(
25-
'integer too large to be encoded as INT2: {!r}'.format(val))
22+
cdef int overflow = 0
23+
cdef long val
24+
25+
try:
26+
val = cpython.PyLong_AsLong(obj)
27+
except OverflowError:
28+
overflow = 1
29+
30+
if overflow or val < -32768 or val > 32767:
31+
raise OverflowError(
32+
'int too big to be encoded as INT2: {!r}'.format(obj))
2633

2734
buf.write_int32(2)
2835
buf.write_int16(<int16_t>val)
@@ -33,20 +40,45 @@ cdef int2_decode(ConnectionSettings settings, FastReadBuffer buf):
3340

3441

3542
cdef int4_encode(ConnectionSettings settings, WriteBuffer buf, obj):
36-
cdef int32_t val = <int32_t>cpython.PyLong_AsLong(obj)
43+
cdef int overflow = 0
44+
cdef long val
45+
46+
try:
47+
val = cpython.PyLong_AsLong(obj)
48+
except OverflowError:
49+
overflow = 1
50+
51+
# "long" and "long long" have the same size for x86_64, need an extra check
52+
if overflow or (sizeof(val) > 4 and (val < -2147483648 or
53+
val > 2147483647)):
54+
raise OverflowError(
55+
'int too big to be encoded as INT4: {!r}'.format(obj))
3756

3857
buf.write_int32(4)
39-
buf.write_int32(val)
58+
buf.write_int32(<int32_t>val)
4059

4160

4261
cdef int4_decode(ConnectionSettings settings, FastReadBuffer buf):
4362
return cpython.PyLong_FromLong(hton.unpack_int32(buf.read(4)))
4463

4564

4665
cdef int8_encode(ConnectionSettings settings, WriteBuffer buf, obj):
47-
cdef int64_t val = cpython.PyLong_AsLongLong(obj)
66+
cdef int overflow = 0
67+
cdef long long val
68+
69+
try:
70+
val = cpython.PyLong_AsLongLong(obj)
71+
except OverflowError:
72+
overflow = 1
73+
74+
# Just in case for systems with "long long" bigger than 8 bytes
75+
if overflow or (sizeof(val) > 8 and (val < -9223372036854775808 or
76+
val > 9223372036854775807)):
77+
raise OverflowError(
78+
'int too big to be encoded as INT8: {!r}'.format(obj))
79+
4880
buf.write_int32(8)
49-
buf.write_int64(val)
81+
buf.write_int64(<int64_t>val)
5082

5183

5284
cdef int8_decode(ConnectionSettings settings, FastReadBuffer buf):

tests/test_codecs.py

+19-1
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,11 @@ async def test_invalid_input(self):
472472
'2',
473473
'aa',
474474
]),
475-
('smallint', ValueError, 'integer too large', [
475+
('smallint', OverflowError, 'int too big to be encoded as INT2', [
476+
2**256, # check for the same exception for any big numbers
477+
decimal.Decimal("2000000000000000000000000000000"),
478+
0xffff,
479+
0xffffffff,
476480
32768,
477481
-32769
478482
]),
@@ -484,10 +488,24 @@ async def test_invalid_input(self):
484488
'2',
485489
'aa',
486490
]),
491+
('int', OverflowError, 'int too big to be encoded as INT4', [
492+
2**256, # check for the same exception for any big numbers
493+
decimal.Decimal("2000000000000000000000000000000"),
494+
0xffffffff,
495+
2**31,
496+
-2**31 - 1,
497+
]),
487498
('int8', TypeError, 'an integer is required', [
488499
'2',
489500
'aa',
490501
]),
502+
('bigint', OverflowError, 'int too big to be encoded as INT8', [
503+
2**256, # check for the same exception for any big numbers
504+
decimal.Decimal("2000000000000000000000000000000"),
505+
0xffffffffffffffff,
506+
2**63,
507+
-2**63 - 1,
508+
]),
491509
('text', TypeError, 'expected str, got bytes', [
492510
b'foo'
493511
]),

0 commit comments

Comments
 (0)