[topl] Generate simpler monitor for deterministic states.

Summary:
This is an optimization. We ask the user to tell us which states are nondeterministic, and we
generate code that handle nondeterminism only for those states. It is common for only one state per
TOPL property to be nondeterministic. This speeds up the biabduction-analysis of the monitor by a
factor of ~10. But, using the monitor is only a little faster.

Facebook

Reviewed By: jvillard

Differential Revision: D19160286

fbshipit-source-id: 4dd39769a
master
Radu Grigore 5 years ago committed by Facebook Github Bot
parent c9699b9cd4
commit 3554101ece

@ -42,4 +42,8 @@ type vertex = string [@@deriving compare, hash, sexp]
type transition = {source: vertex; target: vertex; label: label} type transition = {source: vertex; target: vertex; label: label}
type t = type t =
{name: property_name; message: string option; prefixes: string list; transitions: transition list} { name: property_name
; message: string option
; prefixes: string list
; nondet: string list
; transitions: transition list }

@ -6,6 +6,7 @@
*) *)
open! IStd open! IStd
module L = Logging
let tt = ToplUtils.debug let tt = ToplUtils.debug
@ -26,25 +27,39 @@ type tindex = int
type transition = {source: vindex; target: vindex; label: ToplAst.label} type transition = {source: vindex; target: vindex; label: ToplAst.label}
(** - INV1: Array.length states = Array.length outgoing (** - INV1: Array.length states = Array.length outgoing = Array.length nondets
- INV2: Array.length transitions = Array.length skips - INV2: Array.length transitions = Array.length skips
- INV3: each index of [transitions] occurs exactly once in one of [outgoing]'s lists - INV3: each index of [transitions] occurs exactly once in one of [outgoing]'s lists
- INV4: max_args is the maximum length of the arguments list in a label on a transition The - INV4: max_args is the maximum length of the arguments list in a label on a transition
fields marked as redundant are computed from the others (when the automaton is built), and are
cached for speed. *) The fields marked as redundant are computed from the others (when the automaton is built), and
are cached for speed. *)
type t = type t =
{ states: vname array { states: vname array
; nondets: bool array (* redundant *)
; transitions: transition array ; transitions: transition array
; skips: bool array (* redundant *) ; skips: bool array (* redundant *)
; outgoing: tindex list array ; outgoing: tindex list array
; vindex: vname -> vindex ; vindex: vname -> vindex
; max_args: int (* redundant; cached for speed *) } ; max_args: int (* redundant *) }
(** [index_in H a x] is the (last) index of [x] in array [a]. *) (** [index_in H a] returns a pair of functions [(opt, err)] that lookup the (last) index of an
let index_in (type k) (module H : Hashtbl_intf.S with type key = k) (a : k array) : k -> int = element in [a]. The difference is that [opt x] returns an option, while [err msg x] makes Infer
die, mentioning [msg].*)
let index_in (type k) (module H : Hashtbl_intf.S with type key = k) (a : k array) :
(k -> int option) * (string -> k -> int) =
let h = H.create ~size:(2 * Array.length a) () in let h = H.create ~size:(2 * Array.length a) () in
let f i x = H.set h ~key:x ~data:i in let f i x = H.set h ~key:x ~data:i in
Array.iteri ~f a ; H.find_exn h Array.iteri ~f a ;
let opt = H.find h in
let err msg x =
match opt x with
| Some x ->
x
| None ->
L.die InternalError "ToplAutomaton.index_in out of bounds (%s)" msg
in
(opt, err)
let make properties = let make properties =
@ -57,7 +72,8 @@ let make properties =
Array.of_list (List.dedup_and_sort ~compare:Vname.compare (List.concat_map ~f properties)) Array.of_list (List.dedup_and_sort ~compare:Vname.compare (List.concat_map ~f properties))
in in
Array.iteri ~f:(fun i (p, v) -> tt "state[%d]=(%s,%s)@\n" i p v) states ; Array.iteri ~f:(fun i (p, v) -> tt "state[%d]=(%s,%s)@\n" i p v) states ;
let vindex = index_in (module Vname.Table) states in let vindex_opt, vindex = index_in (module Vname.Table) states in
let vindex = vindex "vertex" in
let transitions : transition array = let transitions : transition array =
let f p = let f p =
let prefix_pname pname = let prefix_pname pname =
@ -92,6 +108,23 @@ let make properties =
in in
Array.fold ~init:0 ~f transitions Array.fold ~init:0 ~f transitions
in in
let nondets : bool array =
let vcount = Array.length states in
let a = Array.create ~len:vcount false in
let f ToplAst.{nondet; name; _} =
let set_nondet state =
match vindex_opt (name, state) with
| Some i ->
a.(i) <- true
| None ->
L.user_warning
"TOPL: %s declared as nondet, but it appears in no transition of property %s" state
name
in
List.iter ~f:set_nondet nondet
in
List.iter ~f properties ; a
in
let skips : bool array = let skips : bool array =
let is_skip {source; target; label} = let is_skip {source; target; label} =
let r = Int.equal source target in let r = Int.equal source target in
@ -104,13 +137,15 @@ let make properties =
in in
Array.map ~f:is_skip transitions Array.map ~f:is_skip transitions
in in
{states; transitions; skips; outgoing; vindex; max_args} {states; nondets; transitions; skips; outgoing; vindex; max_args}
let outgoing a i = a.outgoing.(i) let outgoing a i = a.outgoing.(i)
let vname a i = a.states.(i) let vname a i = a.states.(i)
let is_nondet a i = a.nondets.(i)
let vcount a = Array.length a.states let vcount a = Array.length a.states
let transition a i = a.transitions.(i) let transition a i = a.transitions.(i)

