Skip to content

Commit 49bf644

Browse files
rmacnak-googleCommit Queue
authored andcommitted
[vm] Fix race between Page::Deallocate during isolate group shutdown and Page::Cleanup during Dart_Cleanup.
Dart_Cleanup waited only for the isolate group to be unregistered, which happens before the group's heap is deleted. TEST=tsan Change-Id: I20046516635adbcbf63eae460d7b09e7e26169d8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/416283 Reviewed-by: Alexander Aprelev <[email protected]> Commit-Queue: Ryan Macnak <[email protected]>
1 parent b591571 commit 49bf644

File tree

4 files changed

+82
-3
lines changed

4 files changed

+82
-3
lines changed

runtime/vm/dart.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,8 @@ void Dart::WaitForIsolateShutdown() {
589589
ASSERT(!Isolate::creation_enabled_);
590590
MonitorLocker ml(Isolate::isolate_creation_monitor_);
591591
intptr_t num_attempts = 0;
592-
while (!IsolateGroup::HasOnlyVMIsolateGroup()) {
592+
while (!IsolateGroup::HasOnlyVMIsolateGroup() ||
593+
(Isolate::pending_shutdowns_ != 0)) {
593594
Monitor::WaitResult retval = ml.Wait(1000);
594595
if (retval == Monitor::kTimedOut) {
595596
num_attempts += 1;

runtime/vm/dart_api_impl_test.cc

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,76 @@ UNIT_TEST_CASE(DartAPI_DartInitializeHeapSizes) {
141141
EXPECT(Dart_Cleanup() == nullptr);
142142
}
143143

144+
static RelaxedAtomic<intptr_t> pending_isolate_groups = 0;
145+
static Dart_Isolate CreateCallback(const char* script_uri,
146+
const char* main,
147+
const char* package_root,
148+
const char* package_config,
149+
Dart_IsolateFlags* flags,
150+
void* isolate_data,
151+
char** error) {
152+
pending_isolate_groups++;
153+
return TesterState::create_callback(script_uri, main, package_root,
154+
package_config, flags, isolate_data,
155+
error);
156+
}
157+
static void CleanupCallback(void* isolate_group_data) {
158+
TesterState::group_cleanup_callback(isolate_group_data);
159+
OS::Sleep(3000);
160+
pending_isolate_groups--;
161+
}
162+
163+
UNIT_TEST_CASE(DartAPI_DartCleanupWaitsForGroupCleanupCallbacks) {
164+
EXPECT(Dart_SetVMFlags(TesterState::argc, TesterState::argv) == nullptr);
165+
166+
Dart_InitializeParams params;
167+
memset(&params, 0, sizeof(Dart_InitializeParams));
168+
params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION;
169+
params.vm_snapshot_data = TesterState::vm_snapshot_data;
170+
params.create_group = CreateCallback;
171+
params.shutdown_isolate = TesterState::shutdown_callback;
172+
params.cleanup_group = CleanupCallback;
173+
params.start_kernel_isolate = true;
174+
EXPECT(Dart_Initialize(&params) == nullptr);
175+
176+
Monitor monitor;
177+
bool shutting_down = false;
178+
std::thread thread(
179+
[](Monitor* monitor, bool* shutting_down) {
180+
TestIsolateScope scope;
181+
const char* kScriptChars =
182+
"@pragma('vm:entry-point', 'call')\n"
183+
"int testMain() {\n"
184+
" return 42;\n"
185+
"}\n";
186+
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr);
187+
EXPECT_VALID(lib);
188+
Dart_Handle result =
189+
Dart_Invoke(lib, NewString("testMain"), 0, nullptr);
190+
EXPECT_VALID(result);
191+
int64_t value = 0;
192+
EXPECT_VALID(Dart_IntegerToInt64(result, &value));
193+
EXPECT_EQ(42, value);
194+
195+
MonitorLocker ml(monitor);
196+
*shutting_down = true;
197+
ml.Notify();
198+
},
199+
&monitor, &shutting_down);
200+
201+
{
202+
MonitorLocker ml(&monitor);
203+
while (!shutting_down) {
204+
ml.Wait();
205+
}
206+
}
207+
208+
EXPECT(Dart_Cleanup() == nullptr);
209+
EXPECT_EQ(0, pending_isolate_groups);
210+
211+
thread.join();
212+
}
213+
144214
TEST_CASE(Dart_KillIsolate) {
145215
const char* kScriptChars =
146216
"@pragma('vm:entry-point', 'call')\n"

runtime/vm/isolate.cc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,11 @@ void IsolateGroup::Shutdown() {
524524
thread_pool_.reset();
525525
}
526526

527+
{
528+
MonitorLocker ml(Isolate::isolate_creation_monitor_);
529+
Isolate::pending_shutdowns_++;
530+
}
531+
527532
// Needs to happen before starting to destroy the heap so helper tasks like
528533
// the SampleBlockProcessor don't try to enter the group during this
529534
// tear-down.
@@ -565,7 +570,8 @@ void IsolateGroup::Shutdown() {
565570
Dart::UptimeMillis(), name);
566571
}
567572
MonitorLocker ml(Isolate::isolate_creation_monitor_);
568-
if (!Isolate::creation_enabled_) {
573+
Isolate::pending_shutdowns_--;
574+
if (Isolate::pending_shutdowns_ == 0) {
569575
ml.Notify();
570576
}
571577
if (trace_shutdown) {
@@ -2743,6 +2749,7 @@ Dart_IsolateGroupCleanupCallback Isolate::cleanup_group_callback_ = nullptr;
27432749
Random* IsolateGroup::isolate_group_random_ = nullptr;
27442750
Monitor* Isolate::isolate_creation_monitor_ = nullptr;
27452751
bool Isolate::creation_enabled_ = false;
2752+
intptr_t Isolate::pending_shutdowns_ = 0;
27462753

27472754
RwLock* IsolateGroup::isolate_groups_rwlock_ = nullptr;
27482755
IntrusiveDList<IsolateGroup>* IsolateGroup::isolate_groups_ = nullptr;

runtime/vm/isolate.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1738,9 +1738,10 @@ class Isolate : public IntrusiveDListEntry<Isolate> {
17381738
return accepts_messages_;
17391739
}
17401740

1741-
// This monitor protects [creation_enabled_].
1741+
// This monitor protects [creation_enabled_] and [pending_shutdowns_].
17421742
static Monitor* isolate_creation_monitor_;
17431743
static bool creation_enabled_;
1744+
static intptr_t pending_shutdowns_;
17441745

17451746
ArrayPtr loaded_prefixes_set_storage_;
17461747

0 commit comments

Comments
 (0)