From 903127e896428a76d2c93445fadd960b5c9f477b Mon Sep 17 00:00:00 2001
From: Georgios Kokolatos <gkokolatos@pivotal.io>
Date: Fri, 31 Jul 2020 08:17:02 +0000
Subject: [PATCH] Add and use a heap allocated string version of replace_string
 in pg_regress

The exposed function replase_string() in pg_regress assumes that there exists
enough space in the string it operates on. While this is documented and
expected, the consequence can be subtle failures in the tests which might be
hard to trace back to the root cause.

Provide an alternative function that operates on a heap allocated string instead.
The string regrows if needed and the new size can be used for subsequent reads.

Co-authored-by: Asim R P <pasim@vmware.com>
---
 src/test/regress/pg_regress.c | 58 ++++++++++++++++++++++++++++++-----
 1 file changed, 51 insertions(+), 7 deletions(-)

diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index d82e0189dc..5701c80e42 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -434,6 +434,40 @@ string_matches_pattern(const char *str, const char *pattern)
 	return false;
 }
 
+/*
+ * Replace all occurrences of a string in a string with a different string.
+ *
+ * The string grows if there is not enough space.
+ */
+static char *
+replace_string_heap(char *string, size_t *stringlen,
+					const char *replace, const char *replacement)
+{
+	ssize_t		overflowlen;
+	char	   *ptr;
+
+	overflowlen = strlen(replacement) - strlen(replace);
+	while ((ptr = strstr(string, replace)) != NULL)
+	{
+		char	   *dup = pg_strdup(string);
+
+		if (overflowlen > 0 &&
+			((ptr + strlen(ptr) + overflowlen) > (string + *stringlen - 1)))
+		{
+			*stringlen *= 2;
+			string = realloc(string, *stringlen);
+			ptr = strstr(string, replace);
+		}
+
+		strlcpy(string, dup, ptr - string + 1);
+		strcat(string, replacement);
+		strcat(string, dup + (ptr - string) + strlen(replace));
+		free(dup);
+	}
+
+	return string;
+}
+
 /*
  * Replace all occurrences of a string in a string with a different string.
  * NOTE: Assumes there is enough room in the target buffer!
@@ -521,7 +555,8 @@ convert_sourcefiles_in(const char *source_subdir, const char *dest_dir, const ch
 		char		prefix[MAXPGPATH];
 		FILE	   *infile,
 				   *outfile;
-		char		line[1024];
+		char	   *line;
+		size_t		linelen;
 
 		/* reject filenames not finishing in ".source" */
 		if (strlen(*name) < 8)
@@ -551,15 +586,24 @@ convert_sourcefiles_in(const char *source_subdir, const char *dest_dir, const ch
 					progname, destfile, strerror(errno));
 			exit(2);
 		}
-		while (fgets(line, sizeof(line), infile))
+
+		linelen = 1024;
+		line = malloc(linelen);
+		while (fgets(line, linelen, infile))
 		{
-			replace_string(line, "@abs_srcdir@", inputdir);
-			replace_string(line, "@abs_builddir@", outputdir);
-			replace_string(line, "@testtablespace@", testtablespace);
-			replace_string(line, "@libdir@", dlpath);
-			replace_string(line, "@DLSUFFIX@", DLSUFFIX);
+			line = replace_string_heap(line, &linelen,
+									  "@abs_srcdir@", inputdir);
+			line = replace_string_heap(line, &linelen,
+									  "@abs_builddir@", outputdir);
+			line = replace_string_heap(line, &linelen,
+									  "@testtablespace@", testtablespace);
+			line = replace_string_heap(line, &linelen,
+									  "@libdir@", dlpath);
+			line = replace_string_heap(line, &linelen,
+									  "@DLSUFFIX@", DLSUFFIX);
 			fputs(line, outfile);
 		}
+		free(line);
 		fclose(infile);
 		fclose(outfile);
 	}
-- 
2.25.1

