From bbc6855fbe45d1aa1e68e16626586b26def28cb6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr>
Date: Tue, 14 Sep 2021 13:41:15 +0200
Subject: [PATCH] [Eva] Fixes a soundness bug in the octagon domain on
 downcasts.

On casts, uses option -warn-[un]signed-downcast (instead of
-warn-[un]signed-overflow) to known if an integer wrap is possible.
---
 src/plugins/value/domains/octagons.ml | 24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/src/plugins/value/domains/octagons.ml b/src/plugins/value/domains/octagons.ml
index b8968a5f139..bcd92a3b359 100644
--- a/src/plugins/value/domains/octagons.ml
+++ b/src/plugins/value/domains/octagons.ml
@@ -176,20 +176,32 @@ let _pretty_octagon fmt octagon =
    Use Ival.t to evaluate expressions. *)
 module Rewriting = struct
 
+  let overflow_alarm range =
+    if range.Eval_typ.i_signed
+    then Kernel.SignedOverflow.get ()
+    else Kernel.UnsignedOverflow.get ()
+
+  let downcast_alarm range =
+    if range.Eval_typ.i_signed
+    then Kernel.SignedDowncast.get ()
+    else Kernel.UnsignedDowncast.get ()
+
   (* Checks if the interval [ival] fits in the C type [typ].
      This is used to ensure that an expression cannot overflow: this module
      uses the mathematical semantics of arithmetic operations, and cannot
      soundly translate overflows in the C semantics.  *)
-  let may_overflow typ ival =
+  let may_overflow ?(cast=false) typ ival =
     let open Eval_typ in
     match classify_as_scalar typ with
     | None -> assert false (* This should not happen here. *)
     | Some (TSFloat _) -> false
     | Some (TSInt range | TSPtr range) ->
-      not
-        ((range.i_signed && Kernel.SignedOverflow.get ()) ||
-         (not range.i_signed && Kernel.UnsignedOverflow.get ()) ||
-         Ival.is_included ival (Arith.make_range range))
+      let alarm =
+        if cast
+        then downcast_alarm range
+        else overflow_alarm range
+      in
+      not (alarm || Ival.is_included ival (Arith.make_range range))
 
   (* Simplified form [±X-coeff] for expressions,
      where X is a variable and coeff an interval. *)
@@ -264,7 +276,7 @@ module Rewriting = struct
     | CastE (typ, e) ->
       if Cil.(isIntegralType typ && isIntegralType (typeOf e)) then
         evaluate e >> fun v ->
-        if may_overflow typ v then [] else rewrite evaluate e
+        if may_overflow ~cast:true typ v then [] else rewrite evaluate e
       else []
 
     | Info (e, _) -> rewrite evaluate e
-- 
GitLab