package frama-c-luncov

  1. Overview
  2. Docs

Source file instrument_label.ml

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
(**************************************************************************)
(*                                                                        *)
(*  This file is part of the Frama-C's Luncov plug-in.                    *)
(*                                                                        *)
(*  Copyright (C) 2012-2022                                               *)
(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
(*         alternatives)                                                  *)
(*                                                                        *)
(*  you can redistribute it and/or modify it under the terms of the GNU   *)
(*  Lesser General Public License as published by the Free Software       *)
(*  Foundation, version 2.1.                                              *)
(*                                                                        *)
(*  It is distributed in the hope that it will be useful,                 *)
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
(*  GNU Lesser General Public License for more details.                   *)
(*                                                                        *)
(*  See the GNU Lesser General Public License version 2.1                 *)
(*  for more details (enclosed in the file LICENSE)                       *)
(*                                                                        *)
(**************************************************************************)

open Cil_types
open Instrument

let get_label id =
  let value = get id in
  match value with
  | Label linfo -> linfo
  | _ -> assert false

let get_loc id =
  (get_label id).li_loc

let get_tag id =
  (get_label id).li_tag

let get_annotable_stmt id =
  (get_label id).li_annotable

let get_predicate id =
  (get_label id).li_predicate

let get_kf_id id =
  (get_label id).li_kf_id

let at = ref Req

(** Visitor that removes all but a single label (given its id),
    add a single assertion whose validity implies the uncoverability of a label,
    and provides information to get a Property.t
*)
class label_selector lblid info prj = object (self)
  inherit Visitor.frama_c_copy prj

  val mutable remove_locals = []

  method private clean_locals locals =
    List.filter
      (fun vi ->
         not (List.exists
                (fun vi' -> Cil_datatype.Varinfo.equal vi vi') remove_locals))
      locals

  method private clean_skips stmtl =
    List.filter (fun s ->
        s.labels <> [] || not @@ Cil.is_skip s.skind
      ) stmtl

  method! vfunc _ =
    Cil.DoChildrenPost (fun f ->
        f.slocals <- self#clean_locals f.slocals;
        File.must_recompute_cfg f;
        remove_locals <- [];
        f
      )

  method !vblock _ =
    Cil.DoChildrenPost
      (fun b ->
         b.bstmts <- self#clean_skips b.bstmts;
         b.blocals <- self#clean_locals b.blocals;
         b)

  method! vstmt_aux stmt =
    match stmt.skind, is_stmt_by_sid stmt.sid with
    | _, [lblid'] when lblid' = lblid ->
      self#add_label_annot ();
      Cil.JustCopy
    | Block b, [_] ->
      remove_locals <- b.blocals @ remove_locals;
      stmt.skind <- Instr (Skip Cil_datatype.Location.unknown);
      Cil.JustCopy
    | Instr i, _ ->
      begin match i with
        | Set ((Var v,_), _, _)
        | Local_init (v, _, _)
        | Call (Some (Var v, _),_,_,_) ->
          let vn = "__SEQ_STATUS_" in
          if String.length v.vname > String.length vn
          && String.sub v.vname 0 (String.length vn) = vn then begin
            if String.split_on_char '_' v.vname |> List.rev |> List.hd |> int_of_string <> lblid then
              begin
                stmt.skind <- Instr (Skip Cil_datatype.Location.unknown);
                remove_locals <- [v] @ remove_locals;
              end
          end;
          Cil.JustCopy
        | _ -> Cil.JustCopy
      end
    | _, _ -> Cil.DoChildren

  method private add_label_annot () =
    let lblinfo = get_label lblid in
    let old_kf = Option.get self#current_kf in
    let new_kf = Visitor_behavior.Get.kernel_function self#behavior old_kf in
    let cond = Visitor.visitFramacExpr (self :> Visitor.frama_c_visitor) lblinfo.li_predicate in
    let pred = Logic_utils.expr_to_predicate cond in
    let pred = if !at = Req then Logic_const.pnot pred  else pred in (* NB negated*)
    let top_pred = Logic_const.toplevel_predicate ~kind:Check pred in
    let code_annot = AAssert ([], top_pred) in
    let queued_action () =
      let code_annotation = Logic_const.new_code_annotation code_annot in
      Annotations.add_code_annot ~kf:new_kf wp_emitter lblinfo.li_annotable code_annotation;
      let ip = Property.ip_of_code_annot_single new_kf lblinfo.li_annotable code_annotation in
      info := Some ip;
    in
    Queue.add queued_action self#get_filling_actions
end

let create_project_for_label ?name id =
  let name = match name with None -> "label_"^string_of_int id | Some name -> name in
  let info = ref None in
  let prj = File.create_project_from_visitor name (new label_selector id info) in
  prj, !info
OCaml

Innovation. Community. Security.