On Thu, Mar 24, 2022 at 04:27:40PM +0800, Julien Rouhaud wrote:
> I worked on a patch to fix the problem.  The functions you mention were indeed
> missing some check, but after digging a bit more I found that other problem
> existed.  For instance, feeding a btree page to a gist_page_items_bytea() 
> (both
> pages have the same special size) can be quite problematic too, as you can end
> up accessing bogus data when retrieving the items.  I also added additional
> sanity checks with what is available (gist_page_id for gist, zero-level for
> btree leaf pages and so on), and tried to cover everything with tests.

Thanks for the patch!

I have reviewed what you have sent, bumping on a couple of issues:
- The tests of btree and BRIN failed with 32-bit builds, because
MAXALIGN returns shorter special area sizes in those cases.  This can
be fixed by abusing of \set VERBOSITY to mask the error details.  We
already do that in some of the tests to make them portable.
- Some of the tests were not necessary, overlapping with stuff that
already existed.
- Some checks missed a MAXALIGN().
- Did some tweaks with the error messages.
- Some error messages used an incorrect term to define the index AM
type, aka s/gist/GiST/ or s/brin/BRIN/.
- errdetail() requires a sentence, finishing with a dot (some places
of hashfuncs.c missed that.
- Not your fault, but hash indexes would complain about corrupted
indexes which could be misleading for the user if passing down a
correct page from an incorrect index AM.
- While on it, I have made the error messages more generic in the
places where I could do so.  What I have finished with seems to have a
good balance.

> I'm a bit worried about the btree tests stability.  I avoid emitting the level
> found to help with that, but it still depends on what other AM will put in
> their special page.

Well, the limit of the pageinspect model comes from the fact that it
is possible to pass down any bytea and all those code paths would
happily process the blobs as long as they are 8kB.  Pages can be
crafted as well to bypass some of the checks.  This is superuser-only,
so people have to be careful, but preventing out-of-bound reads is a
different class of problem, as long as these come from valid pages.

With all that in place, I get the attached.  It is Friday, so I am not
going to take my bets on the buildfarm today with a rather-risky
patch.  Monday/Tuesday will be fine.
--
Michael
From f0f9a9cc10be30e10728bd99bc7425bf7f9d3a9e Mon Sep 17 00:00:00 2001
From: Michael Paquier <mich...@paquier.xyz>
Date: Fri, 25 Mar 2022 11:42:28 +0900
Subject: [PATCH v2] pageinspect: add more sanity checks when accessing pages.

As seen in bug #16527, feeding an incorrect page can lead to ouf-of-bound
reads when trying to access the page special area.  To fix it, check that the
special area has the expected size before trying to access in in the functions
that weren't already doing so.

While at it, add other checks when possible to validate that the given page is
from the expected format to avoid other possible invalid access.

Author: Julien Rouhaud
Reported-By: Alexander Lakhin
Discussion: https://postgr.es/m/16527-ef7606186f0610a1%40postgresql.org
Discussion: https://postgr.es/m/150535d6-65ac-16ee-b28a-851965fc485b%40gmail.com
---
 contrib/pageinspect/brinfuncs.c        | 18 +++++++++++++
 contrib/pageinspect/btreefuncs.c       | 14 +++++++++++
 contrib/pageinspect/expected/brin.out  | 10 ++++++++
 contrib/pageinspect/expected/btree.out | 22 +++++++++++++---
 contrib/pageinspect/expected/gin.out   | 12 +++++++--
 contrib/pageinspect/expected/gist.out  | 12 +++++++--
 contrib/pageinspect/expected/hash.out  | 14 +++++++++--
 contrib/pageinspect/ginfuncs.c         | 22 +++++++++++++---
 contrib/pageinspect/gistfuncs.c        | 35 ++++++++++++++++++++++++++
 contrib/pageinspect/hashfuncs.c        | 11 +++++---
 contrib/pageinspect/sql/brin.sql       |  8 ++++++
 contrib/pageinspect/sql/btree.sql      | 18 ++++++++++---
 contrib/pageinspect/sql/gin.sql        |  9 +++++--
 contrib/pageinspect/sql/gist.sql       |  9 +++++--
 contrib/pageinspect/sql/hash.sql       | 10 ++++++--
 15 files changed, 197 insertions(+), 27 deletions(-)

diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index bf12901ac3..0387b2847a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -58,6 +58,15 @@ brin_page_type(PG_FUNCTION_ARGS)
 
 	page = get_page_from_raw(raw_page);
 
+	/* verify the special space has the expected size */
+	if (PageGetSpecialSize(page) != MAXALIGN(sizeof(BrinSpecialSpace)))
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("input page is not a valid %s page", "BRIN"),
+					 errdetail("Expected special size %d, got %d.",
+							   (int) MAXALIGN(sizeof(BrinSpecialSpace)),
+							   (int) PageGetSpecialSize(page))));
+
 	switch (BrinPageType(page))
 	{
 		case BRIN_PAGETYPE_META:
@@ -86,6 +95,15 @@ verify_brin_page(bytea *raw_page, uint16 type, const char *strtype)
 {
 	Page		page = get_page_from_raw(raw_page);
 
+	/* verify the special space has the expected size */
+	if (PageGetSpecialSize(page) != MAXALIGN(sizeof(BrinSpecialSpace)))
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("input page is not a valid %s page", "BRIN"),
+					 errdetail("Expected special size %d, got %d.",
+							   (int) MAXALIGN(sizeof(BrinSpecialSpace)),
+							   (int) PageGetSpecialSize(page))));
+
 	/* verify the special space says this page is what we want */
 	if (BrinPageType(page) != type)
 		ereport(ERROR,
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index d9628dd664..edb7954bd3 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -613,6 +613,15 @@ bt_page_items_bytea(PG_FUNCTION_ARGS)
 
 		uargs->offset = FirstOffsetNumber;
 
+		/* verify the special space has the expected size */
+		if (PageGetSpecialSize(uargs->page) != MAXALIGN(sizeof(BTPageOpaqueData)))
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("input page is not a valid %s page", "btree"),
+					 errdetail("Expected special size %d, got %d.",
+							   (int) MAXALIGN(sizeof(BTPageOpaqueData)),
+							   (int) PageGetSpecialSize(uargs->page))));
+
 		opaque = (BTPageOpaque) PageGetSpecialPointer(uargs->page);
 
 		if (P_ISMETA(opaque))
