-
Notifications
You must be signed in to change notification settings - Fork 88
Expand file tree
/
Copy pathassert.ml
More file actions
63 lines (55 loc) · 2.92 KB
/
assert.ml
File metadata and controls
63 lines (55 loc) · 2.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
(** Analysis of [assert] results ([assert]). *)
open Batteries
open GoblintCil
open Analyses
open GobConfig
module Spec : Analyses.MCPSpec =
struct
include UnitAnalysis.Spec
let name () = "assert"
(* transfer functions *)
let assert_fn man e check refine =
let check_assert e st =
match man.ask (Queries.EvalInt e) with
| v when Queries.ID.is_bot v -> `Bot
| v -> Option.map_default (fun b -> `Lifted b) `Top (Queries.ID.to_bool v)
in
let expr = CilType.Exp.show e in
let warn warn_fn ?annot msg = if check then
if get_bool "dbg.regression" then ( (* This only prints unexpected results (with the difference) as indicated by the comment behind the assert (same as used by the regression test script). *)
let loc = !M.current_loc in
let line = List.at (List.of_enum @@ File.lines_of loc.file) (loc.line-1) in (* nosemgrep: batenum-of_enum *)
let open Str in
let expected = if string_match (regexp ".+//.*\\(FAIL\\|UNKNOWN\\).*") line 0 then Some (matched_group 1 line) else None in
if expected <> annot then (
let result = if annot = None && (expected = Some ("NOWARN") || (expected = Some ("UNKNOWN") && not (String.exists line "UNKNOWN!"))) then "improved" else "failed" in
(* Expressions with logical connectives like a && b are calculated in temporary variables by CIL. Instead of the original expression, we then see something like tmp___0. So we replace expr in msg by the original source if this is the case. *)
let assert_expr = if string_match (regexp ".*assert(\\(.+\\));.*") line 0 then matched_group 1 line else expr in
let msg = if expr <> assert_expr then String.nreplace ~str:msg ~sub:expr ~by:assert_expr else msg in
warn_fn (msg ^ " Expected: " ^ (expected |? "SUCCESS") ^ " -> " ^ result)
)
) else
warn_fn msg
in
(* TODO: use format instead of %s for the following messages *)
match check_assert e man.local with
| `Lifted false ->
warn (M.error ~category:Assert "%s") ~annot:"FAIL" ("Assertion \"" ^ expr ^ "\" will fail.");
if refine then raise Analyses.Deadcode else man.local
| `Lifted true ->
warn (M.success ~category:Assert "%s") ("Assertion \"" ^ expr ^ "\" will succeed");
man.local
| `Bot ->
M.error ~category:Assert "%s" ("Assertion \"" ^ expr ^ "\" produces a bottom. What does that mean? (currently uninitialized arrays' content is bottom)");
man.local
| `Top ->
warn (M.warn ~category:Assert "%s") ~annot:"UNKNOWN" ("Assertion \"" ^ expr ^ "\" is unknown.");
man.local
let special man (lval: lval option) (f:varinfo) (args:exp list) : D.t =
let desc = LibraryFunctions.find f in
match desc.special args, f.vname with
| Assert { exp; check; refine }, _ -> assert_fn man exp check refine
| _, _ -> man.local
end
let _ =
MCP.register_analysis (module Spec : MCPSpec)