Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix EvalAssert transformation to work on coreutil programs #855

Merged
merged 31 commits into from
Oct 28, 2022
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8230749
Default to bottom values in the ask.global for transformations.
jerhard Oct 13, 2022
05ce1fa
EvalAssert transformation: Add declarations for functions in ouptut f…
jerhard Oct 13, 2022
04aa143
Fix YAML witness precondition invariant TypeOfError-s
sim642 Sep 19, 2022
e52b3c0
ad_invariants: Do not generate invariants for pointers when the point…
jerhard Oct 13, 2022
af65ce4
UnionDomain: Fix invariant generation for the case an offset is given.
jerhard Oct 14, 2022
29ef774
Fix indentation in UnionDomain.
jerhard Oct 14, 2022
1c899eb
Use List.partition, remove unnecessary function.
jerhard Oct 14, 2022
bd65a86
Transformation: Change reordering of Cile.file.globals: insert functi…
jerhard Oct 14, 2022
c2fc3db
Format cilfacade.ml
jerhard Oct 14, 2022
efc9f96
Add option witness.invariant.blobs (disabled by default.)
jerhard Oct 14, 2022
139b03a
Change assert to __VERIFIER_assert for assertions created by evalAssert.
jerhard Oct 17, 2022
12a7da9
Pass WitnessUtil.Invariant to transformations; use it in EvalAssert t…
jerhard Oct 18, 2022
2dd919e
Revert "Pass WitnessUtil.Invariant to transformations; use it in Eval…
jerhard Oct 18, 2022
61e1b09
Rename option witness.invariant.blobs to ana.base.invariant.blob
jerhard Oct 18, 2022
e840d56
Merge branch 'master' into fix_evalAssert
jerhard Oct 18, 2022
8b338da
Remove check von TVoid in i_deref in ad_invariant.
jerhard Oct 18, 2022
b5e0fd6
Add script to generate sv-comp bencmarks from coreutils
jerhard Oct 18, 2022
a4f0a6e
Add test case for invariant generation for unions.
jerhard Oct 19, 2022
29badce
Move coreutils.py to scripts folder, change configuration to intervals
jerhard Oct 19, 2022
105b5e2
Revert "Fix indentation in UnionDomain."
jerhard Oct 19, 2022
cfa07d6
Revert "UnionDomain: Fix invariant generation for the case an offset …
jerhard Oct 19, 2022
d85be1f
Merge #861
jerhard Oct 19, 2022
bb4da03
Add cast to void* in generated asserts about pointers
jerhard Oct 24, 2022
22da93a
ad_invariant: Add cast to void* to both pointers if their typesignatu…
jerhard Oct 25, 2022
949f1e8
EvalAssert transformation: Do not add declarations for __builtin func…
jerhard Oct 25, 2022
cc78242
coreutils.py: Generate assertions with both interval and non-interval…
jerhard Oct 25, 2022
6599ed8
Remove scripts/coreutils.py from analyzer repo.
jerhard Oct 25, 2022
c85cc67
Use Cilfacade.mkCast instead of Cil.mkCast.
jerhard Oct 25, 2022
bed9a19
Fix indentation in ValueDomain.ad_invariant.
jerhard Oct 25, 2022
1071e25
Update comment in test case.
jerhard Oct 25, 2022
a929c64
Merge branch 'master' into fix_evalAssert
sim642 Oct 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions src/cdomains/unionDomain.ml
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,22 @@ struct
| Cil.NoOffset ->
let c_lval = Option.get lval in
begin match lift_f with
| `Lifted f ->
let f_lval = Cil.addOffsetLval (Field (f, NoOffset)) c_lval in
value_invariant ~offset ~lval:(Some f_lval) v
| `Top
| `Bot ->
Invariant.none
| `Lifted f ->
let f_lval = Cil.addOffsetLval (Field (f, NoOffset)) c_lval in
value_invariant ~offset ~lval:(Some f_lval) v
| `Top
| `Bot ->
Invariant.none
end
(* invariant for one field *)
| Field (f, offset) ->
let c_lval = Option.get lval in
begin match lift_f with
| `Lifted f' ->
let v = Values.cast ~torg:f'.ftype f.ftype v in
let f_lval = Cil.addOffsetLval (Field (f, NoOffset)) c_lval in
value_invariant ~offset ~lval:(Some f_lval) v
(* Do not add the field offset to lval here:
Otherwise, for pointers to a member type of the union, this would
generate an assertion with illegal field offset. *)
value_invariant ~offset ~lval:lval v
| `Top
| `Bot ->
Invariant.none
Expand Down
15 changes: 13 additions & 2 deletions src/cdomains/valueDomain.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1246,7 +1246,18 @@ struct
else
Invariant.none
in
let i_deref = deref_invariant ~vs ~lval vi offset (Mem c_exp, NoOffset) in
let i_deref =
match Cilfacade.typeOfLval (Var vi, offset) with
| TVoid _ -> Invariant.none (* TODO: Try to determine type of abstract value and introduce appropriate casts *)
| typ ->
(* Address set for a void* variable contains pointers to values of non-void type,
so insert pointer cast to make invariant expression valid (no field/index on void). *)
let newt = TPtr (typ, []) in
let c_exp = Cilfacade.mkCast ~e:c_exp ~newt in
deref_invariant ~vs ~lval vi offset (Mem c_exp, NoOffset)
| exception Cilfacade.TypeOfError _ -> (* typeOffset: Index on a non-array on calloc-ed alloc variables *)
Invariant.none
in

Some (Invariant.(acc || (i && i_deref)))
| Addr.NullPtr ->
Expand Down Expand Up @@ -1285,9 +1296,9 @@ struct
else
Invariant.none
| `Address n -> ad_invariant ~vs ~offset ~lval n
| `Blob n -> blob_invariant ~vs ~offset ~lval n
| `Struct n -> Structs.invariant ~value_invariant:(vd_invariant ~vs) ~offset ~lval n
| `Union n -> Unions.invariant ~value_invariant:(vd_invariant ~vs) ~offset ~lval n
| `Blob n when GobConfig.get_bool "witness.invariant.blobs" -> blob_invariant ~vs ~offset ~lval n
| _ -> Invariant.none (* TODO *)

