Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wfYbN-005Vue-2h for pgsql-hackers@arkaria.postgresql.org; Fri, 03 Jul 2026 07:46:22 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wfYbM-0066Dt-1P for pgsql-hackers@arkaria.postgresql.org; Fri, 03 Jul 2026 07:46:20 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wfYbL-0066Dk-1u for pgsql-hackers@lists.postgresql.org; Fri, 03 Jul 2026 07:46:20 +0000 Received: from fhigh-a7-smtp.messagingengine.com ([103.168.172.158]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1wfYbJ-00000001Hzc-1ZVf for pgsql-hackers@postgresql.org; Fri, 03 Jul 2026 07:46:18 +0000 Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfhigh.phl.internal (Postfix) with ESMTP id C3DA81400050; Fri, 3 Jul 2026 03:46:15 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-02.internal (MEProxy); Fri, 03 Jul 2026 03:46:15 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paquier.xyz; h= cc:cc:content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm2; t=1783064775; x=1783151175; bh=BQZuvgeYgD 9kDrvliPtxrqkT4WCUmta+1H4C44q34Vo=; b=bBjKn8VRfrt+ABTHb/HNmxHFjB BqNlC5C6Qf3PDP7XnYQL+gftRe95rUQ7SQm4EwyStX6a1/4g5frSKXlQ85BYlLzk LlHkkbGZImDENZgiOrcE3R3TyXhsTSmI9FYOEe0GKIKtzD5w/ZrGSLEV6vtSfH++ rAwmU6mvCAPOvd6q8D0BGEpTiONa4h455YFPvPyzHB+gphF59IZ2MAtMgtyIzQ03 ZAFS1NcPLnj2onS/GJn+afwcsEPen4idRf+/f6AKUmFLqAxdGzCG1igesymy3mPd 7XYEN5gd0lIYGkZAtM2dK4c6i9KxUNmZOlVtmEZPObVgab+ZtVkobfcd2b0A== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; t= 1783064775; x=1783151175; bh=BQZuvgeYgD9kDrvliPtxrqkT4WCUmta+1H4 C44q34Vo=; b=iH0uxSWmuqzqxTaFY8tUqDPnQlNV8k5pOCWiR+H5mLexyQGFAgl XtHjnw/vXwifOaaUgz+fNIfkHUBA6t6ECR5BKx1ydTrAIH60UoNkiX4sPzfGYPHf 3Ea2WrMbAtCYhJycfuqe9kRSu6/hiz9qtBE5gcGo+JvlL+5+R8+db+uufXdnbpya 0dDwSdjQFchTW5+04/pqxbFp0dbE/VYkWFnnvMzVRI6bR99Af/jDJxeWkOz+ip5T FHjeYZUusj2JAVxJpRJxhC4TlITWEU5ghc6/p88f3DhiSiKaffFcrr+kZx/gB15b GwlS6jFwZ+cRVkcrbrJg9Be8u6MeSKe5hSw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTE4g1up3dILxylXeOqyo/akncadZnouciIQXksu5LzvuJSGtAE3ZiU6szbOYei4b1 BCMgubnNNKpLDlQ+espxmciL/P+MdMtVLLDhxjOHBhOm4JuhLOkKVPHedF7QdI9lV14qfr 9JUNaaZbYvt7sSC2b1KZC/aiimCFDsA2x0AX3gHBWKzS+RidI64KyhTBRjOhJnbXwZqL0y bD37wGNtu3lnQeT6H9nNwCPgEMKVkszDL4BbDcENaxsrfx1bLGNMCQ02BpyNzH2b9gri8Y Rzk87RIZ6/brgaeAwu6XHrHmYAK3cIc36FZ0f7RelQ1nfjXuan+XrsRwEtA+5lZSq3hLW4 f6mkzSDbSYF1f7XseRpcMji1ZQWN3UwhQbqrxotL5OAHr1su7kB6p/SqSUF+W4OXxhwP21 SCv6SUjEV3Q5XVnY8AwW+vMjPxnWQNSsCGE4arQiDUNxaTxD3O/MVEMI0lK0n9tUd+0V1B lLM4s6zz/wtdx+leihxUtkK7+d0v2haixuniuDdmOeTLinUN44KcnmtejdIjHCeXC3NZJQ DOI/InlVIkUzyBA09LZzV05biillvdte3au64kZ62YRyPBxPhDd+XClZdEql+T7IK3sVKv hfRtbSDDWWZjz4/stcVjpYrdlCGoLZlCWb+4/R/BiPEBlC4o8pPp84QeDwPg X-ME-Proxy: Feedback-ID: i0fe9450f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 3 Jul 2026 03:46:13 -0400 (EDT) Date: Fri, 3 Jul 2026 16:46:09 +0900 From: Michael Paquier To: Henson Choi Cc: lex.borisov@gmail.com, hlinnaka@iki.fi, pgsql@j-davis.com, pgsql-hackers@postgresql.org Subject: Re: Improve the performance of Unicode Normalization Forms. Message-ID: References: <7b76973b-e9b6-4f80-a1d2-4bd467e38346@gmail.com> <24338db8-59f2-42a4-a7de-735cf8f12119@gmail.com> <96ed941e-a531-4c4c-a78d-3ba3227f5411@gmail.com> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="Yxx8i9PTyWL3LlLu" Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Yxx8i9PTyWL3LlLu Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Wed, Jul 01, 2026 at 03:29:25PM +0900, Henson Choi wrote: > Two things kept it hidden: no existing test touches this block (so cfbot > stays green), and even a test that does won't fail without a bounds > check -- the over-read silently returns 0 and happens to give the right > answer. >=20 > Reproduction: the attached test-only patch (nocfbot-unicode-norm-oob.txt) > adds bounds assertions to the two lookups plus regression tests that hit > the boundary. On an --enable-cassert build, >=20 > SELECT normalize(U&'\00C5\+02FA1E', NFD); > SELECT normalize(U&'\+016D6A\0301', NFC); >=20 > abort the backend (TRAP: failed Assert("offset + (cp & 63) < > lengthof(...)")). That's a good find (if you've used some AI tooling here, good use). I don't see an immediate need for in-core checks. One can also enable ubsan to get the same effect with out-of-bound lookups reusing your queries: =2E./../src/include/common/unicode_norm_table.h:6524:27: runtime error: index 17438 out of bounds for type 'uint16 [17438]' =20 The tests would be more important. If we have a gap in these, this usually points to a first patch where we add more tests. Please note that you may not actually need more tests. If I run the test module test_saslprep with PG_TEST_EXTRA=3Dsaslprep to make the costly TAP test run, I get two ubsan reports of this kind. Note that I enable it in some of my buildfarm machines, so it would not go unnoticed. > This extends the tables to 17472/3776, leaves the reader unchanged, and > resolves those codepoints to the dummy 0 entry (NULL), which is correct. > The generator change and the regenerated unicode_norm_table.h go > together. I'd keep the bounds assertion in the lookup as a guard against > future under-padding. This kind of issue is bad. Normalization is applied on the passwords for SCRAM with SASLprep, meaning this patch would touch code that's taken before authentication. This would lead to an immediate CVE, and most likely one with a bad score. We need to be extremely careful with what we are dealing here. SCRAM is used as default authentication method for a lot of cloud providers, AFAIK.=20 Saying that (and still trying to figure out the whole code), the numbers you have published in terms of reduction of the size of the binaries and the runtimes, based on Jeff's or your methods are impressive, seeing what has been posted. I would not underestimate the cost of the two-pass method we currently use when applying the normalization (one to calculate the output size, one to do the normalization). Hence why don't we just do that first and evaluate the gain in run time that we get? One thing that I have been wondering why reading this thread is simply: why don't we use a=20 BinaryStringInfo and start the normalization with a sensible preallocated size, avoiding the first pass for the sizing of the output buffer? It should be a simpler change that rewriting all the tables, and I suspect that it may improve the performance quite a bit, the longer the strings to normalize. And I also suspect that we should do that anyway at the end, and do it first. I am aware of the fact that the patch does some allocation changes, but I would suggest to split the patch into more reviewable pieces rather than drop a big chunk of code changes presented as a single commit, and present one patch for each relevant piece that aims at improving performance. Something that shows up as a red flag for me is the fact that the patch has a long list of bullet points. Each bullet point, in some cases, can point to independent patches worth doing on their own. Anyway, considering that the simplest pieces may be better first, I could think of at least:=20 1) Elimination of the second allocation for the recomposition (in-place recomposition for the decomps buffers). 2) Merge the two-pass decomposition into a single pass 3) The suggestion of Jeff to use a UTF8-native path is also something I'd wonder about, rather than do the uint32 codepoint dance. Not sure about the complexity, but Jeff has mentioned me in the past for his work on native UTF-8 collation support that relying on the codepoints in core was much, much, much faster than ICU (that was for sorting, but we'd burn less CPU for sure here as well). 4) What is now the largest chunk, with the table recreations. I'd suggest some more underground work here in terms of tests, identifying potential gaps in our existing testing that's cheap and good enough for meaningful corner cases. I am wondering if we don't have more to extract here. One idea: we could store the combining class during decomposition, saving one extra lookup? The NF[K]{C,D} operations have been done as they are as a matter of simplicity, relying on the introduction of the normalization API done for SCRAM in v10, where performance was not (and is still not) critical. As a whole, this patch is too large as-is to be digested in a review. Due to the pre-authentication requirement, something not rock-solid is as good as nothing (one can say that for all features, but this one is particularly exposed). (Spoiler: I rely on my brain for this kind of work, gentler for the planet with less tokens and memory burnt. A patch split as a bunch of pieces is more edible for me, personally.) -- Michael --Yxx8i9PTyWL3LlLu Content-Type: application/pgp-signature; name=signature.asc -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEEG72nH6vTowiyblFKnvQgOdbyQH0FAmpHaMEACgkQnvQgOdby QH0N7Q//ULBStdK48LhpgqEw+jY/X15qWUyZXAUTDQW5h8aR1xSBqw4867v5m7HP U5Vnw5+OV1KWj1EDI8PEnzGtVSHNEnTocC3AzcuJtOO2ubWgruK/Im5mwU8ozAJr 1aObW//jhZTAPOJDH+dL80QKuudGWpkOZkA4ZWKZY3dbkBArnEEFMliIPdlZA0ZO //2kfzCm/LH4Lj9J+PMETYgRTXZq2au1y2JOk6PI8rhw4IohOQDUdLxOxKVpIOP3 qYI9EuqYPdTXOOwi+Ydykzk8p/EHaeYkV4AVtodenGVV+mlbXOxYkdBg2HIwka1D CKvpRJ3DjFjH2nqcGZSdahIwF6Cd8YEtilNR/OhbDcU56VayNdqmDoLIVG3BmVBk pqHtk7Vum7hG161V+ZDMDIEqhR4s3IU0DGaZVOGybP5eH+gf19Xqr+Dmezk7R4mA 1jT19lHQ0hneRf55He7aFXwla4P+4sTSwg6MvwIj+QY44dHwyE0dA60fV6UPTPli BhfrZ6o8yntmdIv0UdDM16iJ3XpCaFlNq4QrgxyPgjF4rMVJx47KfaGnbCmHcI8I Fx5A3ILA8Vp20prLNJFZw3M23bfxnSQ9g+l52LsgCsKEnizqfo5xGgyjSnaJosYZ oipSE7P6pv5+wYpqQBncZt0VBYdf8Jk/B97G1UpCFhhhiLcN1Xk= =1FQ0 -----END PGP SIGNATURE----- --Yxx8i9PTyWL3LlLu--