Skip to content

Commit 784b1ba

Browse files
committed
Remove arbitrary line length limits in pg_regress (plain and ECPG).
Refactor replace_string() to use a StringInfo for the modifiable string argument. This allows the string to be of indefinite size initially and/or grow substantially during replacement. The previous logic in convert_sourcefiles_in() had a hard-wired limit of 1024 bytes on any line in input/*.sql or output/*.out files. While we've not had reports of trouble yet, it'd surely have bit us someday. This also fixes replace_string() so it won't get into an infinite loop if the string-to-be-replaced is a substring of the replacement. That's unlikely to happen in current usage, but the function surely shouldn't depend on it. Also fix ecpg_filter() to use a StringInfo and thereby remove its hard limit of 300 bytes on the length of an ecpg source line. Asim Rama Praveen and Georgios Kokolatos, reviewed by Alvaro Herrera and myself Discussion: https://postgr.es/m/y9Dlk2QhiZ39DhaB1QE9mgZ95HcOQKZCNtGwN7XCRKMdBRBnX_0woaRUtTjloEp4PKA6ERmcUcfq3lPGfKPOJ5xX2TV-5WoRYyySeNHRzdw=@protonmail.com
1 parent 8e3c58e commit 784b1ba

File tree

3 files changed

+77
-56
lines changed

3 files changed

+77
-56
lines changed

src/interfaces/ecpg/test/pg_regress_ecpg.c

+38-38
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@
1919
#include "postgres_fe.h"
2020

2121
#include "pg_regress.h"
22+
#include "common/string.h"
23+
#include "lib/stringinfo.h"
2224

23-
#define LINEBUFSIZE 300
2425

2526
static void
2627
ecpg_filter(const char *sourcefile, const char *outfile)
@@ -31,7 +32,7 @@ ecpg_filter(const char *sourcefile, const char *outfile)
3132
*/
3233
FILE *s,
3334
*t;
34-
char linebuf[LINEBUFSIZE];
35+
StringInfoData linebuf;
3536

3637
s = fopen(sourcefile, "r");
3738
if (!s)
@@ -46,13 +47,14 @@ ecpg_filter(const char *sourcefile, const char *outfile)
4647
exit(2);
4748
}
4849

