This is an archive of the discontinued LLVM Phabricator instance.

[analyzer] Fix false positives in inner pointer checker (PR49628)
ClosedPublic

Authored by vsavchenko on Mar 24 2021, 6:18 AM.

Details

Summary

This patch supports std::data and std::addressof functions.

rdar://73463300

Diff Detail

Event Timeline

vsavchenko created this revision.Mar 24 2021, 6:18 AM
vsavchenko requested review of this revision.Mar 24 2021, 6:18 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 24 2021, 6:18 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript

I recommend splitting this into two. I would happily accept the part about std::data().

IMO std::addressof() should be modelled via evalCall as a pure function, instead of hacking it into the InnerPtrChecker.
It is overloaded to accept const T& as well, so the comment about "std::addressof function accepts a non-const reference as an argument" is not entirely true.

I recommend splitting this into two. I would happily accept the part about std::data().

IMO std::addressof() should be modelled via evalCall as a pure function, instead of hacking it into the InnerPtrChecker.

It does make sense to split these in two, but I'm not so sure about evalCall. It is definitely not something that InnerPtrChecker should be bothered with. Another point is that std::addressof might be only one of the function receiving a non-const reference and not modifying it, so it would
be nice to have a place in this checker where such exception is made.

It is overloaded to accept const T& as well, so the comment about "std::addressof function accepts a non-const reference as an argument" is not entirely true.

But it has a T & overload as well, and this is the one causing the FP.

martong added inline comments.Mar 30 2021, 6:47 AM
clang/test/Analysis/inner-pointer.cpp
23

Seems like all test are exercising with std::string, this looks like a legacy in this Checker.
Still, I miss a bit at least one test for the other overloads of std::data, maybe in a follow up patch?

378–392

So these are the FP cases that you are trying to solve?
Would be nice to see more details about the bug report (rdar://73463300) if that is not proprietary.

vsavchenko added inline comments.Mar 31 2021, 7:16 AM
clang/test/Analysis/inner-pointer.cpp
23

I can add it here, but what other test you suggest to add?

378–392
std::optional<std::string> str = "example";
char* dup = strndup(str->c_str(), str->size());

std::optional::operator-> uses std::addressof and the analyzer thinks that the pointer might get changed and raises the alarm.
I decided not to replicate std::optional in tests, and get straight to the point.

martong added inline comments.Mar 31 2021, 7:47 AM
clang/test/Analysis/inner-pointer.cpp
23

For example,

char a[20];
auto c = std::data(s);
consume(c);

Would this produce a warning?

Similarly to initializer list:

template <class E> 
constexpr const E* data(std::initializer_list<E> il) noexcept
{
    return il.begin();
}

int test() {
    auto IL = {0,1,2};
    const auto I = data(IL);
    consume(I);
    return 0;
}
378–392

Okay, thanks, makes sense.

NoQ added a comment.Apr 5 2021, 9:32 AM

It does make sense to split these in two, but I'm not so sure about evalCall.

evalCall should work great for this purpose but definitely not in this checker. Also this checker would still exercise its checkPostCall so it would still need to be silenced even if evalCall is implemented.

clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
234

This will crash if someone overloads std::data with 0 arguments because your CallDescriptions don't require a specific number of arguments. (They're not allowed to do that, yes, but we're still not allowed to crash.)

vsavchenko updated this revision to Diff 336077.Apr 8 2021, 6:09 AM

Require std::data to accept exactly 1 argument

vsavchenko marked an inline comment as done.Apr 8 2021, 6:18 AM
NoQ accepted this revision.Apr 8 2021, 9:35 AM

Looks great now, thanks!

This revision is now accepted and ready to land.Apr 8 2021, 9:35 AM

I'm still not satisfied with the addressof, but I won't block this either.

This revision was landed with ongoing or failed builds.Apr 8 2021, 10:30 AM
This revision was automatically updated to reflect the committed changes.
NoQ added a comment.Apr 20 2021, 11:50 PM

In https://bugs.llvm.org/show_bug.cgi?id=45786 the godbolt link shows that there are still problems with addressof (yes, their "trunk" clang is fresh enough). They seem to have __addressof instead of addressof so maybe we should cover that case real quick. Or maybe outright suppress reference invalidation on double-underscore functions because the checker generally relies on the number of standard functions that don't invalidate references while taking a non-const reference being very limited but this limit definitely doesn't take double-underscore functions into account.

In D99260#2704102, @NoQ wrote:

In https://bugs.llvm.org/show_bug.cgi?id=45786 the godbolt link shows that there are still problems with addressof (yes, their "trunk" clang is fresh enough). They seem to have __addressof instead of addressof so maybe we should cover that case real quick. Or maybe outright suppress reference invalidation on double-underscore functions because the checker generally relies on the number of standard functions that don't invalidate references while taking a non-const reference being very limited but this limit definitely doesn't take double-underscore functions into account.

What is the status quo of this issue? @vsavchenko

In D99260#2704102, @NoQ wrote:

In https://bugs.llvm.org/show_bug.cgi?id=45786 the godbolt link shows that there are still problems with addressof (yes, their "trunk" clang is fresh enough). They seem to have __addressof instead of addressof so maybe we should cover that case real quick. Or maybe outright suppress reference invalidation on double-underscore functions because the checker generally relies on the number of standard functions that don't invalidate references while taking a non-const reference being very limited but this limit definitely doesn't take double-underscore functions into account.

What is the status quo of this issue? @vsavchenko

Ah, yep. Just got back from my vacation!
I'm not sure about shooting off double underscore functions because one never knows what weird coding conventions people have in their project (all TU-local static functions should be named like this for better visibility at their call sites, for example). Being more specific and dealing with std::__ can be better, but I think a quick hack specifically for std::__addressof is better atm.

Based on the comment from @vsavchenko , I had made an addition for a check for __addressof alongside addressof in the checker. What would be the correct way of pushing the diff here? Should I reopen this revision or use the update diff button on the top? I apologize, I'm completely new to pushing changes to LLVM.

Thanks,