Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jYEav-0001Ot-N9 for pgsql-bugs@arkaria.postgresql.org; Mon, 11 May 2020 20:00:09 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1jYEat-0000Ll-VB for pgsql-bugs@arkaria.postgresql.org; Mon, 11 May 2020 20:00:07 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jYEat-0000Le-MC for pgsql-bugs@lists.postgresql.org; Mon, 11 May 2020 20:00:07 +0000 Received: from mail-lj1-x234.google.com ([2a00:1450:4864:20::234]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1jYEar-0001FZ-7Q for pgsql-bugs@lists.postgresql.org; Mon, 11 May 2020 20:00:07 +0000 Received: by mail-lj1-x234.google.com with SMTP id u20so671597ljo.1 for ; Mon, 11 May 2020 13:00:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language; bh=Xaknn20B5/fGLUlZIgmqbDY3zFWbTt6MsN4MJ9uHef0=; b=iwDvI27adx6c67boG1XPKlyTczpQo8yR5ahGcJxxubyhnMGanE+yru9FPjWIxWAyhk xZUqww79A51TVPV/pEDbleyRYLjKjAm+kv49ty8LYPw5iSvtNXAy/BXdtxVdrcb8HtA0 ig4AY9S2Qkeu1LbtaLVcsTlxK7Ja0ggJJX0h5c4ILfZVR6njDVA6AohwnocxY8aBdHTE Bnzcc418ulY/D+tVrAS9Rcvk4RsHCr5NDfxP4CAlx1NDQXkeh87uVtoEV6goS84yOxWq 240mbtPc65HAXbPfudVvUf156wy+Sfs0WcR9L1fQCcEbPuycXgxfx4bj9lvR8S9Wni7v a5og== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language; bh=Xaknn20B5/fGLUlZIgmqbDY3zFWbTt6MsN4MJ9uHef0=; b=GnNrOOdJnD0fZlBvJt0hg+gX8edvRDRq2xemIgX9Zp7NXrqnoNSnriDlVXPU7mbbu6 shTXYcFEEc3t3x7WCi4BTMIqGng3+o7DZZPiPxReO72JRNSt5P/97Gnixzc2vq2yOArW EiPmlu1QSPC7uvKsHggEF2a7Xud8tG6YhFZsPrmvMA8LXE9qrVh0i8T8zpbQQw14kZsm 8MeDewCtv94YsbQ5njlpXDpEXQRnlaDMpaqCcVRcbCdW/mZ7dUK7NL66pVMtXAzJhzKE l3GOtWfZz1A5REkcn4yLV6m0stLoUdvxu+17gA+4s7J8/AXlAg5kNW3oPEf7V+UR4hIz IASw== X-Gm-Message-State: AOAM531I7nk1bn/h6s8caYmHH/iSe7y2qXgHBHMw6lC7MzD6O1eKx7CB tOjas2KqoxKOo049wCczaGLMNbMM X-Google-Smtp-Source: ABdhPJyRLeMLAgr01DfNRQwwNt07ykMssd1lkrPkdFsCerqJJ9t0N2jhl+U133BryI6/98tyV/4lAg== X-Received: by 2002:a2e:b8c1:: with SMTP id s1mr12067195ljp.104.1589227203729; Mon, 11 May 2020 13:00:03 -0700 (PDT) Received: from [1.0.0.7] ([178.155.6.211]) by smtp.gmail.com with ESMTPSA id y186sm11885563lfa.91.2020.05.11.13.00.02 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 11 May 2020 13:00:02 -0700 (PDT) Subject: Re: BUG #16329: Valgrind detects an invalid read when building a gist index with buffering To: Tom Lane Cc: pgsql-bugs@lists.postgresql.org References: <16329-7a6aa9b6fa1118a1@postgresql.org> <3dda6945-c147-5afc-7720-38ec6848dafa@gmail.com> <10261.1588705157@sss.pgh.pa.us> From: Alexander Lakhin Message-ID: <93ca4540-0016-8217-2b31-535613499987@gmail.com> Date: Mon, 11 May 2020 23:00:01 +0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.7.0 MIME-Version: 1.0 In-Reply-To: <10261.1588705157@sss.pgh.pa.us> Content-Type: multipart/mixed; boundary="------------B7119CB6BD6C689D22862A98" Content-Language: en-US List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk This is a multi-part message in MIME format. --------------B7119CB6BD6C689D22862A98 Content-Type: multipart/alternative; boundary="------------133C64CC8A2755D7B9134829" --------------133C64CC8A2755D7B9134829 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit Hello Tom, 05.05.2020 21:59, Tom Lane wrote: >> Could you please let me know if the fix is incorrect (or not elaborated >> enough to be included in the upcoming releases) or this issue is false >> positive? > I took a look at this. I see the hazard, but I'm not sure that > I like your proposed quick-fix. Essentially, the problem is that > gistBuildCallback is supposing that the tuple it creates will survive > the execution of its subroutines, which in fact it won't always. > But that means that at some point the tuple pointer it's passed down to > those subroutines becomes a dangling pointer. What guarantee would we > have that the subroutines don't access the tuple after that point? Thanks for your review! Yes, I'm not excited by this fix too, so I'll try to find another not so quick way to fix it. > Or, if we do just hack it as you suggest, there had better be a couple > of fat comments in gistBufferingBuildInsert warning about the hazards. > > I was somewhat dismayed to realize from looking at the code coverage > report that we have exactly zero test coverage of the gist buffering > build code paths today. That's just awful; how did the feature get > committed with no test coverage? Your proposed test additions raise the > coverage in gistbuild.c and gistbuildbuffers.c to something respectable, > at least. But it looks like there are still some potentially-delicate > paths that aren't tested, notably the "have to stop buffering" business. > Can we do better at reasonable cost, or are those paths just never > reached without huge data volume? (Could we make them more reachable > by turning down maintenance_work_mem or some other setting?) Please look at the improved test that makes the code coverage for gistbuildbuffers.c almost 100%. Best regards, Alexander --------------133C64CC8A2755D7B9134829 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: 7bit
Hello Tom,
05.05.2020 21:59, Tom Lane wrote:
Could you please let me know if the fix is incorrect (or not elaborated
enough to be included in the upcoming releases) or this issue is false
positive?
I took a look at this.  I see the hazard, but I'm not sure that
I like your proposed quick-fix.  Essentially, the problem is that
gistBuildCallback is supposing that the tuple it creates will survive
the execution of its subroutines, which in fact it won't always.
But that means that at some point the tuple pointer it's passed down to
those subroutines becomes a dangling pointer.  What guarantee would we
have that the subroutines don't access the tuple after that point?
Thanks for your review!
Yes, I'm not excited by this fix too, so I'll try to find another not so quick way to fix it.
Or, if we do just hack it as you suggest, there had better be a couple
of fat comments in gistBufferingBuildInsert warning about the hazards.

I was somewhat dismayed to realize from looking at the code coverage
report that we have exactly zero test coverage of the gist buffering
build code paths today.  That's just awful; how did the feature get
committed with no test coverage?  Your proposed test additions raise the
coverage in gistbuild.c and gistbuildbuffers.c to something respectable,
at least.  But it looks like there are still some potentially-delicate
paths that aren't tested, notably the "have to stop buffering" business.
Can we do better at reasonable cost, or are those paths just never
reached without huge data volume?  (Could we make them more reachable
by turning down maintenance_work_mem or some other setting?)
Please look at the improved test that makes the code coverage for gistbuildbuffers.c almost 100%.

Best regards,
Alexander
--------------133C64CC8A2755D7B9134829-- --------------B7119CB6BD6C689D22862A98 Content-Type: text/x-patch; charset=UTF-8; name="gist-buffering-test.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="gist-buffering-test.patch" diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index 90edb4061d4..881623c7552 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -3,7 +3,7 @@ -- -- There are other tests to test different GiST opclasses. This is for -- testing GiST code itself. Vacuuming in particular. -create table gist_point_tbl(id int4, p point); +create table gist_point_tbl(id int4, p point, t text); create index gist_pointidx on gist_point_tbl using gist(p); -- Verify the fillfactor and buffering options create index gist_pointidx2 on gist_point_tbl using gist(p) with (buffering = on, fillfactor=50); @@ -21,10 +21,15 @@ create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=101 ERROR: value 101 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- Insert enough data to create a tree that's a couple of levels deep. -insert into gist_point_tbl (id, p) -select g, point(g*10, g*10) from generate_series(1, 10000) g; +insert into gist_point_tbl (id, p, t) +select g, point(g*10, g*10), repeat('x', 250) from generate_series(1, 20000) g; +insert into gist_point_tbl (id, p, t) +select g, point(g*10, g*10), repeat('x', 250) from generate_series(1, 20000) g; insert into gist_point_tbl (id, p) select g+100000, point(g*10+1, g*10+1) from generate_series(1, 10000) g; +-- Test buffering index build with data +create index gist_pointidx6 on gist_point_tbl using gist(p) include(t) with (buffering = on, fillfactor=50); +drop index gist_pointidx6; -- To test vacuum, delete some entries from all over the index. delete from gist_point_tbl where id % 2 = 1; -- And also delete some concentration of values. diff --git a/src/test/regress/sql/gist.sql b/src/test/regress/sql/gist.sql index b9d398ea941..4e39cf176dc 100644 --- a/src/test/regress/sql/gist.sql +++ b/src/test/regress/sql/gist.sql @@ -4,7 +4,7 @@ -- There are other tests to test different GiST opclasses. This is for -- testing GiST code itself. Vacuuming in particular. -create table gist_point_tbl(id int4, p point); +create table gist_point_tbl(id int4, p point, t text); create index gist_pointidx on gist_point_tbl using gist(p); -- Verify the fillfactor and buffering options @@ -19,12 +19,19 @@ create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=101); -- Insert enough data to create a tree that's a couple of levels deep. -insert into gist_point_tbl (id, p) -select g, point(g*10, g*10) from generate_series(1, 10000) g; +insert into gist_point_tbl (id, p, t) +select g, point(g*10, g*10), repeat('x', 250) from generate_series(1, 20000) g; + +insert into gist_point_tbl (id, p, t) +select g, point(g*10, g*10), repeat('x', 250) from generate_series(1, 20000) g; insert into gist_point_tbl (id, p) select g+100000, point(g*10+1, g*10+1) from generate_series(1, 10000) g; +-- Test buffering index build with data +create index gist_pointidx6 on gist_point_tbl using gist(p) include(t) with (buffering = on, fillfactor=50); +drop index gist_pointidx6; + -- To test vacuum, delete some entries from all over the index. delete from gist_point_tbl where id % 2 = 1; --------------B7119CB6BD6C689D22862A98--