Fix possible Assert failure in verify_compact_attribute() master github/master
authorDavid Rowley <[email protected]>
Mon, 16 Jun 2025 22:49:36 +0000 (10:49 +1200)
committerDavid Rowley <[email protected]>
Mon, 16 Jun 2025 22:49:36 +0000 (10:49 +1200)
Sometimes the TupleDesc used in verify_compact_attribute() is shared
among backends, and since CompactAttribute.attcacheoff gets updated
during tuple deformation, it was possible that another backend would
set attcacheoff on a given CompactAttribute in the small window of time
from when the attcacheoff from the live CompactAttribute was being set
in the 'tmp' CompactAttribute and before the Assert verifying that the
live and tmp CompactAttributes matched.

Here we adjust the code to make a copy of the live CompactAttribute so
that we're not trying to Assert against a shared copy of it.

Author: David Rowley <[email protected]>
Reported-by: Alexander Lakhin <[email protected]>
Discussion: https://postgr.es/m/7195e408-758c-4031-8e61-4f842c716ac0@gmail.com

src/backend/access/common/tupdesc.c

index ffd0c78f905a588fa978fcd9f2f270c89f1e5576..020d00cd01ce76f9aa263d46178b7c27d85fd1eb 100644 (file)
@@ -142,10 +142,17 @@ void
 verify_compact_attribute(TupleDesc tupdesc, int attnum)
 {
 #ifdef USE_ASSERT_CHECKING
-   CompactAttribute *cattr = &tupdesc->compact_attrs[attnum];
+   CompactAttribute cattr;
    Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum);
    CompactAttribute tmp;
 
+   /*
+    * Make a temp copy of the TupleDesc's CompactAttribute.  This may be a
+    * shared TupleDesc and the attcacheoff might get changed by another
+    * backend.
+    */
+   memcpy(&cattr, &tupdesc->compact_attrs[attnum], sizeof(CompactAttribute));
+
    /*
     * Populate the temporary CompactAttribute from the corresponding
     * Form_pg_attribute
@@ -156,11 +163,11 @@ verify_compact_attribute(TupleDesc tupdesc, int attnum)
     * Make the attcacheoff match since it's been reset to -1 by
     * populate_compact_attribute_internal.  Same with attnullability.
     */
-   tmp.attcacheoff = cattr->attcacheoff;
-   tmp.attnullability = cattr->attnullability;
+   tmp.attcacheoff = cattr.attcacheoff;
+   tmp.attnullability = cattr.attnullability;
 
    /* Check the freshly populated CompactAttribute matches the TupleDesc's */
-   Assert(memcmp(&tmp, cattr, sizeof(CompactAttribute)) == 0);
+   Assert(memcmp(&tmp, &cattr, sizeof(CompactAttribute)) == 0);
 #endif
 }