aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/tid.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2022-03-03 20:03:47 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2022-03-03 20:04:35 -0500
commitf7ea240aa7491b6ed2985bb50888bd432f3341df (patch)
tree87d14901c88ddb3457c63af8264579e50b5f1188 /src/backend/utils/adt/tid.c
parentb3c8aae00850384b1cec5311eb1864e2f5e80a44 (diff)
downloadpostgresql-f7ea240aa7491b6ed2985bb50888bd432f3341df.tar.gz
postgresql-f7ea240aa7491b6ed2985bb50888bd432f3341df.zip
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
Diffstat (limited to 'src/backend/utils/adt/tid.c')
-rw-r--r--src/backend/utils/adt/tid.c28
1 files changed, 21 insertions, 7 deletions
diff --git a/src/backend/utils/adt/tid.c b/src/backend/utils/adt/tid.c
index dcc1620afbd..83ac589f957 100644
--- a/src/backend/utils/adt/tid.c
+++ b/src/backend/utils/adt/tid.c
@@ -64,10 +64,10 @@ tidin(PG_FUNCTION_ARGS)
BlockNumber blockNumber;
OffsetNumber offsetNumber;
char *badp;
- int hold_offset;
+ unsigned long cvt;
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;
if (i < NTIDARGS)
@@ -77,22 +77,36 @@ tidin(PG_FUNCTION_ARGS)
"tid", str)));
errno = 0;
- blockNumber = strtoul(coord[0], &badp, 10);
+ cvt = strtoul(coord[0], &badp, 10);
if (errno || *badp != DELIM)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"tid", str)));
+ blockNumber = (BlockNumber) cvt;
- hold_offset = strtol(coord[1], &badp, 10);
- if (errno || *badp != RDELIM ||
- hold_offset > USHRT_MAX || hold_offset < 0)
+ /*
+ * Cope with possibility that unsigned long is wider than BlockNumber, in
+ * 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,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"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));