From a9cdb059e17583f178dba879475fdf70604d9473 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr>
Date: Thu, 11 Feb 2021 09:47:47 +0100
Subject: [PATCH] [libc] math.h: adds behaviors for NaN and infinite cases in
 exp specifications.

---
 share/libc/math.h                           | 58 +++++++++++-
 tests/float/oracle/builtins.res.oracle      | 48 +++++++---
 tests/float/oracle/math_builtins.res.oracle | 97 +++++++++++++++------
 tests/float/oracle/sqrt.0.res.oracle        |  2 +
 tests/float/oracle/sqrt.1.res.oracle        |  2 +
 5 files changed, 161 insertions(+), 46 deletions(-)

diff --git a/share/libc/math.h b/share/libc/math.h
index 84751ea44f6..566406dfae8 100644
--- a/share/libc/math.h
+++ b/share/libc/math.h
@@ -515,19 +515,69 @@ extern double tanh(double x);
 extern float tanhf(float x);
 extern long double tanhl(long double x);
 
-/*@ requires finite_arg: \is_finite(x);
-    requires finite_domain: x <= 0x1.62e42fefa39efp+9;
+/*@
+  assigns errno, \result \from x;
+  behavior normal:
+    assumes finite_arg: \is_finite(x);
+    assumes domain_arg: x >= -0x1.74910d52d3051p9 && x <= 0x1.62e42fefa39efp+9;
     assigns \result \from x;
     ensures res_finite: \is_finite(\result);
     ensures positive_result: \result > 0.;
+  behavior overflow:
+    assumes overflow_arg: \is_finite(x) && x > 0x1.62e42fefa39efp+9;
+    ensures infinite_res: \is_plus_infinity(\result);
+    ensures errno_set: errno == ERANGE;
+  behavior plus_infinity:
+    assumes plus_infinity_arg: \is_plus_infinity(x);
+    assigns \result \from x;
+    ensures infinity_result: \is_plus_infinity(\result);
+  behavior underflow:
+    assumes underflow_arg: \is_finite(x) && x < -0x1.74910d52d3051p9;
+    ensures zero_res: \result == 0.;
+    ensures errno_set: errno == ERANGE;
+  behavior minus_infinity:
+    assumes plus_infinity_arg: \is_minus_infinity(x);
+    assigns \result \from x;
+    ensures zero_result: \is_finite(\result) && \result == 0.;
+  behavior nan:
+    assumes nan_arg: \is_NaN(x);
+    assigns \result \from x;
+    ensures nan_result: \is_NaN(\result);
+  complete behaviors;
+  disjoint behaviors;
 */
 extern double exp(double x);
 
-/*@ requires finite_arg: \is_finite(x);
-    requires res_finite: x <= 0x1.62e42ep+6;
+/*@
+  assigns errno, \result \from x;
+  behavior normal:
+    assumes finite_arg: \is_finite(x);
+    assumes domain_arg: x >= -0x1.9fe368p6 && x <= 0x1.62e42ep+6;
     assigns \result \from x;
     ensures res_finite: \is_finite(\result);
     ensures positive_result: \result > 0.;
+  behavior overflow:
+    assumes overflow_arg: \is_finite(x) && x > 0x1.62e42ep+6;
+    ensures infinite_res: \is_plus_infinity(\result);
+    ensures errno_set: errno == ERANGE;
+  behavior plus_infinity:
+    assumes plus_infinity_arg: \is_plus_infinity(x);
+    assigns \result \from x;
+    ensures infinity_result: \is_plus_infinity(\result);
+  behavior underflow:
+    assumes underflow_arg: \is_finite(x) && x < -0x1.9fe368p6;
+    ensures zero_res: \result == 0.;
+    ensures errno_set: errno == ERANGE;
+  behavior minus_infinity:
+    assumes plus_infinity_arg: \is_minus_infinity(x);
+    assigns \result \from x;
+    ensures zero_result: \is_finite(\result) && \result == 0.;
+  behavior nan:
+    assumes nan_arg: \is_NaN(x);
+    assigns \result \from x;
+    ensures nan_result: \is_NaN(\result);
+  complete behaviors;
+  disjoint behaviors;
 */
 extern float expf(float x);
 