@ -37,6 +37,8 @@ val outgoing : t -> vindex -> tindex list
val vname : t -> vindex -> vname val vname : t -> vindex -> vname
val is_nondet : t -> vindex -> bool
val vcount : t -> int val vcount : t -> int
val transition : t -> tindex -> transition val transition : t -> tindex -> transition

@ -54,6 +54,7 @@ rule raw_token = parse
| "prefix" { PREFIX } | "prefix" { PREFIX }
| "property" { PROPERTY } | "property" { PROPERTY }
| "message" { MESSAGE } | "message" { MESSAGE }
| "nondet" { NONDET }
| ['a'-'z'] id_tail as id { LID id } | ['a'-'z'] id_tail as id { LID id }
| ['A'-'Z'] id_tail as id { UID id } | ['A'-'Z'] id_tail as id { UID id }
| eof { EOF } | eof { EOF }

@ -341,7 +341,9 @@ let generate_execute_state automaton proc_name =
in in
let transitions = ToplAutomaton.outgoing automaton state in let transitions = ToplAutomaton.outgoing automaton state in
let fold f init = List.fold_right ~init ~f transitions in let fold f init = List.fold_right ~init ~f transitions in
fold check_transition_maybe (fold check_transition skip) let detbranches = fold check_transition skip in
if ToplAutomaton.is_nondet automaton state then fold check_transition_maybe detbranches
else detbranches
in in
let body = let body =
gen_if gen_if

