In pageinspect/hashfuncs.c, avoid crashes on alignment-picky machines.
authorTom Lane
Fri, 3 Feb 2017 16:34:41 +0000 (11:34 -0500)
committerTom Lane
Fri, 3 Feb 2017 16:34:47 +0000 (11:34 -0500)
On machines with MAXALIGN = 8, the payload of a bytea is not maxaligned,
since it will start 4 bytes into a palloc'd value.  On alignment-picky
hardware, this will cause failures in accesses to 8-byte-wide values
within the page.  We already encountered this problem when we introduced
GIN index inspection functions, and fixed it in commit 84ad68d64.  Make
use of the same function for hash indexes.

A small difficulty is that up to now contrib/pageinspect has not shared
any functions at all across files.  To support that, introduce a common
header file "pageinspect.h" for the module.

Also, move get_page_from_raw() out of ginfuncs.c, where it didn't
especially belong, and put it in rawpage.c which seems a more natural home.

Per buildfarm.

Discussion: https://postgr.es/m/17311.1486134714@sss.pgh.pa.us

contrib/pageinspect/brinfuncs.c
contrib/pageinspect/btreefuncs.c
contrib/pageinspect/fsmfuncs.c
contrib/pageinspect/ginfuncs.c
contrib/pageinspect/hashfuncs.c
contrib/pageinspect/heapfuncs.c
contrib/pageinspect/pageinspect.h [new file with mode: 0644]
contrib/pageinspect/rawpage.c

index 7b877e3d0ca904723e3574a3572b8993388ebce5..2c7963ec19b74973313a5e1dc542c63caed3a82b 100644 (file)
@@ -9,6 +9,8 @@
  */
 #include "postgres.h"
 
+#include "pageinspect.h"
+
 #include "access/htup_details.h"
 #include "access/brin.h"
 #include "access/brin_internal.h"
index 3f09d5f0a45dc96464ff0cfbca1a5a9c45ed49b2..d50ec3a68d9a849ee3f73ec3bab41dec543926f0 100644 (file)
@@ -27,6 +27,8 @@
 
 #include "postgres.h"
 
+#include "pageinspect.h"
+
 #include "access/nbtree.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_am.h"
index 654164616be33dbe04dcdaa2401a6bd2da9bccab..615dab8b13b6d1c8008c70371d19325aece91fef 100644 (file)
@@ -19,6 +19,8 @@
 
 #include "postgres.h"
 
+#include "pageinspect.h"
+
 #include "funcapi.h"
 #include "lib/stringinfo.h"
 #include "miscadmin.h"
index cea77d301edebdc41c7e333a9773f9772b63cb5e..993fc2d9ae15c978f4822189229cf2e1f93b7ff7 100644 (file)
@@ -9,6 +9,8 @@
  */
 #include "postgres.h"
 
+#include "pageinspect.h"
+
 #include "access/gin.h"
 #include "access/gin_private.h"
 #include "access/htup_details.h"
@@ -29,26 +31,6 @@ PG_FUNCTION_INFO_V1(gin_page_opaque_info);
 PG_FUNCTION_INFO_V1(gin_leafpage_items);
 
 
