From dbd447ab4fcda92ddc7ee13999111e5d68d8d0e5 Mon Sep 17 00:00:00 2001 From: Julien Signoles <julien.signoles@cea.fr> Date: Tue, 23 Oct 2018 18:51:13 +0200 Subject: [PATCH] do not monitor variables with incomplete types (fix bts #2406) --- src/plugins/e-acsl/doc/Changelog | 2 + src/plugins/e-acsl/doc/userman/changes.tex | 4 +- .../e-acsl/doc/userman/limitations.tex | 13 ++- src/plugins/e-acsl/mmodel_analysis.ml | 83 ++++++++++++++----- src/plugins/e-acsl/tests/bts/bts2406.c | 13 +++ .../tests/bts/oracle/bts2406.res.oracle | 5 ++ .../e-acsl/tests/bts/oracle/gen_bts2406.c | 44 ++++++++++ 7 files changed, 139 insertions(+), 25 deletions(-) create mode 100644 src/plugins/e-acsl/tests/bts/bts2406.c create mode 100644 src/plugins/e-acsl/tests/bts/oracle/bts2406.res.oracle create mode 100644 src/plugins/e-acsl/tests/bts/oracle/gen_bts2406.c diff --git a/src/plugins/e-acsl/doc/Changelog b/src/plugins/e-acsl/doc/Changelog index db8c7d4638d..d9bb44c7d8d 100644 --- a/src/plugins/e-acsl/doc/Changelog +++ b/src/plugins/e-acsl/doc/Changelog @@ -19,6 +19,8 @@ # configure configure ############################################################################### +-* E-ACSL [2018/10/23] Fix bug #2406 about monitoring of variables + with incomplete types. -* E-ACSL [2018/10/04] Fix bug #2386 about incorrect typing when performing pointer subtraction. -* E-ACSL [2018/10/04] Support for \at on purely logic variables. diff --git a/src/plugins/e-acsl/doc/userman/changes.tex b/src/plugins/e-acsl/doc/userman/changes.tex index b4969d93baf..5ffb0f549ca 100644 --- a/src/plugins/e-acsl/doc/userman/changes.tex +++ b/src/plugins/e-acsl/doc/userman/changes.tex @@ -6,13 +6,15 @@ release. First we list changes of the last release. \section*{E-ACSL \eacslversion} \begin{itemize} -\item \textbf{Introduction}: Improve a bit and reference related papers. +\item \textbf{Introduction}: Improve a bit and reference new related papers. \item \textbf{What the Plug-in Provides}: Highlight that the memory analysis is not yet robust. \item \textbf{What the Plug-in Provides}: Highlight the importance of \textbf{-e-acsl-prepare}. \item \textbf{Known Limitations}: Replace section ``Limitations of E-ACSL Monitoring Libraries'' by the new section ``Supported Systems''. +\item \textbf{Known Limitations}: Add limitation about monitoring of variables + with incomplete types. \end{itemize} \section*{E-ACSL Chlorine-20180501} diff --git a/src/plugins/e-acsl/doc/userman/limitations.tex b/src/plugins/e-acsl/doc/userman/limitations.tex index 24a3aced3ba..ec0d86ba6c2 100644 --- a/src/plugins/e-acsl/doc/userman/limitations.tex +++ b/src/plugins/e-acsl/doc/userman/limitations.tex @@ -143,8 +143,8 @@ instrumented code (linked against this main) could print some warnings from the \label{sec:limits:no-code} \index{Function!Undefined} -The instrumentation in the generated program is partial for a program $p$ if and -only if $p$ contains a memory-related annotation $a$ and an undefined function +The instrumentation in the generated program is partial for a program $p$ if $p$ +contains a memory-related annotation $a$ and an undefined function $f$ such that: \begin{itemize} \item either $f$ has an (even indirect) effect on a left-value occurring in $a$; @@ -155,6 +155,15 @@ A violation of such an annotation $a$ is undetected. There is no workaround yet. Also, the option \optionuse{-}{e-acsl-check} does not verify the annotations of undefined functions. There is also no workaround yet. +\subsection{Incomplete Types} +\index{Type!Incomplete} + +The instrumentation in the generated program is partial for a program $p$ if $p$ +contains a memory-related annotation $a$ and a variable $v$ with an incomplete +type definition such that $a$ depends on $v$ (even indirectly). + +A violation of such an annotation $a$ is undetected. There is no workaround yet. + \section{Recursive Functions} \index{Function!Recursive} diff --git a/src/plugins/e-acsl/mmodel_analysis.ml b/src/plugins/e-acsl/mmodel_analysis.ml index 1c3f78ee9e6..e5c3136060f 100644 --- a/src/plugins/e-acsl/mmodel_analysis.ml +++ b/src/plugins/e-acsl/mmodel_analysis.ml @@ -25,6 +25,15 @@ open Cil_datatype module Dataflow = Dataflow2 +let must_never_monitor vi = + (* extern ghost variables are usually used (by the Frama-C libc) to + represent some internal invisible states in ACSL specifications. They do + not correspond to something concrete *) + (vi.vghost && vi.vstorage = Extern) + || + (* incomplete types cannot be properly monitored. See BTS #2406. *) + not (Cil.isCompleteType vi.vtype) + (* ********************************************************************** *) (* Backward dataflow analysis to compute a sound over-approximation of what left-values must be tracked by the memory model library *) @@ -225,16 +234,20 @@ module rec Transfer let extend_to_expr always state lhost e = let add_vi state vi = - if is_ptr_or_array_exp e && (always || Varinfo.Hptset.mem vi state) then + if is_ptr_or_array_exp e && (always || Varinfo.Hptset.mem vi state) + then begin match base_addr e with | None -> state | Some vi_e -> - Options.feedback ~level:4 ~dkey - "monitoring %a from %a." - Printer.pp_varinfo vi_e - Printer.pp_lval (lhost, NoOffset); - Varinfo.Hptset.add vi_e state - else + if must_never_monitor vi then state + else begin + Options.feedback ~level:4 ~dkey + "monitoring %a from %a." + Printer.pp_varinfo vi_e + Printer.pp_lval (lhost, NoOffset); + Varinfo.Hptset.add vi_e state + end + end else state in match lhost with @@ -721,44 +734,70 @@ consolidated_must_model_vi vi false *) -let rec must_model_lval bhv ?kf ?stmt = function - | Var vi, _ -> must_model_vi bhv ?kf ?stmt vi - | Mem e, _ -> must_model_exp bhv ?kf ?stmt e +let rec apply_on_vi_base_from_lval f bhv ?kf ?stmt = function + | Var vi, _ -> f bhv ?kf ?stmt vi + | Mem e, _ -> apply_on_vi_base_from_exp f bhv ?kf ?stmt e -and must_model_exp bhv ?kf ?stmt e = match e.enode with +and apply_on_vi_base_from_exp f bhv ?kf ?stmt e = match e.enode with | Lval lv | AddrOf lv | StartOf lv -> - must_model_lval bhv ?kf ?stmt lv + apply_on_vi_base_from_lval f bhv ?kf ?stmt lv | BinOp((PlusPI | IndexPI | MinusPI), e1, _, _) -> - must_model_exp bhv ?kf ?stmt e1 + apply_on_vi_base_from_exp f bhv ?kf ?stmt e1 | BinOp(MinusPP, e1, e2, _) -> - must_model_exp bhv ?kf ?stmt e1 || must_model_exp bhv ?kf ?stmt e2 - | Info(e, _) | CastE(_, e) -> must_model_exp bhv ?kf ?stmt e + apply_on_vi_base_from_exp f bhv ?kf ?stmt e1 + || apply_on_vi_base_from_exp f bhv ?kf ?stmt e2 + | Info(e, _) | CastE(_, e) -> apply_on_vi_base_from_exp f bhv ?kf ?stmt e | BinOp((PlusA | MinusA | Mult | Div | Mod |Shiftlt | Shiftrt | Lt | Gt | Le | Ge | Eq | Ne | BAnd | BXor | BOr | LAnd | LOr), _, _, _) | Const _ -> (* possible in case of static address *) false | UnOp _ | SizeOf _ | SizeOfE _ | SizeOfStr _ | AlignOf _ | AlignOfE _ -> Options.fatal "[pre_analysis] unexpected expression %a" Exp.pretty e +let must_model_lval = apply_on_vi_base_from_lval must_model_vi +let must_model_exp = apply_on_vi_base_from_exp must_model_vi + +let must_never_monitor_lval bhv ?kf ?stmt lv = + apply_on_vi_base_from_lval + (fun _bhv ?kf:_ ?stmt:_ vi -> must_never_monitor vi) + bhv + ?kf + ?stmt + lv + +let must_never_monitor_exp bhv ?kf ?stmt lv = + apply_on_vi_base_from_exp + (fun _bhv ?kf:_ ?stmt:_ vi -> must_never_monitor vi) + bhv + ?kf + ?stmt + lv + (* ************************************************************************** *) (** {1 Public API} *) (* ************************************************************************** *) let must_model_vi ?bhv ?kf ?stmt vi = - not (vi.vghost && vi.vstorage = Extern) + not (must_never_monitor vi) && (Options.Full_mmodel.get () || Error.generic_handle (must_model_vi bhv ?kf ?stmt) false vi) let must_model_lval ?bhv ?kf ?stmt lv = - Options.Full_mmodel.get () - || Error.generic_handle (must_model_lval bhv ?kf ?stmt) false lv + not (must_never_monitor_lval bhv ?kf ?stmt lv) + && + (Options.Full_mmodel.get () + || Error.generic_handle (must_model_lval bhv ?kf ?stmt) false lv) let must_model_exp ?bhv ?kf ?stmt exp = - Options.Full_mmodel.get () - || Error.generic_handle (must_model_exp bhv ?kf ?stmt) false exp + not (must_never_monitor_exp bhv ?kf ?stmt exp) + && + (Options.Full_mmodel.get () + || Error.generic_handle (must_model_exp bhv ?kf ?stmt) false exp) -let use_model () = not (Env.is_empty ()) || Options.Full_mmodel.get () || - Env.has_heap_allocations () +let use_model () = + not (Env.is_empty ()) + || Options.Full_mmodel.get () + || Env.has_heap_allocations () (* Local Variables: diff --git a/src/plugins/e-acsl/tests/bts/bts2406.c b/src/plugins/e-acsl/tests/bts/bts2406.c new file mode 100644 index 00000000000..30c52958e42 --- /dev/null +++ b/src/plugins/e-acsl/tests/bts/bts2406.c @@ -0,0 +1,13 @@ +/* run.config + COMMENT: bts #2306, do not monitor incomplete types +*/ + +const char tab[]; /* not monitored */ +char t[10]; /* monitored */ + +int main(void) { + char *p = tab; /* monitored */ + /*@ assert !\valid(p+(0..9)); */ + /*@ assert \valid(t+(0..9)); */ + return 0; +} diff --git a/src/plugins/e-acsl/tests/bts/oracle/bts2406.res.oracle b/src/plugins/e-acsl/tests/bts/oracle/bts2406.res.oracle new file mode 100644 index 00000000000..7204dfeb385 --- /dev/null +++ b/src/plugins/e-acsl/tests/bts/oracle/bts2406.res.oracle @@ -0,0 +1,5 @@ +[e-acsl] beginning translation. +[e-acsl] translation done in project "e-acsl". +[eva] tests/bts/bts2406.c:5: Warning: + during initialization of variable 'tab', size of type 'char const []' + cannot be computed (Size of array without number of elements.) diff --git a/src/plugins/e-acsl/tests/bts/oracle/gen_bts2406.c b/src/plugins/e-acsl/tests/bts/oracle/gen_bts2406.c new file mode 100644 index 00000000000..cc8337e0e2e --- /dev/null +++ b/src/plugins/e-acsl/tests/bts/oracle/gen_bts2406.c @@ -0,0 +1,44 @@ +/* Generated by Frama-C */ +#include "stdio.h" +#include "stdlib.h" +char const tab[]; +char t[10]; +void __e_acsl_globals_init(void) +{ + __e_acsl_store_block((void *)(t),(size_t)10); + __e_acsl_full_init((void *)(& t)); + return; +} + +int main(void) +{ + int __retres; + __e_acsl_memory_init((int *)0,(char ***)0,(size_t)8); + __e_acsl_globals_init(); + char *p = (char *)(tab); + __e_acsl_store_block((void *)(& p),(size_t)8); + __e_acsl_full_init((void *)(& p)); + /*@ assert ¬\valid(p + (0 .. 9)); */ + { + int __gen_e_acsl_valid; + __gen_e_acsl_valid = __e_acsl_valid((void *)(p + 1 * 0),(size_t)9, + (void *)p,(void *)(& p)); + __e_acsl_assert(! __gen_e_acsl_valid,(char *)"Assertion",(char *)"main", + (char *)"!\\valid(p + (0 .. 9))",10); + } + /*@ assert \valid(&t[0 .. 9]); */ + { + int __gen_e_acsl_valid_2; + __gen_e_acsl_valid_2 = __e_acsl_valid((void *)(& t + 1 * 0),(size_t)9, + (void *)(& t),(void *)0); + __e_acsl_assert(__gen_e_acsl_valid_2,(char *)"Assertion",(char *)"main", + (char *)"\\valid(&t[0 .. 9])",11); + } + __retres = 0; + __e_acsl_delete_block((void *)(t)); + __e_acsl_delete_block((void *)(& p)); + __e_acsl_memory_clean(); + return __retres; +} + + -- GitLab