1 / 93

Trust, but Verify Two-Phase Typing for Dynamic Languages

This research explores static verification approaches for scripting languages using refinement types to ensure array access bounds and functional consistency. It presents challenges and solutions for thorough verification in dynamic environments.

blancal
Download Presentation

Trust, but Verify Two-Phase Typing for Dynamic Languages

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Trust, but VerifyTwo-Phase Typing for Dynamic Languages Panagiotis Vekris, Benjamin Cosman, Ranjit Jhala University of California, San Diego

  2. Scripting Languages – Then “Perl is the duct tape of the Internet.” Hassan Schroeder, Sun's first webmaster “Scripting languages are designed for 'gluing' applications; they use typeless approaches to achieve a higher level of programming and more rapid application development than system programming languages.” John K. Ousterhout

  3. Scripting Languages – Now Front-end Server-side Tooling Complex reasoning calls for stronger guarantees

  4. Talk Outline • Goal: Static Verification of Scripting Languages

  5. Program: Compute index of smallest array element Goal: Verify that array accesses within bounds

  6. Program #1: First-order function minIndexFO(a) { }

  7. Program #1: First-order function minIndexFO(a) { var res =0; return res; }

  8. Program #1: First-order function minIndexFO(a) { var res =0; for (var i =0; i < a.length; i++) { } return res; }

  9. Program #1: First-order function minIndexFO(a) { varres=0; for (var i =0; i < a.length; i++) { if (a[i] < a[res]) res= i; } returnres; }

  10. Program #1: First-order function minIndexFO(a) { if (a.length <=0) return-1; varres=0; for (var i =0; i < a.length; i++) { if (a[i] < a[res]) res= i; } returnres; }

  11. Program #1: First-order function minIndexFO(a) { if (a.length <=0) return-1; varres=0; for (var i =0; i < a.length; i++) { if (a[i] < a[res]) res= i; } returnres; } Array bound checks: easy Dataflow Analysis: 0≤res≤i<a.length

  12. Program #2: Higher-Order function $reduce(a, f, x) { var res = x; for (var i =0; i < a.length; i++) { • res = f(res, a[i], i); } returnres; }

  13. Program #2: Higher-Order function $reduce(a, f, x) { var res = x; for (var i =0; i < a.length; i++) { • res = f(res, a[i], i); } returnres; } • function minIndexHO(a) { • if (a.length <=0) return-1; • function step(min, cur, i) { • return (cur < a[min]) ? i : min; • } • return $reduce(a, step, 0); • }

  14. Challenge: Verify array access function $reduce(a, f, x) { var res = x; for (var i =0; i < a.length; i++) { • res = f(res, a[i], i); } returnres; } • function minIndexHO(a) { • if (a.length <=0) return-1; • function step(min, cur, i) { • return (cur < a[min]) ? i : min; • } • return $reduce(a, step, 0); • } Hard to track relational facts among values and closures with DataFlow analyses

  15. Easy to track relational facts among values and closures with Refinement Types

  16. Talk Outline • Goal: Static Verification of Scripting Languages • Approach: Refinement Types

  17. “Set of valid indices for array a” • type idx<a>={v: number|0 <= v && v <a.length} • type idx<a>={v: number|0 <= v && v <a.length}

  18. “Set of valid indices for array a” • type idx<a>={v: number|0 <= v && v <a.length} Base Type

  19. “Set of valid indices for array a” • type idx<a>={v: number|0 <= v && v <a.length} Logical Predicate

  20. “Set of valid indices for array a” • type idx<a>={v: number|0 <= v && v <a.length} Value Variable

  21. “Set of valid indices for array a” • type idx<a>={v: number|0 <= v && v <a.length}

  22. Higher-Order Example • function $reduce(a, f, x) { • varres = x; • for (var i =0; i < a.length; i++) • res = f(res, a[i], i); • returnres; • }

  23. Higher-Order Type Checking • function $reduce<A,B>(a: A[], f: (B,A,number) => B, x: B): B { • varres = x; • for (var i =0; i < a.length; i++) • res = f(res, a[i], i); • returnres; • }

  24. Higher-Order Value Checking • type idx<a>= { v:number|0 <= v&&v<a.length } • function $reduce<A,B>(a: A[], f: (B,A,idx<a>) => B, x: B): B { • varres = x; • for (var i =0; i < a.length; i++) • res = f(res, a[i], i); • returnres; • } + Refinements [Xi’99]

  25. TypeAnalysis Needs Value Analysis

  26. But there is a tricky problem ...

  27. Problem: “Value Based” Overloading https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

  28. Talk Outline • Goal: Static Verification of Scripting Languages • Approach: Refinement Types • Problem: Value Based Overloading

  29. Value Based Overloading function reduce(a, f, x) { • if (arguments.length ===3) • return$reduce(a, f, x); else • return$reduce(a, f, a[0]); }

  30. Value Based Overloading function reduce(a, f, x) { • if (arguments.length ===3) • return$reduce(a, f, x); else • return$reduce(a, f, a[0]); } Type when called with 3 values: • functionreduce<A,B>(a: A[], f: (B,A,idx<a>) => B, x: B): B

  31. Value Based Overloading function reduce(a, f, x) { • if (arguments.length ===3) • return$reduce(a, f, x); else • return$reduce(a, f, a[0]); } Type when called with 3 values: • functionreduce<A,B>(a: A[], f: (B,A,idx<a>) => B, x: B): B Type when called with 2 values: • functionreduce<A>(a: A[]+, f: (A,A,idx<a>) => A): A

  32. TypeAnalysis Needs Value Analysis

  33. TypeAnalysis Needs Needs Value Analysis

  34. TypeAnalysis Needs Circular Dependency Needs Value Analysis

  35. TypeAnalysis Needs Two-Phased Typing Needs Value Analysis

  36. Talk Outline • Goal: Static Verification of Scripting Languages • Approach: Refinement Types • Problem: Overloading • Solution: Two-Phased Typing

  37. Two-Phased Typing – Goal • functionnegate(flag, x) { • if (flag) return0- x; • elsereturn!x; • } (1) If flag≠0 then x: number (2) Ifflag=0 thenx: boolean

  38. Two-Phased Typing – Goal • functionnegate(flag, x) { • if (flag) return0- x; • elsereturn!x; • } (1) If flag≠0 then x: number (2) Ifflag=0 thenx: boolean • varok1= negate(1, 1); • var ok2 = negate(0, true);

  39. Two-Phased Typing – Goal • functionnegate(flag, x) { • if (flag) return0- x; • elsereturn!x; • } (1) If flag≠0 then x: number (2) Ifflag=0 thenx: boolean • varok1= negate(1, 1); • var ok2 = negate(0, true); • var bad1 = negate(0, 1); • var bad2 = negate(1, true);

  40. Two-Phased Typing – Goal • functionnegate(flag, x) { • if (flag) return0- x; • elsereturn!x; • } (1) If flag≠0 then x: number (2) Ifflag=0 thenx: boolean

  41. Specification • type tt = {v: number| v ≠0} // "truthy" numbers • type ff = {v: number| v =0} // "falsy" numbers • functionnegate(flag, x) { • if (flag) return0- x; • elsereturn!x; • } (1) If flag≠0 then x: number (2) Ifflag=0 thenx: boolean

  42. Specification • type tt = {v: number| v ≠0} // "truthy" numbers • type ff = {v: number| v =0} // "falsy" numbers • functionnegate(flag, x) { • if (flag) return0- x; • elsereturn!x; • } (1) Ifflag: tt then x: number (2) Ifflag: ff thenx: boolean

  43. Specification • type tt = {v: number| v ≠0} // "truthy" numbers • type ff = {v: number| v =0} // "falsy" numbers • function negate(flag: tt, x: number):number; • function negate(flag: ff, x: boolean):boolean; • functionnegate(flag, x) { • if (flag) return0- x; • elsereturn!x; • } Incorporate in negate’s type

  44. Verification • type tt = {v: number| v ≠0} // "truthy" numbers • type ff = {v: number| v =0} // "falsy" numbers • function negate(flag: tt, x: number):number; • function negate(flag: ff, x: boolean):boolean; • functionnegate(flag, x) { • if (flag) return0- x; • elsereturn!x; • } • varok1= negate(1, 1); • var ok2 = negate(0, true); • var bad1 = negate(0, 1); • var bad2 = negate(1, true); (A) Statically check negate’s body (B) Statically check call-sites

  45. Safe Two-Phased Typing Unsafe Source Program

  46. Safe Trust Verify • Cons Gen • Check • Clone • Cast • Resolve Unsafe Source Program Elaborated Program

  47. 1st Phase (Trust) – Clone function negate(flag: tt, x: number):number; • function negate(flag: ff, x: boolean):boolean; function negate(flag, x) { if (flag) return0- x; elsereturn!x; } Split overloaded functions

  48. 1st Phase (Trust) – Clone function negate#1(flag: tt, x: number):number{ • if (flag) return0- x; elsereturn!x; } function negate(flag: tt, x: number):number; • function negate(flag: ff, x: boolean):boolean; function negate(flag, x) { if (flag) return0- x; elsereturn!x; } • function negate#2(flag: ff, x: boolean):boolean{ • if (flag) return0- x; elsereturn!x; } One clone for each conjunct

  49. Safe Trust Verify • Cons Gen • Check • Clone • Cast • Resolve Unsafe Source Program Elaborated Program

  50. 1st Phase (Trust) – Cast function negate#1(flag: tt, x: number):number{ • if (flag) return0- x; elsereturn!x; } • function negate#2(flag: ff, x: boolean):boolean{ • if (flag) return0- x; elsereturn!x; } Check each clone separately

More Related