From d594f758cdbe217359a421167e4e22ab2bb829de Mon Sep 17 00:00:00 2001
From: Jan Rochel <jan.rochel@cea.fr>
Date: Tue, 3 Sep 2024 11:27:44 +0200
Subject: [PATCH] [e-acsl] correctly handle negative integers in rational
 context

This fixes the pathological example from the previous commit by
adding missing code to Gmp.Q.normalize_str that handles signs.
---
 src/plugins/e-acsl/doc/Changelog              |  1 +
 src/plugins/e-acsl/src/code_generator/gmp.ml  |  3 +
 .../tests/arith/oracle/gen_neg_rte_int.c      | 80 +++++++++++++++++++
 .../tests/arith/oracle/neg_rte_int.res.oracle |  9 +++
 4 files changed, 93 insertions(+)
 create mode 100644 src/plugins/e-acsl/tests/arith/oracle/gen_neg_rte_int.c
 create mode 100644 src/plugins/e-acsl/tests/arith/oracle/neg_rte_int.res.oracle

diff --git a/src/plugins/e-acsl/doc/Changelog b/src/plugins/e-acsl/doc/Changelog
index 912d6e60d54..8a8cf08be9b 100644
--- a/src/plugins/e-acsl/doc/Changelog
+++ b/src/plugins/e-acsl/doc/Changelog
@@ -25,6 +25,7 @@
 Plugin E-ACSL <next-release>
 ###############################################################################
 
+-* E-ACSL       [2024-09-03] handle negative integers generated by RTE
 -* E-ACSL       [2024-08-30] fix typing exception occurring for applications
                 of axiomatically defined premises and logic functions
 -* E-ACSL       [2024-06-20] fix typing of logic functions over rationals
diff --git a/src/plugins/e-acsl/src/code_generator/gmp.ml b/src/plugins/e-acsl/src/code_generator/gmp.ml
index 51d50aaa518..1ac1f29301a 100644
--- a/src/plugins/e-acsl/src/code_generator/gmp.ml
+++ b/src/plugins/e-acsl/src/code_generator/gmp.ml
@@ -290,6 +290,9 @@ module Q = struct
         str
       else
         match String.unsafe_get str i with
+        | '-' when i = 0 ->
+          Bytes.unsafe_set buf i '-';
+          pre str len buf (i + 1)
         | '.' ->
           mid buf len;
           post str len buf (len + 1) (i + 1)
