aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Basic/SourceManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Basic/SourceManager.cpp')
-rw-r--r--clang/lib/Basic/SourceManager.cpp25
1 files changed, 25 insertions, 0 deletions
diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp
index e62cef7..8d56b19 100644
--- a/clang/lib/Basic/SourceManager.cpp
+++ b/clang/lib/Basic/SourceManager.cpp
@@ -108,6 +108,31 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag,
return Buffer.getPointer();
}
+ // Check that the file's size fits in an 'unsigned' (with room for a
+ // past-the-end value). This is deeply regrettable, but various parts of
+ // Clang (including elsewhere in this file!) use 'unsigned' to represent file
+ // offsets, line numbers, string literal lengths, and so on, and fail
+ // miserably on large source files.
+ if (ContentsEntry->getSize() >= std::numeric_limits<unsigned>::max()) {
+ // We can't make a memory buffer of the required size, so just make a small
+ // one. We should never hit a situation where we've already parsed to a
+ // later offset of the file, so it shouldn't matter that the buffer is
+ // smaller than the file.
+ Buffer.setPointer(
+ llvm::MemoryBuffer::getMemBuffer("", ContentsEntry->getName())
+ .release());
+ if (Diag.isDiagnosticInFlight())
+ Diag.SetDelayedDiagnostic(diag::err_file_too_large,
+ ContentsEntry->getName());
+ else
+ Diag.Report(Loc, diag::err_file_too_large)
+ << ContentsEntry->getName();
+
+ Buffer.setInt(Buffer.getInt() | InvalidFlag);
+ if (Invalid) *Invalid = true;
+ return Buffer.getPointer();
+ }
+
bool isVolatile = SM.userFilesAreVolatile() && !IsSystemFile;
auto BufferOrError =
SM.getFileManager().getBufferForFile(ContentsEntry, isVolatile);