Fix alignment problem with bbsink_copystream buffer.
authorRobert Haas <rhaas@postgresql.org>
Wed, 19 Jan 2022 13:07:16 +0000 (08:07 -0500)
committerRobert Haas <rhaas@postgresql.org>
Wed, 19 Jan 2022 13:12:08 +0000 (08:12 -0500)
bbsink_copystream wants to store a type byte just before the buffer,
but basebackup.c wants the buffer to be aligned so that it can call
PageIsNew() and PageGetLSN() on it. Therefore, instead of inserting
1 extra byte before the buffer, insert MAXIMUM_ALIGNOF extra bytes
and only use the last one.

On most machines this doesn't cause any problem (except perhaps for
performance) but some buildfarm machines with -fsanitize=alignment
dump core.

Discussion: http://postgr.es/m/CA+TgmoYx5=1A2K9JYV-9zdhyokU4KKTyNQ9q7CiXrX=YBBMWVw@mail.gmail.com

src/backend/replication/basebackup_copy.c

index f42b368c033422454a3988a241061c4baae0c591..8dfdff06449dd94a16852e42b82b881676442a59 100644 (file)
@@ -152,18 +152,22 @@ bbsink_copystream_begin_backup(bbsink *sink)
 {
    bbsink_copystream *mysink = (bbsink_copystream *) sink;
    bbsink_state *state = sink->bbs_state;
+   char *buf;
 
    /*
     * Initialize buffer. We ultimately want to send the archive and manifest
     * data by means of CopyData messages where the payload portion of each
-    * message begins with a type byte, so we set up a buffer that begins with
-    * a the type byte we're going to need, and then arrange things so that
-    * the data we're given will be written just after that type byte. That
-    * will allow us to ship the data with a single call to pq_putmessage and
-    * without needing any extra copying.
+    * message begins with a type byte. However, basebackup.c expects the
+    * buffer to be aligned, so we can't just allocate one extra byte for the
+    * type byte. Instead, allocate enough extra bytes that the portion of
+    * the buffer we reveal to our callers can be aligned, while leaving room
+    * to slip the type byte in just beforehand.  That will allow us to ship
+    * the data with a single call to pq_putmessage and without needing any
+    * extra copying.
     */
-   mysink->msgbuffer = palloc(mysink->base.bbs_buffer_length + 1);
-   mysink->base.bbs_buffer = mysink->msgbuffer + 1;
+   buf = palloc(mysink->base.bbs_buffer_length + MAXIMUM_ALIGNOF);
+   mysink->msgbuffer = buf + (MAXIMUM_ALIGNOF - 1);
+   mysink->base.bbs_buffer = buf + MAXIMUM_ALIGNOF;
    mysink->msgbuffer[0] = 'd'; /* archive or manifest data */
 
    /* Tell client the backup start location. */