Skip to content

Commit 1a9356f

Browse files
committed
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
1 parent ba019b4 commit 1a9356f

File tree

3 files changed

+14
-5
lines changed

3 files changed

+14
-5
lines changed

src/backend/utils/adt/oracle_compat.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,8 @@ translate(PG_FUNCTION_ARGS)
797797
text *to = PG_GETARG_TEXT_PP(2);
798798
text *result;
799799
char *from_ptr,
800-
*to_ptr;
800+
*to_ptr,
801+
*to_end;
801802
char *source,
802803
*target;
803804
int m,
@@ -819,6 +820,7 @@ translate(PG_FUNCTION_ARGS)
819820
from_ptr = VARDATA_ANY(from);
820821
tolen = VARSIZE_ANY_EXHDR(to);
821822
to_ptr = VARDATA_ANY(to);
823+
to_end = to_ptr + tolen;
822824

823825
/*
824826
* The worst-case expansion is to substitute a max-length character for a
@@ -852,16 +854,16 @@ translate(PG_FUNCTION_ARGS)
852854
}
853855
if (i < fromlen)
854856
{
855-
/* substitute */
857+
/* substitute, or delete if no corresponding "to" character */
856858
char *p = to_ptr;
857859

858860
for (i = 0; i < from_index; i++)
859861
{
860-
p += pg_mblen(p);
861-
if (p >= (to_ptr + tolen))
862+
if (p >= to_end)
862863
break;
864+
p += pg_mblen(p);
863865
}
864-
if (p < (to_ptr + tolen))
866+
if (p < to_end)
865867
{
866868
len = pg_mblen(p);
867869
memcpy(target, p, len);

src/test/regress/expected/strings.out

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2116,6 +2116,12 @@ SELECT translate('12345', '14', 'ax');
21162116
a23x5
21172117
(1 row)
21182118

2119+
SELECT translate('12345', '134', 'a');
2120+
translate
2121+
-----------
2122+
a25
2123+
(1 row)
2124+
21192125
SELECT ascii('x');
21202126
ascii
21212127
-------

src/test/regress/sql/strings.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,7 @@ SELECT ltrim('zzzytrim', 'xyz');
719719

720720
SELECT translate('', '14', 'ax');
721721
SELECT translate('12345', '14', 'ax');
722+
SELECT translate('12345', '134', 'a');
722723

723724
SELECT ascii('x');
724725
SELECT ascii('');

0 commit comments

Comments
 (0)