diff --git a/src/plugins/e-acsl/tests/arith/oracle/gen_neg_rte_int.c b/src/plugins/e-acsl/tests/arith/oracle/gen_neg_rte_int.c
new file mode 100644
index 00000000000..f44035f04d8
--- /dev/null
+++ b/src/plugins/e-acsl/tests/arith/oracle/gen_neg_rte_int.c
@@ -0,0 +1,80 @@
+/* Generated by Frama-C */
+#include "pthread.h"
+#include "sched.h"
+#include "signal.h"
+#include "stddef.h"
+#include "stdint.h"
+#include "stdio.h"
+#include "time.h"
+extern  __attribute__((__FC_BUILTIN__)) int __e_acsl_sound_verdict;
+
+char c;
+float f;
+void main(void)
+{
+  __e_acsl_memory_init((int *)0,(char ***)0,8UL);
+  {
+    __e_acsl_mpq_t __gen_e_acsl_;
+    __e_acsl_mpq_t __gen_e_acsl__2;
+    __e_acsl_mpq_t __gen_e_acsl__3;
+    __e_acsl_mpq_t __gen_e_acsl_add;
+    int __gen_e_acsl_lt;
+    __e_acsl_mpq_t __gen_e_acsl__4;
+    int __gen_e_acsl_lt_2;
+    __e_acsl_assert_data_t __gen_e_acsl_assert_data = {.values = (void *)0};
+    __gmpq_init(__gen_e_acsl_);
+    __gmpq_set_str(__gen_e_acsl_,"-129",10);
+    __gmpq_init(__gen_e_acsl__2);
+    __gmpq_set_d(__gen_e_acsl__2,(double)f);
+    __gmpq_init(__gen_e_acsl__3);
+    __gmpq_set_d(__gen_e_acsl__3,0.5);
+    __gmpq_init(__gen_e_acsl_add);
+    __gmpq_add(__gen_e_acsl_add,
+               (__e_acsl_mpq_struct const *)(__gen_e_acsl__2),
+               (__e_acsl_mpq_struct const *)(__gen_e_acsl__3));
+    __gen_e_acsl_lt = __gmpq_cmp((__e_acsl_mpq_struct const *)(__gen_e_acsl_),
+                                 (__e_acsl_mpq_struct const *)(__gen_e_acsl_add));
+    __e_acsl_assert_register_float(& __gen_e_acsl_assert_data,"f",f);
+    __gen_e_acsl_assert_data.blocking = 1;
+    __gen_e_acsl_assert_data.kind = "Assertion";
+    __gen_e_acsl_assert_data.pred_txt = "-129 < (double)f + 0.5";
+    __gen_e_acsl_assert_data.file = "neg_rte_int.c";
+    __gen_e_acsl_assert_data.fct = "main";
+    __gen_e_acsl_assert_data.line = 10;
+    __gen_e_acsl_assert_data.name = "rte/float_to_int";
+    __e_acsl_assert(__gen_e_acsl_lt < 0,& __gen_e_acsl_assert_data);
+    __e_acsl_assert_clean(& __gen_e_acsl_assert_data);
+    __e_acsl_assert_data_t __gen_e_acsl_assert_data_2 =
+      {.values = (void *)0};
+    __gmpq_init(__gen_e_acsl__4);
+    __gmpq_set_str(__gen_e_acsl__4,"128",10);
+    __gen_e_acsl_lt_2 = __gmpq_cmp((__e_acsl_mpq_struct const *)(__gen_e_acsl_add),
+                                   (__e_acsl_mpq_struct const *)(__gen_e_acsl__4));
+    __e_acsl_assert_register_float(& __gen_e_acsl_assert_data_2,"f",f);
+    __gen_e_acsl_assert_data_2.blocking = 1;
+    __gen_e_acsl_assert_data_2.kind = "Assertion";
+    __gen_e_acsl_assert_data_2.pred_txt = "(double)f + 0.5 < 128";
+    __gen_e_acsl_assert_data_2.file = "neg_rte_int.c";
+    __gen_e_acsl_assert_data_2.fct = "main";
+    __gen_e_acsl_assert_data_2.line = 10;
+    __gen_e_acsl_assert_data_2.name = "rte/float_to_int";
+    __e_acsl_assert(__gen_e_acsl_lt_2 < 0,& __gen_e_acsl_assert_data_2);
+    __e_acsl_assert_clean(& __gen_e_acsl_assert_data_2);
+    __gmpq_clear(__gen_e_acsl_);
+    __gmpq_clear(__gen_e_acsl__2);
+    __gmpq_clear(__gen_e_acsl__3);
+    __gmpq_clear(__gen_e_acsl_add);
+    __gmpq_clear(__gen_e_acsl__4);
+  }
+  /*@ assert
+      rte: is_nan_or_infinite:
+        \is_finite(\add_double((double)f, (double)0.5));
+  */
+  /*@ assert rte: float_to_int: (double)f + 0.5 < 128; */
+  /*@ assert rte: float_to_int: -129 < (double)f + 0.5; */
+  c = (char)((double)f + 0.5);
+  __e_acsl_memory_clean();
+  return;
+}
+
+
diff --git a/src/plugins/e-acsl/tests/arith/oracle/neg_rte_int.res.oracle b/src/plugins/e-acsl/tests/arith/oracle/neg_rte_int.res.oracle
new file mode 100644
index 00000000000..59dd7cf1d5e
--- /dev/null
+++ b/src/plugins/e-acsl/tests/arith/oracle/neg_rte_int.res.oracle
@@ -0,0 +1,9 @@
+[e-acsl] beginning translation.
+[e-acsl] neg_rte_int.c:10: Warning: 
+  E-ACSL construct
+  `logic functions or predicates with no definition nor reads clause'
+  is not yet supported.
+  Ignoring annotation.
+[e-acsl] translation done in project "e-acsl".
+[eva:alarm] neg_rte_int.c:10: Warning: 
+  function __e_acsl_assert, behavior blocking: precondition got status unknown.
-- 
GitLab