This is an archive of the discontinued LLVM Phabricator instance.

[analyzer] MacOSXApiChecker: Disallow dispatch_once predicates on heap and in ivars.
ClosedPublic

Authored by NoQ on Oct 24 2016, 8:53 AM.

Details

Summary

As documentation in https://developer.apple.com/reference/dispatch/dispatch_once_t says, only global or static variables should have type dispatch_once_t, otherwise the magic with fast memory barriers doesn't work, and using dispatch_once() would cause hard-to-catch errors.

There's already a check in MacOSXApiChecker that disallows stack variables here. The check is extended to warn upon heap and ivar predicates of type dispatch_once_t.

While ivars could have been handled on the AST level, heap variables could not.

Currently the analyzer core does not realize that all Objective-C objects always reside on the heap. I thought of stating that, say, any SymbolRegionValue of ObjCObjectPointerType type should produce a heap-based symbolic region. However, if i do this, it would no longer be true that different heap-based symbolic regions never alias. So a more complicated solution is necessary here. So for this checker i'm settling on the solution of "treat all ivars as heap regions in this checker".

Diff Detail

Repository
rL LLVM

Event Timeline

NoQ updated this revision to Diff 75587.Oct 24 2016, 8:53 AM
NoQ retitled this revision from to [analyzer] MacOSXApiChecker: Disallow dispatch_once predicates on heap and in ivars..
NoQ updated this object.
NoQ added reviewers: zaks.anna, dcoughlin.
NoQ added a subscriber: cfe-commits.
NoQ updated this revision to Diff 75589.Oct 24 2016, 8:55 AM

Hotfix code duplication i just noticed.

dcoughlin added inline comments.Oct 24 2016, 9:50 AM
lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
92 ↗(On Diff #75589)

"heap allocated" --> "heap-allocated"

94 ↗(On Diff #75589)

It is not clear to me that this FIXME is a good idea. I would remove it so someone doesn't spend a lot of time trying to address it.

Objective-C objects don't have the strong dis-aliasing guarantee that the analyzer assumes for heap base regions. In other words, two calls to [[Foo alloc] init] may yield exactly the same instance. This is because, unlike malloc() and C++ global new, ObjC initializers can (and frequently do) return instances other than the passed-in, freshly-allocated self.

test/Analysis/dispatch-once.m
13 ↗(On Diff #75589)

Should the tests for dispatch_once in unix-fns.c be moved here?

15 ↗(On Diff #75589)

I think it would be good to include the full diagnostic text for the stack local variable case because there is control flow in its construction.

NoQ added inline comments.Oct 24 2016, 10:22 AM
lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
94 ↗(On Diff #75589)

Hmm, that seems to be exactly the thing i'm looking for: heap-based regions that may alias.

The property of a region's staying on the heap has little to do with the property of being able to alias.

I've a feeling that we should have avoided using C++ inheritance in the memregion hierarchy, and instead went for a bunch of constraints. Eg., memory space is essentially a constraint (it may be unknown or get known later through exploring aliasing), region's value type is essentially a constraint (as seen during dynamic type propagation, it may be unknown, it may be partially known, we may get to know it better during the analysis by observing successful dynamic casts), extent is essentially a constraint (that we currently impose on SymbolExtent), offset of a symbolic region inside its true parent region is a constraint, and so on.

But that's too vague. I've no well-defined idea how to make this better at the moment.

zaks.anna edited edge metadata.Oct 24 2016, 5:13 PM

Looks good overall!

NoQ updated this revision to Diff 75739.Oct 25 2016, 11:17 AM
NoQ edited edge metadata.
NoQ marked 2 inline comments as done.

Consider a lot more dispatch_once_t regions: improve diagnostics for local structs containing predicates, find ivar structs with predicates.

Address a couple of review comments, discuss the rest.

test/Analysis/dispatch-once.m
13 ↗(On Diff #75589)

In fact we need to de-duplicate code with unix.API's pthread_once check, which is an exact copy-paste for this checker. Not sure how to achieve that, maybe split both into a single *-once checker (and remove this checker because it becomes empty). Maybe then we'd deal with tests as well.

dcoughlin added inline comments.Oct 25 2016, 2:36 PM
lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
70 ↗(On Diff #75739)

I guess this comment needs to be updated.

94 ↗(On Diff #75589)

If you feel strongly about this, I would suggest putting the FIXME in the core, perhaps in SimpleSValBuilder where the dis-aliasing assumption is introduced or perhaps in the declaration of HeapSpaceRegion. This will make it clear to future maintainers that it is not a defect in the checker.

test/Analysis/dispatch-once.m
26 ↗(On Diff #75739)

Clever.

62 ↗(On Diff #75739)

Interesting. Have you seen this pattern in the wild?

I think this diagnostic is a little bit confusing since the ivar itself isn't being used for the predicate value.

Maybe "... uses a subfield of the instance variable 's' for the predicate value"?

NoQ updated this revision to Diff 75998.Oct 27 2016, 2:52 AM
NoQ marked 3 inline comments as done.

Also, do not create error nodes unless we're sure we're throwing a report.

NoQ added inline comments.Oct 27 2016, 2:53 AM
test/Analysis/dispatch-once.m
62 ↗(On Diff #75739)

Not yet, so this is more of a "because we can" test. That said, i'm not sure about the warning message: it might also be an array element, not necessarily a field, and not necessarily a direct subfield or direct element.

Added array tests and an attempt on a safe warning message.

zaks.anna accepted this revision.Oct 27 2016, 9:00 AM
zaks.anna edited edge metadata.

Looks great! Please, commit.

This revision is now accepted and ready to land.Oct 27 2016, 9:00 AM
This revision was automatically updated to reflect the committed changes.