From edd68732ad472a7a9ae824fe3be06f8f111754d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 13 Jun 2022 12:14:15 +0200 Subject: [PATCH] vt: prevent potential endless loop when finding a slot for a composed character MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Composed characters are stored in a tree structure, using a key as identifier. The key is calculated from the individual characters that make up the composed character sequence. Since the address space for keys is limited, collisions may occur. In this case, we simply increment the key and try again. It is theoretically possible to saturate the key space, in which case we’ll get stuck in an endless loop. Even if the key space isn’t fully saturated, we fairly easy reach a point where there are so many collisions for each insertion, that performance drops significantly. Since key space is limited (it’s not like a hash table that we can grow), our only option is to limit the number of collisions. If we can’t find a slot within a hard code amount of collisions, the character is simply dropped. --- vt.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/vt.c b/vt.c index a98188be..9746364b 100644 --- a/vt.c +++ b/vt.c @@ -738,8 +738,20 @@ action_utf8_print(struct terminal *term, char32_t wc) xassert(wanted_count <= 255); + size_t collision_count = 0; + /* Look for existing combining chain */ while (true) { + if (collision_count > 128) { + static bool have_warned = false; + if (!have_warned) { + have_warned = true; + LOG_WARN("ignoring composed character: " + "too many collisions in hash table"); + } + return; + } + const struct composed *cc = composed_lookup(term->composed, key); if (cc == NULL) break; @@ -756,6 +768,7 @@ action_utf8_print(struct terminal *term, char32_t wc) cc->chars[wanted_count - 1] != wc) { key++; + collision_count++; continue; } @@ -766,6 +779,7 @@ action_utf8_print(struct terminal *term, char32_t wc) if (!match) { key++; + collision_count++; continue; }