From c0d05ec0f3772d70a02d82fb55e6cf7a84f81c0a Mon Sep 17 00:00:00 2001
From: Valentin Perrelle <valentin.perrelle@cea.fr>
Date: Fri, 7 Oct 2022 21:22:24 +0200
Subject: [PATCH] [Dive] add taint information

---
 ivette/src/frama-c/plugins/dive/api/index.ts | 11 +++++--
 ivette/src/frama-c/plugins/dive/style.json   | 33 +++++++++++++++++---
 src/plugins/dive/build.ml                    |  9 ++++--
 src/plugins/dive/dive_graph.ml               | 29 ++++++++++++++---
 src/plugins/dive/dive_graph.mli              |  4 ++-
 src/plugins/dive/dive_types.ml               |  1 +
 src/plugins/dive/server_interface.ml         |  4 ++-
 7 files changed, 76 insertions(+), 15 deletions(-)

diff --git a/ivette/src/frama-c/plugins/dive/api/index.ts b/ivette/src/frama-c/plugins/dive/api/index.ts
index d3232121887..5f76720db27 100644
--- a/ivette/src/frama-c/plugins/dive/api/index.ts
+++ b/ivette/src/frama-c/plugins/dive/api/index.ts
@@ -150,7 +150,7 @@ export type node =
   { id: nodeId, label: string, kind: string, locality: nodeLocality,
     is_root: boolean, backward_explored: string, forward_explored: string,
     writes: location[], values?: string, range: number | string,
-    type?: string };
+    type?: string, taint?: "direct" | "indirect" | "untainted" };
 
 /** Decoder for `node` */
 export const jNode: Json.Decoder<node> =
@@ -166,6 +166,12 @@ export const jNode: Json.Decoder<node> =
     values: Json.jOption(Json.jString),
     range: Json.jUnion<number | string>( Json.jNumber, Json.jString,),
     type: Json.jOption(Json.jString),
+    taint: Json.jOption(
+             Json.jUnion<"direct" | "indirect" | "untainted">(
+               Json.jTag("direct"),
+               Json.jTag("indirect"),
+               Json.jTag("untainted"),
+             )),
   });
 
 /** Natural order for `node` */
@@ -174,7 +180,7 @@ export const byNode: Compare.Order<node> =
     <{ id: nodeId, label: string, kind: string, locality: nodeLocality,
        is_root: boolean, backward_explored: string, forward_explored: string,
        writes: location[], values?: string, range: number | string,
-       type?: string }>({
+       type?: string, taint?: "direct" | "indirect" | "untainted" }>({
     id: byNodeId,
     label: Compare.string,
     kind: Compare.string,
@@ -186,6 +192,7 @@ export const byNode: Compare.Order<node> =
     values: Compare.defined(Compare.string),
     range: Compare.structural,
     type: Compare.defined(Compare.string),
+    taint: Compare.defined(Compare.structural),
   });
 
 /** The dependency between two nodes */
diff --git a/ivette/src/frama-c/plugins/dive/style.json b/ivette/src/frama-c/plugins/dive/style.json
index 84d6611dee4..9b4b706fcba 100644
--- a/ivette/src/frama-c/plugins/dive/style.json
+++ b/ivette/src/frama-c/plugins/dive/style.json
@@ -45,22 +45,31 @@
       "curve-style": "bezier",
       "target-arrow-shape": "vee",
       "target-arrow-color": "#888",
-      "arrow-scale": 2.0
+      "arrow-scale": 2.0,
+      "z-compound-depth": "top"
     }
   },
   {
     "selector": "edge.multiple-selection",
     "style": {
       "overlay-color": "#aaa",
-      "overlay-padding": "10px",
+      "overlay-padding": "4px",
       "overlay-opacity": 0.4
     }
   },
   {
-    "selector": "edge.selection, :selected",
+    "selector": "edge.selection",
     "style": {
       "overlay-color": "#8bf",
-      "overlay-padding": "10px",
+      "overlay-padding": "4px",
+      "overlay-opacity": 0.4
+    }
+  },
+  {
+    "selector": ":selected",
+    "style": {
+      "overlay-color": "#8bf",
+      "overlay-padding": "8px",
       "overlay-opacity": 0.4
     }
   },
@@ -155,6 +164,22 @@
       "ghost-opacity": "0.7"
     }
   },
