From 5fc927344720e6db2bf8b94d6c4b3f592eae2fa6 Mon Sep 17 00:00:00 2001
From: Virgile Prevosto <virgile.prevosto@m4x.org>
Date: Mon, 17 Feb 2020 15:58:48 +0100
Subject: [PATCH] [crowbar] various fixes in code generation

---
 tests/crowbar/test_ghost_cfg.ml | 80 ++++++++++++++++++++++++---------
 1 file changed, 58 insertions(+), 22 deletions(-)

diff --git a/tests/crowbar/test_ghost_cfg.ml b/tests/crowbar/test_ghost_cfg.ml
index 1fb0749203d..71cc880ebb5 100644
--- a/tests/crowbar/test_ghost_cfg.ml
+++ b/tests/crowbar/test_ghost_cfg.ml
@@ -83,8 +83,10 @@ let gen_stmts gen_stmt =
           const (fun env -> env,[]);
           map [gen_stmt; gen_stmts]
             (fun f1 f2 env ->
-              let (env, stmt) = f1 env in
-              let (env, stmts) = f2 env in
+              let (new_env, stmt) = f1 env in
+              let env = merge env new_env in
+              let (new_env, stmts) = f2 env in
+              let env = merge env new_env in
               env, stmt :: stmts)])
 
 let gen_inst ghost env =
@@ -110,8 +112,13 @@ let gen_block ghost f env =
   env, Cil.mkStmt ~ghost (Block (Cil.mkBlock stmts))
 
 let gen_return ghost env =
+  let loc = Loc.unknown in
   let ghost = ghost_status env ghost in
   let stmt = Cil.mkStmt ~ghost (Return (None, Loc.unknown)) in
+  let e =
+    Cil.new_exp ~loc (BinOp(Lt,Cil.evar x,Cil.integer ~loc 53,Cil.intType))
+  in
+  let stmt = Cil.mkStmt ~ghost (If (e,Cil.mkBlock [stmt],Cil.mkBlock[],loc)) in
   let env = if ghost then { env with should_fail = true } else env in
   let env = { env with stmt_stack = stmt :: env.stmt_stack } in
   env, stmt
@@ -119,7 +126,7 @@ let gen_return ghost env =
 let mk_label =
   let nb = ref 0 in
   fun stmt ->
-  match stmt.labels with
+  match List.filter (function Label _ -> true | _ -> false) stmt.labels with
     | [] ->
         incr nb;
         let name = "L" ^ (string_of_int !nb) in
@@ -136,25 +143,38 @@ let rec all_ghosts n l =
     | s :: tl -> s.ghost && all_ghosts (n-1) tl
 
 let gen_goto ghost tgt env =
+  let loc = Loc.unknown in
   let ghost = ghost_status env ghost in
   let len = List.length env.stmt_stack in
   let tgt = tgt mod (len + 1) in
-  if tgt = len then
-    begin
-      let env = { env with should_fail = env.should_fail || ghost } in
-      env, forward_goto_target
-    end
-  else
-    begin
-      let stmt = List.nth env.stmt_stack tgt in
-      mk_label stmt;
-      let should_fail = ghost && not (all_ghosts tgt env.stmt_stack) in
-      let should_fail = env.should_fail || should_fail in
-      let env = { env with should_fail } in
-      env, stmt
-    end
+  let env, stmt =
+    if tgt = len then
+      begin
+        let env = { env with should_fail = env.should_fail || ghost } in
+        let stmt =
+          Cil.mkStmt ~ghost (Goto (ref forward_goto_target, Loc.unknown))
+        in
+        env, stmt
+      end
+    else
+      begin
+        let stmt = List.nth env.stmt_stack tgt in
+        mk_label stmt;
+        let should_fail =
+          (ghost && not (all_ghosts tgt env.stmt_stack))
+          || (not ghost && stmt.ghost)
+        in
+        let should_fail = env.should_fail || should_fail in
+        let env = { env with should_fail } in
+        let stmt = Cil.mkStmt ~ghost (Goto (ref stmt, Loc.unknown)) in
+        env, stmt
+      end
+  in
+  let e = Cil.(new_exp ~loc (BinOp (Gt,evar ~loc x,integer ~loc 64,intType))) in
+  env, Cil.mkStmt ~ghost (If (e,Cil.mkBlock [stmt],Cil.mkBlock [],loc))
 
 let gen_break ghost env =
+  let loc = Loc.unknown in
   let ghost = ghost_status env ghost in
   let skind, should_fail =
     match env.switch_or_loop with
@@ -170,10 +190,13 @@ let gen_break ghost env =
              | Default g1 -> Break Loc.unknown, not g && not g1 && ghost)
   in
   let stmt = Cil.mkStmt ~ghost skind in
+  let e = Cil.(new_exp ~loc (BinOp (Gt,evar ~loc x,integer ~loc 75,intType))) in
+  let stmt = Cil.mkStmt ~ghost (If (e,Cil.mkBlock [stmt],Cil.mkBlock [],loc)) in
   let env = { env with should_fail; stmt_stack = stmt :: env.stmt_stack } in
   env, stmt
 
 let gen_continue ghost env =
+  let loc = Loc.unknown in
   let ghost = ghost_status env ghost in
   let is_loop = function (Is_loop,_) -> true | (Is_switch,_) -> false in
   let skind, should_fail =
@@ -182,6 +205,8 @@ let gen_continue ghost env =
       | Some (_,g) -> Continue Loc.unknown, not g && ghost
   in
   let stmt = Cil.mkStmt ~ghost skind in
+  let e = Cil.(new_exp ~loc (BinOp (Gt,evar ~loc x,integer ~loc 86,intType))) in
+  let stmt = Cil.mkStmt ~ghost (If (e,Cil.mkBlock [stmt],Cil.mkBlock [],loc)) in
   let env = { env with should_fail; stmt_stack = stmt :: env.stmt_stack } in
   env, stmt
 
@@ -191,14 +216,14 @@ let gen_if ghost ghost_else stmt_then stmt_else env =
   let e =
     Cil.new_exp ~loc (BinOp (Ne,Cil.evar ~loc x,Cil.zero ~loc,Cil.intType))
   in
-  let new_env = { env with in_ghost = ghost } in
-  let new_env, then_s = stmt_then new_env in
+  let if_env = { env with in_ghost = ghost } in
+  let new_env, then_s = stmt_then if_env in
   let env = merge env new_env in
-  let ghoste = ghost_status env ghost_else in
-  let new_env = { env with in_ghost = ghoste } in
+  let ghoste = ghost_status if_env ghost_else in
+  let new_env = { if_env with in_ghost = ghoste } in
   let new_env, else_s = stmt_else new_env in
   let env = merge env new_env in
-  env, Cil.mkStmt (If(e,Cil.mkBlock then_s, Cil.mkBlock else_s,loc))
+  env, Cil.mkStmt ~ghost (If(e,Cil.mkBlock then_s, Cil.mkBlock else_s,loc))
 
 let gen_default should_break stmts env =
   let ghost = env.in_ghost in
@@ -246,6 +271,7 @@ let gen_case ghost should_break my_case cases env =
       | Case g1, (_,g2) :: _ ->
           not g2 && g1 (* prevents taking the default clause.*)
   in
+  let should_fail = env.should_fail || should_fail in
   let new_env = { env with in_ghost = ghost; stmt_pos; should_fail } in
   let new_env, stmts = my_case new_env in
   let _, s1 = gen_inst ghost env in
@@ -297,6 +323,7 @@ let gen_switch ghost cases env =
   env, stmt
 
 let gen_loop ghost stmts env =
+  let loc = Loc.unknown in
   let ghost = ghost_status env ghost in
   let new_env =
     { env with
@@ -304,6 +331,14 @@ let gen_loop ghost stmts env =
       switch_or_loop = (Is_loop, ghost) :: env.switch_or_loop }
   in
   let (new_env, stmts) = stmts new_env in
+  let e =
+    Cil.new_exp ~loc (BinOp (Ge,Cil.evar x,Cil.integer ~loc 42,Cil.intType))
+  in
+  let cond_stmt =
+    Cil.mkStmt ~ghost
+      (If (e,Cil.mkBlock [Cil.mkStmt ~ghost (Break loc)],Cil.mkBlock [],loc))
+  in
+  let stmts = cond_stmt :: stmts in
   let env = merge env new_env in
   let stmt =
     Cil.mkStmt ~ghost (Loop([],Cil.mkBlock stmts,Loc.unknown,None,None))
@@ -335,6 +370,7 @@ let gen_file =
   map [gen_body]
     (fun (env, body) ->
       let f = Cil.emptyFunctionFromVI f in
+      f.svar.vdefined <- true;
       f.sbody <- body;
       (env,
        { fileName = Filepath.Normalized.unknown;
-- 
GitLab