1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-08 15:02:10 +03:00

Add wrappers for malloc, calloc, realloc that check for out of memory

situations.  Use them in most places where malloc, and friends are used.
This results in clean error messages in an out of memory situation instead of
segfaulting or silently malfunctioning. In some places, it just allows to
remove some logging code.

PR 51568, PR 51569, PR 51571.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1172686 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Stefan Fritsch
2011-09-19 16:25:42 +00:00
parent e49dcebd01
commit 01ed21af9d
18 changed files with 110 additions and 89 deletions

View File

@@ -12,6 +12,10 @@ Changes with Apache 2.3.15
PR 51714. [Stefan Fritsch, Jim Jagielski, Ruediger Pluem, Eric Covener, PR 51714. [Stefan Fritsch, Jim Jagielski, Ruediger Pluem, Eric Covener,
<lowprio20 gmail.com>] <lowprio20 gmail.com>]
*) Add wrappers for malloc, calloc, realloc that check for out of memory
situations and use them in many places. PR 51568, PR 51569, PR 51571.
[Stefan Fritsch]
*) Fix cross-compilation of mod_cgi/mod_cgid when APR_HAVE_STRUCT_RLIMIT is *) Fix cross-compilation of mod_cgi/mod_cgid when APR_HAVE_STRUCT_RLIMIT is
false but RLIMIT_* are defined. PR51371. [Eric Covener] false but RLIMIT_* are defined. PR51371. [Eric Covener]

View File

@@ -182,4 +182,12 @@
#define ap_func_attr_sentinel #define ap_func_attr_sentinel
#endif #endif
#if ( defined(__GNUC__) && \
(__GNUC__ >= 4 || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 4))) \
|| __has_attribute(warn_unused_result)
#define ap_func_attr_warn_unused_result __attribute__((warn_unused_result))
#else
#define ap_func_attr_warn_unused_result
#endif
#endif /* AP_CONFIG_H */ #endif /* AP_CONFIG_H */

View File

@@ -352,6 +352,8 @@
* 20110724.5 (2.3.15-dev) add ap_set_accept_ranges() * 20110724.5 (2.3.15-dev) add ap_set_accept_ranges()
* 20110724.6 (2.3.15-dev) add max_overlaps and max_reversals to core_dir_config * 20110724.6 (2.3.15-dev) add max_overlaps and max_reversals to core_dir_config
* 20110724.7 (2.3.15-dev) add ap_random_insecure_bytes(), ap_random_pick() * 20110724.7 (2.3.15-dev) add ap_random_insecure_bytes(), ap_random_pick()
* 20110724.8 (2.3.15-dev) add ap_abort_on_oom(), ap_malloc(), ap_calloc(),
* ap_realloc()
*/ */
#define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */ #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
@@ -359,7 +361,7 @@
#ifndef MODULE_MAGIC_NUMBER_MAJOR #ifndef MODULE_MAGIC_NUMBER_MAJOR
#define MODULE_MAGIC_NUMBER_MAJOR 20110724 #define MODULE_MAGIC_NUMBER_MAJOR 20110724
#endif #endif
#define MODULE_MAGIC_NUMBER_MINOR 7 /* 0...n */ #define MODULE_MAGIC_NUMBER_MINOR 8 /* 0...n */
/** /**
* Determine if the server's current MODULE_MAGIC_NUMBER is at least a * Determine if the server's current MODULE_MAGIC_NUMBER is at least a

View File

@@ -2086,6 +2086,38 @@ AP_DECLARE(void) ap_random_insecure_bytes(void *buf, apr_size_t size);
*/ */
AP_DECLARE(apr_uint32_t) ap_random_pick(apr_uint32_t min, apr_uint32_t max); AP_DECLARE(apr_uint32_t) ap_random_pick(apr_uint32_t min, apr_uint32_t max);
/**
* Abort with a error message signifying out of memory
*/
AP_DECLARE(void) ap_abort_on_oom(void) __attribute__((noreturn));
/**
* Wrapper for malloc() that calls ap_abort_on_oom() if out of memory
* @param size size of the memory block
* @return pointer to the allocated memory
* @note ap_malloc may be implemented as a macro
*/
AP_DECLARE(void *) ap_malloc(size_t size) __attribute__((malloc));
/**
* Wrapper for calloc() that calls ap_abort_on_oom() if out of memory
* @param nelem number of elements to allocate memory for
* @param size size of a single element
* @return pointer to the allocated memory
* @note ap_calloc may be implemented as a macro
*/
AP_DECLARE(void *) ap_calloc(size_t nelem, size_t size) __attribute__((malloc));
/**
* Wrapper for realloc() that calls ap_abort_on_oom() if out of memory
* @param ptr pointer to the old memory block (or NULL)
* @param size new size of the memory block
* @return pointer to the reallocated memory
* @note ap_realloc may be implemented as a macro
*/
AP_DECLARE(void *) ap_realloc(void *ptr, size_t size)
ap_func_attr_warn_unused_result;
#define AP_NORESTART APR_OS_START_USEERR + 1 #define AP_NORESTART APR_OS_START_USEERR + 1

View File

@@ -58,7 +58,7 @@ cache_cache_t* cache_init(int max_entries,
cache_cache_free *free_entry) cache_cache_free *free_entry)
{ {
cache_cache_t *tmp; cache_cache_t *tmp;
tmp = malloc(sizeof(cache_cache_t)); tmp = ap_malloc(sizeof(cache_cache_t));
tmp->max_entries = max_entries; tmp->max_entries = max_entries;
tmp->max_size = max_size; tmp->max_size = max_size;
tmp->current_size = 0; tmp->current_size = 0;

View File

@@ -77,23 +77,16 @@ struct cache_hash_t {
*/ */
static cache_hash_entry_t **alloc_array(cache_hash_t *ht, int max) static cache_hash_entry_t **alloc_array(cache_hash_t *ht, int max)
{ {
return calloc(1, sizeof(*ht->array) * (max + 1)); return ap_calloc(1, sizeof(*ht->array) * (max + 1));
} }
cache_hash_t* cache_hash_make(apr_size_t size) cache_hash_t* cache_hash_make(apr_size_t size)
{ {
cache_hash_t *ht; cache_hash_t *ht;
ht = malloc(sizeof(cache_hash_t)); ht = ap_malloc(sizeof(cache_hash_t));
if (!ht) {
return NULL;
}
ht->count = 0; ht->count = 0;
ht->max = size; ht->max = size;
ht->array = alloc_array(ht, ht->max); ht->array = alloc_array(ht, ht->max);
if (!ht->array) {
free(ht);
return NULL;
}
return ht; return ht;
} }
@@ -226,10 +219,7 @@ static cache_hash_entry_t **find_entry(cache_hash_t *ht,
if (he || !val) if (he || !val)
return hep; return hep;
/* add a new entry for non-NULL values */ /* add a new entry for non-NULL values */
he = malloc(sizeof(*he)); he = ap_malloc(sizeof(*he));
if (!he) {
return NULL;
}
he->next = NULL; he->next = NULL;
he->hash = hash; he->hash = hash;
he->key = key; he->key = key;
@@ -260,8 +250,7 @@ void* cache_hash_set(cache_hash_t *ht,
cache_hash_entry_t **hep, *tmp; cache_hash_entry_t **hep, *tmp;
const void *tval; const void *tval;
hep = find_entry(ht, key, klen, val); hep = find_entry(ht, key, klen, val);
/* If hep == NULL, then the malloc() in find_entry failed */ if (*hep) {
if (hep && *hep) {
if (!val) { if (!val) {
/* delete entry */ /* delete entry */
tval = (*hep)->val; tval = (*hep)->val;

View File

@@ -50,17 +50,9 @@ cache_pqueue_t *cache_pq_init(apr_ssize_t n,
cache_pqueue_getpos get, cache_pqueue_getpos get,
cache_pqueue_setpos set) cache_pqueue_setpos set)
{ {
cache_pqueue_t *q; cache_pqueue_t *q = ap_malloc(sizeof(cache_pqueue_t));
if (!(q = malloc(sizeof(cache_pqueue_t)))) {
return NULL;
}
/* Need to allocate n+1 elements since element 0 isn't used. */ /* Need to allocate n+1 elements since element 0 isn't used. */
if (!(q->d = malloc(sizeof(void*) * (n+1)))) { q->d = ap_malloc(sizeof(void*) * (n+1));
free(q);
return NULL;
}
q->avail = q->step = (n+1); /* see comment above about n+1 */ q->avail = q->step = (n+1); /* see comment above about n+1 */
q->pri = pri; q->pri = pri;
q->size = 1; q->size = 1;
@@ -148,7 +140,7 @@ apr_status_t cache_pq_insert(cache_pqueue_t *q, void *d)
/* allocate more memory if necessary */ /* allocate more memory if necessary */
if (q->size >= q->avail) { if (q->size >= q->avail) {
newsize = q->size + q->step; newsize = q->size + q->step;
if (!(tmp = realloc(q->d, sizeof(void*) * newsize))) { if (!(tmp = ap_realloc(q->d, sizeof(void*) * newsize))) {
return APR_EGENERAL; return APR_EGENERAL;
}; };
q->d = tmp; q->d = tmp;

View File

@@ -210,12 +210,7 @@ static apr_status_t socache_dbm_store(ap_socache_instance_t *ctx,
/* create DBM value */ /* create DBM value */
dbmval.dsize = sizeof(apr_time_t) + nData; dbmval.dsize = sizeof(apr_time_t) + nData;
dbmval.dptr = (char *)malloc(dbmval.dsize); dbmval.dptr = (char *)ap_malloc(dbmval.dsize);
if (dbmval.dptr == NULL) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"malloc error creating DBM value");
return APR_ENOMEM;
}
memcpy((char *)dbmval.dptr, &expiry, sizeof(apr_time_t)); memcpy((char *)dbmval.dptr, &expiry, sizeof(apr_time_t));
memcpy((char *)dbmval.dptr+sizeof(apr_time_t), ucaData, nData); memcpy((char *)dbmval.dptr+sizeof(apr_time_t), ucaData, nData);

View File

@@ -109,7 +109,7 @@ static apr_status_t CaseFilterInFilter(ap_filter_t *f,
if(ret != APR_SUCCESS) if(ret != APR_SUCCESS)
return ret; return ret;
buf = malloc(len); buf = ap_malloc(len);
for(n=0 ; n < len ; ++n) for(n=0 ; n < len ; ++n)
buf[n] = apr_toupper(data[n]); buf[n] = apr_toupper(data[n]);

View File

@@ -1384,7 +1384,7 @@ PROXY_DECLARE(char *) ap_proxy_define_balancer(apr_pool_t *p,
(*balancer)->lbmethod = lbmethod; (*balancer)->lbmethod = lbmethod;
if (do_malloc) if (do_malloc)
bshared = malloc(sizeof(proxy_balancer_shared)); bshared = ap_malloc(sizeof(proxy_balancer_shared));
else else
bshared = apr_palloc(p, sizeof(proxy_balancer_shared)); bshared = apr_palloc(p, sizeof(proxy_balancer_shared));
@@ -1798,7 +1798,7 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p,
* if called during config, we don't have shm setup yet, * if called during config, we don't have shm setup yet,
* so just note the info for later. */ * so just note the info for later. */
if (do_malloc) if (do_malloc)
wshared = malloc(sizeof(proxy_worker_shared)); /* will be freed ap_proxy_share_worker */ wshared = ap_malloc(sizeof(proxy_worker_shared)); /* will be freed ap_proxy_share_worker */
else else
wshared = apr_palloc(p, sizeof(proxy_worker_shared)); wshared = apr_palloc(p, sizeof(proxy_worker_shared));

View File

@@ -213,14 +213,14 @@ unsigned char *ssl_asn1_table_set(apr_hash_t *table,
} }
} }
else { else {
asn1 = malloc(sizeof(*asn1)); asn1 = ap_malloc(sizeof(*asn1));
asn1->source_mtime = 0; /* used as a note for encrypted private keys */ asn1->source_mtime = 0; /* used as a note for encrypted private keys */
asn1->cpData = NULL; asn1->cpData = NULL;
} }
asn1->nData = length; asn1->nData = length;
if (!asn1->cpData) { if (!asn1->cpData) {
asn1->cpData = malloc(length); asn1->cpData = ap_malloc(length);
} }
apr_hash_set(table, key, klen, asn1); apr_hash_set(table, key, klen, asn1);

View File

@@ -772,10 +772,10 @@ AP_DECLARE(const char *) ap_setup_prelinked_modules(process_rec *process)
ap_loaded_modules = (module **)apr_palloc(process->pool, ap_loaded_modules = (module **)apr_palloc(process->pool,
sizeof(module *) * conf_vector_length); sizeof(module *) * conf_vector_length);
if (!ap_module_short_names) if (!ap_module_short_names)
ap_module_short_names = calloc(sizeof(char *), conf_vector_length); ap_module_short_names = ap_calloc(sizeof(char *), conf_vector_length);
if (!merger_func_cache) if (!merger_func_cache)
merger_func_cache = calloc(sizeof(merger_func), conf_vector_length); merger_func_cache = ap_calloc(sizeof(merger_func), conf_vector_length);
if (ap_loaded_modules == NULL || ap_module_short_names == NULL if (ap_loaded_modules == NULL || ap_module_short_names == NULL
|| merger_func_cache == NULL) || merger_func_cache == NULL)

View File

@@ -265,14 +265,10 @@ static void destroy_and_exit_process(process_rec *process,
exit(process_exit_value); exit(process_exit_value);
} }
#define OOM_MESSAGE "[crit] Memory allocation failed, " \
"aborting process." APR_EOL_STR
/* APR callback invoked if allocation fails. */ /* APR callback invoked if allocation fails. */
static int abort_on_oom(int retcode) static int abort_on_oom(int retcode)
{ {
write(STDERR_FILENO, OOM_MESSAGE, strlen(OOM_MESSAGE)); ap_abort_on_oom();
abort();
return retcode; /* unreachable, hopefully. */ return retcode; /* unreachable, hopefully. */
} }

View File

@@ -1007,7 +1007,7 @@ static apr_status_t s_socket_add(void *user_baton,
{ {
s_baton_t *s = (s_baton_t*)user_baton; s_baton_t *s = (s_baton_t*)user_baton;
/* XXXXX: recycle listener_poll_types */ /* XXXXX: recycle listener_poll_types */
listener_poll_type *pt = malloc(sizeof(*pt)); listener_poll_type *pt = ap_malloc(sizeof(*pt));
pt->type = PT_SERF; pt->type = PT_SERF;
pt->baton = serf_baton; pt->baton = serf_baton;
pfd->client_data = pt; pfd->client_data = pt;
@@ -1187,7 +1187,7 @@ static apr_status_t event_register_timed_callback(apr_time_t t,
} }
else { else {
/* XXXXX: lol, pool allocation without a context from any thread.Yeah. Right. MPMs Suck. */ /* XXXXX: lol, pool allocation without a context from any thread.Yeah. Right. MPMs Suck. */
te = malloc(sizeof(timer_event_t)); te = ap_malloc(sizeof(timer_event_t));
APR_RING_ELEM_INIT(te, link); APR_RING_ELEM_INIT(te, link);
} }
@@ -1766,7 +1766,7 @@ static void create_listener_thread(thread_starter * ts)
proc_info *my_info; proc_info *my_info;
apr_status_t rv; apr_status_t rv;
my_info = (proc_info *) malloc(sizeof(proc_info)); my_info = (proc_info *) ap_malloc(sizeof(proc_info));
my_info->pid = my_child_num; my_info->pid = my_child_num;
my_info->tid = -1; /* listener thread doesn't have a thread slot */ my_info->tid = -1; /* listener thread doesn't have a thread slot */
my_info->sd = 0; my_info->sd = 0;
@@ -1865,12 +1865,7 @@ static void *APR_THREAD_FUNC start_threads(apr_thread_t * thd, void *dummy)
continue; continue;
} }
my_info = (proc_info *) malloc(sizeof(proc_info)); my_info = (proc_info *) ap_malloc(sizeof(proc_info));
if (my_info == NULL) {
ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf,
"malloc: out of memory");
clean_child_exit(APEXIT_CHILDFATAL);
}
my_info->pid = my_child_num; my_info->pid = my_child_num;
my_info->tid = i; my_info->tid = i;
my_info->sd = 0; my_info->sd = 0;
@@ -2047,16 +2042,8 @@ static void child_main(int child_num_arg)
/* clear the storage; we may not create all our threads immediately, /* clear the storage; we may not create all our threads immediately,
* and we want a 0 entry to indicate a thread which was not created * and we want a 0 entry to indicate a thread which was not created
*/ */
threads = (apr_thread_t **) calloc(1, threads = ap_calloc(threads_per_child, sizeof(apr_thread_t *));
sizeof(apr_thread_t *) * ts = apr_palloc(pchild, sizeof(*ts));
threads_per_child);
if (threads == NULL) {
ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf,
"malloc: out of memory");
clean_child_exit(APEXIT_CHILDFATAL);
}
ts = (thread_starter *) apr_palloc(pchild, sizeof(*ts));
apr_threadattr_create(&thread_attr, pchild); apr_threadattr_create(&thread_attr, pchild);
/* 0 means PTHREAD_CREATE_JOINABLE */ /* 0 means PTHREAD_CREATE_JOINABLE */

View File

@@ -1006,7 +1006,7 @@ static void create_listener_thread(thread_starter *ts)
proc_info *my_info; proc_info *my_info;
apr_status_t rv; apr_status_t rv;
my_info = (proc_info *)malloc(sizeof(proc_info)); my_info = (proc_info *)ap_malloc(sizeof(proc_info));
my_info->pid = my_child_num; my_info->pid = my_child_num;
my_info->tid = -1; /* listener thread doesn't have a thread slot */ my_info->tid = -1; /* listener thread doesn't have a thread slot */
my_info->sd = 0; my_info->sd = 0;
@@ -1072,12 +1072,7 @@ static void * APR_THREAD_FUNC start_threads(apr_thread_t *thd, void *dummy)
continue; continue;
} }
my_info = (proc_info *)malloc(sizeof(proc_info)); my_info = (proc_info *)ap_malloc(sizeof(proc_info));
if (my_info == NULL) {
ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf,
"malloc: out of memory");
clean_child_exit(APEXIT_CHILDFATAL);
}
my_info->pid = my_child_num; my_info->pid = my_child_num;
my_info->tid = i; my_info->tid = i;
my_info->sd = 0; my_info->sd = 0;
@@ -1271,14 +1266,8 @@ static void child_main(int child_num_arg)
/* clear the storage; we may not create all our threads immediately, /* clear the storage; we may not create all our threads immediately,
* and we want a 0 entry to indicate a thread which was not created * and we want a 0 entry to indicate a thread which was not created
*/ */
threads = (apr_thread_t **)calloc(1, threads = (apr_thread_t **)ap_calloc(1,
sizeof(apr_thread_t *) * threads_per_child); sizeof(apr_thread_t *) * threads_per_child);
if (threads == NULL) {
ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf,
"malloc: out of memory");
clean_child_exit(APEXIT_CHILDFATAL);
}
ts = (thread_starter *)apr_palloc(pchild, sizeof(*ts)); ts = (thread_starter *)apr_palloc(pchild, sizeof(*ts));
apr_threadattr_create(&thread_attr, pchild); apr_threadattr_create(&thread_attr, pchild);

View File

@@ -75,7 +75,7 @@ static extra_process_t *extras;
void ap_register_extra_mpm_process(pid_t pid, ap_generation_t gen) void ap_register_extra_mpm_process(pid_t pid, ap_generation_t gen)
{ {
extra_process_t *p = (extra_process_t *)malloc(sizeof(extra_process_t)); extra_process_t *p = (extra_process_t *)ap_malloc(sizeof(extra_process_t));
p->next = extras; p->next = extras;
p->pid = pid; p->pid = pid;

View File

@@ -149,7 +149,7 @@ void ap_init_scoreboard(void *shared_score)
ap_calc_scoreboard_size(); ap_calc_scoreboard_size();
ap_scoreboard_image = ap_scoreboard_image =
calloc(1, sizeof(scoreboard) + server_limit * sizeof(worker_score *)); ap_calloc(1, sizeof(scoreboard) + server_limit * sizeof(worker_score *));
more_storage = shared_score; more_storage = shared_score;
ap_scoreboard_image->global = (global_score *)more_storage; ap_scoreboard_image->global = (global_score *)more_storage;
more_storage += sizeof(global_score); more_storage += sizeof(global_score);
@@ -325,13 +325,7 @@ int ap_create_scoreboard(apr_pool_t *p, ap_scoreboard_e sb_type)
#endif #endif
{ {
/* A simple malloc will suffice */ /* A simple malloc will suffice */
void *sb_mem = calloc(1, scoreboard_size); void *sb_mem = ap_calloc(1, scoreboard_size);
if (sb_mem == NULL) {
ap_log_error(APLOG_MARK, APLOG_CRIT, 0, ap_server_conf,
"(%d)%s: cannot allocate scoreboard",
errno, strerror(errno));
return HTTP_INTERNAL_SERVER_ERROR;
}
ap_init_scoreboard(sb_mem); ap_init_scoreboard(sb_mem);
} }

View File

@@ -2583,3 +2583,36 @@ AP_DECLARE(void) ap_varbuf_free(struct ap_varbuf *vb)
} }
vb->buf = NULL; vb->buf = NULL;
} }
#define OOM_MESSAGE "[crit] Memory allocation failed, " \
"aborting process." APR_EOL_STR
AP_DECLARE(void) ap_abort_on_oom()
{
write(STDERR_FILENO, OOM_MESSAGE, strlen(OOM_MESSAGE));
abort();
}
AP_DECLARE(void *) ap_malloc(size_t size)
{
void *p = malloc(size);
if (p == NULL && size != 0)
ap_abort_on_oom();
return p;
}
AP_DECLARE(void *) ap_calloc(size_t nelem, size_t size)
{
void *p = calloc(nelem, size);
if (p == NULL && nelem != 0 && size != 0)
ap_abort_on_oom();
return p;
}
AP_DECLARE(void *) ap_realloc(void *ptr, size_t size)
{
void *p = realloc(ptr, size);
if (p == NULL && size != 0)
ap_abort_on_oom();
return p;
}