[PATCH v3 1/1] nscd: replace alloca with malloc in aicache, hstcache [BZ #34624]
DJ Delorie
dj@redhat.com
Sat Sep 26 01:34:21 GMT 2026
This changes the alloca fallback to a malloc fallback
in the addrinfo and host cache code.
---
v3: Simplify error returns. Add h_aliases_len.
v2: Florian suggested storing the malloc'd pointer and using *that* as
the "flag", which simplified the code.
nscd/aicache.c | 24 +++++++++++++++++-------
nscd/hstcache.c | 34 ++++++++++++++++++++++++++--------
2 files changed, 43 insertions(+), 15 deletions(-)
diff --git a/nscd/aicache.c b/nscd/aicache.c
index ef15c373f5..46d05065f9 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. */
@@ -419,7 +425,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 +510,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 +536,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..ea00d741bc 100644
--- a/nscd/hstcache.c
+++ b/nscd/hstcache.c
@@ -202,7 +202,9 @@ 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));
+ h_aliases_len = (uint32_t *) malloc (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 +218,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 +233,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 +252,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,
@@ -283,6 +295,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));
@@ -335,7 +349,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 +379,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 +410,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)
--
2.55.0
More information about the Libc-alpha
mailing list