Fix use-after-free in ~TextureInfo

In some paths, the TextureInfo (refcounted) may outlive the TextureManager,
accessing a stale pointer in its destructor. This fixes it.

BUG=chromium-os:25634
TEST=pepper flash, reload videos many times.


Review URL: http://codereview.chromium.org/9374004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@121188 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 34c6916e..c440108 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -1519,6 +1519,9 @@
   TextureToIOSurfaceMap texture_to_io_surface_map_;
 #endif
 
+  typedef std::vector<GLES2DecoderImpl*> ChildList;
+  ChildList children_;
+
   DISALLOW_COPY_AND_ASSIGN(GLES2DecoderImpl);
 };
 
@@ -2699,6 +2702,10 @@
 void GLES2DecoderImpl::Destroy() {
   bool have_context = context_.get() && MakeCurrent();
 
+  ChildList children = children_;
+  for (ChildList::iterator it = children.begin(); it != children.end(); ++it)
+    (*it)->SetParent(NULL, 0);
+  DCHECK(children_.empty());
   SetParent(NULL, 0);
 
   // Unbind everything.
@@ -2801,6 +2808,12 @@
   // parent pointer is a weak pointer so it will be null if the parent has
   // already been destroyed.
   if (parent_) {
+    ChildList::iterator it = std::find(
+        parent_->children_.begin(),
+        parent_->children_.end(),
+        this);
+    DCHECK(it != parent_->children_.end());
+    parent_->children_.erase(it);
     // First check the texture has been mapped into the parent. This might not
     // be the case if initialization failed midway through.
     GLuint service_id = offscreen_saved_color_texture_->id();
@@ -2813,6 +2826,14 @@
   GLES2DecoderImpl* new_parent_impl = static_cast<GLES2DecoderImpl*>(
       new_parent);
   if (new_parent_impl) {
+#ifndef NDEBUG
+    ChildList::iterator it = std::find(
+        new_parent_impl->children_.begin(),
+        new_parent_impl->children_.end(),
+        this);
+    DCHECK(it == new_parent_impl->children_.end());
+#endif
+    new_parent_impl->children_.push_back(this);
     // Map the ID of the saved offscreen texture into the parent so that
     // it can reference it.
     GLuint service_id = offscreen_saved_color_texture_->id();