diff --git a/tests/float/oracle/builtins.res.oracle b/tests/float/oracle/builtins.res.oracle
index 66f30707d32..e6023b3d1ca 100644
--- a/tests/float/oracle/builtins.res.oracle
+++ b/tests/float/oracle/builtins.res.oracle
@@ -99,30 +99,46 @@
   function log10: precondition 'arg_positive' got status invalid.
 [eva] tests/float/builtins.c:85: Call to builtin exp
 [eva] tests/float/builtins.c:85: 
-  function exp: precondition 'finite_arg' got status valid.
+  function exp: precondition ¬(overflow_arg:
+                                  \is_finite(x) ∧ x > 0x1.62e42fefa39efp+9) got status valid.
 [eva] tests/float/builtins.c:85: 
-  function exp: precondition 'finite_domain' got status valid.
+  function exp: precondition ¬(plus_infinity_arg: \is_plus_infinity(x)) got status valid.
+[eva] tests/float/builtins.c:85: 
+  function exp: precondition ¬(nan_arg: \is_NaN(x)) got status valid.
 [eva] tests/float/builtins.c:88: Call to builtin exp
 [eva] tests/float/builtins.c:88: 
-  function exp: precondition 'finite_arg' got status valid.
+  function exp: precondition ¬(overflow_arg:
+                                  \is_finite(x) ∧ x > 0x1.62e42fefa39efp+9) got status valid.
+[eva] tests/float/builtins.c:88: 
+  function exp: precondition ¬(plus_infinity_arg: \is_plus_infinity(x)) got status valid.
 [eva] tests/float/builtins.c:88: 
-  function exp: precondition 'finite_domain' got status valid.
+  function exp: precondition ¬(nan_arg: \is_NaN(x)) got status valid.
 [eva] tests/float/builtins.c:91: Call to builtin exp
 [eva] tests/float/builtins.c:91: 
-  function exp: precondition 'finite_arg' got status valid.
+  function exp: precondition ¬(overflow_arg:
+                                  \is_finite(x) ∧ x > 0x1.62e42fefa39efp+9) got status valid.
+[eva] tests/float/builtins.c:91: 
+  function exp: precondition ¬(plus_infinity_arg: \is_plus_infinity(x)) got status valid.
 [eva] tests/float/builtins.c:91: 
-  function exp: precondition 'finite_domain' got status valid.
+  function exp: precondition ¬(nan_arg: \is_NaN(x)) got status valid.
 [eva:alarm] tests/float/builtins.c:94: Warning: assertion got status unknown.
 [eva] tests/float/builtins.c:95: Call to builtin exp
-[eva] tests/float/builtins.c:95: 
-  function exp: precondition 'finite_arg' got status valid.
 [eva:alarm] tests/float/builtins.c:95: Warning: 
-  function exp: precondition 'finite_domain' got status unknown.
+  function exp: precondition ¬(overflow_arg:
+                                  \is_finite(x) ∧ x > 0x1.62e42fefa39efp+9) got status unknown.
+[eva] tests/float/builtins.c:95: 
+  function exp: precondition ¬(plus_infinity_arg: \is_plus_infinity(x)) got status valid.
+[eva] tests/float/builtins.c:95: 
+  function exp: precondition ¬(nan_arg: \is_NaN(x)) got status valid.
 [eva] tests/float/builtins.c:98: Call to builtin exp
-[eva] tests/float/builtins.c:98: 
-  function exp: precondition 'finite_arg' got status valid.
 [eva:alarm] tests/float/builtins.c:98: Warning: 
