Bug 1557501 - C-C part: Adapt to array changes in nsIPrefBranch. r=jorgk,bz
authorBoris Zbarsky <bzbarsky@mit.edu> and Jorg K <jorgk@jorgk.com>
Fri, 07 Jun 2019 18:29:13 +0200
changeset 35802 ffde4bb2fe1bbca3a4b9ecd027032c1b90f0c5d3
parent 35801 e24c0dd786996801f0a36f4787043aa2b18b30c3
child 35803 d00844c4eba4bd98a20376942673520047193337
push id392
push userclokep@gmail.com
push dateMon, 02 Sep 2019 20:17:19 +0000
reviewersjorgk, bz
bugs1557501
Bug 1557501 - C-C part: Adapt to array changes in nsIPrefBranch. r=jorgk,bz
editor/ui/composer/content/publishprefs.js
mail/components/cloudfile/cloudFileAccounts.jsm
mail/components/migration/src/nsSeamonkeyProfileMigrator.cpp
mailnews/addrbook/src/nsAbLDAPAttributeMap.js
mailnews/addrbook/src/nsAbMDBDirectory.cpp
mailnews/addrbook/src/nsDirPrefs.cpp
mailnews/base/src/nsMsgAccountManager.cpp
mailnews/base/src/nsMsgTagService.cpp
mailnews/extensions/bayesian-spam-filter/src/nsBayesianFilter.cpp
suite/components/profile/nsNetscapeProfileMigratorBase.cpp
--- a/editor/ui/composer/content/publishprefs.js
+++ b/editor/ui/composer/content/publishprefs.js
@@ -245,28 +245,27 @@ function GetPublishData_internal(publish
     publishData.savePassword = true;
   }
 
   // Build history list of directories
   // Always supply the root dir
   publishData.dirList = [""];
 
   // Get the rest from prefs
-  var dirCount = {value:0};
   var dirPrefs;
   try {
-    dirPrefs = publishBranch.getChildList(prefPrefix+"dir.", dirCount);
+    dirPrefs = publishBranch.getChildList(prefPrefix+"dir.");
   } catch (e) {}
 
-  if (dirPrefs && dirCount.value > 0)
+  if (dirPrefs && dirPrefs.length > 0)
   {
-    if (dirCount.value > 1)
+    if (dirPrefs.length > 1)
       dirPrefs.sort();
 
-    for (var j = 0; j < dirCount.value; j++)
+    for (var j = 0; j < dirPrefs.length; j++)
     {
       var dirName = GetPublishStringPref(publishBranch, dirPrefs[j]);
       if (dirName)
         publishData.dirList[j+1] = dirName;
     }
   }
 
   return publishData;