@@ -620,6 +629,11 @@ bt_page_items_bytea(PG_FUNCTION_ARGS)
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 					 errmsg("block is a meta page")));
 
+		if (P_ISLEAF(opaque) && opaque->btpo_level != 0)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("block is not a valid leaf page")));
+
 		if (P_ISDELETED(opaque))
 			elog(NOTICE, "page is deleted");
 
diff --git a/contrib/pageinspect/expected/brin.out b/contrib/pageinspect/expected/brin.out
index 10cd36c177..62ee783b60 100644
--- a/contrib/pageinspect/expected/brin.out
+++ b/contrib/pageinspect/expected/brin.out
@@ -52,4 +52,14 @@ SELECT * FROM brin_page_items(get_raw_page('test1_a_idx', 2), 'test1_a_idx')
 CREATE INDEX test1_a_btree ON test1 (a);
 SELECT brin_page_items(get_raw_page('test1_a_btree', 0), 'test1_a_btree');
 ERROR:  "test1_a_btree" is not a BRIN index
+-- Mask DETAIL messages as these are not portable across architectures.
+\set VERBOSITY terse
+-- Invalid special area size
+SELECT brin_page_type(get_raw_page('test1', 0));
+ERROR:  input page is not a valid BRIN page
+SELECT * FROM brin_metapage_info(get_raw_page('test1', 0));
+ERROR:  input page is not a valid BRIN page
+SELECT * FROM brin_revmap_data(get_raw_page('test1', 0));
+ERROR:  input page is not a valid BRIN page
+\set VERBOSITY default
 DROP TABLE test1;