+  {
+    "selector": "node[taint='direct']",
+    "style": {
+      "underlay-color": "#afa",
+      "underlay-padding": "14px",
+      "underlay-opacity": 1.0
+    }
+  },
+  {
+    "selector": "node[taint='indirect']",
+    "style": {
+      "underlay-color": "#afa",
+      "underlay-padding": "14px",
+      "underlay-opacity": 0.5
+    }
+  },
   {
     "selector": "edge[kind='callee']",
     "style": {
diff --git a/src/plugins/dive/build.ml b/src/plugins/dive/build.ml
index 22a877074d1..a8ef4ad5078 100644
--- a/src/plugins/dive/build.ml
+++ b/src/plugins/dive/build.ml
@@ -103,6 +103,10 @@ struct
   let to_callstacks stmt =
     before stmt |> callstacks
 
+  let is_tainted kinstr lval =
+    let zone = to_zone kinstr lval in
+    before_kinstr kinstr |> is_tainted zone |> Result.to_option
+
   let studia_direct_effect = function
     | e, { Studia.Writes.direct = true } -> Some e
     | _ -> None
@@ -139,8 +143,9 @@ end
 
 let update_node_values node kinstr lval =
   let typ = Cil.typeOfLval lval
-  and cvalue = Eval.to_cvalue kinstr lval in
-  Graph.update_node_values node cvalue typ
+  and cvalue = Eval.to_cvalue kinstr lval
+  and taint = Eval.is_tainted kinstr lval in
+  Graph.update_node_values node ~typ ~cvalue ~taint
 
 
 (* --- Locations handling --- *)
diff --git a/src/plugins/dive/dive_graph.ml b/src/plugins/dive/dive_graph.ml
index 736d4eb7df4..1c60f09ba34 100644
--- a/src/plugins/dive/dive_graph.ml
+++ b/src/plugins/dive/dive_graph.ml
@@ -37,6 +37,7 @@ let new_node
   node_hidden = false;
   node_values = None;
   node_range = Empty;
+  node_taint = None;
   node_writes_computation = NotDone;
   node_reads_computation = NotDone;
   node_writes_stmts = [];
@@ -123,12 +124,21 @@ let edges g =
   fold_edges_e (fun d acc -> d ::acc) g []
 
 
-let update_node_values node new_values typ =
-  let join n = Cvalue.V.join n new_values in
-  node.node_values <-
-    Some (Option.fold ~some:join ~none:new_values node.node_values);
+let update_node_values node ~typ ~cvalue ~taint =
+  let join_taint t1 t2 =
+    let open Eva.Results in
+    match t1, t2 with
+    | Direct, _ | _, Direct -> Direct
+    | Indirect, _ | _, Indirect -> Indirect
+    | Untainted, Untainted -> Untainted
+  in
+  node.node_values <- Some (
+      Option.fold ~some:(Cvalue.V.join cvalue) ~none:cvalue node.node_values);
   node.node_range <-
-    Node_range.(upper_bound node.node_range (evaluate new_values typ))
+    Node_range.(upper_bound node.node_range (evaluate cvalue typ));
+  Option.iter (fun taint ->
+      node.node_taint <- Some (
+          Option.fold ~some:(join_taint taint) ~none:taint node.node_taint)) taint
 
 let find_independant_nodes g roots =
   let module Dfs = Graph.Traverse.Dfs (struct
@@ -325,6 +335,11 @@ struct
     | Partial _ -> `String "partial"
     | NotDone -> `String "no"
 
+  let output_taint = function
+    | Eva.Results.Direct -> `String "direct"
+    | Indirect ->  `String "inddirect"
+    | Untainted ->  `String "untainted"
+
   let output_node node =
     let label = Pretty_utils.to_string Node_kind.pretty node.node_kind in
     `Assoc ([
@@ -345,6 +360,10 @@ struct
             let typ = Cil.typeOfLval lval in
             let str = Pretty_utils.to_string Cil_printer.pp_typ typ in
             [("type", `String str)]
+        end @
+        begin match node.node_taint with
+          | None -> []
+          | Some t -> [("taint", output_taint t)]
         end)
 
   let output_dep (n1,dep,n2) =
diff --git a/src/plugins/dive/dive_graph.mli b/src/plugins/dive/dive_graph.mli
index e2991d9b23b..48047ba0396 100644
--- a/src/plugins/dive/dive_graph.mli
+++ b/src/plugins/dive/dive_graph.mli
@@ -38,7 +38,9 @@ val create_node :
 
 val remove_node : t -> node -> unit
 
-val update_node_values : node -> Cvalue.V.t -> Cil_types.typ -> unit
+val update_node_values : node ->
+  typ:Cil_types.typ -> cvalue:Cvalue.V.t -> taint:Eva.Results.taint option ->
+  unit
 
 val create_dependency : t -> Cil_types.kinstr ->
   node -> dependency_kind -> node -> unit
diff --git a/src/plugins/dive/dive_types.ml b/src/plugins/dive/dive_types.ml
index 56a62322617..9f4235dc75f 100644
--- a/src/plugins/dive/dive_types.ml
+++ b/src/plugins/dive/dive_types.ml
@@ -53,6 +53,7 @@ type node = {
   mutable node_hidden : bool;
   mutable node_values : Cvalue.V.t option;
   mutable node_range : node_range;
+  mutable node_taint : Eva.Results.taint option;
   mutable node_writes_computation : computation;
   mutable node_reads_computation : computation;
   mutable node_writes_stmts : Cil_types.stmt list;
diff --git a/src/plugins/dive/server_interface.ml b/src/plugins/dive/server_interface.ml
index 7f8cd7e4177..c29359d807d 100644
--- a/src/plugins/dive/server_interface.ml
+++ b/src/plugins/dive/server_interface.ml
@@ -200,7 +200,9 @@ struct
       "writes", Jarray Kernel_ast.KfMarker.jtype;
       "values", Joption Jstring;
       "range", Junion [ Jnumber ; Jstring ];
-      "type", Joption Jstring
+      "type", Joption Jstring;
+      "taint", Joption (Junion [
+          Jtag "direct"; Jtag "indirect"; Jtag "untainted"])
     ])
 end
 
-- 
GitLab