Skip to content

Commit 85cd3d9

Browse files
authored
Work around documented Linux mmap bug. (#152595)
On Linux, mmap doesn't always zero-fill slack bytes ([man page]), despite being required to do so by POSIX. If the final page of a file is in the page cache and the bytes past the end of the file get overwritten by some process, those bytes then remain non-zero until the page falls out of the cache or another process overwrites them. Stop trusting that mmap behaves properly and instead check whether the buffer was indeed properly terminated. If not, fall back to using `read` to read the file contents. This fixes an obscure clang crash bug that can occur if another program (such as an editor) mmap's a source file and writes past the end of the mmap'd region shortly before clang or clangd attempts to parse the file. [man page]: https://man7.org/linux/man-pages/man2/mmap.2.html#BUGS
1 parent 36d31b0 commit 85cd3d9

File tree

1 file changed

+8
-2
lines changed

1 file changed

+8
-2
lines changed

llvm/lib/Support/MemoryBuffer.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -501,8 +501,14 @@ getOpenFileImpl(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize,
501501
std::unique_ptr<MB> Result(
502502
new (NamedBufferAlloc(Filename)) MemoryBufferMMapFile<MB>(
503503
RequiresNullTerminator, FD, MapSize, Offset, EC));
504-
if (!EC)
505-
return std::move(Result);
504+
if (!EC) {
505+
// On at least Linux, and possibly on other systems, mmap may return pages
506+
// from the page cache that are not properly filled with trailing zeroes,
507+
// if some prior user of the page wrote non-zero bytes. Detect this and
508+
// don't use mmap in that case.
509+
if (!RequiresNullTerminator || *Result->getBufferEnd() == '\0')
510+
return std::move(Result);
511+
}
506512
}
507513

508514
#ifdef __MVS__

0 commit comments

Comments
 (0)