diff options
author | davidben@chromium.org <davidben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-29 08:54:47 +0000 |
---|---|---|
committer | davidben@chromium.org <davidben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-29 08:54:47 +0000 |
commit | 31a6b3749082169cd9cc44b9495ed31c5b6947f2 (patch) | |
tree | d10927961f56e8fed5d8ff7133e816cd4dcb5578 /content/browser/loader | |
parent | bda4454d010d276415f677f371662c8993da1e20 (diff) | |
download | chromium_src-31a6b3749082169cd9cc44b9495ed31c5b6947f2.zip chromium_src-31a6b3749082169cd9cc44b9495ed31c5b6947f2.tar.gz chromium_src-31a6b3749082169cd9cc44b9495ed31c5b6947f2.tar.bz2 |
Fix HANDLE leak in ResourceDispatcherHost tests.
Ownership of the HANDLE in ResourceMsg_SetDataBuffer isn't managed
automatically.
Also invert ForwardingFilter/TestFilter's superclass/subclass
relationship. This arrangement avoids the useless dest_ = NULL
codepath.
BUG=366246
Review URL: https://codereview.chromium.org/257763007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@266790 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/loader')
-rw-r--r-- | content/browser/loader/resource_dispatcher_host_unittest.cc | 130 |
1 files changed, 83 insertions, 47 deletions
diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc index 7717431..08e5f4d 100644 --- a/content/browser/loader/resource_dispatcher_host_unittest.cc +++ b/content/browser/loader/resource_dispatcher_host_unittest.cc @@ -9,6 +9,7 @@ #include "base/file_util.h" #include "base/files/file_path.h" #include "base/memory/scoped_vector.h" +#include "base/memory/shared_memory.h" #include "base/message_loop/message_loop.h" #include "base/pickle.h" #include "base/run_loop.h" @@ -82,6 +83,29 @@ void GenerateIPCMessage( *message, filter.get(), &msg_is_ok); } +// On Windows, ResourceMsg_SetDataBuffer supplies a HANDLE which is not +// automatically released. +// +// See ResourceDispatcher::ReleaseResourcesInDataMessage. +// +// TODO(davidben): It would be nice if the behavior for base::SharedMemoryHandle +// were more like it is in POSIX where the received fds are tracked in a +// ref-counted core that closes them if not extracted. +void ReleaseHandlesInMessage(const IPC::Message& message) { + if (message.type() == ResourceMsg_SetDataBuffer::ID) { + PickleIterator iter(message); + int request_id; + CHECK(message.ReadInt(&iter, &request_id)); + base::SharedMemoryHandle shm_handle; + if (IPC::ParamTraits<base::SharedMemoryHandle>::Read(&message, + &iter, + &shm_handle)) { + if (base::SharedMemory::IsHandleValid(shm_handle)) + base::SharedMemory::CloseHandle(shm_handle); + } + } +} + } // namespace static int RequestIDForMessage(const IPC::Message& msg) { @@ -133,6 +157,13 @@ static void KickOffRequest() { // We may want to move this to a shared space if it is useful for something else class ResourceIPCAccumulator { public: + ~ResourceIPCAccumulator() { + for (size_t i = 0; i < messages_.size(); i++) { + ReleaseHandlesInMessage(messages_[i]); + } + } + + // On Windows, takes ownership of SharedMemoryHandles in |msg|. void AddMessage(const IPC::Message& msg) { messages_.push_back(msg); } @@ -140,7 +171,8 @@ class ResourceIPCAccumulator { // This groups the messages by their request ID. The groups will be in order // that the first message for each request ID was received, and the messages // within the groups will be in the order that they appeared. - // Note that this clears messages_. + // Note that this clears messages_. The caller takes ownership of any + // SharedMemoryHandles in messages placed into |msgs|. typedef std::vector< std::vector<IPC::Message> > ClassifiedMessages; void GetClassifiedMessages(ClassifiedMessages* msgs); @@ -173,36 +205,39 @@ void ResourceIPCAccumulator::GetClassifiedMessages(ClassifiedMessages* msgs) { } } -// This class forwards the incoming messages to the ResourceDispatcherHostTest. // This is used to emulate different sub-processes, since this filter will -// have a different ID than the original. For the test, we want all the incoming -// messages to go to the same place, which is why this forwards. -class ForwardingFilter : public ResourceMessageFilter { +// have a different ID than the original. +class TestFilter : public ResourceMessageFilter { public: - explicit ForwardingFilter(IPC::Sender* dest, - ResourceContext* resource_context) - : ResourceMessageFilter( - ChildProcessHostImpl::GenerateChildProcessUniqueId(), - PROCESS_TYPE_RENDERER, NULL, NULL, NULL, NULL, - base::Bind(&ForwardingFilter::GetContexts, - base::Unretained(this))), - dest_(dest), - resource_context_(resource_context) { + explicit TestFilter(ResourceContext* resource_context) + : ResourceMessageFilter( + ChildProcessHostImpl::GenerateChildProcessUniqueId(), + PROCESS_TYPE_RENDERER, NULL, NULL, NULL, NULL, + base::Bind(&TestFilter::GetContexts, base::Unretained(this))), + resource_context_(resource_context), + canceled_(false), + received_after_canceled_(0) { ChildProcessSecurityPolicyImpl::GetInstance()->Add(child_id()); set_peer_pid_for_testing(base::GetCurrentProcId()); } + void set_canceled(bool canceled) { canceled_ = canceled; } + int received_after_canceled() const { return received_after_canceled_; } + // ResourceMessageFilter override virtual bool Send(IPC::Message* msg) OVERRIDE { - if (!dest_) - return false; - return dest_->Send(msg); + // No messages should be received when the process has been canceled. + if (canceled_) + received_after_canceled_++; + ReleaseHandlesInMessage(*msg); + delete msg; + return true; } ResourceContext* resource_context() { return resource_context_; } protected: - virtual ~ForwardingFilter() {} + virtual ~TestFilter() {} private: void GetContexts(const ResourceHostMsg_Request& request, @@ -212,8 +247,34 @@ class ForwardingFilter : public ResourceMessageFilter { *request_context = resource_context_->GetRequestContext(); } - IPC::Sender* dest_; ResourceContext* resource_context_; + bool canceled_; + int received_after_canceled_; + + DISALLOW_COPY_AND_ASSIGN(TestFilter); +}; + + +// This class forwards the incoming messages to the ResourceDispatcherHostTest. +// For the test, we want all the incoming messages to go to the same place, +// which is why this forwards. +class ForwardingFilter : public TestFilter { + public: + explicit ForwardingFilter(IPC::Sender* dest, + ResourceContext* resource_context) + : TestFilter(resource_context), + dest_(dest) { + } + + // TestFilter override + virtual bool Send(IPC::Message* msg) OVERRIDE { + return dest_->Send(msg); + } + + private: + virtual ~ForwardingFilter() {} + + IPC::Sender* dest_; DISALLOW_COPY_AND_ASSIGN(ForwardingFilter); }; @@ -622,6 +683,7 @@ class ResourceDispatcherHostTest : public testing::Test, wait_for_request_complete_loop_->Quit(); } + // Do not release handles in it yet; the accumulator owns them now. delete msg; return true; } @@ -1420,32 +1482,6 @@ TEST_F(ResourceDispatcherHostTest, CancelInDelegate) { CheckRequestCompleteErrorCode(msgs[0][0], net::ERR_ACCESS_DENIED); } -// The host delegate acts as a second one so we can have some requests -// pending and some canceled. -class TestFilter : public ForwardingFilter { - public: - explicit TestFilter(ResourceContext* resource_context) - : ForwardingFilter(NULL, resource_context), - has_canceled_(false), - received_after_canceled_(0) { - } - - // ForwardingFilter override - virtual bool Send(IPC::Message* msg) OVERRIDE { - // no messages should be received when the process has been canceled - if (has_canceled_) - received_after_canceled_++; - delete msg; - return true; - } - - bool has_canceled_; - int received_after_canceled_; - - private: - virtual ~TestFilter() {} -}; - // Tests CancelRequestsForProcess TEST_F(ResourceDispatcherHostTest, TestProcessCancel) { scoped_refptr<TestFilter> test_filter = new TestFilter( @@ -1492,7 +1528,7 @@ TEST_F(ResourceDispatcherHostTest, TestProcessCancel) { // Cancel the requests to the test process. host_.CancelRequestsForProcess(filter_->child_id()); - test_filter->has_canceled_ = true; + test_filter->set_canceled(true); // The requests should all be cancelled, except request 4, which is detached. EXPECT_EQ(1, host_.pending_requests()); @@ -1507,7 +1543,7 @@ TEST_F(ResourceDispatcherHostTest, TestProcessCancel) { EXPECT_EQ(0, host_.pending_requests()); // The test delegate should not have gotten any messages after being canceled. - ASSERT_EQ(0, test_filter->received_after_canceled_); + ASSERT_EQ(0, test_filter->received_after_canceled()); // There should be two results. ResourceIPCAccumulator::ClassifiedMessages msgs; |