From 59ada6044d3ee99fcde58999dd4953cb59afc0f5 Mon Sep 17 00:00:00 2001
From: Basile Desloges <basile.desloges@cea.fr>
Date: Mon, 18 Oct 2021 18:19:19 +0200
Subject: [PATCH] [eacsl] Add code generation support for concurrency

---
 .../e-acsl/src/analyses/memory_tracking.ml    | 58 +++++++++++++------
 .../e-acsl/src/analyses/memory_tracking.mli   | 18 ++++++
 .../e-acsl/src/code_generator/injector.ml     | 12 ++++
 src/plugins/e-acsl/src/libraries/functions.ml |  9 +++
 .../e-acsl/src/libraries/functions.mli        | 14 +++++
 5 files changed, 93 insertions(+), 18 deletions(-)

diff --git a/src/plugins/e-acsl/src/analyses/memory_tracking.ml b/src/plugins/e-acsl/src/analyses/memory_tracking.ml
index fcfc5c3d3bb..6237f181b57 100644
--- a/src/plugins/e-acsl/src/analyses/memory_tracking.ml
+++ b/src/plugins/e-acsl/src/analyses/memory_tracking.ml
@@ -731,6 +731,17 @@ let consolidated_must_monitor_vi vi =
     Env.consolidated_mem vi
   end
 
+let concurrent_function_ref = ref None
+
+let abort_because_of_concurrent ~loc vi =
+  Cil.CurrentLoc.set loc;
+  Options.abort
+    ~current:true
+    "Found concurrent function %a and monitored memory properties.\n\
+     Please use option '-e-acsl-concurrency' to add concurrency support."
+    Printer.pp_varinfo vi
+
+
 let must_monitor_vi ?kf ?stmt vi =
   let _kf = match kf, stmt with
     | None, None | Some _, _ -> kf
@@ -739,26 +750,29 @@ let must_monitor_vi ?kf ?stmt vi =
   (* [JS 2013/05/07] that is unsound to take the env from the given stmt in
      presence of aliasing with an address (see tests address.i).
      TODO: could be optimized though *)
-  consolidated_must_monitor_vi vi
-(*  match stmt, kf with
-    | None, _ -> consolidated_must_monitor_vi vi
-    | Some _, None ->
-    assert false
-    | Some stmt, Some kf  ->
-    if not (Env.is_consolidated ()) then
-      ignore (consolidated_must_monitor_vi vi);
-    try
-      let tbl = Env.find kf in
+  let res = consolidated_must_monitor_vi vi in
+  (*  match stmt, kf with
+      | None, _ -> consolidated_must_monitor_vi vi
+      | Some _, None ->
+      assert false
+      | Some stmt, Some kf  ->
+      if not (Env.is_consolidated ()) then
+        ignore (consolidated_must_monitor_vi vi);
       try
-    let set = Stmt.Hashtbl.find tbl stmt in
-    Varinfo.Hptset.mem vi (Env.default_varinfos set)
+        let tbl = Env.find kf in
+        try
+      let set = Stmt.Hashtbl.find tbl stmt in
+      Varinfo.Hptset.mem vi (Env.default_varinfos set)
+        with Not_found ->
+      (* new statement *)
+      consolidated_must_monitor_vi vi
       with Not_found ->
-    (* new statement *)
-    consolidated_must_monitor_vi vi
-    with Not_found ->
-      (* [kf] is dead code *)
-      false
-*)
+        (* [kf] is dead code *)
+        false
+  *)
+  match res, !concurrent_function_ref with
+  | true, Some (loc, vi) -> abort_because_of_concurrent ~loc vi
+  | _, _ -> res
 
 let rec apply_on_vi_base_from_lval f ?kf ?stmt = function
   | Var vi, _ -> f ?kf ?stmt vi
@@ -823,6 +837,14 @@ let use_monitoring () =
   || Options.Full_mtracking.get ()
   || Env.has_heap_allocations ()
 
