Description
Couse:
Usage of apr_table_overlap() function in the python_merge_config() and the way of handling the pools for resource allocation there. In general using this function in python_merge_config() mismatches the pool designated for global configuration items and the one that has to be used for request local data. By using a global pool for local data two request may collide when accessing this one which leads to the crash.
The solution which works fine for us is to implement and use a custom_table_overlap function, which does apr_table_overlay and then apr_table_compress (similar aproach as in mod_perl):
/*
code begin
*/
/**
-
- modpython_table_overlap
**
- modpython_table_overlap
- Replaces the apr_table_overlap() function using a specific pool
- for the resulting table.
*/
static apr_table_t *modpython_table_overlap(apr_pool_t *p,
apr_table_t *current_table,
apr_table_t *new_table)
{
apr_table_t *merge = apr_table_overlay(p, current_table, new_table);
apr_table_compress(merge, APR_OVERLAP_TABLES_SET);
return merge;
}
/**
-
- python_merge_dir_config
**
*/
- python_merge_dir_config
static void *python_merge_config(apr_pool_t *p, void *current_conf,
void *new_conf)
{
py_config *merged_conf =
(py_config *) apr_pcalloc(p, sizeof(py_config));
py_config *cc = (py_config *) current_conf;
py_config *nc = (py_config *) new_conf;
apr_hash_index_t *hi;
char *key;
apr_ssize_t klen;
hl_entry *hle;
/* we basically allow the local configuration to override global,
- by first copying current values and then new values on top
*/
/** create **/
merged_conf->hlists = apr_hash_make(p);
merged_conf->in_filters = apr_hash_make(p);
merged_conf->out_filters = apr_hash_make(p);
/** merge directives and options **/
merged_conf->directives = modpython_table_overlap(p, cc->directives,
nc->directives);
merged_conf->options = modpython_table_overlap(p, cc->options,
nc->options);
/** copy current **/
merged_conf->authoritative = cc->authoritative;
merged_conf->config_dir = apr_pstrdup(p, cc->config_dir);
for (hi = apr_hash_first(p, cc->hlists); hi; hi=apr_hash_next(hi))
{ apr_hash_this(hi, (const void **)&key, &klen, (void **)&hle); apr_hash_set(merged_conf->hlists, key, klen, (void *)hle); }for (hi = apr_hash_first(p, cc->in_filters); hi; hi=apr_hash_next(hi))
{ apr_hash_this(hi, (const void **)&key, &klen, (void **)&hle); apr_hash_set(merged_conf->in_filters, key, klen, (void *)hle); }for (hi = apr_hash_first(p, cc->out_filters); hi; hi=apr_hash_next(hi))
{ apr_hash_this(hi, (const void **)&key, &klen, (void **)&hle); apr_hash_set(merged_conf->out_filters, key, klen, (void *)hle); }/** copy new **/
if (nc->authoritative != merged_conf->authoritative)
merged_conf->authoritative = nc->authoritative;
if (nc->config_dir)
merged_conf->config_dir = apr_pstrdup(p, nc->config_dir);
for (hi = apr_hash_first(p, nc->hlists); hi; hi=apr_hash_next(hi))
{ apr_hash_this(hi, (const void**)&key, &klen, (void **)&hle); apr_hash_set(merged_conf->hlists, key, klen, (void *)hle); }for (hi = apr_hash_first(p, nc->in_filters); hi; hi=apr_hash_next(hi))
{ apr_hash_this(hi, (const void**)&key, &klen, (void **)&hle); apr_hash_set(merged_conf->in_filters, key, klen, (void *)hle); }for (hi = apr_hash_first(p, nc->out_filters); hi; hi=apr_hash_next(hi))
{ apr_hash_this(hi, (const void**)&key, &klen, (void **)&hle); apr_hash_set(merged_conf->out_filters, key, klen, (void *)hle); } return (void *) merged_conf;
}
/*
code end
*/