| /* Reduced from apr-1.7.0/tables/apr_hash.c: 'apr_hash_merge' */ |
| |
| /* { dg-additional-options "-Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */ |
| |
| #include "../../gcc.dg/analyzer/analyzer-decls.h" |
| |
| typedef __SIZE_TYPE__ size_t; |
| |
| extern void* |
| memset(void* __s, int __c, size_t __n) |
| __attribute__((__nothrow__, __leaf__, __nonnull__(1))); |
| |
| typedef struct apr_pool_t apr_pool_t; |
| |
| void* |
| apr_palloc(apr_pool_t* p, size_t size) |
| __attribute__((alloc_size(2), nonnull(1))); |
| |
| typedef struct apr_hash_t apr_hash_t; |
| typedef struct apr_hash_index_t apr_hash_index_t; |
| typedef unsigned int (*apr_hashfunc_t)(const char* key, size_t* klen); |
| typedef struct apr_hash_entry_t apr_hash_entry_t; |
| |
| struct apr_hash_entry_t |
| { |
| apr_hash_entry_t* next; |
| unsigned int hash; |
| const void* key; |
| size_t klen; |
| const void* val; |
| }; |
| |
| struct apr_hash_t |
| { |
| apr_pool_t* pool; |
| apr_hash_entry_t** array; |
| /* [...snip.../ */ |
| unsigned int count, max, seed; |
| apr_hashfunc_t hash_func; |
| apr_hash_entry_t* free; |
| }; |
| |
| static apr_hash_entry_t** |
| alloc_array(apr_hash_t* ht, unsigned int max) |
| { |
| return (apr_hash_entry_t **) memset(apr_palloc(ht->pool, sizeof(*ht->array) * (max + 1)), |
| 0, |
| sizeof(*ht->array) * (max + 1)); |
| } |
| |
| apr_hash_t* |
| apr_hash_merge(apr_pool_t* p, |
| const apr_hash_t* overlay, |
| const apr_hash_t* base) |
| { |
| apr_hash_t* res; |
| apr_hash_entry_t* new_vals = NULL; |
| apr_hash_entry_t* iter; |
| unsigned int i, j, k; |
| res = (apr_hash_t *) apr_palloc(p, sizeof(apr_hash_t)); |
| res->pool = p; |
| res->free = NULL; |
| res->hash_func = base->hash_func; |
| res->count = base->count; |
| res->max = (overlay->max > base->max) ? overlay->max : base->max; |
| if (base->count + overlay->count > res->max) { |
| res->max = res->max * 2 + 1; |
| } |
| res->seed = base->seed; |
| res->array = alloc_array(res, res->max); |
| if (base->count + overlay->count) { |
| new_vals = (apr_hash_entry_t *) |
| apr_palloc(p, sizeof(apr_hash_entry_t) * (base->count + overlay->count)); |
| } |
| j = 0; |
| for (k = 0; k <= base->max; k++) { |
| for (iter = base->array[k]; iter; iter = iter->next) { |
| i = iter->hash & res->max; |
| /* We should only warn for the first of these |
| (it's actually a false positive, but we don't have the |
| invariante to know that). */ |
| new_vals[j].klen = iter->klen; /* { dg-warning "dereference of NULL 'new_vals'" } */ |
| /* ...but not for subsequent ones: */ |
| new_vals[j].key = iter->key; /* { dg-bogus "dereference of NULL 'new_vals'" "PR analyzer/108830" } */ |
| new_vals[j].val = iter->val; /* { dg-bogus "dereference of NULL 'new_vals'" "PR analyzer/108830" } */ |
| new_vals[j].hash = iter->hash; /* { dg-bogus "dereference of NULL 'new_vals'" "PR analyzer/108830" } */ |
| new_vals[j].next = res->array[i]; /* { dg-bogus "dereference of NULL 'new_vals'" "PR analyzer/108830" } */ |
| res->array[i] = &new_vals[j]; /* { dg-bogus "dereference of NULL 'new_vals'" "PR analyzer/108830" } */ |
| j++; |
| } |
| } |
| /* [...snip...] */ |
| return res; |
| } |