diff --git a/contrib/pageinspect/expected/btree.out b/contrib/pageinspect/expected/btree.out
index 80b3dfe861..8f16891037 100644
--- a/contrib/pageinspect/expected/btree.out
+++ b/contrib/pageinspect/expected/btree.out
@@ -1,5 +1,5 @@
-CREATE TABLE test1 (a int8, b text);
-INSERT INTO test1 VALUES (72057594037927937, 'text');
+CREATE TABLE test1 (a int8, b int4range);
+INSERT INTO test1 VALUES (72057594037927937, '[0,1)');
 CREATE INDEX test1_a_idx ON test1 USING btree (a);
 \x
 SELECT * FROM bt_metap('test1_a_idx');
@@ -78,11 +78,25 @@ SELECT bt_page_stats('test1_a_hash', 0);
 ERROR:  "test1_a_hash" is not a btree index
 SELECT bt_page_items('test1_a_hash', 0);
 ERROR:  "test1_a_hash" is not a btree index
--- Failure with incorrect page size
+SELECT bt_page_items(get_raw_page('test1_a_hash', 0));
+ERROR:  block is a meta page
+CREATE INDEX test1_b_gist ON test1 USING gist(b);
+-- Special area of GiST is the same as btree, this complains about inconsistent
+-- leaf data on the page.
+SELECT bt_page_items(get_raw_page('test1_b_gist', 0));
+ERROR:  block is not a valid leaf page
+-- Several failure modes.
 -- Suppress the DETAIL message, to allow the tests to work across various
--- page sizes.
+-- page sizes and architectures.
 \set VERBOSITY terse
+-- invalid page size
 SELECT bt_page_items('aaa'::bytea);
 ERROR:  invalid page size
+-- invalid special area size
+CREATE INDEX test1_a_brin ON test1 USING brin(a);
+SELECT bt_page_items(get_raw_page('test1', 0));
+ERROR:  input page is not a valid btree page
+SELECT bt_page_items(get_raw_page('test1_a_brin', 0));
+ERROR:  input page is not a valid btree page
 \set VERBOSITY default
 DROP TABLE test1;
