summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Klocek <michal.klocek@qt.io>2018-08-17 17:48:55 +0200
committerMichael BrĂ¼ning <michael.bruning@qt.io>2018-08-20 09:59:20 +0000
commit084a80f98014f18de47056567cb89806a5ad4b30 (patch)
tree3235870f0c054d07bd1e922eb1afdd7eac0879c5
parentf78390d24d2128ecf90c17f692d5c6bcd9cf7fa5 (diff)
[Backport] Security Bug 831117 2/2
Oilpan: Clear all Persistents on thread termination Clear all persistents on thread termination, because when we have a bug and it leaves a Persistent behind, it will not be a stale pointer and just causes null dereference. Since we disabled PersistentHeapCollections on non-main threads we can assume all PersistentNode::Self() can be cast to Persistent<DummyGCBase> Bug: 831117 Reviewed-on: https://chromium-review.googlesource.com/1025547 ----------------------------------------------------------------- Oilpan: Clear all Persistents on thread termination. Persistents should be cleared when NumberOfPersistents() != 0. Bug: 831117 Reviewed-on: https://chromium-review.googlesource.com/1089460 ----------------------------------------------------------------- Change-Id: Ibe6f61a894195d240b288e995e633c4749870663 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
-rw-r--r--chromium/third_party/WebKit/Source/platform/heap/PersistentNode.cpp27
-rw-r--r--chromium/third_party/WebKit/Source/platform/heap/PersistentNode.h1
-rw-r--r--chromium/third_party/WebKit/Source/platform/heap/ThreadState.cpp21
3 files changed, 44 insertions, 5 deletions
diff --git a/chromium/third_party/WebKit/Source/platform/heap/PersistentNode.cpp b/chromium/third_party/WebKit/Source/platform/heap/PersistentNode.cpp
index a9499556062..10a035f8472 100644
--- a/chromium/third_party/WebKit/Source/platform/heap/PersistentNode.cpp
+++ b/chromium/third_party/WebKit/Source/platform/heap/PersistentNode.cpp
@@ -125,6 +125,30 @@ void PersistentRegion::TracePersistentNodes(Visitor* visitor,
#endif
}
+void PersistentRegion::PrepareForThreadStateTermination() {
+ DCHECK(!IsMainThread());
+ PersistentNodeSlots* slots = slots_;
+ while (slots) {
+ for (int i = 0; i < PersistentNodeSlots::kSlotCount; ++i) {
+ PersistentNode* node = &slots->slot_[i];
+ if (node->IsUnused())
+ continue;
+ // It is safe to cast to Persistent<DummyGCBase> because persistent heap
+ // collections are banned in non-main threads.
+
+ Persistent<DummyGCBase>* persistent =
+ reinterpret_cast<Persistent<DummyGCBase>*>(node->Self());
+ DCHECK(persistent);
+ persistent->Clear();
+ DCHECK(node->IsUnused());
+ }
+ slots = slots->next_;
+ }
+#if DCHECK_IS_ON()
+ DCHECK_EQ(persistent_count_, 0);
+#endif
+}
+
bool CrossThreadPersistentRegion::ShouldTracePersistentNode(
Visitor* visitor,
PersistentNode* node) {
@@ -145,9 +169,6 @@ void CrossThreadPersistentRegion::PrepareForThreadStateTermination(
// out the underlying heap reference.
MutexLocker lock(mutex_);
- // TODO(sof): consider ways of reducing overhead. (e.g., tracking number of
- // active CrossThreadPersistent<>s pointing into the heaps of each ThreadState
- // and use that count to bail out early.)
PersistentNodeSlots* slots = persistent_region_->slots_;
while (slots) {
for (int i = 0; i < PersistentNodeSlots::kSlotCount; ++i) {
diff --git a/chromium/third_party/WebKit/Source/platform/heap/PersistentNode.h b/chromium/third_party/WebKit/Source/platform/heap/PersistentNode.h
index 60d179c6023..cecbb681973 100644
--- a/chromium/third_party/WebKit/Source/platform/heap/PersistentNode.h
+++ b/chromium/third_party/WebKit/Source/platform/heap/PersistentNode.h
@@ -151,6 +151,7 @@ class PLATFORM_EXPORT PersistentRegion final {
Visitor*,
ShouldTraceCallback = PersistentRegion::ShouldTracePersistentNode);
int NumberOfPersistents();
+ void PrepareForThreadStateTermination();
private:
friend CrossThreadPersistentRegion;
diff --git a/chromium/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/chromium/third_party/WebKit/Source/platform/heap/ThreadState.cpp
index c80d930071c..8b9629b17f1 100644
--- a/chromium/third_party/WebKit/Source/platform/heap/ThreadState.cpp
+++ b/chromium/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -83,6 +83,8 @@ uint8_t ThreadState::main_thread_state_storage_[sizeof(ThreadState)];
const size_t kDefaultAllocatedObjectSizeThreshold = 100 * 1024;
+constexpr size_t kMaxTerminationGCLoops = 20;
+
namespace {
const char* GcReasonString(BlinkGC::GCReason reason) {
@@ -214,9 +216,24 @@ void ThreadState::RunTerminationGC() {
old_count = current_count;
current_count = GetPersistentRegion()->NumberOfPersistents();
}
+
// We should not have any persistents left when getting to this point,
- // if we have it is probably a bug so adding a debug ASSERT to catch this.
- DCHECK(!current_count);
+ // if we have it is a bug, and we have a reference cycle or a missing
+ // RegisterAsStaticReference. Clearing out all the Persistents will avoid
+ // stale pointers and gets them reported as nullptr dereferences.
+
+ if (current_count) {
+ for (size_t i = 0; i < kMaxTerminationGCLoops &&
+ GetPersistentRegion()->NumberOfPersistents();
+ i++) {
+ GetPersistentRegion()->PrepareForThreadStateTermination();
+ CollectGarbage(BlinkGC::kNoHeapPointersOnStack, BlinkGC::kGCWithSweep,
+ BlinkGC::kThreadTerminationGC);
+ }
+ }
+
+ CHECK(!GetPersistentRegion()->NumberOfPersistents());
+
// All of pre-finalizers should be consumed.
DCHECK(ordered_pre_finalizers_.IsEmpty());
CHECK_EQ(GcState(), kNoGCScheduled);