summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2023-03-01 16:30:17 +0000
committerTom Lane2023-03-01 16:30:31 +0000
commitd7056bc1c71d2d876adb60dda8e0ba962e8279df (patch)
tree65552305c23835b4e7de090cbb3b457f176c7770
parent6095069b40d7f01d5e7771d23b18d65dc029fc0d (diff)
Avoid fetching one past the end of translate()'s "to" parameter.
This is usually harmless, but if you were very unlucky it could provoke a segfault due to the "to" string being right up against the end of memory. Found via valgrind testing (so we might've found it earlier, except that our regression tests lacked any exercise of translate()'s deletion feature). Fix by switching the order of the test-for-end-of-string and advance-pointer steps. While here, compute "to_ptr + tolen" just once. (Smarter compilers might figure that out for themselves, but let's just make sure.) Report and fix by Daniil Anisimov, in bug #17816. Discussion: https://postgr.es/m/[email protected]
-rw-r--r--src/backend/utils/adt/oracle_compat.c12
-rw-r--r--src/test/regress/expected/strings.out6
-rw-r--r--src/test/regress/sql/strings.sql1
3 files changed, 14 insertions, 5 deletions
diff --git a/src/backend/utils/adt/oracle_compat.c b/src/backend/utils/adt/oracle_compat.c
index 5f1bc59d878..3b5b794afb3 100644
--- a/src/backend/utils/adt/oracle_compat.c
+++ b/src/backend/utils/adt/oracle_compat.c
@@ -801,7 +801,8 @@ translate(PG_FUNCTION_ARGS)
text *to = PG_GETARG_TEXT_PP(2);
text *result;
char *from_ptr,
- *to_ptr;
+ *to_ptr,
+ *to_end;
char *source,
*target;
int m,
@@ -823,6 +824,7 @@ translate(PG_FUNCTION_ARGS)
from_ptr = VARDATA_ANY(from);
tolen = VARSIZE_ANY_EXHDR(to);
to_ptr = VARDATA_ANY(to);
+ to_end = to_ptr + tolen;
/*
* The worst-case expansion is to substitute a max-length character for a
@@ -857,16 +859,16 @@ translate(PG_FUNCTION_ARGS)
}
if (i < fromlen)
{
- /* substitute */
+ /* substitute, or delete if no corresponding "to" character */
char *p = to_ptr;
for (i = 0; i < from_index; i++)
{
- p += pg_mblen(p);
- if (p >= (to_ptr + tolen))
+ if (p >= to_end)
break;
+ p += pg_mblen(p);
}
- if (p < (to_ptr + tolen))
+ if (p < to_end)
{
len = pg_mblen(p);
memcpy(target, p, len);
diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out
index 403a29ed8c6..62698569e1a 100644
--- a/src/test/regress/expected/strings.out
+++ b/src/test/regress/expected/strings.out
@@ -2443,6 +2443,12 @@ SELECT translate('12345', '14', 'ax');
a23x5
(1 row)
+SELECT translate('12345', '134', 'a');
+ translate
+-----------
+ a25
+(1 row)
+
SELECT ascii('x');
ascii
-------
diff --git a/src/test/regress/sql/strings.sql b/src/test/regress/sql/strings.sql
index 097dcdf69e9..ca32f6bba53 100644
--- a/src/test/regress/sql/strings.sql
+++ b/src/test/regress/sql/strings.sql
@@ -787,6 +787,7 @@ SELECT ltrim('zzzytrim', 'xyz');
SELECT translate('', '14', 'ax');
SELECT translate('12345', '14', 'ax');
+SELECT translate('12345', '134', 'a');
SELECT ascii('x');
SELECT ascii('');