diff --git a/contrib/pageinspect/expected/gin.out b/contrib/pageinspect/expected/gin.out
index 802f48284b..b7774105e0 100644
--- a/contrib/pageinspect/expected/gin.out
+++ b/contrib/pageinspect/expected/gin.out
@@ -36,14 +36,22 @@ FROM gin_leafpage_items(get_raw_page('test1_y_idx',
 ?column? | t
 
 DROP TABLE test1;
--- Failure with incorrect page size
+-- Failure with various modes.
 -- Suppress the DETAIL message, to allow the tests to work across various
--- page sizes.
+-- page sizes and architectures.
 \set VERBOSITY terse
+-- invalid page size
 SELECT gin_leafpage_items('aaa'::bytea);
 ERROR:  invalid page size
 SELECT gin_metapage_info('bbb'::bytea);
 ERROR:  invalid page size
 SELECT gin_page_opaque_info('ccc'::bytea);
 ERROR:  invalid page size
+-- invalid special area size
+SELECT * FROM gin_metapage_info(get_raw_page('test1', 0));
+ERROR:  relation "test1" does not exist
+SELECT * FROM gin_page_opaque_info(get_raw_page('test1', 0));
+ERROR:  relation "test1" does not exist
+SELECT * FROM gin_leafpage_items(get_raw_page('test1', 0));
+ERROR:  relation "test1" does not exist
 \set VERBOSITY default
diff --git a/contrib/pageinspect/expected/gist.out b/contrib/pageinspect/expected/gist.out
index 3f33e04066..c18a7091b2 100644
--- a/contrib/pageinspect/expected/gist.out
+++ b/contrib/pageinspect/expected/gist.out
@@ -68,15 +68,23 @@ SELECT itemoffset, ctid, itemlen FROM gist_page_items_bytea(get_raw_page('test_g
 CREATE INDEX test_gist_btree on test_gist(t);
 SELECT gist_page_items(get_raw_page('test_gist_btree', 0), 'test_gist_btree');
 ERROR:  "test_gist_btree" is not a GiST index
--- Failure with incorrect page size
+-- Failure with various modes.
 -- Suppress the DETAIL message, to allow the tests to work across various
--- page sizes.
+-- page sizes and architectures.
 \set VERBOSITY terse
+-- invalid page size
 SELECT gist_page_items_bytea('aaa'::bytea);
 ERROR:  invalid page size
 SELECT gist_page_items('aaa'::bytea, 'test_gist_idx'::regclass);
 ERROR:  invalid page size
 SELECT gist_page_opaque_info('aaa'::bytea);
 ERROR:  invalid page size
+-- invalid special area size
+SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist', 0));
+ERROR:  input page is not a valid GiST page
+SELECT gist_page_items_bytea(get_raw_page('test_gist', 0));
+ERROR:  input page is not a valid GiST page
+SELECT gist_page_items_bytea(get_raw_page('test_gist_btree', 0));
+ERROR:  input page is not a valid GiST page
 \set VERBOSITY default
 DROP TABLE test_gist;
diff --git a/contrib/pageinspect/expected/hash.out b/contrib/pageinspect/expected/hash.out
index 6c606630dd..96c9511457 100644
--- a/contrib/pageinspect/expected/hash.out
+++ b/contrib/pageinspect/expected/hash.out
@@ -167,10 +167,11 @@ ERROR:  page is not a hash bucket or overflow page
 CREATE INDEX test_hash_a_btree ON test_hash USING btree (a);
 SELECT hash_bitmap_info('test_hash_a_btree', 0);
 ERROR:  "test_hash_a_btree" is not a hash index
--- Failure with incorrect page size
+-- Failure with various modes.
 -- Suppress the DETAIL message, to allow the tests to work across various
--- page sizes.
+-- page sizes and architectures.
 \set VERBOSITY terse
+-- invalid page size
 SELECT hash_metapage_info('aaa'::bytea);
 ERROR:  invalid page size
 SELECT hash_page_items('bbb'::bytea);
@@ -179,5 +180,14 @@ SELECT hash_page_stats('ccc'::bytea);
 ERROR:  invalid page size
 SELECT hash_page_type('ddd'::bytea);
 ERROR:  invalid page size
+-- invalid special area size
+SELECT hash_metapage_info(get_raw_page('test_hash', 0));
+ERROR:  input page is not a valid hash page
+SELECT hash_page_items(get_raw_page('test_hash', 0));
+ERROR:  input page is not a valid hash page
+SELECT hash_page_stats(get_raw_page('test_hash', 0));
+ERROR:  input page is not a valid hash page
+SELECT hash_page_type(get_raw_page('test_hash', 0));
+ERROR:  input page is not a valid hash page
 \set VERBOSITY default
 DROP TABLE test_hash;
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index f55128857e..7ad6d2d3bd 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -49,6 +49,14 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 
 	page = get_page_from_raw(raw_page);
 
+	if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GinPageOpaqueData)))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("input page is not a valid GIN metapage"),
+				 errdetail("Expected special size %d, got %d.",
+						   (int) MAXALIGN(sizeof(GinPageOpaqueData)),
+						   (int) PageGetSpecialSize(page))));
+
 	opaq = (GinPageOpaque) PageGetSpecialPointer(page);
 	if (opaq->flags != GIN_META)
 		ereport(ERROR,
@@ -107,6 +115,14 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 
 	page = get_page_from_raw(raw_page);
 
+	if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GinPageOpaqueData)))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("input page is not a valid GIN data leaf page"),
+				 errdetail("Expected special size %d, got %d.",
+						   (int) MAXALIGN(sizeof(GinPageOpaqueData)),
+						   (int) PageGetSpecialSize(page))));
+
 	opaq = (GinPageOpaque) PageGetSpecialPointer(page);
 
 	/* Build a tuple descriptor for our result type */