-  function exp: precondition 'finite_domain' got status invalid.
+  function exp: precondition ¬(overflow_arg:
+                                  \is_finite(x) ∧ x > 0x1.62e42fefa39efp+9) got status invalid.
+[eva] tests/float/builtins.c:98: 
+  function exp: no state left, precondition ¬(plus_infinity_arg:
+                                                 \is_plus_infinity(x)) got status valid.
+[eva] tests/float/builtins.c:98: 
+  function exp: no state left, precondition ¬(nan_arg: \is_NaN(x)) got status valid.
 [eva] tests/float/builtins.c:102: Call to builtin log
 [eva] tests/float/builtins.c:102: 
   function log: precondition 'finite_arg' got status valid.
@@ -131,9 +147,12 @@
 [eva] tests/float/builtins.c:103: assertion got status valid.
 [eva] tests/float/builtins.c:104: Call to builtin exp
 [eva] tests/float/builtins.c:104: 
-  function exp: precondition 'finite_arg' got status valid.
+  function exp: precondition ¬(overflow_arg:
+                                  \is_finite(x) ∧ x > 0x1.62e42fefa39efp+9) got status valid.
+[eva] tests/float/builtins.c:104: 
+  function exp: precondition ¬(plus_infinity_arg: \is_plus_infinity(x)) got status valid.
 [eva] tests/float/builtins.c:104: 
-  function exp: precondition 'finite_domain' got status valid.
+  function exp: precondition ¬(nan_arg: \is_NaN(x)) got status valid.
 [eva:alarm] tests/float/builtins.c:107: Warning: 
   pointer downcast. assert (unsigned int)(&d) ≤ 2147483647;
 [eva:alarm] tests/float/builtins.c:107: Warning: 
@@ -155,6 +174,7 @@
   assertion 'Eva,initialization' got final status invalid.
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main_log_exp:
+  __fc_errno ∈ [--..--]
   l1 ∈ {0} or UNINITIALIZED
   l2 ∈ {1.00063188031} or UNINITIALIZED
   l3 ∈ {1.09861228867} or UNINITIALIZED
diff --git a/tests/float/oracle/math_builtins.res.oracle b/tests/float/oracle/math_builtins.res.oracle
index 6d134f9df1d..8d5f7927ba8 100644
--- a/tests/float/oracle/math_builtins.res.oracle
+++ b/tests/float/oracle/math_builtins.res.oracle
@@ -1213,39 +1213,58 @@
 [eva] tests/float/math_builtins.c:516: 
   Call to builtin Frama_C_exp for function exp
 [eva] tests/float/math_builtins.c:516: 
-  function exp: precondition 'finite_arg' got status valid.
+  function exp: precondition ¬(overflow_arg:
+                                  \is_finite(x) ∧ x > 0x1.62e42fefa39efp+9) got status valid.
 [eva] tests/float/math_builtins.c:516: 
-  function exp: precondition 'finite_domain' got status valid.
+  function exp: precondition ¬(plus_infinity_arg: \is_plus_infinity(x)) got status valid.
+[eva] tests/float/math_builtins.c:516: 
+  function exp: precondition ¬(nan_arg: \is_NaN(x)) got status valid.
 [eva] tests/float/math_builtins.c:517: 
   Call to builtin Frama_C_exp for function exp
 [eva] tests/float/math_builtins.c:517: 
-  function exp: precondition 'finite_arg' got status valid.
+  function exp: precondition ¬(overflow_arg:
+                                  \is_finite(x) ∧ x > 0x1.62e42fefa39efp+9) got status valid.
+[eva] tests/float/math_builtins.c:517: 
+  function exp: precondition ¬(plus_infinity_arg: \is_plus_infinity(x)) got status valid.
 [eva] tests/float/math_builtins.c:517: 
-  function exp: precondition 'finite_domain' got status valid.
+  function exp: precondition ¬(nan_arg: \is_NaN(x)) got status valid.
 [eva] tests/float/math_builtins.c:518: 
   Call to builtin Frama_C_exp for function exp
 [eva] tests/float/math_builtins.c:518: 
