Presentation is loading. Please wait.

Presentation is loading. Please wait.

1 Practical Pluggable types for Java Chris Andreae James Noble Victoria University of Wellington Shane Arkus Todd Millstein University of California Presented.

Similar presentations


Presentation on theme: "1 Practical Pluggable types for Java Chris Andreae James Noble Victoria University of Wellington Shane Arkus Todd Millstein University of California Presented."— Presentation transcript:

1 1 Practical Pluggable types for Java Chris Andreae James Noble Victoria University of Wellington Shane Arkus Todd Millstein University of California Presented by Lina Zarivach

2 2 Existing type systems are not sufficient Non-null types Declaring and Checking Non-null Types by M. Fahndrich, OOPSLA’03 Non-Null Safety in Eiffel by B. Meyer, ECOOP’05 Readonly types Javari by M. Tschantz, OOPSLA’05 Other type systems Confined Types by J. Vitek, OOPSLA’99 …

3 3 Implementation Ad-hoc: New keywords and compiler reimplementation. Pluggable type systems: Idea by Gilad Bracha, ’04. Implementation by Andreae, Nobel et.al. ’06: JavaCOP  Define new types with Java Annotations  Express new type requirements via JavaCOP Rule Language

4 4 NonNull types example – Pseudo-Declarative syntax & semantics class Person { @NonNull String firstName = "Chris"; void setFirstName(String newName) { firstName = newName;} } A JavaCOP rule to discover this case: rule checkNonNull(Assign a) { where(nonnull(a.lhs)) { require(defNonNull(a.rhs)): error(a,“Assigning possible null to @NonNull variable”); } newName may be NULL!!!

5 5 javac compiler JavaCOP Architecture Java program with new types AST of the program JavaCOP rules

6 6 JavaCOP Rule Language Types A subset of data types generated in the javac compiler. In particular: AST nodes types Type type Symbol type String and generic List types Env Globals

7 7 AST Node types Method call, like meth(args); Instance creation, like new World(“Hello”); Field or method selection, i.e., o.field or o.method();

8 8 Symbols and Types Symbol Table … …

9 9 Rules for AST nodes rule aTreeRule(Tree arg) { } rule finalClass(ClassDef c){ require(!c.supertype().getSym().hasAnnotation("Final")); } Only one argument of type Tree or subclasses of Tree. The rule will be applied to each node of the specified type. Huge API

10 10 Primitive Constraints require( ); rule UnconditionalIf (If i){ require(i.cond.getSymbol != globals.trueConst ): warning(i.cond,"The body of this if will unconditionally be executed"); require(i.cond.getSymbol != globals.falseConst ): warning(i.cond,"The body of this if will never be executed"); } Instance of Globals

11 11 Conditional Constraints where( ) { } rule MicroPatternsExample (ClassDef c){ where(c.isInterface && c.getSym.members.length == 0){ require(c.interfaces.length != 1): warning(globals.NOPOS, "Taxonomy:"+c.flatName ); } Primitive constraint

12 12 Pattern matching where( ; tree => [match using vars]) { } rule checkNonNullFieldAccess(Assign a){ where(nonnull(a.lhs)) { where(String n; a.rhs => [%.n]){ require(n.equals("class")): error(a, "Assigning possibly null field access " + " to @NonNull variable"); }}} % is a wildcard for Tree.

13 13 Universal quantifier Similar to the “enhanced for” in Java 1.5. rule finalMethod(MethodDef m){ forall(Type st: m.enclClass.transitiveSupertypes){ forall(Symbol other: st.getSymbol.memberLookup(m.name)){ where(other.isFinal){ require(!m.overrides(other, st.getSymbol)) :error(m, "You may not override final method "+other ); } } } }

14 14 Existential quantifier Implicit depth-first traversal from a given AST node. Only nodes that match the declared type of the quantifier variable are considered. rule allLocalVarsMustBeAssigned (MethodDef m){ forall(VarDef v : m.varDefs()){ where(v.init == null){ exists(Assign a : m){ require(a.lhs.getSymbol == v.getSymbol ); }: error(v,"The variable " + v + "is never assigned"); }}}

15 15 Predicates (package several conditions into boolean function) declare ( [, ]) { } Invoked by the bodies of rules and other predicates. declare nonnull(Tree t){ require(t.holdsSymbol && t.getSymbol.hasAnnotation("NonNull")); }

16 16 Predicates - achieving disjunctive constraints Predicate can have multiple definitions. An invocation of the predicate succeeds if at least one of the definitions’ bodies is satisfied. declare defNotNull(Tree t){ require(nonnull(t)); } declare defNotNull(Tree t){ require(t.type.isPrimitive()); } declare defNotNull(NewClass t){ require(true); } t is non-null if it has @NonNull annotation. Primitives can’t be null. New instance can’t be null.

17 17 Error reporting : (, ) is either error or warning. When a constraint fails to be satisfied, JavaCOP searches for the nearest enclosing failure clause and executes it. require(a){ require(b); require(c): error(pos1, "error - c has failed"); }: warning(globals.NOPOS, "warning - a or b have failed")

18 18 Rules for custs – syntactic sugar rule aCustRule(origType } Applied to every Tree node that performs explicit or implicit cust rule checkNonNullCust (a <: b @ e){ where(!nonnull(a)){ require(!nonnull(b)): error(e, “A possibly null type "+a +" may not be cast to Non-Null type "+b); }

19 19 Applications A checker for non-null types. A checker for Confined Types. Rules supplied by PMD Java Checker. Rules to identify some micro-patterns. Rules that gather information for software metrics. An EJB3.0 verifier.

20 20 NonNull assignment rule checkNonNullAssignment (Assign a){ where(nonnull(a.lhs )){ require(defNotNull(a.rhs)): error(a,"Assigning possibly null value to @NonNull” "+"variable."); } if(x != null){ @NonNull Object nonnull_x = x;...} The above rule will issue an error for this case!!!

21 21 NonNull assignment – flow-sensitive check rule checkNonNull (Assign a){ where(nonnull(a.lhs )){ require(defNotNull(a.rhs) || safeNullableAssign (a)): error(a,"Assigning possibly null value to @NonNull "+"variable."); }} declare safeNullableAssign (Assign a){ require(localVariable (a.rhs )); require(safeNullableAssign (env.tree, env.next, a)); } declare safeNullableAssign (Block b, Env e, Assign a){ require(safeNullableAssign (e.tree, e.next, a)); } declare safeNullableAssign (If i, Env e, Assign a){ require(nonNullTest(i.cond, a.rhs)&& firstExpression (i.thenpart, a)); } Env represents traversal information

22 22 Confined types Confined type is a type whose instances may not be referenced or accessed from outside a certain protection domain. Confined types protect objects from use by untrusted code.

23 23 Confined types – example 1 A confined type must not be declared public and must not belong to the unnamed global package. rule ConfinedExample1 (ClassDef c){ where(confined(c)){ require(!c.isPublic ()): error(c, "Confined class may not be public"); require(c.packge() != globals.emptyPackage): error(c, "Confined class may not be in the default package"); }

24 24 Confined Types – example 2 Subtypes of a confined type must be confined and belong to the same package as their supertype. rule ConfinedExample2 (ClassDef c){ where(confined(c.supertype)){ require(confined(c)): error(c, "An unconfined class may not extend " + "a confined superclass"); require(c.packge == c.supertype.packge): error(c, “A confined subclass must belong to the same package as its superclass”); }

25 25 JavaCOP Architecture - details Performance: ~0.02 sec/class

26 26 Conclusions The first practical framework for pluggable types. Contributions: Design of JavaCOP Rule Language Implementation of JavaCOP Validation on various kinds of application Future extensions: More support for flow sensitivity Error clause, that count the number of times a constraint failed. Increasing the efficiency of checking the constraints.


Download ppt "1 Practical Pluggable types for Java Chris Andreae James Noble Victoria University of Wellington Shane Arkus Todd Millstein University of California Presented."

Similar presentations


Ads by Google