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 1wXU6T-003I7v-01 for pgsql-hackers@arkaria.postgresql.org; Thu, 11 Jun 2026 01:21:05 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wXU6R-00DmUx-2Y for pgsql-hackers@arkaria.postgresql.org; Thu, 11 Jun 2026 01:21:03 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wXU6R-00DmUp-1M for pgsql-hackers@lists.postgresql.org; Thu, 11 Jun 2026 01:21:03 +0000 Received: from mail-ej1-x635.google.com ([2a00:1450:4864:20::635]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wXU6O-00000002Qzt-410V for pgsql-hackers@postgresql.org; Thu, 11 Jun 2026 01:21:02 +0000 Received: by mail-ej1-x635.google.com with SMTP id a640c23a62f3a-bec449d0af2so884451166b.2 for ; Wed, 10 Jun 2026 18:20:59 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1781140857; cv=none; d=google.com; s=arc-20240605; b=SCqlutEByl2skVJcD7/VNkQPpMkzfxudakExCeOifgNav5FEMGcbllGGN7PSpviZzr fn98OTqmHRArjrMj56n6lnpk5BG3emsCzQ0+0P7PUfUOhhA9a3TduLt1TMWNMuykiMkl Cikj/vc2BfgiUfe/1NQ2sYdQLDE+J+Ugej9OP6YiiTRmgiixtynPiiUgfa6HKvtN/LlC N1dZxUsT0An4oWASUb1fTmDXTBdiRuLbxzD1+FFvb7KEA8e7F+BGp+Q8nJcsdY7LhN3K BkcgkvPCYX7gyjK/alM5QobBJeuFp2TJ1ukoukPth3WyO0ApHJtclv2Y7V9QpauDb4Io VwUA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:from:reply-to:in-reply-to:references :mime-version:dkim-signature; bh=6nmBWXnZpcZYv0A7vmjLfWKpipHOZcT1fGuX0SBNQwI=; fh=++3S2BXtj87KI9SEx6rcLOptGaJ0t8C8cnN6u95gTfI=; b=XK6yj2bGeWXYjEtAFKoO05ZtQGnBo7IP1+uFR/awxkFCcKMu+xF/ZPHFVF9tUNUJ9t 5c0+/b4aHRUk6L4FvJF3FCI2sWK7iMyPGm1lcu1PYMfKfJh2bk1e7tkvUY/Q7gFw0vnk OGZ6FATpYwXgNXsOipZupdo3e4cp3ALg6ISM6d2O0eYiwDQFQv+39Rky6itVfWjYYgNr b1RaMf0AcNzifGtGFIJZ9cIXcLraxSwSme+cJz1eR9GDHKRo1X7HyCBU4S7/nSUl9gm+ +Jr9/OBFaENQsh6W9lc03s2jnQvHKEV0zkcvt+476i6C7sjLpe9hlNMUsJqbHP076kD6 FhGw==; darn=postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1781140857; x=1781745657; darn=postgresql.org; h=cc:to:subject:message-id:date:from:reply-to:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=6nmBWXnZpcZYv0A7vmjLfWKpipHOZcT1fGuX0SBNQwI=; b=Gtoiv4V7NNJj9kctsVbCZq2xBWYWEdmU3PhQJ+hLMwq3cbhojLGtctVJr4vxXQFKqf GIhWtq2vXXLTBxfAVIjtWxaItI3n3GxZqEQTChE17SQ/iZGOCh7Z8fFpiSovBzLjT+Rz CA8RIzmnMf06PUp0J9WmAZq0AkJ1YTgOOxzzG39/S18N8iSTJHGpRbnlW8QJYHiwjLi0 ck8jR+AJ6FLoHL63+cqYDC37rlGR8//4rEsfBTy35cFeF+ghj+B5nyV1W7pzme46XhpH WYLET32dDa/zJX8V5V84bBtNhEQemtU9EgINjc8kVl3+3gjH489xQEOldnvejsIAfQiB tv8w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781140857; x=1781745657; h=cc:to:subject:message-id:date:from:reply-to:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=6nmBWXnZpcZYv0A7vmjLfWKpipHOZcT1fGuX0SBNQwI=; b=ieN6ncf9j158fDz1uUzLloNDk+HouBz6Bz5u0VjzkY2IpTKLyU6WOSfippYJfrJ2JF V/sL0O9SIae6PVgSgR0kXZYEw9R5GwRdrNaFpMlm13l0SqpDq00fqZFkA9yP8fA1ApCi dIwj5LDBGE2j96U+1PPng1+ypMW4L5tPPCkj8rXgYla2LyByEnDQA3p8EykwBTBDhLIi ZUkP7bXga80LKwKaM/zQins7bkvh0uG+jUMLB412BI5TWVMQ1fdvxY3VMEvMZzdf4ATi orFKAl7GuPUHZzJfMyqM/rtsfp9++f0nlMjVxR3ekgQjplgYyuLmphriPOMQwlgKbln4 2Q7A== X-Forwarded-Encrypted: i=1; AFNElJ9HWBYsDIOp7rI4UvposzjMvhQFJnoLDFIO0HcU8w3RAFDe45gIgK3xSS1w1dHvCBvZQrLNjv2zG+XWpm7D@postgresql.org X-Gm-Message-State: AOJu0Yxaous6OKfR3wCQPooc1TzoXPd4GuAPYWljC1ZFeHFoMoav5tEG iVSsdA7JpAseFVzY0SFNG1irbq3KRHCGR6AY6KogpxeSAxomjjF6kDHCkzsAIt4oKsGWm2BaXvg a1ZIAziBuqIwthQh4txOwLiAxnp9rTng= X-Gm-Gg: Acq92OHIidmELO62NXsmWud5oiR7cka7l5Kfmdf3Q1FTS66el7s3pvWUV/m2iQoBVIs /K5hp3ewtnmii2SZJvjv8GniqNw1xKIrczMtrjmDX2hIwXKK4F+i2ivC2pSceK6VhAF66JRQiRa c+RkRcwKI8N9vbFG/VuxeYvvfjdQINLi/mkIZYQWDoCwt7WyNSGjfF1SfeEu0c0SceUU+7TsK/8 TDSFIq7ZQ5UB+JfMMHJ/I37EEEyfi19m9fzMwUs8Ht4t3rzuZ2W312+yeMxBtO3UheSo1M9EGbo JlsIqhaDRgmRsfOBxA/Y+iwYcxzOfRmO/2c75q9sj2ISSCGKzb0Lf7Sx2wvIktLYnuCzVql/5vC tU4zGxv4SV5Yog8yT2+1n/PmTse6HbkU= X-Received: by 2002:a17:906:8a6b:b0:bd1:ba38:c724 with SMTP id a640c23a62f3a-bfc889352e6mr8551066b.32.1781140857483; Wed, 10 Jun 2026 18:20:57 -0700 (PDT) MIME-Version: 1.0 References: <20260610.231902.1271202110858446443.ishii@postgresql.org> In-Reply-To: <20260610.231902.1271202110858446443.ishii@postgresql.org> Reply-To: assam258@gmail.com From: Henson Choi Date: Thu, 11 Jun 2026 10:20:45 +0900 X-Gm-Features: AVVi8CeOpVUom-XhvLeQPXWRg7K4j7KwbAaVFg05ujMgG9EJXu9L8XASN9v16Kg Message-ID: Subject: Re: Row pattern recognition To: Tatsuo Ishii , jian.universality@gmail.com Cc: zsolt.parragi@percona.com, sjjang112233@gmail.com, vik@postgresfriends.org, er@xs4all.nl, jacob.champion@enterprisedb.com, david.g.johnston@gmail.com, peter@eisentraut.org, li.evan.chao@gmail.com, pgsql-hackers@postgresql.org Content-Type: multipart/alternative; boundary="0000000000001af5f70653f02c05" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --0000000000001af5f70653f02c05 Content-Type: text/plain; charset="UTF-8" Hi Tatsuo, == 1. DEFINE evaluation use-after-free (to Tatsuo) == >> nocfbot-0039 (the DEFINE memory-leak fix) added a ResetExprContext() in >> update_reduced_frame, but it resets the wrong context. >> >> ps_ExprContext is the per-output-tuple context that ExecWindowAgg resets >> once per output row. update_reduced_frame now resets it once per NFA row, >> while the output row is still being formed -- so a pass-by-ref window >> function result already datum-copied into that per-tuple memory (when >> numfuncs > 1) is freed before ExecProject reads it. >> >> Neither v47 nor the patch is the answer on its own: v47 had no reset here, >> so no use-after-free, but the DEFINE scratch accumulated over the whole >> forward scan (the leak nocfbot-0039 fixed); nocfbot-0039 added the per-row >> reset but on the shared per-output-tuple context. We do want a per-row >> reset -- just not on that context. >> >> So I think this needs a dedicated ExprContext for DEFINE evaluation, reset >> once per NFA row: it keeps the memory bounded without touching the >> per-output-tuple results. >> >> Question: does a dedicated DEFINE ExprContext look right to you? > > Can we use winstate->tmpcontext instead? I don't think we can. tmpcontext is idle where update_reduced_frame would reset it, but not *during* DEFINE evaluation: a DEFINE with NEXT() re-enters the spooler from inside its ExecEvalExpr (ExecEvalRPRNavSet -> window_gettupleslot -> spool_tuples), and spool_tuples resets winstate->tmpcontext (via ExecQualAndReset on partEqfunction) for every input row it pulls under a PARTITION BY. ExecEvalRPRNavRestore parks a pass-by-ref nav result in that per-tuple memory to survive until the next reset. To give one example, -- the cast forces a pass-by-ref result; a by-value bigint is safe DEFINE b AS PREV(price::numeric) < NEXT(price::numeric) frees PREV's result when NEXT spools the next row, before numeric_lt() reads it -- the same use-after-free as nocfbot-0039, just on a different context. It is the normal forward-scan path (the NFA runs ahead of the spool), and after a tuplestore spill even NEXT-free DEFINEs hit it. More generally, tmpcontext fits its existing users because each one sets its slots, evaluates, and resets within a shallow, straight-line region; it is best kept to that limited, low-depth usage. DEFINE evaluation re-enters the spooler mid-expression, so it cannot honor that contract. So I think the dedicated DEFINE ExprContext is the right call: a once-per-NFA-row reset is a third cadence, distinct from tmpcontext (per-input-tuple) and ps_ExprContext (per-output-tuple) -- the same one-context-per-cadence pattern nodeWindowAgg and nodeAgg already use. Thanks, Henson --0000000000001af5f70653f02c05 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi Tatsuo,

=3D=3D 1. DEFINE evaluation use-after-fr= ee (to Tatsuo) =3D=3D

>> nocfbot-0039 (the DEFINE memory-leak = fix) added a ResetExprContext() in
>> update_reduced_frame, but it= resets the wrong context.
>>
>> ps_ExprContext is the pe= r-output-tuple context that ExecWindowAgg resets
>> once per outpu= t row. =C2=A0update_reduced_frame now resets it once per NFA row,
>&g= t; while the output row is still being formed -- so a pass-by-ref window>> function result already datum-copied into that per-tuple memory (= when
>> numfuncs > 1) is freed before ExecProject reads it.
= >>
>> Neither v47 nor the patch is the answer on its own: v4= 7 had no reset here,
>> so no use-after-free, but the DEFINE scrat= ch accumulated over the whole
>> forward scan (the leak nocfbot-00= 39 fixed); nocfbot-0039 added the per-row
>> reset but on the shar= ed per-output-tuple context.=C2=A0 We do want a per-row
>> reset -= - just not on that context.
>>
>> So I think this needs a= dedicated ExprContext for DEFINE evaluation, reset
>> once per NF= A row: it keeps the memory bounded without touching the
>> per-out= put-tuple results.
>>
>> Question: does a dedicated DEFIN= E ExprContext look right to you?
>
> Can we use winstate->tm= pcontext instead?

I don't think we can. =C2=A0tmpcontext is idle= where update_reduced_frame
would reset it, but not *during* DEFINE eval= uation: a DEFINE with NEXT()
re-enters the spooler from inside its ExecE= valExpr (ExecEvalRPRNavSet
-> window_gettupleslot -> spool_tuples)= , and spool_tuples resets
winstate->tmpcontext (via ExecQualAndReset = on partEqfunction) for every
input row it pulls under a PARTITION BY.=C2= =A0 ExecEvalRPRNavRestore parks a
pass-by-ref nav result in that per-tup= le memory to survive until the
next reset.=C2=A0 To give one example,
=C2=A0 -- the cast forces a pass-by-ref result; a by-value bigint is s= afe
=C2=A0 DEFINE b AS PREV(price::numeric) < NEXT(price::numeric)
frees PREV's result when NEXT spools the next row, before numeric_= lt()
reads it -- the same use-after-free as nocfbot-0039, just on a diff= erent
context.=C2=A0 It is the normal forward-scan path (the NFA runs ah= ead of the
spool), and after a tuplestore spill even NEXT-free DEFINEs h= it it.

More generally, tmpcontext fits its existing users because ea= ch one sets
its slots, evaluates, and resets within a shallow, straight-= line region;
it is best kept to that limited, low-depth usage.=C2=A0 DEF= INE evaluation
re-enters the spooler mid-expression, so it cannot honor = that contract.

So I think the dedicated DEFINE ExprContext is the ri= ght call: a
once-per-NFA-row reset is a third cadence, distinct from tmp= context
(per-input-tuple) and ps_ExprContext (per-output-tuple) -- the s= ame
one-context-per-cadence pattern nodeWindowAgg and nodeAgg already us= e.

Thanks,
Henson
--0000000000001af5f70653f02c05--