Fix duplicated artifical call-edges when performing two-phase pointer analysis - #220
Conversation
|
All contributors have signed the CLA ✍️ ✅ |
|
I have read the CLA Document and I hereby sign the CLA |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #220 +/- ##
============================================
- Coverage 76.47% 76.46% -0.01%
- Complexity 7440 7441 +1
============================================
Files 657 657
Lines 25061 25069 +8
Branches 3717 3717
============================================
+ Hits 19165 19169 +4
Misses 4504 4504
- Partials 1392 1396 +4
🚀 New features to boost your workflow:
|
zhangt2333
left a comment
There was a problem hiding this comment.
Thank you for submitting this PR and for taking the time to investigate this issue. The problem does exist, and it requires careful observation to uncover, so this is a valuable finding.
However, we see several limitations in the current solution:
- It only addresses artificially generated
Invokestatements. The same underlying issue may also affect other statement types, such as artificial field or array loads and stores, so the broader problem is not fully resolved. - It relies on an internal API and should not be considered the final design. Removing IR statements during the analysis lifecycle could potentially affect the monotonicity of the analysis. We have manually verified that this particular implementation does not currently cause such a problem, but we plan to redesign this part so that such an API is no longer needed.
- It does not include a minimal reproducer or regression test case, which makes the behavior and the risk of future regressions more difficult to validate.
For these reasons, our initial preference would have been to track this as an issue rather than treat the current PR as the complete solution. We would then consider a more systematic approach—for example, consistently removing all generated statements, or addressing the problem at a fundamental level by centrally managing all artificial statements. The exact approach still needs to be discussed by the team.
That said, given the timing and the importance of supporting active community contributions, I plan to merge this PR directly as a short-term fix and address the problem comprehensively in follow-up commits.
Thank you again for finding and reporting this issue.
Fix: duplicated artifical call edges generated by
IRModelPluginin two-phase pointer analysesSummary
This PR prevents duplicate artificial call edges from being generated by
IRModelPluginduring two-phase pointer analyses such as Zipper and Zipper-e.Problem
Advanced pointer analyses such as Zipper and Zipper-e first perform a context-insensitive pre-analysis and then run a selective context-sensitive analysis over the same
World.Take
DoPriviledgedModelas an example, which is a concrete subclass ofIRModelPlugin, and modelsAccessController.doPrivileged(...)by creating an artificial instanceInvokeforPrivilegedAction.run(). Constructing theInvokeregisters it with its receiver variable throughVar.addInvoke().However, the artificial
Invokecreated during the pre-analysis remains registered after that analysis finishes. The selective analysis then creates another equivalent artificialInvoke. As a result, the receiver variable contains artificial invocations from both analysis phases.When
DefaultSolver.processCall()processes the statements returned byVar.getInvokes(), both equivalentInvokeobjects are processed, causing the same logical artificial call edge to be generated more than once. Because the two call sites are distinct objects, these duplicate edges are not deduplicated by the call graph.Reproduction
antlrfrom dacapo-2006:To expose the duplicates directly, temporarily add the following block in
ResultProcessor.logStatistics()immediately after the#call graph edgeslog statement:which prints duplicated artificial edges such as:
Fix
My current fix is to add
IRModelPlugin.onFinish(), which now unregisters generated artificial instance invocations from their receiver variables so that subsequent solver runs no longer observe stale statements.