-  function exp: precondition 'finite_arg' got status valid.
+  function exp: precondition ¬(overflow_arg:
+                                  \is_finite(x) ∧ x > 0x1.62e42fefa39efp+9) got status valid.
 [eva] tests/float/math_builtins.c:518: 
-  function exp: precondition 'finite_domain' got status valid.
+  function exp: precondition ¬(plus_infinity_arg: \is_plus_infinity(x)) got status valid.
+[eva] tests/float/math_builtins.c:518: 
+  function exp: precondition ¬(nan_arg: \is_NaN(x)) got status valid.
 [eva] tests/float/math_builtins.c:519: 
   Call to builtin Frama_C_exp for function exp
 [eva] tests/float/math_builtins.c:519: 
-  function exp: precondition 'finite_arg' got status valid.
+  function exp: precondition ¬(overflow_arg:
+                                  \is_finite(x) ∧ x > 0x1.62e42fefa39efp+9) got status valid.
+[eva] tests/float/math_builtins.c:519: 
+  function exp: precondition ¬(plus_infinity_arg: \is_plus_infinity(x)) got status valid.
 [eva] tests/float/math_builtins.c:519: 
-  function exp: precondition 'finite_domain' got status valid.
+  function exp: precondition ¬(nan_arg: \is_NaN(x)) got status valid.
 [eva] tests/float/math_builtins.c:520: 
   Call to builtin Frama_C_exp for function exp
 [eva] tests/float/math_builtins.c:520: 
-  function exp: precondition 'finite_arg' got status valid.
+  function exp: precondition ¬(overflow_arg:
+                                  \is_finite(x) ∧ x > 0x1.62e42fefa39efp+9) got status valid.
 [eva] tests/float/math_builtins.c:520: 
-  function exp: precondition 'finite_domain' got status valid.
+  function exp: precondition ¬(plus_infinity_arg: \is_plus_infinity(x)) got status valid.
+[eva] tests/float/math_builtins.c:520: 
+  function exp: precondition ¬(nan_arg: \is_NaN(x)) got status valid.
 [eva] tests/float/math_builtins.c:521: 
   Call to builtin Frama_C_exp for function exp
-[eva] tests/float/math_builtins.c:521: 
-  function exp: precondition 'finite_arg' got status valid.
 [eva:alarm] tests/float/math_builtins.c:521: Warning: 
-  function exp: precondition 'finite_domain' got status invalid.
+  function exp: precondition ¬(overflow_arg:
+                                  \is_finite(x) ∧ x > 0x1.62e42fefa39efp+9) got status invalid.
+[eva] tests/float/math_builtins.c:521: 
+  function exp: no state left, precondition ¬(plus_infinity_arg:
+                                                 \is_plus_infinity(x)) got status valid.
+[eva] tests/float/math_builtins.c:521: 
+  function exp: no state left, precondition ¬(nan_arg: \is_NaN(x)) got status valid.
 [eva] Recording results for test_exp_det
 [eva] Done for function test_exp_det
 [eva] computing for function test_log_det <- main.
@@ -1782,33 +1801,48 @@
 [eva] tests/float/math_builtins.c:525: 
   Call to builtin Frama_C_expf for function expf
 [eva] tests/float/math_builtins.c:525: 
-  function expf: precondition 'finite_arg' got status valid.
+  function expf: precondition ¬(overflow_arg:
+                                   \is_finite(x) ∧ x > 0x1.62e42ep+6) got status valid.
 [eva] tests/float/math_builtins.c:525: 
-  function expf: precondition 'res_finite' got status valid.
+  function expf: precondition ¬(plus_infinity_arg: \is_plus_infinity(x)) got status valid.
+[eva] tests/float/math_builtins.c:525: 
+  function expf: precondition ¬(nan_arg: \is_NaN(x)) got status valid.
 [eva] tests/float/math_builtins.c:526: 
   Call to builtin Frama_C_expf for function expf
 [eva] tests/float/math_builtins.c:526: 
