improve_parse_snapshot_filename.patch

application/octet-stream

Filename: improve_parse_snapshot_filename.patch
Type: application/octet-stream
Part: 0
Message: Re: BUG #18828: Crash when pg_get_logical_snapshot_meta() passed empty string

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
File+
contrib/pg_logicalinspect/expected/pg_logicalinspect.out 6 0
contrib/pg_logicalinspect/pg_logicalinspect.c 15 21
contrib/pg_logicalinspect/sql/pg_logicalinspect.sql 3 0
diff --git a/contrib/pg_logicalinspect/expected/pg_logicalinspect.out b/contrib/pg_logicalinspect/expected/pg_logicalinspect.out
index f1f0712bec2..f6c9b625d6b 100644
--- a/contrib/pg_logicalinspect/expected/pg_logicalinspect.out
+++ b/contrib/pg_logicalinspect/expected/pg_logicalinspect.out
@@ -4,6 +4,10 @@ CREATE EXTENSION pg_logicalinspect;
 -- ===================================================================
 SELECT pg_get_logical_snapshot_info('0-40796E18.foo');
 ERROR:  invalid snapshot file name "0-40796E18.foo"
+SELECT pg_get_logical_snapshot_info('0--40796E18.snap');
+ERROR:  invalid snapshot file name "0--40796E18.snap"
+SELECT pg_get_logical_snapshot_info('-1--40796E18.snap');
+ERROR:  invalid snapshot file name "-1--40796E18.snap"
 SELECT pg_get_logical_snapshot_info('0/40796E18.foo.snap');
 ERROR:  invalid snapshot file name "0/40796E18.foo.snap"
 SELECT pg_get_logical_snapshot_info('0/40796E18.snap');
@@ -18,6 +22,8 @@ SELECT pg_get_logical_snapshot_info(NULL);
 
 SELECT pg_get_logical_snapshot_info('../snapshots');
 ERROR:  invalid snapshot file name "../snapshots"
+SELECT pg_get_logical_snapshot_info('../snapshots/0-40796E18.snap');
+ERROR:  invalid snapshot file name "../snapshots/0-40796E18.snap"
 SELECT pg_get_logical_snapshot_meta('0-40796E18.foo');
 ERROR:  invalid snapshot file name "0-40796E18.foo"
 SELECT pg_get_logical_snapshot_meta('0-40796E18.foo.snap');
diff --git a/contrib/pg_logicalinspect/pg_logicalinspect.c b/contrib/pg_logicalinspect/pg_logicalinspect.c
index 57bc622f06b..dea3d0d5d3c 100644
--- a/contrib/pg_logicalinspect/pg_logicalinspect.c
+++ b/contrib/pg_logicalinspect/pg_logicalinspect.c
@@ -52,38 +52,32 @@ get_snapbuild_state_desc(SnapBuildState state)
  * Extract the LSN from the given serialized snapshot file name.
  */
 static XLogRecPtr
-parse_snapshot_filename(const char *filename)
+parse_snapshot_filename(char *filename)
 {
 	uint32		hi;
 	uint32		lo;
 	XLogRecPtr	lsn;
-	bool		report_error = false;
+	char		tmpfname[MAXPGPATH];
 
 	/* Extract the values to build the LSN */
-	if (sscanf(filename, "%X-%X", &hi, &lo) != 2)
-		report_error = true;
+	if (sscanf(filename, "%X-%X.snap", &hi, &lo) != 2)
+		goto parse_error;
 
-	/* Ensure filename is %X-%X.snap */
-	if (!report_error)
-	{
-		size_t		buffer_size = strlen(filename) + 1;
-		char	   *buffer = palloc(buffer_size);
-
-		snprintf(buffer, buffer_size, "%X-%X.snap", hi, lo);
-
-		if (strcmp(buffer, filename) != 0)
-			report_error = true;
-
-		pfree(buffer);
-	}
-
-	if (report_error)
-		ereport(ERROR,
-				errmsg("invalid snapshot file name \"%s\"", filename));
+	/*
+	 * Bring back the LSN to the snapshot file format and compare
+	 * it to  the given name to see if the extracted LSN is sane.
+	 */
+	sprintf(tmpfname, "%X-%X.snap", hi, lo);
+	if (strcmp(tmpfname, filename) != 0)
+		goto parse_error;
 
 	lsn = ((uint64) hi) << 32 | lo;
 
 	return lsn;
+
+parse_error:
+	ereport(ERROR,
+			errmsg("invalid snapshot file name \"%s\"", filename));
 }
 
 /*
diff --git a/contrib/pg_logicalinspect/sql/pg_logicalinspect.sql b/contrib/pg_logicalinspect/sql/pg_logicalinspect.sql
index 7d4951f30b0..143cf45dc12 100644
--- a/contrib/pg_logicalinspect/sql/pg_logicalinspect.sql
+++ b/contrib/pg_logicalinspect/sql/pg_logicalinspect.sql
@@ -5,11 +5,14 @@ CREATE EXTENSION pg_logicalinspect;
 -- ===================================================================
 
 SELECT pg_get_logical_snapshot_info('0-40796E18.foo');
+SELECT pg_get_logical_snapshot_info('0--40796E18.snap');
+SELECT pg_get_logical_snapshot_info('-1--40796E18.snap');
 SELECT pg_get_logical_snapshot_info('0/40796E18.foo.snap');
 SELECT pg_get_logical_snapshot_info('0/40796E18.snap');
 SELECT pg_get_logical_snapshot_info('');
 SELECT pg_get_logical_snapshot_info(NULL);
 SELECT pg_get_logical_snapshot_info('../snapshots');
+SELECT pg_get_logical_snapshot_info('../snapshots/0-40796E18.snap');
 
 SELECT pg_get_logical_snapshot_meta('0-40796E18.foo');
 SELECT pg_get_logical_snapshot_meta('0-40796E18.foo.snap');