fix an issue that calling Touch() right before file deletion causes use-after-free

This commit is contained in:
falsycat 2022-11-06 21:53:33 +09:00
parent 3a4d801f95
commit f6be39f719
3 changed files with 15 additions and 9 deletions

View File

@ -206,10 +206,11 @@ class Env final : public nf7::Env {
}
}
void Handle(const nf7::File::Event& e) noexcept override
nf7::File* Handle(const nf7::File::Event& e) noexcept override
try {
// trigger File::Handle()
GetFileOrThrow(e.id).Handle(e);
auto& f = GetFileOrThrow(e.id);
f.Handle(e);
// trigger file watcher
auto itr = watchers_map_.find(e.id);
@ -219,7 +220,10 @@ class Env final : public nf7::Env {
// trigger global watcher
for (auto w : watchers_map_[0]) w->Handle(e);
return &f;
} catch (nf7::ExpiredException&) {
return nullptr;
}
void Exit() noexcept override {

9
nf7.cc
View File

@ -105,11 +105,12 @@ void File::Touch() noexcept {
if (std::exchange(touch_, true)) {
return;
}
env().ExecMain(std::make_shared<nf7::GenericContext>(*this), [this]() {
if (id()) {
env().Handle( {.id = id(), .type = Event::kUpdate});
}
env().ExecSub(
std::make_shared<nf7::GenericContext>(*this),
[this, &env = env(), fid = id()]() {
if (env.Handle({ .id = fid, .type = nf7::File::Event::kUpdate })) {
touch_ = false;
}
});
}
File& File::FindOrThrow(std::string_view name) const {

3
nf7.hh
View File

@ -288,7 +288,8 @@ class Env {
virtual void Save() noexcept = 0;
virtual void Throw(std::exception_ptr&&) noexcept = 0;
virtual void Handle(const File::Event&) noexcept = 0;
// returns the target file if alive
virtual nf7::File* Handle(const File::Event&) noexcept = 0;
virtual File* GetFile(File::Id) const noexcept = 0;
File& GetFileOrThrow(File::Id) const;