diff --git a/src/clang_complete.cc b/src/clang_complete.cc index dd825fd2..b68b4a2a 100644 --- a/src/clang_complete.cc +++ b/src/clang_complete.cc @@ -190,6 +190,12 @@ std::unique_ptr BuildCompilerInstance( Clang->getDiagnostics(), Clang->getInvocation().TargetOpts)); if (!Clang->hasTarget()) return nullptr; + // Construct SourceManager with UserFilesAreVolatile: true because otherwise + // RequiresNullTerminator: true may cause out-of-bounds read when a file is + // mmap'ed but is saved concurrently. + Clang->createFileManager(); + Clang->setSourceManager(new SourceManager(Clang->getDiagnostics(), + Clang->getFileManager(), true)); return Clang; } diff --git a/src/pipeline.cc b/src/pipeline.cc index fab84338..7604c53b 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -150,10 +150,14 @@ std::unique_ptr RawCacheLoad(const std::string &path) { IndexFile::kMajorVersion); } -bool Indexer_Parse(CompletionManager *completion, WorkingFiles *wfiles, - Project *project, VFS *vfs, const GroupMatch &matcher) { +std::mutex &GetFileMutex(const std::string &path) { const int N_MUTEXES = 256; static std::mutex mutexes[N_MUTEXES]; + return mutexes[std::hash()(path) % N_MUTEXES]; +} + +bool Indexer_Parse(CompletionManager *completion, WorkingFiles *wfiles, + Project *project, VFS *vfs, const GroupMatch &matcher) { std::optional opt_request = index_request->TryPopFront(); if (!opt_request) return false; @@ -204,8 +208,7 @@ bool Indexer_Parse(CompletionManager *completion, WorkingFiles *wfiles, if (reparse < 2) do { - std::unique_lock lock( - mutexes[std::hash()(path_to_index) % N_MUTEXES]); + std::unique_lock lock(GetFileMutex(path_to_index)); prev = RawCacheLoad(path_to_index); if (!prev || CacheInvalid(vfs, prev.get(), path_to_index, entry.args, std::nullopt)) @@ -244,8 +247,7 @@ bool Indexer_Parse(CompletionManager *completion, WorkingFiles *wfiles, std::string path = dep.first.val().str(); if (!vfs->Stamp(path, dep.second, 1)) continue; - std::lock_guard lock1( - mutexes[std::hash()(path) % N_MUTEXES]); + std::lock_guard lock1(GetFileMutex(path)); prev = RawCacheLoad(path); if (!prev) continue; @@ -301,7 +303,7 @@ bool Indexer_Parse(CompletionManager *completion, WorkingFiles *wfiles, LOG_IF_S(INFO, loud) << "store index for " << path << " (delta: " << !!prev << ")"; { - std::lock_guard lock(mutexes[std::hash()(path) % N_MUTEXES]); + std::lock_guard lock(GetFileMutex(path)); if (vfs->Loaded(path)) prev = RawCacheLoad(path); else