Establishing Local Temporal Heap Safety Properties with Applications
Establishing Local Temporal Heap Safety Properties with Applications to Compile-Time Memory Management Ran Shaham Eran Yahav Elliot Kolodner Mooly Sagiv
Memory deallocation in a timely manner is a hard problem • Premature deallocation Program errors • Late deallocation Memory leaks Inefficient use of memory
(Old) Idea: Compile-Time GC • The compiler can issue free when objects are no longer needed – Object may still be reachable – Potentially collects objects earlier than run-time garbage collection • Low cost • Candidate for memory/cpu constrained environments • Difficult for imperative heap-manipulating programs – No static names for objects – Destructive updates (mutations) x. field=null
Results • A framework for developing static algorithms for memory management – Compile-Time GC • Free an unneeded object • Handle destructive updates – GC assistance • Assign null to heap references • Reduces reachability heap graph • GC exploits information
Plan • • • A motivating example program The heap safety automaton Concrete semantics for deallocating space Abstract semantics for deallocating space Assign Null Summary
A Linked List Example class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); [4] y. val =. . . ; [5] y. n = x; [6] x = y; } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; [11] y = t; } } }
A Linked List Example class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); [4] y. val =. . . ; [5] y. n = x; [6] x = y; } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; [11] y = t; } y } } x u 1 n u 2 n u 3 n u 4 n u 5 n u 6 n u 7
A Linked List Example class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); [4] y. val =. . . ; [5] y. n = x; [6] x = y; } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; [11] y = t; } y t } } x u 1 n u 2 n u 3 n u 4 n u 5 n u 6 n u 7
A Linked List Example class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); [4] y. val =. . . ; [5] y. n = x; [6] x = y; } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; [11] y = t; } y t } } x u 1 n u 2 n u 3 n u 4 n u 5 n u 6 n u 7
A Linked List Example class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); [4] y. val =. . . ; [5] y. n = x; [6] x = y; } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; [11] y = t; } y t } } x u 1 n u 2 n u 3 n u 4 n u 5 n u 6 n u 7
A Linked List Example class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); [4] y. val =. . . ; [5] y. n = x; [6] x = y; } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; [11] y = t; } y } } x u 1 n u 2 n u 3 n u 4 t n u 5 n u 6 n u 7
Free Unneeded Objects class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); [4] y. val =. . . ; [5] y. n = x; [6] x = y; } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; “free y; ” [11] y = t; y } } } x u 1 n u 2 n u 3 n u 4 t n u 5 n u 6 n u 7
When can we free an object? a = malloc(…) ; b = a; // free (a); ? c = malloc (…); if (b == c) printf(“unexpected equality”); Cannot free an object if it has a reference with a future use!
When can free x be inserted after p? cannot free x p some reference to l is used x references an object l On all execution paths after p there are no uses of references to the object referenced by x inserting free x after p is valid
Computing Free Information • Forward (history) information – Heap paths – For free x after p • Aliases of x after p • Backward (future) information – Use of references – For free x after p • Future use of aliases of x after p • Integration of forward and backward heap information – Alternatives • Integration of an operational semantics and a backward collecting semantics • Automaton-based solution – Automaton states record “future” information
The Heap Safety Automaton • Describes a local temporal heap safety property (a typestate property) – Holds on an execution path for an object – Independent of other objects – In an accepting state on an execution path for an object • Used for property verification – Automaton does not reach the “err” state – For all execution paths for all objects
free x after p automaton cannot free x p some reference to l is used x references an object l Automaton for an object l initial refp, x use 0 refp, x 1 use err
A Concrete Semantics for Deallocating Space • Program state – “Usual heap information” • Variable values, Field Values – Free x after p automaton state • For every object l • Program statement effect – “Usual semantics” – Trigger automaton events
Free “y at 10” Automaton class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); Automaton for [4] y. val =. . . ; an object l [5] y. n = x; [6] x = y; initial 0 } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; [11] y = t; } y } } x u 1 S[0] n u 2 S[0] n u 3 S[0] n u 4 S[0] ref 10, y use ref 10, y n u 5 S[0] use 1 n u 6 S[0] n err u 7 S[0]
Free “y at 10” Automaton class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); Automaton for [4] y. val =. . . ; an object l [5] y. n = x; [6] x = y; initial 0 } [7] y = x; (use x) [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; [11] y = t; } y } } x u 1 S[0] n u 2 S[0] n u 3 S[0] n u 4 S[0] ref 10, y use ref 10, y n u 5 S[0] use 1 n u 6 S[0] n err u 7 S[0]
Free “y at 10” Automaton class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); Automaton for [4] y. val =. . . ; an object l [5] y. n = x; [6] x = y; initial 0 } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; [11] y = t; } y t } } x u 1 S[0] n u 2 S[0] n u 3 S[0] n u 4 S[0] ref 10, y use ref 10, y n u 5 S[0] use 1 n u 6 S[0] n err u 7 S[0]
Free “y at 10” Automaton class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); Automaton for [4] y. val =. . . ; an object l [5] y. n = x; [6] x = y; initial 0 } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; (use y, use y. n, ref 10, y) [11] y = t; } y t } } x u 1 S[0] n u 2 S[0] n u 3 S[0] n u 4 S[0] ref 10, y use ref 10, y n u 5 S[0] use 1 n u 6 S[0] n err u 7 S[0]
Free “y at 10” Automaton class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); Automaton for [4] y. val =. . . ; an object l [5] y. n = x; [6] x = y; initial 0 } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; (use y, use y. n, ref 10, y) [11] y = t; } y t } } x u 1 S[0] n u 2 S[0] n u 3 S[0] n u 4 S[0] ref 10, y use ref 10, y n u 5 S[0] use 1 n u 6 S[0] n err u 7 S[0]
Free “y at 10” Automaton class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); Automaton for [4] y. val =. . . ; an object l [5] y. n = x; [6] x = y; initial 0 } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; (use y, use y. n, ref 10, y) [11] y = t; } y t } } x u 1 S[0] n u 2 S[0] n u 3 S[0] n u 4 S[0] ref 10, y use ref 10, y n u 5 S[0] use 1 n u 6 S[0] n err u 7 S[0]
Free “y at 10” Automaton class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); Automaton for [4] y. val =. . . ; an object l [5] y. n = x; [6] x = y; initial 0 } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; (use y, use y. n, ref 10, y) [11] y = t; } y t } } x u 1 S[1] n u 2 S[0] n u 3 S[0] n u 4 S[0] ref 10, y use ref 10, y n u 5 S[0] use 1 n u 6 S[0] n err u 7 S[0]
Free “y at 10” Automaton class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); Automaton for [4] y. val =. . . ; an object l [5] y. n = x; [6] x = y; initial 0 } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; (use y, use y. n, ref 10, y) [11] y = t; } y } } x u 1 S[1] n u 2 S[1] n u 3 S[1] n u 4 S[1] ref 10, y use 1 err t n u 5 S[0] n u 6 S[0] n u 7 S[0]
Abstract Semantics for Deallocating Space – Challenges • Infinite states – Number of objects is unbounded • Precise heap path information – Precise Association of • an event • corresponding automaton state of a program object • Our framework – Allows a rather precise heap abstraction – Abstraction refinement • automaton state of each program object
Abstract Semantics for Deallocating Space • Program state – Heap Abstraction • Parametric Shape Analysis [SRW 02] • Based on 3 -valued logical structures – Automaton States • Unary predicates s[q] • q ranges over automaton states • Program statement effect – Shape analysis abstract transformers – Events associated with every statement update s[q] • Property Verification – s[err] does not hold
Free “y at 10” Automaton class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); Automaton for [4] y. val =. . . ; an object l [5] y. n = x; [6] x = y; initial 0 } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; [11] y = t; } } n } x S[1] n ref 10, y use ref 10, y y use 1 err t n S[0]
Free “y at 10” Automaton class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); Automaton for [4] y. val =. . . ; an object l [5] y. n = x; [6] x = y; initial 0 } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; (use y, use y. n, ref 10, y) [11] y = t; } } n } x S[1] n ref 10, y use ref 10, y y use 1 err t n S[0]
Free “y at 10” Automaton class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); Automaton for [4] y. val =. . . ; an object l [5] y. n = x; [6] x = y; initial 0 } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; (use y, use y. n, ref 10, y) [11] y = t; } } n } x S[1] n ref 10, y use ref 10, y y use 1 err t n S[0]
Free “y at 10” Automaton class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); Automaton for [4] y. val =. . . ; an object l [5] y. n = x; [6] x = y; initial 0 } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; (use y, use y. n, ref 10, y) [11] y = t; } } n } x S[1] n ref 10, y use ref 10, y y use 1 err t n S[0]
Free “y at 10” Automaton class L { // L is a singly linked list public L n; // next field public int val; // data field } class Main { // Creation and traversal of a singly-linked list public static void main(String args[]) { L x, y, t; [1] x = null; [2] while (. . . ) { // list creation [3] y = new L(); Automaton for [4] y. val =. . . ; an object l [5] y. n = x; [6] x = y; initial 0 } [7] y = x; [8] while (y != null) { // list traversal [9] System. out. print(y. val); [10] t = y. n; (use y, use y. n, ref 10, y) [11] y = t; } } n } x S[1] n ref 10, y use ref 10, y y use 1 err t n S[1] n S[0]
Assign Null • Allows GC to collect more space – Reduces heap reachability • Assign-Null automaton – Contains “back-edges”
When can x. f = null be inserted after p? x. f cannot be assigned null p field f of object l is used field f of object l is not assigned p’ x references an object l On all execution paths after p, x. f is not used before redefinition inserting x. f = null after p is valid
When can x. f = null be inserted after p? x. f cannot be assigned null field f of object l is used p p’ field f of object l is not assigned x references an object l refp, x usef, deff initial 0 refp, x deff 1 usef err
When can x. f = null be inserted after p? x. f cannot be assigned null field f of object l is used p p’ field f of object l is not assigned x references an object l refp, x usef, deff initial 0 refp, x deff 1 usef err
When can x. f = null be inserted after p? x. f cannot be assigned null field f of object l is used p p’ field f of object l is not assigned x references an object l refp, x usef, deff initial 0 refp, x deff 1 usef err
When can x. f = null be inserted after p? x. f cannot be assigned null field f of object l is used p p’ field f of object l is not assigned x references an object l refp, x usef, deff initial 0 refp, x deff 1 usef err
When can x. f = null be inserted after p? x. f cannot be assigned null field f of object l is used p p’ field f of object l is not assigned x references an object l refp, x usef, deff initial 0 refp, x deff 1 usef err
Prototype Implementation • Analysis of Java/Java. Card programs • Precise – Points-to is not enough • Even when it is flow-sensitive, field-sensitive with unbounded context [Emami et al. – PLDI 94] • Scalability issues – Interprocedural shape analysis
Related Work • Memory Management – Compile-Time GC • Mostly for functional languages – Escape Analysis • Limited to objects not escaping their allocating method – Region-based memory management • Usually requires programmer awareness • Software verification of safety properties – Bandera, ESP, SLAM • Precision • Application domain
Summary • Statically identify a subset of unneeded objects • Free – Free an unneeded object – Similar to compile-time GC studied for functional languages • We need to handle destructive updates • Assign null – Assign null to heap references – Reduces reachability heap graph – GC exploits information • Identify potential errors – Issue a warning when a potentially needed object is reclaimed • False alarms may arise • A framework – Formulate compile-time memory management as a verification problem
- Slides: 43