[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