(* TODO: remove duplicate lval arguments? *)
Expand Down
8 changes: 7 additions & 1 deletion src/framework/control.ml
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,13 @@ struct
; context = (fun () -> ctx_failwith "No context in query context.")
; edge = MyCFG.Skip
; local = local
; global = (fun g -> EQSys.G.spec (GHT.find gh (EQSys.GVar.spec g)))
; global =
(fun g ->
try
EQSys.G.spec (GHT.find gh (EQSys.GVar.spec g))
with Not_found ->
M.warn ~category:MessageCategory.Unsound "Global %a not found during transformation, proceeding with bot." Spec.V.pretty g;
Spec.G.bot ())
; spawn = (fun v d -> failwith "Cannot \"spawn\" in query context.")
; split = (fun d es -> failwith "Cannot \"split\" in query context.")
; sideg = (fun v g -> failwith "Cannot \"split\" in query context.")
Expand Down
6 changes: 6 additions & 0 deletions src/transform/evalAssert.ml
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,14 @@ module EvalAssert = struct
in
ChangeDoChildrenPost (s, instrument_statement)
end

let transform (ask: ?node:Node.t -> Cil.location -> Queries.ask) file = begin
visitCilFile (new visitor ask) file;

(* Add function declarations before function definitions.
This way, asserts may reference functions defined later. *)
Cilfacade.add_function_declarations file;

let assert_filename = GobConfig.get_string "trans.output" in
let oc = Stdlib.open_out assert_filename in
dumpFile defaultCilPrinter oc assert_filename file; end
Expand Down
163 changes: 89 additions & 74 deletions src/util/cilfacade.ml
Original file line number Diff line number Diff line change
Expand Up @@ -343,32 +343,32 @@ let locs = Hashtbl.create 200

(** Visitor to count locs appearing inside a fundec. *)
class countFnVisitor = object
inherit nopCilVisitor
method! vstmt s =
match s.skind with
| Return (_, loc)
| Goto (_, loc)
| ComputedGoto (_, loc)
| Break loc
| Continue loc
| If (_,_,_,loc,_)
| Switch (_,_,_,loc,_)
| Loop (_,loc,_,_,_)
-> Hashtbl.replace locs loc.line (); DoChildren
| _ ->
DoChildren

