-
Notifications
You must be signed in to change notification settings - Fork 284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Different approach for param analysis #320
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice approach!
One thing, though: the comments and description don't really match what the code is doing, and I was actually confused for a while trying to build a test case that would fail given the described approach. The actual approach is "look for a path from entry to exit that doesn't dereference the parameter, if it doesn't exist, it's @NonNull
". That seems right to me (or, at least, strictly more right than the original approach), but please change the description and comments to more properly document it.
}); | ||
|
||
// for each param check if there is a path from entry to exit going through basic blocks | ||
// which do not guarantee that the param is non-null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, not sure this comment is right, the way I understand the code below, it says:
"For each param p
, if no path exists from the entry block to the exit block which traverses only basic blocks which do not dereference p
, then mark p
as @NonNull
"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other than the comment being confusing, this approach actually looks broadly correct to me, with the only issues being:
a) Code sets the argument p
when it originally is null
such as:
public void test(String s, String t) {
Objects.requireNonNull(s);
if (t == null) {
t = s;
}
t.toString();
}
(It's probably fine that we don't handle this, but worth checking if this produces a lot of new false positives for monorepo)
b) The whole other issue about exceptional control flow being pruned that might start to matter the more stuff our analysis catches otherwise.
Also, probably worth checking the performance impact of this vs the original approach. I don't think it should be too bad, since all the time probably went into building the IR and GFG either way, but I think it's worth keeping track.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a) works because of SSA, since variables are assigned only one time. A new variable(v8) is created
public void test(String s, String t) {
Objects.requireNonNull(s);
if (t == null) {
t = s;
}
Objects.requireNonNull(t);
}
13:41:12.302 [DEBUG] [TestEventLogger] v8 = phi v3,v2
13:41:12.303 [DEBUG] [TestEventLogger] 9 v10 = invokestatic < Application, Ljava/util/Objects, requireNonNull(Ljava/lang/Object;)Ljava/lang/Object; > v8 @12 exception:v9(line 17)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, right, that makes sense. Nice! Could we add that example as a test then? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.. adding.
Set<Integer> derefedParamList = new HashSet<>(); | ||
Map<ISSABasicBlock, Set<Integer>> blockToDerefSetMap = new HashMap<>(); | ||
|
||
// find which params are definitely non-null in each block |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, slightly clearer: "find which params are dereferenced (and thus non-null) in each block"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually, we test more things than just dereferencing, like precondition and assertions, hence I phrased it like this. And maybe in future we might add more checks which are not just deref too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe "find which params are treated as being non-null inside each basic block", then? :)
And for the comment on the filter:
"For each param p
, if no path exists from the entry block to the exit block which traverses only basic blocks which do not require p
being non-null (e.g. by dereferencing it), then mark p
as @NonNull
"
The main problem I have with "params are definitely non-null in each block" is that it's not clear that they are expected to be non-null on entry vs guaranteed to be non-null by the block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah..makes sense
LGTM. Nice Work. Once Lazaro's comments are addressed, I am okay with accepting this. |
20865e8
to
1815084
Compare
@shas19 Travis CI should be fixed by #322 . Can you rebase, please? 😅 |
1815084
to
054aceb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved!
Using a different approach for param nullness analysis in jar-infer
• Pre-calculate all the params that are guaranteed to be non-null in each basic block ( Using the already existing checks)
• looks for a path from entry to exit that doesn't dereference the parameter, if it doesn't exist, it's
@NonNull
• This covers all the cases from the current approach. Might take more time in execution than the current approach.
computeDerefParamList
uses this approach andcomputeDerefParamListUsingPDom
uses the previous approach. Constant flagUSE_EXTENDED_APPROACH
can be used to switch these approaches.Added tests