-static Page
-get_page_from_raw(bytea *raw_page)
-{
-   int         raw_page_size;
-   Page        page;
-
-   raw_page_size = VARSIZE(raw_page) - VARHDRSZ;
-   if (raw_page_size < BLCKSZ)
-       ereport(ERROR,
-               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                errmsg("input page too small (%d bytes)", raw_page_size)));
-
-   /* make a copy so that the page is properly aligned for struct access */
-   page = palloc(raw_page_size);
-   memcpy(page, VARDATA(raw_page), raw_page_size);
-
-   return page;
-}
-
-
 Datum
 gin_metapage_info(PG_FUNCTION_ARGS)
 {
index 83b469864a9c11cec7345ddd63298548414c4ee5..49cb12e5189c154c56c50aed7b91c764793b0a5b 100644 (file)
@@ -10,6 +10,8 @@
 
 #include "postgres.h"
 
+#include "pageinspect.h"
+
 #include "access/hash.h"
 #include "access/htup_details.h"
 #include "catalog/pg_type.h"
@@ -48,27 +50,15 @@ typedef struct HashPageStat
 
 /*
  * Verify that the given bytea contains a HASH page, or die in the attempt.
- * A pointer to the page is returned.
+ * A pointer to a palloc'd, properly aligned copy of the page is returned.
  */
 static Page
 verify_hash_page(bytea *raw_page, int flags)
 {
-   Page        page;
-   int         raw_page_size;
+   Page        page = get_page_from_raw(raw_page);
    int         pagetype;
    HashPageOpaque pageopaque;
 
-   raw_page_size = VARSIZE(raw_page) - VARHDRSZ;
-
-   if (raw_page_size != BLCKSZ)
-       ereport(ERROR,
-               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                errmsg("invalid page size"),
-                errdetail("Expected size %d, got %d",
-                          BLCKSZ, raw_page_size)));
-
-   page = VARDATA(raw_page);
-
    if (PageIsNew(page))
        ereport(ERROR,
                (errcode(ERRCODE_INDEX_CORRUPTED),
index 748b1db093046e9f643735b2a21d478f9266b14d..1448effb5031e2963e97878c41c20903ca612921 100644 (file)
@@ -25,6 +25,8 @@
 
 #include "postgres.h"
 
+#include "pageinspect.h"
+
 #include "access/htup_details.h"
 #include "funcapi.h"
 #include "catalog/pg_type.h"
diff --git a/contrib/pageinspect/pageinspect.h b/contrib/pageinspect/pageinspect.h
new file mode 100644 (file)
index 0000000..55ca68f
--- /dev/null
@@ -0,0 +1,21 @@
+/*-------------------------------------------------------------------------
+ *
+ * pageinspect.h
+ *   Common functions for pageinspect.
+ *
+ * Copyright (c) 2017, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *   contrib/pageinspect/pageinspect.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _PAGEINSPECT_H_
+#define _PAGEINSPECT_H_
+
+#include "storage/bufpage.h"
+
+/* in rawpage.c */
+extern Page get_page_from_raw(bytea *raw_page);
+
+#endif   /* _PAGEINSPECT_H_ */
index a2ac078d404787ec04605d7544e3bcfa03286ffe..102f360c6f768663ba200a63261c31f53224a30a 100644 (file)
@@ -15,6 +15,8 @@
 
 #include "postgres.h"
 
+#include "pageinspect.h"
+
 #include "access/htup_details.h"
 #include "catalog/catalog.h"
 #include "catalog/namespace.h"
@@ -158,6 +160,42 @@ get_raw_page_internal(text *relname, ForkNumber forknum, BlockNumber blkno)
    return raw_page;
 }
 
+
+/*
+ * get_page_from_raw
+ *
+ * Get a palloc'd, maxalign'ed page image from the result of get_raw_page()
+ *
+ * On machines with MAXALIGN = 8, the payload of a bytea is not maxaligned,
+ * since it will start 4 bytes into a palloc'd value.  On alignment-picky
+ * machines, this will cause failures in accesses to 8-byte-wide values
+ * within the page.  We don't need to worry if accessing only 4-byte or
+ * smaller fields, but when examining a struct that contains 8-byte fields,
+ * use this function for safety.
+ */
+Page
+get_page_from_raw(bytea *raw_page)
+{
+   Page        page;
+   int         raw_page_size;
+
+   raw_page_size = VARSIZE(raw_page) - VARHDRSZ;
+
+   if (raw_page_size != BLCKSZ)
+       ereport(ERROR,
+               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                errmsg("invalid page size"),
+                errdetail("Expected %d bytes, got %d.",
+                          BLCKSZ, raw_page_size)));
+
+   page = palloc(raw_page_size);
+
+   memcpy(page, VARDATA(raw_page), raw_page_size);
+
+   return page;
+}
+
+
 /*
  * page_header
  *