pgpool2.git / summary / log / commit / refs

commit    9a316b28dc90dc83c454a5be7bfb140ff51211f5
Author:   Tatsuo Ishii <ishii at sraoss.co.jp>
Date:     Tue Apr 13 04:14:08 2010 +0000

    Fix long standing bug which causes segfault of pgpool child process.
    This was caused buy miscalculation of shmem size in pgpool parent.
    The bug appears in at least following sequence in 64bit linux
    platform:
    
    1) set max_pool = 1 and num_init_children = 30
    2) connect to the pgpool child which was forked lastly
    3) let pgpool child die by SIGQUIT and fork (i.e. failover,
       child_life_time timeout etc.)
    4) if tries to connect to #3 child, it segfaults
    
    This bug has been there since pgpool-II 1.0 was born.
    
    Bug analysis by Toshihiro Kitagawa.


child.c | 7 ++++--- main.c | 13 +++++++++++-- pool_connection_pool.c | 10 +++++----- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/child.c b/child.c index 6055443e6..06bfeac6e 100644 --- a/child.c +++ b/child.c @@ -1066,22 +1066,23 @@ void cancel_request(CancelPacket *sp) int i; ConnectionInfo *c = NULL; CancelPacket cp; + int loop_num = pool_config->num_init_children*pool_config->max_pool*MAX_NUM_BACKENDS; pool_debug("Cancel request received"); /* look for cancel key from shmem info */ - for (i=0;i<pool_config->num_init_children*pool_config->max_pool;i++) + for (i=0;i<loop_num;i++) { c = &con_info[i]; if (c->pid == sp->pid && c->key == sp->key) { pool_debug("found pid:%d key:%d i:%d",c->pid, c->key,i); - c = &con_info[i/pool_config->max_pool * pool_config->max_pool]; + c = &con_info[i/(pool_config->max_pool * pool_config->max_pool)]; break; } } - if (i == pool_config->num_init_children*pool_config->max_pool) + if (i == loop_num) return; /* invalid key */ for (i=0;i<NUM_BACKENDS;i++,c++) diff --git a/main.c b/main.c index acd2de3cb..e4ba9e17e 100644 --- a/main.c +++ b/main.c @@ -399,7 +399,16 @@ int main(int argc, char **argv) inet_fd = create_inet_domain_socket(pool_config->listen_addresses, pool_config->port); } - size = pool_config->num_init_children * pool_config->max_pool * sizeof(ConnectionInfo); + /* + * con_info is a 3 dimension array: i corresponds to pgpool child + * process, j corresponds to connection pool in each process and k + * corresponds to backends in each connection pool. + * + * XXX: Before 2010/4/12 this was a 2 dimension array: i + * corresponds to pgpool child process, j corresponds to + * connection pool in each process. Of course this was wrong. + */ + size = pool_config->num_init_children * pool_config->max_pool * MAX_NUM_BACKENDS * sizeof(ConnectionInfo); con_info = pool_shared_memory_create(size); if (con_info == NULL) { @@ -418,7 +427,7 @@ int main(int argc, char **argv) memset(pids, 0, size); for (i = 0; i < pool_config->num_init_children; i++) { - pids[i].connection_info = &con_info[i * pool_config->max_pool]; + pids[i].connection_info = &con_info[i * pool_config->max_pool * MAX_NUM_BACKENDS]; } /* create fail over/switch over event area */ diff --git a/pool_connection_pool.c b/pool_connection_pool.c index 2458d3e35..82d748c9b 100644 --- a/pool_connection_pool.c +++ b/pool_connection_pool.c @@ -69,7 +69,7 @@ int pool_init_cp(void) for (i = 0; i < pool_config->max_pool; i++) { pool_connection_pool[i].info = &(MY_PROCESS_INFO.connection_info[i]); - memset(pool_connection_pool[i].info, 0, sizeof(ConnectionInfo)); + memset(pool_connection_pool[i].info, 0, sizeof(ConnectionInfo) * MAX_NUM_BACKENDS); } return 0; } @@ -154,7 +154,7 @@ POOL_CONNECTION_POOL *pool_get_cp(char *user, char *database, int protoMajor, in info = p->info; memset(p, 0, sizeof(POOL_CONNECTION_POOL_SLOT)); p->info = info; - memset(p->info, 0, sizeof(ConnectionInfo)); + memset(p->info, 0, sizeof(ConnectionInfo) * MAX_NUM_BACKENDS); POOL_SETMASK(&oldmask); return NULL; } @@ -201,7 +201,7 @@ void pool_discard_cp(char *user, char *database, int protoMajor) info = p->info; memset(p, 0, sizeof(POOL_CONNECTION_POOL)); p->info = info; - memset(p->info, 0, sizeof(ConnectionInfo)); + memset(p->info, 0, sizeof(ConnectionInfo) * MAX_NUM_BACKENDS); } @@ -277,7 +277,7 @@ POOL_CONNECTION_POOL *pool_create_cp(void) info = p->info; memset(p, 0, sizeof(POOL_CONNECTION_POOL)); p->info = info; - memset(p->info, 0, sizeof(ConnectionInfo)); + memset(p->info, 0, sizeof(ConnectionInfo) * MAX_NUM_BACKENDS); return new_connection(p); } @@ -383,7 +383,7 @@ void pool_backend_timer(void) info = p->info; memset(p, 0, sizeof(POOL_CONNECTION_POOL)); p->info = info; - memset(p->info, 0, sizeof(ConnectionInfo)); + memset(p->info, 0, sizeof(ConnectionInfo) * MAX_NUM_BACKENDS); } else { [parent: 7b64203c7c5e]