|
|
Created:
6 years, 5 months ago by Sigurður Ásgeirsson Modified:
6 years, 5 months ago CC:
chromium-reviews, tfarina, browser-components-watch_chromium.org Base URL:
svn://svn.chromium.org/chrome/trunk/src Project:
chromium Visibility:
Public. |
DescriptionOwnership of the bookmark node is temporarily passed to the task to avoid leaking it if the task never runs. This fixes a leak that occurs in Profile browser tests.
R=gab@chromium.org,joaodasilva@chromium.org
TBR=brettw@chromium.org
BUG=391508
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=281836
Patch Set 1 : Depends on issue 349263004. #
Total comments: 6
Patch Set 2 : Address Gab's comments. #
Messages
Total messages: 17 (0 generated)
PTAL - this is a diff from https://codereview.chromium.org/349263004/, as I intend to land that first, if possible.
https://codereview.chromium.org/372663002/diff/80001/chrome/browser/bookmarks... File chrome/browser/bookmarks/chrome_bookmark_client.cc (right): https://codereview.chromium.org/372663002/diff/80001/chrome/browser/bookmarks... chrome/browser/bookmarks/chrome_bookmark_client.cc:168: // The ownership of maanaged_node_ is in limbo until LoadExtraNodes runs, s/maanaged/managed https://codereview.chromium.org/372663002/diff/80001/chrome/browser/bookmarks... chrome/browser/bookmarks/chrome_bookmark_client.cc:171: managed_node_ = managed.get(); So is the only purpose of storing this as a member for pointer comparison later? If so, would it make sense to use a void* (or perhaps a new type typedef'ed to void* for clarity)? I don't like that there is a fully typed pointer in this class which no one should ever deref...
https://codereview.chromium.org/372663002/diff/80001/chrome/browser/bookmarks... File chrome/browser/bookmarks/chrome_bookmark_client.cc (right): https://codereview.chromium.org/372663002/diff/80001/chrome/browser/bookmarks... chrome/browser/bookmarks/chrome_bookmark_client.cc:9: #include "base/debug/leak_annotations.h" Also, rm this include
Thanks - PTAL. https://codereview.chromium.org/372663002/diff/80001/chrome/browser/bookmarks... File chrome/browser/bookmarks/chrome_bookmark_client.cc (right): https://codereview.chromium.org/372663002/diff/80001/chrome/browser/bookmarks... chrome/browser/bookmarks/chrome_bookmark_client.cc:9: #include "base/debug/leak_annotations.h" On 2014/07/07 18:13:38, gab wrote: > Also, rm this include Done. https://codereview.chromium.org/372663002/diff/80001/chrome/browser/bookmarks... chrome/browser/bookmarks/chrome_bookmark_client.cc:168: // The ownership of maanaged_node_ is in limbo until LoadExtraNodes runs, On 2014/07/07 18:12:47, gab wrote: > s/maanaged/managed Done. https://codereview.chromium.org/372663002/diff/80001/chrome/browser/bookmarks... chrome/browser/bookmarks/chrome_bookmark_client.cc:171: managed_node_ = managed.get(); On 2014/07/07 18:12:47, gab wrote: > So is the only purpose of storing this as a member for pointer comparison later? > If so, would it make sense to use a void* (or perhaps a new type typedef'ed to > void* for clarity)? > > I don't like that there is a fully typed pointer in this class which no one > should ever deref... The member is used by ChromeBookmarkClient::BookmarkModelLoaded, but I don't understand the contract, so can't say which thread that'll run on. I can't naively change this even to a const pointer...
lgtm since you're only making lifetime management better without making the overall model worse, but the current code is very confusing pointer management IMO (at least there should be a big comment on |managed_node_| explaining why it's kept as a member variable and how it should be used.... This code is asking for race conditions... CC joaodasilva who wrote this it looks like (https://codereview.chromium.org/319543003): Joao, can you please fix the lifetime management and usage of |managed_node_|? As-is it's kept as a member variable and used on threads other than the one on which it is initially set without any sort of memory barriers. We temporarily suppressed the memory leak caused by this code and are now trying to mitigate it without a leak-annotation, but really this shouldn't be that way to begin with (or if the current code is sane as-is, as a reader I'm not convinced of that, can you add a comment on the member variable to convince me?). Thanks! Gab
On 2014/07/07 19:00:47, gab wrote: > lgtm since you're only making lifetime management better without making the > overall model worse, but the current code is very confusing pointer management > IMO (at least there should be a big comment on |managed_node_| explaining why > it's kept as a member variable and how it should be used.... > > This code is asking for race conditions... > > CC joaodasilva who wrote this it looks like > (https://codereview.chromium.org/319543003): Joao, can you please fix the > lifetime management and usage of |managed_node_|? As-is it's kept as a member > variable and used on threads other than the one on which it is initially set > without any sort of memory barriers. > > We temporarily suppressed the memory leak caused by this code and are now trying > to mitigate it without a leak-annotation, but really this shouldn't be that way > to begin with (or if the current code is sane as-is, as a reader I'm not > convinced of that, can you add a comment on the member variable to convince > me?). > > Thanks! > Gab This change lgtm, thanks for fixing. I agree that it isn't obvious that the lifetime of managed_node_ is correct; the code is a bit convoluted because we need to retain a handle to the node in ChromeBookmarkClient, but the node needs to be loaded with the rest of the bookmark model in a background thread (from bookmark_storage.cc). This code is correct because: - BookmarkModelFactory depends on ChromeBookmarkClientFactory; - so the managed_node only gets created when the BookmarkModel is loaded; - if shutdown happens during that load, then the node is now deleted by the background task since it's owned by the callback (fixed in this CL) - if the load is successful then the node is owned by the BookmarkModel; - the BookmarkModel always outlives the ChromeBookmarkClient, so the managed_node_ is always valid. Regarding races: all the nodes of the BookmarkModel live in the UI thread. Only LoadExtraNodes() gets called in a background thread when the BookmarkModel gets loaded. But that task is synchronized with the BookmarkModel, so the node won't be used until the model is loaded. After all that said, I think this can be improved: the LoadExtraNode() callback can post back to the ChromeBookmarkClient and tell it the ID of the managed node; and then ChromeBookmarkClient::BookmarkModelLoaded() can get the handle by looking it up by ID. Then the managed_node_ handle isn't set until the model is fully loaded. WDYT?
The CQ bit was checked by siggi@chromium.org
CQ is trying da patch. Follow status at https://chromium-status.appspot.com/cq/siggi@chromium.org/372663002/100001
On 2014/07/08 15:07:04, Joao da Silva wrote: > On 2014/07/07 19:00:47, gab wrote: > > lgtm since you're only making lifetime management better without making the > > overall model worse, but the current code is very confusing pointer management > > IMO (at least there should be a big comment on |managed_node_| explaining why > > it's kept as a member variable and how it should be used.... > > > > This code is asking for race conditions... > > > > CC joaodasilva who wrote this it looks like > > (https://codereview.chromium.org/319543003): Joao, can you please fix the > > lifetime management and usage of |managed_node_|? As-is it's kept as a member > > variable and used on threads other than the one on which it is initially set > > without any sort of memory barriers. > > > > We temporarily suppressed the memory leak caused by this code and are now > trying > > to mitigate it without a leak-annotation, but really this shouldn't be that > way > > to begin with (or if the current code is sane as-is, as a reader I'm not > > convinced of that, can you add a comment on the member variable to convince > > me?). > > > > Thanks! > > Gab > > This change lgtm, thanks for fixing. > > I agree that it isn't obvious that the lifetime of managed_node_ is correct; the > code is a bit convoluted because we need to retain a handle to the node in > ChromeBookmarkClient, but the node needs to be loaded with the rest of the > bookmark model in a background thread (from bookmark_storage.cc). > > This code is correct because: > > - BookmarkModelFactory depends on ChromeBookmarkClientFactory; > > - so the managed_node only gets created when the BookmarkModel is loaded; > > - if shutdown happens during that load, then the node is now deleted by the > background task since it's owned by the callback (fixed in this CL) > > - if the load is successful then the node is owned by the BookmarkModel; > > - the BookmarkModel always outlives the ChromeBookmarkClient, so the > managed_node_ is always valid. > > Regarding races: all the nodes of the BookmarkModel live in the UI thread. Only > LoadExtraNodes() gets called in a background thread when the BookmarkModel gets > loaded. But that task is synchronized with the BookmarkModel, so the node won't > be used until the model is loaded. > > After all that said, I think this can be improved: the LoadExtraNode() callback > can post back to the ChromeBookmarkClient and tell it the ID of the managed > node; and then ChromeBookmarkClient::BookmarkModelLoaded() can get the handle by > looking it up by ID. Then the managed_node_ handle isn't set until the model is > fully loaded. WDYT? Thanks, submitting as-is, as I don't have time to work on this further for now.
On 2014/07/08 15:07:04, Joao da Silva wrote: > On 2014/07/07 19:00:47, gab wrote: > > lgtm since you're only making lifetime management better without making the > > overall model worse, but the current code is very confusing pointer management > > IMO (at least there should be a big comment on |managed_node_| explaining why > > it's kept as a member variable and how it should be used.... > > > > This code is asking for race conditions... > > > > CC joaodasilva who wrote this it looks like > > (https://codereview.chromium.org/319543003): Joao, can you please fix the > > lifetime management and usage of |managed_node_|? As-is it's kept as a member > > variable and used on threads other than the one on which it is initially set > > without any sort of memory barriers. > > > > We temporarily suppressed the memory leak caused by this code and are now > trying > > to mitigate it without a leak-annotation, but really this shouldn't be that > way > > to begin with (or if the current code is sane as-is, as a reader I'm not > > convinced of that, can you add a comment on the member variable to convince > > me?). > > > > Thanks! > > Gab > > This change lgtm, thanks for fixing. > > I agree that it isn't obvious that the lifetime of managed_node_ is correct; the > code is a bit convoluted because we need to retain a handle to the node in > ChromeBookmarkClient, but the node needs to be loaded with the rest of the > bookmark model in a background thread (from bookmark_storage.cc). > > This code is correct because: > > - BookmarkModelFactory depends on ChromeBookmarkClientFactory; > > - so the managed_node only gets created when the BookmarkModel is loaded; > > - if shutdown happens during that load, then the node is now deleted by the > background task since it's owned by the callback (fixed in this CL) > > - if the load is successful then the node is owned by the BookmarkModel; > > - the BookmarkModel always outlives the ChromeBookmarkClient, so the > managed_node_ is always valid. > > Regarding races: all the nodes of the BookmarkModel live in the UI thread. Only > LoadExtraNodes() gets called in a background thread when the BookmarkModel gets > loaded. But that task is synchronized with the BookmarkModel, so the node won't > be used until the model is loaded. > > After all that said, I think this can be improved: the LoadExtraNode() callback > can post back to the ChromeBookmarkClient and tell it the ID of the managed > node; and then ChromeBookmarkClient::BookmarkModelLoaded() can get the handle by > looking it up by ID. Then the managed_node_ handle isn't set until the model is > fully loaded. WDYT? Yes, looking it up by ID (posted back from LoadExtraNode()) feels a LOT safer; keeping this raw pointer may be provably "correct" for now, but I much prefer safety by design than by proof :-)! Thanks! Gab
> Thanks, submitting as-is, as I don't have time to work on this further for now. Yes, sgtm, Joao can you handle improving the design as discussed as a follow-up? Thanks, Gab
FYI, CQ is re-trying this CL (attempt #1). The failing builders are: android_clang_dbg on tryserver.chromium (http://build.chromium.org/p/tryserver.chromium/builders/android_clang_dbg/bui...) chromium_presubmit on tryserver.chromium (http://build.chromium.org/p/tryserver.chromium/builders/chromium_presubmit/bu...) ios_dbg_simulator on tryserver.chromium (http://build.chromium.org/p/tryserver.chromium/builders/ios_dbg_simulator/bui...) linux_chromium_chromeos_clang_dbg on tryserver.chromium (http://build.chromium.org/p/tryserver.chromium/builders/linux_chromium_chrome...) linux_chromium_clang_dbg on tryserver.chromium (http://build.chromium.org/p/tryserver.chromium/builders/linux_chromium_clang_...)
The CQ bit was unchecked by commit-bot@chromium.org
Try jobs failed on following builders: chromium_presubmit on tryserver.chromium (http://build.chromium.org/p/tryserver.chromium/builders/chromium_presubmit/bu...)
The CQ bit was checked by siggi@chromium.org
CQ is trying da patch. Follow status at https://chromium-status.appspot.com/cq/siggi@chromium.org/372663002/100001
Message was sent while issue was closed.
Change committed as 281836 |