Summary: Instrument SIL according to TOPL properties. Roughly, the instrumentation is a set of calls into procedures that simulate a nondeterministic automaton. For now, those procedures are NOP dummies. Reviewed By: jvillard Differential Revision: D15063942 fbshipit-source-id: d22c2f6famaster
							parent
							
								
									6f422fb78f
								
							
						
					
					
						commit
						047c64c528
					
				| @ -0,0 +1,81 @@ | ||||
| (* | ||||
|  * Copyright (c) 2019-present, Facebook, Inc. | ||||
|  * | ||||
|  * This source code is licensed under the MIT license found in the | ||||
|  * LICENSE file in the root directory of this source tree. | ||||
|  *) | ||||
| 
 | ||||
| open! IStd | ||||
| 
 | ||||
| module Vname = struct | ||||
|   module T = struct | ||||
|     type t = ToplAst.property_name * ToplAst.vertex [@@deriving compare, hash, sexp] | ||||
|   end | ||||
| 
 | ||||
|   include T | ||||
|   include Hashable.Make (T) | ||||
| end | ||||
| 
 | ||||
| type vname = Vname.t | ||||
| 
 | ||||
| type vindex = int | ||||
| 
 | ||||
| type tindex = int | ||||
| 
 | ||||
| type transition = {source: vindex; target: vindex; label: ToplAst.label} | ||||
| 
 | ||||
