Bug 1094650 - Avoid excessive heap allocation in nss_builtins_FindObjectsInit(). r=relyea
authorNicholas Nethercote <nnethercote@mozilla.com>
Mon, 17 Nov 2014 13:10:55 +0100
changeset 11306 902bc119dcdb6ae24bf82c466b22000577639e08
parent 11305 e9a7991380db1973c84643c842066b3b5ec18306
child 11307 c92f97d1bd26d81a1a7b98a05985cade88132a2f
push id515
push userkaie@kuix.de
push dateMon, 17 Nov 2014 12:11:07 +0000
reviewersrelyea
bugs1094650
Bug 1094650 - Avoid excessive heap allocation in nss_builtins_FindObjectsInit(). r=relyea
lib/ckfw/builtins/bfind.c
--- a/lib/ckfw/builtins/bfind.c
+++ b/lib/ckfw/builtins/bfind.c
@@ -178,17 +178,26 @@ nss_builtins_FindObjectsInit
   CK_ULONG ulAttributeCount,
   CK_RV *pError
 )
 {
   /* This could be made more efficient.  I'm rather rushed. */
   NSSArena *arena;
   NSSCKMDFindObjects *rv = (NSSCKMDFindObjects *)NULL;
   struct builtinsFOStr *fo = (struct builtinsFOStr *)NULL;
-  builtinsInternalObject **temp = (builtinsInternalObject **)NULL;
+
+  /*
+   * 99% of the time we get 0 or 1 matches. So we start with a small
+   * stack-allocated array to hold the matches and switch to a heap-allocated
+   * array later if the number of matches exceeds STACK_BUF_LENGTH.
+   */
+  #define STACK_BUF_LENGTH 1
+  builtinsInternalObject *stackTemp[STACK_BUF_LENGTH];
+  builtinsInternalObject **temp = stackTemp;
+  PRBool tempIsHeapAllocated = PR_FALSE;
   PRUint32 i;
 
   arena = NSSArena_Create();
   if( (NSSArena *)NULL == arena ) {
     goto loser;
   }
 
   rv = nss_ZNEW(arena, NSSCKMDFindObjects);
@@ -206,46 +215,57 @@ nss_builtins_FindObjectsInit
   fo->arena = arena;
   /* fo->n and fo->i are already zero */
 
   rv->etc = (void *)fo;
   rv->Final = builtins_mdFindObjects_Final;
   rv->Next = builtins_mdFindObjects_Next;
   rv->null = (void *)NULL;
 
-  temp = nss_ZNEWARRAY((NSSArena *)NULL, builtinsInternalObject *, 
-                       nss_builtins_nObjects);
-  if( (builtinsInternalObject **)NULL == temp ) {
-    *pError = CKR_HOST_MEMORY;
-    goto loser;
-  }
-
   for( i = 0; i < nss_builtins_nObjects; i++ ) {
     builtinsInternalObject *o = (builtinsInternalObject *)&nss_builtins_data[i];
 
     if( CK_TRUE == builtins_match(pTemplate, ulAttributeCount, o) ) {
+      if( fo->n == STACK_BUF_LENGTH ) {
+        /* Switch from the small stack array to a heap-allocated array large
+         * enough to handle matches in all remaining cases. */
+        temp = nss_ZNEWARRAY((NSSArena *)NULL, builtinsInternalObject *,
+                             fo->n + nss_builtins_nObjects - i);
+        if( (builtinsInternalObject **)NULL == temp ) {
+          *pError = CKR_HOST_MEMORY;
+          goto loser;
+        }
+        tempIsHeapAllocated = PR_TRUE;
+        (void)nsslibc_memcpy(temp, stackTemp,
+                             sizeof(builtinsInternalObject *) * fo->n);
+      }
+
       temp[ fo->n ] = o;
       fo->n++;
     }
   }
 
   fo->objs = nss_ZNEWARRAY(arena, builtinsInternalObject *, fo->n);
   if( (builtinsInternalObject **)NULL == fo->objs ) {
     *pError = CKR_HOST_MEMORY;
     goto loser;
   }
 
   (void)nsslibc_memcpy(fo->objs, temp, sizeof(builtinsInternalObject *) * fo->n);
-  nss_ZFreeIf(temp);
-  temp = (builtinsInternalObject **)NULL;
+  if (tempIsHeapAllocated) {
+    nss_ZFreeIf(temp);
+    temp = (builtinsInternalObject **)NULL;
+  }
 
   return rv;
 
  loser:
-  nss_ZFreeIf(temp);
+  if (tempIsHeapAllocated) {
+    nss_ZFreeIf(temp);
+  }
   nss_ZFreeIf(fo);
   nss_ZFreeIf(rv);
   if ((NSSArena *)NULL != arena) {
      NSSArena_Destroy(arena);
   }
   return (NSSCKMDFindObjects *)NULL;
 }