Fix accessing already freed data in extended query.
authorTatsuo Ishii <ishii@postgresql.org>
Fri, 13 Jul 2018 08:36:00 +0000 (17:36 +0900)
committerTatsuo Ishii <ishii@postgresql.org>
Fri, 13 Jul 2018 08:36:00 +0000 (17:36 +0900)
When previous_message was set and accessed later on, it looked into
already freed data. This is because read_kind_from_backend() set the
pointer to the previous message in session context, and then released
the memory at the end of the function. No report from fields so far. I
just found this while testing Pgpool-II.

To fix this, store the previous message in the session context, rather
than storing the pointer. Also have a flag in the session context to
indicate whether a previous message is actually stored or not.

All the API for previous message has not been changed.

src/context/pool_session_context.c
src/include/context/pool_session_context.h

index 79384d3f367bc97dd9678c0da75f8693e180cb7f..06d94647374991bdf6dc259e2c01fbb032642575 100644 (file)
@@ -1356,7 +1356,7 @@ void pool_pending_message_reset_previous_message(void)
                                (errmsg("pool_pending_message_reset_previous_message: session context is not initialized")));
                return;
        }
-       session_context->previous_message = NULL;
+       session_context->previous_message_exists = false;
 }
 
 /*
@@ -1370,11 +1370,13 @@ void pool_pending_message_set_previous_message(POOL_PENDING_MESSAGE *message)
                                (errmsg("pool_pending_message_set_previous_message: session context is not initialized")));
                return;
        }
-       session_context->previous_message = message;
+       session_context->previous_message_exists = true;
+       memcpy(&session_context->previous_message, message, sizeof(POOL_PENDING_MESSAGE));
 }
 
 /*
- * Get previous message.
+ * Get previous message. This actually returns the address of memory. Do not
+ * try to free using pool_pending_message_free_pending_message().
  */
 POOL_PENDING_MESSAGE *pool_pending_message_get_previous_message(void)
 {
@@ -1384,7 +1386,10 @@ POOL_PENDING_MESSAGE *pool_pending_message_get_previous_message(void)
                                (errmsg("pool_pending_message_get_previous_message: session context is not initialized")));
                return NULL;
        }
-       return session_context->previous_message;
+       if (session_context->previous_message_exists == false)
+               return NULL;
+
+       return &session_context->previous_message;
 }
 
 /*
index b0bec425c81ec98530f856f3a1d4f55cf95ef679..af5ee4972c66c784f6eca3a237de2cc4e5714fb8 100644 (file)
@@ -229,9 +229,12 @@ typedef struct {
        List *pending_messages;
 
        /*
-        * The last pending message. Reset at Ready for query.
+        * The last pending message. Reset at Ready for query.  Note that this is
+        * a shallow copy of pending message.  Once the are is reset,
+        * previos_message_exists is set to false.
         */
-       POOL_PENDING_MESSAGE *previous_message;
+       bool previous_message_exists;
+       POOL_PENDING_MESSAGE previous_message;
 
        /* Protocol major version number */
        int major;