Skip to content
Snippets Groups Projects
l2lCheckMemSafe.ml 5.03 KiB
(** Time-stamp: <modified the 29/08/2019 (at 15:40) by Erwan Jahier> *)

open Lxm
open Lic
 
let _dbg =  (Lv6Verbose.get_flag "check-mem")


(********************************************************************************)
(* exported *)
let  (is_memoryless_val_exp : LicPrg.t -> Lic.val_exp  -> bool) =
  fun licprg ve ->
    let rec (aux_val_exp : Lic.val_exp  -> bool) =
      fun ve -> aux_val_exp_core ve.ve_core
    and aux_val_exp_core ve_core = 
      match ve_core with
        | CallByPosLic(op, vel) -> (
          (List.for_all aux_val_exp vel) && aux_pos_op op.it 
        )
        | CallByNameLic(_,cl) -> (
          let vel = (snd (List.split cl)) in
          List.for_all aux_val_exp vel
        )
        | Merge(ve,cl) -> (
          let vel = ve::(snd (List.split cl)) in
          List.for_all aux_val_exp vel
        )
    and (aux_pos_op: Lic.by_pos_op -> bool) =
      function
        | CALL({it=nk;_}) | PREDEF_CALL({it=nk;_}) -> (
          match LicPrg.find_node licprg nk with
            | None -> true (* SNO *)
            | Some node_exp -> not node_exp.has_mem_eff
        )
        | CURRENT _ | PRE | ARROW | FBY 
          -> false
        | HAT (_) | ARRAY| ARRAY_SLICE(_) | ARRAY_ACCES(_) | STRUCT_ACCESS(_) 
        | WHEN _ | TUPLE  | CONCAT | CONST _ | CONST_REF  _ | VAR_REF _ 
          -> true
    in
    aux_val_exp ve


let (check_memory : LicPrg.t -> bool -> val_exp -> Lxm.t -> bool -> bool) =
  fun licprg should_have_mem ve lxm warning ->
    match should_have_mem, not (is_memoryless_val_exp licprg ve) with
      | false, false 
      | true,  true -> false (* disable the warning *) 
      | false, true ->
        let msg = "Error: this call uses memory from a function." in
        raise (Lv6errors.Compile_error(lxm,msg))
      | true, false -> warning

(********************************************************************************)
(* exported *)
let  (is_safe_val_exp : LicPrg.t -> Lic.val_exp -> bool) =
  fun licprg ve ->
    let rec (aux_val_exp : Lic.val_exp -> bool) =
      fun ve -> aux_val_exp_core ve.ve_core
    and aux_val_exp_core ve_core = 
      match ve_core with
        | CallByPosLic(op, vel) -> (
          (List.for_all aux_val_exp vel) && aux_pos_op op.it 
        )
        | CallByNameLic(_,cl) -> (
          let vel = (snd (List.split cl)) in
          List.for_all aux_val_exp vel
        )
        | Merge(ve,cl) -> (
          let vel = ve::(snd (List.split cl)) in
          List.for_all aux_val_exp vel
        )
    and (aux_pos_op: Lic.by_pos_op -> bool) =
      function
        | CALL({it=nk;_}) | PREDEF_CALL({it=nk;_}) -> (
          match LicPrg.find_node licprg nk with
            | None -> true (* SNO *)
            | Some node_exp -> node_exp.is_safe_eff
        )
        | CURRENT _ | PRE | ARROW | FBY 
        | HAT (_) | ARRAY| ARRAY_SLICE(_) | ARRAY_ACCES(_) | STRUCT_ACCESS(_) 
        | WHEN _ | TUPLE  | CONCAT | CONST _ | CONST_REF  _ | VAR_REF _ 
          -> true
    in
    aux_val_exp ve

let (check_safety : LicPrg.t -> bool -> val_exp -> Lxm.t -> bool -> bool) =
  fun licprg should_be_safe ve lxm warning ->
    match should_be_safe,  is_safe_val_exp licprg ve with
      | false, false
      | true,  true -> false (* disable the warning *) 
      | true, false ->
        let msg = "Error: calling an unsafe node from a safe one." in
        raise (Lv6errors.Compile_error(lxm,msg))
      | false, true -> warning


(********************************************************************************)
let (check_node : LicPrg.t -> Lic.node_exp -> unit) =
  fun licprg node -> 
    match node.def_eff with  
	   | ExternLic | MetaOpLic | AbstractLic _ -> ()
	   | BodyLic{ eqs_eff = eql ; asserts_eff = vel } ->
        let warning = true in
        let warning = List.fold_left
          (fun warn eq -> check_memory licprg node.has_mem_eff (snd eq.it) eq.src warn) 
          warning eql
        in
        let warning = List.fold_left 
          (fun warn eq -> check_memory licprg node.has_mem_eff eq.it eq.src warn) 
          warning vel
        in 
        if warning then (
          let id = Lic.string_of_node_key node.node_key_eff in
          let msg = Printf.sprintf
            "%s is declared as a node, but it uses no memory (i.e., it is a function)." 
            id 
          in
          Lv6errors.warning node.lxm msg;
        );
        let warning = true in
        let warning = List.fold_left 
          (fun warn eq -> check_safety licprg node.is_safe_eff (snd eq.it) eq.src warn) 
          warning eql
        in
        let warning = List.fold_left
          (fun warn eq -> check_safety licprg node.is_safe_eff eq.it eq.src warn) 
          warning vel
        in
        if warning then (
          let id = Lic.string_of_node_key node.node_key_eff in
          let msg = Printf.sprintf "%s is declared as unsafe, but is safe." id in
          Lv6errors.warning node.lxm msg
        )


(* exported *)
let (doit :  LicPrg.t -> unit) =
  fun inprg -> 
    let (do_node : Lic.node_key -> Lic.node_exp -> unit) = 
      fun _nk ne -> check_node inprg ne
    in
    LicPrg.iter_nodes do_node inprg