diff options
author | Ben Murdoch <benm@google.com> | 2011-01-07 14:18:56 +0000 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-01-11 10:23:13 +0000 |
commit | 201ade2fbba22bfb27ae029f4d23fca6ded109a0 (patch) | |
tree | b793f4ed916f73cf18357ea467ff3deb5ffb5b52 /base | |
parent | d8c4c37a7d0961944bfdfaa117d5c68c8e129c97 (diff) | |
download | external_chromium-201ade2fbba22bfb27ae029f4d23fca6ded109a0.zip external_chromium-201ade2fbba22bfb27ae029f4d23fca6ded109a0.tar.gz external_chromium-201ade2fbba22bfb27ae029f4d23fca6ded109a0.tar.bz2 |
Merge chromium at 9.0.597.55: Initial merge by git.
Change-Id: Id686a88437441ec7e17abb3328a404c7b6c3c6ad
Diffstat (limited to 'base')
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 e397be6..e9b2bd6 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) { } @@ -198,7 +198,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 870a985..45b7ead 100644 --- a/base/thread.h +++ b/base/thread.h @@ -129,8 +129,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); |