Bug 1425807 - Convert nsHostKey members to nsCString r=valentin
authorJeff Hemphill <jthemphill@gmail.com>
Fri, 22 Dec 2017 14:08:17 -0800
changeset 451738 5fc9e32e0988f6aceb55bb45e3d06478178ac10f
parent 451736 6ad8b5129333eba823787614af6015a2fefc18a6
child 451739 9cc3ff239f06936c59eef2a95201837f2c726c2f
child 451756 69f9bc50da95f131f2bae64f97adf2f8f354d37a
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvalentin
bugs1425807
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1425807 - Convert nsHostKey members to nsCString r=valentin MozReview-Commit-ID: 8tZUukA8Rrk
netwerk/dns/nsDNSService2.cpp
netwerk/dns/nsHostResolver.cpp
netwerk/dns/nsHostResolver.h
--- a/netwerk/dns/nsDNSService2.cpp
+++ b/netwerk/dns/nsDNSService2.cpp
@@ -83,28 +83,26 @@ NS_IMPL_ISUPPORTS(nsDNSRecord, nsIDNSRec
 
 NS_IMETHODIMP
 nsDNSRecord::GetCanonicalName(nsACString &result)
 {
     // this method should only be called if we have a CNAME
     NS_ENSURE_TRUE(mHostRecord->flags & nsHostResolver::RES_CANON_NAME,
                    NS_ERROR_NOT_AVAILABLE);
 
-    // if the record is for an IP address literal, then the canonical
-    // host name is the IP address literal.
-    const char *cname;
-    {
-        MutexAutoLock lock(mHostRecord->addr_info_lock);
-        if (mHostRecord->addr_info)
-            cname = mHostRecord->addr_info->mCanonicalName ?
-                mHostRecord->addr_info->mCanonicalName :
-                mHostRecord->addr_info->mHostName;
-        else
-            cname = mHostRecord->host;
+    MutexAutoLock lock(mHostRecord->addr_info_lock);
+    if (mHostRecord->addr_info) {
+        const char* cname = mHostRecord->addr_info->mCanonicalName ?
+            mHostRecord->addr_info->mCanonicalName :
+            mHostRecord->addr_info->mHostName;
         result.Assign(cname);
+    } else {
+        // if the record is for an IP address literal, then the canonical
+        // host name is the IP address literal.
+        result = mHostRecord->host;
     }
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDNSRecord::GetNextAddr(uint16_t port, NetAddr *addr)
 {
     if (mDone) {
--- a/netwerk/dns/nsHostResolver.cpp
+++ b/netwerk/dns/nsHostResolver.cpp
@@ -157,57 +157,60 @@ IsLowPriority(uint16_t flags)
 }
 
 //----------------------------------------------------------------------------
 // this macro filters out any flags that are not used when constructing the
 // host key.  the significant flags are those that would affect the resulting
 // host record (i.e., the flags that are passed down to PR_GetAddrInfoByName).
 #define RES_KEY_FLAGS(_f) ((_f) & nsHostResolver::RES_CANON_NAME)
 
-nsHostRecord::nsHostRecord(const nsHostKey *key)
-    : addr_info_lock("nsHostRecord.addr_info_lock")
+bool
+nsHostKey::operator==(const nsHostKey& other) const
+{
+    return host == other.host &&
+        RES_KEY_FLAGS (flags) == RES_KEY_FLAGS(other.flags) &&
+        af == other.af &&
+        netInterface == other.netInterface &&
+        originSuffix == other.originSuffix;
+}
+
+size_t
+nsHostKey::SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
+{
+    size_t n = 0;
+    n += host.SizeOfExcludingThisIfUnshared(mallocSizeOf);
+    n += netInterface.SizeOfExcludingThisIfUnshared(mallocSizeOf);
+    n += originSuffix.SizeOfExcludingThisIfUnshared(mallocSizeOf);
+    return n;
+}
+
+nsHostRecord::nsHostRecord(const nsHostKey& key)
+    : nsHostKey(key)
+    , addr_info_lock("nsHostRecord.addr_info_lock")
     , addr_info_gencnt(0)
     , addr_info(nullptr)
     , addr(nullptr)
     , negative(false)
     , resolving(false)
     , onQueue(false)
     , usingAnyThread(false)
     , mDoomed(false)
 #if TTL_AVAILABLE
     , mGetTtl(false)
 #endif
     , mBlacklistedCount(0)
     , mResolveAgain(false)
 {
-    host = ((char *) this) + sizeof(nsHostRecord);
-    memcpy((char *) host, key->host, strlen(key->host) + 1);
-    flags = key->flags;
-    af = key->af;
-    netInterface = host + strlen(key->host) + 1;
-    memcpy((char *) netInterface, key->netInterface,
-           strlen(key->netInterface) + 1);
-    originSuffix = netInterface + strlen(key->netInterface) + 1;
-    memcpy((char *) originSuffix, key->originSuffix,
-           strlen(key->originSuffix) + 1);
     PR_INIT_CLIST(this);
 }
 
 nsresult
 nsHostRecord::Create(const nsHostKey *key, nsHostRecord **result)
 {
-    size_t hostLen = strlen(key->host) + 1;
-    size_t netInterfaceLen = strlen(key->netInterface) + 1;
-    size_t originSuffixLen = strlen(key->originSuffix) + 1;
-    size_t size = hostLen + netInterfaceLen + originSuffixLen + sizeof(nsHostRecord);
-
-    // Use placement new to create the object with room for the hostname,
-    // network interface name and originSuffix allocated after it.
-    void *place = ::operator new(size);
-    *result = new(place) nsHostRecord(key);
+    *result = new nsHostRecord(*key);
     NS_ADDREF(*result);
 
     return NS_OK;
 }
 
 void
 nsHostRecord::SetExpiration(const mozilla::TimeStamp& now, unsigned int valid, unsigned int grace)
 {
@@ -235,66 +238,66 @@ nsHostRecord::~nsHostRecord()
     delete addr_info;
 }
 
 bool
 nsHostRecord::Blacklisted(NetAddr *aQuery)
 {
     // must call locked
     LOG(("Checking blacklist for host [%s%s%s], host record [%p].\n",
-          LOG_HOST(host, netInterface), this));
+          LOG_HOST(host.get(), netInterface.get()), this));
 
     // skip the string conversion for the common case of no blacklist
     if (!mBlacklistedItems.Length()) {
         return false;
     }
 
     char buf[kIPv6CStrBufSize];
     if (!NetAddrToString(aQuery, buf, sizeof(buf))) {
         return false;
     }
     nsDependentCString strQuery(buf);
 
     for (uint32_t i = 0; i < mBlacklistedItems.Length(); i++) {
         if (mBlacklistedItems.ElementAt(i).Equals(strQuery)) {
             LOG(("Address [%s] is blacklisted for host [%s%s%s].\n", buf,
-                 LOG_HOST(host, netInterface)));
+                 LOG_HOST(host.get(), netInterface.get())));
             return true;
         }
     }
 
     return false;
 }
 
 void
 nsHostRecord::ReportUnusable(NetAddr *aAddress)
 {
     // must call locked
     LOG(("Adding address to blacklist for host [%s%s%s], host record [%p].\n",
-         LOG_HOST(host, netInterface), this));
+         LOG_HOST(host.get(), netInterface.get()), this));
 
     ++mBlacklistedCount;
 
     if (negative)
         mDoomed = true;
 
     char buf[kIPv6CStrBufSize];
     if (NetAddrToString(aAddress, buf, sizeof(buf))) {
         LOG(("Successfully adding address [%s] to blacklist for host "
-             "[%s%s%s].\n", buf, LOG_HOST(host, netInterface)));
+             "[%s%s%s].\n", buf, LOG_HOST(host.get(), netInterface.get())));
         mBlacklistedItems.AppendElement(nsCString(buf));
     }
 }
 
 void
 nsHostRecord::ResetBlacklist()
 {
     // must call locked
     LOG(("Resetting blacklist for host [%s%s%s], host record [%p].\n",
-         LOG_HOST(host, netInterface), this));
+         LOG_HOST(host.get(), netInterface.get()), this));
     mBlacklistedItems.Clear();
 }
 
 nsHostRecord::ExpirationStatus
 nsHostRecord::CheckExpiration(const mozilla::TimeStamp& now) const {
     if (!mGraceStart.IsNull() && now >= mGraceStart
             && !mValidEnd.IsNull() && now < mValidEnd) {
         return nsHostRecord::EXP_GRACE;
@@ -344,16 +347,17 @@ nsHostRecord::SizeOfIncludingThis(Malloc
 {
     size_t n = mallocSizeOf(this);
 
     // The |host| field (inherited from nsHostKey) actually points to extra
     // memory that is allocated beyond the end of the nsHostRecord (see
     // nsHostRecord::Create()).  So it will be included in the
     // |mallocSizeOf(this)| call above.
 
+    n += nsHostKey::SizeOfExcludingThis(mallocSizeOf);
     n += SizeOfResolveHostCallbackListExcludingHead(mCallbacks, mallocSizeOf);
     n += addr_info ? addr_info->SizeOfIncludingThis(mallocSizeOf) : 0;
     n += mallocSizeOf(addr.get());
 
     n += mBlacklistedItems.ShallowSizeOfExcludingThis(mallocSizeOf);
     for (size_t i = 0; i < mBlacklistedItems.Length(); i++) {
         n += mBlacklistedItems[i].SizeOfExcludingThisIfUnshared(mallocSizeOf);
     }
@@ -399,33 +403,29 @@ struct nsHostDBEnt : PLDHashEntryHdr
 {
     nsHostRecord *rec;
 };
 
 static PLDHashNumber
 HostDB_HashKey(const void *key)
 {
     const nsHostKey *hk = static_cast<const nsHostKey *>(key);
-    return AddToHash(HashString(hk->host), RES_KEY_FLAGS(hk->flags), hk->af,
-                     HashString(hk->netInterface), HashString(hk->originSuffix));
+    return AddToHash(HashString(hk->host.get()), RES_KEY_FLAGS(hk->flags),
+                     hk->af, HashString(hk->netInterface.get()),
+                     HashString(hk->originSuffix.get()));
 }
 
 static bool
 HostDB_MatchEntry(const PLDHashEntryHdr *entry,
                   const void *key)
 {
     const nsHostDBEnt *he = static_cast<const nsHostDBEnt *>(entry);
     const nsHostKey *hk = static_cast<const nsHostKey *>(key);
 
-    return !strcmp(he->rec->host ? he->rec->host : "",
-                   hk->host ? hk->host : "") &&
-            RES_KEY_FLAGS (he->rec->flags) == RES_KEY_FLAGS(hk->flags) &&
-            he->rec->af == hk->af &&
-            !strcmp(he->rec->netInterface, hk->netInterface) &&
-            !strcmp(he->rec->originSuffix, hk->originSuffix);
+    return *he->rec == *hk;
 }
 
 static void
 HostDB_MoveEntry(PLDHashTable *table,
                  const PLDHashEntryHdr *from,
                  PLDHashEntryHdr *to)
 {
     static_cast<nsHostDBEnt *>(to)->rec =
@@ -438,32 +438,32 @@ HostDB_ClearEntry(PLDHashTable *table,
 {
     nsHostDBEnt *he = static_cast<nsHostDBEnt*>(entry);
     MOZ_ASSERT(he, "nsHostDBEnt is null!");
 
     nsHostRecord *hr = he->rec;
     MOZ_ASSERT(hr, "nsHostDBEnt has null host record!");
 
     LOG(("Clearing cache db entry for host [%s%s%s].\n",
-         LOG_HOST(hr->host, hr->netInterface)));
+         LOG_HOST(hr->host.get(), hr->netInterface.get())));
 #if defined(DEBUG)
     {
         MutexAutoLock lock(hr->addr_info_lock);
         if (!hr->addr_info) {
             LOG(("No address info for host [%s%s%s].\n",
-                 LOG_HOST(hr->host, hr->netInterface)));
+                 LOG_HOST(hr->host.get(), hr->netInterface.get())));
         } else {
             if (!hr->mValidEnd.IsNull()) {
                 TimeDuration diff = hr->mValidEnd - TimeStamp::NowLoRes();
                 LOG(("Record for host [%s%s%s] expires in %f seconds.\n",
-                     LOG_HOST(hr->host, hr->netInterface),
+                     LOG_HOST(hr->host.get(), hr->netInterface.get()),
                      diff.ToSeconds()));
             } else {
                 LOG(("Record for host [%s%s%s] not yet valid.\n",
-                     LOG_HOST(hr->host, hr->netInterface)));
+                     LOG_HOST(hr->host.get(), hr->netInterface.get())));
             }
 
             NetAddrElement *addrElement = nullptr;
             char buf[kIPv6CStrBufSize];
             do {
                 if (!addrElement) {
                     addrElement = hr->addr_info->mAddresses.getFirst();
                 } else {
@@ -622,17 +622,17 @@ nsHostResolver::FlushCache()
     // Clear the evictionQ and remove all its corresponding entries from
     // the cache first
     if (!PR_CLIST_IS_EMPTY(&mEvictionQ)) {
         PRCList *node = mEvictionQ.next;
         while (node != &mEvictionQ) {
             nsHostRecord *rec = static_cast<nsHostRecord *>(node);
             node = node->next;
             PR_REMOVE_AND_INIT_LINK(rec);
-            mDB.Remove((nsHostKey *) rec);
+            mDB.Remove(static_cast<nsHostKey *>(rec));
             NS_RELEASE(rec);
         }
     }
 
     // Refresh the cache entries that are resolving RIGHT now, remove the rest.
     for (auto iter = mDB.Iter(); !iter.Done(); iter.Next()) {
         auto entry = static_cast<nsHostDBEnt *>(iter.Get());
         // Try to remove the record, or mark it for refresh.
@@ -766,17 +766,18 @@ nsHostResolver::ResolveHost(const char  
             // in the hash table.  if so, then check to see if we can't
             // just reuse the lookup result.  otherwise, if there are
             // any pending callbacks, then add to pending callbacks queue,
             // and return.  otherwise, add ourselves as first pending
             // callback, and proceed to do the lookup.
             nsAutoCString originSuffix;
             aOriginAttributes.CreateSuffix(originSuffix);
 
-            nsHostKey key = { host, flags, af, netInterface, originSuffix.get() };
+            nsHostKey key(nsCString(host), flags, af, nsCString(netInterface),
+                          originSuffix);
             auto he = static_cast<nsHostDBEnt*>(mDB.Add(&key, fallible));
 
             // if the record is null, the hash table OOM'd.
             if (!he) {
                 LOG(("  Out of memory: no cache entry for host [%s%s%s].\n",
                      LOG_HOST(host, netInterface)));
                 rv = NS_ERROR_OUT_OF_MEMORY;
             }
@@ -843,18 +844,18 @@ nsHostResolver::ResolveHost(const char  
             }
 
             // If this is an IPV4 or IPV6 specific request, check if there is
             // an AF_UNSPEC entry we can use. Otherwise, hit the resolver...
             else if (!he->rec->resolving) {
                 if (!(flags & RES_BYPASS_CACHE) &&
                     ((af == PR_AF_INET) || (af == PR_AF_INET6))) {
                     // First, search for an entry with AF_UNSPEC
-                    const nsHostKey unspecKey = { host, flags, PR_AF_UNSPEC,
-                                                  netInterface, originSuffix.get() };
+                    const nsHostKey unspecKey(nsCString(host), flags, PR_AF_UNSPEC,
+                                              nsCString(netInterface), originSuffix);
                     auto unspecHe =
                         static_cast<nsHostDBEnt*>(mDB.Search(&unspecKey));
                     NS_ASSERTION(!unspecHe ||
                                  (unspecHe && unspecHe->rec),
                                 "Valid host entries should contain a record");
                     TimeStamp now = TimeStamp::NowLoRes();
                     if (unspecHe &&
                         unspecHe->rec->HasUsableResult(now, flags)) {
@@ -1000,17 +1001,18 @@ nsHostResolver::DetachCallback(const cha
     RefPtr<nsResolveHostCallback> callback(aCallback);
 
     {
         MutexAutoLock lock(mLock);
 
         nsAutoCString originSuffix;
         aOriginAttributes.CreateSuffix(originSuffix);
 
-        nsHostKey key = { host, flags, af, netInterface, originSuffix.get() };
+        nsHostKey key(nsCString(host), flags, af, nsCString(netInterface),
+                      originSuffix);
         auto he = static_cast<nsHostDBEnt*>(mDB.Search(&key));
         if (he) {
             // walk list looking for |callback|... we cannot assume
             // that it will be there!
 
             for (nsResolveHostCallback* c: he->rec->mCallbacks) {
                 if (c == callback) {
                     rec = he->rec;
@@ -1051,17 +1053,17 @@ nsHostResolver::ConditionallyCreateThrea
         if (!thr) {
             mThreadCount--;
             NS_RELEASE_THIS();
             return NS_ERROR_OUT_OF_MEMORY;
         }
     }
     else {
         LOG(("  Unable to find a thread for looking up host [%s%s%s].\n",
-             LOG_HOST(rec->host, rec->netInterface)));
+             LOG_HOST(rec->host.get(), rec->netInterface.get())));
     }
     return NS_OK;
 }
 
 nsresult
 nsHostResolver::IssueLookup(nsHostRecord *rec)
 {
     nsresult rv = NS_OK;
@@ -1213,17 +1215,17 @@ nsHostResolver::GetHostToLookup(nsHostRe
 void
 nsHostResolver::PrepareRecordExpiration(nsHostRecord* rec) const
 {
     MOZ_ASSERT(((bool)rec->addr_info) != rec->negative);
     if (!rec->addr_info) {
         rec->SetExpiration(TimeStamp::NowLoRes(),
                            NEGATIVE_RECORD_LIFETIME, 0);
         LOG(("Caching host [%s%s%s] negative record for %u seconds.\n",
-             LOG_HOST(rec->host, rec->netInterface),
+             LOG_HOST(rec->host.get(), rec->netInterface.get()),
              NEGATIVE_RECORD_LIFETIME));
         return;
     }
 
     unsigned int lifetime = mDefaultCacheLifetime;
     unsigned int grace = mDefaultGracePeriod;
 #if TTL_AVAILABLE
     unsigned int ttl = mDefaultCacheLifetime;
@@ -1234,17 +1236,17 @@ nsHostResolver::PrepareRecordExpiration(
         }
         lifetime = ttl;
         grace = 0;
     }
 #endif
 
     rec->SetExpiration(TimeStamp::NowLoRes(), lifetime, grace);
     LOG(("Caching host [%s%s%s] record for %u seconds (grace %d).",
-         LOG_HOST(rec->host, rec->netInterface), lifetime, grace));
+         LOG_HOST(rec->host.get(), rec->netInterface.get()), lifetime, grace));
 }
 
 static bool
 different_rrset(AddrInfo *rrset1, AddrInfo *rrset2)
 {
     if (!rrset1 || !rrset2) {
         return true;
     }
@@ -1348,32 +1350,32 @@ nsHostResolver::CompleteLookup(nsHostRec
             NS_ADDREF(rec);
             if (mEvictionQSize < mMaxCacheEntries)
                 mEvictionQSize++;
             else {
                 // remove first element on mEvictionQ
                 nsHostRecord *head =
                     static_cast<nsHostRecord *>(PR_LIST_HEAD(&mEvictionQ));
                 PR_REMOVE_AND_INIT_LINK(head);
-                mDB.Remove((nsHostKey *) head);
+                mDB.Remove(static_cast<nsHostKey *>(head));
 
                 if (!head->negative) {
                     // record the age of the entry upon eviction.
                     TimeDuration age = TimeStamp::NowLoRes() - head->mValidStart;
                     Telemetry::Accumulate(Telemetry::DNS_CLEANUP_AGE,
                                           static_cast<uint32_t>(age.ToSeconds() / 60));
                 }
 
                 // release reference to rec owned by mEvictionQ
                 NS_RELEASE(head);
             }
 #if TTL_AVAILABLE
             if (!rec->mGetTtl && !rec->resolving && sGetTtlEnabled) {
                 LOG(("Issuing second async lookup for TTL for host [%s%s%s].",
-                     LOG_HOST(rec->host, rec->netInterface)));
+                     LOG_HOST(rec->host.get(), rec->netInterface.get())));
                 rec->flags =
                   (rec->flags & ~RES_PRIORITY_MEDIUM) | RES_PRIORITY_LOW;
                 DebugOnly<nsresult> rv = IssueLookup(rec);
                 NS_WARNING_ASSERTION(
                     NS_SUCCEEDED(rv),
                     "Could not issue second async lookup for TTL.");
             }
 #endif
@@ -1396,37 +1398,38 @@ nsHostResolver::CancelAsyncRequest(const
                                    uint16_t                af,
                                    const char             *netInterface,
                                    nsIDNSListener         *aListener,
                                    nsresult                status)
 
 {
     MutexAutoLock lock(mLock);
 
-    nsAutoCString originSuffix;
+    nsCString originSuffix;
     aOriginAttributes.CreateSuffix(originSuffix);
 
     // Lookup the host record associated with host, flags & address family
-    nsHostKey key = { host, flags, af, netInterface, originSuffix.get() };
+    nsHostKey key(nsCString(host), flags, af, nsCString(netInterface),
+                  originSuffix);
     auto he = static_cast<nsHostDBEnt*>(mDB.Search(&key));
     if (he) {
         nsHostRecord* recPtr = nullptr;
 
         for (RefPtr<nsResolveHostCallback> c : he->rec->mCallbacks) {
             if (c->EqualsAsyncListener(aListener)) {
                 c->remove();
                 recPtr = he->rec;
                 c->OnResolveHostComplete(this, recPtr, status);
                 break;
             }
         }
 
         // If there are no more callbacks, remove the hash table entry
         if (recPtr && recPtr->mCallbacks.isEmpty()) {
-            mDB.Remove((nsHostKey *)recPtr);
+            mDB.Remove(static_cast<nsHostKey *>(recPtr));
             // If record is on a Queue, remove it and then deref it
             if (recPtr->next != recPtr) {
                 PR_REMOVE_LINK(recPtr);
                 NS_RELEASE(recPtr);
             }
         }
     }
 }
@@ -1467,30 +1470,33 @@ nsHostResolver::ThreadFunc(void *arg)
     nsResState rs;
 #endif
     RefPtr<nsHostResolver> resolver = dont_AddRef((nsHostResolver *)arg);
     nsHostRecord *rec  = nullptr;
     AddrInfo *ai = nullptr;
 
     while (rec || resolver->GetHostToLookup(&rec)) {
         LOG(("DNS lookup thread - Calling getaddrinfo for host [%s%s%s].\n",
-             LOG_HOST(rec->host, rec->netInterface)));
+             LOG_HOST(rec->host.get(), rec->netInterface.get())));
 
         TimeStamp startTime = TimeStamp::Now();
 #if TTL_AVAILABLE
         bool getTtl = rec->mGetTtl;
 #else
         bool getTtl = false;
 #endif
 
-        nsresult status = GetAddrInfo(rec->host, rec->af, rec->flags, rec->netInterface,
-                                      &ai, getTtl);
+        nsresult status = GetAddrInfo(rec->host.get(), rec->af,
+                                      rec->flags,
+                                      rec->netInterface.get(), &ai,
+                                      getTtl);
 #if defined(RES_RETRY_ON_FAILURE)
         if (NS_FAILED(status) && rs.Reset()) {
-            status = GetAddrInfo(rec->host, rec->af, rec->flags, rec->netInterface, &ai,
+            status = GetAddrInfo(rec->host.get(), rec->af,
+                                 rec->flags, rec->netInterface.get(), &ai,
                                  getTtl);
         }
 #endif
 
         {   // obtain lock to check shutdown and manage inter-module telemetry
             MutexAutoLock lock(resolver->mLock);
 
             if (!resolver->mShutdown) {
@@ -1513,23 +1519,23 @@ nsHostResolver::ThreadFunc(void *arg)
                 } else {
                     Telemetry::Accumulate(Telemetry::DNS_FAILED_LOOKUP_TIME, millis);
                 }
             }
         }
 
         // CompleteLookup may release "rec", long before we lose it.
         LOG(("DNS lookup thread - lookup completed for host [%s%s%s]: %s.\n",
-             LOG_HOST(rec->host, rec->netInterface),
+             LOG_HOST(rec->host.get(), rec->netInterface.get()),
              ai ? "success" : "failure: unknown host"));
 
         if (LOOKUP_RESOLVEAGAIN == resolver->CompleteLookup(rec, status, ai)) {
             // leave 'rec' assigned and loop to make a renewed host resolve
             LOG(("DNS lookup thread - Re-resolving host [%s%s%s].\n",
-                 LOG_HOST(rec->host, rec->netInterface)));
+                 LOG_HOST(rec->host.get(), rec->netInterface.get())));
         } else {
             rec = nullptr;
         }
     }
     resolver->mThreadCount--;
     resolver = nullptr;
     LOG(("DNS lookup thread - queue empty, thread finished.\n"));
 }
@@ -1556,17 +1562,17 @@ void
 nsHostResolver::GetDNSCacheEntries(nsTArray<DNSCacheEntries> *args)
 {
     for (auto iter = mDB.Iter(); !iter.Done(); iter.Next()) {
         // We don't pay attention to address literals, only resolved domains.
         // Also require a host.
         auto entry = static_cast<nsHostDBEnt*>(iter.Get());
         nsHostRecord* rec = entry->rec;
         MOZ_ASSERT(rec, "rec should never be null here!");
-        if (!rec || !rec->addr_info || !rec->host) {
+        if (!rec || !rec->addr_info) {
             continue;
         }
 
         DNSCacheEntries info;
         info.hostname = rec->host;
         info.family = rec->af;
         info.netInterface = rec->netInterface;
         info.expiration =
--- a/netwerk/dns/nsHostResolver.h
+++ b/netwerk/dns/nsHostResolver.h
@@ -32,21 +32,34 @@ class nsResolveHostCallback;
 #define MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY 5
 #define MAX_NON_PRIORITY_REQUESTS 150
 
 #define MAX_RESOLVER_THREADS (MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY + \
                               MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY)
 
 struct nsHostKey
 {
-    const char *host;
-    uint16_t    flags;
-    uint16_t    af;
-    const char *netInterface;
-    const char *originSuffix;
+    const nsCString host;
+    uint16_t flags;
+    uint16_t af;
+    const nsCString netInterface;
+    const nsCString originSuffix;
+
+    nsHostKey(const nsACString& host, uint16_t flags,
+              uint16_t af, const nsACString& netInterface,
+              const nsACString& originSuffix)
+        : host(host)
+        , flags(flags)
+        , af(af)
+        , netInterface(netInterface)
+        , originSuffix(originSuffix) {
+    }
+
+    bool operator==(const nsHostKey& other) const;
+    size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 };
 
 /**
  * nsHostRecord - ref counted object type stored in host resolver cache.
  */
 class nsHostRecord : public PRCList, public nsHostKey
 {
     typedef mozilla::Mutex Mutex;
@@ -126,16 +139,17 @@ public:
     static DnsPriority GetPriority(uint16_t aFlags);
 
     bool RemoveOrRefresh(); // Mark records currently being resolved as needed
                             // to resolve again.
 
 private:
     friend class nsHostResolver;
 
+    explicit nsHostRecord(const nsHostKey& key);
     mozilla::LinkedList<RefPtr<nsResolveHostCallback>> mCallbacks;
 
     bool    resolving; /* true if this record is being resolved, which means
                         * that it is either on the pending queue or owned by
                         * one of the worker threads. */
 
     bool    onQueue;  /* true if pending and on the queue (not yet given to getaddrinfo())*/
     bool    usingAnyThread; /* true if off queue and contributing to mActiveAnyThreadCount */