Skip to content

Commit 979ae80

Browse files
committed
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. llvm-svn: 364103
1 parent 5050a8d commit 979ae80

File tree

2 files changed

+27
-0
lines changed

2 files changed

+27
-0
lines changed

clang/include/clang/Basic/DiagnosticCommonKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,8 @@ def err_opt_not_valid_on_target : Error<
268268
def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal;
269269
def err_file_modified : Error<
270270
"file '%0' modified since it was first processed">, DefaultFatal;
271+
def err_file_too_large : Error<
272+
"sorry, unsupported: file '%0' is too large for Clang to process">;
271273
def err_unsupported_bom : Error<"%0 byte order mark detected in '%1', but "
272274
"encoding is not supported">, DefaultFatal;
273275
def err_unable_to_rename_temp : Error<

clang/lib/Basic/SourceManager.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,31 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag,
108108
return Buffer.getPointer();
109109
}
110110

111+
// Check that the file's size fits in an 'unsigned' (with room for a
112+
// past-the-end value). This is deeply regrettable, but various parts of
113+
// Clang (including elsewhere in this file!) use 'unsigned' to represent file
114+
// offsets, line numbers, string literal lengths, and so on, and fail
115+
// miserably on large source files.
116+
if (ContentsEntry->getSize() >= std::numeric_limits<unsigned>::max()) {
117+
// We can't make a memory buffer of the required size, so just make a small
118+
// one. We should never hit a situation where we've already parsed to a
119+
// later offset of the file, so it shouldn't matter that the buffer is
120+
// smaller than the file.
121+
Buffer.setPointer(
122+
llvm::MemoryBuffer::getMemBuffer("", ContentsEntry->getName())
123+
.release());
124+
if (Diag.isDiagnosticInFlight())
125+
Diag.SetDelayedDiagnostic(diag::err_file_too_large,
126+
ContentsEntry->getName());
127+
else
128+
Diag.Report(Loc, diag::err_file_too_large)
129+
<< ContentsEntry->getName();
130+
131+
Buffer.setInt(Buffer.getInt() | InvalidFlag);
132+
if (Invalid) *Invalid = true;
133+
return Buffer.getPointer();
134+
}
135+
111136
bool isVolatile = SM.userFilesAreVolatile() && !IsSystemFile;
112137
auto BufferOrError =
113138
SM.getFileManager().getBufferForFile(ContentsEntry, isVolatile);

0 commit comments

Comments
 (0)