This is an archive of the discontinued LLVM Phabricator instance.

[analyzer] Add checker modeling gtest APIs.
ClosedPublic

Authored by dcoughlin on Dec 14 2016, 1:55 PM.

Details

Summary

gtest is a widely-used unit-testing API providing macros for unit test
assertions:

ASSERT_TRUE(p != nullptr);

that expand into an if statement that constructs an object representing
the result of the assertion and returns when the assertion is false:

if (AssertionResult gtest_ar_ = AssertionResult(p == nullptr))
    ;
else
  return ...;

Unfortunately, the analyzer does not model the effect of the constructor
precisely because (1) the copy constructor implementation is missing from the
the header (so it can't be inlined) and (2) the boolean-argument constructor
is constructed into a temporary (so the analyzer decides not to inline it since
it doesn't reliably call temporary destructors right now).

This results in false positives because the analyzer does not realize that the
the assertion must hold along the non-return path.

This patch addresses the false positives by explicitly modeling the effects
of the two un-inlined constructors on the AssertionResult state.

I've added a new package, "apiModeling", for these kinds of checkers that
model APIs but don't emit any diagnostics. I envision all the checkers in
this package always being on by default.

This addresses the false positives reported in PR30936.

Diff Detail

Event Timeline

dcoughlin updated this revision to Diff 81462.Dec 14 2016, 1:55 PM
dcoughlin retitled this revision from to [analyzer] Add checker modeling gtest APIs..
dcoughlin updated this object.
dcoughlin added reviewers: zaks.anna, NoQ.
dcoughlin added subscribers: cfe-commits, alexfh, sbenza.

Thank you Devin!

lib/StaticAnalyzer/Checkers/GTestChecker.cpp
31

"that that"

106

Misalignment here and below

183

Shouldn't we just bind OtherSuccess to our field?

dcoughlin marked 2 inline comments as done.Dec 15 2016, 1:20 PM
dcoughlin added inline comments.
lib/StaticAnalyzer/Checkers/GTestChecker.cpp
31

Thanks!

183

Unfortunately since this is a PostCall, the result of the constructor has already entered value land. It is a LazyCompoundValue with a reference to a previous store. Even if we look through the lazy compound value to get at the memory region, binding it in the current store will have no effect on the returned value.

We could perform the bind and load the result value again -- but then we'd have to replace the result value in the environment, which is not compositional with respect to other checkers' PostCalls, since they may have done their own thing with the old value.

dcoughlin updated this revision to Diff 81651.Dec 15 2016, 1:21 PM
dcoughlin updated this object.
dcoughlin marked an inline comment as done.

Update to address Aleksei's comments.

Looks good for me, but I'm not a reviewer. Thank you Devin!

test/Driver/analyzer-target-enabled-checkers.cpp
7

A very minor nit/question.
Do we have any convention on checker naming? Most checkers are starting with capital letters, but some not. As "API" is an abbreviation, I think we should at least start it with capital.

zaks.anna edited edge metadata.Dec 21 2016, 10:14 AM

Looks great overall. I have minor comments below. Thanks for the awesome comments!!!

lib/StaticAnalyzer/Checkers/GTestChecker.cpp
152

This could be moved up as you are using the state on the previous line.

159

What happens when they are known not to be equal? I am guessing the transition is just not added, correct? Do you test for that (I did not check.)?

172

"getNumArgs() == 1" ?

209

It seems that the num of parameter checking logic here is less restrictive than it could be and that makes this a bit hard to read without looking into the 'model' methods. Ex: I think there are 2 cases:

  • Constructor taking a bool can have either 1 or 2 arguments.
  • Copy constructor taking exactly one argument.

I already committed this, but I'll address the feedback in a follow-on commit.

lib/StaticAnalyzer/Checkers/GTestChecker.cpp
172

You can have additional arguments to a copy constructor as long as they are defaulted. I was trying to be robust against future source-compatible changes, but this was probably too clever. If the copy constructor changes then maybe it would be better to just not model.

209

I'll make this more clear.

test/Driver/analyzer-target-enabled-checkers.cpp
7

We're not terribly consistent, but in general we start packages with lowercase letters and checkers with uppercase names. Checkers are generally UpperCamelCase.

"apiModeling" is a package name, not a checker name. I think to be consistent with most of the other packages it should (?) probably be lowerCamelCase. This matches "coreFoundation" and "insecureAPI" but not "deadcode". I had "api" lowercase since it is an initialism for a thing (package) that starts with lower case and this is how we treat lower camel-case initialisms in Swift. It also matches "osx", which is similarly an initialism.

Does knowing it is a package name (rather than a checker name) change your opinion of whether "API" should be upper case. I'm happy to change it, since it will not be user facing.

I already committed this, but I'll address the feedback in a follow-on commit.

I should have written "I already committed this, *so* I'll address the feedback in a follow-on commit."

I cleaned up the parameter detection and added more tests in r290352.

zaks.anna accepted this revision.Jan 12 2017, 9:56 AM
zaks.anna edited edge metadata.

This is done.

This revision is now accepted and ready to land.Jan 12 2017, 9:56 AM
zaks.anna closed this revision.Jan 12 2017, 9:56 AM