320 likes | 433 Views
Policy Enforcement and Refinement. Douglas R. Smith Kestrel Institute Palo Alto, California. Issue: How to Handle Nonfunctional and Cross-Cutting Concerns wrt Composition and Refinement?. A concern is cross-cutting if its manifestation cuts across the
E N D
Policy EnforcementandRefinement Douglas R. Smith Kestrel Institute Palo Alto, California
Issue: How to Handle Nonfunctional and Cross-Cutting Concerns wrtComposition and Refinement? A concern is cross-cutting if its manifestation cuts across the dominant hierarchical structure of a program/system. • Examples • Log all errors that arise during system execution • Enforce a system-wide error-handling policy • Disallow unauthorized data accesses • Enforce timing and resource constraints on a system design
A Generative Approach to Aspect-Oriented Programming hypothesis: aspects are invariants to maintain
FigureElement incrXY() crosscutting(one form of it) Crosscutting in AspectJ * * Display Point Line 2 getX() getY() setX(int)setY(int) incrXY() getP1() getP2() setP1(Point)setP2(Point) incrXY() aspect ObserverUpdating { pointcut moves(): calls(void Line.setP1(Point)) || calls(void Line.setP2(Point)) || calls(void Point.setX(int)) || calls(void Point.setY(int)) || calls(void FigureElement.incrXY()); after(): moves() { Display.update(); } }
Issues with current approaches toAspect-Oriented Programming • What is the intention of an aspect? • When is an aspect correct? • Is the pointcut complete? • What if theadvice needs to cater for various contexts? • Do two aspects conflict? How do we treat them? • What if an aspect is not a pointwise action, but a behavior?
Maintain an Error Log Policy: Maintain an error log in a system
Expressing System Constraints • Many systems constraints refer to • history (events, actions, state,…) • dynamic context (i.e. the call-stack) • environment behavior • substrate properties (e.g. instruction timing, latence, …)
hist :=S0, act0 hist := hist ::S1, act1 hist := hist ::S2, act2 Virtual Variables in State key idea: extend state with a virtual history variable act0 act1 act2 S0 S3 ••• S1 S2 • Virtual variables • exist for purposes of specification • sliced away prior to code generation
Maintain an Error Log Policy: Maintain an error log in a system Invariant: errlog = filter(error?, actions(hist)) Disruptive Actions: error?(act) Spec for Maintenance Code : for each error action erract, Assume: errlog = filter(error?, actions(hist)) Achieve: errlog´ = filter(error?, actions(hist´)) = filter(error?, actions(hist :: S, erract)) = filter(error?, actions(hist):: erract) = filter(error?, actions(hist)):: erract = errlog :: erract spec satisfied by: errlog :=errlog :: erract
Maintaining an Error Log act0 error1 act2 S0 S3 ••• S1 S2 hist :=S0, act0 hist := hist ::S1, act1 hist := hist ::S2, act2 errlog :=errlog errlog :=errlog::error1 errlog :=errlog
General Case • Invariant: I(x) • Disruptive Actions: any action that changes x or an alias • Spec for Maintenance Code : • for each such action act with specification • Assume: P(x) • Achieve: Q(x, x´) • generate and satisfy new specification • Assume: P(x) I(x) • Achieve: Q(x, x´) I(x´) spec typically satisfied by code of the form: act || update
Summary • What is the intention of the aspect? expressed by an invariant • Is the aspect code correct? yes, by construction • Is the pointcut complete? • static analysis finds all actions that disrupt the invariant • Is the advice efficient in all contexts? • specialized code generated for each context • What if several aspects apply at a program point? • attempt to satisfy the joint specification • What if an aspect is not a pointwise action, but a behavior? • enforcement of policy automata
send(*) read(f ) policy automaton: Two One a read(f ) send(m) A B C D F E Enforce a Security Policy Policy: No send actions allowed after file f is read Build simulation map, then generate new code for corresponding actions Inconsistent joint action spec: send(*) send(m) satisfied by abort action
Error-Handling Policiesand their Enforcement Douglas R. Smith Klaus Havelund Kestrel Technology Palo Alto, California www.kestreltechnology.com
NonRobust Java Program class AddNumbersFromFile { static void doIt(String fileName) throws IOException { DataInputStream source = null; if (fileName != null) source = new DataInputStream(new FileInputStream(fileName)); int count = source.readInt(); int sum = addEm(source,count); System.out.println("Sum is " + sum); } static int addEm(DataInputStream s, int c) throws IOException { int sum = 0; for (int i = 0; i < c; i++) sum += s.readInt(); if (s.available() == 0) s.close(); return sum; }}
Generic File Management Policy FileNotFoundException / handler1 IOException / handler2 use open close Start Open Stop use Error handler3
Generic/Library Policy for DataInputStream’s policy DataInputStreamPolicy { string filename; DataInputStream in; Start: { DataInputStream(FileInputStream(filename)) returns in } -> Open Start: { in.read*() } -> Error replace {throw new Error("Attempt to read from an unopen File"); } Start: { in.available() } -> Start replace {throw new Error("Attempt to invoke available on an unopen File");} Start: { in.close() } -> Start replace {print("Attempt to close an unopen File"); } … policy instance variables
Library Policy (continued) Open: { in.read*() } -> Open catch (EOFException e) {throw new Error("EOF: insufficient data in file " + filename); } catch (IOException e) {throw new Error("Cannot read from File " + filename); } Open: { in.available() } -> Open catch (IOException e) {throw new Error("Unable to determine whether file " + filename + " contains more data"); } Open: { in.close() } -> Closed precondition {in.available() == 0} {System.out.println("Closed file " + filename + " when it contained extra data"); } Open : { exit } -> Closed preaction { System.out.println("Performing a missing close on file " + filename); in.close(); …
Example Policy (continued) Closed: { in.read*() } -> Closed replace {throw new Error ("File " + filename + "already closed"); } Closed: { in.available() } -> Closed replace {throw new Error ("Attempt to invoke available on a closed file: " + filename); } Closed: { in.close() } -> Closed replace {throw new Error ("File " + filename + "already closed"); } }
Application-Specific subPolicy for DataInputStreams policy AddNumbersPolicy extends DataInputStreamPolicy { Open0: { count = in.read*() } -> Open1 postcondition (0 <= count && count <= 1000) {System.out.println("count received an illegal value: " + Integer.toString(count) + "\nsetting count to 0"); count = 0;} catch (EOFException e) {throw new Error("File " + in.filename + " contains no data!"); } Open1: { in.read*() } -> Open1 }
Policy Simulation on the Example Program DoIt entry addEm entry {Start} T fileName != null {Open} F sum = 0; i= 0; source = new DataInputStreamPolicy(fileName) {Start} {Open} {Open} ambiguous analysis F T i < c {Start,Open} {Open} count = source.readInteger(); sum += source.readInteger(); i++; {Open} {Open} call addEm(source,count); {Open Closed, Open Open } {Open} T s.available()==0 {Open} sum = result F s.close(); {Open,Closed} {Open} {Closed} System.out.println("Sum is " + sum) {Open, Closed} {Open,Closed} return sum exit {Open, Closed} exit
Program Transformation to Reduce Policy Ambiguity has ambiguous analysis if ( fileName != null ) source = new DataInputStream(new FileInputStream(fileName)); count = source.readInt(); distribute if-then-else over semicolon if ( fileName != null ){ source = new DataInputStream(new FileInputStream(fileName)); count = source.readInt(); } else { count = source.readInt(); } has unambiguous analysis! apply the policy and simplify if ( fileName == null ) throw new Error("Attempt to read from an unopen File"); source = new DataInputStream(new FileInputStream(fileName)); count = source.readInt(); unambiguous analysis, clear code
Revised Java Program with Unambiguous Analysis class AddNumbersFromFile { static void doIt(String fileName) throws IOException { DataInputStream source = null; if ( fileName == null ) {throw new Error("Attempt to read from an unopen File");} source = new DataInputStream(new FileInputStream(fileName)); count = source.readInt(); int sum = addEm(source,count); System.out.println("Sum is " + sum); } static int addEm(DataInputStream s, int c) throws IOException { int sum = 0; for (int i = 0; i < c; i++) sum += s.readInt(); // if (s.available()==0) s.close(); return sum; } }
Policy-Specific Tracking Code (unambiguous case) HandlErr would generate an extension of the DataInputStream class that records the policy instance bindings for the in error-handlers. public class DataInputStreamForAddNumbers1 extends DataInputStream { public String filename; public DataInputStreamForAddNumbers1(String filename) throws FileNotFoundException { super(new FileInputStream(filename)); // field in stores the file handle this.filename = filename; } }
Revised Java Program with Enforced Policy class RobustlyAddNumbersFromFile1 { static void doIt(String fileName) throws IOException{ DataInputStreamForAddNumbers1 source = null; if ( fileName==null ){ throw new Error("Attempt to read from an unopen File"); } try { source = new DataInputStreamForAddNumbers1(fileName); } catch (FileNotFoundException e) { throw new Error("File " + fileName + " cannot be found"); } int count = 0; try { count = source.readInt(); } catch(EOFException e){ source.close(); throw new Error("File " + source.filename + " contains no data!"); } catch(IOException e){ source.close(); throw new Error("Bad data in file" + source.filename); } …
Policy Simulation on the Example Program DoIt entry addEm entry {Start} T fileName != null {Open} F sum = 0; i= 0; source = new DataInputStreamPolicy(fileName) {Start} {Open} {Open} ambiguous analysis F T i < c {Start,Open} {Open} count = source.readInteger(); sum += source.readInteger(); i++; {Open} {Open} call addEm(source,count); {Open Closed, Open Open } {Open} T s.available()==0 {Open} sum = result F s.close(); {Open,Closed} {Open} {Closed} System.out.println("Sum is " + sum) {Open, Closed} {Open,Closed} return sum exit {Open, Closed} exit
Ambiguous Analysis If the analysis remains ambiguous, then some form of runtime tracking of state is required, and runtime enforcement decisions. Technique: use subclassing to track state
Generic File Management Policy FileNotFoundException / handler1 IOException / handler2 use open close Start Open Stop use Error handler3
Runtime State Tracking public class DataInputStreamForAddNumbers extends DataInputStream { public static final int Start = 1; public static final int Open = 2; public static final int Closed = 3; int currentState = Start; public String filename; public DataInputStreamForAddNumbers(String filename) throws FileNotFoundException { super(new FileInputStream(filename)); // field in stores the file handle this.filename = filename; this.currentState = Open; } public boolean inState(int state){ return this.currentState == state; }
Ambiguous Analysis public int readInteger() throws IOException, EOFException{ int x = 0; switch(currentState){ case Start: throw new Error("Attempt to read from an unopen File"); case Open: try{ x = super.readInt(); } catch (EOFException e){ throw new EOFException("File" + filename + "contains no data!"); } catch (IOException e){ throw new IOException("Cannot read from file " + filename); } break; case Closed: throw new Error("File " + filename + "already closed"); } return x; }
Robustified Source – Ambiguous Casewith state tracking and error-handling inside method calls public class RobustAddNumbersFromFile { static void doIt (String fileName) throws IOException { DataInputStreamForAddNumbers source = null; if ( fileName != null ) source = new DataInputStreamForAddNumbers(fileName); int count = source.readInteger(); int sum = addEm(source,count); System.out.println("Sum is " + sum); } static int addEm(DataInputStreamForAddNumbers s, int c) throws IOException { int sum = 0; for (int i = 0; i < c; i++) sum += source.readInteger(); if ( s.available() == 0 ) s.close(); return sum; } }
Conclusions? • many aspects can be treated as invariant maintenance • an invariant corresponds to a one-state automaton policy • automaton-based policies applied by conservative static analysis • error-handling policies combine normal and abnormal behaviors