 Hi, and welcome back to program analysis. In this video, we will continue with the lecture on dataflow analysis and we will look into how to expand the analysis that we've seen so far from an intra-procedural to an intap-procedural analysis, which essentially goes from looking at just one function at a time to multiple functions together. So let me start by clarifying the terminology here a little bit. So intra-procedural means that we are staying inside a single procedure or a single function, which means that we are reasoning about one function in isolation at a time. This is what we've done so far in this lecture on dataflow analysis. So all the dataflow analyses that we have considered so far are actually intra-procedural. Now in contrast, an inter-procedural analysis reasons not just about a single function, but about multiple functions together. And in particular, this means that the analysis is a reasoning about function calls and function returns because this is how you get from one function to the other and then also back. So how can an inter-procedural dataflow analysis work? So for an intra-procedural analysis, what we had done is to look at the control flow graph. So the logical next step for an inter-procedural dataflow analysis is to look at an inter-procedural control flow graph. So how does that graph look like? Well, it's essentially the control flow graph that you get for each individual function. And then we are connecting the different control flow graphs by adding edges for all the calls and returns. So specifically, there is one edge that connects a call site, so a place in the code where a function is called, to the entry node of the callee, so to the entry node of the function that is being called. And then also there's an edge that connects the exit node of a function. So basically the last statement or maybe the return statement back to the call site or to the possible call sites of this function so that we know that the control can flow back from the exit node to where the function was called. Let's illustrate this idea of an inter-procedural control flow graph with a simple example. So in this example, we'll have two functions, one called foo, foo, which takes some argument x. And then what foo does is to check if x is larger than 1. And if this is the case, it is calling bar with some argument and assigns the return value of bar into variable z. And if that condition is not true, it'll also call bar but with different value and then also assign the return value into z. So this is all that function foo is doing. And now we also need to define function bar. So bar is also taking an argument, let's call it y. And then what bar is doing is to just write this argument to the console and then it returns the argument y plus 1. So now in order to write down the inter-procedural control flow graph for these two functions together, we start by noting down the control flow graphs for each function individually. So let's start with the first one foo and I'll do this with blue color and then the other one using another color. So the control flow graph for the foo function has an entry node as always. Then we have this check whether x is larger than 1 and then there are two branches going out of here, one where we call bar of 5 and write it into z and the other one where we call bar of 3. And then after these two statements the code converges again and reaches the exit node. So this is the control flow graph, the intra-procedural one for foo. Now let's also do the intra-procedural one for bar and I'll use red color for that. So again we'll have an entry node and then in this case the control flow is pretty boring because there's just a straight sequence of statements. So we'll have one note here for the console log call and then another one for this return statement and then from here we always go to the exit statement. Now to connect these two intra-procedural control flow graphs into an inter-procedural control flow graph what we'll do is to look at all the call sites of a function. So basically the two nodes that call bar in our case and connect those nodes to the corresponding entry node of the call e of the called function. So we add another edge here that goes from here to here and another edge here that goes from here to there. And then in order to make sure that we also represent the control flow back from the return statement or the exit node of bar to foo we also need to have edges that go from the exit node back to the node that has called the function. So we'll have one here and another one here. So one question you might have by looking at this graph is whether it's possible that we're calling bar in the then branch of the if of foo and then maybe go back through the other edge into the else branch which would be something that actually cannot happen at runtime and the answer is no. So the way the analysis is using this inter-procedural control flow graph is such that it considers only flows of control that are actually possible. And in particular this means that after returning we do not enter again. So if you just look at this graph naively you could say well okay we can call the function then return to the node that has called a function and then go right into the yeah go again right into the function but this is not possible. So after the analysis has followed an edge that represents a return it won't enter again. And then the other thing is what I just said before so when we are returning the analysis will always go back to the call site. So now having this inter-procedural control flow graph the analysis cannot be performed more or less the same way it's done in an inter-procedural data flow analysis just that now in addition we also need to propagate information across the function boundaries. So this needs to be done in in two ways. So for arguments all information that is associated with an argument given to a call needs to be propagated to the formal parameters of the call leak. So for example if you have some information associated with a local variable a which is then given to a function and in that function this value is referred to a formal parameter called b then we basically need to update all the information associated with a so that it now refers to b while we are in the callee. And then similarly for return values those need to be propagated back to the caller so whatever is associated with a value that is returned needs to be updated so that if the return value is assigned to a variable we then associate that piece of information with the variable where the return value is stored. In contrast local variables are not propagated because they are just local two individual functions but when the analysis returns from a call it needs to continue with the state that we had just before the call. So basically whenever it enters a called function it needs to save this state at the call site and then continue with that state when the call has returned. Now all of this what you see here is for a forward analysis for a backward analysis basically the same things happen the same thing is happening just in the reverse where all the propagation happens in the other direction. All right so I hope you've now gotten an at least rough idea of how data flow analysis can be expanded to an interprocedural setting. We're not going to go into all the details of this simply because it's a pretty complex topic but I wanted to show you at least a little bit of how it works so that you can imagine that the data flow analysis framework is not just for intra procedural analysis but can actually also reason about multiple functions together. Thank you very much for listening and see you next time.