Skip to content
Snippets Groups Projects
Commit c22c8c50 authored by Basile Desloges's avatar Basile Desloges
Browse files

[eacsl] Update `__e_acsl_assert()` to use a structure holding all the data

parent f70e887d
No related branches found
No related tags found
No related merge requests found
...@@ -36,31 +36,38 @@ int eacsl_runtime_sound_verdict = 1; ...@@ -36,31 +36,38 @@ int eacsl_runtime_sound_verdict = 1;
#ifndef E_ACSL_EXTERNAL_ASSERT #ifndef E_ACSL_EXTERNAL_ASSERT
/*! \brief Default implementation of E-ACSL runtime assertions */ /*! \brief Default implementation of E-ACSL runtime assertions */
void eacsl_runtime_assert(int predicate, int blocking, const char *kind, void eacsl_runtime_assert(int predicate, eacsl_assert_data_t *data) {
const char *fct, const char *pred_txt,
const char *file, int line) {
if (eacsl_runtime_sound_verdict) { if (eacsl_runtime_sound_verdict) {
if (!predicate) { if (!predicate) {
// clang-format off
STDERR("%s: In function '%s'\n" STDERR("%s: In function '%s'\n"
"%s:%d: Error: %s failed:\n" "%s:%d: Error: %s failed:\n"
"\tThe failing predicate is:\n" "\tThe failing predicate is:\n"
"\t%s.\n", "\t%s.\n",
file, fct, file, line, kind, pred_txt); data->file, data->fct,
if (blocking) { data->file, data->line, data->kind,
data->pred_txt);
// clang-format on
if (data->blocking) {
# ifndef E_ACSL_NO_ASSERT_FAIL /* Do fail on assertions */ # ifndef E_ACSL_NO_ASSERT_FAIL /* Do fail on assertions */
# ifdef E_ACSL_FAIL_EXITCODE /* Fail by exit with a given code */ # ifdef E_ACSL_FAIL_EXITCODE /* Fail by exit with a given code */
exit(E_ACSL_FAIL_EXITCODE); exit(E_ACSL_FAIL_EXITCODE);
# else # else
raise_abort(file, line); /* Raise abort signal */ raise_abort(data->file, data->line); /* Raise abort signal */
# endif # endif
# endif # endif
} }
} }
} else } else {
// clang-format off
STDERR("%s: In function '%s'\n" STDERR("%s: In function '%s'\n"
"%s:%d: Warning: no sound verdict for %s (guess: %s).\n" "%s:%d: Warning: no sound verdict for %s (guess: %s).\n"
"\tthe considered predicate is:\n" "\tthe considered predicate is:\n"
"\t%s\n", "\t%s\n",
file, fct, file, line, kind, predicate ? "ok" : "FAIL", pred_txt); data->file, data->fct,
data->file, data->line, data->kind, predicate ? "ok" : "FAIL",
data->pred_txt);
// clang-format on
}
} }
#endif #endif
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "../internals/e_acsl_alias.h" #include "../internals/e_acsl_alias.h"
#define eacsl_runtime_sound_verdict export_alias(sound_verdict) #define eacsl_runtime_sound_verdict export_alias(sound_verdict)
#define eacsl_assert_data_t export_alias(assert_data_t)
#define eacsl_runtime_assert export_alias(assert) #define eacsl_runtime_assert export_alias(assert)
/*! E-ACSL instrumentation automatically sets this global to 0 if its verdict /*! E-ACSL instrumentation automatically sets this global to 0 if its verdict
...@@ -39,26 +40,38 @@ ...@@ -39,26 +40,38 @@
For arithmetic properties, the verdict is always sound (?). */ For arithmetic properties, the verdict is always sound (?). */
extern int __attribute__((FC_BUILTIN)) eacsl_runtime_sound_verdict; extern int __attribute__((FC_BUILTIN)) eacsl_runtime_sound_verdict;
/*! Data holding context information for E-ACSL assertions. */
typedef struct eacsl_assert_data_t {
/*! integer representing if the assertion is blocking or not */
int blocking;
/*! C string representing a kind of annotation (e.g., "Assertion") */
const char *kind;
/*! stringified predicate */
const char *pred_txt;
/*! un-instrumented file of predicate placement */
const char *file;
/*! function of predicate placement in the un-instrumented file */
const char *fct;
/*! line of predicate placement in the un-instrumented file */
int line;
/*! values contributing to the predicate */
void *values;
} __attribute__((__FC_BUILTIN__)) eacsl_assert_data_t;
/*! \brief Runtime assertion verifying a given predicate /*! \brief Runtime assertion verifying a given predicate
* \param pred integer code of a predicate * \param predicate integer code of a predicate
* \param blocking integer representing if the assertion is blocking or not * \param data context data for the predicate. */
* \param kind C string representing a kind of annotation (e.g., "Assertion") /*@ requires \valid_read(data) && \initialized(data);
* \param fct @ assigns \nothing;
* \param pred_txt stringified predicate
* \param file un-instrumented file of predicate placement
* \param line line of predicate placement in the un-instrumented file */
/*@ assigns \nothing;
@ behavior blocking: @ behavior blocking:
@ assumes blocking != 0; @ assumes data->blocking != 0;
@ requires pred != 0; @ requires predicate != 0;
@ behavior non_blocking: @ behavior non_blocking:
@ assumes blocking == 0; @ assumes data->blocking == 0;
@ check requires pred != 0; @ check requires predicate != 0;
@ complete behaviors; @ complete behaviors;
@ disjoint behaviors; */ @ disjoint behaviors; */
void eacsl_runtime_assert(int pred, int blocking, const char *kind, void eacsl_runtime_assert(int predicate, eacsl_assert_data_t *data)
const char *fct, const char *pred_txt,
const char *file, int line)
__attribute__((FC_BUILTIN)); __attribute__((FC_BUILTIN));
#endif // E_ACSL_ASSERT_H #endif // E_ACSL_ASSERT_H
...@@ -31,7 +31,10 @@ open Cil_types ...@@ -31,7 +31,10 @@ open Cil_types
type data = { type data = {
(** Indicates if some data have been registered in the context or not. *) (** Indicates if some data have been registered in the context or not. *)
data_registered: bool; data_registered: bool;
(* FIXME: fields added to hold information about the C variable in MR !3288 *) (** [varinfo] representing the C variable for the assertion data. *)
data_vi: varinfo;
(** [exp] representing a pointer to the C variable for the assertion data. *)
data_ptr: exp;
} }
(** External type representing the assertion context. Either [Some data] if we (** External type representing the assertion context. Either [Some data] if we
...@@ -40,10 +43,32 @@ type t = data option ...@@ -40,10 +43,32 @@ type t = data option
let no_data = None let no_data = None
(** C type for the [assert_data_t] structure. *)
let assert_data_ctyp_lazy =
lazy (Globals.Types.find_type
Logic_typing.Typedef (Functions.RTL.mk_api_name "assert_data_t"))
let empty ~loc kf env = let empty ~loc kf env =
(* FIXME: C variable created in MR !3288 *) let assert_data_cty = Lazy.force assert_data_ctyp_lazy in
ignore (loc, kf); let data_vi, _, env =
let data = { data_registered = false } in Env.new_var
~loc
~name:"assert_data"
env
kf
None
assert_data_cty
(fun vi _ ->
[ Smart_stmt.struct_local_init
~loc
vi
[ "values", Smart_exp.null ~loc ] ])
in
let data =
{ data_registered = false;
data_vi;
data_ptr = Cil.mkAddrOfVi data_vi }
in
Some data , env Some data , env
let with_data_from ~loc kf env from = let with_data_from ~loc kf env from =
...@@ -75,8 +100,8 @@ let register ~loc kf env ?(force=false) name e adata = ...@@ -75,8 +100,8 @@ let register ~loc kf env ?(force=false) name e adata =
The registration can be forced for expressions like [sizeof(int)] for The registration can be forced for expressions like [sizeof(int)] for
instance that are [Const] values but not directly known. *) instance that are [Const] values but not directly known. *)
Some adata, env Some adata, env
| Some _adata, _ -> | Some adata, _ ->
let adata = { data_registered = true } in let adata = { adata with data_registered = true } in
(* FIXME: value registered to [adata] in MR !3288 *) (* FIXME: value registered to [adata] in MR !3288 *)
ignore (loc, kf, env, name); ignore (loc, kf, env, name);
Some adata, env Some adata, env
...@@ -108,7 +133,17 @@ let kind_to_string loc k = ...@@ -108,7 +133,17 @@ let kind_to_string loc k =
| Smart_stmt.Variant -> "Variant" | Smart_stmt.Variant -> "Variant"
| Smart_stmt.RTE -> "RTE") | Smart_stmt.RTE -> "RTE")
let runtime_check_with_msg ~adata ~loc msg ~pred_kind kind kf env e = let runtime_check_with_msg ~adata ~loc msg ~pred_kind kind kf env predicate_e =
let env = Env.push env in
let data_ptr, data_vi, env =
match adata with
| Some { data_ptr; data_vi } ->
data_ptr, data_vi, env
| None ->
let adata, env = empty ~loc kf env in
let adata = Option.get adata in
adata.data_ptr, adata.data_vi, env
in
let blocking = let blocking =
match pred_kind with match pred_kind with
| Assert -> Cil.one ~loc | Assert -> Cil.one ~loc
...@@ -116,23 +151,33 @@ let runtime_check_with_msg ~adata ~loc msg ~pred_kind kind kf env e = ...@@ -116,23 +151,33 @@ let runtime_check_with_msg ~adata ~loc msg ~pred_kind kind kf env e =
| Admit -> | Admit ->
Options.fatal "No runtime check should be generated for 'admit' clauses" Options.fatal "No runtime check should be generated for 'admit' clauses"
in in
let kind = kind_to_string loc kind in
let pred_txt = Cil.mkString ~loc msg in
let start_pos = fst loc in let start_pos = fst loc in
let file = start_pos.Filepath.pos_path in let file =
let line = start_pos.Filepath.pos_lnum in Cil.mkString
(* FIXME: [adata] support in MR !3288 *) ~loc
ignore adata; (Filepath.Normalized.to_pretty_string start_pos.Filepath.pos_path)
let stmt = in
Smart_stmt.rtl_call ~loc let fct = Cil.mkString ~loc (Functions.RTL.get_original_name kf) in
"assert" let line = Cil.integer ~loc start_pos.Filepath.pos_lnum in
[ e; let stmts =
blocking; [ Smart_stmt.rtl_call ~loc "assert" [ predicate_e; data_ptr ];
kind_to_string loc kind; Smart_stmt.assigns_field ~loc data_vi "line" line;
Cil.mkString ~loc (Functions.RTL.get_original_name kf); Smart_stmt.assigns_field ~loc data_vi "fct" fct;
Cil.mkString ~loc msg; Smart_stmt.assigns_field ~loc data_vi "file" file;
Cil.mkString ~loc (Filepath.Normalized.to_pretty_string file); Smart_stmt.assigns_field ~loc data_vi "pred_txt" pred_txt;
Cil.integer loc line ] Smart_stmt.assigns_field ~loc data_vi "kind" kind;
Smart_stmt.assigns_field ~loc data_vi "blocking" blocking ]
in
let block, env =
Env.pop_and_get
env
(Smart_stmt.block_from_stmts (List.rev stmts))
~global_clear:false
Env.Middle
in in
stmt, env Smart_stmt.block_stmt block, env
let runtime_check ~adata ~pred_kind kind kf env e p = let runtime_check ~adata ~pred_kind kind kf env e p =
let loc = p.pred_loc in let loc = p.pred_loc in
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment