Index: net/base/x509_certificate.cc |
diff --git a/net/base/x509_certificate.cc b/net/base/x509_certificate.cc |
index 27a4ae0819cfdbb46e54b10bb8077f907141bb46..cf9b65c6c641c91d3a9442de91d622bf7fe6b50e 100644 |
--- a/net/base/x509_certificate.cc |
+++ b/net/base/x509_certificate.cc |
@@ -10,8 +10,11 @@ |
#include <cert.h> |
#endif |
+#include <map> |
+ |
#include "base/histogram.h" |
#include "base/logging.h" |
+#include "base/singleton.h" |
#include "base/time.h" |
namespace net { |
@@ -20,7 +23,7 @@ namespace { |
// Returns true if this cert fingerprint is the null (all zero) fingerprint. |
// We use this as a bogus fingerprint value. |
-bool IsNullFingerprint(const X509Certificate::Fingerprint& fingerprint) { |
+bool IsNullFingerprint(const SHA1Fingerprint& fingerprint) { |
for (size_t i = 0; i < arraysize(fingerprint.data); ++i) { |
if (fingerprint.data[i] != 0) |
return false; |
@@ -57,24 +60,12 @@ bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a, |
#endif |
} |
-bool X509Certificate::FingerprintLessThan::operator()( |
- const SHA1Fingerprint& lhs, |
- const SHA1Fingerprint& rhs) const { |
- for (size_t i = 0; i < sizeof(lhs.data); ++i) { |
- if (lhs.data[i] < rhs.data[i]) |
- return true; |
- if (lhs.data[i] > rhs.data[i]) |
- return false; |
- } |
- return false; |
-} |
- |
bool X509Certificate::LessThan::operator()(X509Certificate* lhs, |
X509Certificate* rhs) const { |
if (lhs == rhs) |
return false; |
- X509Certificate::FingerprintLessThan fingerprint_functor; |
+ SHA1FingerprintLessThan fingerprint_functor; |
return fingerprint_functor(lhs->fingerprint_, rhs->fingerprint_); |
} |
@@ -83,6 +74,40 @@ bool X509Certificate::LessThan::operator()(X509Certificate* lhs, |
// The cache does not hold a reference to the certificate objects. The objects |
// must |Remove| themselves from the cache upon destruction (or else the cache |
// will be holding dead pointers to the objects). |
+// TODO(rsleevi): Fix the cache to hold references, as there is a race where: |
+// Thread A: Release the last reference to an X509Certificate. |
+// Thread B: Calls Find(), which acquires |lock_| |
+// Thread A: X509Certificate DTOR invokes, and calls Remove(), which blocks |
+// on |lock_| |
+// Thread B: Finds the X509Certificate (that is DTORing in Thread A) and |
+// returns it, releasing |lock_| |
+// Thread A: Acquires |lock_|, removes the X509Certificate, and then |
+// proceeds with DTOR |
+// Thread B: Now holds a dead pointer |
+class X509Certificate::Cache { |
+ public: |
+ static Cache* GetInstance(); |
+ void Insert(X509Certificate* cert); |
+ void Remove(X509Certificate* cert); |
+ X509Certificate* Find(const SHA1Fingerprint& fingerprint); |
+ |
+ private: |
+ typedef std::map<SHA1Fingerprint, X509Certificate*, SHA1FingerprintLessThan> |
+ CertMap; |
+ |
+ // Obtain an instance of X509Certificate::Cache via GetInstance(). |
+ Cache() {} |
+ friend struct DefaultSingletonTraits<Cache>; |
+ |
+ // You must acquire this lock before using any private data of this object. |
+ // You must not block while holding this lock. |
+ Lock lock_; |
+ |
+ // The certificate cache. You must acquire |lock_| before using |cache_|. |
+ CertMap cache_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(Cache); |
+}; |
// Get the singleton object for the cache. |
// static |
@@ -113,7 +138,8 @@ void X509Certificate::Cache::Remove(X509Certificate* cert) { |
// Find a certificate in the cache with the given fingerprint. If one does |
// not exist, this method returns NULL. |
-X509Certificate* X509Certificate::Cache::Find(const Fingerprint& fingerprint) { |
+X509Certificate* X509Certificate::Cache::Find( |
+ const SHA1Fingerprint& fingerprint) { |
AutoLock lock(lock_); |
CertMap::iterator pos(cache_.find(fingerprint)); |