From 041e16343a8e8a63ce7b383ff93e2db0ad489478 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr>
Date: Thu, 3 Oct 2024 10:15:37 +0200
Subject: [PATCH] [Eva] Adds tests for the emission of overflow alarms on
 division and modulo.

---
 tests/value/div.i                    | 54 +++++++++++++++-
 tests/value/modulo.i                 | 43 +++++++++++++
 tests/value/oracle/div.res.oracle    | 93 +++++++++++++++++++++++++++-
 tests/value/oracle/modulo.res.oracle | 63 +++++++++++++++----
 4 files changed, 236 insertions(+), 17 deletions(-)

diff --git a/tests/value/div.i b/tests/value/div.i
index a57ddb2084..74d9eb4233 100644
--- a/tests/value/div.i
+++ b/tests/value/div.i
@@ -2,13 +2,13 @@
    STDOPT: #""
 */
 
-
+volatile int nondet;
 int X,Y,Z1,Z2,T,U1,U2,V,W1,W2;
 int a,b,d1,d2,d0,e;
 int t[5]={1,2,3};
 int *p;
 
-void main (void) {
+void test (void) {
   int i;
   volatile int c=0;
   while (c+1)
@@ -36,3 +36,53 @@ void main (void) {
   d0 = 100 / (int)(&X);
   e = - (int) &X;
 }
+
+/* Tests the emission of overflow alarms on a division x/y only if [x] may be
+   equal to MIN_INT and [y] may be equal to -1. Also tests the reduction of the
+   possible values of [x] or [y] when possible. Similar test in file modulo.i. */
+void test_overflow_alarms (void) {
+  int min_int = -2147483648;
+  int min_one = -1;
+  int a = nondet ? min_int : 10;
+  int b = nondet ? -1 : 2;
+  int x = nondet;
+  int y = nondet;
+  int r = 0;
+  if (nondet) {
+    r = a / b; // Overflow alarm.
+    // No reduction as [a] and [b] cannot be reduced simultaneously.
+    Frama_C_show_each(a, b);
+  }
+  if (nondet) {
+    r = a / min_one; // Overflow alarm.
+    r = a / min_one; // No alarm if [a] has been reduced.
+    Frama_C_show_each_ten(a); // Check the reduction of [a].
+  }
+  if (nondet) {
+    r = min_int / b; // Overflow alarm.
+    r = min_int / b; // No alarm if [b] has been reduced.
+    Frama_C_show_each_two(b); // Check the reduction of [b]
+  }
+  if (nondet) {
+    r = x / min_one; // Overflow alarm.
+    r = x / min_one; // No alarm if [x] has been reduced.
+    Frama_C_show_each(x); // All integers except MIN_INT.
+  }
+  if (nondet) {
+    r = min_int / x; // Overflow alarm and division by zero alarm.
+    // All integers except -1 and 0, but not representable as an interval.
+    Frama_C_show_each(x);
+  }
+  if (nondet) {
+    r = min_int / min_one; // Invalid alarm.
+    Frama_C_show_each_BOTTOM(min_int, min_one);
+  }
+  // Overflow alarm and division by zero alarm,
+  // no possible reduction: [x] and [y] must be top_int as the end.
+  r = x / y;
+}
+
+void main (void) {
+  test();
+  test_overflow_alarms();
+}
diff --git a/tests/value/modulo.i b/tests/value/modulo.i
index dc7bc118ff..37fa7c2eff 100644
--- a/tests/value/modulo.i
+++ b/tests/value/modulo.i
@@ -161,6 +161,48 @@ void address_modulo(void) {
   r = uaddr % i;
 }
 
+/* Tests the emission of overflow alarms on operation x%y only if [x] may be
+   equal to MIN_INT and [y] may be equal to -1. Also tests the reduction of the
+   possible values of [x] or [y] when possible. Similar test in file div.i. */
+void test_overflow_alarms (void) {
+  int min_int = -2147483648;
+  int min_one = -1;
+  int a = v ? min_int : 10;
+  int b = v ? -1 : 2;
+  int x = v;
+  int y = v;
+  int r = 0;
+  if (v) {
+    r = a % b; // Overflow alarm.
+    // No reduction as [a] and [b] cannot be reduced simultaneously.
+    Frama_C_show_each(a, b);
+  }
+  if (v) {
+    r = a % min_one; // Overflow alarm.
+    r = a % min_one; // No alarm if [a] has been reduced.
+    Frama_C_show_each_ten(a); // Check the reduction of [a].
+  }
+  if (v) {
+    r = min_int % b; // Overflow alarm.
+    r = min_int % b; // No alarm if [b] has been reduced.
+    Frama_C_show_each_two(b); // Check the reduction of [b]
+  }
+  if (v) {
+    r = x % min_one; // Overflow alarm.
+    r = x % min_one; // No alarm if [x] has been reduced.
+    Frama_C_show_each(x); // All integers except MIN_INT.
+  }
+  if (v) {
+    r = min_int % x; // Overflow alarm and division by zero alarm.
+    // All integers except -1 and 0, but not representable as an interval.
+    Frama_C_show_each(x);
+  }
+  if (v) {
+    r = min_int % min_one; // Invalid alarm.
+    Frama_C_show_each_BOTTOM(min_int, min_one);
+  }
+}
+
 void main() {
   if (v) { pgcd1(a, b); }
   if (v) { pgcd2(a, b); }
@@ -172,4 +214,5 @@ void main() {
   extract_bits_modulo();
   pos_rem();
   address_modulo();
+  test_overflow_alarms();
 }
diff --git a/tests/value/oracle/div.res.oracle b/tests/value/oracle/div.res.oracle
index bf467409f1..4b8b6e318c 100644
--- a/tests/value/oracle/div.res.oracle
+++ b/tests/value/oracle/div.res.oracle
@@ -3,6 +3,7 @@
 [eva] Computing initial state
 [eva] Initial state computed
 [eva:initial-state] Values of globals at initialization
+  nondet ∈ [--..--]
   X ∈ {0}
   Y ∈ {0}
   Z1 ∈ {0}
@@ -24,6 +25,8 @@
    [2] ∈ {3}
    [3..4] ∈ {0}
   p ∈ {0}
+[eva] computing for function test <- main.
+  Called from div.i:86.
 [eva:alarm] div.i:14: Warning: signed overflow. assert c + 1 ≤ 2147483647;
 [eva:alarm] div.i:17: Warning: signed overflow. assert c + 2 ≤ 2147483647;
 [eva] div.i:14: starting to merge loop iterations
@@ -58,11 +61,37 @@
   signed overflow. assert -((int)(&X)) ≤ 2147483647;
 [eva:garbled-mix:write] div.i:37: 
   Assigning imprecise value to e because of arithmetic operation on addresses.
+[eva] Recording results for test
+[eva] Done for function test
+[eva] computing for function test_overflow_alarms <- main.
+  Called from div.i:87.
+[eva:alarm] div.i:52: Warning: signed overflow. assert a_0 / b_0 ≤ 2147483647;
+[eva] div.i:54: Frama_C_show_each: {-2147483648; 10}, {-1; 2}
+[eva:alarm] div.i:57: Warning: 
+  signed overflow. assert a_0 / min_one ≤ 2147483647;
+[eva] div.i:59: Frama_C_show_each_ten: {10}
+[eva:alarm] div.i:62: Warning: 
+  signed overflow. assert min_int / b_0 ≤ 2147483647;
+[eva] div.i:64: Frama_C_show_each_two: {2}
+[eva:alarm] div.i:67: Warning: 
+  signed overflow. assert x / min_one ≤ 2147483647;
+[eva] div.i:69: Frama_C_show_each: [-2147483647..2147483647]
+[eva:alarm] div.i:72: Warning: division by zero. assert x ≢ 0;
+[eva:alarm] div.i:72: Warning: 
+  signed overflow. assert min_int / x ≤ 2147483647;
+[eva] div.i:74: Frama_C_show_each: [-2147483648..2147483647]
+[eva:alarm] div.i:77: Warning: 
+  signed overflow. assert min_int / min_one ≤ 2147483647;
+[eva:alarm] div.i:82: Warning: division by zero. assert y ≢ 0;
+[eva:alarm] div.i:82: Warning: signed overflow. assert x / y ≤ 2147483647;
+[eva] Recording results for test_overflow_alarms
+[eva] Done for function test_overflow_alarms
 [eva] Recording results for main
 [eva] Done for function main
+[eva] div.i:77: assertion 'Eva,signed_overflow' got final status invalid.
 [scope:rm_asserts] removing 2 assertion(s)
 [eva] ====== VALUES COMPUTED ======
-[eva:final-states] Values at end of function main:
+[eva:final-states] Values at end of function test:
   X ∈ [--..--]
   Y ∈ [-126..333],9%27
   Z1 ∈ [-42..111],3%9
@@ -81,10 +110,60 @@
   e ∈ {{ garbled mix of &{X} (origin: Arithmetic {div.i:37}) }}
   p ∈ {{ &t[3] }}
   c ∈ [--..--]
+[eva:final-states] Values at end of function test_overflow_alarms:
+  min_int ∈ {-2147483648}
+  min_one ∈ {-1}
+  a_0 ∈ {-2147483648; 10}
+  b_0 ∈ {-1; 2}
+  x ∈ [--..--]
+  y ∈ [--..--]
+  r ∈ [--..--]
+[eva:final-states] Values at end of function main:
+  X ∈ [--..--]
+  Y ∈ [-126..333],9%27
+  Z1 ∈ [-42..111],3%9
+  Z2 ∈ [-25..66]
+  T ∈ [34..493],7%27
+  U1 ∈ [11..164],2%9
+  U2 ∈ [6..98]
+  V ∈ [-125..334],10%27
+  W1 ∈ [-41..111]
+  W2 ∈ [-25..66]
+  a ∈ [-40000..40000]
+  b ∈ {{ garbled mix of &{Z2} (origin: Arithmetic {div.i:33}) }}
+  d1 ∈ {{ garbled mix of &{X} (origin: Arithmetic {div.i:35}) }}
+  d2 ∈ {{ garbled mix of &{X} (origin: Arithmetic {div.i:34}) }}
+  d0 ∈ {{ garbled mix of &{X} (origin: Arithmetic {div.i:36}) }}
+  e ∈ {{ garbled mix of &{X} (origin: Arithmetic {div.i:37}) }}
+  p ∈ {{ &t[3] }}
+[from] Computing for function test
+[from] Done for function test
+[from] Computing for function test_overflow_alarms
+[from] Done for function test_overflow_alarms
 [from] Computing for function main
 [from] Done for function main
 [from] ====== DEPENDENCIES COMPUTED ======
   These dependencies hold at termination for the executions that terminate:
+[from] Function test:
+  X FROM X (and SELF)
+  Y FROM X
+  Z1 FROM X
+  Z2 FROM X
+  T FROM X
+  U1 FROM X
+  U2 FROM X
+  V FROM X
+  W1 FROM X
+  W2 FROM X
+  a FROM X
+  b FROM X
+  d1 FROM \nothing
+  d2 FROM \nothing
+  d0 FROM \nothing
+  e FROM \nothing
+  p FROM \nothing
+[from] Function test_overflow_alarms:
+  NO EFFECTS
 [from] Function main:
   X FROM X (and SELF)
   Y FROM X
@@ -104,7 +183,15 @@
   e FROM \nothing
   p FROM \nothing
 [from] ====== END OF DEPENDENCIES ======
-[inout] Out (internal) for function main:
+[inout] Out (internal) for function test:
     X; Y; Z1; Z2; T; U1; U2; V; W1; W2; a; b; d1; d2; d0; e; p; c
-[inout] Inputs for function main:
+[inout] Inputs for function test:
     X; Y; Z2; T; V
+[inout] Out (internal) for function test_overflow_alarms:
+    min_int; min_one; a_0; tmp; b_0; tmp_0; x; y; r
+[inout] Inputs for function test_overflow_alarms:
+    nondet
+[inout] Out (internal) for function main:
+    X; Y; Z1; Z2; T; U1; U2; V; W1; W2; a; b; d1; d2; d0; e; p
+[inout] Inputs for function main:
+    nondet; X; Y; Z2; T; V
diff --git a/tests/value/oracle/modulo.res.oracle b/tests/value/oracle/modulo.res.oracle
index 6159974336..bd53257d35 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:165.
-[eva:alarm] modulo.i:165: Warning: 
+  Called from modulo.i:207.
+[eva:alarm] modulo.i:207: 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:166.
-[eva:alarm] modulo.i:166: Warning: 
+  Called from modulo.i:208.
+[eva:alarm] modulo.i:208: 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:167.
-[eva:alarm] modulo.i:167: Warning: 
+  Called from modulo.i:209.
+[eva:alarm] modulo.i:209: 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:169.
+  Called from modulo.i:211.
 [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:170.
+  Called from modulo.i:212.
 [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:171.
+  Called from modulo.i:213.
 [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,19 +83,19 @@
 [eva] Recording results for shift_modulo
 [eva] Done for function shift_modulo
 [eva] computing for function extract_bits_modulo <- main.
-  Called from modulo.i:172.
+  Called from modulo.i:214.
 [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:173.
+  Called from modulo.i:215.
 [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:174.
+  Called from modulo.i:216.
 [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;
@@ -111,8 +111,31 @@
   Assigning imprecise value to r because of arithmetic operation on addresses.
 [eva] Recording results for address_modulo
 [eva] Done for function address_modulo
+[eva] computing for function test_overflow_alarms <- main.
+  Called from modulo.i:217.
+[eva:alarm] modulo.i:176: Warning: 
+  signed overflow. assert a_0 / b_0 ≤ 2147483647;
+[eva] modulo.i:178: Frama_C_show_each: {-2147483648; 10}, {-1; 2}
+[eva:alarm] modulo.i:181: Warning: 
+  signed overflow. assert a_0 / min_one ≤ 2147483647;
+[eva] modulo.i:183: Frama_C_show_each_ten: {10}
+[eva:alarm] modulo.i:186: Warning: 
+  signed overflow. assert min_int / b_0 ≤ 2147483647;
+[eva] modulo.i:188: Frama_C_show_each_two: {2}
+[eva:alarm] modulo.i:191: Warning: 
+  signed overflow. assert x / min_one ≤ 2147483647;
+[eva] modulo.i:193: Frama_C_show_each: [-2147483647..2147483647]
+[eva:alarm] modulo.i:196: Warning: division by zero. assert x ≢ 0;
+[eva:alarm] modulo.i:196: Warning: 
+  signed overflow. assert min_int / x ≤ 2147483647;
+[eva] modulo.i:198: Frama_C_show_each: [-2147483648..2147483647]
+[eva:alarm] modulo.i:201: Warning: 
+  signed overflow. assert min_int / min_one ≤ 2147483647;
+[eva] Recording results for test_overflow_alarms
+[eva] Done for function test_overflow_alarms
 [eva] Recording results for main
 [eva] Done for function main
+[eva] modulo.i:201: assertion 'Eva,signed_overflow' got final status invalid.
 [scope:rm_asserts] removing 2 assertion(s)
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function address_modulo:
@@ -187,6 +210,14 @@
   o1 ∈ [11..268435451],11%24
   o2 ∈ [11..268435451],11%24
   o3 ∈ [11..268435451],11%24
+[eva:final-states] Values at end of function test_overflow_alarms:
+  min_int ∈ {-2147483648}
+  min_one ∈ {-1}
+  a_0 ∈ {-2147483648; 10}
+  b_0 ∈ {-1; 2}
+  x ∈ [--..--]
+  y ∈ [--..--]
+  r ∈ [-2147483647..0]
 [eva:final-states] Values at end of function main:
   A ∈ {0}
   B ∈ {-3; 1}
@@ -223,6 +254,8 @@
 [from] Done for function shift_modulo
 [from] Computing for function simultaneous_congruences
 [from] Done for function simultaneous_congruences
+[from] Computing for function test_overflow_alarms
+[from] Done for function test_overflow_alarms
 [from] Computing for function main
 [from] Done for function main
 [from] ====== DEPENDENCIES COMPUTED ======
@@ -261,6 +294,8 @@
   NO EFFECTS
 [from] Function simultaneous_congruences:
   NO EFFECTS
+[from] Function test_overflow_alarms:
+  NO EFFECTS
 [from] Function main:
   A FROM v
   B FROM v
@@ -317,6 +352,10 @@
     n1; n2; n3; m1; m2; o1; o2; o3
 [inout] Inputs for function simultaneous_congruences:
     i2
+[inout] Out (internal) for function test_overflow_alarms:
+    min_int; min_one; a_0; tmp; b_0; tmp_0; x; y; r
+[inout] Inputs for function test_overflow_alarms:
+    v
 [inout] Out (internal) for function main:
     A; B; C; D; E; F; G; H; I; J; K; L; M; N; O; P; Q
 [inout] Inputs for function main:
-- 
GitLab