@@ -322,36 +321,35 @@ function SavePublishDataToPrefs(publishD
   var publishBranch = GetPublishPrefsBranch();
   if (!publishBranch)
     return false;
 
   // Create name from URL if no site name is provided
   if (!publishData.siteName)
     publishData.siteName = CreateSiteNameFromUrl(publishData.publishUrl, publishData);
 
-  var siteCount = {value:0};
   var siteNamePrefs;
   try {
-    siteNamePrefs = publishBranch.getChildList("site_name.", siteCount);
+    siteNamePrefs = publishBranch.getChildList("site_name.");
   } catch (e) {}
 
-  if (!siteNamePrefs || siteCount.value == 0)
+  if (!siteNamePrefs || siteNamePrefs.length == 0)
   {
     // We currently have no site prefs, so create them
     var siteData = [publishData];
     return SavePublishSiteDataToPrefs(siteData, publishData.siteName);
   }
 
   // Use "previous" name if available in case it was changed
   var previousSiteName =  ("previousSiteName" in publishData && publishData.previousSiteName) ?
                             publishData.previousSiteName : publishData.siteName;
 
   // Find site number of existing site or fall through at next available one
   // (Number is arbitrary; needed to construct unique "site_name.x" pref string)
-  for (var i = 0; i < siteCount.value; i++)
+  for (var i = 0; i < siteNamePrefs.length; i++)
   {
     var siteName = GetPublishStringPref(publishBranch, "site_name."+i);
 
     if (siteName == previousSiteName)
     {
       // Delete prefs for an existing site
       try {
         publishBranch.deleteBranch("site_data." + siteName + ".");
@@ -554,38 +552,37 @@ function GetPublishPrefsBranch()
 }
 
 function GetSiteNameList(doSort, defaultFirst)
 {
   var publishBranch = GetPublishPrefsBranch();
   if (!publishBranch)
     return null;
 
-  var siteCountObj = {value:0};
   var siteNamePrefs;
   try {
-    siteNamePrefs = publishBranch.getChildList("site_name.", siteCountObj);
+    siteNamePrefs = publishBranch.getChildList("site_name.");
   } catch (e) {}
 
-  if (!siteNamePrefs || siteCountObj.value == 0)
+  if (!siteNamePrefs || siteNamePrefs.length == 0)
     return null;
 
   // Array of site names
   var siteNameList = [];
   var index = 0;
   var defaultName = "";
   if (defaultFirst)
   {
     defaultName = GetPublishStringPref(publishBranch, "default_site");
     // This always sorts to top -- replace with real string below
     siteNameList[0] = "";
     index++;
   }
 
-  for (var i = 0; i < siteCountObj.value; i++)
+  for (var i = 0; i < siteNamePrefs.length; i++)
   {
     var siteName = GetPublishStringPref(publishBranch, siteNamePrefs[i]);
     // Skip if siteName pref is empty or is default name
     if (siteName && siteName != defaultName)
     {
       siteNameList[index] = siteName;
       index++;
     }
--- a/mail/components/cloudfile/cloudFileAccounts.jsm
+++ b/mail/components/cloudfile/cloudFileAccounts.jsm
@@ -27,17 +27,17 @@ var cloudFileAccounts = new class extend
     this._providers = new Map();
     this._accounts = new Map();
     this._highestOrdinal = 0;
   }
 
   get _accountKeys() {
     let accountKeySet = new Set();
     let branch = Services.prefs.getBranch(ACCOUNT_ROOT);
-    let children = branch.getChildList("", {});
+    let children = branch.getChildList("");
     for (let child of children) {
       let subbranch = child.substr(0, child.indexOf("."));
       accountKeySet.add(subbranch);
 
       let match = /^account(\d+)$/.exec(subbranch);
       if (match) {
         let ordinal = parseInt(match[1], 10);
         this._highestOrdinal = Math.max(this._highestOrdinal, ordinal);
--- a/mail/components/migration/src/nsSeamonkeyProfileMigrator.cpp
+++ b/mail/components/migration/src/nsSeamonkeyProfileMigrator.cpp
@@ -589,50 +589,49 @@ nsresult nsSeamonkeyProfileMigrator::Cop
 
 void nsSeamonkeyProfileMigrator::ReadBranch(const char* branchName,
                                             nsIPrefService* aPrefService,
                                             PBStructArray& aPrefs) {
   // Enumerate the branch
   nsCOMPtr<nsIPrefBranch> branch;
   aPrefService->GetBranch(branchName, getter_AddRefs(branch));
 
-  uint32_t count;
-  char** prefs = nullptr;
-  nsresult rv = branch->GetChildList("", &count, &prefs);
+  nsTArray<nsCString> prefs;
+  nsresult rv = branch->GetChildList("", prefs);
   if (NS_FAILED(rv)) return;
 
-  for (uint32_t i = 0; i < count; ++i) {
+  for (auto& pref : prefs) {
     // Save each pref's value into an array
-    char* currPref = prefs[i];
+    char* currPref = moz_xstrdup(pref.get());
     int32_t type;
     branch->GetPrefType(currPref, &type);
-    PrefBranchStruct* pref = new PrefBranchStruct;
-    pref->prefName = currPref;
-    pref->type = type;
+    PrefBranchStruct* prefBranch = new PrefBranchStruct;
+    prefBranch->prefName = currPref;
+    prefBranch->type = type;
     switch (type) {
       case nsIPrefBranch::PREF_STRING: {
         nsCString str;
         rv = branch->GetCharPref(currPref, str);
-        pref->stringValue = moz_xstrdup(str.get());
+        prefBranch->stringValue = moz_xstrdup(str.get());
         break;
       }
       case nsIPrefBranch::PREF_BOOL:
-        rv = branch->GetBoolPref(currPref, &pref->boolValue);
+        rv = branch->GetBoolPref(currPref, &prefBranch->boolValue);
         break;
       case nsIPrefBranch::PREF_INT:
-        rv = branch->GetIntPref(currPref, &pref->intValue);
+        rv = branch->GetIntPref(currPref, &prefBranch->intValue);
         break;
       default:
         NS_WARNING(
             "Invalid Pref Type in "
             "nsNetscapeProfileMigratorBase::ReadBranch\n");
         break;
     }
 
-    if (NS_SUCCEEDED(rv)) aPrefs.AppendElement(pref);
+    if (NS_SUCCEEDED(rv)) aPrefs.AppendElement(prefBranch);
   }
 }
 
 void nsSeamonkeyProfileMigrator::WriteBranch(const char* branchName,
                                              nsIPrefService* aPrefService,
                                              PBStructArray& aPrefs) {
   // Enumerate the branch
   nsCOMPtr<nsIPrefBranch> branch;
--- a/mailnews/addrbook/src/nsAbLDAPAttributeMap.js
+++ b/mailnews/addrbook/src/nsAbLDAPAttributeMap.js
@@ -108,18 +108,17 @@ nsAbLDAPAttributeMap.prototype = {
     return props;
   },
 
   setFromPrefs(aPrefBranchName) {
     // get the right pref branch
     let branch = Services.prefs.getBranch(aPrefBranchName + ".");
 
     // get the list of children
-    var childCount = {};
-    var children = branch.getChildList("", childCount);
+    var children = branch.getChildList("");
 
     // do the actual sets
     for (var child of children) {
       this.setAttributeList(child, branch.getCharPref(child), true);
     }
 
     // ensure that everything is kosher
     this.checkState();
--- a/mailnews/addrbook/src/nsAbMDBDirectory.cpp
+++ b/mailnews/addrbook/src/nsAbMDBDirectory.cpp
@@ -74,42 +74,37 @@ NS_IMETHODIMP nsAbMDBDirectory::Init(con
         do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIPrefBranch> prefBranch;
     rv = prefService->GetBranch(PREF_LDAP_SERVER_TREE_NAME ".",
                                 getter_AddRefs(prefBranch));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    char **childArray;
-    uint32_t childCount, i;
+    nsTArray<nsCString> childArray;
     int32_t dotOffset;
     nsCString childValue;
-    nsDependentCString child;
 
-    rv = prefBranch->GetChildList("", &childCount, &childArray);
+    rv = prefBranch->GetChildList("", childArray);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    for (i = 0; i < childCount; ++i) {
-      child.Assign(childArray[i]);
-
+    for (auto &child : childArray) {
       if (StringEndsWith(child, NS_LITERAL_CSTRING(".filename"))) {
         if (NS_SUCCEEDED(prefBranch->GetCharPref(child.get(), childValue))) {
           if (childValue == filename) {
             dotOffset = child.RFindChar('.');
             if (dotOffset != -1) {
               nsAutoCString prefName(StringHead(child, dotOffset));
               m_DirPrefId.AssignLiteral(PREF_LDAP_SERVER_TREE_NAME ".");
               m_DirPrefId.Append(prefName);
             }
           }
         }
       }
     }
-    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(childCount, childArray);
 
     NS_ASSERTION(!m_DirPrefId.IsEmpty(),
                  "Error, Could not set m_DirPrefId in nsAbMDBDirectory::Init");
   }
 
   return nsAbDirProperty::Init(aUri);
 }
 
--- a/mailnews/addrbook/src/nsDirPrefs.cpp
+++ b/mailnews/addrbook/src/nsDirPrefs.cpp
@@ -629,84 +629,91 @@ static void DIR_DeleteServerList(nsTArra
     delete wholeList;
   }
 }
 
 /*****************************************************************************
  * Functions for managing JavaScript prefs for the DIR_Servers
  */
 
-static int comparePrefArrayMembers(const void *aElement1, const void *aElement2,
-                                   void *aData) {
-  const char *element1 = *static_cast<const char *const *>(aElement1);
-  const char *element2 = *static_cast<const char *const *>(aElement2);
-  const uint32_t offset = *((const uint32_t *)aData);
+class MOZ_STACK_CLASS PrefArrayMemberComparator {
+ public:
+  explicit PrefArrayMemberComparator(uint32_t aOffset) : mOffset(aOffset) {}
 
-  // begin the comparison at |offset| chars into the string -
+  // begin the comparison at |mOffset| chars into the string -
   // this avoids comparing the "ldap_2.servers." portion of every element,
   // which will always remain the same.
-  return strcmp(element1 + offset, element2 + offset);
-}
+  bool Equals(const nsCString &aFirst, const nsCString &aSecond) const {
+    return Substring(aFirst, mOffset) == Substring(aSecond, mOffset);
+  }
 
-static nsresult dir_GetChildList(const nsCString &aBranch, uint32_t *aCount,
-                                 char ***aChildList) {
+  bool LessThan(const nsCString &aFirst, const nsCString &aSecond) const {
+    return Substring(aFirst, mOffset) < Substring(aSecond, mOffset);
+  }
+
+ private:
+  uint32_t mOffset;
+};
+
+static nsresult dir_GetChildList(const nsCString &aBranch,
+                                 nsTArray<nsCString> &aChildList) {
   uint32_t branchLen = aBranch.Length();
 
   nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
   if (!prefBranch) {
     return NS_ERROR_FAILURE;
   }
 
-  nsresult rv = prefBranch->GetChildList(aBranch.get(), aCount, aChildList);
+  nsresult rv = prefBranch->GetChildList(aBranch.get(), aChildList);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   // traverse the list, and truncate all the descendant strings to just
   // one branch level below the root branch.
-  for (uint32_t i = *aCount; i--;) {
+  for (auto &child : aChildList) {
     // The prefname we passed to GetChildList was of the form
     // "ldap_2.servers." and we are returned the descendants
     // in the form of "ldap_2.servers.servername.foo"
     // But we want the prefbranch of the servername, so
-    // write a NUL character in to terminate the string early.
-    char *endToken = strchr((*aChildList)[i] + branchLen, '.');
-    if (endToken) *endToken = '\0';
+    // terminate the string at the first '.' after our branchname.
+    int32_t dotPos = child.FindChar('.', branchLen);
+    if (dotPos != kNotFound) {
+      child.Truncate(dotPos);
+    }
   }
 
-  if (*aCount > 1) {
+  if (aChildList.Length() < 1) {
     // sort the list, in preparation for duplicate entry removal
-    NS_QuickSort(*aChildList, *aCount, sizeof(char *), comparePrefArrayMembers,
-                 &branchLen);
+    PrefArrayMemberComparator comparator(branchLen);
+    aChildList.Sort(comparator);
 
     // traverse the list and remove duplicate entries.
     // we use two positions in the list; the current entry and the next
-    // entry; and perform a bunch of in-place ptr moves. so |cur| points
+    // entry; and perform a bunch of in-place moves. so |cur| points
     // to the last unique entry, and |next| points to some (possibly much
     // later) entry to test, at any given point. we know we have >= 2
     // elements in the list here, so we just init the two counters sensibly
     // to begin with.
     uint32_t cur = 0;
-    for (uint32_t next = 1; next < *aCount; ++next) {
+    for (uint32_t next = 1; next < aChildList.Length(); ++next) {
       // check if the elements are equal or unique
-      if (!comparePrefArrayMembers(&((*aChildList)[cur]),
-                                   &((*aChildList)[next]), &branchLen)) {
-        // equal - just free & increment the next element ptr
+      if (comparator.Equals(aChildList[cur], aChildList[next])) {
+        // equal - just increment the next element ptr
 
-        free((*aChildList)[next]);
       } else {
         // cur & next are unique, so we need to shift the element.
         // ++cur will point to the next free location in the
         // reduced array (it's okay if that's == next)
-        (*aChildList)[++cur] = (*aChildList)[next];
+        aChildList[++cur] = aChildList[next];
       }
     }
 
     // update the unique element count
-    *aCount = cur + 1;
+    aChildList.SetLength(cur + 1);
   }
 
   return NS_OK;
 }
 
 static char *DIR_GetStringPref(const char *prefRoot, const char *prefLeaf,
                                const char *defaultValue) {
   nsresult rv;
@@ -949,43 +956,41 @@ static char *dir_CreateServerPrefName(DI
   if (!leafName || !*leafName) {
     // we need to handle this in case the description has no alphanumeric chars
     // it's very common for cjk users
     leafName = strdup("_nonascii");
   }
 
   if (leafName) {
     int32_t uniqueIDCnt = 0;
-    char **children = nullptr;
+    nsTArray<nsCString> children;
     /* we need to verify that this pref string name is unique */
     prefName = PR_smprintf(PREF_LDAP_SERVER_TREE_NAME ".%s", leafName);
     isUnique = false;
-    uint32_t prefCount;
-    nsresult rv =
-        dir_GetChildList(NS_LITERAL_CSTRING(PREF_LDAP_SERVER_TREE_NAME "."),
-                         &prefCount, &children);
+    nsresult rv = dir_GetChildList(
+        NS_LITERAL_CSTRING(PREF_LDAP_SERVER_TREE_NAME "."), children);
     if (NS_SUCCEEDED(rv)) {
       while (!isUnique && prefName) {
         isUnique = true; /* now flip the logic and assume we are unique until we
                             find a match */
-        for (uint32_t i = 0; i < prefCount && isUnique; ++i) {
-          if (!PL_strcasecmp(children[i],
-                             prefName)) /* are they the same branch? */
+        for (auto &child : children) {
+          if (child.EqualsIgnoreCase(
+                  prefName)) { /* are they the same branch? */
             isUnique = false;
+            break;
+          }
         }
         if (!isUnique) /* then try generating a new pref name and try again */
         {
           PR_smprintf_free(prefName);
           prefName = PR_smprintf(PREF_LDAP_SERVER_TREE_NAME ".%s_%d", leafName,
                                  ++uniqueIDCnt);
         }
       } /* if we have a list of pref Names */
-
-      NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, children);
-    } /* while we don't have a unique name */
+    }   /* while we don't have a unique name */
 
     // fallback to "user_directory_N" form if we failed to verify
     if (!isUnique && prefName) {
       PR_smprintf_free(prefName);
       prefName = nullptr;
     }
 
     PR_Free(leafName);
@@ -1043,36 +1048,35 @@ static void DIR_GetPrefsForOneServer(DIR
 static nsresult dir_GetPrefs(nsTArray<DIR_Server *> **list) {
   nsresult rv;
   nsCOMPtr<nsIPrefBranch> pPref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
   if (NS_FAILED(rv)) return rv;
 
   (*list) = new nsTArray<DIR_Server *>();
   if (!(*list)) return NS_ERROR_OUT_OF_MEMORY;
 
-  char **children;
-  uint32_t prefCount;
+  nsTArray<nsCString> children;
 
   rv = dir_GetChildList(NS_LITERAL_CSTRING(PREF_LDAP_SERVER_TREE_NAME "."),
-                        &prefCount, &children);
+                        children);
   if (NS_FAILED(rv)) return rv;
 
   /* TBD: Temporary code to read broken "ldap" preferences tree.
    *      Remove line with if statement after M10.
    */
   if (dir_UserId == 0)
     pPref->GetIntPref(PREF_LDAP_GLOBAL_TREE_NAME ".user_id", &dir_UserId);
 
-  for (uint32_t i = 0; i < prefCount; ++i) {
+  for (auto &child : children) {
     DIR_Server *server;
 
     server = (DIR_Server *)PR_Calloc(1, sizeof(DIR_Server));
     if (server) {
       DIR_InitServer(server);
-      server->prefName = strdup(children[i]);
+      server->prefName = strdup(child.get());
       DIR_GetPrefsForOneServer(server);
       if (server->description && server->description[0] &&
           ((server->dirType == PABDirectory ||
             server->dirType == MAPIDirectory ||
             server->dirType ==
                 FixedQueryLDAPDirectory ||  // this one might go away
             server->dirType == LDAPDirectory))) {
         if (!dir_IsServerDeleted(server)) {
@@ -1080,18 +1084,16 @@ static nsresult dir_GetPrefs(nsTArray<DI
         } else
           DIR_DeleteServer(server);
       } else {
         DIR_DeleteServer(server);
       }
     }
   }
 
-  NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, children);
-
   return NS_OK;
 }
 
 // I don't think we care about locked positions, etc.
 void DIR_SortServersByPosition(nsTArray<DIR_Server *> *serverList) {
   int i, j;
   DIR_Server *server;
 
--- a/mailnews/base/src/nsMsgAccountManager.cpp
+++ b/mailnews/base/src/nsMsgAccountManager.cpp
@@ -250,37 +250,33 @@ void nsMsgAccountManager::getUniqueAccou
     rv = prefBranch->GetIntPref("mail.account.lastKey", &lastKey);
     if (NS_FAILED(rv) || lastKey == 0) {
       // If lastKey pref does not contain a valid value, loop over existing
       // pref names mail.account.* .
       nsCOMPtr<nsIPrefBranch> prefBranchAccount;
       rv = prefservice->GetBranch("mail.account.",
                                   getter_AddRefs(prefBranchAccount));
       if (NS_SUCCEEDED(rv)) {
-        uint32_t prefCount;
-        char **prefList;
-        rv = prefBranchAccount->GetChildList("", &prefCount, &prefList);
+        nsTArray<nsCString> prefList;
+        rv = prefBranchAccount->GetChildList("", prefList);
         if (NS_SUCCEEDED(rv)) {
           // Pref names are of the format accountX.
           // Find the maximum value of 'X' used so far.
-          for (uint32_t i = 0; i < prefCount; i++) {
-            nsCString prefName;
-            prefName.Assign(prefList[i]);
+          for (auto &prefName : prefList) {
             if (StringBeginsWith(prefName,
                                  NS_LITERAL_CSTRING(ACCOUNT_PREFIX))) {
               int32_t dotPos = prefName.FindChar('.');
               if (dotPos != kNotFound) {
                 nsCString keyString(Substring(prefName, strlen(ACCOUNT_PREFIX),
                                               dotPos - strlen(ACCOUNT_PREFIX)));
                 int32_t thisKey = keyString.ToInteger(&rv);
                 if (NS_SUCCEEDED(rv)) lastKey = std::max(lastKey, thisKey);
               }
             }
           }
-          NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefList);
         }
       }
     }
 
     // Use next available key and store the value in the pref.
     aResult.Assign(ACCOUNT_PREFIX);
     aResult.AppendInt(++lastKey);
     rv = prefBranch->SetIntPref("mail.account.lastKey", lastKey);
--- a/mailnews/base/src/nsMsgTagService.cpp
+++ b/mailnews/base/src/nsMsgTagService.cpp
@@ -24,22 +24,16 @@
 #define TAG_PREF_SUFFIX_COLOR ".color"
 #define TAG_PREF_SUFFIX_ORDINAL ".ordinal"
 #define TAG_CMP_LESSER -1
 #define TAG_CMP_EQUAL 0
 #define TAG_CMP_GREATER 1
 
 static bool gMigratingKeys = false;
 
-// comparison functions for nsQuickSort
-static int CompareMsgTagKeys(const void *aTagPref1, const void *aTagPref2) {
-  return strcmp(*static_cast<const char *const *>(aTagPref1),
-                *static_cast<const char *const *>(aTagPref2));
-}
-
 static int CompareMsgTags(const void *aTagPref1, const void *aTagPref2) {
   // Sort nsMsgTag objects by ascending order, using their ordinal or key.
   // The "smallest" value will be first in the sorted array,
   // thus being the most important element.
   nsMsgTag *element1 = *(nsMsgTag **)aTagPref1;
   nsMsgTag *element2 = *(nsMsgTag **)aTagPref2;
 
   // if we have only one element, it wins
@@ -126,36 +120,36 @@ NS_IMETHODIMP nsMsgTagService::SetTagFor
   ToLowerCase(prefName);
   prefName.AppendLiteral(TAG_PREF_SUFFIX_TAG);
   return SetUnicharPref(prefName.get(), tag);
 }
 
 /* void getKeyForTag (in wstring tag); */
 NS_IMETHODIMP nsMsgTagService::GetKeyForTag(const nsAString &aTag,
                                             nsACString &aKey) {
-  uint32_t count;
-  char **prefList;
-  nsresult rv = m_tagPrefBranch->GetChildList("", &count, &prefList);
+  nsTArray<nsCString> prefList;
+  nsresult rv = m_tagPrefBranch->GetChildList("", prefList);
   NS_ENSURE_SUCCESS(rv, rv);
   // traverse the list, and look for a pref with the desired tag value.
-  for (uint32_t i = count; i--;) {
+  // XXXbz is there a good reason to reverse the list here, or did the
+  // old code do it just to be clever and save some characters in the
+  // for loop header?
+  for (auto &prefName : mozilla::Reversed(prefList)) {
     // We are returned the tag prefs in the form "<key>.<tag_data_type>", but
     // since we only want the tags, just check that the string ends with "tag".
-    nsDependentCString prefName(prefList[i]);
     if (StringEndsWith(prefName, NS_LITERAL_CSTRING(TAG_PREF_SUFFIX_TAG))) {
       nsAutoString curTag;
-      GetUnicharPref(prefList[i], curTag);
+      GetUnicharPref(prefName.get(), curTag);
       if (aTag.Equals(curTag)) {
         aKey = Substring(prefName, 0,
                          prefName.Length() - STRLEN(TAG_PREF_SUFFIX_TAG));
         break;
       }
     }
   }
-  NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, prefList);
   ToLowerCase(aKey);
   return NS_OK;
 }
 
 /* ACString getTopKey (in ACString keylist); */
 NS_IMETHODIMP nsMsgTagService::GetTopKey(const nsACString &keyList,
                                          nsACString &_retval) {
   _retval.Truncate();
@@ -339,67 +333,63 @@ NS_IMETHODIMP nsMsgTagService::GetAllTag
   NS_ENSURE_ARG_POINTER(aTagArray);
 
   // preset harmless default values
   *aCount = 0;
   *aTagArray = nullptr;
 
   // get the actual tag definitions
   nsresult rv;
-  uint32_t prefCount;
-  char **prefList;
-  rv = m_tagPrefBranch->GetChildList("", &prefCount, &prefList);
+  nsTArray<nsCString> prefList;
+  rv = m_tagPrefBranch->GetChildList("", prefList);
   NS_ENSURE_SUCCESS(rv, rv);
   // sort them by key for ease of processing
-  qsort(prefList, prefCount, sizeof(char *), CompareMsgTagKeys);
+  prefList.Sort();
 
   // build an array of nsIMsgTag elements from the orderered list
   // it's at max the same size as the preflist, but usually only about half
   nsIMsgTag **tagArray =
-      (nsIMsgTag **)moz_xmalloc(sizeof(nsIMsgTag *) * prefCount);
+      (nsIMsgTag **)moz_xmalloc(sizeof(nsIMsgTag *) * prefList.Length());
 
   if (!tagArray) {
-    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefList);
     return NS_ERROR_OUT_OF_MEMORY;
   }
   uint32_t currentTagIndex = 0;
   nsMsgTag *newMsgTag;
   nsString tag;
   nsCString lastKey, color, ordinal;
-  for (uint32_t i = prefCount; i--;) {
+  for (auto &pref : mozilla::Reversed(prefList)) {
     // extract just the key from <key>.<info=tag|color|ordinal>
-    char *info = strrchr(prefList[i], '.');
-    if (info) {
-      nsAutoCString key(Substring(prefList[i], info));
+    int32_t dotLoc = pref.RFindChar('.');
+    if (dotLoc != kNotFound) {
+      auto &key = Substring(pref, 0, dotLoc);
       if (key != lastKey) {
         if (!key.IsEmpty()) {
           // .tag MUST exist (but may be empty)
           rv = GetTagForKey(key, tag);
           if (NS_SUCCEEDED(rv)) {
             // .color MAY exist
             color.Truncate();
             GetColorForKey(key, color);
             // .ordinal MAY exist
             rv = GetOrdinalForKey(key, ordinal);
             if (NS_FAILED(rv)) ordinal.Truncate();
             // store the tag info in our array
             newMsgTag = new nsMsgTag(key, tag, color, ordinal);
             if (!newMsgTag) {
               NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(currentTagIndex, tagArray);
-              NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefList);
               return NS_ERROR_OUT_OF_MEMORY;
             }
             NS_ADDREF(tagArray[currentTagIndex++] = newMsgTag);
           }
         }
         lastKey = key;
       }
     }
   }
-  NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefList);
 
   // sort the non-null entries by ordinal
   qsort(tagArray, currentTagIndex, sizeof(nsMsgTag *), CompareMsgTags);
 
   // All done, now return the values (the idl's size_is(count) parameter
   // ensures that the array is cut accordingly).
   *aCount = currentTagIndex;
   *aTagArray = tagArray;
--- a/mailnews/extensions/bayesian-spam-filter/src/nsBayesianFilter.cpp
+++ b/mailnews/extensions/bayesian-spam-filter/src/nsBayesianFilter.cpp
@@ -272,48 +272,46 @@ Tokenizer::Tokenizer()
    *
    * Header names in the preference should be all lower case
    *
    * Extensions may also set the maximum length of a token (default is
    * kMaxLengthForToken) by setting the int preference:
    *   "mailnews.bayesian_spam_filter.maxlengthfortoken"
    */
 
-  char** headers;
-  uint32_t count;
+  nsTArray<nsCString> headers;
 
   // get customized maximum token length
   int32_t maxLengthForToken;
   rv = prefBranch->GetIntPref("maxlengthfortoken", &maxLengthForToken);
   mMaxLengthForToken =
       NS_SUCCEEDED(rv) ? uint32_t(maxLengthForToken) : kMaxLengthForToken;
 
   rv = prefs->GetBranch("mailnews.bayesian_spam_filter.tokenizeheader.",
                         getter_AddRefs(prefBranch));
-  if (NS_SUCCEEDED(rv)) rv = prefBranch->GetChildList("", &count, &headers);
+  if (NS_SUCCEEDED(rv)) rv = prefBranch->GetChildList("", headers);
 
   if (NS_SUCCEEDED(rv)) {
     mCustomHeaderTokenization = true;
-    for (uint32_t i = 0; i < count; i++) {
+    for (auto& header : headers) {
       nsCString value;
-      prefBranch->GetCharPref(headers[i], value);
+      prefBranch->GetCharPref(header.get(), value);
       if (value.EqualsLiteral("false")) {
-        mDisabledHeaders.AppendElement(headers[i]);
+        mDisabledHeaders.AppendElement(header);
         continue;
       }
-      mEnabledHeaders.AppendElement(headers[i]);
+      mEnabledHeaders.AppendElement(header);
       if (value.EqualsLiteral("standard"))
         value.SetIsVoid(true);  // Void means use default delimiter
       else if (value.EqualsLiteral("full"))
         value.Truncate();  // Empty means add full header
       else
         UnescapeCString(value);
       mEnabledHeadersDelimiters.AppendElement(value);
     }
-    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, headers);
   }
 }
 
 Tokenizer::~Tokenizer() {}
 
 inline Token* Tokenizer::get(const char* word) {
   return static_cast<Token*>(TokenHash::get(word));
 }
--- a/suite/components/profile/nsNetscapeProfileMigratorBase.cpp
+++ b/suite/components/profile/nsNetscapeProfileMigratorBase.cpp
@@ -512,32 +512,32 @@ void
 nsNetscapeProfileMigratorBase::ReadBranch(const char * branchName,
                                           nsIPrefService* aPrefService,
                                           PBStructArray &aPrefs)
 {
   // Enumerate the branch
   nsCOMPtr<nsIPrefBranch> branch;
   aPrefService->GetBranch(branchName, getter_AddRefs(branch));
 
-  uint32_t count;
-  char** prefs = nullptr;
+  nsTArray<nsCString> prefs;
 
-  nsresult rv = branch->GetChildList("", &count, &prefs);
+  nsresult rv = branch->GetChildList("", prefs);
   if (NS_FAILED(rv))
     return;
 
-  for (uint32_t i = 0; i < count; ++i) {
+  for (auto& pref : prefs) {
     // Save each pref's value into an array
-    char* currPref = prefs[i];
+    char* currPref = moz_xstrdup(pref.get());
     int32_t type;
     branch->GetPrefType(currPref, &type);
 
     PrefBranchStruct* pref = new PrefBranchStruct;
     if (!pref) {
       NS_WARNING("Could not create new PrefBranchStruct");
+      free(currPref);
       return;
     }
     pref->prefName = currPref;
     pref->type = type;
 
     switch (type) {
     case nsIPrefBranch::PREF_STRING: {
       nsCString str;