Skip to content

Commit 516eb3b

Browse files
committed
Version 2.13.3
* Cherry-pick 30321de to stable * Cherry-pick f827c53 to stable * Cherry-pick 05e5427 to stable
2 parents fdce7a8 + 74b8195 commit 516eb3b

11 files changed

+122
-21
lines changed

CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## 2.13.2 - 2021-06-09
1+
## 2.13.3 - 2021-06-10
22

33
This is a patch release that fixes:
44

runtime/bin/file_system_watcher.cc

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
namespace dart {
1515
namespace bin {
1616

17+
bool FileSystemWatcher::delayed_filewatch_callback_ = false;
18+
1719
void FUNCTION_NAME(FileSystemWatcher_IsSupported)(Dart_NativeArguments args) {
1820
Dart_SetBooleanReturnValue(args, FileSystemWatcher::IsSupported());
1921
}

runtime/bin/file_system_watcher.h

+8
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,15 @@ class FileSystemWatcher {
4848
static intptr_t GetSocketId(intptr_t id, intptr_t path_id);
4949
static Dart_Handle ReadEvents(intptr_t id, intptr_t path_id);
5050

51+
static void set_delayed_filewatch_callback(bool value) {
52+
delayed_filewatch_callback_ = value;
53+
}
54+
static bool delayed_filewatch_callback() {
55+
return delayed_filewatch_callback_;
56+
}
57+
5158
private:
59+
static bool delayed_filewatch_callback_;
5260
DISALLOW_COPY_AND_ASSIGN(FileSystemWatcher);
5361
};
5462

runtime/bin/file_system_watcher_macos.cc

+17-12
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ class FSEventsWatcher {
6161
int write_fd,
6262
bool recursive)
6363
: watcher_(watcher),
64-
ready_(false),
6564
base_path_length_(strlen(base_path)),
6665
path_ref_(CFStringCreateWithCString(NULL,
6766
base_path,
@@ -74,9 +73,14 @@ class FSEventsWatcher {
7473
}
7574

7675
~Node() {
77-
Stop();
76+
// This is invoked outside of [Callback] execution because
77+
// [context.release] callback is invoked when [FSEventStream] is
78+
// deallocated, the same [FSEventStream] that [Callback] gets a reference
79+
// to during its execution. [Callback] holding a reference prevents stream
80+
// from deallocation.
7881
close(write_fd_);
7982
CFRelease(path_ref_);
83+
watcher_ = nullptr; // this is to catch access-after-free in Callback
8084
}
8185

8286
void set_ref(FSEventStreamRef ref) { ref_ = ref; }
@@ -85,6 +89,9 @@ class FSEventsWatcher {
8589
FSEventStreamContext context;
8690
memset(&context, 0, sizeof(context));
8791
context.info = reinterpret_cast<void*>(this);
92+
context.release = [](const void* info) {
93+
delete static_cast<const Node*>(info);
94+
};
8895
CFArrayRef array = CFArrayCreate(
8996
NULL, reinterpret_cast<const void**>(&path_ref_), 1, NULL);
9097
FSEventStreamRef ref = FSEventStreamCreate(
@@ -93,7 +100,6 @@ class FSEventsWatcher {
93100
CFRelease(array);
94101

95102
set_ref(ref);
96-
ready_.store(true, std::memory_order_release);
97103

98104
FSEventStreamScheduleWithRunLoop(ref_, watcher_->run_loop_,
99105
kCFRunLoopDefaultMode);
@@ -103,23 +109,19 @@ class FSEventsWatcher {
103109
}
104110

105111
void Stop() {
106-
ASSERT(ready_);
107112
FSEventStreamStop(ref_);
108113
FSEventStreamInvalidate(ref_);
109114
FSEventStreamRelease(ref_);
110-
ready_.store(false, std::memory_order_release);
111115
}
112116

113117
FSEventsWatcher* watcher() const { return watcher_; }
114-
bool ready() const { return ready_.load(std::memory_order_acquire); }
115118
intptr_t base_path_length() const { return base_path_length_; }
116119
int read_fd() const { return read_fd_; }
117120
int write_fd() const { return write_fd_; }
118121
bool recursive() const { return recursive_; }
119122

120123
private:
121124
FSEventsWatcher* watcher_;
122-
std::atomic<bool> ready_;
123125
intptr_t base_path_length_;
124126
CFStringRef path_ref_;
125127
int read_fd_;
@@ -218,12 +220,15 @@ class FSEventsWatcher {
218220
void* event_paths,
219221
const FSEventStreamEventFlags event_flags[],
220222
const FSEventStreamEventId event_ids[]) {
221-
Node* node = reinterpret_cast<Node*>(client);
223+
if (FileSystemWatcher::delayed_filewatch_callback()) {
224+
// Used in tests to highlight race between callback invocation
225+
// and unwatching the file path, Node destruction
226+
TimerUtils::Sleep(1000 /* ms */);
227+
}
228+
Node* node = static_cast<Node*>(client);
229+
RELEASE_ASSERT(node->watcher() != nullptr);
222230
ASSERT(Thread::Compare(node->watcher()->threadId_,
223231
Thread::GetCurrentThreadId()));
224-
if (!node->ready()) {
225-
return;
226-
}
227232
for (size_t i = 0; i < num_events; i++) {
228233
char* path = reinterpret_cast<char**>(event_paths)[i];
229234
FSEvent event;
@@ -274,7 +279,7 @@ intptr_t FileSystemWatcher::WatchPath(intptr_t id,
274279

275280
void FileSystemWatcher::UnwatchPath(intptr_t id, intptr_t path_id) {
276281
USE(id);
277-
delete reinterpret_cast<FSEventsWatcher::Node*>(path_id);
282+
reinterpret_cast<FSEventsWatcher::Node*>(path_id)->Stop();
278283
}
279284

280285
intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) {

runtime/bin/main_options.cc

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "bin/dartdev_isolate.h"
1212
#include "bin/error_exit.h"
13+
#include "bin/file_system_watcher.h"
1314
#include "bin/options.h"
1415
#include "bin/platform.h"
1516
#include "bin/utils.h"
@@ -472,6 +473,9 @@ bool Options::ParseArguments(int argc,
472473
Options::long_ssl_cert_evaluation());
473474
#endif // !defined(DART_IO_SECURE_SOCKET_DISABLED)
474475

476+
FileSystemWatcher::set_delayed_filewatch_callback(
477+
Options::delayed_filewatch_callback());
478+
475479
// The arguments to the VM are at positions 1 through i-1 in argv.
476480
Platform::SetExecutableArguments(i, argv);
477481

runtime/bin/main_options.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ namespace bin {
4848
V(suppress_core_dump, suppress_core_dump) \
4949
V(enable_service_port_fallback, enable_service_port_fallback) \
5050
V(disable_dart_dev, disable_dart_dev) \
51-
V(long_ssl_cert_evaluation, long_ssl_cert_evaluation)
51+
V(long_ssl_cert_evaluation, long_ssl_cert_evaluation) \
52+
V(bypass_trusting_system_roots, bypass_trusting_system_roots) \
53+
V(delayed_filewatch_callback, delayed_filewatch_callback)
5254

5355
// Boolean flags that have a short form.
5456
#define SHORT_BOOL_OPTIONS_LIST(V) \

runtime/tests/vm/dart/transferable_throws_oom_test.dart

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ main() {
2626
// Attempt to create total 1tb uint8list which should fail on 32 and 64-bit
2727
// platforms.
2828
final bytes100MB = Uint8List(100 * 1024 * 1024);
29-
final total1TB = List<Uint8List>.filled(10000, bytes100MB);
30-
// Try to make a 1 TB transferable.
31-
Expect.throws(() => TransferableTypedData.fromList(total1TB));
29+
final total1PB = List<Uint8List>.filled(10 * 1000 * 1000, bytes100MB);
30+
// Try to make a 1 PB transferable.
31+
Expect.throws(() => TransferableTypedData.fromList(total1PB));
3232
}

runtime/tests/vm/dart_2/transferable_throws_oom_test.dart

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ main() {
2626
// Attempt to create total 1tb uint8list which should fail on 32 and 64-bit
2727
// platforms.
2828
final bytes100MB = Uint8List(100 * 1024 * 1024);
29-
final total1TB = List<Uint8List>.filled(10000, bytes100MB);
30-
// Try to make a 1 TB transferable.
31-
Expect.throws(() => TransferableTypedData.fromList(total1TB));
29+
final total1PB = List<Uint8List>.filled(10 * 1000 * 1000, bytes100MB);
30+
// Try to make a 1 PB transferable.
31+
Expect.throws(() => TransferableTypedData.fromList(total1PB));
3232
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// VMOptions=--delayed-filewatch-callback --enable-isolate-groups --experimental-enable-isolate-groups-jit
6+
// VMOptions=--delayed-filewatch-callback --no-enable-isolate-groups
7+
8+
// Verifies that cancelling subscription from inside of the event handler
9+
// works as expected, does not result in crash or hang.
10+
11+
import "dart:async";
12+
import "dart:io";
13+
14+
import "package:path/path.dart";
15+
16+
final completer = Completer<void>();
17+
late StreamSubscription subscription;
18+
19+
void handleWatchEvent(event) {
20+
if (event is FileSystemCreateEvent && event.path.endsWith('txt')) {
21+
subscription.cancel();
22+
completer.complete();
23+
}
24+
}
25+
26+
void main() async {
27+
if (!FileSystemEntity.isWatchSupported) return;
28+
final dir = Directory.systemTemp.createTempSync('dart_file_system_watcher');
29+
final watcher = dir.watch();
30+
subscription = watcher.listen(handleWatchEvent);
31+
32+
print('watching ${dir.path}');
33+
for (int i = 0; i < 1000; i++) {
34+
File(join(dir.path, 'file_$i.txt')).createSync();
35+
}
36+
await completer.future;
37+
try {
38+
dir.deleteSync(recursive: true);
39+
} catch (_) {}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// VMOptions=--delayed-filewatch-callback --enable-isolate-groups --experimental-enable-isolate-groups-jit
6+
// VMOptions=--delayed-filewatch-callback --no-enable-isolate-groups
7+
8+
// Verifies that cancelling subscription from inside of the event handler
9+
// works as expected, does not result in crash or hang.
10+
11+
import "dart:async";
12+
import "dart:io";
13+
14+
import "package:path/path.dart";
15+
16+
final completer = Completer<void>();
17+
var subscription;
18+
19+
void handleWatchEvent(event) {
20+
if (event is FileSystemCreateEvent && event.path.endsWith('txt')) {
21+
subscription.cancel();
22+
completer.complete();
23+
}
24+
}
25+
26+
void main() async {
27+
if (!FileSystemEntity.isWatchSupported) return;
28+
final dir = Directory.systemTemp.createTempSync('dart_file_system_watcher');
29+
final watcher = dir.watch();
30+
subscription = watcher.listen(handleWatchEvent);
31+
32+
print('watching ${dir.path}');
33+
for (int i = 0; i < 1000; i++) {
34+
File(join(dir.path, 'file_$i.txt')).createSync();
35+
}
36+
await completer.future;
37+
try {
38+
dir.deleteSync(recursive: true);
39+
} catch (_) {}
40+
}

tools/VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,6 @@
2626
CHANNEL stable
2727
MAJOR 2
2828
MINOR 13
29-
PATCH 2
29+
PATCH 3
3030
PRERELEASE 0
3131
PRERELEASE_PATCH 0

0 commit comments

Comments
 (0)