diff options
author | xhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-05 23:46:07 +0000 |
---|---|---|
committer | xhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-05 23:46:07 +0000 |
commit | a71bff5edfc7e87a7ccbdaf589a66dd3954acd8d (patch) | |
tree | b6555958ef6d580428b7a5420e9f4e40723dc121 /media/webm | |
parent | 9b95ac04d7183a8b655228f16dd46ac4f6cc6ae6 (diff) | |
download | chromium_src-a71bff5edfc7e87a7ccbdaf589a66dd3954acd8d.zip chromium_src-a71bff5edfc7e87a7ccbdaf589a66dd3954acd8d.tar.gz chromium_src-a71bff5edfc7e87a7ccbdaf589a66dd3954acd8d.tar.bz2 |
Fix memory leak in WebMContentEncodingsClient.
- Make ContentEncoding a class instead of a struct.
- Remove ref count from ContentEncoding.
- Revert r123446: "Suppress leak in WebMListParser"
- Revert r123451: "Update suppression for 115606"
- Revert r123499: "Suppress WebMContentEncodingsClient::OnListStart leak for drmemory."
BUG=115606
TEST=media_unittest with HeapCheck
Review URL: http://codereview.chromium.org/9474022
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@125024 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/webm')
-rw-r--r-- | media/webm/webm_content_encodings.cc | 10 | ||||
-rw-r--r-- | media/webm/webm_content_encodings.h | 33 | ||||
-rw-r--r-- | media/webm/webm_content_encodings_client.cc | 77 | ||||
-rw-r--r-- | media/webm/webm_content_encodings_client.h | 9 | ||||
-rw-r--r-- | media/webm/webm_content_encodings_client_unittest.cc | 85 | ||||
-rw-r--r-- | media/webm/webm_tracks_parser.cc | 10 | ||||
-rw-r--r-- | media/webm/webm_tracks_parser.h | 4 |
7 files changed, 152 insertions, 76 deletions
diff --git a/media/webm/webm_content_encodings.cc b/media/webm/webm_content_encodings.cc index 53cd171..a5b7bfe 100644 --- a/media/webm/webm_content_encodings.cc +++ b/media/webm/webm_content_encodings.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/logging.h" #include "media/webm/webm_content_encodings.h" namespace media { @@ -16,4 +17,13 @@ ContentEncoding::ContentEncoding() ContentEncoding::~ContentEncoding() {} +void ContentEncoding::SetEncryptionKeyId(const uint8* encryption_key_id, + int size) { + DCHECK(encryption_key_id); + DCHECK_GT(size, 0); + encryption_key_id_.reset(new uint8[size]); + memcpy(encryption_key_id_.get(), encryption_key_id, size); + encryption_key_id_size_ = size; +} + } // namespace media diff --git a/media/webm/webm_content_encodings.h b/media/webm/webm_content_encodings.h index 4a5f62f..2947a26 100644 --- a/media/webm/webm_content_encodings.h +++ b/media/webm/webm_content_encodings.h @@ -5,16 +5,14 @@ #ifndef MEDIA_WEBM_WEBM_CONTENT_ENCODINGS_H_ #define MEDIA_WEBM_WEBM_CONTENT_ENCODINGS_H_ -#include <vector> - -#include "base/compiler_specific.h" -#include "base/memory/ref_counted.h" +#include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "media/base/media_export.h" namespace media { -struct MEDIA_EXPORT ContentEncoding : public base::RefCounted<ContentEncoding> { +class MEDIA_EXPORT ContentEncoding { + public: // The following enum definitions are based on the ContentEncoding element // specified in the Matroska spec. @@ -45,8 +43,28 @@ struct MEDIA_EXPORT ContentEncoding : public base::RefCounted<ContentEncoding> { }; ContentEncoding(); - virtual ~ContentEncoding(); + ~ContentEncoding(); + + int64 order() const { return order_; } + void set_order(int64 order) { order_ = order; } + + Scope scope() const { return scope_; } + void set_scope(Scope scope) { scope_ = scope; } + + Type type() const { return type_; } + void set_type(Type type) { type_ = type; } + + EncryptionAlgo encryption_algo() const { return encryption_algo_; } + void set_encryption_algo(EncryptionAlgo encryption_algo) { + encryption_algo_ = encryption_algo; + } + const uint8* encryption_key_id() const { return encryption_key_id_.get(); } + int encryption_key_id_size() const { return encryption_key_id_size_; } + + void SetEncryptionKeyId(const uint8* encryption_key_id, int size); + + private: int64 order_; Scope scope_; Type type_; @@ -54,12 +72,9 @@ struct MEDIA_EXPORT ContentEncoding : public base::RefCounted<ContentEncoding> { scoped_array<uint8> encryption_key_id_; int encryption_key_id_size_; - private: DISALLOW_COPY_AND_ASSIGN(ContentEncoding); }; -typedef std::vector<scoped_refptr<ContentEncoding> > ContentEncodings; - } // namespace media #endif // MEDIA_WEBM_WEBM_CONTENT_ENCODINGS_H_ diff --git a/media/webm/webm_content_encodings_client.cc b/media/webm/webm_content_encodings_client.cc index 4e09ff8..086f85b 100644 --- a/media/webm/webm_content_encodings_client.cc +++ b/media/webm/webm_content_encodings_client.cc @@ -5,37 +5,43 @@ #include "media/webm/webm_content_encodings_client.h" #include "base/logging.h" +#include "base/stl_util.h" #include "media/webm/webm_constants.h" namespace media { WebMContentEncodingsClient::WebMContentEncodingsClient() - : content_encryption_encountered_(false) { + : content_encryption_encountered_(false), + content_encodings_ready_(false) { } -WebMContentEncodingsClient::~WebMContentEncodingsClient() {} +WebMContentEncodingsClient::~WebMContentEncodingsClient() { + STLDeleteElements(&content_encodings_); +} const ContentEncodings& WebMContentEncodingsClient::content_encodings() const { + DCHECK(content_encodings_ready_); return content_encodings_; } WebMParserClient* WebMContentEncodingsClient::OnListStart(int id) { if (id == kWebMIdContentEncodings) { - DCHECK(!cur_content_encoding_); + DCHECK(!cur_content_encoding_.get()); DCHECK(!content_encryption_encountered_); - content_encodings_.clear(); + STLDeleteElements(&content_encodings_); + content_encodings_ready_ = false; return this; } if (id == kWebMIdContentEncoding) { - DCHECK(!cur_content_encoding_); + DCHECK(!cur_content_encoding_.get()); DCHECK(!content_encryption_encountered_); - cur_content_encoding_ = new ContentEncoding; + cur_content_encoding_.reset(new ContentEncoding()); return this; } if (id == kWebMIdContentEncryption) { - DCHECK(cur_content_encoding_); + DCHECK(cur_content_encoding_.get()); if (content_encryption_encountered_) { DVLOG(1) << "Unexpected multiple ContentEncryption."; return NULL; @@ -58,40 +64,41 @@ bool WebMContentEncodingsClient::OnListEnd(int id) { DVLOG(1) << "Missing ContentEncoding."; return false; } + content_encodings_ready_ = true; return true; } if (id == kWebMIdContentEncoding) { - DCHECK(cur_content_encoding_); + DCHECK(cur_content_encoding_.get()); // // Specify default values to missing mandatory elements. // - if (cur_content_encoding_->order_ == ContentEncoding::kOrderInvalid) { + if (cur_content_encoding_->order() == ContentEncoding::kOrderInvalid) { // Default value of encoding order is 0, which should only be used on the // first ContentEncoding. if (!content_encodings_.empty()) { DVLOG(1) << "Missing ContentEncodingOrder."; return false; } - cur_content_encoding_->order_ = 0; + cur_content_encoding_->set_order(0); } - if (cur_content_encoding_->scope_ == ContentEncoding::kScopeInvalid) - cur_content_encoding_->scope_ = ContentEncoding::kScopeAllFrameContents; + if (cur_content_encoding_->scope() == ContentEncoding::kScopeInvalid) + cur_content_encoding_->set_scope(ContentEncoding::kScopeAllFrameContents); - if (cur_content_encoding_->type_ == ContentEncoding::kTypeInvalid) - cur_content_encoding_->type_ = ContentEncoding::kTypeCompression; + if (cur_content_encoding_->type() == ContentEncoding::kTypeInvalid) + cur_content_encoding_->set_type(ContentEncoding::kTypeCompression); // Check for elements valid in spec but not supported for now. - if (cur_content_encoding_->type_ == ContentEncoding::kTypeCompression) { + if (cur_content_encoding_->type() == ContentEncoding::kTypeCompression) { DVLOG(1) << "ContentCompression not supported."; return false; } // Enforce mandatory elements without default values. - DCHECK(cur_content_encoding_->type_ == ContentEncoding::kTypeEncryption); + DCHECK(cur_content_encoding_->type() == ContentEncoding::kTypeEncryption); if (!content_encryption_encountered_) { DVLOG(1) << "ContentEncodingType is encryption but ContentEncryption " "is missing."; @@ -104,12 +111,12 @@ bool WebMContentEncodingsClient::OnListEnd(int id) { } if (id == kWebMIdContentEncryption) { - DCHECK(cur_content_encoding_); + DCHECK(cur_content_encoding_.get()); // Specify default value for elements that are not present. - if (cur_content_encoding_->encryption_algo_ == + if (cur_content_encoding_->encryption_algo() == ContentEncoding::kEncAlgoInvalid) { - cur_content_encoding_->encryption_algo_ = - ContentEncoding::kEncAlgoNotEncrypted; + cur_content_encoding_->set_encryption_algo( + ContentEncoding::kEncAlgoNotEncrypted); } return true; } @@ -122,10 +129,10 @@ bool WebMContentEncodingsClient::OnListEnd(int id) { // Multiple occurrence restriction and range are checked in this function. // Mandatory occurrence restriction is checked in OnListEnd. bool WebMContentEncodingsClient::OnUInt(int id, int64 val) { - DCHECK(cur_content_encoding_); + DCHECK(cur_content_encoding_.get()); if (id == kWebMIdContentEncodingOrder) { - if (cur_content_encoding_->order_ != ContentEncoding::kOrderInvalid) { + if (cur_content_encoding_->order() != ContentEncoding::kOrderInvalid) { DVLOG(1) << "Unexpected multiple ContentEncodingOrder."; return false; } @@ -136,12 +143,12 @@ bool WebMContentEncodingsClient::OnUInt(int id, int64 val) { return false; } - cur_content_encoding_->order_ = val; + cur_content_encoding_->set_order(val); return true; } if (id == kWebMIdContentEncodingScope) { - if (cur_content_encoding_->scope_ != ContentEncoding::kScopeInvalid) { + if (cur_content_encoding_->scope() != ContentEncoding::kScopeInvalid) { DVLOG(1) << "Unexpected multiple ContentEncodingScope."; return false; } @@ -157,12 +164,12 @@ bool WebMContentEncodingsClient::OnUInt(int id, int64 val) { return false; } - cur_content_encoding_->scope_ = static_cast<ContentEncoding::Scope>(val); + cur_content_encoding_->set_scope(static_cast<ContentEncoding::Scope>(val)); return true; } if (id == kWebMIdContentEncodingType) { - if (cur_content_encoding_->type_ != ContentEncoding::kTypeInvalid) { + if (cur_content_encoding_->type() != ContentEncoding::kTypeInvalid) { DVLOG(1) << "Unexpected multiple ContentEncodingType."; return false; } @@ -177,12 +184,12 @@ bool WebMContentEncodingsClient::OnUInt(int id, int64 val) { return false; } - cur_content_encoding_->type_ = static_cast<ContentEncoding::Type>(val); + cur_content_encoding_->set_type(static_cast<ContentEncoding::Type>(val)); return true; } if (id == kWebMIdContentEncAlgo) { - if (cur_content_encoding_->encryption_algo_ != + if (cur_content_encoding_->encryption_algo() != ContentEncoding::kEncAlgoInvalid) { DVLOG(1) << "Unexpected multiple ContentEncAlgo."; return false; @@ -194,8 +201,8 @@ bool WebMContentEncodingsClient::OnUInt(int id, int64 val) { return false; } - cur_content_encoding_->encryption_algo_ = - static_cast<ContentEncoding::EncryptionAlgo>(val); + cur_content_encoding_->set_encryption_algo( + static_cast<ContentEncoding::EncryptionAlgo>(val)); return true; } @@ -207,19 +214,17 @@ bool WebMContentEncodingsClient::OnUInt(int id, int64 val) { // Multiple occurrence restriction is checked in this function. Mandatory // restriction is checked in OnListEnd. bool WebMContentEncodingsClient::OnBinary(int id, const uint8* data, int size) { - DCHECK(cur_content_encoding_); + DCHECK(cur_content_encoding_.get()); DCHECK(data); DCHECK_GT(size, 0); if (id == kWebMIdContentEncKeyID) { - if (cur_content_encoding_->encryption_key_id_.get() || - cur_content_encoding_->encryption_key_id_size_) { + if (cur_content_encoding_->encryption_key_id() || + cur_content_encoding_->encryption_key_id_size()) { DVLOG(1) << "Unexpected multiple ContentEncKeyID"; return false; } - cur_content_encoding_->encryption_key_id_.reset(new uint8[size]); - memcpy(cur_content_encoding_->encryption_key_id_.get(), data, size); - cur_content_encoding_->encryption_key_id_size_ = size; + cur_content_encoding_->SetEncryptionKeyId(data, size); return true; } diff --git a/media/webm/webm_content_encodings_client.h b/media/webm/webm_content_encodings_client.h index 9a4c876..257d37d 100644 --- a/media/webm/webm_content_encodings_client.h +++ b/media/webm/webm_content_encodings_client.h @@ -5,6 +5,8 @@ #ifndef MEDIA_WEBM_WEBM_CONTENT_ENCODINGS_CLIENT_H_ #define MEDIA_WEBM_WEBM_CONTENT_ENCODINGS_CLIENT_H_ +#include <vector> + #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" #include "media/base/media_export.h" @@ -13,6 +15,8 @@ namespace media { +typedef std::vector<ContentEncoding*> ContentEncodings; + // Parser for WebM ContentEncodings element. class MEDIA_EXPORT WebMContentEncodingsClient : public WebMParserClient { public: @@ -28,10 +32,13 @@ class MEDIA_EXPORT WebMContentEncodingsClient : public WebMParserClient { virtual bool OnBinary(int id, const uint8* data, int size) OVERRIDE; private: - scoped_refptr<ContentEncoding> cur_content_encoding_; + scoped_ptr<ContentEncoding> cur_content_encoding_; bool content_encryption_encountered_; ContentEncodings content_encodings_; + // |content_encodings_| is ready. For debugging purpose. + bool content_encodings_ready_; + DISALLOW_COPY_AND_ASSIGN(WebMContentEncodingsClient); }; diff --git a/media/webm/webm_content_encodings_client_unittest.cc b/media/webm/webm_content_encodings_client_unittest.cc index b3e8daa..e7e37d1 100644 --- a/media/webm/webm_content_encodings_client_unittest.cc +++ b/media/webm/webm_content_encodings_client_unittest.cc @@ -17,8 +17,6 @@ class WebMContentEncodingsClientTest : public testing::Test { void ParseAndExpectToFail(const uint8* buf, int size) { int result = parser_.Parse(buf, size); EXPECT_EQ(-1, result); - const ContentEncodings content_encodings = client_.content_encodings(); - EXPECT_TRUE(content_encodings.empty()); } protected: @@ -59,16 +57,18 @@ TEST_F(WebMContentEncodingsClientTest, SingleContentEncoding) { int result = parser_.Parse(kContentEncodings, size); ASSERT_EQ(size, result); - const ContentEncodings content_encodings = client_.content_encodings(); + const ContentEncodings& content_encodings = client_.content_encodings(); + ASSERT_EQ(1u, content_encodings.size()); - EXPECT_EQ(0, content_encodings[0]->order_); + ASSERT_TRUE(content_encodings[0]); + EXPECT_EQ(0, content_encodings[0]->order()); EXPECT_EQ(ContentEncoding::kScopeAllFrameContents, - content_encodings[0]->scope_); - EXPECT_EQ(ContentEncoding::kTypeEncryption, content_encodings[0]->type_); + content_encodings[0]->scope()); + EXPECT_EQ(ContentEncoding::kTypeEncryption, content_encodings[0]->type()); EXPECT_EQ(ContentEncoding::kEncAlgoAes, - content_encodings[0]->encryption_algo_); - EXPECT_TRUE(content_encodings[0]->encryption_key_id_.get()); - EXPECT_EQ(8, content_encodings[0]->encryption_key_id_size_); + content_encodings[0]->encryption_algo()); + EXPECT_TRUE(content_encodings[0]->encryption_key_id()); + EXPECT_EQ(8, content_encodings[0]->encryption_key_id_size()); } TEST_F(WebMContentEncodingsClientTest, MultipleContentEncoding) { @@ -95,19 +95,20 @@ TEST_F(WebMContentEncodingsClientTest, MultipleContentEncoding) { int result = parser_.Parse(kContentEncodings, size); ASSERT_EQ(size, result); - const ContentEncodings content_encodings = client_.content_encodings(); + const ContentEncodings& content_encodings = client_.content_encodings(); ASSERT_EQ(2u, content_encodings.size()); for (int i = 0; i < 2; ++i) { - EXPECT_EQ(i, content_encodings[i]->order_); + ASSERT_TRUE(content_encodings[i]); + EXPECT_EQ(i, content_encodings[i]->order()); EXPECT_EQ(ContentEncoding::kScopeAllFrameContents | ContentEncoding::kScopeTrackPrivateData, - content_encodings[i]->scope_); - EXPECT_EQ(ContentEncoding::kTypeEncryption, content_encodings[i]->type_); + content_encodings[i]->scope()); + EXPECT_EQ(ContentEncoding::kTypeEncryption, content_encodings[i]->type()); EXPECT_EQ(!i ? ContentEncoding::kEncAlgoAes : ContentEncoding::kEncAlgoDes, - content_encodings[i]->encryption_algo_); - EXPECT_TRUE(content_encodings[i]->encryption_key_id_.get()); - EXPECT_EQ(8, content_encodings[i]->encryption_key_id_size_); + content_encodings[i]->encryption_algo()); + EXPECT_TRUE(content_encodings[i]->encryption_key_id()); + EXPECT_EQ(8, content_encodings[i]->encryption_key_id_size()); } } @@ -125,16 +126,54 @@ TEST_F(WebMContentEncodingsClientTest, DefaultValues) { int result = parser_.Parse(kContentEncodings, size); ASSERT_EQ(size, result); - const ContentEncodings content_encodings = client_.content_encodings(); + const ContentEncodings& content_encodings = client_.content_encodings(); + ASSERT_EQ(1u, content_encodings.size()); - EXPECT_EQ(0, content_encodings[0]->order_); + ASSERT_TRUE(content_encodings[0]); + EXPECT_EQ(0, content_encodings[0]->order()); EXPECT_EQ(ContentEncoding::kScopeAllFrameContents, - content_encodings[0]->scope_); - EXPECT_EQ(ContentEncoding::kTypeEncryption, content_encodings[0]->type_); + content_encodings[0]->scope()); + EXPECT_EQ(ContentEncoding::kTypeEncryption, content_encodings[0]->type()); EXPECT_EQ(ContentEncoding::kEncAlgoNotEncrypted, - content_encodings[0]->encryption_algo_); - EXPECT_FALSE(content_encodings[0]->encryption_key_id_.get()); - EXPECT_EQ(0, content_encodings[0]->encryption_key_id_size_); + content_encodings[0]->encryption_algo()); + EXPECT_FALSE(content_encodings[0]->encryption_key_id()); + EXPECT_EQ(0, content_encodings[0]->encryption_key_id_size()); +} + +TEST_F(WebMContentEncodingsClientTest, ContentEncodingsClientReuse) { + const uint8 kContentEncodings[] = { + 0x6D, 0x80, 0xA1, // ContentEncodings (size = 33) + 0x62, 0x40, 0x9e, // ContentEncoding (size = 30) + 0x50, 0x31, 0x81, 0x00, // ContentEncodingOrder (size = 1) + 0x50, 0x32, 0x81, 0x01, // ContentEncodingScope (size = 1) + 0x50, 0x33, 0x81, 0x01, // ContentEncodingType (size = 1) + 0x50, 0x35, 0x8F, // ContentEncryption (size = 15) + 0x47, 0xE1, 0x81, 0x05, // ContentEncAlgo (size = 1) + 0x47, 0xE2, 0x88, // ContentEncKeyID (size = 8) + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + }; + int size = sizeof(kContentEncodings); + + // Parse for the first time. + int result = parser_.Parse(kContentEncodings, size); + ASSERT_EQ(size, result); + + // Parse again. + parser_.Reset(); + result = parser_.Parse(kContentEncodings, size); + ASSERT_EQ(size, result); + const ContentEncodings& content_encodings = client_.content_encodings(); + + ASSERT_EQ(1u, content_encodings.size()); + ASSERT_TRUE(content_encodings[0]); + EXPECT_EQ(0, content_encodings[0]->order()); + EXPECT_EQ(ContentEncoding::kScopeAllFrameContents, + content_encodings[0]->scope()); + EXPECT_EQ(ContentEncoding::kTypeEncryption, content_encodings[0]->type()); + EXPECT_EQ(ContentEncoding::kEncAlgoAes, + content_encodings[0]->encryption_algo()); + EXPECT_TRUE(content_encodings[0]->encryption_key_id()); + EXPECT_EQ(8, content_encodings[0]->encryption_key_id_size()); } TEST_F(WebMContentEncodingsClientTest, InvalidContentEncodingOrder) { diff --git a/media/webm/webm_tracks_parser.cc b/media/webm/webm_tracks_parser.cc index 9757b10..84550b7 100644 --- a/media/webm/webm_tracks_parser.cc +++ b/media/webm/webm_tracks_parser.cc @@ -79,7 +79,7 @@ bool WebMTracksParser::OnListEnd(int id) { if (track_default_duration_ > 0) { // Convert nanoseconds to base::TimeDelta. - default_duration= base::TimeDelta::FromMicroseconds( + default_duration = base::TimeDelta::FromMicroseconds( track_default_duration_ / 1000.0); } @@ -87,15 +87,15 @@ bool WebMTracksParser::OnListEnd(int id) { video_track_num_ = track_num_; video_default_duration_ = default_duration; if (track_content_encodings_client_.get()) { - video_content_encodings_ = - track_content_encodings_client_->content_encodings(); + video_content_encodings_client_ = + track_content_encodings_client_.Pass(); } } else if (track_type_ == kWebMTrackTypeAudio) { audio_track_num_ = track_num_; audio_default_duration_ = default_duration; if (track_content_encodings_client_.get()) { - audio_content_encodings_ = - track_content_encodings_client_->content_encodings(); + audio_content_encodings_client_ = + track_content_encodings_client_.Pass(); } } else { DVLOG(1) << "Unexpected TrackType " << track_type_; diff --git a/media/webm/webm_tracks_parser.h b/media/webm/webm_tracks_parser.h index 4626e8b..efe45d9 100644 --- a/media/webm/webm_tracks_parser.h +++ b/media/webm/webm_tracks_parser.h @@ -54,11 +54,11 @@ class WebMTracksParser : public WebMParserClient { int64 audio_track_num_; base::TimeDelta audio_default_duration_; - ContentEncodings audio_content_encodings_; + scoped_ptr<WebMContentEncodingsClient> audio_content_encodings_client_; int64 video_track_num_; base::TimeDelta video_default_duration_; - ContentEncodings video_content_encodings_; + scoped_ptr<WebMContentEncodingsClient> video_content_encodings_client_; DISALLOW_IMPLICIT_CONSTRUCTORS(WebMTracksParser); }; |