CopySerializedPgbson: type the header temp as varattrib_4b

GCC 14's extended -Warray-bounds check for C treats a dereference
through a pointer cast as an access of the *cast type's full size*.
VARSIZE() casts its argument to varattrib_4b *, and that union is 8
bytes wide (it also holds the in-line compressed format). So when
CopySerializedPgbson() passes the address of its 4-byte uint32 header
temp, the checker models an 8-byte access on a 4-byte object and
reports:

  varatt.h:226:45: error: array subscript 'varattrib_4b[0]' is
  partly outside array bounds of 'uint32[1]' [-Werror=array-bounds=]

The code only ever reads va_4byte.va_header, i.e. 4 bytes at offset 0,
so this is a false positive -- but the build uses -Werror, so it
fails.

The failure was architecture dependent even with the same gcc (16.x)
version, because whether the flagged access survives to the analysis
phase depends on target-specific code generation:

- On targets whose backends emit unaligned loads freely (x86-64,
  aarch64, loongarch64, ...), the 4-byte memcpy() of the header plus
  the following read through the varattrib_4b * cast is folded into
  one unaligned 4-byte load straight from the source buffer. No
  access of the local variable remains, so the warning never fires.

- On riscv64 the backend conservatively keeps the memcpy(), since it
  will not emit an unaligned load for a pointer with unknown
  alignment. The subsequent read of the 4-byte local through the
  varattrib_4b * cast then reaches -Warray-bounds, whose modeled
  8-byte access does not fit the uint32 object, and the build fails.

Typing the temporary varattrib_4b makes the checked object 8 bytes,
matching the type the macro casts through, so the modeled access is
in bounds and the warning disappears on every architecture.

The memcpy() is deliberately kept at 4 bytes (not
sizeof(varattrib_4b)): the last serialized value in the state buffer
(the input expression) may sit at the very end of the enclosing
bytea, and an 8-byte copy would read past it. Runtime behaviour is
unchanged, as VARSIZE() only touches the first 4 header bytes.

Refs: https://buildd.debian.org/status/fetch.php?pkg=documentdb&arch=riscv64&ver=1.0~RC1-1&stamp=1790748100&raw=1

--- a/pg_documentdb/src/aggregation/bson_sorted_accumulator.c
+++ b/pg_documentdb/src/aggregation/bson_sorted_accumulator.c
@@ -300,10 +300,17 @@ DeserializeOrderState(bytea *byteArray,
 static pgbson *
 CopySerializedPgbson(char **bytes)
 {
-	uint32 varlenaHeader;
+	varattrib_4b varlenaHeader;
 
-	/* Serialized values can follow one-byte flags, so their addresses may be unaligned. */
-	memcpy(&varlenaHeader, *bytes, sizeof(varlenaHeader));
+	/*
+	 * Serialized values can follow one-byte flags, so their addresses may be
+	 * unaligned. Only the 4 varlena header bytes are copied: the last value
+	 * in the serialized state may sit at the end of the enclosing buffer, and
+	 * varattrib_4b itself is 8 bytes. Using the union as the temporary type
+	 * also keeps GCC's -Warray-bounds happy when VARSIZE() casts the local's
+	 * address back to varattrib_4b *.
+	 */
+	memcpy(&varlenaHeader, *bytes, sizeof(uint32));
 
 	Size bsonSize = VARSIZE(&varlenaHeader);
 	pgbson *bson = palloc(bsonSize);
