RewriteRope.cpp assertion: Assertion `getPiece(StartPiece).size() > NumBytes' failed.

Get

/home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/Rewrite/Core/RewriteRope.cpp:377: void {anonymous}::RopePieceBTreeLeaf::erase(unsigned int, unsigned int): Assertion `getPiece(StartPiece).size() > NumBytes’ failed.
Abort

Are there any known issues here (or a possible bug in my replacement code) :

(gdb) where
#0 0x00002aaaab4b2f45 in raise () from /lib64/libc.so.6
#1 0x00002aaaab4b4340 in abort () from /lib64/libc.so.6
#2 0x00002aaaab4ac486 in __assert_fail () from /lib64/libc.so.6
#3 0x0000000000cc32de in (anonymous namespace)::RopePieceBTreeNode::erase(unsigned int, unsigned int) ()
#4 0x0000000000cc4e9b in clang::RewriteBuffer::ReplaceText(unsigned int, unsigned int, llvm::StringRef) ()
#5 0x0000000000cc6c36 in clang::Rewriter::ReplaceText(clang::SourceLocation, unsigned int, llvm::StringRef) ()
#6 0x0000000000cb3f5a in clang::tooling::Replacement::apply(clang::Rewriter&) const ()
#7 0x0000000000cb569e in clang::tooling::applyAllReplacements(std::set<clang::tooling::Replacement, clang::tooling::Replacement::Less, std::allocatorclang::tooling::Replacement >&, clang::Rewriter&) ()
#8 0x0000000000cb5c01 in clang::tooling::RefactoringTool::runAndSave(clang::tooling::FrontendActionFactory*) ()
#9 0x0000000000417d89 in main (argc=2, argv=0x7fffffffcfa8) at RenameMethod.cpp:301
(gdb)

Here’s more info:

RenameMethod: /home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/Rewrite/Core/RewriteRope.cpp:377: void {anonymous}::RopePieceBTreeLeaf::erase(unsigned int, unsigned int): Assertion `getPiece(StartPiece).size() > NumBytes’ failed.

stack:

Program received signal SIGABRT, Aborted.
0x00002aaaab4b2f45 in raise () from /lib64/libc.so.6
(gdb) where
#0 0x00002aaaab4b2f45 in raise () from /lib64/libc.so.6
#1 0x00002aaaab4b4340 in abort () from /lib64/libc.so.6
#2 0x00002aaaab4ac486 in __assert_fail () from /lib64/libc.so.6
#3 0x0000000000f66751 in (anonymous namespace)::RopePieceBTreeLeaf::erase (this=0x3675550, Offset=50490, NumBytes=4294951421)
at /home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/Rewrite/Core/RewriteRope.cpp:377
#4 0x0000000000f67114 in (anonymous namespace)::RopePieceBTreeNode::erase (this=0x3675550, Offset=50490, NumBytes=4294951421)
at /home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/Rewrite/Core/RewriteRope.cpp:652
#5 0x0000000000f6764d in clang::RopePieceBTree::erase (this=0x64a8480, Offset=50490, NumBytes=4294951421)
at /home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/Rewrite/Core/RewriteRope.cpp:755
#6 0x0000000000f6a5bb in clang::RewriteRope::erase(unsigned int, unsigned int) ()
#7 0x0000000000f684fb in clang::RewriteBuffer::ReplaceText (this=0x64a8478, OrigOffset=50501, OrigLength=4294951421, NewStr=…)
at /home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/Rewrite/Core/Rewriter.cpp:111
#8 0x0000000000f692ab in clang::Rewriter::ReplaceText (this=0x7fffffffc3b0, Start=…, OrigLength=4294951421, NewStr=…)
at /home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/Rewrite/Core/Rewriter.cpp:309
#9 0x0000000000f5db27 in clang::tooling::Replacement::apply (this=0x63ea2c0, Rewrite=…)
at /home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/Tooling/Refactoring.cpp:69
#10 0x0000000000f5dfc4 in clang::tooling::applyAllReplacements (Replaces=…, Rewrite=…)
at /home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/Tooling/Refactoring.cpp:130
#11 0x0000000000f5e2c0 in clang::tooling::RefactoringTool::applyAllReplacements (this=0x7fffffffcc98, Rewrite=…)
at /home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/Tooling/Refactoring.cpp:166
#12 0x0000000000f5e1fa in clang::tooling::RefactoringTool::runAndSave (this=0x7fffffffcc98, ActionFactory=0x1c50af0)
at /home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/Tooling/Refactoring.cpp:158
#13 0x0000000000421305 in main (argc=2, argv=0x7fffffffcfd8) at RenameMethod.cpp:341

The sizes being compared:

#3 0x0000000000f66761 in (anonymous namespace)::RopePieceBTreeLeaf::erase (this=0x3675550, Offset=50490, NumBytes=4294951421)
at /home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/Rewrite/Core/RewriteRope.cpp:377
377 assert(getPiece(StartPiece).size() > NumBytes);
(gdb) p NumBytes
$1 = 4294951421
(gdb) p /x NumBytes
$2 = 0xffffc1fd
(gdb) p getPiece(StartPiece).size()
$3 = 10836

Looks like some code somewhat allows NumBytes is effectively negative. That goes back to the object creation:

(gdb) frame 9
#9 0x0000000000f5db37 in clang::tooling::Replacement::apply (this=0x63ea2c0, Rewrite=…)
at /home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/Tooling/Refactoring.cpp:69
69 bool RewriteSucceeded = !Rewrite.ReplaceText(Start, Length, ReplacementText);
(gdb) p *this
$7 = {FilePath = {static npos = ,
_M_dataplus = {<std::allocator> = {<__gnu_cxx::new_allocator> = {}, },
_M_p = 0x4ac9cb8 “/view/peeterj_clang8/vbs/engn/include/sqloOSResourceTrack.h”}}, Offset = 50501, Length = 4294951421, ReplacementText = {
static npos = , _M_dataplus = {<std::allocator> = {<__gnu_cxx::new_allocator> = {}, },
_M_p = 0x6466b98 “&g_pOSResourceTracked”}}}

I’m assuming that this Length isn’t the replacement length, but is the source range of the text to replace. That’s calculated in this code as:

virtual void run(const MatchFinder::MatchResult &Result) {
const CallExpr *M = Result.Nodes.getStmtAs(“x”);
const Expr * a = M->getArg( 3 ) ;

if ( const CStyleCastExpr * v = dyn_cast( a ) )
{
const Expr * theCastedValue = v->getSubExprAsWritten() ;

if ( theCastedValue )
{
std::string replacement = decl2str( theCastedValue, Result.SourceManager ) ;

if ( replacement.length() )
{
SourceLocation start = v->getLocStart() ;
SourceLocation end = v->getLocEnd() ;
CharSourceRange range = CharSourceRange::getTokenRange( SourceRange(start, end) ) ;

Replace->insert(
Replacement(*Result.SourceManager,
range,
replacement));
}
}

somehow this has led to a negative length in the Replacement() object.

It looks like the code that’s blowing up here is:

// FIXME: This should go into the Lexer, but we need to figure out how
// to handle ranges for refactoring in general first - there is no obvious
// good way how to integrate this into the Lexer yet.
static int getRangeSize(SourceManager &Sources, const CharSourceRange &Range) {
SourceLocation SpellingBegin = Sources.getSpellingLoc(Range.getBegin());
SourceLocation SpellingEnd = Sources.getSpellingLoc(Range.getEnd());
std::pair<FileID, unsigned> Start = Sources.getDecomposedLoc(SpellingBegin);
std::pair<FileID, unsigned> End = Sources.getDecomposedLoc(SpellingEnd);
if (Start.first != End.first) return -1;
if (Range.isTokenRange())
End.second += Lexer::MeasureTokenLength(SpellingEnd, Sources,
LangOptions());
return End.second - Start.second;
}

(gdb) c
Continuing.
r: &g_pOSResourceTracked

Breakpoint 2, clang::tooling::getRangeSize (Sources=…, Range=…)
at /home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/Tooling/Refactoring.cpp:111
111 if (Range.isTokenRange())
(gdb) p Start
$16 = {first = {ID = 102780}, second = 50501}
(gdb) p End
$17 = {first = {ID = 102780}, second = 34606}
(gdb) n
113 LangOptions());
(gdb) n
114 return End.second - Start.second;
(gdb) p End
$18 = {first = {ID = 102780}, second = 34626}
(gdb) p End.second - Start.second
$19 = 4294951421

The Lexer:: addition added 20 bytes, but something is out of sync with this method of getting the source location range:

SourceLocation start = v->getLocStart() ;
SourceLocation end = v->getLocEnd() ;

Here v is a CStyleCastExpr object.

Hi,

Get

/home/hotellnx94/peeterj/clang/sources/llvm/tools/clang/lib/Rewrite/Core/RewriteRope.cpp:377:
void {anonymous}::RopePieceBTreeLeaf::erase(unsigned int, unsigned int):
Assertion `getPiece(StartPiece).size() > NumBytes' failed.
Abort

Are there any known issues here (or a possible bug in my replacement code) :

The issue is maybe the way you are using the Replacements class. Are you rewriting multiple time the same location? Do you have any overlap in your replacements? Do you call applyAllReplacements() multiple time with different replacements?

All these practices are likely to fail. I feel that if the Replacement were based on SourceRange and SourceLocation instead of File/Offset/Length it would help handling these "complex" situations.

Mehdi