-
Notifications
You must be signed in to change notification settings - Fork 257
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
Static call analysis: overwriting and implementing calls #13
Comments
These are different kinds of relationships, though. They are not call relationships, and thus should not be mixed with them. |
Surely, I am not contesting, that "overwrites" and "implements" are different kinds of relationships. But for a complete overview of the static call structure there are needed as well as the direct calls.
Von: Matthieu Vergne [mailto:[email protected]]
Gesendet: Samstag, 20. Oktober 2018 20:11
An: gousiosg/java-callgraph
Cc: Dolland Peter MTPCE; Author
Betreff: Re: [gousiosg/java-callgraph] Static call analysis: overwriting and implementing calls (#13)
These are different kinds of relationships, though. They are not call relationships, and thus should not be mixed with them.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub<#13 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/ADShEMakrOYLAUxgO4e9djIn-N8_JE-mks5um2dJgaJpZM4P4So7>.
|
I think I see what you mean, and I could understand the need. But it seems to me that such addition would have a significant impact on the tool. I just proposed a pull request for a better identification of lambdas in #22 (and I am glad it was accepted), but what I did was fix to better identify a one-to-one relationships between the lambda and the method instantiating it. In your case it is not a one-to-one relationships. If you take the first point, with overriding. Here is an example: class Root {
void doSomething() {
System.out.println("I am root!");
}
}
class Child1 extends Root {
@Override
void doSomething() {
System.out.println("I am child1!");
}
}
class Child2 extends Root {
@Override
void doSomething() {
System.out.println("I am child2!");
}
} Now you have a method accepting a void execute(Root root) {
root.doSomething();
} The point is that the call graph here would depend on the agument's value: execute(new Root());
execute(new Child1());
execute(new Child2()); All three are valid calls, but then each of them calls the The second point, with interface implementation, is exactly the same, excepted that The problem here is that you cannot do it in a single pass without consuming huge amounts of space (RAM or hard disk, depending on the strategy used). Indeed, If you do it in 2 passes, then during the first pass you need to store the types of the various instances passed to If you do it in 1 pass, you need to remember instead which methods might be impacted by such behaviours. But since you cannot guess in advance all the override/implement relationships, then you must assume it may happen for any (non-final) type. Which means you need to remember more or less every method you have seen, or said another way store a complete graph of the calls in the JAR. Which means that you need to store at least the same amount of information that you generate in output, which is really costly for huge JARs. More other, you need then to browse this graph when you discover an override/implement relationships, in order to know where to add it. This is one again really costly, but this time in terms of computation time. You would need to use even more space to optimize it. Briefly, with 1 pass you obtain a tool which consumes more than it generates at the end, and with 2 passes you still need to consume way more than what you currently do. So it might be useful, but the impact would be huge. Maybe it would make sense in the dynamic analysis (which I am not familiar with and I did not use), but in static analysis it seems to me like a tool killer. Just too finish on a good note : if it is about adding the override/implement relationships between methods, then it might be OK, because you only need to list them once for all. Then all the calls relationships can be inferred from what is generated in output. So the information would be there. But retrieving the calls themselves... I would not recommend it for this tool. Just make a script/additional tool which builds on the result of the JAR analysis for that. |
|
Let me show what we see currently with the example of Mathieu in the call graph (only methods):
M:Root:doSomething() (M)java.io.PrintStream:println(java.lang.String)
M:Child1:doSomething()(M)java.io.PrintStream:println(java.lang.String)
M:Child2:doSomething()(M)java.io.PrintStream:println(java.lang.String)
Any definition of a method execute calling root.doSomething() will lead to an entry in the call graph as
M:AnyClass:execute(Root) (M)Root:doSomething()
independently, what the concrete (dynamic) type of root is. But however, any hint is missing, that possibly Child1.doSomething or Child2.doSomething is called instead. We could solve this issue by adding calls
M:AnyClass:execute(Root) (M)Child1:doSomething()
M:AnyClass:execute(Root) (M)Child2:doSomething()
to the graph. I think, it would be much clearer for the static analysis (and supposedly easier to implement), if we add the indication, that Root:doSomething() is overwritten:
M:Root:doSomething() (V)Child1:doSomething()
M:Root:doSomething() (V)Child2:doSomething()
We avoid here to multiply the calls of Root:doSomething(), and no (static) information is lost.
For interfaces the same is valid. However, I think it would be clearer, if the call type indicates that we are dealing with an interface method and its implementation, e.g. with (F).
Please note, that we are discussing here only the static analysis of the call structure. Only the existence of an overwriting or implementing method implies a potential call, if a super class or interface method is called. It is essential for the static analysis of a program, that we can recognize a potential call sequence from a call of method A to a call of method B, and possibly even more important, if we can prove, that there is no such call sequence from A to B. But this is only possible, if we have a complete analysis of the call structure and our tool is correct.
Von: Georgios Gousios [mailto:[email protected]]
Gesendet: Mittwoch, 24. Oktober 2018 09:39
An: gousiosg/java-callgraph
Cc: Dolland Peter MTPCE; Author
Betreff: Re: [gousiosg/java-callgraph] Static call analysis: overwriting and implementing calls (#13)
java-callgraph was supposed to be a quick-and-dirty call graph generator. Resolving virtual dispatch calls (which is what we are discussing here) is not a trivial problem and other, more advanced tools (such as Soot and Wala) feature multiple implementations of algorithms proposed in scientific literature. I am not sure that we should implement those in java-callgraph.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub<#13 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/ADShEGaSiKDMYfsbrifSywEYVoZMA9MRks5uoBkhgaJpZM4P4So7>.
|
Thanks for the comment. I don't disagree with the algorithm you propose, what I am saying is that tools such as Wala and Soot already offer this functionality (actually, more advanced versions of it). It would take me a lot of time (which I don't have currently) to implement this and get it right, so I will probably pass. However, I am open to PRs! |
If it is only about adding the overriding/implementing relationships then it should be doable in one pass with few impacts. This is a similar analysis than I did for the lambdas, so you may look and inspire from the class I would gladly review your pull request if you make one. |
Hi Georgios and Matthieu,
I made locally some changes to the java-callgraph static lib. The most important one:
Additionally to the classes (C:) and the methods (M:) section I am dumping out an overridings (V:) section with lines of the format
V:<specifying class or interface>:<method signature> <overriding class>
So I can get the full static call information. If a method is calling an interface method, I will also see, what the potential implementations are and which methods they are calling.
Furthermore I list in the classes section, if a class is extending another one, which is marked with <S>, and if a class is implementing an interface, or an interface is extending another one, which is marked with <I> in both cases. Interfaces are listed with I: instead of C:. Abstract and native methods are listed with A: and N: in the classes section too, since they will not appear as a calling method necessarily.
My question is: Are you interested in my changes? I would push them in a separate branch, but I would need permissions to do so. So you will be able, to merge them according to your needs.
Best regards,
Peter Dolland, MTPCE
Von: Matthieu Vergne [mailto:[email protected]]
Gesendet: Mittwoch, 24. Oktober 2018 20:30
An: gousiosg/java-callgraph
Cc: Dolland Peter MTPCE; Author
Betreff: Re: [gousiosg/java-callgraph] Static call analysis: overwriting and implementing calls (#13)
If it is only about adding the overriding/implementing relationships then it should be doable in one pass with few impacts. This is a similar analysis than I did for the lambdas, so you may look and inspire from the class DynamicCallManager that I wrote for them to make a pull request. Actually, you may add your methods in the same class, since its purpose is to deal with such dynamic analysis.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub<#13 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/ADShECiGUZvFfuY1ABdN1P5OKh5el7x8ks5uoLGhgaJpZM4P4So7>.
|
Hi Peter, yes I am interested to see a PR that implements the functionality you are discussing here. Please also make sure you update the README file with the new output formats. |
* Started commit for heuristic processing * Update configs * Add heuristic class GetBest with integration to the Test step for JCallGraph * Update GetBest to update color values, add hash for compare, and update algo used for path sum (to avoid infinite loop with previous all paths algo). * Update mph-table.yaml * Started commit for heuristic processing * Update configs * Add heuristic class GetBest with integration to the Test step for JCallGraph * Update GetBest to update color values, add hash for compare, and update algo used for path sum (to avoid infinite loop with previous all paths algo). * Update mph-table.yaml * Added preliminary unit tests * Failsafe plugin added to pom file * Added jetty plugin to start server for integration testing * Added RepoTool integration test, modified POM to reflect int-test stage * Set 'skipTests' parameter to false to run int tests * Updated Integration Tests * Added Convex Integration Test * Added 'runOrder' parameter in POM for Int Tests, Updated Integration tests to sequentially run and added assert statements * Removed unnecessary test files on local branch * Update with patched items based on feedback * Add updates to GetBest score calculation and fix issue with output directory * Update patch/yaml names to have correct extensions * Add runall.sh and buildsvg.sh * Add runall.sh and buildsvg.sh * Updated MphTableIT to run without being platform specific * Resolved ordering issue * Started commit for heuristic processing * Update configs * Add heuristic class GetBest with integration to the Test step for JCallGraph * Update GetBest to update color values, add hash for compare, and update algo used for path sum (to avoid infinite loop with previous all paths algo). * Update mph-table.yaml * Update with patched items based on feedback * Add updates to GetBest score calculation and fix issue with output directory * Update patch/yaml names to have correct extensions * Add runall.sh and buildsvg.sh * Add runall.sh and buildsvg.sh * Started commit for heuristic processing * Update configs * Add heuristic class GetBest with integration to the Test step for JCallGraph * Update GetBest to update color values, add hash for compare, and update algo used for path sum (to avoid infinite loop with previous all paths algo). * Update mph-table.yaml * Started commit for heuristic processing * Update configs * Add heuristic class GetBest with integration to the Test step for JCallGraph * Update GetBest to update color values, add hash for compare, and update algo used for path sum (to avoid infinite loop with previous all paths algo). * Update mph-table.yaml * Update with patched items based on feedback * Add updates to GetBest score calculation and fix issue with output directory * Update patch/yaml names to have correct extensions * Add runall.sh and buildsvg.sh * Add runall.sh and buildsvg.sh * Started commit for heuristic processing * Update configs * Add heuristic class GetBest with integration to the Test step for JCallGraph * Update GetBest to update color values, add hash for compare, and update algo used for path sum (to avoid infinite loop with previous all paths algo). * Update mph-table.yaml * Update with patched items based on feedback * Add updates to GetBest score calculation and fix issue with output directory * Update patch/yaml names to have correct extensions * Move fixed to new "project" directory (e.g. convex-fixed). * Add green/yellow/red arrows for paths. * Update so buildyaml looks for @Property attributes instead of just junit Test attribute * Add basic documentation to the read me * Rename files * commit runAll * Update yaml patch names for fixed * Remove unneeded configs Co-authored-by: ameka4 <[email protected]> Co-authored-by: alekh <[email protected]> Co-authored-by: Alekh Meka <[email protected]>
In order to see, what may be called from what, two further types of method calls seem to me important: (1.) a method is overwritten by another one. (this is not just a true call, but however, I think java-callgraph could do so, since the overwriting method is executed instead of the overwritten one.)
(2.) an interface method is implemented by a concrete method. (java-callgraph is already listing calls of interface method. So for completeness (respective to the given jars) I want to see also the implementing methods.)
The text was updated successfully, but these errors were encountered: