diff --git a/nscd/aicache.c b/nscd/aicache.c index ef15c373f5..d87e7e966f 100644 --- a/nscd/aicache.c +++ b/nscd/aicache.c @@ -102,7 +102,9 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, int32_t ttl = INT32_MAX; ssize_t total = 0; char *key_copy = NULL; - bool alloca_used = false; + /* If not NULL, dataset is a temporary dataset not inserted into the + database, and needs to be free'd. */ + void *dataset_alloc = NULL; time_t timeout = MAX_TIMEOUT_VALUE; while (!no_more) @@ -173,10 +175,12 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, /* We cannot permanently add the result in the moment. But we can provide the result as is. Store the data in some temporary memory. */ - dataset = (struct dataset *) alloca (total + req->key_len); + dataset = (struct dataset *) malloc (total + req->key_len); + if (dataset == NULL) + goto out; /* We cannot add this record to the permanent database. */ - alloca_used = true; + dataset_alloc = dataset; } /* Fill in the address and address families. */ @@ -345,10 +349,12 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, /* We cannot permanently add the result in the moment. But we can provide the result as is. Store the data in some temporary memory. */ - dataset = (struct dataset *) alloca (total + req->key_len); + dataset = (struct dataset *) malloc (total + req->key_len); + if (dataset == NULL) + goto out; /* We cannot add this record to the permanent database. */ - alloca_used = true; + dataset_alloc = dataset; } /* Fill in the address and address families. */ @@ -400,8 +406,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, resp)) == 0) { /* The data has not changed. We will just bump the - timeout value. Note that the new record has been - allocated on the stack and need not be freed. */ + timeout value. */ dh->timeout = dataset->head.timeout; dh->ttl = dataset->head.ttl; ++dh->nreloads; @@ -419,7 +424,9 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, key_copy = (char *) newp + (key_copy - (char *) dataset); dataset = memcpy (newp, dataset, total + req->key_len); - alloca_used = false; + + free (dataset_alloc); + dataset_alloc = NULL; } /* Mark the old record as obsolete. */ @@ -502,7 +509,7 @@ next_nip: out: __resolv_context_put (ctx); - if (dataset != NULL && !alloca_used) + if (dataset != NULL && dataset_alloc == NULL) { /* If necessary, we also propagate the data to disk. */ if (db->persistent) @@ -528,6 +535,8 @@ next_nip: scratch_buffer_free (&tmpbuf4); scratch_buffer_free (&canonbuf); + free (dataset_alloc); + return timeout; } diff --git a/nscd/hstcache.c b/nscd/hstcache.c index fe91818640..44ef80be77 100644 --- a/nscd/hstcache.c +++ b/nscd/hstcache.c @@ -15,7 +15,6 @@ You should have received a copy of the GNU General Public License along with this program; if not, see . */ -#include #include #include #include @@ -188,7 +187,7 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, /* Determine the I/O structure. */ size_t h_name_len = strlen (hst->h_name) + 1; size_t h_aliases_cnt; - uint32_t *h_aliases_len; + uint32_t *h_aliases_len = NULL; size_t h_addr_list_cnt; char *addresses; char *aliases; @@ -202,7 +201,13 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, for (cnt = 0; hst->h_aliases[cnt] != NULL; ++cnt) ++h_aliases_cnt; /* Determine the length of all aliases. */ - h_aliases_len = (uint32_t *) alloca (h_aliases_cnt * sizeof (uint32_t)); + if (h_aliases_cnt > 0) + { + h_aliases_len = (uint32_t *) reallocarray (NULL, h_aliases_cnt, + sizeof (uint32_t)); + if (h_aliases_len == NULL) + return MAX_TIMEOUT_VALUE; + } total = 0; for (cnt = 0; cnt < h_aliases_cnt; ++cnt) { @@ -216,8 +221,11 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, ++h_addr_list_cnt; if (h_addr_list_cnt == 0) - /* Invalid entry. */ - return MAX_TIMEOUT_VALUE; + { + /* Invalid entry. */ + free (h_aliases_len); + return MAX_TIMEOUT_VALUE; + } total += (sizeof (struct dataset) + h_name_len @@ -228,8 +236,10 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, change. Allocate memory on the cache since it is likely discarded anyway. If it turns out to be necessary to have a new record we can still allocate real memory. */ - bool alloca_used = false; dataset = NULL; + /* If not NULL, dataset is a temporary dataset not inserted into + the database, and needs to be free'd. */ + void *dataset_alloc = NULL; /* If the record contains more than one IP address (used for load balancing etc) don't cache the entry. This is something @@ -245,10 +255,15 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, /* We cannot permanently add the result in the moment. But we can provide the result as is. Store the data in some temporary memory. */ - dataset = (struct dataset *) alloca (total + req->key_len); + dataset = (struct dataset *) malloc (total + req->key_len); + if (dataset == NULL) + { + free (h_aliases_len); + return MAX_TIMEOUT_VALUE; + } /* We cannot add this record to the permanent database. */ - alloca_used = true; + dataset_alloc = dataset; } timeout = datahead_init_pos (&dataset->head, total + req->key_len, @@ -271,7 +286,8 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, cp = dataset->strdata; cp = mempcpy (cp, hst->h_name, h_name_len); - cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (uint32_t)); + if (h_aliases_cnt > 0) + cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (uint32_t)); /* The normal addresses first. */ addresses = cp; @@ -283,6 +299,8 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, for (cnt = 0; cnt < h_aliases_cnt; ++cnt) cp = mempcpy (cp, hst->h_aliases[cnt], h_aliases_len[cnt]); + free (h_aliases_len); + assert (cp == dataset->strdata + total - offsetof (struct dataset, strdata)); @@ -308,8 +326,7 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, dh->allocsize - offsetof (struct dataset, resp)) == 0) { /* The data has not changed. We will just bump the - timeout value. Note that the new record has been - allocated on the stack and need not be freed. */ + timeout value. */ assert (h_addr_list_cnt == 1); dh->ttl = dataset->head.ttl; dh->timeout = dataset->head.timeout; @@ -335,7 +352,9 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, key_copy = (char *) newp + (key_copy - (char *) dataset); dataset = memcpy (newp, dataset, total + req->key_len); - alloca_used = false; + + free (dataset_alloc); + dataset_alloc = NULL; } } @@ -363,7 +382,7 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, the current cache handling cannot handle and it is more than questionable whether it is worthwhile complicating the cache handling just for handling such a special case. */ - if (! alloca_used) + if (dataset_alloc == NULL) { /* If necessary, we also propagate the data to disk. */ if (db->persistent) @@ -394,6 +413,8 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, pthread_rwlock_unlock (&db->lock); } + free (dataset_alloc); + dataset_alloc = NULL; } if (__builtin_expect (!all_written, 0) && debug_level > 0)