[PATCH v2 1/1] nscd: replace alloca with malloc in aicache, hstcache [BZ #34624]

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Fri Sep 25 18:45:41 GMT 2026



On 23/09/26 21:55, DJ Delorie wrote:
> This changes the alloca fallback to a malloc fallback
> in the addrinfo and host cache code.
> ---
> 
> v2: Florian suggested storing the malloc'd pointer and using *that* as
>     the "flag", which simplified the code.
> 
>  nscd/aicache.c  | 26 +++++++++++++++++++-------
>  nscd/hstcache.c | 16 +++++++++++-----
>  2 files changed, 30 insertions(+), 12 deletions(-)
> 
> diff --git a/nscd/aicache.c b/nscd/aicache.c
> index ef15c373f5..b08723a251 100644
> --- a/nscd/aicache.c
> +++ b/nscd/aicache.c
> @@ -102,7 +102,7 @@ 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;
> +  void *dataset_alloc = NULL;
>    time_t timeout = MAX_TIMEOUT_VALUE;
> 
>    while (!no_more)
> @@ -173,10 +173,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 next_nip;
> 

I think this makes the client see a negative answer when the failure was memory
exhaustion, because status[1] == NSS_STATUS_SUCCESS at this point.  I think it
should go to 'out', similar to scratch_buffer_grow failure.



>        /* We cannot add this record to the permanent database.  */
> -      alloca_used = true;
> +      dataset_alloc = dataset;
>      }
> 
>    /* Fill in the address and address families.  */
> @@ -345,10 +347,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 next_nip;
> 
>        /* We cannot add this record to the permanent database.  */
> -      alloca_used = true;
> +      dataset_alloc = dataset;
>      }
> 
>    /* Fill in the address and address families.  */
> @@ -419,7 +423,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.  */
> @@ -439,6 +445,9 @@ addhstaiX (struct database_dyn *db, int fd,
> request_header *req,
>        goto out;
> 
>  next_nip:
> +      free (dataset_alloc);
> +      dataset_alloc = NULL;
> +

And with the 'goto out' fix above this is not required because this is
no failure that will fall here.

>        if (nss_next_action (nip, status[1]) == NSS_ACTION_RETURN)
>   break;
> 
> @@ -502,7 +511,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 +537,9 @@ next_nip:
>    scratch_buffer_free (&tmpbuf4);
>    scratch_buffer_free (&canonbuf);
> 
> +  free (dataset_alloc);
> +  dataset_alloc = NULL;

The NULL is not strictly required here.

> +
>    return timeout;
>  }
> 
> diff --git a/nscd/hstcache.c b/nscd/hstcache.c
> index fe91818640..bb91fd7a1a 100644
> --- a/nscd/hstcache.c
> +++ b/nscd/hstcache.c
> @@ -228,7 +228,7 @@ 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;
> +      void *dataset_alloc = false;

I think using 'false' is confusing here and out code guidelines as for NULL
(-std=gnu23 rejects it with "incompatible types ...'".

>        dataset = NULL;
> 
>        /* If the record contains more than one IP address (used for
> @@ -245,10 +245,12 @@ 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)
> +    return timeout;
> 
>    /* 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,
> @@ -335,7 +337,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 +367,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 +398,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)

There are still an alloca on htscache after this fix:

  h_aliases_len = (uint32_t *) alloca (h_aliases_cnt * sizeof (uint32_t));

Maybe also convert this one as well or add a comment on why it is not required.


More information about the Libc-alpha mailing list