Skip to content

Commit 6f74f8d

Browse files
committed
filesystem: Fix crash when watch callback returns error or throws
Signed-off-by: Rohit Agrawal <rohit.agrawal@databricks.com>
1 parent bea479c commit 6f74f8d

File tree

5 files changed

+60
-9
lines changed

5 files changed

+60
-9
lines changed

source/common/filesystem/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,12 @@ envoy_cc_library(
120120
"//source/common/common:assert_lib",
121121
"//source/common/common:linked_object",
122122
"//source/common/common:minimal_logger_lib",
123+
"//source/common/common:thread_lib",
123124
"//source/common/common:utility_lib",
124125
"//source/common/network:default_socket_interface_lib",
125126
] + select({
126127
"//bazel:windows_x86_64": [
127128
"//source/common/api:os_sys_calls_lib",
128-
"//source/common/common:thread_lib",
129129
],
130130
"//conditions:default": [],
131131
}),

source/common/filesystem/inotify/watcher_impl.cc

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "source/common/common/assert.h"
1212
#include "source/common/common/fmt.h"
13+
#include "source/common/common/thread.h"
1314
#include "source/common/common/utility.h"
1415
#include "source/common/filesystem/watcher_impl.h"
1516

@@ -52,6 +53,23 @@ absl::Status WatcherImpl::addWatch(absl::string_view path, uint32_t events, OnCh
5253
return absl::OkStatus();
5354
}
5455

