From 4dc5dd0883e6093f53e40ff4fadb2457dcf0f8cd Mon Sep 17 00:00:00 2001 From: Maxim Smyatkin Date: Sat, 16 May 2026 21:19:06 +0300 Subject: [PATCH] Fix infinite loops in replaceStringInfoString The function had a few problems: - replace ="a" and replacement="ab" would give an infinite loop leading to OOM. We have a similar case in pg_dump: replace="range", replacement="multirange" - Copying the whole string each time there is a match - Empty replace pattern also leads to infinite loop We can still do better: for example count number of matches and do a single allocation, or even run the replacement inplace. But it's probably not worth it. --- src/common/stringinfo.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/common/stringinfo.c b/src/common/stringinfo.c index f177516c26f..e458f821a0c 100644 --- a/src/common/stringinfo.c +++ b/src/common/stringinfo.c @@ -364,16 +364,32 @@ enlargeStringInfo(StringInfo str, int needed) void replaceStringInfoString(StringInfo str, char *replace, char *replacement) { - char *ptr; + char *match_ptr = NULL; + char *start_ptr = str->data; + char *dup = NULL; + size_t replace_len = strlen(replace); - while ((ptr = strstr(str->data, replace)) != NULL) - { - char *dup = pstrdup(str->data); + // prevent empty loop, cuz strstr will always return start_ptr + if (replace_len == 0) + return; - resetStringInfo(str); - appendBinaryStringInfo(str, dup, ptr - str->data); + while ((match_ptr = strstr(start_ptr, replace)) != NULL) + { + if (dup == NULL) + { + dup = pstrdup(str->data); + start_ptr = dup; + match_ptr = dup + (match_ptr - str->data); + resetStringInfo(str); + } + + appendBinaryStringInfo(str, start_ptr, match_ptr - start_ptr); appendStringInfoString(str, replacement); - appendStringInfoString(str, dup + (ptr - str->data) + strlen(replace)); + start_ptr = match_ptr + replace_len; + } + if (dup != NULL) + { + appendStringInfoString(str, start_ptr); pfree(dup); } }