@@ -188,9 +204,9 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 					 errmsg("input page is not a valid GIN data leaf page"),
-					 errdetail("Special size %d, expected %d",
-							   (int) PageGetSpecialSize(page),
-							   (int) MAXALIGN(sizeof(GinPageOpaqueData)))));
+					 errdetail("Expected special size %d, got %d.",
+							   (int) MAXALIGN(sizeof(GinPageOpaqueData)),
+							   (int) PageGetSpecialSize(page))));
 
 		opaq = (GinPageOpaque) PageGetSpecialPointer(page);
 		if (opaq->flags != (GIN_DATA | GIN_LEAF | GIN_COMPRESSED))
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index a31cff47fe..6bb81ffb84 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -55,7 +55,23 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 
 	page = get_page_from_raw(raw_page);
 
+	/* verify the special space has the expected size */
+	if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GISTPageOpaqueData)))
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("input page is not a valid %s page", "GiST"),
+					 errdetail("Expected special size %d, got %d.",
+							   (int) MAXALIGN(sizeof(GISTPageOpaqueData)),
+							   (int) PageGetSpecialSize(page))));
+
 	opaq = (GISTPageOpaque) PageGetSpecialPointer(page);
+	if (opaq->gist_page_id != GIST_PAGE_ID)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("input page is not a valid %s page", "GiST"),
+					 errdetail("Expected %08x, got %08x.",
+							   GIST_PAGE_ID,
+							   opaq->gist_page_id)));
 
 	/* Build a tuple descriptor for our result type */
 	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
@@ -101,6 +117,7 @@ gist_page_items_bytea(PG_FUNCTION_ARGS)
 	bytea	   *raw_page = PG_GETARG_BYTEA_P(0);
 	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
 	Page		page;
+	GISTPageOpaque opaq;
 	OffsetNumber offset;
 	OffsetNumber maxoff = InvalidOffsetNumber;
 
@@ -113,6 +130,24 @@ gist_page_items_bytea(PG_FUNCTION_ARGS)
 
 	page = get_page_from_raw(raw_page);
 
+	/* verify the special space has the expected size */
+	if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GISTPageOpaqueData)))
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("input page is not a valid %s page", "GiST"),
+					 errdetail("Expected special size %d, got %d.",
+							   (int) MAXALIGN(sizeof(GISTPageOpaqueData)),
+							   (int) PageGetSpecialSize(page))));
+
+	opaq = (GISTPageOpaque) PageGetSpecialPointer(page);
+	if (opaq->gist_page_id != GIST_PAGE_ID)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("input page is not a valid %s page", "GiST"),
+					 errdetail("Expected %08x, got %08x.",
+							   GIST_PAGE_ID,
+							   opaq->gist_page_id)));
+
 	/* Avoid bogus PageGetMaxOffsetNumber() call with deleted pages */
 	if (GistPageIsDeleted(page))
 		elog(NOTICE, "page is deleted");
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff73c363fc..6de21d6608 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -66,14 +66,17 @@ verify_hash_page(bytea *raw_page, int flags)
 
 		if (PageGetSpecialSize(page) != MAXALIGN(sizeof(HashPageOpaqueData)))
 			ereport(ERROR,
-					(errcode(ERRCODE_INDEX_CORRUPTED),
-					 errmsg("index table contains corrupted page")));
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("input page is not a valid %s page", "hash"),
+					 errdetail("Expected special size %d, got %d.",
+							   (int) MAXALIGN(sizeof(HashPageOpaqueData)),
+							   (int) PageGetSpecialSize(page))));
 
 		pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
 		if (pageopaque->hasho_page_id != HASHO_PAGE_ID)
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-					 errmsg("page is not a hash page"),
+					 errmsg("input page is not a valid %s page", "hash"),
 					 errdetail("Expected %08x, got %08x.",
 							   HASHO_PAGE_ID, pageopaque->hasho_page_id)));
 
