FullSourceLoc, getSpellingLineNumber segmentation fault

Hi,

Does somebody know what can make the method getSpellingLineNumber from FullSourceLoc to generate a segmentation fault? I’m using clang 3.6.

http://clang.llvm.org/doxygen/classclang_1_1FullSourceLoc.html#a52927fcf23cf662c209e5e996bf59917

Before using this method, I have checked that the FullSourceLoc is valid. This is the code:

if(loc.isValid()){

if(!(loc.getFileID().isInvalid())){

if(Context->getSourceManager().getFileEntryForID(loc.getFileID()) != NULL){

unsigned int = loc.getSpellingLineNumber();
}
}
}

I can’t find anything special in the code which I’m using to check if my program works:

void DeleteNode( XMLNode* node ) {
node->_parent->DeleteChild( node );
}

And this is the tree:

-CXXMethodDecl 0x26b4090 <line:1576:5, line:1578:5> line:1576:10 DeleteNode ‘void (class tinyxml2::XMLNode *)’

-ParmVarDecl 0x26b4010 <col:22, col:31> col:31 used node ‘class tinyxml2::XMLNode *’
-CompoundStmt 0x26c9500 <col:38, line:1578:5>
`-CXXMemberCallExpr 0x26c94b8 <line:1577:9, col:42> ‘void’

-MemberExpr 0x26c9460 <col:9, col:24> ‘’ ->DeleteChild 0x2699420
-ImplicitCastExpr 0x26c9448 <col:9, col:15> 'class tinyxml2::XMLNode *' <LValueToRValue> -MemberExpr 0x26c9418 <col:9, col:15> ‘class tinyxml2::XMLNode *’ lvalue ->_parent 0x269a310
-ImplicitCastExpr 0x26c9400 <col:9> 'class tinyxml2::XMLNode *' <LValueToRValue> -DeclRefExpr 0x26c93d8 col:9 ‘class tinyxml2::XMLNode *’ lvalue ParmVar 0x26b4010 ‘node’ ‘class tinyxml2::XMLNode *’

The object “loc” contains the location of the MemberExpr “_parent”.

Thanks.

Hi,

I used to face a lot of crashes on this method, it would usually explode at some #SSE2 code in a static method called ComputeLineNumbers inside clang.

Are you using virtual files? Are you generating the AST more than once (I mean, calling Tool.BuildAST() more than once)?

I don’t quite remember how I fixed, but I think those two might have something to do with the problem.

Cheers,

Hi Mikhail,

Well, let me explain you what I’m doing:

  1. I’m using LibTooling, so I run the tool “Tool.run()” to start the traveral of the AST.
  2. At one point during the execution, I need to know some information about the AST, so I call “TraverseDecl” and the AST is visited recursively with VisitMemberExpr.

By doing this, I’m calling internally to Tool.BuildAST() twice, right? I think I’m not using virtual files.

So, what can I do? The thing is that I don’t know when a call to this method is going to crash.

Maybe, should I look first in the AST if the MemberExpr has a parent CXXMemberCallExpr?

Thanks.

Hi again,

I have carried out what I told you about taking the CXXMemberCallExpr node before calling “getSpellingLineNumber” (in case there is a parent of the MemberExpr object of this type). That worked, but I’m in doubt because I don’t know wether this “patch” scales or not for other programs. Furthermore, I don’t know if I should take care of other similar situations…

Oh sorry! Forget about the previous message. It is not working (I had commented the line where getSpellingLineNumber was called). I definitely don’t know how to sort out this issue. The problem is that the tool crashes when reaching that point: is there something I can do so that, at least, the tool doesn’t crash?

Thanks and sorry again.

Hello,

I finally found the two commits the “fixed” the crashes, the first one might help you:

  1. Use PresumedLoc instead of FullSourceLoc

Basically, it’s the code used in ASTDumper.

I have something like:

sm = &ASTContext->getSourceManager();

if(!sm)
return;

clang::SourceLocation SpellingLoc = sm->getSpellingLoc(decl.getSourceRange().getBegin());
clang::PresumedLoc &PLoc = sm->getPresumedLoc(SpellingLoc);

if (PLoc.isInvalid()) {
location.set_file("");
return;
}

location.set_line(PLoc.getLine());
location.set_file(PLoc.getFilename());

where:

sm is a clang::SourceManager *sm;
ASTContext is a clang::ASTContext *ASTContext;
location is an internal class that holds location information.

One minor note is to always update your ASTContext (in your case, the object Context), since it changes from translation unit.

Thank you very much. Bad news, Mikhail. I tried your fix and it doesn’t work by the moment. The problem is in this line:

PresumedLoc PLoc = sm.getPresumedLoc(SpellingLoc)

(note: the compiler gave me an error when I put PresumedLoc& PLoc, so I just delete &).

Just to discard that other things could be causing the problem, I have attempted the following:

  • I don’t call to HandleTranslationUnit before doing this, so the AST is not traversed twice.

  • Instead of taking a MemberExpr, I have tried with a Stmt and a CXXMethodDecl. The same. However, taking the CXXRecordDecl that nested the statement and the method does worked.

  • I have tried to assign the ASTContext as in the ASTDumper:

ASTContext &Ctx = cast(DC)->getASTContext();
This was even worse. Failed directly in:

SourceLocation SpellingLoc = sm.getSpellingLoc(FS->getSourceRange().getBegin());

Anyway, I’m using ASTMatchers, so I update the ASTContext in each match:

void System::run(const MatchFinder::MatchResult &Result) {
Context = Result.Context; (Context is a field of the class System declared as ASTContext *Context;)

}

  • I have also tried to check that the object “SpellingLoc” wasn’t invalid:

if(SpellingLoc.isValid()){
PresumedLoc PLoc = sm.getPresumedLoc(SpellingLoc);
}

The SpellingLoc object , however, is valid.

Sincerely, I don’t know what else to try. This is the code as I have it right now:

void System::run(const MatchFinder::MatchResult &Result) {
Context = Result.Context;

const Stmt *FS = 0;
if( FS = Result.Nodes.getNodeAsclang::Stmt(“statement”)){

SourceManager& sm = Context->getSourceManager();
SourceLocation SpellingLoc = sm.getSpellingLoc(FS->getSourceRange().getBegin());

if(SpellingLoc.isValid()){
PresumedLoc PLoc = sm.getPresumedLoc(SpellingLoc);

if (!PLoc.isInvalid()) {
std::pair<unsigned, const char *> location =
std::pair<unsigned, const char *>(PLoc.getLine(), PLoc.getFilename());

getCoverage(location);
}
}
}
}

Perhaps something in the code of the program that I’m using to check this impedes the correct generation of the AST…

I’m sorry to hear that it didn’t help.

My last advice would be to update to clang 3.7 (or 3.8, when it’s released). I know that this can create a whole new set of problems but it’s the only possible solution I can find.

Since I moved to 3.8, clang has been a lot more stable.

Thank you,

OMG. After long hours trying to figure out what was going on, I applied my system to other C++ programs and the system worked perfectly. So, once I knew that the problem was in the C++ program I was using to check my system:

  1. I decided to create a new application from scratch with the minimum. This new application worked when I run it in the C++ program.

  2. I did the contrary: starting from the complete application, I was removing method by method invokation to know which part was the responsible to make the system crash. However, I didn’t manage to get it work.

Finally, looking at the Makefile of the C++ program, I found that in the rule to generate the object file of the program, there was the -DDEBUG flag. So I provided this flag after “–” when running my application. That worked!!

Now, I have two doubts:

  1. I don’t know why the application that I started from scratched worked even without incluiding -DDEBUG and the one that I was skimming derived from the complete application did not. What could be affecting in my system to make this difference?

  2. Should then I use FullSourceLoc or PresumedLoc in the end?

Thank you for your time Mikhail.