f818b5c
2012-04-12  Jeff Law  <law@redhat.com>
f818b5c
f818b5c
	* nscd/grpcache.c (cache_addgr): Track alloca usage with alloca_account.
f818b5c
	Do not allocate DATASET on the stack if it's too large.  Free DATASET
f818b5c
	if needed.
f818b5c
f818b5c
diff -rcp a/nscd/grpcache.c b/nscd/grpcache.c
f818b5c
*** a/nscd/grpcache.c	Wed Apr 11 12:50:07 2012
f818b5c
--- b/nscd/grpcache.c	Wed Apr 11 21:45:58 2012
f818b5c
*************** cache_addgr (struct database_dyn *db, in
f818b5c
*** 178,184 ****
f818b5c
        char *cp;
f818b5c
        const size_t key_len = strlen (key);
f818b5c
        const size_t buf_len = 3 * sizeof (grp->gr_gid) + key_len + 1;
f818b5c
!       char *buf = alloca (buf_len);
f818b5c
        ssize_t n;
f818b5c
        size_t cnt;
f818b5c
  
f818b5c
--- 178,185 ----
f818b5c
        char *cp;
f818b5c
        const size_t key_len = strlen (key);
f818b5c
        const size_t buf_len = 3 * sizeof (grp->gr_gid) + key_len + 1;
f818b5c
!       size_t alloca_used = 0;
f818b5c
!       char *buf = alloca_account (buf_len, alloca_used);
f818b5c
        ssize_t n;
f818b5c
        size_t cnt;
f818b5c
  
f818b5c
*************** cache_addgr (struct database_dyn *db, in
f818b5c
*** 190,196 ****
f818b5c
        /* Determine the length of all members.  */
f818b5c
        while (grp->gr_mem[gr_mem_cnt])
f818b5c
  	++gr_mem_cnt;
f818b5c
!       gr_mem_len = (uint32_t *) alloca (gr_mem_cnt * sizeof (uint32_t));
f818b5c
        for (gr_mem_cnt = 0; grp->gr_mem[gr_mem_cnt]; ++gr_mem_cnt)
f818b5c
  	{
f818b5c
  	  gr_mem_len[gr_mem_cnt] = strlen (grp->gr_mem[gr_mem_cnt]) + 1;
f818b5c
--- 191,198 ----
f818b5c
        /* Determine the length of all members.  */
f818b5c
        while (grp->gr_mem[gr_mem_cnt])
f818b5c
  	++gr_mem_cnt;
f818b5c
!       gr_mem_len = (uint32_t *) alloca_account (gr_mem_cnt * sizeof (uint32_t),
f818b5c
! 						alloca_used);
f818b5c
        for (gr_mem_cnt = 0; grp->gr_mem[gr_mem_cnt]; ++gr_mem_cnt)
f818b5c
  	{
f818b5c
  	  gr_mem_len[gr_mem_cnt] = strlen (grp->gr_mem[gr_mem_cnt]) + 1;
f818b5c
*************** cache_addgr (struct database_dyn *db, in
f818b5c
*** 205,214 ****
f818b5c
  	 change.  Allocate memory on the cache since it is likely
f818b5c
  	 discarded anyway.  If it turns out to be necessary to have a
f818b5c
  	 new record we can still allocate real memory.  */
f818b5c
!       bool alloca_used = false;
f818b5c
        dataset = NULL;
f818b5c
  
f818b5c
!       if (he == NULL)
f818b5c
  	dataset = (struct dataset *) mempool_alloc (db, total + n, 1);
f818b5c
  
f818b5c
        if (dataset == NULL)
f818b5c
--- 207,216 ----
f818b5c
  	 change.  Allocate memory on the cache since it is likely
f818b5c
  	 discarded anyway.  If it turns out to be necessary to have a
f818b5c
  	 new record we can still allocate real memory.  */
f818b5c
!       bool dataset_in_stack_or_freed = false;
f818b5c
        dataset = NULL;
f818b5c
  
f818b5c
!       if (he == NULL || ! __libc_use_alloca (alloca_used + total + n))
f818b5c
  	dataset = (struct dataset *) mempool_alloc (db, total + n, 1);
f818b5c
  
f818b5c
        if (dataset == NULL)
f818b5c
*************** cache_addgr (struct database_dyn *db, in
f818b5c
*** 216,225 ****
f818b5c
  	  /* We cannot permanently add the result in the moment.  But
f818b5c
  	     we can provide the result as is.  Store the data in some
f818b5c
  	     temporary memory.  */
f818b5c
! 	  dataset = (struct dataset *) alloca (total + n);
f818b5c
  
f818b5c
  	  /* We cannot add this record to the permanent database.  */
f818b5c
! 	  alloca_used = true;
f818b5c
  	}
f818b5c
  
f818b5c
        dataset->head.allocsize = total + n;
f818b5c
--- 218,227 ----
f818b5c
  	  /* We cannot permanently add the result in the moment.  But
f818b5c
  	     we can provide the result as is.  Store the data in some
f818b5c
  	     temporary memory.  */
f818b5c
! 	  dataset = (struct dataset *) alloca_account (total + n, alloca_used);
f818b5c
  
f818b5c
  	  /* We cannot add this record to the permanent database.  */
f818b5c
! 	  dataset_in_stack_or_freed = true;
f818b5c
  	}
f818b5c
  
f818b5c
        dataset->head.allocsize = total + n;
f818b5c
*************** cache_addgr (struct database_dyn *db, in
f818b5c
*** 273,278 ****
f818b5c
--- 275,288 ----
f818b5c
  		 allocated on the stack and need not be freed.  */
f818b5c
  	      dh->timeout = dataset->head.timeout;
f818b5c
  	      ++dh->nreloads;
f818b5c
+ 
f818b5c
+ 	      /* If the new record was not allocated on the stack, then it must
f818b5c
+ 		 be freed.  Note that it can no longer be used.  */
f818b5c
+ 	      if (! dataset_in_stack_or_freed)
f818b5c
+ 		{
f818b5c
+ 		  free (dataset);
f818b5c
+ 		  dataset_in_stack_or_freed = true;
f818b5c
+ 		}
f818b5c
  	    }
f818b5c
  	  else
f818b5c
  	    {
f818b5c
*************** cache_addgr (struct database_dyn *db, in
f818b5c
*** 288,294 ****
f818b5c
  		  key_copy = (char *) newp + (key_copy - (char *) dataset);
f818b5c
  
f818b5c
  		  dataset = memcpy (newp, dataset, total + n);
f818b5c
! 		  alloca_used = false;
f818b5c
  		}
f818b5c
  
f818b5c
  	      /* Mark the old record as obsolete.  */
f818b5c
--- 298,304 ----
f818b5c
  		  key_copy = (char *) newp + (key_copy - (char *) dataset);
f818b5c
  
f818b5c
  		  dataset = memcpy (newp, dataset, total + n);
f818b5c
! 		  dataset_in_stack_or_freed = false;
f818b5c
  		}
f818b5c
  
f818b5c
  	      /* Mark the old record as obsolete.  */
f818b5c
*************** cache_addgr (struct database_dyn *db, in
f818b5c
*** 303,309 ****
f818b5c
  	  assert (fd != -1);
f818b5c
  
f818b5c
  #ifdef HAVE_SENDFILE
f818b5c
! 	  if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
f818b5c
  	    {
f818b5c
  	      assert (db->wr_fd != -1);
f818b5c
  	      assert ((char *) &dataset->resp > (char *) db->data);
f818b5c
--- 313,319 ----
f818b5c
  	  assert (fd != -1);
f818b5c
  
f818b5c
  #ifdef HAVE_SENDFILE
f818b5c
! 	  if (__builtin_expect (db->mmap_used, 1) && !dataset_in_stack_or_freed)
f818b5c
  	    {
f818b5c
  	      assert (db->wr_fd != -1);
f818b5c
  	      assert ((char *) &dataset->resp > (char *) db->data);
f818b5c
*************** cache_addgr (struct database_dyn *db, in
f818b5c
*** 330,336 ****
f818b5c
  
f818b5c
        /* Add the record to the database.  But only if it has not been
f818b5c
  	 stored on the stack.  */
f818b5c
!       if (! alloca_used)
f818b5c
  	{
f818b5c
  	  /* If necessary, we also propagate the data to disk.  */
f818b5c
  	  if (db->persistent)
f818b5c
--- 340,346 ----
f818b5c
  
f818b5c
        /* Add the record to the database.  But only if it has not been
f818b5c
  	 stored on the stack.  */
f818b5c
!       if (! dataset_in_stack_or_freed)
f818b5c
  	{
f818b5c
  	  /* If necessary, we also propagate the data to disk.  */
f818b5c
  	  if (db->persistent)