@@ -134,7 +137,7 @@ verify_hash_page(bytea *raw_page, int flags)
 			ereport(ERROR,
 					(errcode(ERRCODE_INDEX_CORRUPTED),
 					 errmsg("invalid version for metadata"),
-					 errdetail("Expected %d, got %d",
+					 errdetail("Expected %d, got %d.",
 							   HASH_VERSION, metap->hashm_version)));
 	}
 
diff --git a/contrib/pageinspect/sql/brin.sql b/contrib/pageinspect/sql/brin.sql
index 8717229c5d..dc5d1661b6 100644
--- a/contrib/pageinspect/sql/brin.sql
+++ b/contrib/pageinspect/sql/brin.sql
@@ -19,4 +19,12 @@ SELECT * FROM brin_page_items(get_raw_page('test1_a_idx', 2), 'test1_a_idx')
 CREATE INDEX test1_a_btree ON test1 (a);
 SELECT brin_page_items(get_raw_page('test1_a_btree', 0), 'test1_a_btree');
 
+-- Mask DETAIL messages as these are not portable across architectures.
+\set VERBOSITY terse
+-- Invalid special area size
+SELECT brin_page_type(get_raw_page('test1', 0));
+SELECT * FROM brin_metapage_info(get_raw_page('test1', 0));
+SELECT * FROM brin_revmap_data(get_raw_page('test1', 0));
+\set VERBOSITY default
+
 DROP TABLE test1;
diff --git a/contrib/pageinspect/sql/btree.sql b/contrib/pageinspect/sql/btree.sql
index fdda777b9e..44d83f90ba 100644
--- a/contrib/pageinspect/sql/btree.sql
+++ b/contrib/pageinspect/sql/btree.sql
@@ -1,5 +1,5 @@
-CREATE TABLE test1 (a int8, b text);
-INSERT INTO test1 VALUES (72057594037927937, 'text');
+CREATE TABLE test1 (a int8, b int4range);
+INSERT INTO test1 VALUES (72057594037927937, '[0,1)');
 CREATE INDEX test1_a_idx ON test1 USING btree (a);
 
 \x
@@ -26,12 +26,22 @@ CREATE INDEX test1_a_hash ON test1 USING hash(a);
 SELECT bt_metap('test1_a_hash');
 SELECT bt_page_stats('test1_a_hash', 0);
 SELECT bt_page_items('test1_a_hash', 0);
+SELECT bt_page_items(get_raw_page('test1_a_hash', 0));
+CREATE INDEX test1_b_gist ON test1 USING gist(b);
+-- Special area of GiST is the same as btree, this complains about inconsistent
+-- leaf data on the page.
+SELECT bt_page_items(get_raw_page('test1_b_gist', 0));
 
--- Failure with incorrect page size
+-- Several failure modes.
 -- Suppress the DETAIL message, to allow the tests to work across various
--- page sizes.
+-- page sizes and architectures.
 \set VERBOSITY terse
+-- invalid page size
 SELECT bt_page_items('aaa'::bytea);
+-- invalid special area size
+CREATE INDEX test1_a_brin ON test1 USING brin(a);
+SELECT bt_page_items(get_raw_page('test1', 0));
+SELECT bt_page_items(get_raw_page('test1_a_brin', 0));
 \set VERBOSITY default
 
 DROP TABLE test1;
