From 330c6ff741575b318b6bf00131cbca576d2e2387 Mon Sep 17 00:00:00 2001 From: Manuel Reyes Bravo Date: Fri, 2 Oct 2026 14:44:44 -0300 Subject: [PATCH v3 1/2] Fix out-of-bounds read in pg_trgm word similarity calc_word_similarity() looks at found[j] once more after its merge loop. When neither string has a trigram, as in word_similarity('', ''), found[] has no elements and that read is past its end. The value never affects the result: with no trigrams in the second string, iterate_word_similarity() returns 0 without using ulen1. But it is undefined behavior, and builds with -fsanitize=undefined abort on it. cfbot hit it through a test with stored empty strings in the fix for bug #19701. Backpatch-through: 14 Discussion: https://postgr.es/m/19701-c861a62e79bf49ce@postgresql.org --- contrib/pg_trgm/expected/pg_word_trgm.out | 7 +++++++ contrib/pg_trgm/sql/pg_word_trgm.sql | 3 +++ contrib/pg_trgm/trgm_op.c | 3 ++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/contrib/pg_trgm/expected/pg_word_trgm.out b/contrib/pg_trgm/expected/pg_word_trgm.out index c66a67f30ef..17a3831dfe7 100644 --- a/contrib/pg_trgm/expected/pg_word_trgm.out +++ b/contrib/pg_trgm/expected/pg_word_trgm.out @@ -1050,3 +1050,10 @@ select * from test_trgm2 where t ~ '.*$x'; --- (0 rows) +-- No trigrams on either side: must not read past the end of an empty array +SELECT word_similarity('', ''), strict_word_similarity('', ''); + word_similarity | strict_word_similarity +-----------------+------------------------ + 0 | 0 +(1 row) + diff --git a/contrib/pg_trgm/sql/pg_word_trgm.sql b/contrib/pg_trgm/sql/pg_word_trgm.sql index d2ada49133a..304409728cc 100644 --- a/contrib/pg_trgm/sql/pg_word_trgm.sql +++ b/contrib/pg_trgm/sql/pg_word_trgm.sql @@ -46,3 +46,6 @@ select t,word_similarity('Kabankala',t) as sml from test_trgm2 where t %> 'Kaban -- test unsatisfiable pattern select * from test_trgm2 where t ~ '.*$x'; + +-- No trigrams on either side: must not read past the end of an empty array +SELECT word_similarity('', ''), strict_word_similarity('', ''); diff --git a/contrib/pg_trgm/trgm_op.c b/contrib/pg_trgm/trgm_op.c index 22bcc3c3361..00cc0e5e63e 100644 --- a/contrib/pg_trgm/trgm_op.c +++ b/contrib/pg_trgm/trgm_op.c @@ -919,7 +919,8 @@ calc_word_similarity(char *str1, int slen1, char *str2, int slen2, found[j] = true; } } - if (found[j]) + /* With no trigrams at all, found[] is empty and there is no last one */ + if (len > 0 && found[j]) ulen1++; /* Run iterative procedure to find maximum similarity with word */ -- 2.55.0