From ce328ca3cafdc3f4e9166a581b8882b5e4962167 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 21 Jun 2019 20:46:22 +0000 Subject: [PATCH] PR42301: Abort cleanly if we encounter a huge source file rather than crashing. Ideally we wouldn't care about the size of a file so long as it fits in memory, but in practice we have lots of hardocded assumptions that unsigned can be used to index files, string literals, and so on. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@364103 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticCommonKinds.td | 2 ++ lib/Basic/SourceManager.cpp | 25 ++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index 52ab4b8ad3..776d16bd54 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -268,6 +268,8 @@ def err_opt_not_valid_on_target : Error< def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal; def err_file_modified : Error< "file '%0' modified since it was first processed">, DefaultFatal; +def err_file_too_large : Error< + "sorry, unsupported: file '%0' is too large for Clang to process">; def err_unsupported_bom : Error<"%0 byte order mark detected in '%1', but " "encoding is not supported">, DefaultFatal; def err_unable_to_rename_temp : Error< diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index e62cef7ec5..8d56b19b10 100644 --- a/lib/Basic/SourceManager.cpp +++ b/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::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); -- 2.40.0