-  function expf: precondition 'finite_arg' got status valid.
+  function expf: precondition ¬(overflow_arg:
+                                   \is_finite(x) ∧ x > 0x1.62e42ep+6) got status valid.
+[eva] tests/float/math_builtins.c:526: 
+  function expf: precondition ¬(plus_infinity_arg: \is_plus_infinity(x)) got status valid.
 [eva] tests/float/math_builtins.c:526: 
-  function expf: precondition 'res_finite' got status valid.
+  function expf: precondition ¬(nan_arg: \is_NaN(x)) got status valid.
 [eva] tests/float/math_builtins.c:527: 
   Call to builtin Frama_C_expf for function expf
 [eva] tests/float/math_builtins.c:527: 
-  function expf: precondition 'finite_arg' got status valid.
+  function expf: precondition ¬(overflow_arg:
+                                   \is_finite(x) ∧ x > 0x1.62e42ep+6) got status valid.
 [eva] tests/float/math_builtins.c:527: 
-  function expf: precondition 'res_finite' got status valid.
+  function expf: precondition ¬(plus_infinity_arg: \is_plus_infinity(x)) got status valid.
+[eva] tests/float/math_builtins.c:527: 
+  function expf: precondition ¬(nan_arg: \is_NaN(x)) got status valid.
 [eva] tests/float/math_builtins.c:528: 
   Call to builtin Frama_C_expf for function expf
 [eva] tests/float/math_builtins.c:528: 
-  function expf: precondition 'finite_arg' got status valid.
+  function expf: precondition ¬(overflow_arg:
+                                   \is_finite(x) ∧ x > 0x1.62e42ep+6) got status valid.
+[eva] tests/float/math_builtins.c:528: 
+  function expf: precondition ¬(plus_infinity_arg: \is_plus_infinity(x)) got status valid.
 [eva] tests/float/math_builtins.c:528: 
-  function expf: precondition 'res_finite' got status valid.
+  function expf: precondition ¬(nan_arg: \is_NaN(x)) got status valid.
 [eva] tests/float/math_builtins.c:529: 
   Call to builtin Frama_C_expf for function expf
 [eva] tests/float/math_builtins.c:529: 
-  function expf: precondition 'finite_arg' got status valid.
+  function expf: precondition ¬(overflow_arg:
+                                   \is_finite(x) ∧ x > 0x1.62e42ep+6) got status valid.
 [eva] tests/float/math_builtins.c:529: 
-  function expf: precondition 'res_finite' got status valid.
+  function expf: precondition ¬(plus_infinity_arg: \is_plus_infinity(x)) got status valid.
+[eva] tests/float/math_builtins.c:529: 
+  function expf: precondition ¬(nan_arg: \is_NaN(x)) got status valid.
 [eva] Recording results for test_expf_det
 [eva] Done for function test_expf_det
 [eva] computing for function test_logf_det <- main.
@@ -2455,12 +2489,14 @@
   d ∈ {1.3824840787361052*2^-96}
   f32__f ∈ {1.382483*2^-96}
 [eva:final-states] Values at end of function test_exp_det:
+  __fc_errno ∈ [--..--]
   a ∈ {1.7094457008275896*2^60}
   b ∈ {1.0826822658929016*2^-3}
   c ∈ {1.0000000000000000}
   d ∈ {1.0000000000000000}
   e ∈ {1.4715177646857693*2^-2}
 [eva:final-states] Values at end of function test_expf_det:
+  __fc_errno ∈ [--..--]
   f32__a ∈ {1.709445*2^60}
   f32__b ∈ {1.082682*2^-3}
   f32__c ∈ {1.000000}
@@ -2706,6 +2742,7 @@
   f32__e ∈ {-0.000000}
   f32__f ∈ {-1.000000}
 [eva:final-states] Values at end of function main:
+  __fc_errno ∈ [--..--]
   __retres ∈ {0}
 [from] Computing for function double_interval
 [from] Done for function double_interval
