Skip to content

Commit f7ea240

Browse files
committed
Tighten overflow checks in tidin().
This code seems to have been written on the assumption that "unsigned long" is 32 bits; or at any rate it ignored the possibility of conversion overflow. Rewrite, borrowing some logic from oidin(). Discussion: https://postgr.es/m/[email protected]
1 parent b3c8aae commit f7ea240

File tree

3 files changed

+52
-7
lines changed

3 files changed

+52
-7
lines changed

src/backend/utils/adt/tid.c

+21-7
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ tidin(PG_FUNCTION_ARGS)
6464
BlockNumber blockNumber;
6565
OffsetNumber offsetNumber;
6666
char *badp;
67-
int hold_offset;
67+
unsigned long cvt;
6868

6969
for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
70-
if (*p == DELIM || (*p == LDELIM && !i))
70+
if (*p == DELIM || (*p == LDELIM && i == 0))
7171
coord[i++] = p + 1;
7272

7373
if (i < NTIDARGS)
@@ -77,22 +77,36 @@ tidin(PG_FUNCTION_ARGS)
7777
"tid", str)));
7878

7979
errno = 0;
80-
blockNumber = strtoul(coord[0], &badp, 10);
80+
cvt = strtoul(coord[0], &badp, 10);
8181
if (errno || *badp != DELIM)
8282
ereport(ERROR,
8383
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
8484
errmsg("invalid input syntax for type %s: \"%s\"",
8585
"tid", str)));
86+
blockNumber = (BlockNumber) cvt;
8687

87-
hold_offset = strtol(coord[1], &badp, 10);
88-
if (errno || *badp != RDELIM ||
89-
hold_offset > USHRT_MAX || hold_offset < 0)
88+
/*
89+
* Cope with possibility that unsigned long is wider than BlockNumber, in
90+
* which case strtoul will not raise an error for some values that are out
91+
* of the range of BlockNumber. (See similar code in oidin().)
92+
*/
93+
#if SIZEOF_LONG > 4
94+
if (cvt != (unsigned long) blockNumber &&
95+
cvt != (unsigned long) ((int32) blockNumber))
9096
ereport(ERROR,
9197
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
9298
errmsg("invalid input syntax for type %s: \"%s\"",
9399
"tid", str)));
100+
#endif
94101

95-
offsetNumber = hold_offset;
102+
cvt = strtoul(coord[1], &badp, 10);
103+
if (errno || *badp != RDELIM ||
104+
cvt > USHRT_MAX)
105+
ereport(ERROR,
106+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
107+
errmsg("invalid input syntax for type %s: \"%s\"",
108+
"tid", str)));
109+
offsetNumber = (OffsetNumber) cvt;
96110

97111
result = (ItemPointer) palloc(sizeof(ItemPointerData));
98112

src/test/regress/expected/tid.out

+19
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
-- basic tests for the TID data type
2+
SELECT
3+
'(0,0)'::tid as tid00,
4+
'(0,1)'::tid as tid01,
5+
'(-1,0)'::tid as tidm10,
6+
'(4294967295,65535)'::tid as tidmax;
7+
tid00 | tid01 | tidm10 | tidmax
8+
-------+-------+----------------+--------------------
9+
(0,0) | (0,1) | (4294967295,0) | (4294967295,65535)
10+
(1 row)
11+
12+
SELECT '(4294967296,1)'::tid; -- error
13+
ERROR: invalid input syntax for type tid: "(4294967296,1)"
14+
LINE 1: SELECT '(4294967296,1)'::tid;
15+
^
16+
SELECT '(1,65536)'::tid; -- error
17+
ERROR: invalid input syntax for type tid: "(1,65536)"
18+
LINE 1: SELECT '(1,65536)'::tid;
19+
^
120
-- tests for functions related to TID handling
221
CREATE TABLE tid_tab (a int);
322
-- min() and max() for TIDs

src/test/regress/sql/tid.sql

+12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
-- basic tests for the TID data type
2+
3+
SELECT
4+
'(0,0)'::tid as tid00,
5+
'(0,1)'::tid as tid01,
6+
'(-1,0)'::tid as tidm10,
7+
'(4294967295,65535)'::tid as tidmax;
8+
9+
SELECT '(4294967296,1)'::tid; -- error
10+
SELECT '(1,65536)'::tid; -- error
11+
12+
113
-- tests for functions related to TID handling
214

315
CREATE TABLE tid_tab (a int);

0 commit comments

Comments
 (0)