pgpool2.git / summary / log / commit / refs
commit d6592ea7a95ed48855332037bca285cc6f6a3547
Author: Tatsuo Ishii <ishii@postgresql.org>
Date: Mon Aug 05 12:15:41 2013 +0000
Fix double free bug with on memory query cache reported in bug #68.
The bug occurs when multiple bind/execute messages come after a parse
message. When a parse messages comes, query context is created along
with temp cache. The pointer to the temp cache is added to the temp
cache array when the query executed. Subsequent bind messages uses the
same temp cache pointer to the cache array. This is the source of
double free bug when the cache array discarded. The solution is, reset
temp cache pointer in the query context when the temp cache buffer is
added to the cache array.
pool_memqcache.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/pool_memqcache.c b/pool_memqcache.c
index acb7a740b..f6d6ef7e4 100644
--- a/pool_memqcache.c
+++ b/pool_memqcache.c
@@ -1567,9 +1567,13 @@ static void pool_reset_memqcache_buffer(void)
{
POOL_TEMP_QUERY_CACHE *cache;
+ pool_debug("pool_reset_memqcache_buffer: discard: %p", session_context->query_cache_array);
+
pool_discard_query_cache_array(session_context->query_cache_array);
session_context->query_cache_array = pool_create_query_cache_array();
+ pool_debug("pool_reset_memqcache_buffer: create: %p", session_context->query_cache_array);
+
/*
* if the query context is still under use, we cannot discard
* temporary cache.
@@ -2579,8 +2583,11 @@ void pool_discard_query_cache_array(POOL_QUERY_CACHE_ARRAY *cache_array)
if (!cache_array)
return;
+ pool_debug("pool_discard_query_cache_array: num_caches: %d", cache_array->num_caches);
+
for (i=0;i<cache_array->num_caches;i++)
{
+ pool_debug("pool_discard_query_cache_array: i: %d cache: %p", i, cache_array->caches[i]);
pool_discard_temp_query_cache(cache_array->caches[i]);
}
free(cache_array);
@@ -2597,6 +2604,8 @@ static POOL_QUERY_CACHE_ARRAY * pool_add_query_cache_array(POOL_QUERY_CACHE_ARRA
if (!cache_array)
return cp;
+ pool_debug("pool_add_query_cache_array: num_caches: %d cache: %p", cache_array->num_caches, cache);
+
if (cache_array->num_caches >= cache_array->array_size)
{
cache_array->array_size += POOL_QUERY_CACHE_ARRAY_ALLOCATE_NUM;
@@ -2712,7 +2721,7 @@ static void pool_add_temp_query_cache(POOL_TEMP_QUERY_CACHE *temp_cache, char ki
if ((buflen+data_len+sizeof(int)+1) > pool_config->memqcache_maxcache)
{
- pool_log("pool_add_temp_query_cache: data size exceeds memqcache_maxcache. current:%zd requested:%zd memq_maxcache:%d",
+ pool_debug("pool_add_temp_query_cache: data size exceeds memqcache_maxcache. current:%zd requested:%zd memq_maxcache:%d",
buflen, data_len+sizeof(int)+1, pool_config->memqcache_maxcache);
temp_cache->is_exceeded = true;
return;
@@ -3048,6 +3057,16 @@ void pool_handle_query_cache(POOL_CONNECTION_POOL *backend, char *query, Node *n
{
session_context->query_cache_array =
pool_add_query_cache_array(session_context->query_cache_array, cache);
+ /*
+ * Reset temp_cache pointer in the current query
+ * context so that we don't add the same temp cache to
+ * the cache array. This is necessary such that case
+ * when next query is just a "bind message", without
+ * "parse message". In the case the query context is
+ * reused and same cache pointer will be added to the
+ * query_cache_array which we do not want.
+ */
+ session_context->query_context->temp_cache = NULL;
}
/* Count up temporary SELECT stats */
[parent: 583d188e07fd]