summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-01-11 07:54:31 -0800
committerAndroid Git Automerger <android-git-automerger@android.com>2011-01-11 07:54:31 -0800
commit14eaf44f53c8cd47b3164278b32d46cfc43a0c0c (patch)
treeb1c1ea6b77a6762d252d4fbe321fb0b6cf105926 /base
parent67a47206fe3c7732c9ba1b07fcca6839c8af9d94 (diff)
parent201ade2fbba22bfb27ae029f4d23fca6ded109a0 (diff)
downloadexternal_chromium-14eaf44f53c8cd47b3164278b32d46cfc43a0c0c.zip
external_chromium-14eaf44f53c8cd47b3164278b32d46cfc43a0c0c.tar.gz
external_chromium-14eaf44f53c8cd47b3164278b32d46cfc43a0c0c.tar.bz2
am 201ade2f: Merge chromium at 9.0.597.55: Initial merge by git.
* commit '201ade2fbba22bfb27ae029f4d23fca6ded109a0': Merge chromium at 9.0.597.55: Initial merge by git.
Diffstat (limited to 'base')
-rw-r--r--base/base.gypi5
-rw-r--r--base/base_paths.h9
-rw-r--r--base/base_paths_linux.cc4
-rw-r--r--base/base_paths_mac.mm2
-rw-r--r--base/command_line_unittest.cc19
-rw-r--r--base/condition_variable_posix.cc1
-rw-r--r--base/crypto/encryptor_openssl.cc2
-rw-r--r--base/crypto/rsa_private_key.h4
-rw-r--r--base/crypto/rsa_private_key_openssl.cc10
-rw-r--r--base/crypto/signature_creator.h9
-rw-r--r--base/crypto/signature_creator_openssl.cc33
-rw-r--r--base/crypto/signature_verifier.h5
-rw-r--r--base/crypto/signature_verifier_openssl.cc66
-rw-r--r--base/crypto/symmetric_key.h8
-rw-r--r--base/crypto/symmetric_key_openssl.cc28
-rw-r--r--base/debug/leak_tracker.h6
-rw-r--r--base/file_util.h8
-rw-r--r--base/file_util_posix.cc26
-rw-r--r--base/file_util_unittest.cc51
-rw-r--r--base/i18n/icu_encoding_detection.cc36
-rw-r--r--base/i18n/icu_encoding_detection.h6
-rw-r--r--base/i18n/rtl.cc21
-rw-r--r--base/i18n/rtl.h28
-rw-r--r--base/lazy_instance.h11
-rw-r--r--base/lock.h3
-rw-r--r--base/lock_impl.h3
-rw-r--r--base/logging.cc6
-rw-r--r--base/message_loop.cc8
-rw-r--r--base/message_loop_proxy.h3
-rw-r--r--base/message_loop_proxy_impl.cc12
-rw-r--r--base/message_loop_unittest.cc64
-rw-r--r--base/message_pump_win.h1
-rw-r--r--base/metrics/histogram.cc1
-rw-r--r--base/native_library.h9
-rw-r--r--base/native_library_win.cc23
-rw-r--r--base/nss_util.cc133
-rw-r--r--base/openssl_util.cc25
-rw-r--r--base/openssl_util.h37
-rw-r--r--base/path_service.cc8
-rw-r--r--base/path_service.h5
-rw-r--r--base/path_service_unittest.cc4
-rw-r--r--base/platform_file.h3
-rw-r--r--base/platform_file_posix.cc1
-rw-r--r--base/platform_file_unittest.cc2
-rw-r--r--base/platform_file_win.cc1
-rw-r--r--base/platform_thread.h18
-rw-r--r--base/platform_thread_posix.cc33
-rw-r--r--base/platform_thread_win.cc74
-rw-r--r--base/process_util_posix.cc58
-rw-r--r--base/process_util_unittest.cc2
-rw-r--r--base/scoped_temp_dir.cc18
-rw-r--r--base/scoped_temp_dir.h2
-rw-r--r--base/scoped_temp_dir_unittest.cc23
-rw-r--r--base/simple_thread_unittest.cc1
-rw-r--r--base/singleton.h12
-rw-r--r--base/task.h2
-rw-r--r--base/test/test_file_util.h8
-rw-r--r--base/test/test_file_util_win.cc58
-rw-r--r--base/third_party/dmg_fp/dtoa_wrapper.cc40
-rw-r--r--base/third_party/icu/icu_utf.h2
-rw-r--r--base/thread.cc4
-rw-r--r--base/thread.h4
-rw-r--r--base/thread_checker.cc13
-rw-r--r--base/thread_checker.h8
-rw-r--r--base/thread_restrictions.cc23
-rw-r--r--base/thread_restrictions.h35
-rw-r--r--base/thread_unittest.cc1
-rw-r--r--base/tracked_objects.cc27
-rw-r--r--base/tracked_objects.h1
-rw-r--r--base/values_util.cc14
-rw-r--r--base/values_util.h28
-rw-r--r--base/vlog.cc11
-rw-r--r--base/win/pe_image.cc6
-rw-r--r--base/win/registry.cc7
-rw-r--r--base/win/rgs_helper.h89
-rw-r--r--base/win/scoped_comptr.h5
76 files changed, 1081 insertions, 296 deletions
diff --git a/base/base.gypi b/base/base.gypi
index 8b876bd..a71ccf4 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -14,8 +14,8 @@
'sources': [
'../build/build_config.h',
'third_party/dmg_fp/dmg_fp.h',
- 'third_party/dmg_fp/dtoa.cc',
'third_party/dmg_fp/g_fmt.cc',
+ 'third_party/dmg_fp/dtoa_wrapper.cc',
'third_party/icu/icu_utf.cc',
'third_party/icu/icu_utf.h',
'third_party/nspr/prtime.cc',
@@ -281,6 +281,8 @@
'utf_string_conversions.h',
'values.cc',
'values.h',
+ 'values_util.cc',
+ 'values_util.h',
'version.cc',
'version.h',
'vlog.cc',
@@ -306,6 +308,7 @@
'win/pe_image.h',
'win/registry.cc',
'win/registry.h',
+ 'win/rgs_helper.h',
'win/scoped_bstr.cc',
'win/scoped_bstr.h',
'win/scoped_comptr.h',
diff --git a/base/base_paths.h b/base/base_paths.h
index 0f9be04..72cff15 100644
--- a/base/base_paths.h
+++ b/base/base_paths.h
@@ -33,10 +33,11 @@ enum {
// for tests that need to locate various resources. It
// should not be used outside of test code.
#if defined(OS_POSIX)
- DIR_USER_CACHE, // Directory where user cache data resides. The Chromium
- // browser cache can be a subdirectory of DIR_USER_CACHE.
- // This is $XDG_CACHE_HOME on Linux and ~/Library/Caches
- // on Mac.
+ DIR_CACHE, // Directory where to put cache data. Note this is
+ // *not* where the browser cache lives, but the
+ // browser cache can be a subdirectory.
+ // This is $XDG_CACHE_HOME on Linux and
+ // ~/Library/Caches on Mac.
#endif
PATH_END
diff --git a/base/base_paths_linux.cc b/base/base_paths_linux.cc
index bb8e635..f8b99e6 100644
--- a/base/base_paths_linux.cc
+++ b/base/base_paths_linux.cc
@@ -105,11 +105,15 @@ bool PathProviderPosix(int key, FilePath* result) {
<< "Try running from your chromium/src directory.";
return false;
}
+<<<<<<< HEAD
case base::DIR_USER_CACHE:
#ifdef ANDROID
NOTREACHED();
return false;
#else
+=======
+ case base::DIR_CACHE:
+>>>>>>> Chromium.org at 9.0.597.55
scoped_ptr<base::Environment> env(base::Environment::Create());
FilePath cache_dir(base::nix::GetXDGDirectory(env.get(), "XDG_CACHE_HOME",
".cache"));
diff --git a/base/base_paths_mac.mm b/base/base_paths_mac.mm
index b9225d8..97413ba 100644
--- a/base/base_paths_mac.mm
+++ b/base/base_paths_mac.mm
@@ -47,7 +47,7 @@ bool PathProviderMac(int key, FilePath* result) {
case base::FILE_MODULE: {
return GetNSExecutablePath(result);
}
- case base::DIR_USER_CACHE:
+ case base::DIR_CACHE:
return mac_util::GetUserDirectory(NSCachesDirectory, result);
case base::DIR_APP_DATA:
return mac_util::GetUserDirectory(NSApplicationSupportDirectory, result);
diff --git a/base/command_line_unittest.cc b/base/command_line_unittest.cc
index 5c525ae..6fd6440 100644
--- a/base/command_line_unittest.cc
+++ b/base/command_line_unittest.cc
@@ -179,3 +179,22 @@ TEST(CommandLineTest, AppendArguments) {
EXPECT_TRUE(c1.HasSwitch("switch2"));
}
+#if defined(OS_WIN)
+// Make sure that the program part of a command line is always quoted.
+// This only makes sense on Windows and the test is basically here to guard
+// against regressions.
+TEST(CommandLineTest, ProgramQuotes) {
+ const FilePath kProgram(L"Program");
+
+ // Check that quotes are not returned from GetProgram().
+ CommandLine cl(kProgram);
+ EXPECT_EQ(kProgram.value(), cl.GetProgram().value());
+
+ // Verify that in the command line string, the program part is always quoted.
+ CommandLine::StringType cmd(cl.command_line_string());
+ CommandLine::StringType program(cl.GetProgram().value());
+ EXPECT_EQ('"', cmd[0]);
+ EXPECT_EQ(program, cmd.substr(1, program.length()));
+ EXPECT_EQ('"', cmd[program.length() + 1]);
+}
+#endif
diff --git a/base/condition_variable_posix.cc b/base/condition_variable_posix.cc
index 9555be7..5d9ccb4 100644
--- a/base/condition_variable_posix.cc
+++ b/base/condition_variable_posix.cc
@@ -8,7 +8,6 @@
#include <sys/time.h>
#include "base/lock.h"
-#include "base/lock_impl.h"
#include "base/logging.h"
#include "base/time.h"
diff --git a/base/crypto/encryptor_openssl.cc b/base/crypto/encryptor_openssl.cc
index 44ae932..7e09545 100644
--- a/base/crypto/encryptor_openssl.cc
+++ b/base/crypto/encryptor_openssl.cc
@@ -34,7 +34,7 @@ class ScopedCipherCTX {
}
~ScopedCipherCTX() {
EVP_CIPHER_CTX_cleanup(&ctx_);
- ClearOpenSSLERRStack();
+ ClearOpenSSLERRStack(FROM_HERE);
}
EVP_CIPHER_CTX* get() { return &ctx_; }
diff --git a/base/crypto/rsa_private_key.h b/base/crypto/rsa_private_key.h
index ea5daac..ecec015 100644
--- a/base/crypto/rsa_private_key.h
+++ b/base/crypto/rsa_private_key.h
@@ -204,7 +204,9 @@ class RSAPrivateKey {
~RSAPrivateKey();
-#if defined(USE_NSS)
+#if defined(USE_OPENSSL)
+ EVP_PKEY* key() { return key_; }
+#elif defined(USE_NSS)
SECKEYPrivateKeyStr* key() { return key_; }
#elif defined(OS_WIN)
HCRYPTPROV provider() { return provider_; }
diff --git a/base/crypto/rsa_private_key_openssl.cc b/base/crypto/rsa_private_key_openssl.cc
index e14965f..0776b63 100644
--- a/base/crypto/rsa_private_key_openssl.cc
+++ b/base/crypto/rsa_private_key_openssl.cc
@@ -29,10 +29,10 @@ bool ExportKey(EVP_PKEY* key,
if (!key)
return false;
+ OpenSSLErrStackTracer err_tracer(FROM_HERE);
ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new(BIO_s_mem()));
int res = export_fn(bio.get(), key);
- ClearOpenSSLERRStack();
if (!res)
return false;
@@ -49,11 +49,9 @@ bool ExportKey(EVP_PKEY* key,
// static
RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
- EnsureOpenSSLInit();
-
+ OpenSSLErrStackTracer err_tracer(FROM_HERE);
ScopedOpenSSL<RSA, RSA_free> rsa_key(RSA_generate_key(num_bits, 65537L,
NULL, NULL));
- ClearOpenSSLERRStack();
if (!rsa_key.get())
return NULL;
@@ -74,7 +72,7 @@ RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) {
// static
RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
const std::vector<uint8>& input) {
- EnsureOpenSSLInit();
+ OpenSSLErrStackTracer err_tracer(FROM_HERE);
// BIO_new_mem_buf is not const aware, but it does not modify the buffer.
char* data = reinterpret_cast<char*>(const_cast<uint8*>(input.data()));
@@ -87,13 +85,11 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
// Info structure returned.
ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> p8inf(
d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), NULL));
- ClearOpenSSLERRStack();
if (!p8inf.get())
return NULL;
scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
result->key_ = EVP_PKCS82PKEY(p8inf.get());
- ClearOpenSSLERRStack();
if (!result->key_)
return NULL;
diff --git a/base/crypto/signature_creator.h b/base/crypto/signature_creator.h
index 38e327b..c405560 100644
--- a/base/crypto/signature_creator.h
+++ b/base/crypto/signature_creator.h
@@ -8,7 +8,10 @@
#include "build/build_config.h"
-#if defined(USE_NSS)
+#if defined(USE_OPENSSL)
+// Forward declaration for openssl/*.h
+typedef struct env_md_ctx_st EVP_MD_CTX;
+#elif defined(USE_NSS)
// Forward declaration.
struct SGNContextStr;
#elif defined(OS_MACOSX)
@@ -48,7 +51,9 @@ class SignatureCreator {
RSAPrivateKey* key_;
-#if defined(USE_NSS)
+#if defined(USE_OPENSSL)
+ EVP_MD_CTX* sign_context_;
+#elif defined(USE_NSS)
SGNContextStr* sign_context_;
#elif defined(OS_MACOSX)
CSSM_CC_HANDLE sig_handle_;
diff --git a/base/crypto/signature_creator_openssl.cc b/base/crypto/signature_creator_openssl.cc
index 5d70f01..7eed379 100644
--- a/base/crypto/signature_creator_openssl.cc
+++ b/base/crypto/signature_creator_openssl.cc
@@ -4,29 +4,50 @@
#include "base/crypto/signature_creator.h"
+#include <openssl/evp.h>
+
#include "base/logging.h"
+#include "base/openssl_util.h"
+#include "base/scoped_ptr.h"
namespace base {
// static
SignatureCreator* SignatureCreator::Create(RSAPrivateKey* key) {
- return NULL;
+ OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ scoped_ptr<SignatureCreator> result(new SignatureCreator);
+ result->key_ = key;
+ if (!EVP_SignInit_ex(result->sign_context_, EVP_sha1(), NULL))
+ return NULL;
+ return result.release();
}
-SignatureCreator::SignatureCreator() {
+SignatureCreator::SignatureCreator()
+ : sign_context_(EVP_MD_CTX_create()) {
}
SignatureCreator::~SignatureCreator() {
+ EVP_MD_CTX_destroy(sign_context_);
}
bool SignatureCreator::Update(const uint8* data_part, int data_part_len) {
- NOTIMPLEMENTED();
- return false;
+ OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ return EVP_SignUpdate(sign_context_, data_part, data_part_len) == 1;
}
bool SignatureCreator::Final(std::vector<uint8>* signature) {
- NOTIMPLEMENTED();
- return false;
+ OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ EVP_PKEY* key = key_->key();
+ signature->resize(EVP_PKEY_size(key));
+
+ unsigned int len = 0;
+ int rv = EVP_SignFinal(sign_context_, signature->data(), &len, key);
+ if (!rv) {
+ signature->clear();
+ return false;
+ }
+ signature->resize(len);
+ return true;
}
} // namespace base
diff --git a/base/crypto/signature_verifier.h b/base/crypto/signature_verifier.h
index 4746edc..e2b61af 100644
--- a/base/crypto/signature_verifier.h
+++ b/base/crypto/signature_verifier.h
@@ -83,7 +83,10 @@ class SignatureVerifier {
std::vector<uint8> signature_;
-#if defined(USE_NSS)
+#if defined(USE_OPENSSL)
+ struct VerifyContext;
+ VerifyContext* verify_context_;
+#elif defined(USE_NSS)
VFYContext* vfy_context_;
#elif defined(OS_MACOSX)
std::vector<uint8> public_key_info_;
diff --git a/base/crypto/signature_verifier_openssl.cc b/base/crypto/signature_verifier_openssl.cc
index 49b5e07..b4fff78 100644
--- a/base/crypto/signature_verifier_openssl.cc
+++ b/base/crypto/signature_verifier_openssl.cc
@@ -4,14 +4,28 @@
#include "base/crypto/signature_verifier.h"
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <vector>
+
#include "base/logging.h"
+#include "base/openssl_util.h"
+#include "base/scoped_ptr.h"
namespace base {
-SignatureVerifier::SignatureVerifier() {
+struct SignatureVerifier::VerifyContext {
+ ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> public_key;
+ ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy> ctx;
+};
+
+SignatureVerifier::SignatureVerifier()
+ : verify_context_(NULL) {
}
SignatureVerifier::~SignatureVerifier() {
+ Reset();
}
bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm,
@@ -20,22 +34,60 @@ bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm,
int signature_len,
const uint8* public_key_info,
int public_key_info_len) {
- NOTIMPLEMENTED();
- return false;
+ DCHECK(!verify_context_);
+ verify_context_ = new VerifyContext;
+ OpenSSLErrStackTracer err_tracer(FROM_HERE);
+
+ ScopedOpenSSL<X509_ALGOR, X509_ALGOR_free> algorithm(
+ d2i_X509_ALGOR(NULL, &signature_algorithm, signature_algorithm_len));
+ if (!algorithm.get())
+ return false;
+
+ const EVP_MD* digest = EVP_get_digestbyobj(algorithm.get()->algorithm);
+ DCHECK(digest);
+
+ signature_.assign(signature, signature + signature_len);
+
+ // BIO_new_mem_buf is not const aware, but it does not modify the buffer.
+ char* data = reinterpret_cast<char*>(const_cast<uint8*>(public_key_info));
+ ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new_mem_buf(data,
+ public_key_info_len));
+ if (!bio.get())
+ return false;
+
+ verify_context_->public_key.reset(d2i_PUBKEY_bio(bio.get(), NULL));
+ if (!verify_context_->public_key.get())
+ return false;
+
+ verify_context_->ctx.reset(EVP_MD_CTX_create());
+ int rv = EVP_VerifyInit_ex(verify_context_->ctx.get(), digest, NULL);
+ return rv == 1;
}
void SignatureVerifier::VerifyUpdate(const uint8* data_part,
int data_part_len) {
- NOTIMPLEMENTED();
+ DCHECK(verify_context_);
+ OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ int rv = EVP_VerifyUpdate(verify_context_->ctx.get(),
+ data_part, data_part_len);
+ DCHECK_EQ(rv, 1);
}
bool SignatureVerifier::VerifyFinal() {
- NOTIMPLEMENTED();
- return false;
+ DCHECK(verify_context_);
+ OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ int rv = EVP_VerifyFinal(verify_context_->ctx.get(),
+ signature_.data(), signature_.size(),
+ verify_context_->public_key.get());
+ DCHECK_GE(rv, 0);
+ Reset();
+ return rv == 1;
}
void SignatureVerifier::Reset() {
- NOTIMPLEMENTED();
+ delete verify_context_;
+ verify_context_ = NULL;
+ signature_.clear();
}
} // namespace base
diff --git a/base/crypto/symmetric_key.h b/base/crypto/symmetric_key.h
index 6ad0646..ce98fa6 100644
--- a/base/crypto/symmetric_key.h
+++ b/base/crypto/symmetric_key.h
@@ -49,10 +49,10 @@ class SymmetricKey {
size_t iterations,
size_t key_size_in_bits);
- // Imports a raw key. For this call to be successful, |raw_key| must have been
- // generated by either GenerateRandomKey or DeriveKeyFromPassword, and
- // must have been exported with GetRawKey. The caller owns the returned
- // SymmetricKey.
+ // Imports an array of key bytes in |raw_key|. This key may have been
+ // generated by GenerateRandomKey or DeriveKeyFromPassword and exported with
+ // GetRawKey, or via another compatible method. The key must be of suitable
+ // size for use with |algorithm|. The caller owns the returned SymmetricKey.
static SymmetricKey* Import(Algorithm algorithm, const std::string& raw_key);
#if defined(USE_OPENSSL)
diff --git a/base/crypto/symmetric_key_openssl.cc b/base/crypto/symmetric_key_openssl.cc
index 9f0ad38..409cce4 100644
--- a/base/crypto/symmetric_key_openssl.cc
+++ b/base/crypto/symmetric_key_openssl.cc
@@ -30,18 +30,13 @@ SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm,
if (key_size_in_bits == 0)
return NULL;
- EnsureOpenSSLInit();
+ OpenSSLErrStackTracer err_tracer(FROM_HERE);
scoped_ptr<SymmetricKey> key(new SymmetricKey);
uint8* key_data =
reinterpret_cast<uint8*>(WriteInto(&key->key_, key_size_in_bytes + 1));
- int res = RAND_bytes(key_data, key_size_in_bytes);
- if (res != 1) {
- DLOG(ERROR) << "RAND_bytes failed. res = " << res;
- ClearOpenSSLERRStack();
- return NULL;
- }
- return key.release();
+ int rv = RAND_bytes(key_data, key_size_in_bytes);
+ return rv == 1 ? key.release() : NULL;
}
// static
@@ -54,20 +49,15 @@ SymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm,
int key_size_in_bytes = key_size_in_bits / 8;
DCHECK_EQ(static_cast<int>(key_size_in_bits), key_size_in_bytes * 8);
- EnsureOpenSSLInit();
+ OpenSSLErrStackTracer err_tracer(FROM_HERE);
scoped_ptr<SymmetricKey> key(new SymmetricKey);
uint8* key_data =
reinterpret_cast<uint8*>(WriteInto(&key->key_, key_size_in_bytes + 1));
- int res = PKCS5_PBKDF2_HMAC_SHA1(password.data(), password.length(),
- reinterpret_cast<const uint8*>(salt.data()),
- salt.length(), iterations,
- key_size_in_bytes, key_data);
- if (res != 1) {
- DLOG(ERROR) << "HMAC SHA1 failed. res = " << res;
- ClearOpenSSLERRStack();
- return NULL;
- }
- return key.release();
+ int rv = PKCS5_PBKDF2_HMAC_SHA1(password.data(), password.length(),
+ reinterpret_cast<const uint8*>(salt.data()),
+ salt.length(), iterations,
+ key_size_in_bytes, key_data);
+ return rv == 1 ? key.release() : NULL;
}
// static
diff --git a/base/debug/leak_tracker.h b/base/debug/leak_tracker.h
index 8af82a9..9709aa1 100644
--- a/base/debug/leak_tracker.h
+++ b/base/debug/leak_tracker.h
@@ -91,8 +91,10 @@ class LeakTracker : public LinkNode<LeakTracker<T> > {
stacktraces[count] = allocation_stack;
++count;
- LOG(ERROR) << "Leaked " << node << " which was allocated by:";
- allocation_stack.OutputToStream(&LOG_STREAM(ERROR));
+ if (LOG_IS_ON(ERROR)) {
+ LOG_STREAM(ERROR) << "Leaked " << node << " which was allocated by:";
+ allocation_stack.OutputToStream(&LOG_STREAM(ERROR));
+ }
}
CHECK_EQ(0u, count);
diff --git a/base/file_util.h b/base/file_util.h
index bba7e2d..e34d0de 100644
--- a/base/file_util.h
+++ b/base/file_util.h
@@ -179,6 +179,14 @@ bool ReadFileToString(const FilePath& path, std::string* contents);
// in |buffer|. This function is protected against EINTR and partial reads.
// Returns true iff |bytes| bytes have been successfuly read from |fd|.
bool ReadFromFD(int fd, char* buffer, size_t bytes);
+
+// Creates a symbolic link at |symlink| pointing to |target|. Returns
+// false on failure.
+bool CreateSymbolicLink(const FilePath& target, const FilePath& symlink);
+
+// Reads the given |symlink| and returns where it points to in |target|.
+// Returns false upon failure.
+bool ReadSymbolicLink(const FilePath& symlink, FilePath* target);
#endif // defined(OS_POSIX)
#if defined(OS_WIN)
diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc
index f1caa29..56b1ce0 100644
--- a/base/file_util_posix.cc
+++ b/base/file_util_posix.cc
@@ -33,7 +33,6 @@
#include "base/basictypes.h"
#include "base/eintr_wrapper.h"
#include "base/file_path.h"
-#include "base/lock.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/singleton.h"
@@ -374,6 +373,29 @@ bool ReadFromFD(int fd, char* buffer, size_t bytes) {
return total_read == bytes;
}
+bool CreateSymbolicLink(const FilePath& target_path,
+ const FilePath& symlink_path) {
+ DCHECK(!symlink_path.empty());
+ DCHECK(!target_path.empty());
+ return ::symlink(target_path.value().c_str(),
+ symlink_path.value().c_str()) != -1;
+}
+
+bool ReadSymbolicLink(const FilePath& symlink_path,
+ FilePath* target_path) {
+ DCHECK(!symlink_path.empty());
+ DCHECK(target_path);
+ char buf[PATH_MAX];
+ ssize_t count = ::readlink(symlink_path.value().c_str(), buf, arraysize(buf));
+
+ if (count <= 0)
+ return false;
+
+ *target_path = FilePath(FilePath::StringType(buf, count));
+
+ return true;
+}
+
// Creates and opens a temporary file in |directory|, returning the
// file descriptor. |path| is set to the temporary file path.
// This function does NOT unlink() the file.
@@ -865,4 +887,4 @@ bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
}
#endif // defined(OS_MACOSX)
-} // namespace file_util
+} // namespace file_util
diff --git a/base/file_util_unittest.cc b/base/file_util_unittest.cc
index ca36b6a..cb77828 100644
--- a/base/file_util_unittest.cc
+++ b/base/file_util_unittest.cc
@@ -581,17 +581,46 @@ TEST_F(FileUtilTest, NormalizeFilePathReparsePoints) {
#endif // defined(OS_WIN)
-// The following test of NormalizeFilePath() require that we create a symlink.
-// This can not be done on windows before vista. On vista, creating a symlink
-// requires privilege "SeCreateSymbolicLinkPrivilege".
-// TODO(skerner): Investigate the possibility of giving base_unittests the
-// privileges required to create a symlink.
#if defined(OS_POSIX)
-bool MakeSymlink(const FilePath& link_to, const FilePath& link_from) {
- return (symlink(link_to.value().c_str(), link_from.value().c_str()) == 0);
+TEST_F(FileUtilTest, CreateAndReadSymlinks) {
+ FilePath link_from = temp_dir_.path().Append(FPL("from_file"));
+ FilePath link_to = temp_dir_.path().Append(FPL("to_file"));
+ CreateTextFile(link_to, bogus_content);
+
+ ASSERT_TRUE(file_util::CreateSymbolicLink(link_to, link_from))
+ << "Failed to create file symlink.";
+
+ // If we created the link properly, we should be able to read the
+ // contents through it.
+ std::wstring contents = ReadTextFile(link_from);
+ ASSERT_EQ(contents, bogus_content);
+
+ FilePath result;
+ ASSERT_TRUE(file_util::ReadSymbolicLink(link_from, &result));
+ ASSERT_EQ(link_to.value(), result.value());
+
+ // Link to a directory.
+ link_from = temp_dir_.path().Append(FPL("from_dir"));
+ link_to = temp_dir_.path().Append(FPL("to_dir"));
+ file_util::CreateDirectory(link_to);
+
+ ASSERT_TRUE(file_util::CreateSymbolicLink(link_to, link_from))
+ << "Failed to create directory symlink.";
+
+ // Test failures.
+ ASSERT_FALSE(file_util::CreateSymbolicLink(link_to, link_to));
+ ASSERT_FALSE(file_util::ReadSymbolicLink(link_to, &result));
+ FilePath missing = temp_dir_.path().Append(FPL("missing"));
+ ASSERT_FALSE(file_util::ReadSymbolicLink(missing, &result));
}
+
+// The following test of NormalizeFilePath() require that we create a symlink.
+// This can not be done on Windows before Vista. On Vista, creating a symlink
+// requires privilege "SeCreateSymbolicLinkPrivilege".
+// TODO(skerner): Investigate the possibility of giving base_unittests the
+// privileges required to create a symlink.
TEST_F(FileUtilTest, NormalizeFilePathSymlinks) {
FilePath normalized_path;
@@ -600,7 +629,7 @@ TEST_F(FileUtilTest, NormalizeFilePathSymlinks) {
FilePath link_to = temp_dir_.path().Append(FPL("to_file"));
CreateTextFile(link_to, bogus_content);
- ASSERT_TRUE(MakeSymlink(link_to, link_from))
+ ASSERT_TRUE(file_util::CreateSymbolicLink(link_to, link_from))
<< "Failed to create file symlink.";
// Check that NormalizeFilePath sees the link.
@@ -614,7 +643,7 @@ TEST_F(FileUtilTest, NormalizeFilePathSymlinks) {
link_to = temp_dir_.path().Append(FPL("to_dir"));
file_util::CreateDirectory(link_to);
- ASSERT_TRUE(MakeSymlink(link_to, link_from))
+ ASSERT_TRUE(file_util::CreateSymbolicLink(link_to, link_from))
<< "Failed to create directory symlink.";
ASSERT_FALSE(file_util::NormalizeFilePath(link_from, &normalized_path))
@@ -623,9 +652,9 @@ TEST_F(FileUtilTest, NormalizeFilePathSymlinks) {
// Test that a loop in the links causes NormalizeFilePath() to return false.
link_from = temp_dir_.path().Append(FPL("link_a"));
link_to = temp_dir_.path().Append(FPL("link_b"));
- ASSERT_TRUE(MakeSymlink(link_to, link_from))
+ ASSERT_TRUE(file_util::CreateSymbolicLink(link_to, link_from))
<< "Failed to create loop symlink a.";
- ASSERT_TRUE(MakeSymlink(link_from, link_to))
+ ASSERT_TRUE(file_util::CreateSymbolicLink(link_from, link_to))
<< "Failed to create loop symlink b.";
// Infinite loop!
diff --git a/base/i18n/icu_encoding_detection.cc b/base/i18n/icu_encoding_detection.cc
index 55785c5..d579af2 100644
--- a/base/i18n/icu_encoding_detection.cc
+++ b/base/i18n/icu_encoding_detection.cc
@@ -9,8 +9,6 @@
namespace base {
-// TODO(jungshik): We can apply more heuristics here (e.g. using various hints
-// like TLD, the UI language/default encoding of a client, etc).
bool DetectEncoding(const std::string& text, std::string* encoding) {
if (IsStringASCII(text)) {
*encoding = std::string();
@@ -21,9 +19,6 @@ bool DetectEncoding(const std::string& text, std::string* encoding) {
UCharsetDetector* detector = ucsdet_open(&status);
ucsdet_setText(detector, text.data(), static_cast<int32_t>(text.length()),
&status);
- // TODO(jungshik): Should we check the quality of the match? A rather
- // arbitrary number is assigned by ICU and it's hard to come up with
- // a lower limit.
const UCharsetMatch* match = ucsdet_detect(detector, &status);
const char* detected_encoding = ucsdet_getName(match, &status);
ucsdet_close(detector);
@@ -35,4 +30,35 @@ bool DetectEncoding(const std::string& text, std::string* encoding) {
return true;
}
+bool DetectAllEncodings(const std::string& text,
+ std::vector<std::string>* encodings) {
+ UErrorCode status = U_ZERO_ERROR;
+ UCharsetDetector* detector = ucsdet_open(&status);
+ ucsdet_setText(detector, text.data(), static_cast<int32_t>(text.length()),
+ &status);
+ int matches_count = 0;
+ const UCharsetMatch** matches = ucsdet_detectAll(detector,
+ &matches_count,
+ &status);
+ if (U_FAILURE(status)) {
+ ucsdet_close(detector);
+ return false;
+ }
+
+ encodings->clear();
+ for (int i = 0; i < matches_count; i++) {
+ UErrorCode get_name_status = U_ZERO_ERROR;
+ const char* encoding_name = ucsdet_getName(matches[i], &get_name_status);
+
+ // If we failed to get the encoding's name, ignore the error.
+ if (U_FAILURE(get_name_status))
+ continue;
+
+ encodings->push_back(encoding_name);
+ }
+
+ ucsdet_close(detector);
+ return !encodings->empty();
+}
+
} // namespace base
diff --git a/base/i18n/icu_encoding_detection.h b/base/i18n/icu_encoding_detection.h
index e7e6253..cdc4cb7 100644
--- a/base/i18n/icu_encoding_detection.h
+++ b/base/i18n/icu_encoding_detection.h
@@ -7,6 +7,7 @@
#pragma once
#include <string>
+#include <vector>
namespace base {
@@ -15,6 +16,11 @@ namespace base {
// Returns true on success.
bool DetectEncoding(const std::string& text, std::string* encoding);
+// Detect all possible encodings of |text| and put their names
+// (as returned by ICU) in |encodings|. Returns true on success.
+bool DetectAllEncodings(const std::string& text,
+ std::vector<std::string>* encodings);
+
} // namespace base
#endif // BASE_I18N_ICU_ENCODING_DETECTION_H_
diff --git a/base/i18n/rtl.cc b/base/i18n/rtl.cc
index 0881fb7..6a5d293 100644
--- a/base/i18n/rtl.cc
+++ b/base/i18n/rtl.cc
@@ -163,30 +163,27 @@ TextDirection GetFirstStrongCharacterDirection(const std::wstring& text) {
}
#endif
-bool AdjustStringForLocaleDirection(const string16& text,
- string16* localized_text) {
- if (!IsRTL() || text.empty())
+bool AdjustStringForLocaleDirection(string16* text) {
+ if (!IsRTL() || text->empty())
return false;
// Marking the string as LTR if the locale is RTL and the string does not
// contain strong RTL characters. Otherwise, mark the string as RTL.
- *localized_text = text;
- bool has_rtl_chars = StringContainsStrongRTLChars(text);
+ bool has_rtl_chars = StringContainsStrongRTLChars(*text);
if (!has_rtl_chars)
- WrapStringWithLTRFormatting(localized_text);
+ WrapStringWithLTRFormatting(text);
else
- WrapStringWithRTLFormatting(localized_text);
+ WrapStringWithRTLFormatting(text);
return true;
}
#if defined(WCHAR_T_IS_UTF32)
-bool AdjustStringForLocaleDirection(const std::wstring& text,
- std::wstring* localized_text) {
- string16 out;
- if (AdjustStringForLocaleDirection(WideToUTF16(text), &out)) {
+bool AdjustStringForLocaleDirection(std::wstring* text) {
+ string16 temp = WideToUTF16(*text);
+ if (AdjustStringForLocaleDirection(&temp)) {
// We should only touch the output on success.
- *localized_text = UTF16ToWide(out);
+ *text = UTF16ToWide(temp);
return true;
}
return false;
diff --git a/base/i18n/rtl.h b/base/i18n/rtl.h
index ed0882f..82ac576 100644
--- a/base/i18n/rtl.h
+++ b/base/i18n/rtl.h
@@ -71,13 +71,12 @@ TextDirection GetFirstStrongCharacterDirection(const string16& text);
TextDirection GetFirstStrongCharacterDirection(const std::wstring& text);
#endif
-// Given the string in |text|, this function creates a copy of the string with
+// Given the string in |text|, this function modifies the string in place with
// the appropriate Unicode formatting marks that mark the string direction
-// (either left-to-right or right-to-left). The new string is returned in
-// |localized_text|. The function checks both the current locale and the
-// contents of the string in order to determine the direction of the returned
-// string. The function returns true if the string in |text| was properly
-// adjusted.
+// (either left-to-right or right-to-left). The function checks both the current
+// locale and the contents of the string in order to determine the direction of
+// the returned string. The function returns true if the string in |text| was
+// properly adjusted.
//
// Certain LTR strings are not rendered correctly when the context is RTL. For
// example, the string "Foo!" will appear as "!Foo" if it is rendered as is in
@@ -85,16 +84,7 @@ TextDirection GetFirstStrongCharacterDirection(const std::wstring& text);
// string is always treated as a right-to-left string. This is done by
// inserting certain Unicode formatting marks into the returned string.
//
-// TODO(brettw) bug 47194: This funciton is confusing. If it does no adjustment
-// becuase the current locale is not RTL, it will do nothing and return false.
-// This means you have to check the return value in many cases which doesn't
-// make sense. This should be cleaned up and probably just take a single
-// argument that's a pointer to a string that it modifies as necessary. In the
-// meantime, the recommended usage is to use the same arg as input & output,
-// which will work without extra checks:
-// AdjustStringForLocaleDirection(text, &text);
-//
-// TODO(idana) bug# 1206120: this function adjusts the string in question only
+// TODO(idana) bug 6806: this function adjusts the string in question only
// if the current locale is right-to-left. The function does not take care of
// the opposite case (an RTL string displayed in an LTR context) since
// adjusting the string involves inserting Unicode formatting characters that
@@ -102,11 +92,9 @@ TextDirection GetFirstStrongCharacterDirection(const std::wstring& text);
// installed. Since the English version of Windows doesn't have right-to-left
// language support installed by default, inserting the direction Unicode mark
// results in Windows displaying squares.
-bool AdjustStringForLocaleDirection(const string16& text,
- string16* localized_text);
+bool AdjustStringForLocaleDirection(string16* text);
#if defined(WCHAR_T_IS_UTF32)
-bool AdjustStringForLocaleDirection(const std::wstring& text,
- std::wstring* localized_text);
+bool AdjustStringForLocaleDirection(std::wstring* text);
#endif
// Returns true if the string contains at least one character with strong right
diff --git a/base/lazy_instance.h b/base/lazy_instance.h
index ebf1e73..f8d5987 100644
--- a/base/lazy_instance.h
+++ b/base/lazy_instance.h
@@ -36,14 +36,19 @@
#define BASE_LAZY_INSTANCE_H_
#pragma once
+#include <new> // For placement new.
+
#include "base/atomicops.h"
#include "base/basictypes.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/thread_restrictions.h"
namespace base {
template <typename Type>
struct DefaultLazyInstanceTraits {
+ static const bool kAllowedToAccessOnNonjoinableThread = false;
+
static Type* New(void* instance) {
// Use placement new to initialize our instance in our preallocated space.
// The parenthesis is very important here to force POD type initialization.
@@ -57,6 +62,8 @@ struct DefaultLazyInstanceTraits {
template <typename Type>
struct LeakyLazyInstanceTraits {
+ static const bool kAllowedToAccessOnNonjoinableThread = true;
+
static Type* New(void* instance) {
return DefaultLazyInstanceTraits<Type>::New(instance);
}
@@ -112,6 +119,9 @@ class LazyInstance : public LazyInstanceHelper {
}
Type* Pointer() {
+ if (!Traits::kAllowedToAccessOnNonjoinableThread)
+ base::ThreadRestrictions::AssertSingletonAllowed();
+
// We will hopefully have fast access when the instance is already created.
if ((base::subtle::NoBarrier_Load(&state_) != STATE_CREATED) &&
NeedsInstance()) {
@@ -126,7 +136,6 @@ class LazyInstance : public LazyInstanceHelper {
// and CompleteInstance(...) happens before "return instance_" below.
// See the corresponding HAPPENS_BEFORE in CompleteInstance(...).
ANNOTATE_HAPPENS_AFTER(&state_);
-
return instance_;
}
diff --git a/base/lock.h b/base/lock.h
index 0ae4861..ba34964 100644
--- a/base/lock.h
+++ b/base/lock.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,6 +7,7 @@
#pragma once
#include "base/lock_impl.h"
+#include "base/platform_thread.h"
// A convenient wrapper for an OS specific critical section. The only real
// intelligence in this class is in debug mode for the support for the
diff --git a/base/lock_impl.h b/base/lock_impl.h
index 9a6a1a0..6066495 100644
--- a/base/lock_impl.h
+++ b/base/lock_impl.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -15,7 +15,6 @@
#endif
#include "base/basictypes.h"
-#include "base/platform_thread.h"
// This class implements the underlying platform-specific spin-lock mechanism
// used for the Lock class. Most users should not use LockImpl directly, but
diff --git a/base/logging.cc b/base/logging.cc
index 9cc191d..a202e05 100644
--- a/base/logging.cc
+++ b/base/logging.cc
@@ -608,12 +608,6 @@ void LogMessage::Init(const char* file, int line) {
}
LogMessage::~LogMessage() {
- // The macros in logging.h should already avoid creating LogMessages
- // when this holds, but it's possible that users create LogMessages
- // directly (e.g., using LOG_STREAM() directly).
- if (severity_ < min_log_level)
- return;
-
#ifndef NDEBUG
if (severity_ == LOG_FATAL) {
// Include a stack trace on a fatal.
diff --git a/base/message_loop.cc b/base/message_loop.cc
index 1e472e0..1670d79 100644
--- a/base/message_loop.cc
+++ b/base/message_loop.cc
@@ -165,10 +165,6 @@ MessageLoop::MessageLoop(Type type)
MessageLoop::~MessageLoop() {
DCHECK_EQ(this, current());
- // Let interested parties have one last shot at accessing this.
- FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,
- WillDestroyCurrentMessageLoop());
-
DCHECK(!state_);
// Clean up any unprocessed tasks, but take care: deleting a task could
@@ -188,6 +184,10 @@ MessageLoop::~MessageLoop() {
}
DCHECK(!did_work);
+ // Let interested parties have one last shot at accessing this.
+ FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,
+ WillDestroyCurrentMessageLoop());
+
// OK, now make it so that no one can find us.
lazy_tls_ptr.Pointer()->Set(NULL);
}
diff --git a/base/message_loop_proxy.h b/base/message_loop_proxy.h
index 4d38155..6a8cbe8 100644
--- a/base/message_loop_proxy.h
+++ b/base/message_loop_proxy.h
@@ -16,7 +16,8 @@ struct MessageLoopProxyTraits;
// This class provides a thread-safe refcounted interface to the Post* methods
// of a message loop. This class can outlive the target message loop. You can
-// obtain a MessageLoopProxy via Thread::message_loop_proxy().
+// obtain a MessageLoopProxy via Thread::message_loop_proxy() or
+// MessageLoopProxy::CreateForCurrentThread().
class MessageLoopProxy
: public base::RefCountedThreadSafe<MessageLoopProxy,
MessageLoopProxyTraits> {
diff --git a/base/message_loop_proxy_impl.cc b/base/message_loop_proxy_impl.cc
index 2e0f809..c0619aa 100644
--- a/base/message_loop_proxy_impl.cc
+++ b/base/message_loop_proxy_impl.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/message_loop_proxy_impl.h"
+#include "base/thread_restrictions.h"
namespace base {
@@ -45,6 +46,11 @@ bool MessageLoopProxyImpl::PostNonNestableDelayedTask(
}
bool MessageLoopProxyImpl::BelongsToCurrentThread() {
+ // We shouldn't use MessageLoop::current() since it uses LazyInstance which
+ // may be deleted by ~AtExitManager when a WorkerPool thread calls this
+ // function.
+ // http://crbug.com/63678
+ base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
AutoLock lock(message_loop_lock_);
return (target_message_loop_ &&
(MessageLoop::current() == target_message_loop_));
@@ -72,6 +78,11 @@ bool MessageLoopProxyImpl::PostTaskHelper(
}
void MessageLoopProxyImpl::OnDestruct() const {
+ // We shouldn't use MessageLoop::current() since it uses LazyInstance which
+ // may be deleted by ~AtExitManager when a WorkerPool thread calls this
+ // function.
+ // http://crbug.com/63678
+ base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
bool delete_later = false;
{
AutoLock lock(message_loop_lock_);
@@ -98,4 +109,3 @@ MessageLoopProxy::CreateForCurrentThread() {
}
} // namespace base
-
diff --git a/base/message_loop_unittest.cc b/base/message_loop_unittest.cc
index a3c3307..537c606 100644
--- a/base/message_loop_unittest.cc
+++ b/base/message_loop_unittest.cc
@@ -1647,3 +1647,67 @@ TEST(MessageLoopTest, FileDescriptorWatcherDoubleStop) {
} // namespace
#endif // defined(OS_POSIX)
+
+namespace {
+class RunAtDestructionTask : public Task {
+ public:
+ RunAtDestructionTask(bool* task_destroyed, bool* destruction_observer_called)
+ : task_destroyed_(task_destroyed),
+ destruction_observer_called_(destruction_observer_called) {
+ }
+ ~RunAtDestructionTask() {
+ EXPECT_FALSE(*destruction_observer_called_);
+ *task_destroyed_ = true;
+ }
+ virtual void Run() {
+ // This task should never run.
+ ADD_FAILURE();
+ }
+ private:
+ bool* task_destroyed_;
+ bool* destruction_observer_called_;
+};
+
+class MLDestructionObserver : public MessageLoop::DestructionObserver {
+ public:
+ MLDestructionObserver(bool* task_destroyed, bool* destruction_observer_called)
+ : task_destroyed_(task_destroyed),
+ destruction_observer_called_(destruction_observer_called),
+ task_destroyed_before_message_loop_(false) {
+ }
+ virtual void WillDestroyCurrentMessageLoop() {
+ task_destroyed_before_message_loop_ = *task_destroyed_;
+ *destruction_observer_called_ = true;
+ }
+ bool task_destroyed_before_message_loop() const {
+ return task_destroyed_before_message_loop_;
+ }
+ private:
+ bool* task_destroyed_;
+ bool* destruction_observer_called_;
+ bool task_destroyed_before_message_loop_;
+};
+
+} // namespace
+
+TEST(MessageLoopTest, DestructionObserverTest) {
+ // Verify that the destruction observer gets called at the very end (after
+ // all the pending tasks have been destroyed).
+ MessageLoop* loop = new MessageLoop;
+ const int kDelayMS = 100;
+
+ bool task_destroyed = false;
+ bool destruction_observer_called = false;
+
+ MLDestructionObserver observer(&task_destroyed, &destruction_observer_called);
+ loop->AddDestructionObserver(&observer);
+ loop->PostDelayedTask(
+ FROM_HERE,
+ new RunAtDestructionTask(&task_destroyed, &destruction_observer_called),
+ kDelayMS);
+ delete loop;
+ EXPECT_TRUE(observer.task_destroyed_before_message_loop());
+ // The task should have been destroyed when we deleted the loop.
+ EXPECT_TRUE(task_destroyed);
+ EXPECT_TRUE(destruction_observer_called);
+}
diff --git a/base/message_pump_win.h b/base/message_pump_win.h
index d57fe1d..ea7dd39 100644
--- a/base/message_pump_win.h
+++ b/base/message_pump_win.h
@@ -11,7 +11,6 @@
#include <list>
#include "base/basictypes.h"
-#include "base/lock.h"
#include "base/message_pump.h"
#include "base/observer_list.h"
#include "base/scoped_handle.h"
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index 2003f25..729e3b9 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -614,7 +614,6 @@ Count Histogram::SampleSet::TotalCount() const {
++it) {
total += *it;
}
- DCHECK_EQ(total, redundant_count_);
return total;
}
diff --git a/base/native_library.h b/base/native_library.h
index 3d8c280..6afd06d 100644
--- a/base/native_library.h
+++ b/base/native_library.h
@@ -54,6 +54,15 @@ typedef void* NativeLibrary;
// you're done.
NativeLibrary LoadNativeLibrary(const FilePath& library_path);
+#if defined(OS_WIN)
+// Loads a native library from disk. Release it with UnloadNativeLibrary when
+// you're done.
+// This function retrieves the LoadLibrary function exported from kernel32.dll
+// and calls it instead of directly calling the LoadLibrary function via the
+// import table.
+NativeLibrary LoadNativeLibraryDynamically(const FilePath& library_path);
+#endif // OS_WIN
+
// Unloads a native library.
void UnloadNativeLibrary(NativeLibrary library);
diff --git a/base/native_library_win.cc b/base/native_library_win.cc
index b498eba..b8a806b 100644
--- a/base/native_library_win.cc
+++ b/base/native_library_win.cc
@@ -12,8 +12,10 @@
namespace base {
-// static
-NativeLibrary LoadNativeLibrary(const FilePath& library_path) {
+typedef HMODULE (WINAPI* LoadLibraryFunction)(const wchar_t* file_name);
+
+NativeLibrary LoadNativeLibraryHelper(const FilePath& library_path,
+ LoadLibraryFunction load_library_api) {
// LoadLibrary() opens the file off disk.
base::ThreadRestrictions::AssertIOAllowed();
@@ -29,7 +31,7 @@ NativeLibrary LoadNativeLibrary(const FilePath& library_path) {
}
}
- HMODULE module = LoadLibrary(library_path.value().c_str());
+ HMODULE module = (*load_library_api)(library_path.value().c_str());
if (restore_directory)
file_util::SetCurrentDirectory(current_directory);
@@ -37,6 +39,21 @@ NativeLibrary LoadNativeLibrary(const FilePath& library_path) {
}
// static
+NativeLibrary LoadNativeLibrary(const FilePath& library_path) {
+ return LoadNativeLibraryHelper(library_path, LoadLibraryW);
+}
+
+NativeLibrary LoadNativeLibraryDynamically(const FilePath& library_path) {
+ typedef HMODULE (WINAPI* LoadLibraryFunction)(const wchar_t* file_name);
+
+ LoadLibraryFunction load_library;
+ load_library = reinterpret_cast<LoadLibraryFunction>(
+ GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW"));
+
+ return LoadNativeLibraryHelper(library_path, load_library);
+}
+
+// static
void UnloadNativeLibrary(NativeLibrary library) {
FreeLibrary(library);
}
diff --git a/base/nss_util.cc b/base/nss_util.cc
index fd91142..580fb60 100644
--- a/base/nss_util.cc
+++ b/base/nss_util.cc
@@ -19,8 +19,8 @@
#endif
#include "base/file_util.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
-#include "base/singleton.h"
#include "base/stringprintf.h"
#include "base/thread_restrictions.h"
@@ -83,7 +83,7 @@ void UseLocalCacheOfNSSDatabaseIfNFS(const FilePath& database_dir) {
struct statfs buf;
if (statfs(database_dir.value().c_str(), &buf) == 0) {
if (buf.f_type == NFS_SUPER_MAGIC) {
- scoped_ptr<base::Environment> env(base::Environment::Create());
+ scoped_ptr<Environment> env(Environment::Create());
const char* use_cache_env_var = "NSS_SDB_USE_CACHE";
if (!env->HasVar(use_cache_env_var))
env->SetVar(use_cache_env_var, "yes");
@@ -111,12 +111,19 @@ SECMODModule *InitDefaultRootCerts() {
// A singleton to initialize/deinitialize NSPR.
// Separate from the NSS singleton because we initialize NSPR on the UI thread.
+// Now that we're leaking the singleton, we could merge back with the NSS
+// singleton.
class NSPRInitSingleton {
- public:
+ private:
+ friend struct DefaultLazyInstanceTraits<NSPRInitSingleton>;
+
NSPRInitSingleton() {
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
}
+ // NOTE(willchan): We don't actually execute this code since we leak NSS to
+ // prevent non-joinable threads from using NSS after it's already been shut
+ // down.
~NSPRInitSingleton() {
PL_ArenaFinish();
PRStatus prstatus = PR_Cleanup();
@@ -126,14 +133,59 @@ class NSPRInitSingleton {
}
};
+LazyInstance<NSPRInitSingleton, LeakyLazyInstanceTraits<NSPRInitSingleton> >
+ g_nspr_singleton(LINKER_INITIALIZED);
+
class NSSInitSingleton {
public:
+#if defined(OS_CHROMEOS)
+ void OpenPersistentNSSDB() {
+ if (!chromeos_user_logged_in_) {
+ chromeos_user_logged_in_ = true;
+ real_db_slot_ = OpenUserDB(GetDefaultConfigDirectory(),
+ "Real NSS database");
+ }
+ }
+#endif // defined(OS_CHROMEOS)
+
+ bool OpenTestNSSDB(const FilePath& path, const char* description) {
+ test_db_slot_ = OpenUserDB(path, description);
+ return !!test_db_slot_;
+ }
+
+ void CloseTestNSSDB() {
+ if (test_db_slot_) {
+ SECStatus status = SECMOD_CloseUserDB(test_db_slot_);
+ if (status != SECSuccess)
+ LOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError();
+ PK11_FreeSlot(test_db_slot_);
+ test_db_slot_ = NULL;
+ }
+ }
+
+ PK11SlotInfo* GetDefaultKeySlot() {
+ if (test_db_slot_)
+ return PK11_ReferenceSlot(test_db_slot_);
+ if (real_db_slot_)
+ return PK11_ReferenceSlot(real_db_slot_);
+ return PK11_GetInternalKeySlot();
+ }
+
+#if defined(USE_NSS)
+ Lock* write_lock() {
+ return &write_lock_;
+ }
+#endif // defined(USE_NSS)
+
+ private:
+ friend struct DefaultLazyInstanceTraits<NSSInitSingleton>;
+
NSSInitSingleton()
: real_db_slot_(NULL),
test_db_slot_(NULL),
root_(NULL),
chromeos_user_logged_in_(false) {
- base::EnsureNSPRInit();
+ EnsureNSPRInit();
// We *must* have NSS >= 3.12.3. See bug 26448.
COMPILE_ASSERT(
@@ -207,15 +259,13 @@ class NSSInitSingleton {
PK11_FreeSlot(slot);
}
- // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011
- // is fixed, we will no longer need the lock. We should detect this and not
- // initialize a Lock here.
- write_lock_.reset(new Lock());
-
root_ = InitDefaultRootCerts();
#endif // !defined(USE_NSS)
}
+ // NOTE(willchan): We don't actually execute this code since we leak NSS to
+ // prevent non-joinable threads from using NSS after it's already been shut
+ // down.
~NSSInitSingleton() {
if (real_db_slot_) {
SECMOD_CloseUserDB(real_db_slot_);
@@ -238,46 +288,6 @@ class NSSInitSingleton {
}
}
-#if defined(OS_CHROMEOS)
- void OpenPersistentNSSDB() {
- if (!chromeos_user_logged_in_) {
- chromeos_user_logged_in_ = true;
- real_db_slot_ = OpenUserDB(GetDefaultConfigDirectory(),
- "Real NSS database");
- }
- }
-#endif // defined(OS_CHROMEOS)
-
- bool OpenTestNSSDB(const FilePath& path, const char* description) {
- test_db_slot_ = OpenUserDB(path, description);
- return !!test_db_slot_;
- }
-
- void CloseTestNSSDB() {
- if (test_db_slot_) {
- SECStatus status = SECMOD_CloseUserDB(test_db_slot_);
- if (status != SECSuccess)
- LOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError();
- PK11_FreeSlot(test_db_slot_);
- test_db_slot_ = NULL;
- }
- }
-
- PK11SlotInfo* GetDefaultKeySlot() {
- if (test_db_slot_)
- return PK11_ReferenceSlot(test_db_slot_);
- if (real_db_slot_)
- return PK11_ReferenceSlot(real_db_slot_);
- return PK11_GetInternalKeySlot();
- }
-
-#if defined(USE_NSS)
- Lock* write_lock() {
- return write_lock_.get();
- }
-#endif // defined(USE_NSS)
-
- private:
static PK11SlotInfo* OpenUserDB(const FilePath& path,
const char* description) {
const std::string modspec =
@@ -300,35 +310,40 @@ class NSSInitSingleton {
SECMODModule *root_;
bool chromeos_user_logged_in_;
#if defined(USE_NSS)
- scoped_ptr<Lock> write_lock_;
+ // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011
+ // is fixed, we will no longer need the lock.
+ Lock write_lock_;
#endif // defined(USE_NSS)
};
+LazyInstance<NSSInitSingleton, LeakyLazyInstanceTraits<NSSInitSingleton> >
+ g_nss_singleton(LINKER_INITIALIZED);
+
} // namespace
void EnsureNSPRInit() {
- Singleton<NSPRInitSingleton>::get();
+ g_nspr_singleton.Get();
}
void EnsureNSSInit() {
// Initializing SSL causes us to do blocking IO.
// Temporarily allow it until we fix
// http://code.google.com/p/chromium/issues/detail?id=59847
- base::ThreadRestrictions::ScopedAllowIO allow_io;
- Singleton<NSSInitSingleton>::get();
+ ThreadRestrictions::ScopedAllowIO allow_io;
+ g_nss_singleton.Get();
}
#if defined(USE_NSS)
bool OpenTestNSSDB(const FilePath& path, const char* description) {
- return Singleton<NSSInitSingleton>::get()->OpenTestNSSDB(path, description);
+ return g_nss_singleton.Get().OpenTestNSSDB(path, description);
}
void CloseTestNSSDB() {
- Singleton<NSSInitSingleton>::get()->CloseTestNSSDB();
+ g_nss_singleton.Get().CloseTestNSSDB();
}
Lock* GetNSSWriteLock() {
- return Singleton<NSSInitSingleton>::get()->write_lock();
+ return g_nss_singleton.Get().write_lock();
}
AutoNSSWriteLock::AutoNSSWriteLock() : lock_(GetNSSWriteLock()) {
@@ -347,7 +362,7 @@ AutoNSSWriteLock::~AutoNSSWriteLock() {
#if defined(OS_CHROMEOS)
void OpenPersistentNSSDB() {
- Singleton<NSSInitSingleton>::get()->OpenPersistentNSSDB();
+ g_nss_singleton.Get().OpenPersistentNSSDB();
}
#endif
@@ -357,7 +372,7 @@ Time PRTimeToBaseTime(PRTime prtime) {
PRExplodedTime prxtime;
PR_ExplodeTime(prtime, PR_GMTParameters, &prxtime);
- base::Time::Exploded exploded;
+ Time::Exploded exploded;
exploded.year = prxtime.tm_year;
exploded.month = prxtime.tm_month + 1;
exploded.day_of_week = prxtime.tm_wday;
@@ -371,7 +386,7 @@ Time PRTimeToBaseTime(PRTime prtime) {
}
PK11SlotInfo* GetDefaultNSSKeySlot() {
- return Singleton<NSSInitSingleton>::get()->GetDefaultKeySlot();
+ return g_nss_singleton.Get().GetDefaultKeySlot();
}
} // namespace base
diff --git a/base/openssl_util.cc b/base/openssl_util.cc
index 894c710..5cfc34a 100644
--- a/base/openssl_util.cc
+++ b/base/openssl_util.cc
@@ -22,6 +22,20 @@ unsigned long CurrentThreadId() {
// Singleton for initializing and cleaning up the OpenSSL library.
class OpenSSLInitSingleton {
+ public:
+ static OpenSSLInitSingleton* Get() {
+ // We allow the SSL environment to leak for multiple reasons:
+ // - it is used from a non-joinable worker thread that is not stopped on
+ // shutdown, hence may still be using OpenSSL library after the AtExit
+ // runner has completed.
+ // - There are other OpenSSL related singletons (e.g. the client socket
+ // context) who's cleanup depends on the global environment here, but
+ // we can't control the order the AtExit handlers will run in so
+ // allowing the global environment to leak at least ensures it is
+ // available for those other singletons to reliably cleanup.
+ return Singleton<OpenSSLInitSingleton,
+ LeakySingletonTraits<OpenSSLInitSingleton> >::get();
+ }
private:
friend struct DefaultSingletonTraits<OpenSSLInitSingleton>;
OpenSSLInitSingleton() {
@@ -43,8 +57,7 @@ class OpenSSLInitSingleton {
}
static void LockingCallback(int mode, int n, const char* file, int line) {
- Singleton<OpenSSLInitSingleton>::get()->OnLockingCallback(mode, n, file,
- line);
+ OpenSSLInitSingleton::Get()->OnLockingCallback(mode, n, file, line);
}
void OnLockingCallback(int mode, int n, const char* file, int line) {
@@ -64,16 +77,18 @@ class OpenSSLInitSingleton {
} // namespace
void EnsureOpenSSLInit() {
- (void)Singleton<OpenSSLInitSingleton>::get();
+ (void)OpenSSLInitSingleton::Get();
}
-void ClearOpenSSLERRStack() {
+void ClearOpenSSLERRStack(const tracked_objects::Location& location) {
if (logging::DEBUG_MODE && VLOG_IS_ON(1)) {
int error_num = ERR_get_error();
if (error_num == 0)
return;
- DVLOG(1) << "OpenSSL ERR_get_error stack:";
+ std::string message;
+ location.Write(true, true, &message);
+ DVLOG(1) << "OpenSSL ERR_get_error stack from " << message;
char buf[140];
do {
ERR_error_string_n(error_num, buf, arraysize(buf));
diff --git a/base/openssl_util.h b/base/openssl_util.h
index 1d290ae..60cb0b7 100644
--- a/base/openssl_util.h
+++ b/base/openssl_util.h
@@ -16,13 +16,22 @@ namespace base {
template <typename T, void (*destructor)(T*)>
class ScopedOpenSSL {
public:
- explicit ScopedOpenSSL(T* ptr_) : ptr_(ptr_) { }
+ ScopedOpenSSL() : ptr_(NULL) { }
+ explicit ScopedOpenSSL(T* ptr) : ptr_(ptr) { }
~ScopedOpenSSL() { if (ptr_) (*destructor)(ptr_); }
T* get() const { return ptr_; }
+ void reset(T* ptr) {
+ if (ptr != ptr_) {
+ if (ptr_) (*destructor)(ptr_);
+ ptr_ = ptr;
+ }
+ }
private:
T* ptr_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedOpenSSL);
};
// Provides a buffer of at least MIN_SIZE bytes, for use when calling OpenSSL's
@@ -72,8 +81,30 @@ class ScopedOpenSSLSafeSizeBuffer {
void EnsureOpenSSLInit();
// Drains the OpenSSL ERR_get_error stack. On a debug build the error codes
-// are send to VLOG(1), on a release build they are disregarded.
-void ClearOpenSSLERRStack();
+// are send to VLOG(1), on a release build they are disregarded. In most
+// cases you should pass FROM_HERE as the |location|.
+void ClearOpenSSLERRStack(const tracked_objects::Location& location);
+
+// Place an instance of this class on the call stack to automatically clear
+// the OpenSSL error stack on function exit.
+class OpenSSLErrStackTracer {
+ public:
+ // Pass FROM_HERE as |location|, to help track the source of OpenSSL error
+ // messages. Note any diagnostic emitted will be tagged with the location of
+ // the constructor call as it's not possible to trace a destructor's callsite.
+ explicit OpenSSLErrStackTracer(const tracked_objects::Location& location)
+ : location_(location) {
+ EnsureOpenSSLInit();
+ }
+ ~OpenSSLErrStackTracer() {
+ ClearOpenSSLERRStack(location_);
+ }
+
+ private:
+ const tracked_objects::Location location_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(OpenSSLErrStackTracer);
+};
} // namespace base
diff --git a/base/path_service.cc b/base/path_service.cc
index 9eed56d..8660c42 100644
--- a/base/path_service.cc
+++ b/base/path_service.cc
@@ -215,14 +215,6 @@ bool PathService::Get(int key, std::wstring* result) {
}
#endif
-// TODO(evan): remove me -- see comments in header.
-bool PathService::IsOverridden(int key) {
- PathData* path_data = GetPathData();
- DCHECK(path_data);
- AutoLock scoped_lock(path_data->lock);
- return path_data->overrides.find(key) != path_data->overrides.end();
-}
-
bool PathService::Override(int key, const FilePath& path) {
PathData* path_data = GetPathData();
DCHECK(path_data);
diff --git a/base/path_service.h b/base/path_service.h
index 6873e1f..4d99cdc 100644
--- a/base/path_service.h
+++ b/base/path_service.h
@@ -45,11 +45,6 @@ class PathService {
// over the lifetime of the app, so this method should be used with caution.
static bool Override(int key, const FilePath& path);
- // Return whether a path was overridden.
- // TODO(evan): temporarily restoring this to quick-fix a regression.
- // Remove me again once it's fixed properly.
- static bool IsOverridden(int key);
-
// To extend the set of supported keys, you can register a path provider,
// which is just a function mirroring PathService::Get. The ProviderFunc
// returns false if it cannot provide a non-empty path for the given key.
diff --git a/base/path_service_unittest.cc b/base/path_service_unittest.cc
index c65f7a5..26998de 100644
--- a/base/path_service_unittest.cc
+++ b/base/path_service_unittest.cc
@@ -22,9 +22,9 @@ bool ReturnsValidPath(int dir_type) {
FilePath path;
bool result = PathService::Get(dir_type, &path);
#if defined(OS_POSIX)
- // If chromium has never been started on this account, the cache path will not
+ // If chromium has never been started on this account, the cache path may not
// exist.
- if (dir_type == base::DIR_USER_CACHE)
+ if (dir_type == base::DIR_CACHE)
return result && !path.value().empty();
#endif
return result && !path.value().empty() && file_util::PathExists(path);
diff --git a/base/platform_file.h b/base/platform_file.h
index b350f8c..1ca9868 100644
--- a/base/platform_file.h
+++ b/base/platform_file.h
@@ -77,6 +77,9 @@ struct PlatformFileInfo {
// True if the file corresponds to a directory.
bool is_directory;
+ // True if the file corresponds to a symbolic link.
+ bool is_symbolic_link;
+
// The last modified time of a file.
base::Time last_modified;
diff --git a/base/platform_file_posix.cc b/base/platform_file_posix.cc
index 8af078b..901c298 100644
--- a/base/platform_file_posix.cc
+++ b/base/platform_file_posix.cc
@@ -193,6 +193,7 @@ bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {
return false;
info->is_directory = S_ISDIR(file_info.st_mode);
+ info->is_symbolic_link = S_ISLNK(file_info.st_mode);
info->size = file_info.st_size;
info->last_modified = base::Time::FromTimeT(file_info.st_mtime);
info->last_accessed = base::Time::FromTimeT(file_info.st_atime);
diff --git a/base/platform_file_unittest.cc b/base/platform_file_unittest.cc
index 90fca1a..e54ab61 100644
--- a/base/platform_file_unittest.cc
+++ b/base/platform_file_unittest.cc
@@ -269,6 +269,7 @@ TEST(PlatformFile, TouchGetInfoPlatformFile) {
base::Time now = base::Time::Now() + base::TimeDelta::FromSeconds(2);
EXPECT_EQ(0, info.size);
EXPECT_FALSE(info.is_directory);
+ EXPECT_FALSE(info.is_symbolic_link);
EXPECT_LE(info.last_accessed.ToInternalValue(), now.ToInternalValue());
EXPECT_LE(info.last_modified.ToInternalValue(), now.ToInternalValue());
EXPECT_LE(info.creation_time.ToInternalValue(), now.ToInternalValue());
@@ -296,6 +297,7 @@ TEST(PlatformFile, TouchGetInfoPlatformFile) {
EXPECT_TRUE(base::GetPlatformFileInfo(file, &info));
EXPECT_EQ(info.size, kTestDataSize);
EXPECT_FALSE(info.is_directory);
+ EXPECT_FALSE(info.is_symbolic_link);
// ext2/ext3 and HPS/HPS+ seem to have a timestamp granularity of 1s.
#if defined(OS_POSIX)
diff --git a/base/platform_file_win.cc b/base/platform_file_win.cc
index 34d8e45..1398397 100644
--- a/base/platform_file_win.cc
+++ b/base/platform_file_win.cc
@@ -214,6 +214,7 @@ bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {
info->size = size.QuadPart;
info->is_directory =
file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0;
+ info->is_symbolic_link = false; // Windows doesn't have symbolic links.
info->last_modified = base::Time::FromFileTime(file_info.ftLastWriteTime);
info->last_accessed = base::Time::FromFileTime(file_info.ftLastAccessTime);
info->creation_time = base::Time::FromFileTime(file_info.ftCreationTime);
diff --git a/base/platform_thread.h b/base/platform_thread.h
index e330422..43bf298 100644
--- a/base/platform_thread.h
+++ b/base/platform_thread.h
@@ -34,9 +34,19 @@ typedef pid_t PlatformThreadId;
#endif
#endif
+const PlatformThreadId kInvalidThreadId = 0;
+
// A namespace for low-level thread functions.
class PlatformThread {
public:
+ // Implement this interface to run code on a background thread. Your
+ // ThreadMain method will be called on the newly created thread.
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+ virtual void ThreadMain() = 0;
+ };
+
// Gets the current thread id, which may be useful for logging purposes.
static PlatformThreadId CurrentId();
@@ -49,14 +59,6 @@ class PlatformThread {
// Sets the thread name visible to a debugger. This has no effect otherwise.
static void SetName(const char* name);
- // Implement this interface to run code on a background thread. Your
- // ThreadMain method will be called on the newly created thread.
- class Delegate {
- public:
- virtual ~Delegate() {}
- virtual void ThreadMain() = 0;
- };
-
// Creates a new thread. The |stack_size| parameter can be 0 to indicate
// that the default stack size should be used. Upon success,
// |*thread_handle| will be assigned a handle to the newly created thread,
diff --git a/base/platform_thread_posix.cc b/base/platform_thread_posix.cc
index 66f3928..e442e9c 100644
--- a/base/platform_thread_posix.cc
+++ b/base/platform_thread_posix.cc
@@ -7,6 +7,11 @@
#include <errno.h>
#include <sched.h>
+#include "base/logging.h"
+#include "base/safe_strerror_posix.h"
+#include "base/scoped_ptr.h"
+#include "base/thread_restrictions.h"
+
#if defined(OS_MACOSX)
#include <mach/mach.h>
#include <sys/resource.h>
@@ -24,18 +29,27 @@
#include <sys/nacl_syscalls.h>
#endif
-#include "base/logging.h"
-#include "base/safe_strerror_posix.h"
-
#if defined(OS_MACOSX)
namespace base {
void InitThreading();
} // namespace base
#endif
-static void* ThreadFunc(void* closure) {
- PlatformThread::Delegate* delegate =
- static_cast<PlatformThread::Delegate*>(closure);
+namespace {
+
+struct ThreadParams {
+ PlatformThread::Delegate* delegate;
+ bool joinable;
+};
+
+} // namespace
+
+static void* ThreadFunc(void* params) {
+ ThreadParams* thread_params = static_cast<ThreadParams*>(params);
+ PlatformThread::Delegate* delegate = thread_params->delegate;
+ if (!thread_params->joinable)
+ base::ThreadRestrictions::SetSingletonAllowed(false);
+ delete thread_params;
delegate->ThreadMain();
return NULL;
}
@@ -174,9 +188,14 @@ bool CreateThread(size_t stack_size, bool joinable,
if (stack_size > 0)
pthread_attr_setstacksize(&attributes, stack_size);
- success = !pthread_create(thread_handle, &attributes, ThreadFunc, delegate);
+ ThreadParams* params = new ThreadParams;
+ params->delegate = delegate;
+ params->joinable = joinable;
+ success = !pthread_create(thread_handle, &attributes, ThreadFunc, params);
pthread_attr_destroy(&attributes);
+ if (!success)
+ delete params;
return success;
}
diff --git a/base/platform_thread_win.cc b/base/platform_thread_win.cc
index a4a1b52..e5afc52 100644
--- a/base/platform_thread_win.cc
+++ b/base/platform_thread_win.cc
@@ -5,6 +5,7 @@
#include "base/platform_thread.h"
#include "base/logging.h"
+#include "base/thread_restrictions.h"
#include "base/win/windows_version.h"
namespace {
@@ -20,13 +21,58 @@ typedef struct tagTHREADNAME_INFO {
DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;
-DWORD __stdcall ThreadFunc(void* closure) {
- PlatformThread::Delegate* delegate =
- static_cast<PlatformThread::Delegate*>(closure);
+struct ThreadParams {
+ PlatformThread::Delegate* delegate;
+ bool joinable;
+};
+
+DWORD __stdcall ThreadFunc(void* params) {
+ ThreadParams* thread_params = static_cast<ThreadParams*>(params);
+ PlatformThread::Delegate* delegate = thread_params->delegate;
+ if (!thread_params->joinable)
+ base::ThreadRestrictions::SetSingletonAllowed(false);
+ delete thread_params;
delegate->ThreadMain();
return NULL;
}
+// CreateThreadInternal() matches PlatformThread::Create(), except that
+// |out_thread_handle| may be NULL, in which case a non-joinable thread is
+// created.
+bool CreateThreadInternal(size_t stack_size,
+ PlatformThread::Delegate* delegate,
+ PlatformThreadHandle* out_thread_handle) {
+ PlatformThreadHandle thread_handle;
+ unsigned int flags = 0;
+ if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) {
+ flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
+ } else {
+ stack_size = 0;
+ }
+
+ ThreadParams* params = new ThreadParams;
+ params->delegate = delegate;
+ params->joinable = out_thread_handle != NULL;
+
+ // Using CreateThread here vs _beginthreadex makes thread creation a bit
+ // faster and doesn't require the loader lock to be available. Our code will
+ // have to work running on CreateThread() threads anyway, since we run code
+ // on the Windows thread pool, etc. For some background on the difference:
+ // http://www.microsoft.com/msj/1099/win32/win321099.aspx
+ thread_handle = CreateThread(
+ NULL, stack_size, ThreadFunc, params, flags, NULL);
+ if (!thread_handle) {
+ delete params;
+ return false;
+ }
+
+ if (out_thread_handle)
+ *out_thread_handle = thread_handle;
+ else
+ CloseHandle(thread_handle);
+ return true;
+}
+
} // namespace
// static
@@ -67,29 +113,13 @@ void PlatformThread::SetName(const char* name) {
// static
bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
PlatformThreadHandle* thread_handle) {
- unsigned int flags = 0;
- if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) {
- flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
- } else {
- stack_size = 0;
- }
-
- // Using CreateThread here vs _beginthreadex makes thread creation a bit
- // faster and doesn't require the loader lock to be available. Our code will
- // have to work running on CreateThread() threads anyway, since we run code
- // on the Windows thread pool, etc. For some background on the difference:
- // http://www.microsoft.com/msj/1099/win32/win321099.aspx
- *thread_handle = CreateThread(
- NULL, stack_size, ThreadFunc, delegate, flags, NULL);
- return *thread_handle != NULL;
+ DCHECK(thread_handle);
+ return CreateThreadInternal(stack_size, delegate, thread_handle);
}
// static
bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
- PlatformThreadHandle thread_handle;
- bool result = Create(stack_size, delegate, &thread_handle);
- CloseHandle(thread_handle);
- return result;
+ return CreateThreadInternal(stack_size, delegate, NULL);
}
// static
diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc
index 07e3125..8a97dcd 100644
--- a/base/process_util_posix.cc
+++ b/base/process_util_posix.cc
@@ -101,9 +101,52 @@ int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds,
return status;
}
-void StackDumpSignalHandler(int signal) {
+void StackDumpSignalHandler(int signal, siginfo_t* info, ucontext_t* context) {
LOG(ERROR) << "Received signal " << signal;
debug::StackTrace().PrintBacktrace();
+
+ // TODO(shess): Port to Linux.
+#if defined(OS_MACOSX)
+ // TODO(shess): Port to 64-bit.
+#if ARCH_CPU_32_BITS
+ char buf[1024];
+ size_t len;
+
+ // NOTE: Even |snprintf()| is not on the approved list for signal
+ // handlers, but buffered I/O is definitely not on the list due to
+ // potential for |malloc()|.
+ len = static_cast<size_t>(
+ snprintf(buf, sizeof(buf),
+ "ax: %x, bx: %x, cx: %x, dx: %x\n",
+ context->uc_mcontext->__ss.__eax,
+ context->uc_mcontext->__ss.__ebx,
+ context->uc_mcontext->__ss.__ecx,
+ context->uc_mcontext->__ss.__edx));
+ write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
+
+ len = static_cast<size_t>(
+ snprintf(buf, sizeof(buf),
+ "di: %x, si: %x, bp: %x, sp: %x, ss: %x, flags: %x\n",
+ context->uc_mcontext->__ss.__edi,
+ context->uc_mcontext->__ss.__esi,
+ context->uc_mcontext->__ss.__ebp,
+ context->uc_mcontext->__ss.__esp,
+ context->uc_mcontext->__ss.__ss,
+ context->uc_mcontext->__ss.__eflags));
+ write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
+
+ len = static_cast<size_t>(
+ snprintf(buf, sizeof(buf),
+ "ip: %x, cs: %x, ds: %x, es: %x, fs: %x, gs: %x\n",
+ context->uc_mcontext->__ss.__eip,
+ context->uc_mcontext->__ss.__cs,
+ context->uc_mcontext->__ss.__ds,
+ context->uc_mcontext->__ss.__es,
+ context->uc_mcontext->__ss.__fs,
+ context->uc_mcontext->__ss.__gs));
+ write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
+#endif // ARCH_CPU_32_BITS
+#endif // defined(OS_MACOSX)
_exit(1);
}
@@ -571,12 +614,13 @@ bool EnableInProcessStackDumping() {
sigemptyset(&action.sa_mask);
bool success = (sigaction(SIGPIPE, &action, NULL) == 0);
- success &= (signal(SIGILL, &StackDumpSignalHandler) != SIG_ERR);
- success &= (signal(SIGABRT, &StackDumpSignalHandler) != SIG_ERR);
- success &= (signal(SIGFPE, &StackDumpSignalHandler) != SIG_ERR);
- success &= (signal(SIGBUS, &StackDumpSignalHandler) != SIG_ERR);
- success &= (signal(SIGSEGV, &StackDumpSignalHandler) != SIG_ERR);
- success &= (signal(SIGSYS, &StackDumpSignalHandler) != SIG_ERR);
+ sig_t handler = reinterpret_cast<sig_t>(&StackDumpSignalHandler);
+ success &= (signal(SIGILL, handler) != SIG_ERR);
+ success &= (signal(SIGABRT, handler) != SIG_ERR);
+ success &= (signal(SIGFPE, handler) != SIG_ERR);
+ success &= (signal(SIGBUS, handler) != SIG_ERR);
+ success &= (signal(SIGSEGV, handler) != SIG_ERR);
+ success &= (signal(SIGSYS, handler) != SIG_ERR);
return success;
}
diff --git a/base/process_util_unittest.cc b/base/process_util_unittest.cc
index e92459c..34c444c 100644
--- a/base/process_util_unittest.cc
+++ b/base/process_util_unittest.cc
@@ -203,7 +203,7 @@ TEST_F(ProcessUtilTest, GetAppOutput) {
FilePath python_runtime;
ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &python_runtime));
python_runtime = python_runtime.Append(FILE_PATH_LITERAL("third_party"))
- .Append(FILE_PATH_LITERAL("python_24"))
+ .Append(FILE_PATH_LITERAL("python_26"))
.Append(FILE_PATH_LITERAL("python.exe"));
CommandLine cmd_line(python_runtime);
diff --git a/base/scoped_temp_dir.cc b/base/scoped_temp_dir.cc
index 5cd13b4..000ed0a 100644
--- a/base/scoped_temp_dir.cc
+++ b/base/scoped_temp_dir.cc
@@ -11,7 +11,8 @@ ScopedTempDir::ScopedTempDir() {
}
ScopedTempDir::~ScopedTempDir() {
- Delete();
+ if (!path_.empty() && !Delete())
+ LOG(WARNING) << "Could not delete temp dir in dtor.";
}
bool ScopedTempDir::CreateUniqueTempDir() {
@@ -57,10 +58,19 @@ bool ScopedTempDir::Set(const FilePath& path) {
return true;
}
-void ScopedTempDir::Delete() {
- if (!path_.empty() && !file_util::Delete(path_, true))
+bool ScopedTempDir::Delete() {
+ if (path_.empty())
+ return false;
+
+ bool ret = file_util::Delete(path_, true);
+ if (ret) {
+ // We only clear the path if deleted the directory.
+ path_.clear();
+ } else {
LOG(ERROR) << "ScopedTempDir unable to delete " << path_.value();
- path_.clear();
+ }
+
+ return ret;
}
FilePath ScopedTempDir::Take() {
diff --git a/base/scoped_temp_dir.h b/base/scoped_temp_dir.h
index 6845562..f44bcca 100644
--- a/base/scoped_temp_dir.h
+++ b/base/scoped_temp_dir.h
@@ -38,7 +38,7 @@ class ScopedTempDir {
bool Set(const FilePath& path);
// Deletes the temporary directory wrapped by this object.
- void Delete();
+ bool Delete();
// Caller takes ownership of the temporary directory so it won't be destroyed
// when this object goes out of scope.
diff --git a/base/scoped_temp_dir_unittest.cc b/base/scoped_temp_dir_unittest.cc
index cf5fed3..039a1ed 100644
--- a/base/scoped_temp_dir_unittest.cc
+++ b/base/scoped_temp_dir_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/file_util.h"
+#include "base/platform_file.h"
#include "base/scoped_temp_dir.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -78,7 +79,7 @@ TEST(ScopedTempDir, MultipleInvocations) {
ScopedTempDir dir;
EXPECT_TRUE(dir.CreateUniqueTempDir());
EXPECT_FALSE(dir.CreateUniqueTempDir());
- dir.Delete();
+ EXPECT_TRUE(dir.Delete());
EXPECT_TRUE(dir.CreateUniqueTempDir());
EXPECT_FALSE(dir.CreateUniqueTempDir());
ScopedTempDir other_dir;
@@ -87,3 +88,23 @@ TEST(ScopedTempDir, MultipleInvocations) {
EXPECT_FALSE(dir.CreateUniqueTempDir());
EXPECT_FALSE(other_dir.CreateUniqueTempDir());
}
+
+#if defined(OS_WIN)
+TEST(ScopedTempDir, LockedTempDir) {
+ ScopedTempDir dir;
+ EXPECT_TRUE(dir.CreateUniqueTempDir());
+ int file_flags = base::PLATFORM_FILE_CREATE_ALWAYS |
+ base::PLATFORM_FILE_WRITE;
+ base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
+ FilePath file_path(dir.path().Append(FILE_PATH_LITERAL("temp")));
+ base::PlatformFile file = base::CreatePlatformFile(file_path, file_flags,
+ NULL, &error_code);
+ EXPECT_NE(base::kInvalidPlatformFileValue, file);
+ EXPECT_EQ(base::PLATFORM_FILE_OK, error_code);
+ EXPECT_FALSE(dir.Delete()); // We should not be able to delete.
+ EXPECT_FALSE(dir.path().empty()); // We should still have a valid path.
+ EXPECT_TRUE(base::ClosePlatformFile(file));
+ // Now, we should be able to delete.
+ EXPECT_TRUE(dir.Delete());
+}
+#endif // defined(OS_WIN)
diff --git a/base/simple_thread_unittest.cc b/base/simple_thread_unittest.cc
index 85995c2..208290a 100644
--- a/base/simple_thread_unittest.cc
+++ b/base/simple_thread_unittest.cc
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "base/atomic_sequence_num.h"
-#include "base/lock.h"
#include "base/simple_thread.h"
#include "base/string_number_conversions.h"
#include "base/waitable_event.h"
diff --git a/base/singleton.h b/base/singleton.h
index 564b686..8435c43 100644
--- a/base/singleton.h
+++ b/base/singleton.h
@@ -8,7 +8,9 @@
#include "base/at_exit.h"
#include "base/atomicops.h"
+#include "base/platform_thread.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/thread_restrictions.h"
// Default traits for Singleton<Type>. Calls operator new and operator delete on
// the object. Registers automatic deletion at process exit.
@@ -30,6 +32,11 @@ struct DefaultSingletonTraits {
// Set to true to automatically register deletion of the object on process
// exit. See below for the required call that makes this happen.
static const bool kRegisterAtExit = true;
+
+ // Set to false to disallow access on a non-joinable thread. This is
+ // different from kRegisterAtExit because StaticMemorySingletonTraits allows
+ // access on non-joinable threads, and gracefully handles this.
+ static const bool kAllowedToAccessOnNonjoinableThread = false;
};
@@ -39,6 +46,7 @@ struct DefaultSingletonTraits {
template<typename Type>
struct LeakySingletonTraits : public DefaultSingletonTraits<Type> {
static const bool kRegisterAtExit = false;
+ static const bool kAllowedToAccessOnNonjoinableThread = true;
};
@@ -85,6 +93,7 @@ struct StaticMemorySingletonTraits {
}
static const bool kRegisterAtExit = true;
+ static const bool kAllowedToAccessOnNonjoinableThread = true;
// Exposed for unittesting.
static void Resurrect() {
@@ -176,6 +185,9 @@ class Singleton {
// Return a pointer to the one true instance of the class.
static Type* get() {
+ if (!Traits::kAllowedToAccessOnNonjoinableThread)
+ base::ThreadRestrictions::AssertSingletonAllowed();
+
// Our AtomicWord doubles as a spinlock, where a value of
// kBeingCreatedMarker means the spinlock is being held for creation.
static const base::subtle::AtomicWord kBeingCreatedMarker = 1;
diff --git a/base/task.h b/base/task.h
index 28d15fc..b21ccd8 100644
--- a/base/task.h
+++ b/base/task.h
@@ -274,7 +274,7 @@ struct RunnableMethodTraits {
// };
// } // namespace foo
//
-// DISABLE_RUNNABLE_METHOD_REFCOUNT(foo::Bar)
+// DISABLE_RUNNABLE_METHOD_REFCOUNT(foo::Bar);
//
// This is different from DISALLOW_COPY_AND_ASSIGN which is declared inside the
// class.
diff --git a/base/test/test_file_util.h b/base/test/test_file_util.h
index 362c525..2de74e7 100644
--- a/base/test/test_file_util.h
+++ b/base/test/test_file_util.h
@@ -30,6 +30,14 @@ bool EvictFileFromSystemCache(const FilePath& file);
bool CopyRecursiveDirNoCache(const FilePath& source_dir,
const FilePath& dest_dir);
+#if defined(OS_WIN)
+// Returns true if the volume supports Alternate Data Streams.
+bool VolumeSupportsADS(const FilePath& path);
+
+// Returns true if the ZoneIdentifier is correctly set to "Internet" (3).
+bool HasInternetZoneIdentifier(const FilePath& full_path);
+#endif // defined(OS_WIN)
+
} // namespace file_util
#endif // BASE_TEST_TEST_FILE_UTIL_H_
diff --git a/base/test/test_file_util_win.cc b/base/test/test_file_util_win.cc
index 8e5b37b..fc3d018 100644
--- a/base/test/test_file_util_win.cc
+++ b/base/test/test_file_util_win.cc
@@ -4,6 +4,7 @@
#include "base/test/test_file_util.h"
+#include <shlwapi.h>
#include <windows.h>
#include <vector>
@@ -173,4 +174,61 @@ bool CopyRecursiveDirNoCache(const FilePath& source_dir,
return true;
}
+// Checks if the volume supports Alternate Data Streams. This is required for
+// the Zone Identifier implementation.
+bool VolumeSupportsADS(const FilePath& path) {
+ wchar_t drive[MAX_PATH] = {0};
+ wcscpy_s(drive, MAX_PATH, path.value().c_str());
+
+ if (!PathStripToRootW(drive))
+ return false;
+
+ DWORD fs_flags = 0;
+ if (!GetVolumeInformationW(drive, NULL, 0, 0, NULL, &fs_flags, NULL, 0))
+ return false;
+
+ if (fs_flags & FILE_NAMED_STREAMS)
+ return true;
+
+ return false;
+}
+
+// Return whether the ZoneIdentifier is correctly set to "Internet" (3)
+bool HasInternetZoneIdentifier(const FilePath& full_path) {
+ std::wstring path = full_path.value() + L":Zone.Identifier";
+
+ // This polling and sleeping here is a very bad pattern. But due to how
+ // Windows file semantics work it's really hard to do it other way. We are
+ // reading a file written by a different process, using a different handle.
+ // Windows does not guarantee that we will get the same contents even after
+ // the other process closes the handle, flushes the buffers, etc.
+ for (int i = 0; i < 20; i++) {
+ PlatformThread::Sleep(1000);
+
+ const DWORD kShare = FILE_SHARE_READ |
+ FILE_SHARE_WRITE |
+ FILE_SHARE_DELETE;
+ HANDLE file = CreateFile(path.c_str(), GENERIC_READ, kShare, NULL,
+ OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (file == INVALID_HANDLE_VALUE)
+ continue;
+
+ char buffer[100] = {0};
+ DWORD read = 0;
+ BOOL read_result = ::ReadFile(file, buffer, 100, &read, NULL);
+ CloseHandle(file);
+
+ if (!read_result)
+ continue;
+
+ const char kIdentifier[] = "[ZoneTransfer]\nZoneId=3";
+ if (read != arraysize(kIdentifier))
+ continue;
+
+ if (strcmp(kIdentifier, buffer) == 0)
+ return true;
+ }
+ return false;
+}
+
} // namespace file_util
diff --git a/base/third_party/dmg_fp/dtoa_wrapper.cc b/base/third_party/dmg_fp/dtoa_wrapper.cc
new file mode 100644
index 0000000..fbbaf80
--- /dev/null
+++ b/base/third_party/dmg_fp/dtoa_wrapper.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The purpose of this file is to supply the macro definintions necessary
+// to make third_party/dmg_fp/dtoa.cc threadsafe.
+#include "base/lock.h"
+#include "base/logging.h"
+
+// We need two locks because they're sometimes grabbed at the same time.
+// A single lock would lead to an attempted recursive grab.
+static Lock dtoa_locks[2];
+
+/*
+ * This define and the code below is to trigger thread-safe behavior
+ * in dtoa.cc, per this comment from the file:
+ *
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ * multiple threads. In this case, you must provide (or suitably
+ * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed
+ * in pow5mult, ensures lazy evaluation of only one copy of high
+ * powers of 5; omitting this lock would introduce a small
+ * probability of wasting memory, but would otherwise be harmless.)
+ * You must also invoke freedtoa(s) to free the value s returned by
+ * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined.
+ */
+#define MULTIPLE_THREADS
+
+inline static void ACQUIRE_DTOA_LOCK(size_t n) {
+ DCHECK(n < arraysize(dtoa_locks));
+ dtoa_locks[n].Acquire();
+}
+
+inline static void FREE_DTOA_LOCK(size_t n) {
+ DCHECK(n < arraysize(dtoa_locks));
+ dtoa_locks[n].Release();
+}
+
+#include "base/third_party/dmg_fp/dtoa.cc"
diff --git a/base/third_party/icu/icu_utf.h b/base/third_party/icu/icu_utf.h
index 43b4967..9cb1247 100644
--- a/base/third_party/icu/icu_utf.h
+++ b/base/third_party/icu/icu_utf.h
@@ -79,7 +79,7 @@ typedef int8 UBool;
((uint32)(c)<0xd800 || \
((uint32)(c)>0xdfff && \
(uint32)(c)<=0x10ffff && \
- !U_IS_UNICODE_NONCHAR(c)))
+ !CBU_IS_UNICODE_NONCHAR(c)))
/**
* Is this code point a surrogate (U+d800..U+dfff)?
diff --git a/base/thread.cc b/base/thread.cc
index 41d78f0..bc715f0 100644
--- a/base/thread.cc
+++ b/base/thread.cc
@@ -40,7 +40,7 @@ Thread::Thread(const char* name)
startup_data_(NULL),
thread_(0),
message_loop_(NULL),
- thread_id_(0),
+ thread_id_(kInvalidThreadId),
name_(name) {
}
@@ -174,7 +174,7 @@ void Thread::ThreadMain() {
message_loop_proxy_ = NULL;
}
CleanUpAfterMessageLoopDestruction();
- thread_id_ = 0;
+ thread_id_ = kInvalidThreadId;
}
} // namespace base
diff --git a/base/thread.h b/base/thread.h
index 572eb8a..fc542f0 100644
--- a/base/thread.h
+++ b/base/thread.h
@@ -126,8 +126,8 @@ class Thread : PlatformThread::Delegate {
PlatformThreadId thread_id() const { return thread_id_; }
// Returns true if the thread has been started, and not yet stopped.
- // When a thread is running, the thread_id_ is non-zero.
- bool IsRunning() const { return thread_id_ != 0; }
+ // When a thread is running, |thread_id_| is a valid id.
+ bool IsRunning() const { return thread_id_ != kInvalidThreadId; }
protected:
// Called just prior to starting the message loop
diff --git a/base/thread_checker.cc b/base/thread_checker.cc
index 394a90a..52f9847 100644
--- a/base/thread_checker.cc
+++ b/base/thread_checker.cc
@@ -7,7 +7,7 @@
// This code is only done in debug builds.
#ifndef NDEBUG
-ThreadChecker::ThreadChecker() {
+ThreadChecker::ThreadChecker() : valid_thread_id_(kInvalidThreadId) {
EnsureThreadIdAssigned();
}
@@ -15,17 +15,20 @@ ThreadChecker::~ThreadChecker() {}
bool ThreadChecker::CalledOnValidThread() const {
EnsureThreadIdAssigned();
- return *valid_thread_id_ == PlatformThread::CurrentId();
+ AutoLock auto_lock(lock_);
+ return valid_thread_id_ == PlatformThread::CurrentId();
}
void ThreadChecker::DetachFromThread() {
- valid_thread_id_.reset();
+ AutoLock auto_lock(lock_);
+ valid_thread_id_ = kInvalidThreadId;
}
void ThreadChecker::EnsureThreadIdAssigned() const {
- if (valid_thread_id_.get())
+ AutoLock auto_lock(lock_);
+ if (valid_thread_id_ != kInvalidThreadId)
return;
- valid_thread_id_.reset(new PlatformThreadId(PlatformThread::CurrentId()));
+ valid_thread_id_ = PlatformThread::CurrentId();
}
#endif // NDEBUG
diff --git a/base/thread_checker.h b/base/thread_checker.h
index 5d5445e..c09bcbe 100644
--- a/base/thread_checker.h
+++ b/base/thread_checker.h
@@ -6,8 +6,10 @@
#define BASE_THREAD_CHECKER_H_
#pragma once
+#ifndef NDEBUG
+#include "base/lock.h"
#include "base/platform_thread.h"
-#include "base/scoped_ptr.h"
+#endif // NDEBUG
// Before using this class, please consider using NonThreadSafe as it
// makes it much easier to determine the nature of your class.
@@ -47,8 +49,10 @@ class ThreadChecker {
private:
void EnsureThreadIdAssigned() const;
+ mutable Lock lock_;
// This is mutable so that CalledOnValidThread can set it.
- mutable scoped_ptr<PlatformThreadId> valid_thread_id_;
+ // It's guarded by |lock_|.
+ mutable PlatformThreadId valid_thread_id_;
};
#else
// Do nothing in release mode.
diff --git a/base/thread_restrictions.cc b/base/thread_restrictions.cc
index 270d663..6767d80 100644
--- a/base/thread_restrictions.cc
+++ b/base/thread_restrictions.cc
@@ -18,13 +18,16 @@ namespace {
LazyInstance<ThreadLocalBoolean, LeakyLazyInstanceTraits<ThreadLocalBoolean> >
g_io_disallowed(LINKER_INITIALIZED);
+LazyInstance<ThreadLocalBoolean, LeakyLazyInstanceTraits<ThreadLocalBoolean> >
+ g_singleton_disallowed(LINKER_INITIALIZED);
+
} // anonymous namespace
// static
bool ThreadRestrictions::SetIOAllowed(bool allowed) {
- bool previous_allowed = g_io_disallowed.Get().Get();
+ bool previous_disallowed = g_io_disallowed.Get().Get();
g_io_disallowed.Get().Set(!allowed);
- return !previous_allowed;
+ return !previous_disallowed;
}
// static
@@ -39,6 +42,22 @@ void ThreadRestrictions::AssertIOAllowed() {
}
}
+bool ThreadRestrictions::SetSingletonAllowed(bool allowed) {
+ bool previous_disallowed = g_singleton_disallowed.Get().Get();
+ g_singleton_disallowed.Get().Set(!allowed);
+ return !previous_disallowed;
+}
+
+// static
+void ThreadRestrictions::AssertSingletonAllowed() {
+ if (g_singleton_disallowed.Get().Get()) {
+ LOG(FATAL) << "LazyInstance/Singleton is not allowed to be used on this "
+ << "thread. Most likely it's because this thread is not "
+ << "joinable, so AtExitManager may have deleted the object "
+ << "on shutdown, leading to a potential shutdown crash.";
+ }
+}
+
} // namespace base
#endif // NDEBUG
diff --git a/base/thread_restrictions.h b/base/thread_restrictions.h
index a10aaec..51e5a15 100644
--- a/base/thread_restrictions.h
+++ b/base/thread_restrictions.h
@@ -9,8 +9,13 @@
namespace base {
-// ThreadRestrictions helps protect threads that should not block from
-// making blocking calls. It works like this:
+// Certain behavior is disallowed on certain threads. ThreadRestrictions helps
+// enforce these rules. Examples of such rules:
+//
+// * Do not do blocking IO (makes the thread janky)
+// * Do not access Singleton/LazyInstance (may lead to shutdown crashes)
+//
+// Here's more about how the protection works:
//
// 1) If a thread should not be allowed to make IO calls, mark it:
// base::ThreadRestrictions::SetIOAllowed(false);
@@ -45,6 +50,20 @@ class ThreadRestrictions {
DISALLOW_COPY_AND_ASSIGN(ScopedAllowIO);
};
+ // Constructing a ScopedAllowSingleton temporarily allows accessing for the
+ // current thread. Doing this is almost always incorrect.
+ class ScopedAllowSingleton {
+ public:
+ ScopedAllowSingleton() { previous_value_ = SetSingletonAllowed(true); }
+ ~ScopedAllowSingleton() { SetSingletonAllowed(previous_value_); }
+ private:
+ // Whether singleton use is allowed when the ScopedAllowSingleton was
+ // constructed.
+ bool previous_value_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedAllowSingleton);
+ };
+
#ifndef NDEBUG
// Set whether the current thread to make IO calls.
// Threads start out in the *allowed* state.
@@ -55,15 +74,25 @@ class ThreadRestrictions {
// and DCHECK if not. See the block comment above the class for
// a discussion of where to add these checks.
static void AssertIOAllowed();
+
+ // Set whether the current thread can use singletons. Returns the previous
+ // value.
+ static bool SetSingletonAllowed(bool allowed);
+
+ // Check whether the current thread is allowed to use singletons (Singleton /
+ // LazyInstance). DCHECKs if not.
+ static void AssertSingletonAllowed();
#else
// In Release builds, inline the empty definitions of these functions so
// that they can be compiled out.
static bool SetIOAllowed(bool allowed) { return true; }
static void AssertIOAllowed() {}
+ static bool SetSingletonAllowed(bool allowed) { return true; }
+ static void AssertSingletonAllowed() {}
#endif
private:
- ThreadRestrictions(); // class for namespacing only
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ThreadRestrictions);
};
} // namespace base
diff --git a/base/thread_unittest.cc b/base/thread_unittest.cc
index 1651a6a..6b72b83 100644
--- a/base/thread_unittest.cc
+++ b/base/thread_unittest.cc
@@ -6,7 +6,6 @@
#include <vector>
-#include "base/lock.h"
#include "base/message_loop.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
index 4631f34..9db25ff 100644
--- a/base/tracked_objects.cc
+++ b/base/tracked_objects.cc
@@ -10,6 +10,7 @@
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
+#include "base/thread_restrictions.h"
using base::TimeDelta;
@@ -89,7 +90,13 @@ Lock ThreadData::list_lock_;
// static
ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED;
-ThreadData::ThreadData() : next_(NULL), message_loop_(MessageLoop::current()) {}
+ThreadData::ThreadData() : next_(NULL) {
+ // This shouldn't use the MessageLoop::current() LazyInstance since this might
+ // be used on a non-joinable thread.
+ // http://crbug.com/62728
+ base::ThreadRestrictions::ScopedAllowSingleton scoped_allow_singleton;
+ message_loop_ = MessageLoop::current();
+}
ThreadData::~ThreadData() {}
@@ -260,8 +267,14 @@ void ThreadData::WriteHTMLTotalAndSubtotals(
}
Births* ThreadData::TallyABirth(const Location& location) {
- if (!message_loop_) // In case message loop wasn't yet around...
- message_loop_ = MessageLoop::current(); // Find it now.
+ {
+ // This shouldn't use the MessageLoop::current() LazyInstance since this
+ // might be used on a non-joinable thread.
+ // http://crbug.com/62728
+ base::ThreadRestrictions::ScopedAllowSingleton scoped_allow_singleton;
+ if (!message_loop_) // In case message loop wasn't yet around...
+ message_loop_ = MessageLoop::current(); // Find it now.
+ }
BirthMap::iterator it = birth_map_.find(location);
if (it != birth_map_.end()) {
@@ -279,8 +292,12 @@ Births* ThreadData::TallyABirth(const Location& location) {
void ThreadData::TallyADeath(const Births& lifetimes,
const TimeDelta& duration) {
- if (!message_loop_) // In case message loop wasn't yet around...
- message_loop_ = MessageLoop::current(); // Find it now.
+ {
+ // http://crbug.com/62728
+ base::ThreadRestrictions::ScopedAllowSingleton scoped_allow_singleton;
+ if (!message_loop_) // In case message loop wasn't yet around...
+ message_loop_ = MessageLoop::current(); // Find it now.
+ }
DeathMap::iterator it = death_map_.find(&lifetimes);
if (it != death_map_.end()) {
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
index 87912c0..8590a8c 100644
--- a/base/tracked_objects.h
+++ b/base/tracked_objects.h
@@ -11,7 +11,6 @@
#include <vector>
#include "base/lock.h"
-#include "base/task.h"
#include "base/thread_local_storage.h"
#include "base/tracked.h"
diff --git a/base/values_util.cc b/base/values_util.cc
new file mode 100644
index 0000000..31d8e8c
--- /dev/null
+++ b/base/values_util.cc
@@ -0,0 +1,14 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/values_util.h"
+
+RefCountedList::RefCountedList(ListValue* list) {
+ list_ = list;
+}
+
+RefCountedList::~RefCountedList() {
+ if (list_)
+ delete list_;
+}
diff --git a/base/values_util.h b/base/values_util.h
new file mode 100644
index 0000000..57b35c1
--- /dev/null
+++ b/base/values_util.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_VALUES_UTIL_H_
+#define BASE_VALUES_UTIL_H_
+#pragma once
+
+#include "base/values.h"
+#include "base/ref_counted.h"
+
+class RefCountedList : public base::RefCountedThreadSafe<RefCountedList> {
+ public:
+ // Takes ownership of |list|.
+ explicit RefCountedList(ListValue* list);
+ virtual ~RefCountedList();
+
+ virtual ListValue* Get() {
+ return list_;
+ }
+
+ private:
+ ListValue* list_;
+
+ DISALLOW_COPY_AND_ASSIGN(RefCountedList);
+};
+
+#endif // BASE_VALUES_UTIL_H_
diff --git a/base/vlog.cc b/base/vlog.cc
index cda9cea..8903f39 100644
--- a/base/vlog.cc
+++ b/base/vlog.cc
@@ -36,11 +36,12 @@ VlogInfo::VlogInfo(const std::string& v_switch,
typedef std::pair<std::string, std::string> KVPair;
int vlog_level = 0;
- if (base::StringToInt(v_switch, &vlog_level)) {
- SetMaxVlogLevel(vlog_level);
- } else {
- LOG(WARNING) << "Parsed v switch \""
- << v_switch << "\" as " << vlog_level;
+ if (!v_switch.empty()) {
+ if (base::StringToInt(v_switch, &vlog_level)) {
+ SetMaxVlogLevel(vlog_level);
+ } else {
+ LOG(WARNING) << "Could not parse v switch \"" << v_switch << "\"";
+ }
}
std::vector<KVPair> kv_pairs;
diff --git a/base/win/pe_image.cc b/base/win/pe_image.cc
index 76fdbcd..fcf03c1 100644
--- a/base/win/pe_image.cc
+++ b/base/win/pe_image.cc
@@ -558,12 +558,12 @@ PVOID PEImageAsData::RVAToAddr(DWORD rva) const {
return NULL;
PVOID in_memory = PEImage::RVAToAddr(rva);
- DWORD dummy;
+ DWORD disk_offset;
- if (!ImageAddrToOnDiskOffset(in_memory, &dummy))
+ if (!ImageAddrToOnDiskOffset(in_memory, &disk_offset))
return NULL;
- return in_memory;
+ return PEImage::RVAToAddr(disk_offset);
}
} // namespace win
diff --git a/base/win/registry.cc b/base/win/registry.cc
index 977ea00..3372cf4 100644
--- a/base/win/registry.cc
+++ b/base/win/registry.cc
@@ -357,7 +357,12 @@ bool RegKey::WriteValue(const wchar_t* name, DWORD value) {
bool RegKey::DeleteKey(const wchar_t* name) {
base::ThreadRestrictions::AssertIOAllowed();
- return (!key_) ? false : (ERROR_SUCCESS == SHDeleteKey(key_, name));
+ if (!key_)
+ return false;
+ LSTATUS ret = SHDeleteKey(key_, name);
+ if (ERROR_SUCCESS != ret)
+ SetLastError(ret);
+ return ERROR_SUCCESS == ret;
}
bool RegKey::DeleteValue(const wchar_t* value_name) {
diff --git a/base/win/rgs_helper.h b/base/win/rgs_helper.h
new file mode 100644
index 0000000..16e33bf
--- /dev/null
+++ b/base/win/rgs_helper.h
@@ -0,0 +1,89 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Defines a map for adding variables to rgs files. This allows COM object
+// classes to declare the values of these variables so that we don't need to
+// copy/paste them and manually keep them in sync.
+// To use this, declare the registry ID of your RGS file using
+// the DECLARE_REGISTRY_RESOURCEID_EX macro, instead of the
+// DECLARE_REGISTRY_RESOURCEID, then add a registry map to your class
+// using the registry map macros:
+// BEGIN_REGISTRY_MAP(MyClassName)
+// REGMAP_ENTRY("NAME", "MyClassName Class")
+// REGMAP_ENTRY_UUID("CLSID", CLSID_MyClassName)
+// END_REGISTRY_MAP()
+//
+// You can then refer to the names above in your RGS file as
+// variables %NAME% and %CLSID%, respectively.
+#ifndef BASE_WIN_RGS_HELPER_H_
+#define BASE_WIN_RGS_HELPER_H_
+
+#include "base/string_util.h"
+
+struct ATLRegmapEntryHelper : public _ATL_REGMAP_ENTRY {
+ ATLRegmapEntryHelper() {
+ szKey = NULL;
+ szData = NULL;
+ }
+ ATLRegmapEntryHelper(LPCOLESTR key, LPCOLESTR data) {
+ szKey = key;
+ size_t size = lstrlen(data) + 1;
+ szData = new wchar_t[size];
+ base::wcslcpy(const_cast<wchar_t*>(szData), data, size);
+ }
+
+ ATLRegmapEntryHelper(LPCOLESTR key, UINT resid) {
+ wchar_t data[256] = {0};
+ szKey = key;
+ if (::LoadString(_pModule->m_hInstResource, resid, data,
+ arraysize(data) - 1) == 0) {
+ *data = L'\0';
+ }
+
+ size_t size = lstrlen(data) + 1;
+
+ szData = new wchar_t[size];
+ base::wcslcpy(const_cast<wchar_t*>(szData), data, size);
+ }
+
+ ATLRegmapEntryHelper(LPCOLESTR key, REFGUID guid) {
+ szKey = key;
+ static const size_t kGuidStringSize = 40;
+ szData = new wchar_t[kGuidStringSize];
+ if (szData) {
+ if (::StringFromGUID2(guid, const_cast<LPOLESTR>(szData),
+ kGuidStringSize) == 0) {
+ *const_cast<LPOLESTR>(szData) = L'\0';
+ }
+ }
+ }
+ ~ATLRegmapEntryHelper() {
+ delete [] szData;
+ }
+};
+
+#define BEGIN_REGISTRY_MAP(x)\
+ static struct _ATL_REGMAP_ENTRY *_GetRegistryMap() {\
+ static const ATLRegmapEntryHelper map[] = {
+#define REGMAP_ENTRY(x, y) ATLRegmapEntryHelper(OLESTR(##x), OLESTR(##y)),
+
+#define REGMAP_UUID(x, clsid) ATLRegmapEntryHelper(OLESTR(##x), clsid),
+
+// This allows usage of a Resource string.
+#define REGMAP_RESOURCE(x, resid) ATLRegmapEntryHelper(OLESTR(##x), resid),
+
+// This allows usage of a static function to be called to provide the string.
+#define REGMAP_FUNCTION(x, f) ATLRegmapEntryHelper(OLESTR(##x), ##f()),
+
+#define END_REGISTRY_MAP() ATLRegmapEntryHelper() };\
+ return (_ATL_REGMAP_ENTRY*)map;\
+ }
+
+#define DECLARE_REGISTRY_RESOURCEID_EX(x)\
+ static HRESULT WINAPI UpdateRegistry(BOOL bRegister) {\
+ return ATL::_pAtlModule->UpdateRegistryFromResource((UINT)x, bRegister, \
+ _GetRegistryMap());\
+ }
+
+#endif // BASE_WIN_RGS_HELPER_H_
diff --git a/base/win/scoped_comptr.h b/base/win/scoped_comptr.h
index b65aaff..6375218 100644
--- a/base/win/scoped_comptr.h
+++ b/base/win/scoped_comptr.h
@@ -82,6 +82,11 @@ class ScopedComPtr : public scoped_refptr<Interface> {
return &ptr_;
}
+ // A convenience for whenever a void pointer is needed as an out argument.
+ void** ReceiveVoid() {
+ return reinterpret_cast<void**>(Receive());
+ }
+
template <class Query>
HRESULT QueryInterface(Query** p) {
DCHECK(p != NULL);