Hi,

The attached patch replaces sscanf with strtol and strtoul in the
ImportSnapshot helpers (parseIntFromText, parseXidFromText, and
parseVxidFromText) to improve reliability and efficiency. By utilizing
the end pointer, we can locate the next line without re-scanning the
entire string.

Additionally, this change aligns the snapshot code with the rest of
the Postgres backend, which already favors these functions for safer
parsing.

--
Regards,
Amul Sul
EDB: http://www.enterprisedb.com
From 9869b9f19775de7d13f1bada5db5d8f14bf20859 Mon Sep 17 00:00:00 2001
From: Amul Sul <[email protected]>
Date: Mon, 20 Apr 2026 10:21:28 +0530
Subject: [PATCH] snapmgr: replace sscanf with strtol/strtoul in snapshot parse
 helpers

parseIntFromText, parseXidFromText, and parseVxidFromText used sscanf
to convert digit strings to integers.  Replace with strtol/strtoul,
which provide explicit overflow detection and advance the end-pointer
directly, avoiding a redundant strchr scan over the already-parsed
digits.
---
 src/backend/utils/time/snapmgr.c | 45 +++++++++++++++++++++++++-------
 1 file changed, 35 insertions(+), 10 deletions(-)

diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index 10fe18df2e7..20b8421b881 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -1308,24 +1308,27 @@ parseIntFromText(const char *prefix, char **s, const char *filename)
 {
 	char	   *ptr = *s;
 	int			prefixlen = strlen(prefix);
-	int			val;
+	long		val;
+	char	   *endptr;
 
 	if (strncmp(ptr, prefix, prefixlen) != 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid snapshot data in file \"%s\"", filename)));
 	ptr += prefixlen;
-	if (sscanf(ptr, "%d", &val) != 1)
+	errno = 0;
+	val = strtol(ptr, &endptr, 10);
+	if (endptr == ptr || errno != 0 || val < INT_MIN || val > INT_MAX)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid snapshot data in file \"%s\"", filename)));
-	ptr = strchr(ptr, '\n');
+	ptr = strchr(endptr, '\n');
 	if (!ptr)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid snapshot data in file \"%s\"", filename)));
 	*s = ptr + 1;
-	return val;
+	return (int) val;
 }
 
 static TransactionId
@@ -1333,24 +1336,27 @@ parseXidFromText(const char *prefix, char **s, const char *filename)
 {
 	char	   *ptr = *s;
 	int			prefixlen = strlen(prefix);
-	TransactionId val;
+	unsigned long val;
+	char	   *endptr;
 
 	if (strncmp(ptr, prefix, prefixlen) != 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid snapshot data in file \"%s\"", filename)));
 	ptr += prefixlen;
-	if (sscanf(ptr, "%u", &val) != 1)
+	errno = 0;
+	val = strtoul(ptr, &endptr, 10);
+	if (endptr == ptr || errno != 0 || val > UINT_MAX)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid snapshot data in file \"%s\"", filename)));
-	ptr = strchr(ptr, '\n');
+	ptr = strchr(endptr, '\n');
 	if (!ptr)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid snapshot data in file \"%s\"", filename)));
 	*s = ptr + 1;
-	return val;
+	return (TransactionId) val;
 }
 
 static void
@@ -1359,17 +1365,36 @@ parseVxidFromText(const char *prefix, char **s, const char *filename,
 {
 	char	   *ptr = *s;
 	int			prefixlen = strlen(prefix);
+	long		lval;
+	unsigned long ulval;
+	char	   *endptr;
 
 	if (strncmp(ptr, prefix, prefixlen) != 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid snapshot data in file \"%s\"", filename)));
 	ptr += prefixlen;
-	if (sscanf(ptr, "%d/%u", &vxid->procNumber, &vxid->localTransactionId) != 2)
+
+	/* Parse procNumber (the signed integer before '/') */
+	errno = 0;
+	lval = strtol(ptr, &endptr, 10);
+	if (endptr == ptr || errno != 0 || lval < INT_MIN || lval > INT_MAX ||
+		*endptr != '/')
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid snapshot data in file \"%s\"", filename)));
-	ptr = strchr(ptr, '\n');
+	vxid->procNumber = (ProcNumber) lval;
+	ptr = endptr + 1;			/* skip the '/' separator */
+
+	/* Parse localTransactionId (the unsigned integer after '/') */
+	errno = 0;
+	ulval = strtoul(ptr, &endptr, 10);
+	if (endptr == ptr || errno != 0 || ulval > UINT_MAX)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+				 errmsg("invalid snapshot data in file \"%s\"", filename)));
+	vxid->localTransactionId = (LocalTransactionId) ulval;
+	ptr = strchr(endptr, '\n');
 	if (!ptr)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-- 
2.47.1

Reply via email to