diff --git a/src/plugins/eva/ast/eva_ast_builder.ml b/src/plugins/eva/ast/eva_ast_builder.ml index 1faa1e6f1dc9af1562e723b2e979439ee994ff4b..6b8f061985b4b973e1746bfe692491f51f4501be 100644 --- a/src/plugins/eva/ast/eva_ast_builder.ml +++ b/src/plugins/eva/ast/eva_ast_builder.ml @@ -202,6 +202,7 @@ struct | _ -> invalid_arg "unsupported construction" let add = binop PlusA + let div = binop Div let eq = binop Eq let ne = binop Ne diff --git a/src/plugins/eva/ast/eva_ast_builder.mli b/src/plugins/eva/ast/eva_ast_builder.mli index 7a7bdcdcdc614698b005d31bd49cca0ec52bc539..448da7c1e6af41fccbf4959492dc1a7605b235ea 100644 --- a/src/plugins/eva/ast/eva_ast_builder.mli +++ b/src/plugins/eva/ast/eva_ast_builder.mli @@ -73,6 +73,7 @@ sig val cast: typ -> exp -> exp (* (typ)x *) val add: exp -> exp -> exp (* x + y *) + val div: exp -> exp -> exp (* x / y *) val eq: exp -> exp -> exp (* x == y *) val ne: exp -> exp -> exp (* x != y *) diff --git a/src/plugins/eva/engine/evaluation.ml b/src/plugins/eva/engine/evaluation.ml index cbb95ced117ad297b74bf51bc738689398b55540..c6a940037fead7e93263663590fbceead7d3f2e3 100644 --- a/src/plugins/eva/engine/evaluation.ml +++ b/src/plugins/eva/engine/evaluation.ml @@ -541,15 +541,31 @@ module Make let truth = Value.assume_bounded Alarms.Upper_bound size_int value in reduce_by_truth ~alarm (index_expr, value) truth - let assume_valid_binop typ (e1, v1 as arg1) op (e2, v2 as arg2) = + (* The behavior of a%b is undefined if the quotient a/b overflows + (according to 6.5.5,§6 in the C standard). This is checked here. *) + let assume_valid_mod context typ (e1, v1) (e2, v2) = + let expr = Eva_ast.Build.div e1 e2 in + let value = Value.forward_binop context typ Div v1 v2 in + let check_overflow value = + let open Evaluated.Operators in + (* Check overflow alarms, but the reduced value of a/b is useless here. *) + let+ _v = handle_overflow ~may_overflow:true context expr typ value in + (* We could probably reduce [v1] or [v2] in some cases. *) + v1, v2 + in + Bottom.fold ~bottom:(return (v1, v2)) check_overflow value + + let assume_valid_binop context typ (e1, v1 as arg1) op (e2, v2 as arg2) = let open Evaluated.Operators in if Cil.isIntegralType typ then match op with | Div | Mod -> let truth = Value.assume_non_zero v2 in let alarm () = Alarms.Division_by_zero (Eva_ast.to_cil_exp e2) in - let+ v2 = reduce_by_truth ~alarm arg2 truth in - v1, v2 + let* v2 = reduce_by_truth ~alarm arg2 truth in + if op = Mod + then assume_valid_mod context typ (e1, v1) (e2, v2) + else return (v1, v2) | Shiftrt -> let warn_negative = Kernel.RightShiftNegative.get () in reduce_shift ~warn_negative typ arg1 arg2 @@ -616,7 +632,7 @@ module Make let e1 = if Eva_ast.is_zero_ptr e1 then None else Some e1 in forward_comparison ~compute typ_e1 kind (e1, v1) arg2 | None -> - let& v1, v2 = assume_valid_binop typ arg1 op arg2 in + let& v1, v2 = assume_valid_binop context typ arg1 op arg2 in Value.forward_binop context typ_e1 op v1 v2 let forward_unop context unop (e, v as arg) = diff --git a/tests/value/modulo.i b/tests/value/modulo.i index e802427c601e40b1b4eeb7ef6856a121ecb1a95c..dc7bc118ff839f8957828e481a0aca454e188560 100644 --- a/tests/value/modulo.i +++ b/tests/value/modulo.i @@ -147,7 +147,9 @@ void pos_rem(void) { int l = (int)*(signed char*)&n; // Best rem is ([0..72] \cup {255})%255, we approximate by [-128..127] } -/* No overflow alarms should be emitted on mod operations, even on addresses. */ +/* On modulo, overflow alarms should only be emitted on INT_MIN % -1, which + is not possible on addresses. However, garbled mixes on arithmetic operations + involving addresses currently lose all precision and lead to false alarms. */ void address_modulo(void) { int* ptr = v ? &A : &B; unsigned int uaddr = (unsigned int) ptr; diff --git a/tests/value/oracle/addition.res.oracle b/tests/value/oracle/addition.res.oracle index 394936b8b9df05a61b4935cb721c0e66380efa36..8e49b33bc5d9199023561d3a7cf7ddf7716ceff9 100644 --- a/tests/value/oracle/addition.res.oracle +++ b/tests/value/oracle/addition.res.oracle @@ -136,8 +136,11 @@ out of bounds read. assert \valid_read(*((int **)45)); [eva] addition.i:87: Frama_C_show_each_1: [-10..15] [eva] addition.i:88: assertion got status valid. +[eva:alarm] addition.i:98: Warning: + signed overflow. assert p17 / (int)(-1) ≤ 2147483647; [eva] Recording results for main [eva] Done for function main +[eva] addition.i:98: assertion 'Eva,signed_overflow' got final status invalid. [scope:rm_asserts] removing 9 assertion(s) [eva] ====== VALUES COMPUTED ====== [eva:final-states] Values at end of function main: @@ -165,7 +168,7 @@ {{ garbled mix of &{p1} (origin: Misaligned read {addition.i:61}) }} p15 ∈ {-1} p16 ∈ {2949122} - p17 ∈ {-2147483648; 0} + p17 ∈ {-2147483648} u1 ∈ {8} q1 ∈ {{ &p1 }} quo1 ∈ {3} @@ -363,6 +366,8 @@ [eva:alarm] addition.i:66: Warning: out of bounds read. assert \valid_read(*((int **)45)); [eva] addition.i:87: Frama_C_show_each_1: [-10..15] +[eva:alarm] addition.i:98: Warning: + signed overflow. assert p17 / (int)(-1) ≤ 2147483647; [eva] Recording results for main [eva] Done for function main [scope:rm_asserts] removing 9 assertion(s) @@ -393,7 +398,7 @@ {{ garbled mix of &{p1} (origin: Misaligned read {addition.i:61}) }} p15 ∈ {-1} p16 ∈ {2; 2949122; 3014658} - p17 ∈ {-2147483648; 0} + p17 ∈ {-2147483648} u1 ∈ {8} q1 ∈ {{ &p1 }} quo1 ∈ {3} diff --git a/tests/value/oracle/modulo.res.oracle b/tests/value/oracle/modulo.res.oracle index 2735d95852af1642e100d42a180b75add289acd7..af30cb8df0c8dfda0300fb88381c97c172f0131f 100644 --- a/tests/value/oracle/modulo.res.oracle +++ b/tests/value/oracle/modulo.res.oracle @@ -26,8 +26,8 @@ b ∈ [--..--] i2 ∈ [--..--] [eva] computing for function pgcd1 <- main. - Called from modulo.i:163. -[eva:alarm] modulo.i:163: Warning: + Called from modulo.i:165. +[eva:alarm] modulo.i:165: Warning: function pgcd1: precondition got status unknown. [eva] modulo.i:37: loop invariant got status valid. [eva] modulo.i:38: loop invariant got status valid. @@ -40,8 +40,8 @@ [eva] Recording results for pgcd1 [eva] Done for function pgcd1 [eva] computing for function pgcd2 <- main. - Called from modulo.i:164. -[eva:alarm] modulo.i:164: Warning: + Called from modulo.i:166. +[eva:alarm] modulo.i:166: Warning: function pgcd2: precondition got status unknown. [eva] modulo.i:50: loop invariant got status valid. [eva] modulo.i:53: Frama_C_show_each_2: [-10..10], [1..10], [-9..9] @@ -49,15 +49,15 @@ [eva] Recording results for pgcd2 [eva] Done for function pgcd2 [eva] computing for function pgcd3 <- main. - Called from modulo.i:165. -[eva:alarm] modulo.i:165: Warning: + Called from modulo.i:167. +[eva:alarm] modulo.i:167: Warning: function pgcd3: precondition got status unknown. [eva:alarm] modulo.i:63: Warning: division by zero. assert b_0 ≢ 0; [eva] modulo.i:64: Frama_C_show_each_3: [-10..10], [-10..10], [-9..9] [eva] Recording results for pgcd3 [eva] Done for function pgcd3 [eva] computing for function main2 <- main. - Called from modulo.i:167. + Called from modulo.i:169. [eva:alarm] modulo.i:9: Warning: signed overflow. assert -2147483648 ≤ 4 * i; [eva:alarm] modulo.i:9: Warning: signed overflow. assert 4 * i ≤ 2147483647; [eva:alarm] modulo.i:10: Warning: signed overflow. assert -2147483648 ≤ 4 * i; @@ -69,12 +69,12 @@ [eva] Recording results for main2 [eva] Done for function main2 [eva] computing for function simultaneous_congruences <- main. - Called from modulo.i:168. + Called from modulo.i:170. [eva:alarm] modulo.i:76: Warning: assertion got status unknown. [eva] Recording results for simultaneous_congruences [eva] Done for function simultaneous_congruences [eva] computing for function shift_modulo <- main. - Called from modulo.i:169. + Called from modulo.i:171. [eva:alarm] modulo.i:100: Warning: assertion got status unknown. [eva:alarm] modulo.i:103: Warning: signed overflow. assert (int)((int)(i * 12) + 5) << 25 ≤ 2147483647; @@ -83,30 +83,38 @@ [eva] Recording results for shift_modulo [eva] Done for function shift_modulo [eva] computing for function extract_bits_modulo <- main. - Called from modulo.i:170. + Called from modulo.i:172. [eva:alarm] modulo.i:109: Warning: assertion got status unknown. [eva] Recording results for extract_bits_modulo [eva] Done for function extract_bits_modulo [eva] computing for function pos_rem <- main. - Called from modulo.i:171. + Called from modulo.i:173. [eva:alarm] modulo.i:137: Warning: assertion got status unknown. [eva:alarm] modulo.i:142: Warning: assertion got status unknown. [eva:alarm] modulo.i:146: Warning: assertion got status unknown. [eva] Recording results for pos_rem [eva] Done for function pos_rem [eva] computing for function address_modulo <- main. - Called from modulo.i:172. -[eva:garbled-mix:write] modulo.i:156: - Assigning imprecise value to r because of arithmetic operation on addresses. -[eva:alarm] modulo.i:157: Warning: division by zero. assert i ≢ 0; -[eva:garbled-mix:write] modulo.i:157: - Assigning imprecise value to r because of arithmetic operation on addresses. + Called from modulo.i:174. +[eva:alarm] modulo.i:158: Warning: + signed overflow. assert -2147483648 ≤ addr / 16; +[eva:alarm] modulo.i:158: Warning: + signed overflow. assert addr / 16 ≤ 2147483647; [eva:garbled-mix:write] modulo.i:158: Assigning imprecise value to r because of arithmetic operation on addresses. +[eva:alarm] modulo.i:159: Warning: division by zero. assert i ≢ 0; [eva:alarm] modulo.i:159: Warning: - division by zero. assert (unsigned int)i ≢ 0; + signed overflow. assert -2147483648 ≤ addr / i; +[eva:alarm] modulo.i:159: Warning: + signed overflow. assert addr / i ≤ 2147483647; [eva:garbled-mix:write] modulo.i:159: Assigning imprecise value to r because of arithmetic operation on addresses. +[eva:garbled-mix:write] modulo.i:160: + Assigning imprecise value to r because of arithmetic operation on addresses. +[eva:alarm] modulo.i:161: Warning: + division by zero. assert (unsigned int)i ≢ 0; +[eva:garbled-mix:write] modulo.i:161: + Assigning imprecise value to r because of arithmetic operation on addresses. [eva] Recording results for address_modulo [eva] Done for function address_modulo [eva] Recording results for main @@ -118,7 +126,7 @@ uaddr ∈ {{ (unsigned int)&A ; (unsigned int)&B }} addr ∈ {{ (int)&A ; (int)&B }} i ∈ [-99..99] - r ∈ {{ garbled mix of &{A; B} (origin: Arithmetic {modulo.i:159}) }} + r ∈ {{ garbled mix of &{A; B} (origin: Arithmetic {modulo.i:161}) }} [eva:final-states] Values at end of function extract_bits_modulo: i ∈ [0..10] aa1 ∈ [1291..32011],1291%3072 diff --git a/tests/value/oracle_equality/addition.res.oracle b/tests/value/oracle_equality/addition.res.oracle index cfbd463cdffd29c09f0e53feed5f870850e73e5c..27a80490220c3faa309e2febd15c8abdfec54e72 100644 --- a/tests/value/oracle_equality/addition.res.oracle +++ b/tests/value/oracle_equality/addition.res.oracle @@ -5,25 +5,26 @@ < signed overflow. assert (int)*((char *)(&q1)) + 2 ≤ 2147483647; < [eva:garbled-mix:write] addition.i:61: Warning: < Assigning imprecise value to p14 because of misaligned read of addresses. -141c135,140 -< [scope:rm_asserts] removing 9 assertion(s) ---- +142a137,141 > [eva:garbled-mix:summary] Warning: > Origins of garbled mix generated during analysis: > addition.i:59: misaligned read of addresses > (read in 1 statement, propagated through 2 statements) > garbled mix of &{p1} +144c143 +< [scope:rm_asserts] removing 9 assertion(s) +--- > [scope:rm_asserts] removing 7 assertion(s) -165c164 +168c167 < {{ garbled mix of &{p1} (origin: Misaligned read {addition.i:61}) }} --- > {{ garbled mix of &{p1} (origin: Misaligned read {addition.i:59}) }} -359,362d357 +362,365d360 < [eva:alarm] addition.i:61: Warning: < signed overflow. assert -2147483648 ≤ (int)*((char *)(&q1)) + 2; < [eva:alarm] addition.i:61: Warning: < signed overflow. assert (int)*((char *)(&q1)) + 2 ≤ 2147483647; -368c363,368 +373c368,373 < [scope:rm_asserts] removing 9 assertion(s) --- > [eva:garbled-mix:summary] Warning: @@ -32,7 +33,7 @@ > (read in 1 statement, propagated through 2 statements) > garbled mix of &{p1} > [scope:rm_asserts] removing 7 assertion(s) -393c393 +398c398 < {{ garbled mix of &{p1} (origin: Misaligned read {addition.i:61}) }} --- > {{ garbled mix of &{p1} (origin: Misaligned read {addition.i:59}) }}