aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2023-03-01 11:30:17 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2023-03-01 11:30:17 -0500
commitb162660d3ac44688f18919cd460423022e467512 (patch)
treeaaabe7f92853522d77834f2e0dc2f8ff7233b21d /src
parent11290c89bbe52283186b3bd38f06ae677d99ca9f (diff)
downloadpostgresql-b162660d3ac44688f18919cd460423022e467512.tar.gz
postgresql-b162660d3ac44688f18919cd460423022e467512.zip
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/17816-70f3d2764e88a108@postgresql.org
Diffstat (limited to 'src')
-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 ecd8268b23b..85db92411f0 100644
--- a/src/backend/utils/adt/oracle_compat.c
+++ b/src/backend/utils/adt/oracle_compat.c
@@ -723,7 +723,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,
@@ -745,6 +746,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
@@ -778,16 +780,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 516b668f361..ba64c999d50 100644
--- a/src/test/regress/expected/strings.out
+++ b/src/test/regress/expected/strings.out
@@ -1856,6 +1856,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 a736a94ce13..8589712d41b 100644
--- a/src/test/regress/sql/strings.sql
+++ b/src/test/regress/sql/strings.sql
@@ -645,6 +645,7 @@ SELECT ltrim('zzzytrim', 'xyz');
SELECT translate('', '14', 'ax');
SELECT translate('12345', '14', 'ax');
+SELECT translate('12345', '134', 'a');
SELECT ascii('x');
SELECT ascii('');