Re: BUG #16801: Invalid memory access on WITH RECURSIVE with nested WITHs

Michael Paquier <michael@paquier.xyz>

From: Michael Paquier <michael@paquier.xyz>
To: Tom Lane <tgl@sss.pgh.pa.us>
Cc: Alexander Lakhin <exclusion@gmail.com>, pgsql-bugs@lists.postgresql.org
Date: 2021-02-25T02:30:36Z
Lists: pgsql-bugs
On Wed, Feb 24, 2021 at 09:13:46PM -0500, Tom Lane wrote:
> Michael Paquier <michael@paquier.xyz> writes:
>> WITH RECURSIVE outermost(x) AS (
>>   SELECT 1
>>   UNION (WITH innermost as (WITH innermost2 AS (SELECT 2) SELECT * FROM innermost2)
>>          SELECT * FROM outermost
>>          UNION SELECT * FROM innermost)
>> )
>> SELECT * FROM outermost ORDER BY 1;
> 
> Hmm, I don't see any failure from that...

Perhaps because you are not compiling with -DUSE_VALGRIND which is why
this fails with only two nested levels?  I get a failure once I do
that.

> In my understanding of the bug, you need at least half a dozen levels of
> WITH nesting to provoke a problem, because nothing will go wrong until the
> innerwiths list gets to be six entries long, causing list.c to move its
> elements array to somewhere else.  If it is possible to fail without that
> then there's still something here that I don't get.

Anyway, I also get a failure without -DUSE_VALGRIND once I apply 6
nested levels:
#1  0x00007ff47eb5b537 in __GI_abort () at abort.c:79
#2  0x000055b24c7b340e in ExceptionalCondition
(conditionName=0x55b24c8e917a "cstate->innerwiths == NIL",
errorType=0x55b24c8e8803 "FailedAssertion",
fileName=0x55b24c8e8a08 "parse_cte.c", lineNumber=869) at
assert.c:69
#3  0x000055b24c2db9a5 in checkWellFormedRecursion
(cstate=0x7ffe2fce8a30) at parse_cte.c:869

Here you go with a test case:
WITH RECURSIVE outermost(x) AS (
  SELECT 1
  UNION (WITH innermost1 AS (
    SELECT 2
    UNION (WITH innermost2 AS (
      SELECT 3
      UNION (WITH innermost3 AS (
        SELECT 4
	UNION (WITH innermost4 AS (
          SELECT 5
          UNION (WITH innermost5 AS (
	    SELECT 6
	    UNION (WITH innermost6 AS (SELECT 7)
	      SELECT * FROM innermost6))
            SELECT * FROM innermost5))
          SELECT * FROM innermost4))
        SELECT * FROM innermost3))
      SELECT * FROM innermost2))
    SELECT * FROM outermost
    UNION SELECT * FROM innermost1)
)
SELECT * FROM outermost ORDER BY 1;

My previous patch and HEAD break on that in
checkWellFormedRecursionWalker(), not your patch.
--
Michael

Commits

  1. Fix list-manipulation bug in WITH RECURSIVE processing.