| (** INV1: Array.length states = Array.length outgoing | ||||
|     INV2: each index of [transitions] occurs exactly once in one of [outgoing]'s lists *) | ||||
| type t = | ||||
|   { states: vname array | ||||
|   ; transitions: transition array | ||||
|   ; outgoing: tindex list array | ||||
|   ; vindex: vname -> vindex } | ||||
| 
 | ||||
| (** [index_in H a x] is the (last) index of [x] in array [a]. *) | ||||
| let index_in (type k) (module H : Hashtbl_intf.S with type key = k) (a : k array) : k -> int = | ||||
|   let h = H.create ~size:(2 * Array.length a) () in | ||||
|   let f i x = H.set h ~key:x ~data:i in | ||||
|   Array.iteri ~f a ; | ||||
|   let find x = H.find_exn h x in | ||||
|   find | ||||
| 
 | ||||
| 
 | ||||
| let make properties = | ||||
|   let states : vname array = | ||||
|     let open ToplAst in | ||||
|     let f p = | ||||
|       let f {source; target; _} = [(p.name, source); (p.name, target)] in | ||||
|       List.concat_map ~f p.transitions | ||||
|     in | ||||
|     Array.of_list (List.concat_map ~f properties) | ||||
|   in | ||||
|   let vindex = index_in (module Vname.Table) states in | ||||
|   let transitions : transition array = | ||||
|     let f p = | ||||
|       let prefix_pname pname = | ||||
|         "^\\(\\|" ^ String.concat ~sep:"\\|" p.ToplAst.prefixes ^ "\\)\\." ^ pname ^ "()$" | ||||
|       in | ||||
|       let f t = | ||||
|         let source = vindex ToplAst.(p.name, t.source) in | ||||
|         let target = vindex ToplAst.(p.name, t.target) in | ||||
|         let procedure_name = prefix_pname ToplAst.(t.label.procedure_name) in | ||||
|         let label = {t.ToplAst.label with procedure_name} in | ||||
|         {source; target; label} | ||||
|       in | ||||
|       List.map ~f p.ToplAst.transitions | ||||
|     in | ||||
|     Array.of_list (List.concat_map ~f properties) | ||||
|   in | ||||
|   let outgoing : tindex list array = | ||||
|     let vcount = Array.length states in | ||||
|     let a = Array.create ~len:vcount [] in | ||||
|     let f i t = a.(t.source) <- i :: a.(t.source) in | ||||
|     Array.iteri ~f transitions ; a | ||||
|   in | ||||
|   {states; transitions; outgoing; vindex} | ||||
| 
 | ||||
| 
 | ||||
| let transition a i = a.transitions.(i) | ||||
| 
 | ||||
| let tcount a = Array.length a.transitions | ||||
| @ -0,0 +1,39 @@ | ||||
| (* | ||||
|  * Copyright (c) 2019-present, Facebook, Inc. | ||||
|  * | ||||
|  * This source code is licensed under the MIT license found in the | ||||
|  * LICENSE file in the root directory of this source tree. | ||||
|  *) | ||||
| 
 | ||||
| open! IStd | ||||
| 
 | ||||
| (* An automaton is a different representation for a set of TOPL properties: states and transitions | ||||
|    are identified by nonnegative integers; and transitions are grouped by their source. Also, the | ||||
|    meaning of transition labels does not depend on context (e.g., prefixes are now included). | ||||
| 
 | ||||
|    We identify states by integers because biabduction tracks integers well; for example, equality | ||||
|    checks on integers are obvious, we don't need to worry about whether we should be using an | ||||
|    equals() method. | ||||
| 
 | ||||
|    We identify transitions by integers because, in the monitor code that we generate, we use a | ||||
|    boolean variable transitionN to tell if the static part of a transition guard is satisfied. The N | ||||
|    is just some identifier for the transition, and integers are convenient identifiers. | ||||
| 
 | ||||
|    NOTE: Now, the signature is the minimal needed for code instrumentation, but the implementation | ||||
|    does some extra work (such as grouping transitions by their source) that will be useful for | ||||
|    code generation. (TODO: remove note once code generation is implemented.) | ||||
| *) | ||||
| 
 | ||||
| type t | ||||
| 
 | ||||
| type vindex = int | ||||
| 
 | ||||
| type tindex = int (* from 0 to tcount()-1, inclusive *) | ||||
| 
 | ||||
| type transition = {source: vindex; target: vindex; label: ToplAst.label} | ||||
| 
 | ||||
| val make : ToplAst.t list -> t | ||||
| 
 | ||||
| val transition : t -> tindex -> transition | ||||
| 
 | ||||
| val tcount : t -> int | ||||
| @ -0,0 +1,14 @@ | ||||
| /* | ||||
|  * Copyright (c) 2019-present, Facebook, Inc. | ||||
|  * | ||||
|  * This source code is licensed under the MIT license found in the | ||||
|  * LICENSE file in the root directory of this source tree. | ||||
|  */ | ||||
| import java.util.*; | ||||
| 
 | ||||
| class Iterators { | ||||
|   void hasNextBad_FN(List<Integer> x) { | ||||
|     Iterator<Integer> i = x.iterator(); | ||||
|     i.next(); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,29 @@ | ||||
| property HasNext | ||||
|   prefix <java.util.{Collection,Iterator}> | ||||
|   start -> start: * | ||||
|   start -> invalid: I = iterator(*) | ||||
|   invalid -> valid: <true> = hasNext(i) // treat as shorthand for <B> = hasNext if (b) | ||||
|   valid -> invalid: next(i) | ||||
|   invalid -> error: next(i) | ||||
| 
 | ||||
| property UnsafeIterator | ||||
|   prefix <java.util.{Collection,Iterator}> | ||||
|   start -> iterating: I = iterator(C) | ||||
|   iterating -> modified: remove(c, *) | ||||
|   iterating -> modified: add(c, *) | ||||
|   modified -> error: next(i) | ||||
| 
 | ||||
| property UnsafeMapIterator | ||||
|   start -> start: * | ||||
|   start -> gotView: View = keySet(M) | ||||
|   start -> gotView: View = values(M) | ||||
|   gotView -> iterating: I = iterator(view) | ||||
|   iterating -> updated: put(m, *) | ||||
|   updated -> error: next(i) | ||||
| 
 | ||||
| property SkipIndexAfterRemove | ||||
|   prefix <java.util.ArrayList> | ||||
|   start -> start: * | ||||
|   start -> removed: remove(Collection, Index) | ||||
|   removed -> ok:    get(collection, index) | ||||
|   removed -> error: get(collection, J) // TODO: if (j!=index) | ||||
					Loading…
					
					
				
		Reference in new issue