package frama-c

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file normAtLabels.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
(**************************************************************************)
(*                                                                        *)
(*  This file is part of WP plug-in of Frama-C.                           *)
(*                                                                        *)
(*  Copyright (C) 2007-2024                                               *)
(*    CEA (Commissariat a l'energie atomique et aux energies              *)
(*         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 licenses/LGPLv2.1).            *)
(*                                                                        *)
(**************************************************************************)

open Cil_types

type label_mapping = Cil_types.logic_label -> Clabels.c_label

(** push the Tat down to the 'data' operations.
 * This can be useful in cases like \at (x + \at(y, Ly), Lx) because
 * it gives \at(x, Lx) + \at(y, Ly) so there is no more \at imbrications.
  * Also try to "normalize" label :
  * - remove Here because its meaning change when propagating,
  * - remove Old because its meaning depend on where it comes from.
 * *)
class norm_at (mapping : label_mapping) =
  object(self)
    inherit Visitor.generic_frama_c_visitor
        (Visitor_behavior.copy (Project.current ()))

    val mutable current_label = None

    method private change_label label =
      let label = mapping label in
      let old_label = current_label in
      current_label <- Some label; old_label

    method private restore_term old_label x =
      current_label <- old_label;
      let x = match x.term_node with
        | Ttypeof x -> (* Ttypeof is used as a dummy unary construct *) x
        | _ -> assert false
      in x

    method private restore_pred old_label x =
      current_label <- old_label;
      let x = match x.pred_content with
        | Pnot x -> (* Pnot is used as a dummy unary construct *) x
        | _ -> assert false
      in x

    method! vterm t =
      match t.term_node with
      | Tat (t, l) ->
        let old_label = self#change_label l in
        let new_t = {t with term_node = Ttypeof t} in
        Cil.ChangeDoChildrenPost (new_t, self#restore_term old_label)
      | TAddrOf (h, _) | TLval (h, _) | TStartOf (h, _)  ->
        let old_label = current_label in
        let at_label = match h with
          | TResult _ | TVar{lv_name="\\exit_status"} -> Some Clabels.post
          | _ -> old_label
        in
        current_label <- None;
        let post t =
          current_label <- old_label;
          match at_label with
          | Some label -> {t with term_node = Tat (t, Clabels.to_logic label)}
          | None -> t
        in Cil.ChangeDoChildrenPost (t, post)
      | Tapp _ ->
        let post = function
          | {term_node=Tapp(predicate,labels,args)} as t ->
            let normalize l = mapping l |> Clabels.to_logic in
            let new_labels = List.map normalize labels in
            { t with term_node=Tapp(predicate,new_labels,args) }
          | _ -> assert false
        in
        Cil.ChangeDoChildrenPost (t,post)
      | _ -> Cil.DoChildren

    method! vpredicate p = match p.pred_content with
      | Pat (p, l) ->
        let old_label = self#change_label l in
        let new_p = {p with pred_content = Pnot p} in
        Cil.ChangeDoChildrenPost (new_p, self#restore_pred old_label)
      | Papp _ ->
        let post = function
          | {pred_content=Papp(predicate,labels,args)} as p ->
            let normalize l = mapping l |> Clabels.to_logic in
            let new_labels = List.map normalize labels in
            { p with pred_content=Papp(predicate,new_labels,args) }
          | _ -> assert false
        in
        Cil.ChangeDoChildrenPost (p,post)
      | _ -> Cil.DoChildren
  end

exception LabelError of logic_label

let option l = function Some l -> l | None -> raise (LabelError l)

let labels_empty l = raise (LabelError l)

let enclosing_loop ?kf ?at l =
  match kf , at with
  | Some kf , Some stmt -> Kernel_function.find_enclosing_loop kf stmt
  | _ -> raise (LabelError l)

let labels_fct ?kf ?at l =
  match l with
  | BuiltinLabel Init -> Clabels.init
  | BuiltinLabel Pre -> Clabels.pre
  | StmtLabel at -> Clabels.stmt !at
  | BuiltinLabel LoopEntry -> Clabels.loop_entry (enclosing_loop ?kf ?at l)
  (* Labels fct is not used to label invariant establishment/preservation,
     thus, contrary to what is done in [labels_loop], Current is not Here. *)
  | BuiltinLabel LoopCurrent -> Clabels.loop_current (enclosing_loop ?kf ?at l)
  | _ -> raise (LabelError l)

(* -------------------------------------------------------------------------- *)
(* --- Function Contracts                                                 --- *)
(* -------------------------------------------------------------------------- *)

let labels_fct_pre = function
  | BuiltinLabel Init -> Clabels.init
  | BuiltinLabel (Pre|Here) -> Clabels.pre
  | l -> raise (LabelError l)

let labels_fct_post ~exit = function
  | BuiltinLabel Init -> Clabels.init
  | BuiltinLabel (Pre | Old)  -> Clabels.pre
  | BuiltinLabel (Post | Here) -> if exit then Clabels.exit else Clabels.post
  | l -> raise (LabelError l)

let labels_fct_assigns ~exit = function
  | BuiltinLabel Init -> Clabels.init
  | BuiltinLabel (Here | Pre | Old) -> Clabels.pre
  | BuiltinLabel Post -> if exit then Clabels.exit else Clabels.post
  | l -> raise (LabelError l)

(* -------------------------------------------------------------------------- *)
(* --- Statements Contracts                                               --- *)
(* -------------------------------------------------------------------------- *)

let labels_stmt_pre ~kf s = function
  | BuiltinLabel Here -> Clabels.stmt s
  | l -> labels_fct ~kf ~at:s l

let labels_stmt_post ~kf s = function
  | BuiltinLabel Old -> Clabels.stmt s
  | BuiltinLabel (Here | Post) -> Clabels.stmt_post s
  | l -> labels_fct ~kf ~at:s l

let labels_stmt_assigns ~kf s = function
  | BuiltinLabel (Here | Old) -> Clabels.stmt s
  | BuiltinLabel Post -> Clabels.stmt_post s
  | l -> labels_fct ~kf ~at:s l

(* LEGACY *)
let labels_stmt_post_l ~kf s l_post = function
  | BuiltinLabel Old -> Clabels.stmt s
  | BuiltinLabel (Here | Post) as l -> option l l_post
  | l -> labels_fct ~kf ~at:s l

(* LEGACY *)
let labels_stmt_assigns_l ~kf s l_post = function
  | BuiltinLabel (Here | Old) -> Clabels.stmt s
  | BuiltinLabel Post as l -> option l l_post
  | l -> labels_fct ~kf ~at:s l

(* -------------------------------------------------------------------------- *)
(* --- User Assertions in Functions Code                                  --- *)
(* -------------------------------------------------------------------------- *)

let labels_assert ~kf s = function
  | BuiltinLabel Here -> Clabels.stmt s
  | l -> labels_fct ~kf ~at:s l

let labels_loop s = function
  (* In invariant preservation/establishment, LoopCurrent is Here. *)
  | BuiltinLabel (Here | LoopCurrent) -> Clabels.here
  | BuiltinLabel LoopEntry -> Clabels.loop_entry s
  | FormalLabel wplabel -> Clabels.formal wplabel
  | l -> labels_fct ?kf:None ?at:None l (* current loop is handled above *)

(* -------------------------------------------------------------------------- *)
(* --- User Defined Predicates                                            --- *)
(* -------------------------------------------------------------------------- *)

let labels_predicate lab_pairs l =
  try List.assoc l lab_pairs |> Clabels.of_logic
  with Not_found -> Clabels.of_logic l

let labels_axiom = function
  | FormalLabel a -> Clabels.formal a
  | l -> raise (LabelError l)

(* -------------------------------------------------------------------------- *)
(* --- Apply Normalization                                                --- *)
(* -------------------------------------------------------------------------- *)

(** @raise LabelError if there is a label in [p] that is incompatible
 * with the [labels] translation *)
let preproc_annot labels p =
  let visitor = new norm_at labels in
  Visitor.visitFramacPredicate visitor p

let preproc_term labels t =
  let visitor = new norm_at labels in
  Visitor.visitFramacTerm visitor t

(** @raise LabelError if there is a label in [p] that is incompatible
 * with the [labels] translation *)
let preproc_assigns labels asgns =
  let visitor = new norm_at labels in
  List.map (Visitor.visitFramacFrom visitor) asgns

let has_postassigns = function
  | WritesAny -> false
  | Writes froms ->
    let exception HAS_POST in
    let visitor = new norm_at (fun l ->
        if Clabels.is_post l then raise HAS_POST
        else Clabels.of_logic l
      ) in
    try
      List.iter
        (fun fr -> ignore @@ Visitor.visitFramacFrom visitor fr)
        froms ;
      false
    with HAS_POST ->
      true

let catch_label_error ex txt1 txt2 = match ex with
  | LabelError lab ->
    Wp_parameters.warning
      "Unexpected label %a in %s : ignored %s"
      Wp_error.pp_logic_label lab txt1 txt2
  | _ -> raise ex

(* -------------------------------------------------------------------------- *)
OCaml

Innovation. Community. Security.