pageinspect: Fix unaligned struct access in GIN functions
authorPeter Eisentraut <[email protected]>
Fri, 4 Nov 2016 16:00:00 +0000 (12:00 -0400)
committerPeter Eisentraut <[email protected]>
Fri, 4 Nov 2016 14:05:37 +0000 (10:05 -0400)
The raw page data that is passed into the functions will not be aligned
at 8-byte boundaries.  Casting that to a struct and accessing int64
fields will result in unaligned access.  On most platforms, you get away
with it, but it will result on a crash on pickier platforms such as ia64
and sparc64.

contrib/pageinspect/ginfuncs.c

index 145e2ce709cc6d3a8732ebd4d89a3023165599de..6e4103df6a96e19562252c99195c37daed1477b5 100644 (file)
@@ -28,11 +28,31 @@ PG_FUNCTION_INFO_V1(gin_metapage_info);
 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)
 {
    bytea      *raw_page = PG_GETARG_BYTEA_P(0);
-   int         raw_page_size;
    TupleDesc   tupdesc;
    Page        page;
    GinPageOpaque opaq;
@@ -46,12 +66,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 (errmsg("must be superuser to use raw page functions"))));
 
-   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)));
-   page = VARDATA(raw_page);
+   page = get_page_from_raw(raw_page);
 
    opaq = (GinPageOpaque) PageGetSpecialPointer(page);
    if (opaq->flags != GIN_META)
@@ -94,7 +109,6 @@ Datum
 gin_page_opaque_info(PG_FUNCTION_ARGS)
 {
    bytea      *raw_page = PG_GETARG_BYTEA_P(0);
-   int         raw_page_size;
    TupleDesc   tupdesc;
    Page        page;
    GinPageOpaque opaq;
@@ -110,12 +124,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 (errmsg("must be superuser to use raw page functions"))));
 
-   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)));
-   page = VARDATA(raw_page);
+   page = get_page_from_raw(raw_page);
 
    opaq = (GinPageOpaque) PageGetSpecialPointer(page);
 
@@ -173,7 +182,6 @@ Datum
 gin_leafpage_items(PG_FUNCTION_ARGS)
 {
    bytea      *raw_page = PG_GETARG_BYTEA_P(0);
-   int         raw_page_size;
    FuncCallContext *fctx;
    gin_leafpage_items_state *inter_call_data;
 
@@ -182,8 +190,6 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 (errmsg("must be superuser to use raw page functions"))));
 
-   raw_page_size = VARSIZE(raw_page) - VARHDRSZ;
-
    if (SRF_IS_FIRSTCALL())
    {
        TupleDesc   tupdesc;
@@ -191,11 +197,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
        Page        page;
        GinPageOpaque opaq;
 
-       if (raw_page_size < BLCKSZ)
-           ereport(ERROR,
-                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                 errmsg("input page too small (%d bytes)", raw_page_size)));
-       page = VARDATA(raw_page);
+       page = get_page_from_raw(raw_page);
 
        if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GinPageOpaqueData)))
            ereport(ERROR,