56+
void WatcherImpl::callAndLogOnError(OnChangedCb& cb, uint32_t events, const std::string& file) {
57+
TRY_ASSERT_MAIN_THREAD {
58+
const absl::Status status = cb(events);
59+
if (!status.ok()) {
60+
ENVOY_LOG(warn, "Filesystem watch callback for '{}' returned error: {}", file,
61+
status.message());
62+
}
63+
}
64+
END_TRY
65+
MULTI_CATCH(
66+
const std::exception& e,
67+
{
68+
ENVOY_LOG(warn, "Filesystem watch callback for '{}' threw exception: {}", file, e.what());
69+
},
70+
{ ENVOY_LOG(warn, "Filesystem watch callback for '{}' threw unknown exception", file); });
71+
}
72+
5573
absl::Status WatcherImpl::onInotifyEvent() {
5674
while (true) {
5775
// The buffer needs to be suitably aligned to store the first inotify_event structure.
@@ -90,10 +108,10 @@ absl::Status WatcherImpl::onInotifyEvent() {
90108
if (watch.events_ & events) {
91109
if (watch.file_ == file) {
92110
ENVOY_LOG(debug, "matched callback: file: {}", file);
93-
RETURN_IF_NOT_OK(watch.cb_(events));
111+
callAndLogOnError(watch.cb_, events, file);
94112
} else if (watch.file_.empty()) {
95113
ENVOY_LOG(debug, "matched callback: directory: {}", file);
96-
RETURN_IF_NOT_OK(watch.cb_(events));
114+
callAndLogOnError(watch.cb_, events, file);
97115
}
98116
}
99117
}

source/common/filesystem/inotify/watcher_impl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class WatcherImpl : public Watcher, Logger::Loggable<Logger::Id::file> {
4040
};
4141

4242
absl::Status onInotifyEvent();
43+
void callAndLogOnError(OnChangedCb& cb, uint32_t events, const std::string& file);
4344

4445
Filesystem::Instance& file_system_;
4546
int inotify_fd_;

source/common/filesystem/kqueue/watcher_impl.cc

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "source/common/common/assert.h"
1010
#include "source/common/common/fmt.h"
11+
#include "source/common/common/thread.h"
1112
#include "source/common/common/utility.h"
1213
#include "source/common/filesystem/watcher_impl.h"
1314

@@ -116,20 +117,28 @@ absl::Status WatcherImpl::onKqueueEvent() {
116117

117118
absl::StatusOr<PathSplitResult> pathname_or_error =
118119
file_system_.splitPathFromFilename(file->file_);
119-
RETURN_IF_NOT_OK_REF(pathname_or_error.status());
120+
if (!pathname_or_error.ok()) {
121+
ENVOY_LOG(warn, "Failed to split path '{}': {}", file->file_,
122+
pathname_or_error.status().message());
123+
continue;
124+
}
120125
PathSplitResult& pathname = pathname_or_error.value();
121126

122127
if (file->watching_dir_) {
123128
if (event.fflags & NOTE_DELETE) {
124-
// directory was deleted
129+
// Directory was deleted.
125130
removeWatch(file);
126131
return absl::OkStatus();
127132
}
128133

129134
if (event.fflags & NOTE_WRITE) {
130-
// directory was written -- check if the file we're actually watching appeared
135+
// Directory was written -- check if the file we're actually watching appeared.
131136
auto file_or_error = addWatch(file->file_, file->events_, file->callback_, true);
132-
RETURN_IF_NOT_OK_REF(file_or_error.status());
137+
if (!file_or_error.ok()) {
138+
ENVOY_LOG(warn, "Failed to re-add watch for '{}': {}", file->file_,
139+
file_or_error.status().message());
140+
continue;
141+
}
133142
FileWatchPtr new_file = file_or_error.value();
134143
if (new_file != nullptr) {
135144
removeWatch(file);
@@ -150,7 +159,11 @@ absl::Status WatcherImpl::onKqueueEvent() {
150159
removeWatch(file);
151160

152161
auto file_or_error = addWatch(file->file_, file->events_, file->callback_, true);
153-
RETURN_IF_NOT_OK_REF(file_or_error.status());
162+
if (!file_or_error.ok()) {
163+
ENVOY_LOG(warn, "Failed to re-add watch for '{}': {}", file->file_,
164+
file_or_error.status().message());
165+
continue;
166+
}
154167
FileWatchPtr new_file = file_or_error.value();
155168
if (new_file == nullptr) {
156169
return absl::OkStatus();
@@ -173,11 +186,29 @@ absl::Status WatcherImpl::onKqueueEvent() {
173186

174187
if (events & file->events_) {
175188
ENVOY_LOG(debug, "matched callback: file: {}", file->file_);
176-
RETURN_IF_NOT_OK(file->callback_(events));
189+
callAndLogOnError(file->callback_, events, file->file_);
177190
}
178191
}
179192
return absl::OkStatus();
180193
}
181194

195+
void WatcherImpl::callAndLogOnError(Watcher::OnChangedCb& cb, uint32_t events,
196+
const std::string& file) {
197+
TRY_ASSERT_MAIN_THREAD {
198+
const absl::Status status = cb(events);
199+
if (!status.ok()) {
200+
ENVOY_LOG(warn, "Filesystem watch callback for '{}' returned error: {}", file,
201+
status.message());
202+
}
203+
}
204+
END_TRY
205+
MULTI_CATCH(
206+
const std::exception& e,
207+
{
208+
ENVOY_LOG(warn, "Filesystem watch callback for '{}' threw exception: {}", file, e.what());
209+
},
210+
{ ENVOY_LOG(warn, "Filesystem watch callback for '{}' threw unknown exception", file); });
211+
}
212+
182213
} // namespace Filesystem
183214
} // namespace Envoy

source/common/filesystem/kqueue/watcher_impl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class WatcherImpl : public Watcher, Logger::Loggable<Logger::Id::file> {
4646
absl::StatusOr<FileWatchPtr> addWatch(absl::string_view path, uint32_t events,
4747
Watcher::OnChangedCb cb, bool pathMustExist);
4848
void removeWatch(FileWatchPtr& watch);
49+
void callAndLogOnError(OnChangedCb& cb, uint32_t events, const std::string& file);
4950

5051
Filesystem::Instance& file_system_;
5152
int queue_;

0 commit comments

Comments
 (0)