method! vinst = function
| Set (_,_,loc,_)
| Call (_,_,_,loc,_)
| Asm (_,_,_,_,_,loc)
-> Hashtbl.replace locs loc.line (); SkipChildren
| _ -> SkipChildren

method! vvdec _ = SkipChildren
method! vexpr _ = SkipChildren
method! vlval _ = SkipChildren
method! vtype _ = SkipChildren
inherit nopCilVisitor
method! vstmt s =
match s.skind with
| Return (_, loc)
| Goto (_, loc)
| ComputedGoto (_, loc)
| Break loc
| Continue loc
| If (_,_,_,loc,_)
| Switch (_,_,_,loc,_)
| Loop (_,loc,_,_,_)
-> Hashtbl.replace locs loc.line (); DoChildren
| _ ->
DoChildren

method! vinst = function
| Set (_,_,loc,_)
| Call (_,_,_,loc,_)
| Asm (_,_,_,_,_,loc)
-> Hashtbl.replace locs loc.line (); SkipChildren
| _ -> SkipChildren

method! vvdec _ = SkipChildren
method! vexpr _ = SkipChildren
method! vlval _ = SkipChildren
method! vtype _ = SkipChildren
end

let fnvis = new countFnVisitor
Expand All @@ -393,16 +393,16 @@ module StmtH = Hashtbl.Make (CilType.Stmt)

let stmt_fundecs: fundec StmtH.t ResettableLazy.t =
ResettableLazy.from_fun (fun () ->
let h = StmtH.create 113 in
iterGlobals !current_file (function
| GFun (fd, _) ->
List.iter (fun stmt ->
StmtH.replace h stmt fd
) fd.sallstmts
| _ -> ()
);
h
)
let h = StmtH.create 113 in
iterGlobals !current_file (function
| GFun (fd, _) ->
List.iter (fun stmt ->
StmtH.replace h stmt fd
) fd.sallstmts
| _ -> ()
);
h
)

let pseudo_return_to_fun = StmtH.create 113

Expand All @@ -416,14 +416,14 @@ module VarinfoH = Hashtbl.Make (CilType.Varinfo)

let varinfo_fundecs: fundec VarinfoH.t ResettableLazy.t =
ResettableLazy.from_fun (fun () ->
let h = VarinfoH.create 111 in
iterGlobals !current_file (function
| GFun (fd, _) ->
VarinfoH.replace h fd.svar fd
| _ -> ()
);
h
)
let h = VarinfoH.create 111 in
iterGlobals !current_file (function
| GFun (fd, _) ->
VarinfoH.replace h fd.svar fd
| _ -> ()
);
h
)

(** Find [fundec] by the function's [varinfo] (has the function name and type). *)
let find_varinfo_fundec vi = VarinfoH.find (ResettableLazy.force varinfo_fundecs) vi (* vi argument must be explicit, otherwise force happens immediately *)
Expand All @@ -433,14 +433,14 @@ module StringH = Hashtbl.Make (Printable.Strings)

let name_fundecs: fundec StringH.t ResettableLazy.t =
ResettableLazy.from_fun (fun () ->
let h = StringH.create 111 in
iterGlobals !current_file (function
| GFun (fd, _) ->
StringH.replace h fd.svar.vname fd
| _ -> ()
);
h
)
let h = StringH.create 111 in
iterGlobals !current_file (function
| GFun (fd, _) ->
StringH.replace h fd.svar.vname fd
| _ -> ()
);
h
)