49-
while (fgets(linebuf, LINEBUFSIZE, s))
50+
initStringInfo(&linebuf);
51+
52+
while (pg_get_line_append(s, &linebuf))
5053
{
5154
/* check for "#line " in the beginning */
52-
if (strstr(linebuf, "#line ") == linebuf)
55+
if (strstr(linebuf.data, "#line ") == linebuf.data)
5356
{
54-
char *p = strchr(linebuf, '"');
55-
char *n;
57+
char *p = strchr(linebuf.data, '"');
5658
int plen = 1;
5759

5860
while (*p && (*(p + plen) == '.' || strchr(p + plen, '/') != NULL))
@@ -62,13 +64,15 @@ ecpg_filter(const char *sourcefile, const char *outfile)
6264
/* plen is one more than the number of . and / characters */
6365
if (plen > 1)
6466
{
65-
n = (char *) malloc(plen);
66-
strlcpy(n, p + 1, plen);
67-
replace_string(linebuf, n, "");
67+
memmove(p + 1, p + plen, strlen(p + plen) + 1);
68+
/* we don't bother to fix up linebuf.len */
6869
}
6970
}
70-
fputs(linebuf, t);
71+
fputs(linebuf.data, t);
72+
resetStringInfo(&linebuf);
7173
}
74+
75+
pfree(linebuf.data);
7276
fclose(s);
7377
fclose(t);
7478
}
@@ -87,40 +91,42 @@ ecpg_start_test(const char *testname,
8791
PID_TYPE pid;
8892
char inprg[MAXPGPATH];
8993
char insource[MAXPGPATH];
90-
char *outfile_stdout,
94+
StringInfoData testname_dash;
95+
char outfile_stdout[MAXPGPATH],
9196
expectfile_stdout[MAXPGPATH];
92-
char *outfile_stderr,
97+
char outfile_stderr[MAXPGPATH],
9398
expectfile_stderr[MAXPGPATH];
94-
char *outfile_source,
99+
char outfile_source[MAXPGPATH],
95100
expectfile_source[MAXPGPATH];
96101
char cmd[MAXPGPATH * 3];
97-
char *testname_dash;
98102
char *appnameenv;
99103

100104
snprintf(inprg, sizeof(inprg), "%s/%s", inputdir, testname);
105+
snprintf(insource, sizeof(insource), "%s.c", testname);
106+
107+
initStringInfo(&testname_dash);
108+
appendStringInfoString(&testname_dash, testname);
109+
replace_string(&testname_dash, "/", "-");
101110

102-
testname_dash = strdup(testname);
103-
replace_string(testname_dash, "/", "-");
104111
snprintf(expectfile_stdout, sizeof(expectfile_stdout),
105112
"%s/expected/%s.stdout",
106-
outputdir, testname_dash);
113+
outputdir, testname_dash.data);
107114
snprintf(expectfile_stderr, sizeof(expectfile_stderr),
108115
"%s/expected/%s.stderr",
109-
outputdir, testname_dash);
116+
outputdir, testname_dash.data);
110117
snprintf(expectfile_source, sizeof(expectfile_source),
111118
"%s/expected/%s.c",
112-
outputdir, testname_dash);
113-
114-
/*
115-
* We can use replace_string() here because the replacement string does
116-
* not occupy more space than the replaced one.
117-
*/
118-
outfile_stdout = strdup(expectfile_stdout);
119-
replace_string(outfile_stdout, "/expected/", "/results/");
120-
outfile_stderr = strdup(expectfile_stderr);
121-
replace_string(outfile_stderr, "/expected/", "/results/");
122-
outfile_source = strdup(expectfile_source);
123-
replace_string(outfile_source, "/expected/", "/results/");
119+
outputdir, testname_dash.data);
120+
121+
snprintf(outfile_stdout, sizeof(outfile_stdout),
122+
"%s/results/%s.stdout",
123+
outputdir, testname_dash.data);
124+
snprintf(outfile_stderr, sizeof(outfile_stderr),
125+
"%s/results/%s.stderr",
126+
outputdir, testname_dash.data);
127+
snprintf(outfile_source, sizeof(outfile_source),
128+
"%s/results/%s.c",
129+
outputdir, testname_dash.data);
124130

125131
add_stringlist_item(resultfiles, outfile_stdout);
126132
add_stringlist_item(expectfiles, expectfile_stdout);
@@ -134,18 +140,15 @@ ecpg_start_test(const char *testname,
134140
add_stringlist_item(expectfiles, expectfile_source);
135141
add_stringlist_item(tags, "source");
136142

137-
snprintf(insource, sizeof(insource), "%s.c", testname);
138143
ecpg_filter(insource, outfile_source);
139144

140-
snprintf(inprg, sizeof(inprg), "%s/%s", inputdir, testname);
141-
142145
snprintf(cmd, sizeof(cmd),
143146
"\"%s\" >\"%s\" 2>\"%s\"",
144147
inprg,
145148
outfile_stdout,
146149
outfile_stderr);
147150

148-
appnameenv = psprintf("PGAPPNAME=ecpg/%s", testname_dash);
151+
appnameenv = psprintf("PGAPPNAME=ecpg/%s", testname_dash.data);
149152
putenv(appnameenv);
150153

151154
pid = spawn_process(cmd);
@@ -160,10 +163,7 @@ ecpg_start_test(const char *testname,
160163
unsetenv("PGAPPNAME");
161164
free(appnameenv);
162165

163-
free(testname_dash);
164-
free(outfile_stdout);
165-
free(outfile_stderr);
166-
free(outfile_source);
166+
free(testname_dash.data);
167167

168168
return pid;
169169
}

src/test/regress/pg_regress.c

+35-17
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@
3131

3232
#include "common/logging.h"
3333
#include "common/restricted_token.h"
34+
#include "common/string.h"
3435
#include "common/username.h"
3536
#include "getopt_long.h"
37+
#include "lib/stringinfo.h"
3638
#include "libpq/pqcomm.h" /* needed for UNIXSOCK_PATH() */
3739
#include "pg_config_paths.h"
3840
#include "pg_regress.h"
@@ -435,22 +437,32 @@ string_matches_pattern(const char *str, const char *pattern)
435437
}
436438