@ -29,6 +29,7 @@
%token LT %token LT
%token MESSAGE %token MESSAGE
%token NE %token NE
%token NONDET
%token PREFIX %token PREFIX
%token PROPERTY %token PROPERTY
%token RC %token RC
@ -42,17 +43,22 @@
properties: ps=one_property* EOF { ps } properties: ps=one_property* EOF { ps }
one_property: one_property:
PROPERTY name=identifier LC message=message? prefixes=prefix* transitions=transition* RC PROPERTY name=identifier LC message=message? prefixes=prefix* nondet=nondet
{ ToplAst.{name; message; prefixes; transitions} } transitions=transition* RC
{ ToplAst.{name; message; prefixes; nondet; transitions} }
message: MESSAGE s=STRING { s } message: MESSAGE s=STRING { s }
prefix: PREFIX s=STRING { s } prefix: PREFIX s=STRING { s }
nondet: NONDET LP ns=state* RP { ns }
transition: transition:
source=identifier ARROW target=identifier COLON label=label source=state ARROW target=state COLON label=label
{ ToplAst.{source; target; label} } { ToplAst.{source; target; label} }
state: i=identifier { i }
label: label:
return=value_pattern ASGN cp=call_pattern condition=condition? return=value_pattern ASGN cp=call_pattern condition=condition?
{ let procedure_name, arguments = cp in { let procedure_name, arguments = cp in

@ -1,5 +1,6 @@
property SkipAfterRemove property SkipAfterRemove
prefix "ArrayList" prefix "ArrayList"
nondet (start)
start -> start: * start -> start: *
start -> removed: remove(Collection, Index) start -> removed: remove(Collection, Index)
removed -> ok: get(collection, index) removed -> ok: get(collection, index)

@ -2,6 +2,7 @@ property HasNext
prefix "Iterator" prefix "Iterator"
prefix "List" prefix "List"
prefix "Scanner" prefix "Scanner"
nondet (start)
start -> start: * start -> start: *
start -> invalid: I = iterator(*) start -> invalid: I = iterator(*)
start -> invalid: Scanner(I, *) // For constructors, biabduction has "this" as first argument start -> invalid: Scanner(I, *) // For constructors, biabduction has "this" as first argument

@ -1,8 +1,8 @@
codetoanalyze/java/topl/IndexSkip.java, IndexSkip.foo(java.util.ArrayList):void, 2, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure foo(...),Taking true branch,Skipping get(...): unknown method,start of procedure saveArgs(...),return from a call to void Property.saveArgs(Object,ArrayList,Object),start of procedure execute(),start of procedure execute_state_0(),Taking false branch,return from a call to void Property.execute_state_0(),start of procedure execute_state_1(),Taking true branch,start of procedure maybe(),return from a call to void Property.maybe(),Taking false branch,start of procedure maybe(),return from a call to void Property.maybe(),Taking false branch,Taking false branch,Taking false branch,return from a call to void Property.execute_state_1(),start of procedure execute_state_2(),Taking false branch,return from a call to void Property.execute_state_2(),start of procedure execute_state_3(),Taking false branch,return from a call to void Property.execute_state_3(),start of procedure execute_state_4(),Taking false branch,return from a call to void Property.execute_state_4(),start of procedure execute_state_5(),Taking false branch,return from a call to void Property.execute_state_5(),start of procedure execute_state_6(),Taking false branch,return from a call to void Property.execute_state_6(),start of procedure execute_state_7(),Taking false branch,return from a call to void Property.execute_state_7(),return from a call to void Property.execute()] codetoanalyze/java/topl/IndexSkip.java, IndexSkip.foo(java.util.ArrayList):void, 2, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure foo(...),Taking true branch,Skipping get(...): unknown method,start of procedure saveArgs(...),return from a call to void Property.saveArgs(Object,ArrayList,Object),start of procedure execute(),start of procedure execute_state_0(),Taking false branch,return from a call to void Property.execute_state_0(),start of procedure execute_state_1(),Taking true branch,Taking false branch,Taking false branch,return from a call to void Property.execute_state_1(),start of procedure execute_state_2(),Taking false branch,return from a call to void Property.execute_state_2(),start of procedure execute_state_3(),Taking false branch,return from a call to void Property.execute_state_3(),start of procedure execute_state_4(),Taking false branch,return from a call to void Property.execute_state_4(),start of procedure execute_state_5(),Taking false branch,return from a call to void Property.execute_state_5(),start of procedure execute_state_6(),Taking false branch,return from a call to void Property.execute_state_6(),start of procedure execute_state_7(),Taking false branch,return from a call to void Property.execute_state_7(),return from a call to void Property.execute()]
codetoanalyze/java/topl/Iterators.java, Iterators.hasNextBad(java.util.List):void, 0, TOPL_ERROR, no_bucket, ERROR, [] codetoanalyze/java/topl/Iterators.java, Iterators.hasNextBad(java.util.List):void, 0, TOPL_ERROR, no_bucket, ERROR, []
codetoanalyze/java/topl/Iterators.java, Iterators.hasNextBad(java.util.List):void, 2, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure hasNextBad(...),Skipping iterator(): unknown method,start of procedure saveArgs(...),return from a call to void Property.saveArgs(Object,List),start of procedure execute(),start of procedure execute_state_0(),Taking false branch,return from a call to void Property.execute_state_0(),start of procedure execute_state_1(),Taking true branch,start of procedure maybe(),return from a call to void Property.maybe(),Taking false branch,start of procedure maybe(),return from a call to void Property.maybe(),Taking false branch,Taking false branch,Taking false branch,return from a call to void Property.execute_state_1(),start of procedure execute_state_2(),Taking false branch,return from a call to void Property.execute_state_2(),start of procedure execute_state_3(),Taking false branch,return from a call to void Property.execute_state_3(),start of procedure execute_state_4(),Taking false branch,return from a call to void Property.execute_state_4(),start of procedure execute_state_5(),Taking false branch,return from a call to void Property.execute_state_5(),start of procedure execute_state_6(),Taking false branch,return from a call to void Property.execute_state_6(),start of procedure execute_state_7(),Taking false branch,return from a call to void Property.execute_state_7(),return from a call to void Property.execute()] codetoanalyze/java/topl/Iterators.java, Iterators.hasNextBad(java.util.List):void, 2, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure hasNextBad(...),Skipping iterator(): unknown method,start of procedure saveArgs(...),return from a call to void Property.saveArgs(Object,List),start of procedure execute(),start of procedure execute_state_0(),Taking false branch,return from a call to void Property.execute_state_0(),start of procedure execute_state_1(),Taking true branch,Taking false branch,Taking false branch,return from a call to void Property.execute_state_1(),start of procedure execute_state_2(),Taking false branch,return from a call to void Property.execute_state_2(),start of procedure execute_state_3(),Taking false branch,return from a call to void Property.execute_state_3(),start of procedure execute_state_4(),Taking false branch,return from a call to void Property.execute_state_4(),start of procedure execute_state_5(),Taking false branch,return from a call to void Property.execute_state_5(),start of procedure execute_state_6(),Taking false branch,return from a call to void Property.execute_state_6(),start of procedure execute_state_7(),Taking false branch,return from a call to void Property.execute_state_7(),return from a call to void Property.execute()]
codetoanalyze/java/topl/Iterators.java, Iterators.hasNextInterproceduralBad(java.util.List):void, 0, TOPL_ERROR, no_bucket, ERROR, [] codetoanalyze/java/topl/Iterators.java, Iterators.hasNextInterproceduralBad(java.util.List):void, 0, TOPL_ERROR, no_bucket, ERROR, []
codetoanalyze/java/topl/Iterators.java, Iterators.hasNextInterproceduralBad(java.util.List):void, 1, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure hasNextInterproceduralBad(...),Skipping iterator(): unknown method,start of procedure saveArgs(...),return from a call to void Property.saveArgs(Object,List),start of procedure execute(),start of procedure execute_state_0(),Taking false branch,return from a call to void Property.execute_state_0(),start of procedure execute_state_1(),Taking true branch,start of procedure maybe(),return from a call to void Property.maybe(),Taking false branch,start of procedure maybe(),return from a call to void Property.maybe(),Taking false branch,Taking false branch,Taking false branch,return from a call to void Property.execute_state_1(),start of procedure execute_state_2(),Taking false branch,return from a call to void Property.execute_state_2(),start of procedure execute_state_3(),Taking false branch,return from a call to void Property.execute_state_3(),start of procedure execute_state_4(),Taking false branch,return from a call to void Property.execute_state_4(),start of procedure execute_state_5(),Taking false branch,return from a call to void Property.execute_state_5(),start of procedure execute_state_6(),Taking false branch,return from a call to void Property.execute_state_6(),start of procedure execute_state_7(),Taking false branch,return from a call to void Property.execute_state_7(),return from a call to void Property.execute(),start of procedure getSingleElementOk(...),Skipping next(): unknown method] codetoanalyze/java/topl/Iterators.java, Iterators.hasNextInterproceduralBad(java.util.List):void, 1, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure hasNextInterproceduralBad(...),Skipping iterator(): unknown method,start of procedure saveArgs(...),return from a call to void Property.saveArgs(Object,List),start of procedure execute(),start of procedure execute_state_0(),Taking false branch,return from a call to void Property.execute_state_0(),start of procedure execute_state_1(),Taking true branch,Taking false branch,Taking false branch,return from a call to void Property.execute_state_1(),start of procedure execute_state_2(),Taking false branch,return from a call to void Property.execute_state_2(),start of procedure execute_state_3(),Taking false branch,return from a call to void Property.execute_state_3(),start of procedure execute_state_4(),Taking false branch,return from a call to void Property.execute_state_4(),start of procedure execute_state_5(),Taking false branch,return from a call to void Property.execute_state_5(),start of procedure execute_state_6(),Taking false branch,return from a call to void Property.execute_state_6(),start of procedure execute_state_7(),Taking false branch,return from a call to void Property.execute_state_7(),return from a call to void Property.execute(),start of procedure getSingleElementOk(...),Skipping next(): unknown method]
codetoanalyze/java/topl/Iterators.java, Iterators.hasNextInterproceduralOk(java.util.List):void, 2, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure hasNextInterproceduralOk(...),Skipping iterator(): unknown method,start of procedure saveArgs(...),return from a call to void Property.saveArgs(Object,List),start of procedure execute(),start of procedure execute_state_0(),Taking false branch,return from a call to void Property.execute_state_0(),start of procedure execute_state_1(),Taking true branch,start of procedure maybe(),return from a call to void Property.maybe(),Taking false branch,start of procedure maybe(),return from a call to void Property.maybe(),Taking false branch,Taking false branch,Taking false branch,return from a call to void Property.execute_state_1(),start of procedure execute_state_2(),Taking false branch,return from a call to void Property.execute_state_2(),start of procedure execute_state_3(),Taking false branch,return from a call to void Property.execute_state_3(),start of procedure execute_state_4(),Taking false branch,return from a call to void Property.execute_state_4(),start of procedure execute_state_5(),Taking false branch,return from a call to void Property.execute_state_5(),start of procedure execute_state_6(),Taking false branch,return from a call to void Property.execute_state_6(),start of procedure execute_state_7(),Taking false branch,return from a call to void Property.execute_state_7(),return from a call to void Property.execute()] codetoanalyze/java/topl/Iterators.java, Iterators.hasNextInterproceduralOk(java.util.List):void, 2, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure hasNextInterproceduralOk(...),Skipping iterator(): unknown method,start of procedure saveArgs(...),return from a call to void Property.saveArgs(Object,List),start of procedure execute(),start of procedure execute_state_0(),Taking false branch,return from a call to void Property.execute_state_0(),start of procedure execute_state_1(),Taking true branch,Taking false branch,Taking false branch,return from a call to void Property.execute_state_1(),start of procedure execute_state_2(),Taking false branch,return from a call to void Property.execute_state_2(),start of procedure execute_state_3(),Taking false branch,return from a call to void Property.execute_state_3(),start of procedure execute_state_4(),Taking false branch,return from a call to void Property.execute_state_4(),start of procedure execute_state_5(),Taking false branch,return from a call to void Property.execute_state_5(),start of procedure execute_state_6(),Taking false branch,return from a call to void Property.execute_state_6(),start of procedure execute_state_7(),Taking false branch,return from a call to void Property.execute_state_7(),return from a call to void Property.execute()]
codetoanalyze/java/topl/Iterators.java, Iterators.hasNextOk(java.util.List):void, 2, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure hasNextOk(...),Skipping iterator(): unknown method,start of procedure saveArgs(...),return from a call to void Property.saveArgs(Object,List),start of procedure execute(),start of procedure execute_state_0(),Taking false branch,return from a call to void Property.execute_state_0(),start of procedure execute_state_1(),Taking true branch,start of procedure maybe(),return from a call to void Property.maybe(),Taking false branch,start of procedure maybe(),return from a call to void Property.maybe(),Taking false branch,Taking false branch,Taking false branch,return from a call to void Property.execute_state_1(),start of procedure execute_state_2(),Taking false branch,return from a call to void Property.execute_state_2(),start of procedure execute_state_3(),Taking false branch,return from a call to void Property.execute_state_3(),start of procedure execute_state_4(),Taking false branch,return from a call to void Property.execute_state_4(),start of procedure execute_state_5(),Taking false branch,return from a call to void Property.execute_state_5(),start of procedure execute_state_6(),Taking false branch,return from a call to void Property.execute_state_6(),start of procedure execute_state_7(),Taking false branch,return from a call to void Property.execute_state_7(),return from a call to void Property.execute()] codetoanalyze/java/topl/Iterators.java, Iterators.hasNextOk(java.util.List):void, 2, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure hasNextOk(...),Skipping iterator(): unknown method,start of procedure saveArgs(...),return from a call to void Property.saveArgs(Object,List),start of procedure execute(),start of procedure execute_state_0(),Taking false branch,return from a call to void Property.execute_state_0(),start of procedure execute_state_1(),Taking true branch,Taking false branch,Taking false branch,return from a call to void Property.execute_state_1(),start of procedure execute_state_2(),Taking false branch,return from a call to void Property.execute_state_2(),start of procedure execute_state_3(),Taking false branch,return from a call to void Property.execute_state_3(),start of procedure execute_state_4(),Taking false branch,return from a call to void Property.execute_state_4(),start of procedure execute_state_5(),Taking false branch,return from a call to void Property.execute_state_5(),start of procedure execute_state_6(),Taking false branch,return from a call to void Property.execute_state_6(),start of procedure execute_state_7(),Taking false branch,return from a call to void Property.execute_state_7(),return from a call to void Property.execute()]
codetoanalyze/java/topl/ScannerFail.java, ScannerFail.readBad():void, 0, TOPL_ERROR, no_bucket, ERROR, [] codetoanalyze/java/topl/ScannerFail.java, ScannerFail.readBad():void, 0, TOPL_ERROR, no_bucket, ERROR, []

