This is an archive of the discontinued LLVM Phabricator instance.

[StaticAnalyzer] Fix crash in CastToStructChecker
ClosedPublic

Authored by danielmarjamaki on Jan 4 2017, 9:11 AM.

Diff Detail

Repository
rL LLVM

Event Timeline

danielmarjamaki retitled this revision from to [StaticAnalyzer] Fix crash in CastToStructChecker.
danielmarjamaki updated this object.
danielmarjamaki added a reviewer: NoQ.
danielmarjamaki set the repository for this revision to rL LLVM.
danielmarjamaki added a subscriber: cfe-commits.
NoQ edited edge metadata.Jan 11 2017, 3:32 AM
NoQ added a subscriber: zaks.anna.

Looks good. I assume the crash is in getTypeInfo(); do you have any idea what are exact prerequisites for using this method? So that there were no more crashes here.

Please, subscribe cfe-commits list on the patches as described in http://llvm.org/docs/Phabricator.html.

Thanks!
Anna

In D28297#642523, @NoQ wrote:

Looks good. I assume the crash is in getTypeInfo(); do you have any idea what are exact prerequisites for using this method? So that there were no more crashes here.

Yes. The crash happens during the getTypeInfo() call. I don't know what prerequisites are interesting to check.

The Type pointer returned by getTypePtr() must be nonnull and valid. The method clang::Type::getTypeClass() is called using that type pointer. If that returns Type::Record then the Type pointer is casted to a RecordType. And RecordType::getDecl() is called. The RecordDecl that is returned by that call is passed to getASTRecordLayout() shown below.

The crash occurs on the first assert in this code:

const ASTRecordLayout &
ASTContext::getASTRecordLayout(const RecordDecl *D) const {
  // These asserts test different things.  A record has a definition
  // as soon as we begin to parse the definition.  That definition is
  // not a complete definition (which is what isDefinition() tests)
  // until we *finish* parsing the definition.

  if (D->hasExternalLexicalStorage() && !D->getDefinition())
    getExternalSource()->CompleteType(const_cast<RecordDecl*>(D));
    
  D = D->getDefinition();
  assert(D && "Cannot get layout of forward declarations!");
  assert(!D->isInvalidDecl() && "Cannot get layout of invalid decl!");
  assert(D->isCompleteDefinition() && "Cannot layout type before complete!");
....

I am not sure I can write testcases that prevent regressions but do you think I should add isInvalidDecl() and isCompleteDefinition() also?

NoQ accepted this revision.Feb 15 2017, 7:20 AM

I sometimes wish ASTContext methods just didn't crash :)
Oh well, let's just see if more problems show up.

lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
93 ↗(On Diff #83062)

I think we should move the check here then. That'd avoid double-checking if ToPointeeTy is a record type (we could cast<> directly on this branch).

This revision is now accepted and ready to land.Feb 15 2017, 7:20 AM

Please, make sure future reviews go through cfg-dev list. See http://llvm.org/docs/Phabricator.html.

This revision was automatically updated to reflect the committed changes.
danielmarjamaki reopened this revision.Feb 21 2017, 3:40 AM

I reverted the change because there were buildbot failures.

This revision is now accepted and ready to land.Feb 21 2017, 3:40 AM

It was reported in the bugzilla report that my first fix did not fix all crashes. A new example code was provided that triggered a new crash. I have updated the patch so both crashes are fixed.

danielmarjamaki requested review of this revision.Feb 23 2017, 7:49 AM
danielmarjamaki edited edge metadata.

I have updated the patch and want a new review.

a.sidorin edited edge metadata.Mar 3 2017, 1:33 AM

Looks like a right fix.

lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
93 ↗(On Diff #83062)

Or just hoist it out of condition?

zaks.anna accepted this revision.Mar 3 2017, 9:50 AM

Thanks. looks good.

This revision is now accepted and ready to land.Mar 3 2017, 9:50 AM
This revision was automatically updated to reflect the committed changes.