437439
/*
438-
* Replace all occurrences of a string in a string with a different string.
439-
* NOTE: Assumes there is enough room in the target buffer!
440+
* Replace all occurrences of "replace" in "string" with "replacement".
441+
* The StringInfo will be suitably enlarged if necessary.
442+
*
443+
* Note: this is optimized on the assumption that most calls will find
444+
* no more than one occurrence of "replace", and quite likely none.
440445
*/
441446
void
442-
replace_string(char *string, const char *replace, const char *replacement)
447+
replace_string(StringInfo string, const char *replace, const char *replacement)
443448
{
449+
int pos = 0;
444450
char *ptr;
445451

446-
while ((ptr = strstr(string, replace)) != NULL)
452+
while ((ptr = strstr(string->data + pos, replace)) != NULL)
447453
{
448-
char *dup = pg_strdup(string);
454+
/* Must copy the remainder of the string out of the StringInfo */
455+
char *suffix = pg_strdup(ptr + strlen(replace));
449456

450-
strlcpy(string, dup, ptr - string + 1);
451-
strcat(string, replacement);
452-
strcat(string, dup + (ptr - string) + strlen(replace));
453-
free(dup);
457+
/* Truncate StringInfo at start of found string ... */
458+
string->len = ptr - string->data;
459+
/* ... and append the replacement (this restores the trailing '\0') */
460+
appendStringInfoString(string, replacement);
461+
/* Next search should start after the replacement */
462+
pos = string->len;
463+
/* Put back the remainder of the string */
464+
appendStringInfoString(string, suffix);
465+
free(suffix);
454466
}
455467
}
456468

@@ -521,7 +533,7 @@ convert_sourcefiles_in(const char *source_subdir, const char *dest_dir, const ch
521533
char prefix[MAXPGPATH];
522534
FILE *infile,
523535
*outfile;
524-
char line[1024];
536+
StringInfoData line;
525537

526538
/* reject filenames not finishing in ".source" */
527539
if (strlen(*name) < 8)
@@ -551,15 +563,21 @@ convert_sourcefiles_in(const char *source_subdir, const char *dest_dir, const ch
551563
progname, destfile, strerror(errno));
552564
exit(2);
553565
}
554-
while (fgets(line, sizeof(line), infile))
566+
567+
initStringInfo(&line);
568+
569+
while (pg_get_line_append(infile, &line))
555570
{
556-
replace_string(line, "@abs_srcdir@", inputdir);
557-
replace_string(line, "@abs_builddir@", outputdir);
558-
replace_string(line, "@testtablespace@", testtablespace);
559-
replace_string(line, "@libdir@", dlpath);
560-
replace_string(line, "@DLSUFFIX@", DLSUFFIX);
561-
fputs(line, outfile);
571+
replace_string(&line, "@abs_srcdir@", inputdir);
572+
replace_string(&line, "@abs_builddir@", outputdir);
573+
replace_string(&line, "@testtablespace@", testtablespace);
574+
replace_string(&line, "@libdir@", dlpath);
575+
replace_string(&line, "@DLSUFFIX@", DLSUFFIX);
576+
fputs(line.data, outfile);
577+
resetStringInfo(&line);
562578
}
579+
580+
pfree(line.data);
563581
fclose(infile);
564582
fclose(outfile);
565583
}

src/test/regress/pg_regress.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#define INVALID_PID INVALID_HANDLE_VALUE
1919
#endif
2020

21+
struct StringInfoData; /* avoid including stringinfo.h here */
22+
2123
/* simple list of strings */
2224
typedef struct _stringlist
2325
{
@@ -49,5 +51,6 @@ int regression_main(int argc, char *argv[],
4951
init_function ifunc, test_function tfunc);
5052
void add_stringlist_item(_stringlist **listhead, const char *str);
5153
PID_TYPE spawn_process(const char *cmdline);
52-
void replace_string(char *string, const char *replace, const char *replacement);
54+
void replace_string(struct StringInfoData *string,
55+
const char *replace, const char *replacement);
5356
bool file_exists(const char *file);

0 commit comments

Comments
 (0)