(** Find [fundec] by the function's name. *)
(* TODO: why unused? *)
Expand All @@ -455,19 +455,19 @@ type varinfo_role =

let varinfo_roles: varinfo_role VarinfoH.t ResettableLazy.t =
ResettableLazy.from_fun (fun () ->
let h = VarinfoH.create 113 in
iterGlobals !current_file (function
| GFun (fd, _) ->
VarinfoH.replace h fd.svar Function; (* function itself can be used as a variable (function pointer) *)
List.iter (fun vi -> VarinfoH.replace h vi (Formal fd)) fd.sformals;
List.iter (fun vi -> VarinfoH.replace h vi (Local fd)) fd.slocals
| GVar (vi, _, _)
| GVarDecl (vi, _) ->
VarinfoH.replace h vi Global
| _ -> ()
);
h
)
let h = VarinfoH.create 113 in
iterGlobals !current_file (function
| GFun (fd, _) ->
VarinfoH.replace h fd.svar Function; (* function itself can be used as a variable (function pointer) *)
List.iter (fun vi -> VarinfoH.replace h vi (Formal fd)) fd.sformals;
List.iter (fun vi -> VarinfoH.replace h vi (Local fd)) fd.slocals
| GVar (vi, _, _)
| GVarDecl (vi, _) ->
VarinfoH.replace h vi Global
| _ -> ()
);
h
)

(** Find the role of the [varinfo]. *)
let find_varinfo_role vi = VarinfoH.find (ResettableLazy.force varinfo_roles) vi (* vi argument must be explicit, otherwise force happens immediately *)
Expand Down Expand Up @@ -496,15 +496,15 @@ let find_scope_fundec vi =
let original_names: string VarinfoH.t ResettableLazy.t =
(* only invert environment map when necessary (e.g. witnesses) *)
ResettableLazy.from_fun (fun () ->
let h = VarinfoH.create 113 in
Hashtbl.iter (fun original_name (envdata, _) ->
match envdata with
| Cabs2cil.EnvVar vi when vi.vname <> "" -> (* TODO: fix temporary variables with empty names being in here *)
VarinfoH.replace h vi original_name
| _ -> ()
) Cabs2cil.environment;
h
)
let h = VarinfoH.create 113 in
Hashtbl.iter (fun original_name (envdata, _) ->
match envdata with
| Cabs2cil.EnvVar vi when vi.vname <> "" -> (* TODO: fix temporary variables with empty names being in here *)
VarinfoH.replace h vi original_name
| _ -> ()
) Cabs2cil.environment;
h
)

(** Find the original name (in input source code) of the [varinfo].
If it was renamed by CIL, then returns the original name before renaming.
Expand All @@ -527,3 +527,18 @@ let stmt_pretty_short () x =
| Instr (y::ys) -> dn_instr () y
| If (exp,_,_,_,_) -> dn_exp () exp
| _ -> dn_stmt () x

(** Given a [Cil.file], reorders its [globals].
This function may be used after a code transformation to ensure that the order of globals yields a compilable program. *)
let add_function_declarations (file: Cil.file): unit =
let globals = file.globals in
let functions, non_functions = List.partition (fun g -> match g with GFun _ -> true | _ -> false) globals in
let upto_last_type, non_types = GobList.until_last_with (fun g -> match g with GType _ -> true | _ -> false) non_functions in
let declaration_from_GFun f = match f with
| GFun (f, _) ->
GVarDecl (f.svar, locUnknown)
| _ -> failwith "Expected GFun, but was something else."
in
let fun_decls = List.map declaration_from_GFun functions in
let globals = upto_last_type @ fun_decls @ non_types @ functions in
file.globals <- globals
9 changes: 9 additions & 0 deletions src/util/gobList.ml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,12 @@ let rec fold_while_some (f : 'a -> 'b -> 'a option) (acc: 'a) (xs: 'b list): 'a
end

let equal = List.eq

(** Given a predicate and a list, returns two lists [(l1, l2)].
[l1] contains the prefix of the list until the last element that satisfies the predicate, [l2] contains all subsequent elements. The order of elements is preserved. *)
let until_last_with (pred: 'a -> bool) (xs: 'a list) =
let rec until_last_helper last seen = function
| [] -> List.rev last, List.rev seen
| h::t -> if pred h then until_last_helper (h::seen@last) [] t else until_last_helper last (h::seen) t
in
until_last_helper [] [] xs
6 changes: 6 additions & 0 deletions src/util/options.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2102,6 +2102,12 @@
"Whether to dump assertions about all local variables or limitting it to modified ones where possible.",
"type": "boolean",
"default": true
},
"blobs": {
"title": "witness.invariant.blobs",
"description": "Whether to dump assertions about all blobs. Enabling this option may lead to unsound asserts.",
"type": "boolean",
"default": false
}
},
"additionalProperties": false
Expand Down