@ -1,6 +1,7 @@
property HasNext property HasNext
prefix "Iterator" prefix "Iterator"
prefix "List" prefix "List"
nondet (start)
start -> start: * start -> start: *
start -> invalid: I = iterator(*) start -> invalid: I = iterator(*)
invalid -> valid: <true> = hasNext(i) // treat as shorthand for <B> = hasNext if (b) invalid -> valid: <true> = hasNext(i) // treat as shorthand for <B> = hasNext if (b)
@ -10,12 +11,15 @@ property HasNext
property UnsafeIterator property UnsafeIterator
prefix "Collection" prefix "Collection"
prefix "Iterator" prefix "Iterator"
nondet (start)
start -> start: *
start -> iterating: I = iterator(C) start -> iterating: I = iterator(C)
iterating -> modified: remove(c, *) iterating -> modified: remove(c, *)
iterating -> modified: add(c, *) iterating -> modified: add(c, *)
modified -> error: next(i) modified -> error: next(i)
property UnsafeMapIterator property UnsafeMapIterator
nondet (start)
start -> start: * start -> start: *
start -> gotView: View = keySet(M) start -> gotView: View = keySet(M)
start -> gotView: View = values(M) start -> gotView: View = values(M)
@ -25,7 +29,8 @@ property UnsafeMapIterator
property SkipIndexAfterRemove property SkipIndexAfterRemove
prefix "ArrayList" prefix "ArrayList"
nondet (start)
start -> start: * start -> start: *
start -> removed: remove(Collection, Index) start -> removed: remove(Collection, Index)
removed -> ok: get(collection, index) removed -> ok: get(collection, index)
removed -> error: get(collection, J) // TODO: if (j!=index) removed -> error: get(collection, J) if J != index

