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/3441768.1646343914@sss.pgh.pa.us
This commit is contained in:
Tom Lane 2022-03-03 20:03:47 -05:00
parent b3c8aae008
commit f7ea240aa7
3 changed files with 52 additions and 7 deletions

View File

@ -64,10 +64,10 @@ tidin(PG_FUNCTION_ARGS)
BlockNumber blockNumber; BlockNumber blockNumber;
OffsetNumber offsetNumber; OffsetNumber offsetNumber;
char *badp; char *badp;
int hold_offset; unsigned long cvt;
for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++) for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
if (*p == DELIM || (*p == LDELIM && !i)) if (*p == DELIM || (*p == LDELIM && i == 0))
coord[i++] = p + 1; coord[i++] = p + 1;
if (i < NTIDARGS) if (i < NTIDARGS)
@ -77,22 +77,36 @@ tidin(PG_FUNCTION_ARGS)
"tid", str))); "tid", str)));
errno = 0; errno = 0;
blockNumber = strtoul(coord[0], &badp, 10); cvt = strtoul(coord[0], &badp, 10);
if (errno || *badp != DELIM) if (errno || *badp != DELIM)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"", errmsg("invalid input syntax for type %s: \"%s\"",
"tid", str))); "tid", str)));
blockNumber = (BlockNumber) cvt;
hold_offset = strtol(coord[1], &badp, 10); /*
if (errno || *badp != RDELIM || * Cope with possibility that unsigned long is wider than BlockNumber, in
hold_offset > USHRT_MAX || hold_offset < 0) * which case strtoul will not raise an error for some values that are out
* of the range of BlockNumber. (See similar code in oidin().)
*/
#if SIZEOF_LONG > 4
if (cvt != (unsigned long) blockNumber &&
cvt != (unsigned long) ((int32) blockNumber))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"", errmsg("invalid input syntax for type %s: \"%s\"",
"tid", str))); "tid", str)));
#endif
offsetNumber = hold_offset; cvt = strtoul(coord[1], &badp, 10);
if (errno || *badp != RDELIM ||
cvt > USHRT_MAX)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"tid", str)));
offsetNumber = (OffsetNumber) cvt;
result = (ItemPointer) palloc(sizeof(ItemPointerData)); result = (ItemPointer) palloc(sizeof(ItemPointerData));

View File

@ -1,3 +1,22 @@
-- basic tests for the TID data type
SELECT
'(0,0)'::tid as tid00,
'(0,1)'::tid as tid01,
'(-1,0)'::tid as tidm10,
'(4294967295,65535)'::tid as tidmax;
tid00 | tid01 | tidm10 | tidmax
-------+-------+----------------+--------------------
(0,0) | (0,1) | (4294967295,0) | (4294967295,65535)
(1 row)
SELECT '(4294967296,1)'::tid; -- error
ERROR: invalid input syntax for type tid: "(4294967296,1)"
LINE 1: SELECT '(4294967296,1)'::tid;
^
SELECT '(1,65536)'::tid; -- error
ERROR: invalid input syntax for type tid: "(1,65536)"
LINE 1: SELECT '(1,65536)'::tid;
^
-- tests for functions related to TID handling -- tests for functions related to TID handling
CREATE TABLE tid_tab (a int); CREATE TABLE tid_tab (a int);
-- min() and max() for TIDs -- min() and max() for TIDs

View File

@ -1,3 +1,15 @@
-- basic tests for the TID data type
SELECT
'(0,0)'::tid as tid00,
'(0,1)'::tid as tid01,
'(-1,0)'::tid as tidm10,
'(4294967295,65535)'::tid as tidmax;
SELECT '(4294967296,1)'::tid; -- error
SELECT '(1,65536)'::tid; -- error
-- tests for functions related to TID handling -- tests for functions related to TID handling
CREATE TABLE tid_tab (a int); CREATE TABLE tid_tab (a int);