Skip to content

Commit

Permalink
Fix history file parsing. (#995)
Browse files Browse the repository at this point in the history
The previous coding used a statically allocated array of pointers to
newlines in that file, limiting our parsing abilities to files of 1024 lines
maximum. Apparently that's not a good limit, so use dynamically allocated
memory instead.

Fixes #991.
  • Loading branch information
dimitri committed Jun 2, 2023
1 parent 10c62c2 commit 97de12e
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 6 deletions.
17 changes: 11 additions & 6 deletions src/bin/pg_autoctl/pgsql.c
Expand Up @@ -3094,18 +3094,18 @@ bool
parseTimeLineHistory(const char *filename, const char *content,
IdentifySystem *system)
{
char *historyLines[BUFSIZE] = { 0 };
int lineCount = splitLines((char *) content, historyLines, BUFSIZE);
int lineCount = countLines((char *) content);
char **historyLines = (char **) calloc(lineCount, sizeof(char *));
int lineNumber = 0;

if (lineCount >= PG_AUTOCTL_MAX_TIMELINES)
if (historyLines == NULL)
{
log_error("history file \"%s\" contains %d lines, "
"pg_autoctl only supports up to %d lines",
filename, lineCount, PG_AUTOCTL_MAX_TIMELINES - 1);
log_error(ALLOCATION_FAILED_ERROR);
return false;
}

splitLines((char *) content, historyLines, lineCount);

uint64_t prevend = InvalidXLogRecPtr;

system->timelines.count = 0;
Expand Down Expand Up @@ -3141,6 +3141,7 @@ parseTimeLineHistory(const char *filename, const char *content,
{
log_error("Failed to parse history file line %d: \"%s\"",
lineNumber, ptr);
free(historyLines);
return false;
}

Expand All @@ -3149,6 +3150,7 @@ parseTimeLineHistory(const char *filename, const char *content,
if (!stringToUInt(historyLines[lineNumber], &(entry->tli)))
{
log_error("Failed to parse history timeline \"%s\"", tabptr);
free(historyLines);
return false;
}

Expand All @@ -3167,6 +3169,7 @@ parseTimeLineHistory(const char *filename, const char *content,
{
log_error("Failed to parse history timeline %d LSN \"%s\"",
entry->tli, lsn);
free(historyLines);
return false;
}

Expand All @@ -3184,6 +3187,8 @@ parseTimeLineHistory(const char *filename, const char *content,
entry = &(system->timelines.history[++system->timelines.count]);
}

free(historyLines);

/*
* Create one more entry for the "tip" of the timeline, which has no entry
* in the history file.
Expand Down
37 changes: 37 additions & 0 deletions src/bin/pg_autoctl/string_utils.c
Expand Up @@ -495,6 +495,43 @@ IntervalToString(double seconds, char *buffer, size_t size)
}


/*
* countLines returns how many line separators (\n) are found in the given
* string.
*/
int
countLines(char *buffer)
{
int lineNumber = 0;
char *currentLine = buffer;

if (buffer == NULL)
{
return 0;
}

do {
char *newLinePtr = strchr(currentLine, '\n');

if (newLinePtr == NULL)
{
if (strlen(currentLine) > 0)
{
++lineNumber;
}
currentLine = NULL;
}
else
{
++lineNumber;
currentLine = ++newLinePtr;
}
} while (currentLine != NULL && *currentLine != '\0');

return lineNumber;
}


/*
* splitLines prepares a multi-line error message in a way that calling code
* can loop around one line at a time and call log_error() or log_warn() on
Expand Down
1 change: 1 addition & 0 deletions src/bin/pg_autoctl/string_utils.h
Expand Up @@ -37,6 +37,7 @@ bool stringToUInt32(const char *str, uint32_t *number);
bool stringToDouble(const char *str, double *number);
bool IntervalToString(double seconds, char *buffer, size_t size);

int countLines(char *buffer);
int splitLines(char *errorMessage, char **linesArray, int size);
void processBufferCallback(const char *buffer, bool error);

Expand Down

0 comments on commit 97de12e

Please sign in to comment.