@ -4,12 +4,13 @@ property ForwardUncommitted
prefix "javax.servlet" prefix "javax.servlet"
prefix "javax.servlet.{ServletOutputStream,ServletResponse}" prefix "javax.servlet.{ServletOutputStream,ServletResponse}"
prefix "java.io.PrintWriter" prefix "java.io.PrintWriter"
nondet (start)
start -> start: * start -> start: *
start -> tracking: R = "ServletResponse.\<init\>" start -> tracking: R = "ServletResponse.\<init\>"
tracking -> ok: flushBuffer(r) tracking -> ok: flushBuffer(r)
tracking -> gotWriter: W = getWriter(r) tracking -> gotWriter: W = getWriter(r)
gotWriter -> ok: flush(w) gotWriter -> ok: flush(w)
gotWrite -> ok: flushBuffer(r) gotWriter -> ok: flushBuffer(r)
tracking -> gotStream: S = getOutputStream(r) tracking -> gotStream: S = getOutputStream(r)
gotStream -> ok: flush(s) gotStream -> ok: flush(s)
gotStream -> ok: flushBuffer(r) gotStream -> ok: flushBuffer(r)
@ -24,6 +25,7 @@ property ForwardUncommitted
property InterleavedResponse1 property InterleavedResponse1
message "A ServletResponse was asked for both a writer and a stream." message "A ServletResponse was asked for both a writer and a stream."
prefix "javax.servlet.ServletResponse" prefix "javax.servlet.ServletResponse"
nondet (start)
start -> start: * start -> start: *
start -> gotWriter: W = getWriter(R) start -> gotWriter: W = getWriter(R)
start -> gotStream: S = getOutputStream(R) start -> gotStream: S = getOutputStream(R)
@ -34,6 +36,7 @@ property InterleavedResponse2
// vertex names: w = got writer; W = used writer; similarly for s, S // vertex names: w = got writer; W = used writer; similarly for s, S
message "Incompatible methods for putting data into a response were used." message "Incompatible methods for putting data into a response were used."
prefix "javax.servlet.ServletResponse" prefix "javax.servlet.ServletResponse"
nondet (start)
start -> start: * start -> start: *
start -> w: W = getWriter(R) start -> w: W = getWriter(R)
start -> s: S = getOutputStream(R) start -> s: S = getOutputStream(R)

Loading…
Cancel
Save