aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Basic/SourceManager.cpp
diff options
context:
space:
mode:
authorVakhurin Sergei <igelbox@gmail.com>2024-09-16 17:30:53 +0300
committerGitHub <noreply@github.com>2024-09-16 10:30:53 -0400
commite5d255607d200f59c5f7474b8dde6fe72d53e348 (patch)
treea2571bb25a7bb6f95f2fb470dcb802bddd15a137 /clang/lib/Basic/SourceManager.cpp
parente6618aae43012d3759f326ac6527744885825331 (diff)
downloadllvm-e5d255607d200f59c5f7474b8dde6fe72d53e348.zip
llvm-e5d255607d200f59c5f7474b8dde6fe72d53e348.tar.gz
llvm-e5d255607d200f59c5f7474b8dde6fe72d53e348.tar.bz2
Fix OOM in FormatDiagnostic (#108187)
Resolves: #70930 (and probably latest comments from https://github.com/clangd/clangd/issues/251) by fixing racing for the shared `DiagStorage` value which caused messing with args inside the storage and then formatting the following message with `getArgSInt(1)` == 2: ``` def err_module_odr_violation_function : Error< "%q0 has different definitions in different modules; " "%select{definition in module '%2'|defined here}1 " "first difference is " ``` which causes `HandleSelectModifier` to go beyond the `ArgumentLen` so the recursive call to `FormatDiagnostic` was made with `DiagStr` > `DiagEnd` that leads to infinite `while (DiagStr != DiagEnd)`. **The Main Idea:** Reuse the existing `DiagStorageAllocator` logic to make all `DiagnosticBuilder`s having independent states. Also, encapsulating the rest of state (e.g. ID and Loc) into `DiagnosticBuilder`. **TODO (if it will be requested by reviewer):** - [x] add a test (I have no idea how to turn a whole bunch of my proprietary code which leads `clangd` to OOM into a small public example.. probably I must try using [this](https://github.com/llvm/llvm-project/issues/70930#issuecomment-2209872975) instead) - [x] [`Diag.CurDiagID != diag::fatal_too_many_errors`](https://github.com/llvm/llvm-project/pull/108187#pullrequestreview-2296395489) - [ ] ? get rid of `DiagStorageAllocator` at all and make `DiagnosticBuilder` having they own `DiagnosticStorage` coz it seems pretty small so should fit the stack for short-living `DiagnosticBuilder` instances
Diffstat (limited to 'clang/lib/Basic/SourceManager.cpp')
-rw-r--r--clang/lib/Basic/SourceManager.cpp23
1 files changed, 4 insertions, 19 deletions
diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp
index d6ec26a..65a8a72 100644
--- a/clang/lib/Basic/SourceManager.cpp
+++ b/clang/lib/Basic/SourceManager.cpp
@@ -130,13 +130,8 @@ ContentCache::getBufferOrNone(DiagnosticsEngine &Diag, FileManager &FM,
// the file could also have been removed during processing. Since we can't
// really deal with this situation, just create an empty buffer.
if (!BufferOrError) {
- if (Diag.isDiagnosticInFlight())
- Diag.SetDelayedDiagnostic(diag::err_cannot_open_file,
- ContentsEntry->getName(),
- BufferOrError.getError().message());
- else
- Diag.Report(Loc, diag::err_cannot_open_file)
- << ContentsEntry->getName() << BufferOrError.getError().message();
+ Diag.Report(Loc, diag::err_cannot_open_file)
+ << ContentsEntry->getName() << BufferOrError.getError().message();
return std::nullopt;
}
@@ -153,12 +148,7 @@ ContentCache::getBufferOrNone(DiagnosticsEngine &Diag, FileManager &FM,
// ContentsEntry::getSize() could have the wrong size. Use
// MemoryBuffer::getBufferSize() instead.
if (Buffer->getBufferSize() >= std::numeric_limits<unsigned>::max()) {
- if (Diag.isDiagnosticInFlight())
- Diag.SetDelayedDiagnostic(diag::err_file_too_large,
- ContentsEntry->getName());
- else
- Diag.Report(Loc, diag::err_file_too_large)
- << ContentsEntry->getName();
+ Diag.Report(Loc, diag::err_file_too_large) << ContentsEntry->getName();
return std::nullopt;
}
@@ -168,12 +158,7 @@ ContentCache::getBufferOrNone(DiagnosticsEngine &Diag, FileManager &FM,
// have come from a stat cache).
if (!ContentsEntry->isNamedPipe() &&
Buffer->getBufferSize() != (size_t)ContentsEntry->getSize()) {
- if (Diag.isDiagnosticInFlight())
- Diag.SetDelayedDiagnostic(diag::err_file_modified,
- ContentsEntry->getName());
- else
- Diag.Report(Loc, diag::err_file_modified)
- << ContentsEntry->getName();
+ Diag.Report(Loc, diag::err_file_modified) << ContentsEntry->getName();
return std::nullopt;
}