+let found_concurrent_function ~loc vi =
+  if use_monitoring () then
+    abort_because_of_concurrent ~loc vi
+  else
+    match !concurrent_function_ref with
+    | None -> concurrent_function_ref := Some (loc, vi)
+    | Some _ -> ()
+
 (*
 Local Variables:
 compile-command: "make -C ../../../../.."
diff --git a/src/plugins/e-acsl/src/analyses/memory_tracking.mli b/src/plugins/e-acsl/src/analyses/memory_tracking.mli
index 78e29d61ecc..4a90e24f50b 100644
--- a/src/plugins/e-acsl/src/analyses/memory_tracking.mli
+++ b/src/plugins/e-acsl/src/analyses/memory_tracking.mli
@@ -42,6 +42,24 @@ val must_monitor_lval: ?kf:kernel_function -> ?stmt:stmt -> lval -> bool
 val must_monitor_exp: ?kf:kernel_function -> ?stmt:stmt -> exp -> bool
 (** Same as {!must_model_vi}, for expressions *)
 
+val found_concurrent_function: loc:location -> varinfo -> unit
+(** [found_concurrent_function ~loc fvi] signals to the memory tracking
+    sub-system that a concurrent function [fvi] has been found at [loc] while
+    parsing the sources. This function needs only to be called if the
+    concurrency support of E-ACSL is deactivated.
+
+    If the memory monitoring is in use when a concurrent function is found,
+    abort the parsing: the user needs to activate the concurrency support.
+
+    Otherwise store the information of the first concurrent function found.
+    Later if the memory monitoring is used because of memory properties to
+    verify, then abort the parsing: the user needs to activate the concurrency
+    support.
+
+    In summary, an analyzed source code can be concurrent with the concurrency
+    support of E-ACSL deactivated only if no memory properties are to be
+    verified. *)
+
 (*
   Local Variables:
   compile-command: "make -C ../../../../.."
diff --git a/src/plugins/e-acsl/src/code_generator/injector.ml b/src/plugins/e-acsl/src/code_generator/injector.ml
index 528ce36f51b..fe2bb263fc6 100644
--- a/src/plugins/e-acsl/src/code_generator/injector.ml
+++ b/src/plugins/e-acsl/src/code_generator/injector.ml
@@ -60,6 +60,18 @@ let rename_caller ~loc caller args =
     in
     fvi, args
   end
+  else if Functions.Concurrency.has_replacement caller.vorig_name then
+    if Options.Concurrency.get () then
+      let fvi =
+        Rtl.Symbols.replacement
+          ~get_name:Functions.Concurrency.replacement_name
+          caller
+      in
+      fvi, args
+    else begin
+      Memory_tracking.found_concurrent_function ~loc caller;
+      caller, args
+    end
   else if Options.Validate_format_strings.get ()
        && Functions.Libc.is_printf_name caller.vorig_name then
     (* rewrite names of format functions (such as printf). This case differs
diff --git a/src/plugins/e-acsl/src/libraries/functions.ml b/src/plugins/e-acsl/src/libraries/functions.ml
index d44745b0694..1d44e2869d6 100644
--- a/src/plugins/e-acsl/src/libraries/functions.ml
+++ b/src/plugins/e-acsl/src/libraries/functions.ml
@@ -212,6 +212,15 @@ module Libc = struct
 
 end
 
+module Concurrency = struct
+  let has_replacement fn =
+    match fn with
+    | "pthread_create" -> true
+    | _ -> false
+
+  let replacement_name fn = RTL.api_prefix ^ fn
+end
+
 let check kf =
   (* [kf] is monitored iff all functions must be monitored or [kf] belongs to
      the white list *)
diff --git a/src/plugins/e-acsl/src/libraries/functions.mli b/src/plugins/e-acsl/src/libraries/functions.mli
index c2d1453c34e..f5d13814748 100644
--- a/src/plugins/e-acsl/src/libraries/functions.mli
+++ b/src/plugins/e-acsl/src/libraries/functions.mli
@@ -181,6 +181,20 @@ module Libc: sig
 
 end (* Libc *)
 
+(* ************************************************************************** *)
+(** {2 Concurrency} Operations concerning the support of concurrency *)
+(* ************************************************************************** *)
+
+module Concurrency: sig
+  val has_replacement: string -> bool
+  (** Given the name of C library function return true if there is a drop-in
+      replacement function for it in the RTL. *)
+
+  val replacement_name: string -> string
+  (** Given the name of C library function return the name of the RTL function
+      that potentially replaces it. *)
+end (* Concurrency *)
+
 (*
 Local Variables:
 compile-command: "make -C ../../../../.."
-- 
GitLab