920 likes | 1.1k Views
Context-Sensitivity Analysis Literature Review. by José Nelson Amaral (amaral@cs.ualberta.ca) University of Alberta. Dimensions of Pointer Analysis. Unification-based × Insertion-based Flow-sensitive × flow-insensitive Field-sensitive × field-insensitive × field-based
E N D
Context-Sensitivity AnalysisLiterature Review by José Nelson Amaral (amaral@cs.ualberta.ca) University of Alberta
Dimensions of Pointer Analysis • Unification-based × Insertion-based • Flow-sensitive × flow-insensitive • Field-sensitive × field-insensitive × field-based • Context-sensitive × context-insensitive
a Andersen’s X Steensgaard’s (Example) Insertion X Unification Program: Steensgaard: a = &b; S = {(a,b)} b Andersen: S = {(a,b)} b a CMPUT 680 - Compiler Design and Optimization After (Shapiro/Horwitz, PPL97)
a Andersen’s X Steensgaard’s (Example) Program: Steensgaard: a = &b; b = &c; S = {(a,b); (b,c)} b c Andersen: S = {(a,b); (b,c)} b c a CMPUT 680 - Compiler Design and Optimization After (Shapiro/Horwitz, PPL97)
a Andersen’s X Steensgaard’s (Example) Program: Steensgaard: a = &b; b = &c; if(cond) a = &d; S = {(a,b); (b,c)} b c Andersen: What should happen in each analysis? S = {(a,b); (b,c)} b c a CMPUT 680 - Compiler Design and Optimization After (Shapiro/Horwitz, PPL97)
a Andersen’s X Steensgaard’s (Example) Program: Steensgaard: a = &b; b = &c; if(cond) a = &d; S = {(a,b); (b,c); (a,d); (d,c)} (b,d) c Andersen: S = {(a,b); (b,c); (a,d)} b c a d CMPUT 680 - Compiler Design and Optimization After (Shapiro/Horwitz, PPL97)
a Andersen’s X Steensgaard’s (Example) Program: Steensgaard: a = &b; b = &c; if(cond) a = &d; d = &e; S = {(a,b); (b,c); (a,d); (d,c)} (b,d) c Andersen: And now? S = {(a,b); (b,c); (a,d)} b c a d CMPUT 680 - Compiler Design and Optimization After (Shapiro/Horwitz, PPL97)
a Andersen’s X Steensgaard’s (Example) Program: Steensgaard: a = &b; b = &c; if(cond) a = &d; d = &e; S = {(a,b); (b,c); (a,d); (d,c); (d,e); (b,e)} (b,d) (c,e) Andersen: S = {(a,b); (b,c); (a,d); (d,e)} b c a e d CMPUT 680 - Compiler Design and Optimization After (Shapiro/Horwitz, PPL97)
a a a Flow-sensitive X Flow-insensitive (Example) Strong update: Not only a now points to d, but also a no longer points to b b b c Program: a = &b; b = &c; if(cond) a = &d; d = &e; a b c d Insertion based Unification based a b,d c d b c a b c a b,d c,e e d CMPUT 680 - Compiler Design and Optimization
Flow-sensitivity in SSA(incomplete slide) All variables that had their address taken must have an “access path” which is their address. They can only be referenced through their access paths. pb = &b; pc = &c; pd = &d; pe = &e; a0 = pb; *pb = pc; if(cond) a1 = pd; a2 = phi(a0, a1, FALSE, TRUE); *pd = pe; pb pc Program: b c a0 a2 e a1 d pd pe In SSA flow-sensitive information can be obtained from the single graph above. CMPUT 680 - Compiler Design and Optimization
Field-insensitive × Field-based × Field-sensitive analysis • Field insensitive: Each aggregate object modeled by a single abstract variable. • Field-based: An abstract variable models all instances of a field of an aggregate type. • Field-sensitive: Unique abstract variable models each field of each aggregate object. (PearceKellyHankinTOPLAS07)
Field Sensitivity (Example) Assume a flow insensitive, insertion-based analysis. a Program: Field Insensitive Field Based Field Sensitive typedef struct{ int *f1; int *f2; } aggr; aggr a,b; int *c, d, e, f; a.f1 = &d; Program: af1 d f1 d d (PearceKellyHankinTOPLAS07)
Field Sensitivity (Example) Assume a flow insensitive, insertion-based analysis. a Program: Field Insensitive Field Based Field Sensitive typedef struct{ int *f1; int *f2; } aggr; aggr a,b; int *c, d, e, f; a.f1 = &d; a.f2 = &f; Program: af1 d f1 d d f f f (PearceKellyHankinTOPLAS07)
Field Sensitivity (Example) Assume a flow insensitive, insertion-based analysis. a Program: Field Insensitive Field Based Field Sensitive typedef struct{ int *f1; int *f2; } aggr; aggr a,b; int *c, d, e, f; a.f1 = &d; a.f2 = &f; Program: af1 d f1 d d f af2 f2 f f (PearceKellyHankinTOPLAS07)
Field Sensitivity (Example) Assume a flow insensitive, insertion-based analysis. a Program: Field Insensitive Field Based Field Sensitive typedef struct{ int *f1; int *f2; } aggr; aggr a,b; int *c, d, e, f; a.f1 = &d; a.f2 = &f; b.f1 = &e; af1 d f1 d d e f af2 e f2 f f e (PearceKellyHankinTOPLAS07)
Field Sensitivity (Example) Assume a flow insensitive, insertion-based analysis. b a Program: Field Insensitive Field Based Field Sensitive typedef struct{ int *f1; int *f2; } aggr; aggr a,b; int *c, d, e, f; a.f1 = &d; a.f2 = &f; b.f1 = &e; af1 d f1 d d e f af2 e f2 f f bf1 e (PearceKellyHankinTOPLAS07)
Field Sensitivity (Example) Assume a flow insensitive, insertion-based analysis. c b a Program: Field Insensitive Field Based Field Sensitive typedef struct{ int *f1; int *f2; } aggr; aggr a,b; int *c, d, e, f; a.f1 = &d; a.f2 = &f; b.f1 = &e; c = a.f1; af1 d f1 d d c e f c af2 e f2 f f bf1 e (PearceKellyHankinTOPLAS07)
Field Sensitivity (Example) Assume a flow insensitive, insertion-based analysis. c b a Program: Field Insensitive Field Based Field Sensitive typedef struct{ int *f1; int *f2; } aggr; aggr a,b; int *c, d, e, f; a.f1 = &d; a.f2 = &f; b.f1 = &e; c = a.f1; af1 d f1 d d c e f c af2 e f2 f f bf1 e (PearceKellyHankinTOPLAS07)
Field Sensitivity in C • A field-sensitive analysis for C is fundamentally harder than a field-sensitive analysis for Java: • C allows the address of a field to be taken • Existing field-sensitive analysis for C: • YongHorwitzRepsPLDI99; • ChandraRepsPASTE99; • JohnsonWagnerUSENIX04; • PearceKellyHankinTOPLAS07;
What context-sensitivity means? • Context-sensitive analysis: “the effects of a procedure call are estimated within a specific calling context” • Context-insensitive analysis: “the effects of a procedure call summarizes the information for all calling contexts.” (EmamiGhyaHendrenPLDI94)
Another definition • “A context-insensitive (CI) algorithm does not distinguish the different calling contexts of a procedure, whereas a context-sensitive (CS) does.” (ZhuCalmanPLDI04) • “CS treats multiple calls to a single procedure independently.” (RufPLDI95) • “CI constructs a single approximation to a procedure’s effect on all of its callers.” (RufPLDI95)
Alternative definition:The calling context problem • The calling context problem is “the problem of correctly accounting for the calling context of a called procedure.” HorowitzRepsBlinkeyTOPLAS90
A more strict definition • “A precise CS analysis yields results as precise as if they were computed on a modified program with all method calls inlined.” • Requires a context-sensitive heap abstraction: • a separate abstraction is needed for each copy of an allocation statement • Virtual call targets must be computed context-sensitively • separately for each calling context; • using precise points-to information; SridharanBodikPLDI06
Context-Sensitive Example • Two calls to a function foo produce different return values because of the points-to set at the point immediately before each call to foo. • In other words, the return value of foo changes depending on the context within which foo is invoked.
#include <stdlib.h> typedefintarr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(intargc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo Is there an algorithm that “gets” this example? Emami, Ghiya, and Hendren (PLDI94) should get it. We need to study the points-to sets that the algorithm computes at points P1, P2, and P3. P1 P2 P3
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo In the following animation: y x x definitely points to y (variable x contains the address of variable y) x probably points to y (arrowsare colored red only for convenience in the animation, they represent new points-to relations that were not in the previous slide) P1 P2 P3
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo x1 x2 x3 a1 a2 a3 y1 y2 y3 P1?
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo x1 x2 x3 a1 a2 a3 y1 y2 y3 P1
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo PA? p2 p3 t x1 x2 x3 a1 a2 a3 y1 y2 y3
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo PA p2 p3 t x1 x2 x3 a1 a2 a3 y1 y2 y3
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo PA’? p2 p3 t x1 x2 x3 a1 a2 a3 y1 y2 y3
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo PA’ p2 p3 t x1 x2 x3 a1 a2 a3 y1 y2 y3
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo PA”? p2 p3 t x1 x2 x3 a1 a2 a3 y1 y2 y3
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo PA” p2 p3 t x1 x2 x3 a1 a2 a3 y1 y2 y3
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo PA” p2 p3 t x1 x2 x3 a1 a2 a3 y1 y2 y3
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo PA’’’? p2 p3 t x1 x2 x3 a1 a2 a3 y1 y2 y3
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo PA’’’? p2 p3 t x1 x2 x3 a1 a2 a3 y1 y2 y3
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo PB? p2 p3 t x1 x2 x3 a1 a2 a3 y1 y2 y3
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo PB p2 p3 t x1 x2 x3 a1 a2 a3 y1 y2 y3
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo lp x1 x2 x3 a1 a2 a3 y1 y2 y3 P2?
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo lp x1 x2 x3 a1 a2 a3 y1 y2 y3 P2
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo PA? p2 lp p3 t x2 x3 x1 a2 a3 a1 y1 y3 y2
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo PA p2 lp p3 t x2 x3 x1 a2 a3 a1 y1 y3 y2
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo PB? t lp p2 p3 x3 x1 x2 a2 a3 a1 y3 y1 y2
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo PB t lp p2 p3 x3 x1 x2 a2 a3 a1 y3 y1 y2
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo lp lq x1 x2 x3 a1 a2 a3 y1 y2 y3 P3?
#include <stdlib.h> typedef int arr[10000]; arr a1, a2, a3; int cond1, cond2; int *foo (int **p2, int **p3){ int *t; if(cond2){ t = *p2; *p2 = *p3; *p3 = t; } return *p2; } int main(int argc, char *argv[]){ int *x1, *x2, *x3, *y1, *y2, *y3; int *lp, *lq, r; cond1 = argc-1; cond2 = argc-2; a1[0] = argc; a2[0] = argc+1; a3[0] = argc+2; x1 = a1; x2 = a2; x3 = a3; y1 = a1; y2 = a2; y3 = a3; if(cond1){ x1 = a2; x2 = a1; } lp = foo(&x2, &x3); lq = foo(&y2, &y3); return (*lp + *lq); } Context-sensitive example foo lp lq x1 x2 x3 a1 a2 a3 y1 y2 y3 P3
Solutions to the context-sensitive problem • Create a context for each acyclic path from the root of the call graph to the current invocation (EmamiGhyaHendrenPLDI94). • Create a context for each set of “relevant” alias set on entry of procedure --- also known as partial transfer functions (PTF) (WilsonLamPLDI95) • “to answer simple queries (PTF) requires all the results to be computed.” (WhaleyLamPLDI04) (Descriptions taken from RufPLDI95)
Solutions to the context-sensitive problem (cont.) • Tag each alias to allow a procedure to propagate only appropriate aliases to its callers: • uses aliases on entry to the enclosing procedure (LandiRyderPLDI93) • Augment summary with abstraction of call stack (Cooper89MScThesis, ChoiBurkeCarinePoPL93) • A fully context-sensitive analysis is exponential on the size of the input program --- unless the number of contexts considered is limited somehow.