-
Notifications
You must be signed in to change notification settings - Fork 88
Bachelor's Thesis – tnilboG: Extending Goblint Analyzer with Weakest Preconditions #1946
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
base: master
Are you sure you want to change the base?
Changes from 24 commits
9a60066
5faf07f
b91d566
b565a75
7b532a3
d2cdb8b
b7b41df
6a9ae2a
d3cdd34
a7e512b
9690b86
6450feb
87b6749
a4eb80c
77ac4fe
d52f916
237399e
d8d8913
e396a37
177ed17
7994fb5
25845da
45a201e
48e53bc
1a84c57
f02c447
9a0fa2c
e676dd1
39a493c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,232 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| open GoblintCil | ||||||||||||||||||||||||||||||||||||||||||||||||||
| open Analyses | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| module BackwSpec : BackwAnalyses.BackwSpecSpec = functor (ForwSpec : Analyses.Spec) -> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| struct | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| include BackwAnalyses.DefaultBackwSpec (ForwSpec) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| module C = ForwSpec.C | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| (* Adding these module definitions because the "include" of the DefaultBackwSpec is not enough*) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| module D_forw = ForwSpec.D | ||||||||||||||||||||||||||||||||||||||||||||||||||
| module G_forw = ForwSpec.G | ||||||||||||||||||||||||||||||||||||||||||||||||||
| module V_forw = ForwSpec.V | ||||||||||||||||||||||||||||||||||||||||||||||||||
| module P_forw = ForwSpec.P | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let name () = "liveness" | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| module G = Lattice.Unit | ||||||||||||||||||||||||||||||||||||||||||||||||||
| module V = EmptyV | ||||||||||||||||||||||||||||||||||||||||||||||||||
| module P = EmptyP | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| module LiveVariableSet = SetDomain.ToppedSet (Basetype.Variables) (struct let topname = "All variables" end) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| module D = LiveVariableSet (*Set of program variables as domain*) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| let startstate v = D.empty() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let exitstate v = D.empty() | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| let rec vars_from_lval (l: lval) : varinfo list = | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let vars_written_to = | ||||||||||||||||||||||||||||||||||||||||||||||||||
| match l with | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | Var v, _ -> ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (Cil.isFunctionType v.vtype) then [] else [v] (*I do not want functions in the set of live variables*) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | Mem m, _ -> vars_from_expr m | ||||||||||||||||||||||||||||||||||||||||||||||||||
| in | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| let vars_in_offset = | ||||||||||||||||||||||||||||||||||||||||||||||||||
| match l with | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | Var _, off -> vars_from_offset off | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | Mem _, off -> Logs.debug "(!) vars_in_offset used"; vars_from_offset off | ||||||||||||||||||||||||||||||||||||||||||||||||||
| in | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| (vars_written_to @ vars_in_offset) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| and vars_from_offset (off: offset) : varinfo list = | ||||||||||||||||||||||||||||||||||||||||||||||||||
| match off with | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | NoOffset -> [] | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | Field (_, off) -> vars_from_offset off (* what to do with fieldinfo?*) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | Index (e, off) -> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let vars_in_e = vars_from_expr e in | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let vars_in_off = vars_from_offset off in | ||||||||||||||||||||||||||||||||||||||||||||||||||
| (match vars_in_off with | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | [] -> [] | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | vars_in_off -> (vars_in_e @ vars_in_off)) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| and vars_from_expr (e: exp) : varinfo list = | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let rec aux acc e = | ||||||||||||||||||||||||||||||||||||||||||||||||||
| match e with | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | Lval v -> vars_from_lval v @ acc | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | BinOp (_, e1, e2, _) -> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let acc1 = aux acc e1 in | ||||||||||||||||||||||||||||||||||||||||||||||||||
| aux acc1 e2 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | UnOp (_, e1, _) -> aux acc e1 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | SizeOfE e1 -> aux acc e1 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | AlignOfE e1 -> aux acc e1 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | Question (e1, e2, e3, _) -> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let acc1 = aux acc e1 in | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let acc2 = aux acc1 e2 in | ||||||||||||||||||||||||||||||||||||||||||||||||||
| aux acc2 e3 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | CastE (_, e1) -> aux acc e1 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | AddrOf (l1) -> (match vars_from_lval l1 with | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | [] -> acc | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | v -> (v @ acc) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| (* | AddrOfLabel _ -> Logs.debug "(!) Expression of type AddrOfLabel"; acc | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | StartOf l1 -> Logs.debug "(!) Expression of type StartOf"; acc | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | Const _ ->Logs.debug "(!) Expression of type Const"; acc | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | Real _ -> Logs.debug "(!) Expression of type Real"; acc | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | Imag _ -> Logs.debug "(!) Expression of type Imag"; acc | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | SizeOf _ -> Logs.debug "(!) Expression of type SizeOf"; acc | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | AlignOf _ -> Logs.debug "(!) Expression of type AlignOf"; acc | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | SizeOfStr _ -> Logs.debug "(!) Expression of type SizeOfStr"; acc *) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | _ -> acc | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| in | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| (* let give_exp_type e = | ||||||||||||||||||||||||||||||||||||||||||||||||||
| match e with | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | Const _ -> Logs.debug "(!) Expression of type Const" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | Lval _ -> Logs.debug "(!) Expression of type Lval" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | SizeOf _ -> Logs.debug "(!) Expression of type SizeOf" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | Real _ -> Logs.debug "(!) Expression of type Real" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | Imag _ -> Logs.debug "(!) Expression of type Imag" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | SizeOfE _ -> Logs.debug "(!) Expression of type SizeOfE" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | SizeOfStr _ -> Logs.debug "(!) Expression of type SizeOfSTr" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | AlignOf _ -> Logs.debug "(!) Expression of type AlignOf" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | AlignOfE _ -> Logs.debug "(!) Expression of type AlignOfE" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | UnOp _ -> Logs.debug "(!) Expression of type UnOp" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | BinOp _ -> Logs.debug "(!) Expression of type BinOp" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | Question _ -> Logs.debug "(!) Expression of type Question" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | CastE _ -> Logs.debug "(!) Expression of type CastE" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | AddrOf _ -> Logs.debug "(!) Expression of type AddrOf" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | AddrOfLabel _ -> Logs.debug "(!) Expression of type AddrOfLabel" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | StartOf _ -> Logs.debug "(!) Expression of type StartOf" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | _ -> Logs.debug "(!) Impossible: Expression of unknown type" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| in | ||||||||||||||||||||||||||||||||||||||||||||||||||
| give_exp_type e; *) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| aux [] e | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| let assign man man_forw (lval:lval) (rval:exp) = | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let v = vars_from_lval lval in | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| (* This is wrong. If the variabes describe a memory location, they should instead all be added to the set of live variables!*) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| match v with | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | [] -> D.join man.local (D.of_list (vars_from_expr rval)) (*if I do not know what the value is assigned to, then all RHS-Variables might be relevant*) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | v-> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let l = (D.diff man.local (D.of_list v)) in | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (List.exists (fun elem -> D.mem elem man.local) v) then D.join l (D.of_list (vars_from_expr rval)) (*if anything on the rhs is important, this is live now*) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| else ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let loc = M.Location.Node man.node in | ||||||||||||||||||||||||||||||||||||||||||||||||||
| (match v with | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | v::_ -> M.warn ~loc:loc "Unnecessary assignment to variable %s, as it is not live at this program point" v.vname | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | [] -> () (*this case is already handled above*) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ); l) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| let branch man man_forw (exp:exp) (tv:bool) = | ||||||||||||||||||||||||||||||||||||||||||||||||||
| (* This just randomly asks whether all loops terimante to use getg_forw utilized in man.global *) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| (* let () = | ||||||||||||||||||||||||||||||||||||||||||||||||||
| match man_forw.ask(Queries.MustTermAllLoops) with | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | true -> Logs.debug "MustTermAllLoops is TRUE" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | _ -> Logs.debug "MustTermAllLoops is NOT TRUE" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| in *) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| let branch_irrelevant : bool = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| match Queries.eval_bool (Analyses.ask_of_man man_forw) exp with | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | `Lifted b -> tv <> b | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | `Bot -> false | ||||||||||||||||||||||||||||||||||||||||||||||||||
| | `Top -> false | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| in | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if branch_irrelevant then (D.of_list (vars_from_expr exp)) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if branch_irrelevant then (D.of_list (vars_from_expr exp)) | |
| if branch_irrelevant then D.bot () |
Copilot
AI
Mar 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When eval_bool returns a definite boolean and tv <> b, this branch is unreachable. In that case, branch should propagate D.bot () (to kill the unreachable path), not D.of_list (vars_from_expr exp) which keeps/introduces liveness information on an impossible path.
| if branch_irrelevant then (D.of_list (vars_from_expr exp)) | |
| if branch_irrelevant then D.bot () |
Copilot
AI
Mar 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
combine_env uses List.combine args f.sformals, which raises Invalid_argument if lengths differ. Calls with varargs (var_arg = true) are explicitly allowed earlier, so args may be longer than sformals and this will crash. Use a safe zip (e.g. iterate over List.combine (List.take (List.length f.sformals) args) f.sformals, or fold over formals with List.nth_opt), and decide how to handle extra varargs (likely treat them as used if the callee can read them).
| let arg_formal_pairs = List.combine args f.sformals in | |
| let relevant_arg_vars = | |
| List.fold_left (fun acc (arg_exp, formal_var) -> | |
| if D.mem formal_var au then | |
| D.join acc (D.of_list(vars_from_expr arg_exp)) | |
| else | |
| acc | |
| ) (D.empty()) arg_formal_pairs | |
| (* Safely pair arguments with formals, truncating to the shorter list to avoid List.combine exceptions. *) | |
| let rec combine_truncate args formals acc = | |
| match args, formals with | |
| | arg_exp :: args_tail, formal_var :: formals_tail -> | |
| combine_truncate args_tail formals_tail ((arg_exp, formal_var) :: acc) | |
| | _, _ -> | |
| List.rev acc | |
| in | |
| let arg_formal_pairs = combine_truncate args f.sformals [] in | |
| let relevant_arg_vars = | |
| List.fold_left (fun acc (arg_exp, formal_var) -> | |
| if D.mem formal_var au then | |
| D.join acc (D.of_list (vars_from_expr arg_exp)) | |
| else | |
| acc | |
| ) (D.empty ()) arg_formal_pairs |
Copilot
AI
Feb 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return is defined twice in this module (earlier at line ~149 and again here). The later definition silently shadows the earlier one, which is confusing and makes it easy to reason about the wrong behavior. Please keep only one return implementation and remove the other.
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -91,8 +91,8 @@ let init () = | |||||||||
| RmUnused.keepUnused := true; | ||||||||||
| print_CIL_Input := true; | ||||||||||
| Cabs2cil.allowDuplication := false; (* needed for ARG uncilling, maybe something else as well? *) | ||||||||||
| Cabs2cil.silenceLongDoubleWarning := true; | ||||||||||
| Cabs2cil.addLoopConditionLabels := true | ||||||||||
| Cabs2cil.silenceLongDoubleWarning := true | ||||||||||
| (* Cabs2cil.addLoopConditionLabels := true *) | ||||||||||
|
||||||||||
| Cabs2cil.silenceLongDoubleWarning := true | |
| (* Cabs2cil.addLoopConditionLabels := true *) | |
| Cabs2cil.silenceLongDoubleWarning := true; | |
| Cabs2cil.addLoopConditionLabels := true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
vars_from_offsetdrops variables used in an index expression when the remaining offset isNoOffset: theIndex (e, off)case returns[]ifvars_in_offis empty, which incorrectly ignoresefor e.g.a[i]. This will make the liveness result wrong. Always include variables from the index expression regardless of the nested offset.