@@ -2876,8 +2913,10 @@
 [from] Function double_interval:
   \result FROM min; max; nondet
 [from] Function exp:
+  __fc_errno FROM x
   \result FROM x
 [from] Function expf:
+  __fc_errno FROM x
   \result FROM x
 [from] Function floor:
   \result FROM x
@@ -2930,9 +2969,9 @@
 [from] Function test_diff_pow_powf:
   NO EFFECTS
 [from] Function test_exp_det:
-  NO EFFECTS
+  __fc_errno FROM \nothing
 [from] Function test_expf_det:
-  NO EFFECTS
+  __fc_errno FROM \nothing
 [from] Function test_floor:
   NO EFFECTS
 [from] Function test_floor_det:
@@ -2996,6 +3035,7 @@
 [from] Function test_truncf_det:
   NO EFFECTS
 [from] Function main:
+  __fc_errno FROM \nothing
   \result FROM \nothing
 [from] ====== END OF DEPENDENCIES ======
 [inout] Out (internal) for function double_interval:
@@ -3050,11 +3090,11 @@
 [inout] Inputs for function test_diff_pow_powf:
     \nothing
 [inout] Out (internal) for function test_exp_det:
-    a; b; c; d; e
+    __fc_errno; a; b; c; d; e
 [inout] Inputs for function test_exp_det:
     nondet
 [inout] Out (internal) for function test_expf_det:
-    f32__a; f32__b; f32__c; f32__d; f32__e
+    __fc_errno; f32__a; f32__b; f32__c; f32__d; f32__e
 [inout] Inputs for function test_expf_det:
     \nothing
 [inout] Out (internal) for function test_floor:
@@ -3180,10 +3220,11 @@
 [inout] Inputs for function test_truncf_det:
     \nothing
 [inout] Out (internal) for function main:
-    __retres
+    __fc_errno; __retres
 [inout] Inputs for function main:
     nondet; any_double; any_float
 /* Generated by Frama-C */
+#include "errno.h"
 #include "math.h"
 static int volatile nondet;
 static double volatile any_double;
diff --git a/tests/float/oracle/sqrt.0.res.oracle b/tests/float/oracle/sqrt.0.res.oracle
index fecf923ed14..ae53efbab13 100644
--- a/tests/float/oracle/sqrt.0.res.oracle
+++ b/tests/float/oracle/sqrt.0.res.oracle
@@ -14,6 +14,7 @@
 [eva] tests/float/sqrt.c:19: 
   Frama_C_dump_each:
   # Cvalue domain:
+  __fc_errno ∈ [--..--]
   k ∈ UNINITIALIZED
   i ∈ {-0.}
   j ∈ {-0.}
@@ -24,6 +25,7 @@
 [eva] tests/float/sqrt.c:23: 
   Frama_C_dump_each:
   # Cvalue domain:
+  __fc_errno ∈ [--..--]
   k ∈ UNINITIALIZED
   i ∈ {-0.}
   j ∈ {-0.}
diff --git a/tests/float/oracle/sqrt.1.res.oracle b/tests/float/oracle/sqrt.1.res.oracle
index 6478e72b4c4..75d3c6a1725 100644
--- a/tests/float/oracle/sqrt.1.res.oracle
+++ b/tests/float/oracle/sqrt.1.res.oracle
@@ -14,6 +14,7 @@
 [eva] tests/float/sqrt.c:19: 
   Frama_C_dump_each:
   # Cvalue domain:
+  __fc_errno ∈ [--..--]
   k ∈ UNINITIALIZED
   i ∈ {-0.}
   j ∈ {-0.}
@@ -24,6 +25,7 @@
 [eva] tests/float/sqrt.c:23: 
   Frama_C_dump_each:
   # Cvalue domain:
+  __fc_errno ∈ [--..--]
   k ∈ UNINITIALIZED
   i ∈ {-0.}
   j ∈ {-0.}
-- 
GitLab