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

9
nf7.cc
View File

@ -105,11 +105,12 @@ void File::Touch() noexcept {
if (std::exchange(touch_, true)) { if (std::exchange(touch_, true)) {
return; return;
} }
env().ExecMain(std::make_shared<nf7::GenericContext>(*this), [this]() { env().ExecSub(
if (id()) { std::make_shared<nf7::GenericContext>(*this),
env().Handle( {.id = id(), .type = Event::kUpdate}); [this, &env = env(), fid = id()]() {
} if (env.Handle({ .id = fid, .type = nf7::File::Event::kUpdate })) {
touch_ = false; touch_ = false;
}
}); });
} }
File& File::FindOrThrow(std::string_view name) const { 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 Save() noexcept = 0;
virtual void Throw(std::exception_ptr&&) 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; virtual File* GetFile(File::Id) const noexcept = 0;
File& GetFileOrThrow(File::Id) const; File& GetFileOrThrow(File::Id) const;