Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Static Analysis -- Guaranteed calls to functions in a program

Is there a way to find out all function calls that will execute as part of a Program in C# world?

For example, given this:

static void Main(string[] args)
{
     if (true)
     {
         CallTrueFunction();
     }
     else
     {
         CallFalseFunction();
     }
 }

Can I say through FxCop or some other system get to know CallTrueFunction?

like image 235
halivingston Avatar asked Apr 06 '14 00:04

halivingston


2 Answers

The short answer is no.

The slightly longer answer is no, not for any non-trivial program in any programming language.

The longer answer is that you are describing the halting problem more or less. There is no general way to determine which methods are reachable and which are not because to do so you would need to solve the halting problem.

Imagine a while loop and after the loop is the only call to myfunc(). Is myfunc() called? You can't know because the loop may or may not terminate. Perhaps the loop relies on a variable passed into the function. Perhaps it relies on input from the user. Whatever the case, if the loop terminates then myfunc() is called. If the loop doesn't terminate, then myfunc() is dead code that will never be called. Let's just say you do while(Console.ReadLine() != "G") { }. Does your program call myfunc()? Depends on the input!

And much like the halting problem, you can construct trivially small programs that always produce the correct answer, or create extremely tiny finite state machines that always produce the correct answer. But if you then take your static analysis program and run it on even a moderately small app the number of potential state combinations quickly exceeds the number of available atoms in the universe.

The only way to know if your program will call this function or that function is to run it and see if it does. Then you can say "For input X, in environment Y, on CPU Z, at date time D, given these versions of these system libraries, while the system was under this amount of CPU load, and this amount of I/O load, and where ground vibrations did not interrupt the hard disk, and where a cosmic ray did not flip any bits in memory, my program called the subset G of all available functions F".

If any of those variables change (the input being the primary one), then your previous analysis is incomplete.

Note: It is not even possible to make strong guarantees about which functions could possibly be called because reflection could call any function by constructing a string (so you can't even scan for function names), or even generate and inject brand new functions into your program.

like image 99
russbishop Avatar answered Oct 26 '22 16:10

russbishop


Depending on what you want to achieve, one possible way is to approach things the other way around and mark/remove everything that cannot be reached. With Resharper you can easily find all unused code. Going by your example, this would mark:

else
{
    CallFalseFunction();
}

as unreachable code. And it will suggest you change:

if (true)
{
    CallTrueFunction();
}

to:

CallTrueFunction();

Once you have cleaned up your project this way, everything that is left should be callable through some execution path and everything not relying on a conditional parameter should be called (assuming the program does not abort halfway).

This will not help you when trying to find what methods are called from a specific entry point in your app with specific parameters. If that is what you are looking for, maybe you can try looking to use a profiler that is capable of logging every method that is called. That way you logging will give you the list of functions.

like image 39
Sam Avatar answered Oct 26 '22 16:10

Sam