Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6327cfe
deps: update V8 to 8.7.220
targos Nov 19, 2020
500ead2
build: reset embedder string to "-node.0"
targos Nov 19, 2020
ad8eed3
deps: V8: un-cherry-pick bd019bd
refack Mar 27, 2019
6da0120
deps: patch V8 to run on older XCode versions
ryzokuken Sep 14, 2019
3fac798
deps: V8: patch register-arm64.h
refack May 22, 2019
a79d681
deps: V8: forward declaration of `Rtl*FunctionTable`
refack May 22, 2019
60fb216
deps: make v8.h compatible with VS2015
joaocgreis Nov 1, 2019
dc721ee
deps: V8: silence irrelevant warnings
targos Mar 27, 2019
b4e1287
deps: patch V8 to run on Xcode 8
mmarchini Mar 10, 2020
cfd934f
deps: update V8 postmortem metadata script
cjihrig Jul 4, 2020
7f96548
deps: update V8 postmortem metadata script
cjihrig Sep 15, 2020
5e10ebb
deps: fix V8 build issue with inline methods
gengjiawen Oct 14, 2020
ed898f7
deps: V8: cherry-pick d76abfed3512
targos Oct 14, 2020
e262dab
deps: V8: cherry-pick 3176bfd447a9
addaleax Oct 12, 2020
6218c1c
deps: V8: cherry-pick 7b3a27b7ae65
targos Oct 19, 2020
685fbe2
deps: V8: cherry-pick 45e49775f5a3
targos Oct 21, 2020
1772fe1
deps: cherry-pick 9a49b22 from V8 upstream
danbev Nov 3, 2020
f4305dd
deps: V8: cherry-pick 821fb3883a8e
targos Nov 12, 2020
d074cfd
deps: V8: cherry-pick 086eecbd96b6
oleavr Nov 6, 2020
3e15799
deps: V8: cherry-pick 4e077ff0444a
oleavr Nov 6, 2020
de67931
deps: V8: cherry-pick 1d0f426311d4
oleavr Nov 6, 2020
685cb6e
src: fix v8 api deprecation
gengjiawen Sep 15, 2020
b7311fb
tools: update V8 gypfiles for 8.7
targos Sep 11, 2020
ad2fd53
deps: V8: restore compatibility with 8.6
targos Nov 19, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
deps: V8: cherry-pick 3176bfd447a9
Original commit message:

    [heap-profiler] Fix crash when a snapshot deleted while taking one

    Fix a crash/hang that occurred when deleting a snapshot during the
    GC that is part of taking another one.

    Specifically, when deleting the only other snapshot in such
    a situation, the `v8::HeapSnapshot::Delete()` method sees that there
    is only one (complete) snapshot at that point, and decides that it is
    okay to perform “delete all snapshots” instead of just deleting
    the requested one. That resets the internal string lookup table
    of the heap profiler, but the new snapshot that is currently in
    progress still holds references to the old string lookup table,
    leading to a use-after-free segfault or infinite loop.

    Fix this by guarding against resetting the string table while
    another heap snapshot is being taken, and add a test that would
    crash before this fix.

    This can be triggered in Node.js by repeatedly calling
    `v8.getHeapSnapshot()`, which provides heap snapshots as weakly
    held host objects.

    Change-Id: If9ac3728bf79114000982f1e7bb05e8034299e3c
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2464823
    Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
    Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
    Cr-Commit-Position: refs/heads/master@{#70445}

Refs: v8/v8@3176bfd

PR-URL: #35612
Refs: #35559
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Richard Lau <rlau@redhat.com>
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com>
Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
  • Loading branch information
addaleax authored and targos committed Nov 19, 2020
commit e262dabce012299b3013e7a7799ade8bbb63b2bc
2 changes: 1 addition & 1 deletion common.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
'v8_embedder_string': '-node.11',
'v8_embedder_string': '-node.12',

##### V8 defaults for Node.js #####

Expand Down
3 changes: 2 additions & 1 deletion deps/v8/src/api/api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10870,7 +10870,8 @@ static i::HeapSnapshot* ToInternal(const HeapSnapshot* snapshot) {

void HeapSnapshot::Delete() {
i::Isolate* isolate = ToInternal(this)->profiler()->isolate();
if (isolate->heap_profiler()->GetSnapshotsCount() > 1) {
if (isolate->heap_profiler()->GetSnapshotsCount() > 1 ||
isolate->heap_profiler()->IsTakingSnapshot()) {
ToInternal(this)->Delete();
} else {
// If this is the last snapshot, clean up all accessory data as well.
Expand Down
12 changes: 9 additions & 3 deletions deps/v8/src/profiler/heap-profiler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ namespace internal {
HeapProfiler::HeapProfiler(Heap* heap)
: ids_(new HeapObjectsMap(heap)),
names_(new StringsStorage()),
is_tracking_object_moves_(false) {}
is_tracking_object_moves_(false),
is_taking_snapshot_(false) {}

HeapProfiler::~HeapProfiler() = default;

Expand All @@ -28,7 +29,8 @@ void HeapProfiler::DeleteAllSnapshots() {
}

void HeapProfiler::MaybeClearStringsStorage() {
if (snapshots_.empty() && !sampling_heap_profiler_ && !allocation_tracker_) {
if (snapshots_.empty() && !sampling_heap_profiler_ && !allocation_tracker_ &&
!is_taking_snapshot_) {
names_.reset(new StringsStorage());
}
}
Expand Down Expand Up @@ -66,6 +68,7 @@ HeapSnapshot* HeapProfiler::TakeSnapshot(
v8::ActivityControl* control,
v8::HeapProfiler::ObjectNameResolver* resolver,
bool treat_global_objects_as_roots) {
is_taking_snapshot_ = true;
HeapSnapshot* result = new HeapSnapshot(this, treat_global_objects_as_roots);
{
HeapSnapshotGenerator generator(result, control, resolver, heap());
Expand All @@ -78,6 +81,7 @@ HeapSnapshot* HeapProfiler::TakeSnapshot(
}
ids_->RemoveDeadEntries();
is_tracking_object_moves_ = true;
is_taking_snapshot_ = false;

heap()->isolate()->debug()->feature_tracker()->Track(
DebugFeatureTracker::kHeapSnapshot);
Expand Down Expand Up @@ -138,10 +142,12 @@ void HeapProfiler::StopHeapObjectsTracking() {
}
}

int HeapProfiler::GetSnapshotsCount() {
int HeapProfiler::GetSnapshotsCount() const {
return static_cast<int>(snapshots_.size());
}

bool HeapProfiler::IsTakingSnapshot() const { return is_taking_snapshot_; }

HeapSnapshot* HeapProfiler::GetSnapshot(int index) {
return snapshots_.at(index).get();
}
Expand Down
4 changes: 3 additions & 1 deletion deps/v8/src/profiler/heap-profiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ class HeapProfiler : public HeapObjectAllocationTracker {

SnapshotObjectId PushHeapObjectsStats(OutputStream* stream,
int64_t* timestamp_us);
int GetSnapshotsCount();
int GetSnapshotsCount() const;
bool IsTakingSnapshot() const;
HeapSnapshot* GetSnapshot(int index);
SnapshotObjectId GetSnapshotObjectId(Handle<Object> obj);
SnapshotObjectId GetSnapshotObjectId(NativeObject obj);
Expand Down Expand Up @@ -93,6 +94,7 @@ class HeapProfiler : public HeapObjectAllocationTracker {
std::unique_ptr<StringsStorage> names_;
std::unique_ptr<AllocationTracker> allocation_tracker_;
bool is_tracking_object_moves_;
bool is_taking_snapshot_;
base::Mutex profiler_mutex_;
std::unique_ptr<SamplingHeapProfiler> sampling_heap_profiler_;
std::vector<std::pair<v8::HeapProfiler::BuildEmbedderGraphCallback, void*>>
Expand Down
37 changes: 37 additions & 0 deletions deps/v8/test/cctest/test-heap-profiler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4119,3 +4119,40 @@ TEST(Bug8373_2) {

heap_profiler->StopTrackingHeapObjects();
}

TEST(HeapSnapshotDeleteDuringTakeSnapshot) {
// Check that a heap snapshot can be deleted during GC while another one
// is being taken.

LocalContext env;
v8::HandleScope scope(env->GetIsolate());
v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
int gc_calls = 0;
v8::Global<v8::Object> handle;

{
struct WeakData {
const v8::HeapSnapshot* snapshot;
int* gc_calls;
v8::Global<v8::Object>* handle;
};
WeakData* data =
new WeakData{heap_profiler->TakeHeapSnapshot(), &gc_calls, &handle};

v8::HandleScope scope(env->GetIsolate());
handle.Reset(env->GetIsolate(), v8::Object::New(env->GetIsolate()));
handle.SetWeak(
data,
[](const v8::WeakCallbackInfo<WeakData>& data) {
std::unique_ptr<WeakData> weakdata{data.GetParameter()};
const_cast<v8::HeapSnapshot*>(weakdata->snapshot)->Delete();
++*weakdata->gc_calls;
weakdata->handle->Reset();
},
v8::WeakCallbackType::kParameter);
}
CHECK_EQ(gc_calls, 0);

CHECK(ValidateSnapshot(heap_profiler->TakeHeapSnapshot()));
CHECK_EQ(gc_calls, 1);
}