diff --git a/contrib/pageinspect/sql/gin.sql b/contrib/pageinspect/sql/gin.sql
index aadb07856d..7a3bfdfae2 100644
--- a/contrib/pageinspect/sql/gin.sql
+++ b/contrib/pageinspect/sql/gin.sql
@@ -20,11 +20,16 @@ FROM gin_leafpage_items(get_raw_page('test1_y_idx',
 
 DROP TABLE test1;
 
--- Failure with incorrect page size
+-- Failure with various modes.
 -- Suppress the DETAIL message, to allow the tests to work across various
--- page sizes.
+-- page sizes and architectures.
 \set VERBOSITY terse
+-- invalid page size
 SELECT gin_leafpage_items('aaa'::bytea);
 SELECT gin_metapage_info('bbb'::bytea);
 SELECT gin_page_opaque_info('ccc'::bytea);
+-- invalid special area size
+SELECT * FROM gin_metapage_info(get_raw_page('test1', 0));
+SELECT * FROM gin_page_opaque_info(get_raw_page('test1', 0));
+SELECT * FROM gin_leafpage_items(get_raw_page('test1', 0));
 \set VERBOSITY default
diff --git a/contrib/pageinspect/sql/gist.sql b/contrib/pageinspect/sql/gist.sql
index 8abeb19140..e76f6fa8d1 100644
--- a/contrib/pageinspect/sql/gist.sql
+++ b/contrib/pageinspect/sql/gist.sql
@@ -30,13 +30,18 @@ SELECT itemoffset, ctid, itemlen FROM gist_page_items_bytea(get_raw_page('test_g
 CREATE INDEX test_gist_btree on test_gist(t);
 SELECT gist_page_items(get_raw_page('test_gist_btree', 0), 'test_gist_btree');
 
--- Failure with incorrect page size
+-- Failure with various modes.
 -- Suppress the DETAIL message, to allow the tests to work across various
--- page sizes.
+-- page sizes and architectures.
 \set VERBOSITY terse
+-- invalid page size
 SELECT gist_page_items_bytea('aaa'::bytea);
 SELECT gist_page_items('aaa'::bytea, 'test_gist_idx'::regclass);
 SELECT gist_page_opaque_info('aaa'::bytea);
+-- invalid special area size
+SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist', 0));
+SELECT gist_page_items_bytea(get_raw_page('test_gist', 0));
+SELECT gist_page_items_bytea(get_raw_page('test_gist_btree', 0));
 \set VERBOSITY default
 
 DROP TABLE test_gist;
diff --git a/contrib/pageinspect/sql/hash.sql b/contrib/pageinspect/sql/hash.sql
index fcddd706ae..ccc984c086 100644
--- a/contrib/pageinspect/sql/hash.sql
+++ b/contrib/pageinspect/sql/hash.sql
@@ -82,14 +82,20 @@ SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 5));
 CREATE INDEX test_hash_a_btree ON test_hash USING btree (a);
 SELECT hash_bitmap_info('test_hash_a_btree', 0);
 
--- Failure with incorrect page size
+-- Failure with various modes.
 -- Suppress the DETAIL message, to allow the tests to work across various
--- page sizes.
+-- page sizes and architectures.
 \set VERBOSITY terse
+-- invalid page size
 SELECT hash_metapage_info('aaa'::bytea);
 SELECT hash_page_items('bbb'::bytea);
 SELECT hash_page_stats('ccc'::bytea);
 SELECT hash_page_type('ddd'::bytea);
+-- invalid special area size
+SELECT hash_metapage_info(get_raw_page('test_hash', 0));
+SELECT hash_page_items(get_raw_page('test_hash', 0));
+SELECT hash_page_stats(get_raw_page('test_hash', 0));
+SELECT hash_page_type(get_raw_page('test_hash', 0));
 \set VERBOSITY default
 
 DROP TABLE test_hash;
-- 
2.35.1

Attachment: signature.asc
Description: PGP signature

Reply via email to