"Buffer is not null terminated" when using libTooling

I am trying to using clang::Rewriter to modify a large cpp code base, but I ran into this assertion error

void llvm::MemoryBuffer::init(const char*, const char*, bool): Assertion `(!RequiresNullTerminator || BufEnd[0] == 0) && "Buffer is not null terminated!"' failed.

the backtrace looks like this:


#0  __pthread_kill_implementation (no_tid=0, signo=6, threadid=140737347022976) at ./nptl/pthread_kill.c:44
#1  __pthread_kill_internal (signo=6, threadid=140737347022976) at ./nptl/pthread_kill.c:78
#2  __GI___pthread_kill (threadid=140737347022976, signo=signo@entry=6) at ./nptl/pthread_kill.c:89
#3  0x00007ffff797a476 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#4  0x00007ffff79607f3 in __GI_abort () at ./stdlib/abort.c:79
#5  0x00007ffff796071b in __assert_fail_base (fmt=0x7ffff7b15150 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", 
    assertion=0x555559638df0 "(!RequiresNullTerminator || BufEnd[0] == 0) && \"Buffer is not null terminated!\"", 
    file=0x555559638da8 "/home/***/apps/llvm-project/llvm/lib/Support/MemoryBuffer.cpp", line=51, function=<optimized out>) at ./assert/assert.c:92
#6  0x00007ffff7971e96 in __GI___assert_fail (assertion=0x555559638df0 "(!RequiresNullTerminator || BufEnd[0] == 0) && \"Buffer is not null terminated!\"", 
    file=0x555559638da8 "/home/***/apps/llvm-project/llvm/lib/Support/MemoryBuffer.cpp", line=51, 
    function=0x555559638d68 "void llvm::MemoryBuffer::init(const char*, const char*, bool)") at ./assert/assert.c:101
#7  0x0000555555c984d3 in llvm::MemoryBuffer::init (this=0x55555d6b52c0, 
    BufStart=0x7ffff773e000 "/*\n  Formatting library for C++\n\n  Copyright (c) 2012 - present, Victor Zverovich\n\n  Permission is hereby granted, free of charge, to any person obtaining\n  a copy of this software and associated docu"..., 
    BufEnd=0x7ffff778c27e "xt>\n  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {instrumentor(\"fmt::dynamic_formatter::parse,auto (ParseContext &) -> decltype(ctx.begin())\")..., RequiresNullTerminator=true)
    at /home/***/apps/llvm-project/llvm/lib/Support/MemoryBuffer.cpp:51
#8  0x0000555555c9ad14 in (anonymous namespace)::MemoryBufferMMapFile<llvm::MemoryBuffer>::MemoryBufferMMapFile (this=0x55555d6b52c0, RequiresNullTerminator=true, 
    FD=4, Len=320126, Offset=0, EC=std::error_code = {std::_V2::error_category: 0}) at /home/***/apps/llvm-project/llvm/lib/Support/MemoryBuffer.cpp:217
#9  0x0000555555c9a389 in getOpenFileImpl<llvm::MemoryBuffer> (FD=4, Filename=..., FileSize=320126, MapSize=320126, Offset=0, RequiresNullTerminator=true, 
    IsVolatile=false, Alignment=std::optional<llvm::Align> [no contained value]) at /home/***/apps/llvm-project/llvm/lib/Support/MemoryBuffer.cpp:480
#10 0x0000555555c9984d in llvm::MemoryBuffer::getOpenFile (FD=4, Filename=..., FileSize=320126, RequiresNullTerminator=true, IsVolatile=false, 
    Alignment=std::optional<llvm::Align> [no contained value]) at /home/***/apps/llvm-project/llvm/lib/Support/MemoryBuffer.cpp:524
#11 0x0000555555be347b in (anonymous namespace)::RealFile::getBuffer (this=0x55555c4b35a0, Name=..., FileSize=320126, RequiresNullTerminator=true, IsVolatile=false)
    at /home/***/apps/llvm-project/llvm/lib/Support/VirtualFileSystem.cpp:230
#12 0x0000555555be29d5 in llvm::vfs::FileSystem::getBufferForFile (this=0x55555c309270, Name=..., FileSize=320126, RequiresNullTerminator=true, IsVolatile=false)
    at /home/***/apps/llvm-project/llvm/lib/Support/VirtualFileSystem.cpp:124
#13 0x0000555556501440 in clang::FileManager::getBufferForFileImpl (this=0x55555c35a5a0, Filename=..., FileSize=320126, isVolatile=false, 
    RequiresNullTerminator=true) at /home/***/apps/llvm-project/clang/lib/Basic/FileManager.cpp:571
#14 0x000055555650133e in clang::FileManager::getBufferForFile (this=0x55555c35a5a0, Entry=0x55555ca44218, isVolatile=false, RequiresNullTerminator=true)
    at /home/***/apps/llvm-project/clang/lib/Basic/FileManager.cpp:562
#15 0x0000555556541b08 in clang::SrcMgr::ContentCache::getBufferOrNone (this=0x55555d579938, Diag=..., FM=..., Loc=...)
    at /home/***/apps/llvm-project/clang/lib/Basic/SourceManager.cpp:117
#16 0x0000555555d544d1 in clang::SourceManager::getBufferOrNone (this=0x55555c383990, FID=..., Loc=...)
    at /home/***/apps/llvm-project/clang/include/clang/Basic/SourceManager.h:1029
#17 0x00005555594b4a23 in clang::Preprocessor::EnterSourceFile (this=0x55555c368750, FID=..., CurDir=..., Loc=..., IsFirstIncludeOfFile=true)
    at /home/***/apps/llvm-project/clang/lib/Lex/PPLexerChange.cpp:80
#18 0x00005555594a84de in clang::Preprocessor::HandleHeaderIncludeOrImport (this=0x55555c368750, HashLoc=..., IncludeTok=..., FilenameTok=..., EndLoc=..., 
    LookupFrom=..., LookupFromFile=0x0) at /home/***/apps/llvm-project/clang/lib/Lex/PPDirectives.cpp:2518
#19 0x00005555594a5a46 in clang::Preprocessor::HandleIncludeDirective (this=0x55555c368750, HashLoc=..., IncludeTok=..., LookupFrom=..., LookupFromFile=0x0)
    at /home/***/apps/llvm-project/clang/lib/Lex/PPDirectives.cpp:1959
#20 0x00005555594a2ddf in clang::Preprocessor::HandleDirective (this=0x55555c368750, Result=...)
    at /home/***/apps/llvm-project/clang/lib/Lex/PPDirectives.cpp:1220
#21 0x000055555945e907 in clang::Lexer::LexTokenInternal (this=0x55555d7157a0, Result=..., TokAtPhysicalStartOfLine=true)
    at /home/***/apps/llvm-project/clang/lib/Lex/Lexer.cpp:4362
--Type <RET> for more, q to quit, c to continue without paging--c
#22 0x000055555945bbcb in clang::Lexer::Lex (this=0x55555d7157a0, Result=...) at /home/***/apps/llvm-project/clang/lib/Lex/Lexer.cpp:3576
#23 0x00005555594ee58f in clang::Preprocessor::Lex (this=0x55555c368750, Result=...) at /home/***/apps/llvm-project/clang/lib/Lex/Preprocessor.cpp:891
#24 0x0000555556b21785 in clang::Parser::ConsumeBrace (this=0x55555d0dee50) at /home/***/apps/llvm-project/clang/include/clang/Parse/Parser.h:646
#25 0x0000555556b22fe5 in clang::BalancedDelimiterTracker::consumeClose (this=0x7fffffffc4d0) at /home/***/apps/llvm-project/clang/include/clang/Parse/RAIIObjectsForParser.h:464
#26 0x0000555556b6026b in clang::Parser::ParseInnerNamespace (this=0x55555d0dee50, InnerNSs=..., index=0, InlineLoc=..., attrs=..., Tracker=...) at /home/***/apps/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp:266
#27 0x0000555556b5fff2 in clang::Parser::ParseNamespace (this=0x55555d0dee50, Context=clang::DeclaratorContext::File, DeclEnd=..., InlineLoc=...) at /home/***/apps/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp:238
#28 0x0000555556b3950e in clang::Parser::ParseDeclaration (this=0x55555d0dee50, Context=clang::DeclaratorContext::File, DeclEnd=..., DeclAttrs=..., DeclSpecAttrs=..., DeclSpecStart=0x0) at /home/***/apps/llvm-project/clang/lib/Parse/ParseDecl.cpp:1838
#29 0x0000555556b169b6 in clang::Parser::ParseExternalDeclaration (this=0x55555d0dee50, Attrs=..., DeclSpecAttrs=..., DS=0x0) at /home/***/apps/llvm-project/clang/lib/Parse/Parser.cpp:959
#30 0x0000555556b15d63 in clang::Parser::ParseTopLevelDecl (this=0x55555d0dee50, Result=..., ImportState=@0x7fffffffcb64: clang::Sema::ModuleImportState::NotACXX20Module) at /home/***/apps/llvm-project/clang/lib/Parse/Parser.cpp:745
#31 0x0000555556b10ee4 in clang::ParseAST (S=..., PrintStats=false, SkipFunctionBodies=false) at /home/***/apps/llvm-project/clang/lib/Parse/ParseAST.cpp:162
#32 0x0000555556610855 in clang::ASTFrontendAction::ExecuteAction (this=0x55555c8ca880) at /home/***/apps/llvm-project/clang/lib/Frontend/FrontendAction.cpp:1168
#33 0x0000555556610104 in clang::FrontendAction::Execute (this=0x55555c8ca880) at /home/***/apps/llvm-project/clang/lib/Frontend/FrontendAction.cpp:1058
#34 0x00005555566794af in clang::CompilerInstance::ExecuteAction (this=0x7fffffffce00, Act=...) at /home/***/apps/llvm-project/clang/lib/Frontend/CompilerInstance.cpp:1049
#35 0x0000555556af784b in clang::tooling::FrontendActionFactory::runInvocation (this=0x55555c35ee70, Invocation=std::shared_ptr<clang::CompilerInvocation> (empty) = {...}, Files=0x55555c35a5a0, PCHContainerOps=std::shared_ptr<clang::PCHContainerOperations> (empty) = {...}, DiagConsumer=0x55555c248020 <ignore_diagnostics_consumer>) at /home/***/apps/llvm-project/clang/lib/Tooling/Tooling.cpp:434
#36 0x0000555556af7675 in clang::tooling::ToolInvocation::runInvocation (this=0x7fffffffd5e0, BinaryName=0x55555d6bb050 "/usr/bin/c++", Compilation=0x55555c3a6970, Invocation=std::shared_ptr<clang::CompilerInvocation> (empty) = {...}, PCHContainerOps=std::shared_ptr<clang::PCHContainerOperations> (empty) = {...}) at /home/***/apps/llvm-project/clang/lib/Tooling/Tooling.cpp:409
#37 0x0000555556af7470 in clang::tooling::ToolInvocation::run (this=0x7fffffffd5e0) at /home/***/apps/llvm-project/clang/lib/Tooling/Tooling.cpp:394
#38 0x0000555556af8d3c in clang::tooling::ClangTool::run (this=0x7fffffffd790, Action=0x55555c35ee70) at /home/***/apps/llvm-project/clang/lib/Tooling/Tooling.cpp:588
#39 0x0000555555ae8a85 in main (argc=3, argv=0x7fffffffdac8) at /home/***/apps/llvm-project/clang-tools-extra/my-clang-preprocessor/src/main.cpp:277
(gdb) 

looking into the gdb and the only thing I found confusing is the ContentsEntry variable in ContentCache::getBufferOrNone has incorrect Size (less than actual file size)

I suspect that it might be due to incorrect usage of rewriter.overwriteChangedFiles(). Once I commented it out, the code works. So I guess the rewriter might be writing to the file (a #include’ed header, thus changing the file size, but the clangTools somehow still caches the origianl file size.

Can I have a clue (e.g., did I mess up the timing to modify a #include’ed header)?