From 8a9f4506ff3ec498ebe3def566a594990bfa3c4e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr>
Date: Wed, 27 Mar 2024 15:46:04 +0100
Subject: [PATCH] [Eva] Tests the reduction by ACSL predicates valid_string and
 valid_read_string.

---
 tests/value/oracle/strings_logic.res.oracle   | 232 ++++++++++++++++++
 .../oracle_multidim/strings_logic.res.oracle  |   8 +
 tests/value/strings_logic.c                   | 178 ++++++++++++++
 3 files changed, 418 insertions(+)
 create mode 100644 tests/value/oracle/strings_logic.res.oracle
 create mode 100644 tests/value/oracle_multidim/strings_logic.res.oracle
 create mode 100644 tests/value/strings_logic.c

diff --git a/tests/value/oracle/strings_logic.res.oracle b/tests/value/oracle/strings_logic.res.oracle
new file mode 100644
index 00000000000..1b681b00f32
--- /dev/null
+++ b/tests/value/oracle/strings_logic.res.oracle
@@ -0,0 +1,232 @@
+[kernel] Parsing strings_logic.c (with preprocessing)
+[eva] Analyzing a complete application starting at main
+[eva] Computing initial state
+[eva] Initial state computed
+[eva:initial-state] Values of globals at initialization
+  nondet ∈ [--..--]
+[eva] computing for function reduce_by_valid_string <- main.
+  Called from strings_logic.c:177.
+[eva:loop-unroll:auto] strings_logic.c:30: Automatic loop unrolling.
+[eva:loop-unroll:auto] strings_logic.c:36: Automatic loop unrolling.
+[eva:loop-unroll:auto] strings_logic.c:41: Automatic loop unrolling.
+[eva:loop-unroll:auto] strings_logic.c:48: Automatic loop unrolling.
+[eva:loop-unroll:auto] strings_logic.c:53: Automatic loop unrolling.
+[eva:alarm] strings_logic.c:84: Warning: assertion got status unknown.
+[eva] strings_logic.c:85: 
+  Frama_C_show_each_valid_string_zero_offset:
+  {{ &s1 ; &s2 ; &s_zero ; &s_partially_valid ; &s_imprecise ; &s_unknown ;
+     &anything }}
+[eva:alarm] strings_logic.c:89: Warning: assertion got status unknown.
+[eva] strings_logic.c:90: 
+  Frama_C_show_each_valid_read_string_zero_offset:
+  {{ &s1 ; &s2 ; &s_const ; &s_zero ; &s_partially_valid ; &s_imprecise ;
+     &s_unknown ; &anything ; "hello\000 world" ; "hello world" }}
+[eva:alarm] strings_logic.c:94: Warning: assertion got status unknown.
+[eva] strings_logic.c:95: 
+  Frama_C_show_each_invalid_string_zero_offset:
+  {{ NULL ; &s_const ; &s_uninit ; &s_partially_initialized ; &s_imprecise ;
+     &s_unknown ; &anything ; "hello\000 world" ; "hello world" }}
+[eva:alarm] strings_logic.c:99: Warning: assertion got status unknown.
+[eva] strings_logic.c:100: 
+  Frama_C_show_each_invalid_read_string_zero_offset:
+  {{ NULL ; &s_uninit ; &s_partially_initialized ; &s_imprecise ; &s_unknown ;
+     &anything }}
+[eva:alarm] strings_logic.c:108: Warning: assertion got status unknown.
+[eva] strings_logic.c:109: 
+  Frama_C_show_each_valid_string_precise_offset:
+  {{ &s1 + {5; 10} ; &s2 + {5; 10} ; &s_zero + {5; 10; 20} ;
+     &s_partially_initialized + {5; 10; 20} ;
+     &s_partially_valid + {5; 10; 20} ; &s_imprecise + {5; 10; 20} ;
+     &s_unknown + {5; 10; 20} ; &anything + {5; 10} }}
+[eva:alarm] strings_logic.c:113: Warning: assertion got status unknown.
+[eva] strings_logic.c:114: 
+  Frama_C_show_each_valid_read_string_precise_offset:
+  {{ &s1 + {5; 10} ; &s2 + {5; 10} ; &s_const + {5; 10} ;
+     &s_zero + {5; 10; 20} ; &s_partially_initialized + {5; 10; 20} ;
+     &s_partially_valid + {5; 10; 20} ; &s_imprecise + {5; 10; 20} ;
+     &s_unknown + {5; 10; 20} ; &anything + {5; 10} ;
+     "hello\000 world" + {5; 10} ; "hello world" + {5; 10} }}
+[eva:alarm] strings_logic.c:118: Warning: assertion got status unknown.
+[eva] strings_logic.c:119: 
+  Frama_C_show_each_invalid_string_precise_offset:
+  {{ NULL + {5; 10; 20} ; &s1 + {5; 10; 20} ; &s2 + {5; 10; 20} ;
+     &s_const + {5; 10; 20} ; &s_uninit + {5; 10; 20} ;
+     &s_partially_initialized + {5; 10; 20} ;
+     &s_partially_valid + {5; 10; 20} ; &s_imprecise + {5; 10; 20} ;
+     &s_unknown + {5; 10; 20} ; &anything + {5; 10; 20} ;
+     "hello\000 world" + {5; 10; 20} ; "hello world" + {5; 10; 20} }}
+[eva:alarm] strings_logic.c:123: Warning: assertion got status unknown.
+[eva] strings_logic.c:124: 
+  Frama_C_show_each_invalid_read_string_precise_offset:
+  {{ NULL + {5; 10; 20} ; &s1 + {5; 10; 20} ; &s2 + {5; 10; 20} ;
+     &s_const + {5; 10; 20} ; &s_uninit + {5; 10; 20} ;
+     &s_partially_initialized + {5; 10; 20} ;
+     &s_partially_valid + {5; 10; 20} ; &s_imprecise + {5; 10; 20} ;
+     &s_unknown + {5; 10; 20} ; &anything + {5; 10; 20} ;
+     "hello\000 world" + {5; 10; 20} ; "hello world" + {5; 10; 20} }}
+[eva:alarm] strings_logic.c:131: Warning: assertion got status unknown.
+[eva] strings_logic.c:132: 
+  Frama_C_show_each_valid_string_imprecise_offset:
+  {{ &s1 + [0..13] ; &s2 + [0..12] ; &s_zero + [0..31] ;
+     &s_partially_initialized + [0..31] ; &s_partially_valid + [0..31] ;
+     &s_imprecise + [0..31] ; &s_unknown + [0..31] ; &anything + [0..15] }}
+[eva:alarm] strings_logic.c:136: Warning: assertion got status unknown.
+[eva] strings_logic.c:137: 
+  Frama_C_show_each_valid_read_string_imprecise_offset:
+  {{ &s1 + [0..13] ; &s2 + [0..12] ; &s_const + [0..16] ; &s_zero + [0..31] ;
+     &s_partially_initialized + [0..31] ; &s_partially_valid + [0..31] ;
+     &s_imprecise + [0..31] ; &s_unknown + [0..31] ; &anything + [0..15] ;
+     "hello\000 world" + [0..12] ; "hello world" + [0..11] }}
+[eva:alarm] strings_logic.c:141: Warning: assertion got status unknown.
+[eva] strings_logic.c:142: 
+  Frama_C_show_each_invalid_string_imprecise_offset:
+  {{ NULL + [0..4294967295] ; &s1 + [-123..147] ; &s2 + [-123..147] ;
+     &s_const + [-123..147] ; &s_zero + [-123..147] ; &s_uninit + [-123..147] ;
+     &s_partially_initialized + [-123..147] ;
+     &s_partially_valid + [-123..147] ; &s_imprecise + [-123..147] ;
+     &s_unknown + [-123..147] ; &anything + [-123..147] ;
+     "hello\000 world" + [-123..147] ; "hello world" + [-123..147] }}
+[eva:alarm] strings_logic.c:146: Warning: assertion got status unknown.
+[eva] strings_logic.c:147: 
+  Frama_C_show_each_invalid_read_string_imprecise_offset:
+  {{ NULL + [0..4294967295] ; &s1 + [-123..147] ; &s2 + [-123..147] ;
+     &s_const + [-123..147] ; &s_zero + [-123..147] ; &s_uninit + [-123..147] ;
+     &s_partially_initialized + [-123..147] ;
+     &s_partially_valid + [-123..147] ; &s_imprecise + [-123..147] ;
+     &s_unknown + [-123..147] ; &anything + [-123..147] ;
+     "hello\000 world" + [-123..147] ; "hello world" + [-123..147] }}
+[eva] computing for function garbled_mix <- reduce_by_valid_string <- main.
+  Called from strings_logic.c:151.
+[eva] using specification for function garbled_mix
+[eva:garbled-mix:assigns] strings_logic.c:151: 
+  The specification of function garbled_mix
+  has generated a garbled mix of addresses for assigns clause \result.
+[eva] Done for function garbled_mix
+[eva:alarm] strings_logic.c:154: Warning: assertion got status unknown.
+[eva] strings_logic.c:155: 
+  Frama_C_show_each_valid_string_garbled_mix:
+  {{ &s1 + [0..13] ; &s2 + [0..12] ; &s_zero + [0..31] ;
+     &s_partially_initialized + [0..31] ; &s_partially_valid + [0..31] ;
+     &s_imprecise + [0..31] ; &s_unknown + [0..31] ; &anything + [0..15] }}
+[eva:alarm] strings_logic.c:159: Warning: assertion got status unknown.
+[eva] strings_logic.c:160: 
+  Frama_C_show_each_valid_read_string_garbled_mix:
+  {{ &s1 + [0..13] ; &s2 + [0..12] ; &s_const + [0..16] ; &s_zero + [0..31] ;
+     &s_partially_initialized + [0..31] ; &s_partially_valid + [0..31] ;
+     &s_imprecise + [0..31] ; &s_unknown + [0..31] ; &anything + [0..15] ;
+     "hello\000 world" + [0..12] ; "hello world" + [0..11] }}
+[eva:alarm] strings_logic.c:164: Warning: assertion got status unknown.
+[eva] strings_logic.c:165: 
+  Frama_C_show_each_invalid_string_garbled_mix:
+  {{ garbled mix of &{s1; s2; s_const; s_zero; s_uninit;
+                      s_partially_initialized; s_partially_valid; s_imprecise;
+                      s_unknown; anything; "hello\000 world"; "hello world"}
+  (origin: Library function {strings_logic.c:151}) }}
+[eva:alarm] strings_logic.c:169: Warning: assertion got status unknown.
+[eva] strings_logic.c:170: 
+  Frama_C_show_each_invalid_read_string_garbled_mix:
+  {{ garbled mix of &{s1; s2; s_const; s_zero; s_uninit;
+                      s_partially_initialized; s_partially_valid; s_imprecise;
+                      s_unknown; anything; "hello\000 world"; "hello world"}
+  (origin: Library function {strings_logic.c:151}) }}
+[eva] Recording results for reduce_by_valid_string
+[eva] Done for function reduce_by_valid_string
+[eva] Recording results for main
+[eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    strings_logic.c:151: assigns clause on addresses
+      (read in 2 statements, propagated through 1 statement)
+      garbled mix of &{s1; s2; s_const; s_zero; s_uninit;
+                       s_partially_initialized; s_partially_valid; s_imprecise;
+                       s_unknown; anything; "hello\000 world"; "hello world"}
+[eva] ====== VALUES COMPUTED ======
+[eva:final-states] Values at end of function reduce_by_valid_string:
+  s1[0] ∈ {104}
+    [1] ∈ {101}
+    [2..3] ∈ {108}
+    [4] ∈ {111}
+    [5] ∈ {0}
+    [6] ∈ {32}
+    [7] ∈ {119}
+    [8] ∈ {111}
+    [9] ∈ {114}
+    [10] ∈ {108}
+    [11] ∈ {100}
+    [12] ∈ {33}
+    [13] ∈ {0}
+  s2[0] ∈ {104}
+    [1] ∈ {101}
+    [2..3] ∈ {108}
+    [4] ∈ {111}
+    [5] ∈ {32}
+    [6] ∈ {119}
+    [7] ∈ {111}
+    [8] ∈ {114}
+    [9] ∈ {108}
+    [10] ∈ {100}
+    [11] ∈ {33}
+    [12] ∈ {0}
+  s_const[0] ∈ {99}
+         [1] ∈ {111}
+         [2] ∈ {110}
+         [3] ∈ {115}
+         [4] ∈ {116}
+         [5] ∈ {32}
+         [6] ∈ {99}
+         [7] ∈ {104}
+         [8] ∈ {97}
+         [9] ∈ {114}
+         [10] ∈ {32}
+         [11] ∈ {97}
+         [12..13] ∈ {114}
+         [14] ∈ {97}
+         [15] ∈ {121}
+         [16] ∈ {0}
+  s_zero[0..31] ∈ {0}
+  s_partially_initialized[0..9] ∈ UNINITIALIZED
+                         [10..24] ∈ {105}
+                         [25] ∈ {0}
+                         [26..31] ∈ UNINITIALIZED
+  s_invalid[0..31] ∈ {97}
+  s_partially_valid[0..7] ∈ {111}
+                   [8] ∈ {0}
+                   [9..15] ∈ {111}
+                   [16] ∈ {0}
+                   [17..31] ∈ {111}
+  s_imprecise[0..31] ∈ [--..--]
+  s_unknown[0..31] ∈ [--..--] or UNINITIALIZED
+  anything.ptr ∈ {{ &x }}
+          .d ∈ [-128. .. 127.]
+          .c ∈ [--..--]
+          .[bits 104 to 127] ∈ UNINITIALIZED
+  p ∈ {0}
+  offset ∈ {5; 10; 20}
+[eva:final-states] Values at end of function main:
+  
+[from] Computing for function reduce_by_valid_string
+[from] Computing for function garbled_mix <-reduce_by_valid_string
+[from] Done for function garbled_mix
+[from] Done for function reduce_by_valid_string
+[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 garbled_mix:
+  \result FROM p
+[from] Function reduce_by_valid_string:
+  NO EFFECTS
+[from] Function main:
+  NO EFFECTS
+[from] ====== END OF DEPENDENCIES ======
+[inout] Out (internal) for function reduce_by_valid_string:
+    s1[0..13]; s2[0..12]; s_const[0..16]; s_zero[0..31];
+    s_partially_initialized[10..25]; i; s_invalid[0..31]; i_0;
+    s_partially_valid[0..31]; i_1; s_imprecise[0..31]; i_2; s_unknown[0..31];
+    i_3; anything{.ptr; .d; .c}; p; offset; tmp; tmp_0
+[inout] Inputs for function reduce_by_valid_string:
+    nondet
+[inout] Out (internal) for function main:
+    \nothing
+[inout] Inputs for function main:
+    nondet
diff --git a/tests/value/oracle_multidim/strings_logic.res.oracle b/tests/value/oracle_multidim/strings_logic.res.oracle
new file mode 100644
index 00000000000..ed8b014f3c9
--- /dev/null
+++ b/tests/value/oracle_multidim/strings_logic.res.oracle
@@ -0,0 +1,8 @@
+83c83
+<   {{ NULL + [0..4294967295] ; &s1 + [-123..147] ; &s2 + [-123..147] ;
+---
+>   {{ NULL + [0..147] ; &s1 + [-123..147] ; &s2 + [-123..147] ;
+92c92
+<   {{ NULL + [0..4294967295] ; &s1 + [-123..147] ; &s2 + [-123..147] ;
+---
+>   {{ NULL + [0..147] ; &s1 + [-123..147] ; &s2 + [-123..147] ;
diff --git a/tests/value/strings_logic.c b/tests/value/strings_logic.c
new file mode 100644
index 00000000000..3fe276661fe
--- /dev/null
+++ b/tests/value/strings_logic.c
@@ -0,0 +1,178 @@
+/* run.config*
+   STDOPT: +"-eva-auto-loop-unroll 32"
+*/
+
+/* Tests the evaluation and reduction by ACSL predicate on strings. */
+
+#include "__fc_string_axiomatic.h"
+
+volatile char nondet;
+
+struct anything {
+  int *ptr;
+  double d;
+  char c;
+};
+
+/*@ assigns \result \from p; */
+char* garbled_mix(char *p);
+
+/* Tests the reduction by ACSL predicate "valid_string" and "valid_read_string"
+   from the Frama-C libc. */
+void reduce_by_valid_string (void) {
+  char s1[] = "hello\000 world!";
+  char s2[] = "hello world!";
+  const char s_const[] = "const char array";
+  char s_zero[32] = {0};
+  char s_uninit[32];
+
+  char s_partially_initialized[32]; // valid only between 10 and 25.
+  for (int i = 10; i < 25; i++) {
+    s_partially_initialized[i] = 'i';
+  }
+  s_partially_initialized[25] = '\0';
+
+  char s_invalid[32]; // Invalid as no terminating \0
+  for (int i = 0; i < 32; i++){
+    s_invalid[i] = 'a';
+  }
+
+  char s_partially_valid[32]; // valid up to offset 16.
+  for (int i = 0; i < 32; i++){
+    s_partially_valid[i] = 'o';
+  }
+  s_partially_valid[8] = '\0';
+  s_partially_valid[16] = '\0';
+
+  char s_imprecise[32]; // char array of imprecise values
+  for (int i = 0; i < 32; i++){
+    s_imprecise[i] = nondet;
+  }
+
+  char s_unknown[32]; // char array of imprecise values that may be uninitialized
+  for (int i = 0; i < 32; i++) {
+    if (nondet) s_unknown[i] = nondet;
+  }
+
+  int x;
+  struct anything anything;
+  anything.ptr = &x;
+  anything.d = (double)nondet;
+  anything.c = nondet;
+
+  // Pointer p that can point to any of the strings above.
+  char *p;
+  switch (nondet) {
+    case 0: p = "hello\000 world"; break;
+    case 1: p = "hello world"; break;
+    case 2: p = s1; break;
+    case 3: p = s2; break;
+    case 4: p = s_const; break;
+    case 5: p = s_zero; break;
+    case 6: p = s_uninit; break;
+    case 7: p = s_partially_initialized; break;
+    case 8: p = s_partially_valid; break;
+    case 9: p = s_imprecise; break;
+    case 10: p = s_unknown; break;
+    case 11: p = (char *)&anything; break;
+    default: p = NULL;
+  }
+
+  // Test with a zero offset for all bases.
+
+  if (nondet) {
+    //@ assert valid_string(p);
+    Frama_C_show_each_valid_string_zero_offset(p);
+  }
+
+  if (nondet) {
+    //@ assert valid_read_string(p);
+    Frama_C_show_each_valid_read_string_zero_offset(p);
+  }
+
+  if (nondet) {
+    //@ assert !valid_string(p);
+    Frama_C_show_each_invalid_string_zero_offset(p);
+  }
+
+  if (nondet) {
+    //@ assert !valid_read_string(p);
+    Frama_C_show_each_invalid_read_string_zero_offset(p);
+  }
+
+  // Test with a precise non-zero non-singleton offset.
+  int offset = nondet ? 5 : (nondet ? 10 : 20);
+  p = p + offset;
+
+  if (nondet) {
+    //@ assert valid_string(p);
+    Frama_C_show_each_valid_string_precise_offset(p);
+  }
+
+  if (nondet) {
+    //@ assert valid_read_string(p);
+    Frama_C_show_each_valid_read_string_precise_offset(p);
+  }
+
+  if (nondet) {
+    //@ assert !valid_string(p);
+    Frama_C_show_each_invalid_string_precise_offset(p);
+  }
+
+  if (nondet) {
+    //@ assert !valid_read_string(p);
+    Frama_C_show_each_invalid_read_string_precise_offset(p);
+  }
+
+  // Test with a very imprecise offset.
+  p = p + nondet;
+
+  if (nondet) {
+    //@ assert valid_string(p);
+    Frama_C_show_each_valid_string_imprecise_offset(p);
+  }
+
+  if (nondet) {
+    //@ assert valid_read_string(p);
+    Frama_C_show_each_valid_read_string_imprecise_offset(p);
+  }
+
+  if (nondet) {
+    //@ assert !valid_string(p);
+    Frama_C_show_each_invalid_string_imprecise_offset(p);
+  }
+
+  if (nondet) {
+    //@ assert !valid_read_string(p);
+    Frama_C_show_each_invalid_read_string_imprecise_offset(p);
+  }
+
+  // Test with a garbled mix.
+  p = garbled_mix(p);
+
+  if (nondet) {
+    //@ assert valid_string(p);
+    Frama_C_show_each_valid_string_garbled_mix(p);
+  }
+
+  if (nondet) {
+    //@ assert valid_read_string(p);
+    Frama_C_show_each_valid_read_string_garbled_mix(p);
+  }
+
+  if (nondet) {
+    //@ assert !valid_string(p);
+    Frama_C_show_each_invalid_string_garbled_mix(p);
+  }
+
+  if (nondet) {
+    //@ assert !valid_read_string(p);
+    Frama_C_show_each_invalid_read_string_garbled_mix(p);
+  }
+
+  p = NULL;
+}
+
+void main (void) {
+  reduce_by_valid_string();
+}
-- 
GitLab