diff --git a/.Makefile.lint b/.Makefile.lint index 80fb691a8370490eea2a7db9b60c1fae64ab498a..5d2bc8a03c8723836cade9e74cb693dda737f6d5 100644 --- a/.Makefile.lint +++ b/.Makefile.lint @@ -99,8 +99,6 @@ ML_LINT_KO+=src/kernel_services/plugin_entry_points/emitter.ml ML_LINT_KO+=src/kernel_services/plugin_entry_points/emitter.mli ML_LINT_KO+=src/kernel_services/plugin_entry_points/journal.ml ML_LINT_KO+=src/kernel_services/plugin_entry_points/journal.mli -ML_LINT_KO+=src/kernel_services/plugin_entry_points/log.ml -ML_LINT_KO+=src/kernel_services/plugin_entry_points/log.mli ML_LINT_KO+=src/kernel_services/visitors/cabsvisit.ml ML_LINT_KO+=src/kernel_services/visitors/cabsvisit.mli ML_LINT_KO+=src/kernel_services/visitors/visitor.ml @@ -344,10 +342,3 @@ ML_LINT_KO+=src/plugins/variadic/standard.ml ML_LINT_KO+=src/plugins/variadic/translate.ml ML_LINT_KO+=src/plugins/variadic/va_build.ml ML_LINT_KO+=src/plugins/variadic/va_types.mli -ML_LINT_KO+=src/plugins/e-acsl/src/analyses/mmodel_analysis.ml -ML_LINT_KO+=src/plugins/e-acsl/src/analyses/rte.ml -ML_LINT_KO+=src/plugins/e-acsl/src/code_generator/at_with_lscope.ml -ML_LINT_KO+=src/plugins/e-acsl/src/code_generator/at_with_lscope.mli -ML_LINT_KO+=src/plugins/e-acsl/src/code_generator/temporal.ml -ML_LINT_KO+=src/plugins/e-acsl/src/code_generator/temporal.mli - diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 87d65d5591a26341fecf9f5c8e2e77512a365b82..7e14dfd7ff3072248ca5b9b640d5a926663f0df3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -92,6 +92,13 @@ volatile: tags: - nix +metacsl: + stage: tests + script: + - nix/frama-ci.sh build -A meta.tests + tags: + - nix + Security: stage: tests script: diff --git a/Changelog b/Changelog index ca81d8698f74c64ed4d224ea0a0cdaeb0dd06da9..bae7947a32be91e156dd40d0e19c4182b4206104 100644 --- a/Changelog +++ b/Changelog @@ -16,7 +16,11 @@ ################################## Open Source Release <next-release> ################################## - +- Kernel [2020-09-08] Add option -print-cpp-commands, to print the + preprocessing commands used by Frama-C. +- Eva [2020-09-07] Deprecates legacy options aliases -val-* in favor + of option names -eva-*. +-* Slicing [2020-09-07] Better handling of invalid command line options. - Eva [2020-07-27] Improved automatic loop unroll (-eva-auto-loop-unroll option) on loops with several exit conditions, conditions using equality operators, temporary variables introduced by the Frama-C diff --git a/Makefile b/Makefile index 432c0e8363f6b0598675ff68943e6266bc8ea1eb..46cd5d27563136ac7e713e035be6c87b7e319fcb 100644 --- a/Makefile +++ b/Makefile @@ -899,7 +899,6 @@ PLUGIN_CMO:= partitioning/split_strategy domains/domain_mode value_parameters \ domains/cvalue/builtins_watchpoint \ domains/cvalue/builtins_float domains/cvalue/builtins_split \ domains/inout_domain \ - utils/state_import \ legacy/eval_terms legacy/eval_annots \ domains/powerset engine/transfer_logic \ domains/cvalue/cvalue_transfer domains/cvalue/cvalue_init \ @@ -1790,11 +1789,14 @@ lint: $(LINT_TARGET) check-ocp-indent-version: if command -v ocp-indent >/dev/null; then \ - $(eval ocp_version_major := $(shell ocp-indent --version | $(SED) -E "s/^([0-9]+)\.[0-9]+\..*/\1/")) \ - $(eval ocp_version_minor := $(shell ocp-indent --version | $(SED) -E "s/^[0-9]+\.([0-9]+)\..*/\1/")) \ - if [ "$(ocp_version_major)" -lt 1 -o "$(ocp_version_minor)" -lt 7 ]; then \ - echo "error: ocp-indent >=1.7.0 required for linting (got $(ocp_version_major).$(ocp_version_minor))"; \ + if [ -z "$(shell ocp-indent --version)" ]; then echo "warning: ocp-indent returned an empty string, assuming it is the correct version"; \ + else \ + $(eval ocp_version_major := $(shell ocp-indent --version | $(SED) -E "s/^([0-9]+)\.[0-9]+\..*/\1/")) \ + $(eval ocp_version_minor := $(shell ocp-indent --version | $(SED) -E "s/^[0-9]+\.([0-9]+)\..*/\1/")) \ + if [ "$(ocp_version_major)" -lt 1 -o "$(ocp_version_minor)" -lt 7 ]; then \ + echo "error: ocp-indent 1.7.0 required for linting (got $(ocp_version_major).$(ocp_version_minor))"; \ exit 1; \ + fi; \ fi; \ else \ exit 1; \ @@ -2407,12 +2409,9 @@ else DISTRIB_HEADERS:=open-source # for checking that distributed files aren't under proprietary licence. DISTRIB_PROPRIETARY_HEADERS:=$(CEA_PROPRIETARY_HEADERS) -# DISTRIB_TESTS contents files that can be distributed without header checking +# DISTRIB_TESTS contains files that can be distributed without header checking DISTRIB_TESTS:=$(filter-out $(CEA_PROPRIETARY_FILES) ,\ $(DISTRIB_TESTS)) -# DISTRIB_FILES contents files that can be distributed with header checking -DISTRIB_FILES:=$(filter-out $(CEA_PROPRIETARY_FILES) ,\ - $(DISTRIB_FILES)) endif # Set some variables for `headers`target. diff --git a/configure.in b/configure.in index 3f792af4a5f4938a604d93d181bcb4807ebd9999..ba6d68bb09d2cd9c8cd493f16d55164f957ee11c 100644 --- a/configure.in +++ b/configure.in @@ -397,6 +397,31 @@ else HAS_LANDMARKS="no" fi +# Python 3 (for analysis-scripts) +######## + +AC_MSG_CHECKING(for python3) + +PYTHON3_VERSION=$(python3 --version 2>/dev/null || echo "") +if test -z "$PYTHON3_VERSION" ; then + AC_MSG_RESULT(not found. Some non-regression tests will be disabled.) + HAS_PYTHON36="no" +else + AC_MSG_RESULT(found) + AC_MSG_CHECKING(for python3 >= 3.6) + PYTHON3_VERSION=$(echo "$PYTHON3_VERSION" | cut -d' ' -f2-) + case $PYTHON3_VERSION in + 2.*|3.[[0-5]].*) + AC_MSG_RESULT(found $PYTHON3_VERSION (too old); some non-regression tests will be disabled) + HAS_PYTHON36="no" + ;; + *) + AC_MSG_RESULT(ok) + HAS_PYTHON36="yes" + ;; + esac +fi + ############ # Platform # ############ @@ -978,6 +1003,7 @@ AC_SUBST(DEVELOPMENT) AC_SUBST(HAS_APRON) AC_SUBST(HAS_MPFR) AC_SUBST(HAS_LANDMARKS) +AC_SUBST(HAS_PYTHON36) AC_SUBST(LABLGTK_VERSION) AC_SUBST(OCAMLBEST) AC_SUBST(OCAMLVERSION) diff --git a/devel_tools/docker/frama-c.20.0/Dockerfile b/devel_tools/docker/frama-c.20.0/Dockerfile index d73738fb95080d205a3c8a6668c246dbd41ca1a7..66dcd40c0252c89768cc13ce42210595823e1f79 100644 --- a/devel_tools/docker/frama-c.20.0/Dockerfile +++ b/devel_tools/docker/frama-c.20.0/Dockerfile @@ -1,7 +1,11 @@ FROM debian:sid as base -RUN apt update -RUN apt install opam -y +RUN apt-get update && apt-get install -y \ + cvc4 \ + opam \ + z3 \ + && rm -rf /var/lib/apt/lists/* + RUN opam init --disable-sandboxing --compiler=ocaml-base-compiler.4.05.0 -y # "RUN eval $(opam env)" does not work, so we manually set its variables @@ -11,11 +15,10 @@ ENV OCAML_TOPLEVEL_PATH "/root/.opam/ocaml-base-compiler.4.05.0/lib/toplevel" ENV MANPATH "$MANPATH:/root/.opam/ocaml-base-compiler.4.05.0/man" ENV PATH "/root/.opam/ocaml-base-compiler.4.05.0/bin:$PATH" -RUN opam update -y -RUN opam install depext -y +RUN opam update -y && opam install depext -y # Install packages from reference configuration -RUN opam depext --install -y \ +RUN apt-get update && opam update -y && opam depext --install -y --verbose \ alt-ergo.2.0.0 \ apron.20160125 \ conf-graphviz.0.1 \ @@ -26,7 +29,8 @@ RUN opam depext --install -y \ why3.1.2.0 \ yojson.1.7.0 \ zarith.1.9.1 \ - --verbose # intentionally left as last line in this RUN command + && rm -rf /var/lib/apt/lists/* + RUN why3 config --detect-provers # with_source: keep Frama-C sources @@ -47,12 +51,14 @@ RUN cd /root && \ ARG with_test=no RUN if [ "${with_test}" != "no" ]; then \ - opam depext --install -y \ + apt-get update && \ + opam update -y && opam depext --install -y \ conf-python-3.1.0.0 \ conf-time.1 \ --verbose \ && \ - apt install python -y && \ + apt-get install python -y && \ + rm -rf /var/lib/apt/lists/* && \ cd /root/frama-c-* && \ make tests; \ fi diff --git a/devel_tools/docker/frama-c.21.0/Dockerfile b/devel_tools/docker/frama-c.21.0/Dockerfile index 3a615a7bf0f9d87ec211b428dd12891c3ea4c57d..472d6dce9eb0e3f5fc718bc80fee0dba5bb0421c 100644 --- a/devel_tools/docker/frama-c.21.0/Dockerfile +++ b/devel_tools/docker/frama-c.21.0/Dockerfile @@ -1,7 +1,11 @@ FROM debian:sid as base -RUN apt update -RUN apt install opam -y +RUN apt-get update && apt-get install -y \ + cvc4 \ + opam \ + z3 \ + && rm -rf /var/lib/apt/lists/* + RUN opam init --disable-sandboxing --compiler=ocaml-base-compiler.4.07.1 -y # "RUN eval $(opam env)" does not work, so we manually set its variables @@ -11,11 +15,10 @@ ENV OCAML_TOPLEVEL_PATH "/root/.opam/ocaml-base-compiler.4.07.1/lib/toplevel" ENV MANPATH "$MANPATH:/root/.opam/ocaml-base-compiler.4.07.1/man" ENV PATH "/root/.opam/ocaml-base-compiler.4.07.1/bin:$PATH" -RUN opam update -y -RUN opam install depext -y +RUN opam update -y && opam install depext -y # Install packages from reference configuration -RUN opam depext --install -y \ +RUN apt-get update && opam update -y && opam depext --install -y --verbose \ alt-ergo.2.0.0 \ apron.v0.9.12 \ conf-graphviz.0.1 \ @@ -27,7 +30,11 @@ RUN opam depext --install -y \ yojson.1.7.0 \ zarith.1.9.1 \ zmq.5.1.3 \ - --verbose # intentionally left as last line in this RUN command + && rm -rf /var/lib/apt/lists/* + +# Install non-OCaml solvers +RUN apt install z3 cvc4 -y + RUN why3 config --full-config # with_source: keep Frama-C sources @@ -48,11 +55,13 @@ RUN cd /root && \ ARG with_test=no RUN if [ "${with_test}" != "no" ]; then \ - opam depext --install -y \ + apt-get update && \ + opam update -y && opam depext --install -y \ conf-python-3.1.0.0 \ conf-time.1 \ --verbose \ && \ + rm -rf /var/lib/apt/lists/* && \ cd /root/frama-c-* && \ make tests; \ fi diff --git a/devel_tools/docker/frama-c.21.1/Dockerfile b/devel_tools/docker/frama-c.21.1/Dockerfile index 8852ac14805bad7b5862b8b1205a5e667ab8ca8c..c37b6441aa885a8e2bdee5acb507b95443c04338 100644 --- a/devel_tools/docker/frama-c.21.1/Dockerfile +++ b/devel_tools/docker/frama-c.21.1/Dockerfile @@ -1,7 +1,11 @@ FROM debian:sid as base -RUN apt update -RUN apt install opam -y +RUN apt-get update && apt-get install -y \ + cvc4 \ + opam \ + z3 \ + && rm -rf /var/lib/apt/lists/* + RUN opam init --disable-sandboxing --compiler=ocaml-base-compiler.4.07.1 -y # "RUN eval $(opam env)" does not work, so we manually set its variables @@ -11,11 +15,10 @@ ENV OCAML_TOPLEVEL_PATH "/root/.opam/ocaml-base-compiler.4.07.1/lib/toplevel" ENV MANPATH "$MANPATH:/root/.opam/ocaml-base-compiler.4.07.1/man" ENV PATH "/root/.opam/ocaml-base-compiler.4.07.1/bin:$PATH" -RUN opam update -y -RUN opam install depext -y +RUN opam update -y && opam install depext -y # Install packages from reference configuration -RUN opam depext --install -y \ +RUN apt-get update && opam update -y && opam depext --install -y --verbose \ alt-ergo.2.0.0 \ apron.v0.9.12 \ conf-graphviz.0.1 \ @@ -27,7 +30,11 @@ RUN opam depext --install -y \ yojson.1.7.0 \ zarith.1.9.1 \ zmq.5.1.3 \ - --verbose # intentionally left as last line in this RUN command + && rm -rf /var/lib/apt/lists/* + +# Install non-OCaml solvers +RUN apt install z3 cvc4 -y + RUN why3 config --full-config # with_source: keep Frama-C sources @@ -48,11 +55,13 @@ RUN cd /root && \ ARG with_test=no RUN if [ "${with_test}" != "no" ]; then \ - opam depext --install -y \ + apt-get update && \ + opam update -y && opam depext --install -y \ conf-python-3.1.0.0 \ conf-time.1 \ --verbose \ && \ + rm -rf /var/lib/apt/lists/* && \ cd /root/frama-c-* && \ make tests; \ fi diff --git a/devel_tools/docker/frama-c.dev/Dockerfile b/devel_tools/docker/frama-c.dev/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..aa819b0a6617f4d3396392fcb00153e7327d5d52 --- /dev/null +++ b/devel_tools/docker/frama-c.dev/Dockerfile @@ -0,0 +1,65 @@ +FROM debian:sid as base + +RUN apt-get update && apt-get install -y \ + cvc4 \ + opam \ + z3 \ + && rm -rf /var/lib/apt/lists/* + +RUN opam init --disable-sandboxing --compiler=ocaml-base-compiler.4.08.1 -y + +# "RUN eval $(opam env)" does not work, so we manually set its variables +ENV OPAM_SWITCH_PREFIX "/root/.opam/ocaml-base-compiler.4.08.1" +ENV CAML_LD_LIBRARY_PATH "/root/.opam/ocaml-base-compiler.4.08.1/lib/stublibs:/root/.opam/ocaml-base-compiler.4.08.1/lib/ocaml/stublibs:/root/.opam/ocaml-base-compiler.4.08.1/lib/ocaml" +ENV OCAML_TOPLEVEL_PATH "/root/.opam/ocaml-base-compiler.4.08.1/lib/toplevel" +ENV MANPATH "$MANPATH:/root/.opam/ocaml-base-compiler.4.08.1/man" +ENV PATH "/root/.opam/ocaml-base-compiler.4.08.1/bin:$PATH" + +RUN opam update -y && opam install depext -y + +# Install packages from reference configuration +RUN apt-get update && opam update -y && opam depext --install -y --verbose \ + alt-ergo.2.0.0 \ + apron.v0.9.12 \ + conf-graphviz.0.1 \ + mlgmpidl.1.2.12 \ + ocamlfind.1.8.1 \ + ocamlgraph.1.8.8 \ + ppx_deriving_yojson.3.5.2 \ + why3.1.3.1 \ + yojson.1.7.0 \ + zarith.1.9.1 \ + zmq.5.1.3 \ + && rm -rf /var/lib/apt/lists/* + +# Install non-OCaml solvers +RUN apt install z3 cvc4 -y + +RUN why3 config --full-config + +# with_source: keep Frama-C sources +ARG with_source=no + +RUN cd /root && \ + git clone https://git.frama-c.com/pub/frama-c.git && \ + (cd frama-c && \ + autoconf && ./configure --disable-gui && \ + make -j && \ + make install \ + ) && \ + [ "${with_source}" != "no" ] || rm -rf frama-c + +# with_test: run Frama-C tests; requires "with_source=yes" +ARG with_test=no + +RUN if [ "${with_test}" != "no" ]; then \ + apt-get update && \ + opam update -y && opam depext --install -y \ + conf-python-3.1.0.0 \ + conf-time.1 \ + --verbose \ + && \ + rm -rf /var/lib/apt/lists/* && \ + cd /root/frama-c && \ + make tests; \ + fi diff --git a/doc/userman/user-changes.tex b/doc/userman/user-changes.tex index a688b58cb2e19ef05641b190138dbc5aea7024ff..ae1a9e54c797c1016e3d0b73212eb9ee38fc08c8 100644 --- a/doc/userman/user-changes.tex +++ b/doc/userman/user-changes.tex @@ -5,6 +5,13 @@ release. First we list changes of the last release. \section*{\nextframacversion} +\begin{itemize} +\item \textbf{Preparing the Sources:} added option + \texttt{-print-cpp-commands}. +\item \textbf{Reports:} add section about SARIF output + (via \textsf{Markdown Report}). +\end{itemize} + \section*{21.0 (Scandium)} \begin{itemize} diff --git a/doc/userman/user-report.tex b/doc/userman/user-report.tex index 79f1b91be3eda2f29617b92dab883e24eee62d44..10effa4444db6d37d5e5e03b8720b6b696cc98a3 100644 --- a/doc/userman/user-report.tex +++ b/doc/userman/user-report.tex @@ -19,6 +19,13 @@ It provides the following features, which we detail in turn: \item Make Frama-C exit with a non-null status code on some classified warning or error. \end{itemize} +\FramaC has recently earned the ability to output data in the SARIF% +\footnote{Static Analysis Results Interchange Format, +\url{https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=sarif}} format. +This is performed by the \textsf{Markdown Report} plug-in, described in +section~\ref{sarif}. + + %% -------------------------------------------------------------------------- %% --- Textual Report %% -------------------------------------------------------------------------- @@ -245,3 +252,38 @@ each one following the format given in Figure~\ref{report-classified-event}. warnings (default is: \verb+'REVIEW'+) \end{description} +\section{SARIF Output via the Markdown Report Plug-in}\label{sarif} + +SARIF is a JSON-based standard output format for static analysis results. +It is currently supported by \FramaC in its version 2.1.0. +Some IDEs, such as Visual Code, contain plug-ins which allow importing SARIF +reports. A few Microsoft tools and libraries related to SARIF are available +at \url{https://sarifweb.azurewebsites.net/}. Microsoft also publishes +command-line tools for SARIF, made available via NPM packages and .Net Core +applications. + +\subsection{Prerequisites} + +SARIF output is produced by the \textsf{Markdown Report} (MdR) plug-in. +The plug-in is distributed with \FramaC, but it depends on optional +features, namely the \texttt{opam} package \texttt{ppx\_deriving\_yojson}, +so it may not be available in every \FramaC installation. + +When installing \FramaC via opam, include the optional dependency +\texttt{ppx\_deriving\_yojson} to ensure MdR will be available. +Note that MdR has other features and output formats, which are not described +here. + +\subsection{Generating a SARIF Report} + +To enable generation of a SARIF report, use option \texttt{-mdr-gen sarif}. +It will produce a JSON file (by default, \texttt{report.sarif}) with an entry +for each ACSL property. + +You can change the output file name with option \texttt{-mdr-out <f>}. + +Note that there are no filtering options in the SARIF output; it is up to the +tools importing the file to decide which information to sort, filter, and +display. + +For more details about \textsf{Markdown Report}, use option \texttt{-mdr-help.} diff --git a/doc/userman/user-sources.tex b/doc/userman/user-sources.tex index 030d362f6f863016ab4cc3de58ce887afb9b8f61..0bb8b4360ed20e101419d6464d87e3603f151742 100644 --- a/doc/userman/user-sources.tex +++ b/doc/userman/user-sources.tex @@ -29,34 +29,38 @@ in the figure. Note that some plug-ins, such as \textsf{Variadic} (described in chapter~\ref{user-variadic}), perform further AST transformations before most analyses are run. -\section{Pre-processing the Source Files}\label{sec:preprocessing} +\section{Preprocessing the Source Files}\label{sec:preprocessing} The list of files to analyze must be provided on the command line, or chosen interactively in the GUI. Files with the suffix -{\tt .i} are assumed to be already pre-processed \C files. \FramaC -pre-processes the other files with the following command. +{\tt .i} are assumed to be already preprocessed \C files. \FramaC +preprocesses {\tt .c} and {\tt .h} files with the following basic command: \begin{shell} \$ gcc -C -E -I . \end{shell} +Plus some architecture-dependent flags. The {\em exact} preprocessing command +line can be obtained via options \texttt{-kernel-msg-key pp} and +\optiondef{-}{print-cpp-commands} (the latter exits \FramaC after printing). Option \optiondef{-}{cpp-extra-args} can be used to add arguments to the -default pre-processing command, typically via the inclusion of defines +default preprocessing command, typically via the inclusion of defines (\texttt{-D} switches) and header directories (\texttt{-I} switches), as in \texttt{-cpp-extra-args="-DDEBUG -DARCH=ia32 -I./headers"}. You can also add arguments on a per-file basis, using option \optiondef{-}{cpp-extra-args-per-file}. -If you need to, you can also {\em replace} the pre-processing command +If you need to, you can also {\em replace} the preprocessing command entirely with option \optiondef{-}{cpp-command}. Placeholders (see below) can be used for advanced commands. -If no placeholders are used, the pre-processor is invoked in the +If no placeholders are used, the preprocessor is invoked in the following way. \begin{commands} -\texttt{<cmd> <args> -o <output file> <input file>} +\texttt{<cmd> <args> <input file> -o <output file>} \end{commands} -In this command, \texttt{<output file>} is chosen by \FramaC while -\texttt{<input file>} is one of the filenames provided by the user. +In this command, \texttt{<output file>} is a temporary filename chosen by +\FramaC while \texttt{<input file>} is one of the filenames provided by the +user. For commands which do not follow this pattern, it is also possible to use the following placeholders: @@ -103,29 +107,29 @@ are ignored. Also note that the use of the database simply adds flags be specified by the user. In all of the above cases, -\acsl annotations are pre-processed by default (option \optiondef{-}{pp-annot} -is set by default). Unless a custom pre-processor is specified +\acsl annotations are preprocessed by default (option \optiondef{-}{pp-annot} +is set by default). Unless a custom preprocessor is specified (via \optionuse{-}{cpp-frama-c-compliant}), \FramaC considers that \gcc is -installed and uses it as pre-processor. -If you do \emph{not} want annotations to be pre-processed, you need to pass +installed and uses it as preprocessor. +If you do \emph{not} want annotations to be preprocessed, you need to pass option \texttt{-no-pp-annot} to \FramaC. Note that some headers in the standard C library provided with \FramaC (described below) use such annotations, therefore it might be necessary to disable inclusion of such headers. -Also note that ACSL annotations are pre-processed separately from the C +Also note that ACSL annotations are preprocessed separately from the C code in a second pass, and that arguments given as \texttt{-cpp-extra-args} are -\emph{not} given to the second pass of pre-processing. Instead, +\emph{not} given to the second pass of preprocessing. Instead, \texttt{-pp-annot} relies on the ability of \gcc to output all macro definitions (including those given with \texttt{-D}) in the -pre-processed file. In particular, \texttt{-cpp-extra-args} must be +preprocessed file. In particular, \texttt{-cpp-extra-args} must be used if you are including header files who behave differently depending on the number of times they are included. In addition, files having the suffix \texttt{.ci} will be considered as needing preprocessing for ACSL annotations only. Those files may contain -\texttt{\#define} directives and annotations are pre-processed as explained in +\texttt{\#define} directives and annotations are preprocessed as explained in the previous paragraph. This allows to have macros in ACSL annotations while -using a non-GNU-like pre-processor. +using a non-GNU-like preprocessor. \begin{important} An experimental, incomplete, C standard library is bundled with \FramaC and installed @@ -143,7 +147,7 @@ using a non-GNU-like pre-processor. \section{Merging the Source Code files} -After pre-processing, \FramaC parses, type-checks and links the source +After preprocessing, \FramaC parses, type-checks and links the source code. It also performs these operations for the \acsl annotations optionally present in the program. Together, these steps form the \emph{merging} phase of the creation of an analysis project. @@ -347,7 +351,7 @@ supported are typedefs redefinition. a certain number of C macros. They are summarized below. \begin{description} -\item \textttdef{\_\_FRAMAC\_\_}: defined to 1 during pre-processing by \FramaC, +\item \textttdef{\_\_FRAMAC\_\_}: defined to 1 during preprocessing by \FramaC, as if the user had added \texttt{-D\_\_FRAMAC\_\_} to the command line. Useful for conditional compilation and detection of an execution by \FramaC. @@ -465,7 +469,7 @@ preparation itself succeeds, by running \FramaC without any option. \$ frama-c <input files> \end{shell} -If you need to use other options for pre-processing or normalizing the source +If you need to use other options for preprocessing or normalizing the source code, you can use the option \optiondef{-}{typecheck} for the same purpose. For instance: \begin{shell} diff --git a/doc/userman/user-start.tex b/doc/userman/user-start.tex index 099980681bbc7495273ca9b0a0e83435773c346d..0822ca2040412bb21512dceba88ac610c29893f5 100644 --- a/doc/userman/user-start.tex +++ b/doc/userman/user-start.tex @@ -266,7 +266,7 @@ content of the file to \texttt{\~{}/.bash\_completion} \item You can \texttt{source} the file, e.g. from your \texttt{.bashrc} with the following command: \begin{verbatim} -source $(frama-c -print-share-path)/.autocomplete_frama-c || true +source $(frama-c-config -share)/autocomplete_frama-c || true \end{verbatim} \end{itemize} diff --git a/ivette/src/dome/src/renderer/layout/forms.tsx b/ivette/src/dome/src/renderer/layout/forms.tsx index 4a9e5a3cb866b90efca884c1d4e1c158f425a7d9..f22cc646cc7064752b387d90bd7534fb3ce5a8e8 100644 --- a/ivette/src/dome/src/renderer/layout/forms.tsx +++ b/ivette/src/dome/src/renderer/layout/forms.tsx @@ -939,14 +939,13 @@ export interface SliderFieldProps extends FieldProps<number> { } const FORMAT_VALUE = (v: number) => Number(v).toString(); -const FORMAT_RANGE = (v: number) => v > 0 ? `+${v}` : `-${-v}`; +const FORMAT_RANGE = (v: number) => (v > 0 ? `+${v}` : `-${-v}`); const FORMATING = (props: SliderFieldProps) => { const { labelValue = true, min } = props; if (labelValue === false) return undefined; if (labelValue === true) return min < 0 ? FORMAT_RANGE : FORMAT_VALUE; return labelValue; -} - +}; const CSS_SLIDER = 'dome-text-label dome-xForm-units dome-xForm-slider-value'; const SHOW_SLIDER = `${CSS_SLIDER} dome-xForm-slider-show`; diff --git a/man/frama-c.1 b/man/frama-c.1 index 66cfcd0fea3cb54912b7077fc834d76899be92e8..6eb485315a7f5a8ecc0f79e11f8489f9691269d9 100644 --- a/man/frama-c.1 +++ b/man/frama-c.1 @@ -25,45 +25,45 @@ .\" using pandoc 2.0 or newer. To modify this file, edit the Markdown file .\" and run `make man/frama-c.1`. -.TH FRAMA-C 1 2020-04-02 +.TH FRAMA-C 1 2020-09-01 .SH NAME .PP -frama\-c[.byte] \- a static analyzer for C programs +frama-c[.byte] - a static analyzer for C programs .PP -frama\-c\-gui[.byte] \- the graphical interface of frama\-c +frama-c-gui[.byte] - the graphical interface of frama-c .SH SYNOPSIS .PP -\f[B]frama\-c\f[] [ \f[I]options\f[] ] \f[I]files\f[] +\f[B]frama-c\f[R] [ \f[I]options\f[R] ] \f[I]files\f[R] .SH DESCRIPTION .PP -\f[B]frama\-c\f[] is a suite of tools dedicated to the analysis of +\f[B]frama-c\f[R] is a suite of tools dedicated to the analysis of source code written in C. It gathers several analysis techniques in a single collaborative framework. This framework can be extended by additional plugins placed in the -\f[B]$FRAMAC_PLUGIN\f[] directory. +\f[B]$FRAMAC_PLUGIN\f[R] directory. The command .RS .PP -frama\-c \-\-plugins +frama-c --plugins .RE .PP will provide the full list of the plugins that are currently installed. .PP -\f[B]frama\-c\-gui\f[] is the graphical user interface of -\f[B]frama\-c\f[]. -It features the same options as the command\-line version. +\f[B]frama-c-gui\f[R] is the graphical user interface of +\f[B]frama-c\f[R]. +It features the same options as the command-line version. .PP -\f[B]frama\-c.byte\f[] and \f[B]frama\-c\-gui.byte\f[] are the OCaml -bytecode versions of the command\-line and graphical user interface +\f[B]frama-c.byte\f[R] and \f[B]frama-c-gui.byte\f[R] are the OCaml +bytecode versions of the command-line and graphical user interface respectively. .PP -By default, Frama\-C recognizes \f[I].c\f[] files as C files needing -pre\-processing and \f[I].i\f[] files as C files having been already -pre\-processed. +By default, Frama-C recognizes \f[I].c\f[R] files as C files needing +pre-processing and \f[I].i\f[R] files as C files having been already +pre-processed. Some plugins may extend the list of recognized files. -Pre\-processing can be customized through the \f[B]\-cpp\-command\f[] -and \f[B]\-cpp\-extra\-args\f[] options. +Pre-processing can be customized through the \f[B]-cpp-command\f[R] and +\f[B]-cpp-extra-args\f[R] options. .SH OPTIONS .SS Syntax .PP @@ -71,738 +71,553 @@ Options taking an additional parameter can also be written under the form .RS .PP -\-\f[I]option\f[]=\f[I]param\f[] +-\f[I]option\f[R]=\f[I]param\f[R] .RE .PP -This form is mandatory when \f[I]param\f[] starts with a dash (`\-'). +This form is mandatory when \f[I]param\f[R] starts with a dash (`-'). .PP Most options that take no parameter have a corresponding .RS .PP -\-no\-\f[I]option\f[] +-no-\f[I]option\f[R] .RE .PP option which has the opposite effect. .SS Help options .TP -.B \-help +.B -help gives a short usage notice. -.RS -.RE .TP -.B \-kernel\-help -prints the list of options recognized by Frama\-C's kernel -.RS -.RE +.B -kernel-help +prints the list of options recognized by Frama-C\[cq]s kernel .TP -.B \-explain +.B -explain prints a help message for each other option given on the command line -.RS -.RE .TP -.B \-verbose \f[I]n\f[] +.B -verbose \f[I]n\f[R] sets verbosity level. Defaults to 1. Setting it to 0 will output less progress messages. -This level can also be set on a per\-\f[I]plugin\f[] basis, with option -\-\f[I]plugin\f[]\-\f[B]verbose\f[] \f[I]n\f[]. +This level can also be set on a per-\f[I]plugin\f[R] basis, with option +-\f[I]plugin\f[R]-\f[B]verbose\f[R] \f[I]n\f[R]. Verbosity level of the kernel can be controlled with option -\f[B]\-kernel\-verbose\f[] \f[I]n\f[]. -.RS -.RE +\f[B]-kernel-verbose\f[R] \f[I]n\f[R]. .TP -.B \-debug \f[I]n\f[] +.B -debug \f[I]n\f[R] sets debugging level. Defaults to 0, meaning no debugging messages. -This option has the same per\-plugin (and kernel) specializations as -\f[B]\-verbose\f[]. -.RS -.RE +This option has the same per-plugin (and kernel) specializations as +\f[B]-verbose\f[R]. .TP -.B \-quiet +.B -quiet sets verbosity and debugging level to 0. -.RS -.RE -.SS Options controlling Frama\-C's kernel +.SS Options controlling Frama-C\[cq]s kernel .TP -.B \-absolute\-valid\-range \f[I]min\-max\f[] -considers that all numerical addresses in the range \f[I]min\-max\f[] +.B -absolute-valid-range \f[I]min-max\f[R] +considers that all numerical addresses in the range \f[I]min-max\f[R] are valid. Bounds are parsed as OCaml integer constants. By default, all numerical addresses are considered invalid. -.RS -.RE .TP -.B \-add\-path \f[I]p1[,p2[\&...,pn]]\f[] -adds directories \f[I]p1\f[] through \f[I]pn\f[] to the list of +.B -add-path \f[I]p1[,p2[\&...,pn]]\f[R] +adds directories \f[I]p1\f[R] through \f[I]pn\f[R] to the list of directories in which plugins are searched. -.RS -.RE .TP -.B [\-no]\-aggressive\-merging +.B [-no]-aggressive-merging merges function definitions modulo renaming. Defaults to no. -.RS -.RE .TP -.B [\-no]\-allow\-duplication +.B [-no]-allow-duplication allows duplication of small blocks during normalization of tests and loops. Otherwise, normalization uses labels and gotos. -Bigger blocks and blocks with non\-trivial control flow are never +Bigger blocks and blocks with non-trivial control flow are never duplicated. Defaults to yes. -.RS -.RE .TP -.B [\-no]\-annot +.B [-no]-annot reads ACSL annotations. This is the default. -Annotations are pre\-processed by default. -Use \-no\-pp\-annot if you don't want to expand macros in annotations. -.RS -.RE +Annotations are pre-processed by default. +Use -no-pp-annot if you don\[cq]t want to expand macros in annotations. .TP -.B \-big\-ints\-hex \f[I]max\f[] -integers larger than \f[I]max\f[] are displayed in hexadecimal (by +.B -big-ints-hex \f[I]max\f[R] +integers larger than \f[I]max\f[R] are displayed in hexadecimal (by default, all integers are displayed in decimal). -.RS -.RE .TP -.B \-check +.B -check performs integrity checks on the internal AST (for developers only). -.RS -.RE .TP -.B [\-no]\-asm\-contracts -generates contracts for assembly code written according to gcc's +.B [-no]-asm-contracts +generates contracts for assembly code written according to gcc\[cq]s extended syntax. Defaults to yes. -.RS -.RE .TP -.B [\-no]\-asm\-contracts\-auto\-validate +.B [-no]-asm-contracts-auto-validate automatically marks contracts generated from asm as valid. Defaults to no. -.RS -.RE .TP -.B \-c11 +.B -c11 enables (partial) C11 compatibility, e.g.\ typedef redefinitions. Defaults to no. -.RS -.RE .TP -.B [\-no]\-collapse\-call\-cast +.B [-no]-collapse-call-cast allows implicit cast between the value returned by a function and the lvalue it is assigned to. Otherwise, a temporary variable is used and the cast is made explicit. Defaults to yes. -.RS -.RE .TP -.B [\-no]\-constfold +.B [-no]-constfold folds all syntactically constant expressions in the code before analyses. Defaults to no. -.RS -.RE .TP -.B \-const\-readonly +.B -const-readonly variables with const qualifier must be actually constant. Defaults to yes. -The opposite option is \f[B]\-unsafe\-writable\f[]. -.RS -.RE +The opposite option is \f[B]-unsafe-writable\f[R]. .TP -.B [\-no]\-continue\-annot\-error -when analyzing an annotation, the default behavior (the \f[B]\-no\f[] +.B [-no]-continue-annot-error +when analyzing an annotation, the default behavior (the \f[B]-no\f[R] version of this option) when a typechecking error occurs is to reject the source file as is the case for typechecking errors within the C code. With this option on, the typechecker will only output a warning and -discard the annotation but typeâ€checking will continue (errors in C code -are still fatal, though). +discard the annotation but type\[hy]checking will continue (errors in C +code are still fatal, though). .PD 0 .P .PD -\f[B]Deprecated\f[]: use \f[B]\-kernel\-warn\-key annot\-error\f[] +\f[B]Deprecated\f[R]: use \f[B]-kernel-warn-key annot-error\f[R] instead. -.RS -.RE .TP -.B \-cpp\-command \f[I]cmd\f[] -uses \f[I]cmd\f[] as the command to pre\-process C files. -Defaults to the \f[B]CPP\f[] environment variable or to -.RS -.RE +.B -cpp-command \f[I]cmd\f[R] +uses \f[I]cmd\f[R] as the command to pre-process C files. +Defaults to the \f[B]CPP\f[R] environment variable or to .RS .PP -gcc \-C \-E \-I. +gcc -C -E -I. .RE .PP if it is not set. If unset, the command is built as follows: .RS .PP -CPP \-o +CPP -o .RE .PP -\f[I]%1\f[] and \f[I]%2\f[] can be used into the \f[B]CPP\f[] string to -mark the position of \f[I]\f[] and \f[I]\f[] respectively. +\f[I]%1\f[R] and \f[I]%2\f[R] can be used into the \f[B]CPP\f[R] string +to mark the position of \f[I]\f[R] and \f[I]\f[R] respectively. Note that this option is often better replaced by -\f[B]\-cpp\-extra\-args\f[]. +\f[B]-cpp-extra-args\f[R]. .TP -.B \-cpp\-extra\-args \f[I]args\f[] -gives additional arguments to the pre\-processor. -Pre\-processing annotations is done in two separate pre\-processing +.B -cpp-extra-args \f[I]args\f[R] +gives additional arguments to the pre-processor. +Pre-processing annotations is done in two separate pre-processing stages. The first one is a normal pass on the C code which retains macro definitions. These are then used in the second pass during which annotations are -pre\-processed. -\f[I]args\f[] are used only for the first pass, so that arguments that +pre-processed. +\f[I]args\f[R] are used only for the first pass, so that arguments that should not be used twice (such as additional include directives or macro -definitions) must thus go there instead of \f[B]\-cpp\-command\f[]. -.RS -.RE +definitions) must thus go there instead of \f[B]-cpp-command\f[R]. .TP -.B \-cpp\-extra\-args\-per\-file \f[I]file1:args1,\&...,filen:argsn\f[] -like \f[B]\-cpp\-extra\-args\f[], but the arguments only apply to the +.B -cpp-extra-args-per-file \f[I]file1:args1,\&...,filen:argsn\f[R] +like \f[B]-cpp-extra-args\f[R], but the arguments only apply to the specified files. -.RS -.RE .TP -.B [\-no]\-cpp\-frama\-c\-compliant -indicates that the chosen preprocessor complies to some Frama\-C +.B [-no]-cpp-frama-c-compliant +indicates that the chosen preprocessor complies to some Frama-C requirements, such as accepting the same set of options as GNU cpp, and -accepting architecture\-specific options such as \-m32/\-m64. +accepting architecture-specific options such as -m32/-m64. Default values depend on the installed preprocessor at configure time. -See also \f[B]\-pp\-annot\f[]. -.RS -.RE +See also \f[B]-pp-annot\f[R]. .TP -.B [\-no]\-autoload\-plugins +.B [-no]-autoload-plugins when on, load all the dynamic plugins found in the search path (see -\f[B]\-print\-plugin\-path\f[] for more information on the default -search path). -Otherwise, only plugins requested by \f[B]\-load\-module\f[] will be +\f[B]-print-plugin-path\f[R] for more information on the default search +path). +Otherwise, only plugins requested by \f[B]-load-module\f[R] will be loaded. Defaults to on. -.RS -.RE .TP -.B \-enums \f[I]repr\f[] +.B -enums \f[I]repr\f[R] choose the way the representation of enumerated types is determined. -\f[B]frama\-c \-enums help\f[] gives the list of available options. -Default is \f[B]gcc\-enums\f[]. -.RS -.RE +\f[B]frama-c -enums help\f[R] gives the list of available options. +Default is \f[B]gcc-enums\f[R]. .TP -.B \-float\-digits \f[I]n\f[] -when outputting floating\-point numbers, display \f[I]n\f[] digits. +.B -float-digits \f[I]n\f[R] +when outputting floating-point numbers, display \f[I]n\f[R] digits. Defaults to 12. -.RS -.RE .TP -.B \-float\-flush\-to\-zero +.B -float-flush-to-zero floating point operations flush to zero. -.RS -.RE .TP -.B \-float\-hex +.B -float-hex display floats as hexadecimal. -.RS -.RE .TP -.B \-float\-normal +.B -float-normal display floats with the standard OCaml routine. -.RS -.RE .TP -.B \-float\-relative -display float intervals as [ \f[I]lower_bound\f[]++\f[I]width\f[] ]. -.RS -.RE +.B -float-relative +display float intervals as [ \f[I]lower_bound\f[R]++\f[I]width\f[R] ]. .TP -.B [\-no]\-frama\-c\-stdlib -adds \f[B]\-I$FRAMAC_SHARE/libc\f[] to the options given to the cpp +.B [-no]-frama-c-stdlib +adds \f[B]-I$FRAMAC_SHARE/libc\f[R] to the options given to the cpp command. -If \f[B]\-cpp\-frama\-c\-compliant\f[] is not false, also adds -\f[B]\-nostdinc\f[] to prevent an inconsistent mix of system and -Frama\-C header files. +If \f[B]-cpp-frama-c-compliant\f[R] is not false, also adds +\f[B]-nostdinc\f[R] to prevent an inconsistent mix of system and Frama-C +header files. Defaults to yes. -.RS -.RE .TP -.B \-implicit\-function\-declaration \f[I]action\f[] +.B -implicit-function-declaration \f[I]action\f[R] warns or aborts when a function is called before it has been declared. -\f[I]action\f[] can be one of \f[B]ignore\f[], \f[B]warn\f[], or -\f[B]error\f[]. -Defaults to \f[B]warn\f[]. +\f[I]action\f[R] can be one of \f[B]ignore\f[R], \f[B]warn\f[R], or +\f[B]error\f[R]. +Defaults to \f[B]warn\f[R]. .PD 0 .P .PD -\f[B]Deprecated\f[]: use \f[B]\-kernel\-warn\-key -typing:implicit\-function\-declaration\f[] instead. -.RS -.RE +\f[B]Deprecated\f[R]: use \f[B]-kernel-warn-key +typing:implicit-function-declaration\f[R] instead. .TP -.B \-initialized\-padding\-locals +.B -initialized-padding-locals implicit initialization of locals sets padding bits to 0. If false, padding bits are left uninitialized. Defaults to yes. -.RS -.RE .TP -.B \-inline\-calls \f[I]f1,\&...,fn\f[] -syntactically inlines calls to functions \f[I]f1,\&...,fn\f[]. -Use \f[B]\@inline\f[] to select all functions with attribute -\f[I]inline\f[]. +.B -inline-calls \f[I]f1,\&...,fn\f[R] +syntactically inlines calls to functions \f[I]f1,\&...,fn\f[R]. +Use \f[B]\[at]inline\f[R] to select all functions with attribute +\f[I]inline\f[R]. Recursive functions are inlined only at the first level. Calls via function pointers are not inlined. -.RS -.RE .TP -.B \-journal\-disable +.B -journal-disable do not output a journal of the current session. -See \f[B]\-journal\-enable\f[]. -.RS -.RE +See \f[B]-journal-enable\f[R]. .TP -.B \-journal\-enable +.B -journal-enable on by default, dumps a journal of all the actions performed during the -current Frama\-C session in the form of an OCaml script that can be -replayed with \f[B]\-load\-script\f[]. -The name of the script can be set with the \f[B]\-journal\-name\f[] +current Frama-C session in the form of an OCaml script that can be +replayed with \f[B]-load-script\f[R]. +The name of the script can be set with the \f[B]-journal-name\f[R] option. -.RS -.RE .TP -.B \-journal\-name \f[I]name\f[] -sets the name of the journal file (without the \f[I].ml\f[] extension). -Defaults to \f[B]frama_c_journal\f[]. -.RS -.RE +.B -journal-name \f[I]name\f[R] +sets the name of the journal file (without the \f[I].ml\f[R] extension). +Defaults to \f[B]frama_c_journal\f[R]. .TP -.B \-json\-compilation\-database \f[I]path\f[] -use \f[I]path\f[] as a JSON compilation database (see +.B -json-compilation-database \f[I]path\f[R] +use \f[I]path\f[R] as a JSON compilation database (see <https://clang.llvm.org/docs/JSONCompilationDatabase.html> for more -information): each file preprocessed by Frama\-C will include -corresponding \f[B]\-I\f[] and \f[B]\-D\f[] flags according to the -specifications in \f[I]path\f[]. -If \f[I]path\f[] is a directory, use -\f[B]<path>/compile_commands.json\f[]. +information): each file preprocessed by Frama-C will include +corresponding \f[B]-I\f[R] and \f[B]-D\f[R] flags according to the +specifications in \f[I]path\f[R]. +If \f[I]path\f[R] is a directory, use +\f[B]<path>/compile_commands.json\f[R]. Disabled by default. -.RS -.RE .TP -.B [\-no]\-keep\-comments -tries to preserve comments when pretty\-printing the source code. +.B [-no]-keep-comments +tries to preserve comments when pretty-printing the source code. Defaults to no. -.RS -.RE .TP -.B [\-no]\-keep\-switch -when \f[B]\-simplify\-cfg\f[] is set, keeps switch statements. +.B [-no]-keep-switch +when \f[B]-simplify-cfg\f[R] is set, keeps switch statements. Defaults to no. -.RS -.RE .TP -.B \-keep\-unused\-specified\-functions -see \f[B]\-remove\-unused\-specified\-functions\f[]. -.RS -.RE +.B -keep-unused-specified-functions +see \f[B]-remove-unused-specified-functions\f[R]. .TP -.B \-keep\-unused\-types -see \f[B]\-remove\-unused\-types\f[]. -.RS -.RE +.B -keep-unused-types +see \f[B]-remove-unused-types\f[R]. .TP -.B \-kernel\-log \f[I]kind:file\f[] -copies log messages from the Frama\-C's kernel to file. -\f[I]kind\f[] specifies which kinds of messages to be copied (e.g. -\f[B]w\f[] for warnings, \f[B]e\f[] for errors, etc.). -See \f[B]\-kernel\-help\f[] for more details. -Can also be set on a per\-plugin basis, with option -\-\f[I]<plugin>\f[]\-\f[B]log\f[]. -.RS -.RE +.B -kernel-log \f[I]kind:file\f[R] +copies log messages from the Frama-C\[cq]s kernel to file. +\f[I]kind\f[R] specifies which kinds of messages to be copied +(e.g.\ \f[B]w\f[R] for warnings, \f[B]e\f[R] for errors, etc.). +See \f[B]-kernel-help\f[R] for more details. +Can also be set on a per-plugin basis, with option +-\f[I]<plugin>\f[R]-\f[B]log\f[R]. .TP -.B \-kernel\-msg\-key \f[I]k1,\&...,kn\f[] +.B -kernel-msg-key \f[I]k1,\&...,kn\f[R] controls the emission of messages based on categories. -Use \f[B]\-kernel\-msg\-key help\f[] to get a list of available -categories, and \f[B]\-kernel\-msg\-key=\[lq]*\[rq]\f[] to control all +Use \f[B]-kernel-msg-key help\f[R] to get a list of available +categories, and \f[B]-kernel-msg-key=\[lq]*\[rq]\f[R] to control all categories. -To disable a category, add a \f[B]\-\f[] before its name; to enable a -category, simply add its name, with an optional \f[B]+\f[] before it. -For instance, \f[B]\-kernel\-msg\-key=\-k1,k2\f[] will disable messages -from category \f[B]k1\f[] and enable those from category \f[B]k2\f[]. -Can also be set on a per\-plugin basis, with option -\-\f[I]<plugin>\f[]\-\f[B]msg\-key\f[]. +To disable a category, add a \f[B]-\f[R] before its name; to enable a +category, simply add its name, with an optional \f[B]+\f[R] before it. +For instance, \f[B]-kernel-msg-key=-k1,k2\f[R] will disable messages +from category \f[B]k1\f[R] and enable those from category \f[B]k2\f[R]. +Can also be set on a per-plugin basis, with option +-\f[I]<plugin>\f[R]-\f[B]msg-key\f[R]. Note that each plugin has its own set of categories. -.RS -.RE .TP -.B \-kernel\-warn\-key \f[I]k1=a1,\&...,kn=an\f[] +.B -kernel-warn-key \f[I]k1=a1,\&...,kn=an\f[R] controls the emission of warnings based on categories: for each warning -category \f[I]k\f[], associate action \f[I]a\f[]. -Use \f[B]\-kernel\-warn\-key help\f[] to get a list of available warning +category \f[I]k\f[R], associate action \f[I]a\f[R]. +Use \f[B]-kernel-warn-key help\f[R] to get a list of available warning categories and their currently associated actions. -The following actions can be set per category: \f[B]active\f[] (warn), -\f[B]feedback\f[], \f[B]error\f[], \f[B]abort\f[], \f[B]once\f[], -\f[B]feedback\-once\f[], \f[B]err\-once\f[]. -Omitting the action is equivalent to setting it to \f[B]active\f[]. -Warning categories can also be set on a per\-plugin basis, with option -\-\f[I]<plugin>\f[]\f[B]\-warn\-key\f[]. -.RS -.RE -.TP -.B [\-no]\-lib\-entry +The following actions can be set per category: \f[B]active\f[R] (warn), +\f[B]feedback\f[R], \f[B]error\f[R], \f[B]abort\f[R], \f[B]once\f[R], +\f[B]feedback-once\f[R], \f[B]err-once\f[R]. +Omitting the action is equivalent to setting it to \f[B]active\f[R]. +Warning categories can also be set on a per-plugin basis, with option +-\f[I]<plugin>\f[R]\f[B]-warn-key\f[R]. +.TP +.B [-no]-lib-entry indicates that the entry point is called during program execution. This implies in particular that global variables cannot be assumed to have their initial values. -The default is \f[B]\-no\-lib\-entry\f[]: the entry point is also the +The default is \f[B]-no-lib-entry\f[R]: the entry point is also the starting point of the program and globals have their initial value. -.RS -.RE .TP -.B \-load \f[I]file\f[] -loads the (previously saved) state contained in \f[I]file\f[]. -.RS -.RE +.B -load \f[I]file\f[R] +loads the (previously saved) state contained in \f[I]file\f[R]. .TP -.B \-load\-module \f[I]SPEC\f[] -dynamically load OCaml plug\-ins, modules and scripts. -Each \f[I]SPEC\f[] can be an OCaml source or object file, with or +.B -load-module \f[I]SPEC\f[R] +dynamically load OCaml plug-ins, modules and scripts. +Each \f[I]SPEC\f[R] can be an OCaml source or object file, with or without extension, or a Findlib package. Loading order is preserved and additional dependencies can be listed in -*\f[B].depend\f[] files. -.RS -.RE +*\f[B].depend\f[R] files. .TP -.B \-load\-script \f[I]SPEC\f[] -alias for option \f[B]\-load\-module\f[]. -.RS -.RE +.B -load-script \f[I]SPEC\f[R] +alias for option \f[B]-load-module\f[R]. .TP -.B \-machdep \f[I]machine\f[] -uses \f[I]machine\f[] as the current machine\-dependent configuration +.B -machdep \f[I]machine\f[R] +uses \f[I]machine\f[R] as the current machine-dependent configuration (size of the various integer types, endiandness, \&...). The list of currently supported machines is available through option -\f[I]\-machdep help\f[]. -Default is \f[B]x86_32\f[]. -.RS -.RE +\f[I]-machdep help\f[R]. +Default is \f[B]x86_32\f[R]. .TP -.B \-main \f[I]f\f[] -sets \f[I]f\f[] as the entry point of the analysis. -Defaults to \f[B]main\f[]. +.B -main \f[I]f\f[R] +sets \f[I]f\f[R] as the entry point of the analysis. +Defaults to \f[B]main\f[R]. By default, it is considered as the starting point of the program under analysis. -Use \f[B]\-lib\-entry\f[] if \f[I]f\f[] is supposed to be called in the +Use \f[B]-lib-entry\f[R] if \f[I]f\f[R] is supposed to be called in the middle of an execution. -.RS -.RE .TP -.B \-obfuscate +.B -obfuscate prints an obfuscated version of the code (where original identifiers are replaced by meaningless ones) and exits. The correspondence table between original and new symbols is kept at the beginning of the result. -.RS -.RE .TP -.B \-ocode \f[I]file\f[] -redirects pretty\-printed code to \f[I]file\f[] instead of standard +.B -ocode \f[I]file\f[R] +redirects pretty-printed code to \f[I]file\f[R] instead of standard output. -.RS -.RE .TP -.B [\-no]\-orig\-name +.B [-no]-orig-name During the normalization phase, some variables may get renamed when -different variables with the same name can co\-exist (e.g.\ a global +different variables with the same name can co-exist (e.g.\ a global variable and a formal parameter). When this option is on, a message is printed each time this occurs. Defaults to no. -.RS -.RE .TP -.B [\-no]\-pp\-annot -pre\-processes annotations. +.B [-no]-pp-annot +pre-processes annotations. This is currently only possible when using gcc (or GNU cpp) -pre\-processor. -The default is to pre\-process annotations when the default -pre\-processor is identified as GNU or GNU\-like. -See also \f[B]\-cpp\-frama\-c\-compliant\f[]. -.RS -.RE +pre-processor. +The default is to pre-process annotations when the default pre-processor +is identified as GNU or GNU-like. +See also \f[B]-cpp-frama-c-compliant\f[R]. .TP -.B [\-no]\-print -pretty\-prints the source code as normalized by CIL. +.B [-no]-print +pretty-prints the source code as normalized by CIL. Defaults to no. -.RS -.RE .TP -.B [\-no]\-print\-libc -expands \f[B]#include\f[] directives in the pretty\-printed CIL code for -files in the Frama\-C standard library. +.B -print-cpp-commands +outputs the preprocessing commands for all input files. +.TP +.B [-no]-print-libc +expands \f[B]#include\f[R] directives in the pretty-printed CIL code for +files in the Frama-C standard library. Defaults to no. -.RS -.RE .TP -.B \-print\-libpath -outputs the directory where the Frama\-C kernel library is installed. -.RS -.RE +.B -print-libpath +outputs the directory where the Frama-C kernel library is installed. .TP -.B \-print\-path -alias of \f[B]\-print\-share\-path\f[]. -.RS -.RE +.B -print-path +alias of \f[B]-print-share-path\f[R]. .TP -.B \-print\-plugin\-path -outputs the directory where Frama\-C searches its plugins (can be -overridden by the \f[B]FRAMAC_PLUGIN\f[] variable and the -\f[B]\-add\-path\f[] option). -.RS -.RE +.B -print-plugin-path +outputs the directory where Frama-C searches its plugins (can be +overridden by the \f[B]FRAMAC_PLUGIN\f[R] variable and the +\f[B]-add-path\f[R] option). .TP -.B \-print\-share\-path -outputs the directory where Frama\-C stores its data (can be overridden -by the \f[B]FRAMAC_SHARE\f[] variable). -.RS -.RE +.B -print-share-path +outputs the directory where Frama-C stores its data (can be overridden +by the \f[B]FRAMAC_SHARE\f[R] variable). .TP -.B [\-no]\-remove\-exn +.B [-no]-remove-exn transforms throw and try/catch statements into normal C functions. Defaults to no, unless the input source language has an exception mechanism. -.RS -.RE .TP -.B \-remove\-inlined \f[I]f1,\&...,fn\f[] -removes inlined functions \f[I]f1,\&...,fn\f[] from the AST, which must -have been given to \f[B]\-inline\-calls\f[]. +.B -remove-inlined \f[I]f1,\&...,fn\f[R] +removes inlined functions \f[I]f1,\&...,fn\f[R] from the AST, which must +have been given to \f[B]-inline-calls\f[R]. Note: this option does not check if the given functions were fully inlined. -.RS -.RE .TP -.B \-remove\-projects \f[I]p1,\&...,pn\f[] -removes the given projects \f[I]p1,\&...,pn\f[]. -\f[B]\@all_but_current\f[] removes all projects but the current one. -.RS -.RE +.B -remove-projects \f[I]p1,\&...,pn\f[R] +removes the given projects \f[I]p1,\&...,pn\f[R]. +\f[B]\[at]all_but_current\f[R] removes all projects but the current one. .TP -.B \-remove\-unused\-specified\-functions +.B -remove-unused-specified-functions keeps function prototypes that have an ACSL specification but are not used in the code. This is the default. -Functions having the attribute \f[B]FRAMAC_BUILTIN\f[] are always kept. -.RS -.RE +Functions having the attribute \f[B]FRAMAC_BUILTIN\f[R] are always kept. .TP -.B \-remove\-unused\-types +.B -remove-unused-types remove types and struct/union/enum declarations that are not referenced anywhere else in the code. This is the default. -Use \f[B]\-keep\-unused\-types\f[] to keep these definitions. -.RS -.RE +Use \f[B]-keep-unused-types\f[R] to keep these definitions. .TP -.B \-safe\-arrays +.B -safe-arrays for multidimensional arrays or arrays that are fields inside structs, assumes that all accesses must be in bound (set by default). -The opposite option is \f[B]\-unsafe\-arrays\f[]. -.RS -.RE +The opposite option is \f[B]-unsafe-arrays\f[R]. .TP -.B \-save \f[I]file\f[] -saves Frama\-C's state into \f[I]file\f[] after analyses have taken +.B -save \f[I]file\f[R] +saves Frama-C\[cq]s state into \f[I]file\f[R] after analyses have taken place. -.RS -.RE .TP -.B \-session \f[I]s\f[] -sets \f[I]s\f[] as the directory in which session files are searched. -.RS -.RE +.B -session \f[I]s\f[R] +sets \f[I]s\f[R] as the directory in which session files are searched. .TP -.B [\-no]\-set\-project\-as\-default +.B [-no]-set-project-as-default the current project becomes the default one (and so future -\f[B]\-then\f[] sequences are applied on it). +\f[B]-then\f[R] sequences are applied on it). Defaults to no. -.RS -.RE .TP -.B [\-no]\-simplify\-cfg -removes \f[B]break\f[], \f[B]continue\f[] and \f[B]switch\f[] statements -before analyses. +.B [-no]-simplify-cfg +removes \f[B]break\f[R], \f[B]continue\f[R] and \f[B]switch\f[R] +statements before analyses. Defaults to no. -.RS -.RE .TP -.B [\-no]\-simplify\-trivial\-loops -simplifies trivial loops such as \f[B]do \&... while (0)\f[] loops. +.B [-no]-simplify-trivial-loops +simplifies trivial loops such as \f[B]do \&... while (0)\f[R] loops. Defaults to yes. -.RS -.RE .TP -.B \-then -allows one to compose analyses: a first run of Frama\-C will occur with -the options before \f[B]\-then\f[] and a second run will be done with -the options after \f[B]\-then\f[] on the current project from the first +.B -then +allows one to compose analyses: a first run of Frama-C will occur with +the options before \f[B]-then\f[R] and a second run will be done with +the options after \f[B]-then\f[R] on the current project from the first run. -.RS -.RE .TP -.B \-then\-last -like \f[B]\-then\f[], but the second group of actions is executed on the +.B -then-last +like \f[B]-then\f[R], but the second group of actions is executed on the last project created by a program transformer. -.RS -.RE .TP -.B \-then\-on \f[I]prj\f[] -similar to \f[B]\-then\f[] except that the second run is performed in -project \f[I]prj\f[]. -If no such project exists, Frama\-C exits with an error. -.RS -.RE +.B -then-on \f[I]prj\f[R] +similar to \f[B]-then\f[R] except that the second run is performed in +project \f[I]prj\f[R]. +If no such project exists, Frama-C exits with an error. .TP -.B \-then\-replace -like \f[B]\-then\-last\f[], but also removes the previous current +.B -then-replace +like \f[B]-then-last\f[R], but also removes the previous current project. -.RS -.RE .TP -.B \-time \f[I]file\f[] -appends user time and date in the given file when Frama\-C exits. -.RS -.RE +.B -time \f[I]file\f[R] +appends user time and date in the given file when Frama-C exits. .TP -.B \-typecheck +.B -typecheck forces typechecking of the source files. This option is only relevant if no further analysis is requested (as typechecking will implicitly occur before the analysis is launched). -.RS -.RE .TP -.B \-ulevel \f[I]n\f[] -syntactically unroll loops \f[I]n\f[] times before the analysis. +.B -ulevel \f[I]n\f[R] +syntactically unroll loops \f[I]n\f[R] times before the analysis. This can be quite costly and some plugins (e.g.\ Eva) provide more efficient ways to perform the same thing. See their respective manuals for more information. -This can also be activated on a per\-loop basis via the \f[B]loop pragma -unroll \f[] directive. -A negative value for \f[I]n\f[] will inhibit such pragmas. -.RS -.RE +This can also be activated on a per-loop basis via the \f[B]loop pragma +unroll \f[R] directive. +A negative value for \f[I]n\f[R] will inhibit such pragmas. .TP -.B [\-no]\-ulevel\-force -ignores \f[B]UNROLL\f[] loop pragmas disabling unrolling. -.RS -.RE +.B [-no]-ulevel-force +ignores \f[B]UNROLL\f[R] loop pragmas disabling unrolling. .PP -[\-no]\-unicode outputs ACSL formulas with UTF\-8 characters. +[-no]-unicode outputs ACSL formulas with UTF-8 characters. This is the default. -When given the \f[B]\-no\-unicode\f[] option, Frama\-C will use the -ASCII version instead. +When given the \f[B]-no-unicode\f[R] option, Frama-C will use the ASCII +version instead. See the ACSL manual for the correspondence. .TP -.B \-unsafe\-arrays -see \f[B]\-safe\-arrays\f[]. -.RS -.RE +.B -unsafe-arrays +see \f[B]-safe-arrays\f[R]. .TP -.B [\-no]\-unspecified\-access +.B [-no]-unspecified-access checks that read/write accesses occurring in an unspecified order -(according to the C standard's notion of sequence points) are performed -on separate locations. -With \f[B]\-no\-unspecified\-access\f[], assumes that it is always the +(according to the C standard\[cq]s notion of sequence points) are +performed on separate locations. +With \f[B]-no-unspecified-access\f[R], assumes that it is always the case (this is the default). -.RS -.RE .TP -.B \-version -outputs the version string of Frama\-C. -.RS -.RE +.B -version +outputs the version string of Frama-C. .TP -.B \-warn\-decimal\-float \f[I]freq\f[] -warns when a floating\-point constant cannot be exactly represented +.B -warn-decimal-float \f[I]freq\f[R] +warns when a floating-point constant cannot be exactly represented (e.g.\ 0.1). -\f[I]freq\f[] can be one of \f[B]none\f[], \f[B]once\f[], or -\f[B]all\f[]. +\f[I]freq\f[R] can be one of \f[B]none\f[R], \f[B]once\f[R], or +\f[B]all\f[R]. .PD 0 .P .PD -\f[B]Deprecated\f[]: use \f[B]\-kernel\-warn\-key -parser:decimal\-float=once\f[] (and variants) instead. -.RS -.RE +\f[B]Deprecated\f[R]: use \f[B]-kernel-warn-key +parser:decimal-float=once\f[R] (and variants) instead. .TP -.B [\-no]\-warn\-invalid\-pointer +.B [-no]-warn-invalid-pointer generate alarms for invalid pointer arithmetic. Defaults to no. -.RS -.RE .TP -.B [\-no]\-warn\-left\-shift\-negative +.B [-no]-warn-left-shift-negative generate alarms for signed left shifts on negative values. Defaults to yes. -.RS -.RE .TP -.B [\-no]\-warn\-right\-shift\-negative +.B [-no]-warn-right-shift-negative generate alarms for signed right shifts on negative values. Defaults to no. -.RS -.RE .TP -.B [\-no]\-warn\-pointer\-downcast +.B [-no]-warn-pointer-downcast generates alarms when the downcast of a pointer may exceed the destination range. Defaults to yes. -.RS -.RE .TP -.B [\-no]\-warn\-signed\-downcast +.B [-no]-warn-signed-downcast generates alarms when signed downcasts may exceed the destination range. Defaults to no. -.RS -.RE .TP -.B [\-no]\-warn\-signed\-overflow +.B [-no]-warn-signed-overflow generates alarms for signed operations that overflow. Defaults to yes. -.RS -.RE .TP -.B [\-no]\-warn\-unsigned\-downcast +.B [-no]-warn-unsigned-downcast generates alarms when unsigned downcasts may exceed the destination range. Defaults to no. -.RS -.RE .TP -.B [\-no]\-warn\-unsigned\-overflow +.B [-no]-warn-unsigned-overflow generates alarms for unsigned operations that overflow. Defaults to no. -.RS -.RE .TP -.B [\-no]\-warn\-invalid\-bool +.B [-no]-warn-invalid-bool generates alarms for reads of trap representations of _Bool lvalues. Defaults to yes. -.RS -.RE -.SS Plugin\-specific options +.SS Plugin-specific options .PP For each plugin, the command .RS .PP -frama\-c \-plugin\-help +frama-c -plugin-help .RE .PP will give the list of options that are specific to the plugin. @@ -810,64 +625,45 @@ will give the list of options that are specific to the plugin. .TP .B 0 Successful execution -.RS -.RE .TP .B 1 Invalid user input -.RS -.RE .TP .B 2 User interruption (kill or equivalent) -.RS -.RE .TP .B 3 Unimplemented feature -.RS -.RE .TP .B 4 5 6 Internal error -.RS -.RE .TP .B 125 Unknown error -.RS -.RE .PP Exit statuses greater than 2 can be considered as a bug (or a feature -request for the case of exit status 3) and may be reported on Frama\-C's -BTS (see below). +request for the case of exit status 3) and may be reported on +Frama-C\[cq]s BTS (see below). .SH ENVIRONMENT VARIABLES .PP -It is possible to control the places where Frama\-C looks for its files +It is possible to control the places where Frama-C looks for its files through the following variables. .TP .B FRAMAC_LIB -The directory where kernel's compiled interfaces are installed. -.RS -.RE +The directory where kernel\[cq]s compiled interfaces are installed. .TP .B FRAMAC_PLUGIN -The directory where Frama\-C can find standard plugins. -If you wish to have plugins in several places, use \f[B]\-add\-path\f[] +The directory where Frama-C can find standard plugins. +If you wish to have plugins in several places, use \f[B]-add-path\f[R] instead. -.RS -.RE .TP .B FRAMAC_SHARE -The directory where Frama\-C data (e.g.\ its version of the standard +The directory where Frama-C data (e.g.\ its version of the standard library) is installed. -.RS -.RE .SH SEE ALSO .PP -Frama\-C user manual: -http://frama\-c.com/download/frama\-c\-user\-manual.pdf +Frama-C user manual: http://frama-c.com/download/frama-c-user-manual.pdf .PP -Frama\-C homepage: http://frama\-c.com +Frama-C homepage: http://frama-c.com .PP -Frama\-C BTS: http://bts.frama\-c.com +Frama-C BTS: http://bts.frama-c.com diff --git a/man/frama-c.1.header b/man/frama-c.1.header index 2bc62cfc5176c9274f4dad74c7c7d4894dd84a7c..0f53666d7fe149a1b104dd8bc8fccf774f4b9726 100644 --- a/man/frama-c.1.header +++ b/man/frama-c.1.header @@ -25,4 +25,4 @@ .\" using pandoc 2.0 or newer. To modify this file, edit the Markdown file .\" and run `make man/frama-c.1`. -.TH FRAMA-C 1 2020-05-26 +.TH FRAMA-C 1 2020-09-01 diff --git a/man/frama-c.1.md b/man/frama-c.1.md index 396cf3138d6b15f78d2354d2b41a5767104c8bc8..35111cfa6e87e5064a33e9a72e6661004692de18 100644 --- a/man/frama-c.1.md +++ b/man/frama-c.1.md @@ -333,6 +333,9 @@ See also **-cpp-frama-c-compliant**. [-no]-print : pretty-prints the source code as normalized by CIL. Defaults to no. +-print-cpp-commands +: outputs the preprocessing commands for all input files. + [-no]-print-libc : expands **#include** directives in the pretty-printed CIL code for files in the Frama-C standard library. Defaults to no. diff --git a/nix/default.nix b/nix/default.nix index fdce398cfe5fadaca673a976eb8bb381dec43ffa..b3e6929a292d9f526fabea47f1ded55b933450e4 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -214,7 +214,9 @@ rec { inherit src; buildInputs = (mk_buildInputs { opamPackages = [ "xml-light" ]; } ) ++ [ pkgs.getopt - pkgs.libxslt pkgs.libxml2 pkgs.autoPatchelfHook stdenv.cc.cc.lib + pkgs.libxslt pkgs.libxml2 pkgs.autoPatchelfHook + pkgs.swiProlog + stdenv.cc.cc.lib ]; counter_examples_src = plugins.counter-examples.src; genassigns_src = plugins.genassigns.src; @@ -226,6 +228,7 @@ rec { volatile_src = plugins.volatile.src; security_src = plugins.security.src; context_from_precondition_src = plugins.context-from-precondition.src; + metacsl_src = plugins.meta.src; postPatch = '' patchShebangs . ''; @@ -234,8 +237,8 @@ rec { chmod -R u+w -- "$sourceRoot/src/plugins/counter-examples" cp -r --preserve=mode "$genassigns_src" "$sourceRoot/src/plugins/genassigns" chmod -R u+w -- "$sourceRoot/src/plugins/genassigns" - cp -r --preserve=mode "$frama_clang_src" "$sourceRoot/src/plugins/frama-clang" - chmod -R u+w -- "$sourceRoot/src/plugins/frama-clang" + # cp -r --preserve=mode "$frama_clang_src" "$sourceRoot/src/plugins/frama-clang" + # chmod -R u+w -- "$sourceRoot/src/plugins/frama-clang" cp -r --preserve=mode "$pathcrawler_src" "$sourceRoot/src/plugins/pathcrawler" chmod -R u+w -- "$sourceRoot/src/plugins/pathcrawler" cp -r --preserve=mode "$mthread_src" "$sourceRoot/src/plugins/mthread" diff --git a/nix/frama-ci.nix b/nix/frama-ci.nix index e093574991eec97d4c896c33edf17c28d543b5cf..7939e05dd1161d65a13c6d4093cfff78d3f3fe81 100644 --- a/nix/frama-ci.nix +++ b/nix/frama-ci.nix @@ -5,7 +5,7 @@ let src = builtins.fetchGit { "url" = "https://bobot:${password}@git.frama-c.com/frama-c/Frama-CI.git"; "name" = "Frama-CI"; - "rev" = "abf07b7c0f53b33b32c8b170580e14480fd3aba6"; + "rev" = "3e8a67b19d5923c651509070eec5db646b80ec32"; "ref" = "master"; }; in diff --git a/share/Makefile.config.in b/share/Makefile.config.in index 0739e3cef9cf47ea569ff43de2d365dc91910a61..6f266c9ff6dcc620e0cfdc50bd500c7afa812529 100644 --- a/share/Makefile.config.in +++ b/share/Makefile.config.in @@ -128,6 +128,9 @@ HAS_MPFR ?=@HAS_MPFR@ # landmarks HAS_LANDMARKS ?=@HAS_LANDMARKS@ +# python 3.6 +HAS_PYTHON36 ?=@HAS_PYTHON36@ + ########################## # Miscellaneous commands # ########################## @@ -157,8 +160,12 @@ HAVE_BUILTIN_VA_LIST ?=@HAVE_BUILTIN_VA_LIST@ # Non-plugin test directories containing some ML files to compile TEST_DIRS_AS_PLUGIN:=\ dynamic dynamic_plugin journal saveload spec misc syntax cil \ - pretty_printing builtins libc value fc_script -TEST_DIRS_AS_PLUGIN+=jcdb + pretty_printing builtins libc value + +ifeq ($(HAS_PYTHON36),yes) +TEST_DIRS_AS_PLUGIN+= fc_script jcdb +endif + PLUGIN_TESTS_LIST+=$(TEST_DIRS_AS_PLUGIN) ########################## diff --git a/share/analysis-scripts/analysis.mk b/share/analysis-scripts/analysis.mk index e732240db26edd846b33d9d6d610b25454044b7b..068fe3b20cfa6afee747a2382882ac4b6a0a3a72 100644 --- a/share/analysis-scripts/analysis.mk +++ b/share/analysis-scripts/analysis.mk @@ -118,7 +118,7 @@ EVAFLAGS ?= \ -eva-print-callstacks -eva-warn-key alarm=inactive \ -no-deps-print -no-calldeps-print \ -eva-warn-key garbled-mix \ - -memexec-all -calldeps -permissive -from-verbose 0 \ + -calldeps -permissive -from-verbose 0 \ $(if $(EVABUILTINS), -eva-builtin=$(call fc_list,$(EVABUILTINS)),) \ $(if $(EVAUSESPECS), -eva-use-spec $(call fc_list,$(EVAUSESPECS)),) FCFLAGS ?= diff --git a/share/analysis-scripts/make_template.py b/share/analysis-scripts/make_template.py index 504043a6ebf62a733e1b9290293b866f0a15463a..6cbab8c30caf80289ff47531e00502af661bbbab 100755 --- a/share/analysis-scripts/make_template.py +++ b/share/analysis-scripts/make_template.py @@ -44,13 +44,13 @@ if len(sys.argv) > 2: print(" creates a Frama-C makefile in [dir] (default: .frama-c)") sys.exit(1) -framac_in_path = True -framac = shutil.which("frama-c") -if not framac: - framac_in_path = False - if os.environ.get("FRAMAC"): - framac = os.environ["FRAMAC"] - else: +framac_in_path = False +if os.environ.get("FRAMAC"): + framac = os.environ["FRAMAC"] +if not framac or not os.path.isfile(framac): + framac_in_path = True + framac = shutil.which("frama-c") + if not framac: sys.exit("error: frama-c must be in the PATH, "\ "or in environment variable FRAMAC") diff --git a/src/kernel_internals/typing/cabs2cil.ml b/src/kernel_internals/typing/cabs2cil.ml index 17cf66913b9a127047fe7e66bbaf98ad4e871dfb..209aed920b7b55df2f804b9f84f17bb8bbf17ab4 100644 --- a/src/kernel_internals/typing/cabs2cil.ml +++ b/src/kernel_internals/typing/cabs2cil.ml @@ -5995,7 +5995,8 @@ and doExp local_env let res = if Cil.isCompleteType typ then new_exp ~loc (SizeOf typ) else begin - Kernel.error ~once:true ~current:true "sizeof on incomplete type"; + Kernel.error ~once:true ~current:true + "sizeof on incomplete type '%a'" Cil_printer.pp_typ typ; new_exp ~loc (Const (CStr ("booo sizeof(incomplete)"))) end in @@ -7784,11 +7785,7 @@ and doCondExp local_env asconst end else CEAnd (ce1, ce2)) | CEExp(se1, e1'), CEExp (se2, e2') when theMachine.useLogicalOperators && isEmpty se1 && isEmpty se2 -> - CEExp - (empty, - new_exp ~loc - (BinOp(LAnd, - makeCast e1' intType, makeCast e2' intType, intType))) + CEExp (empty, new_exp ~loc (BinOp(LAnd, e1', e2', intType))) | _ -> CEAnd (ce1, ce2) end @@ -7807,11 +7804,7 @@ and doCondExp local_env asconst end else CEOr (ce1, ce2)) | CEExp (se1, e1'), CEExp (se2, e2') when theMachine.useLogicalOperators && isEmpty se1 && isEmpty se2 -> - CEExp - (empty, - new_exp ~loc - (BinOp(LOr, - makeCast e1' intType, makeCast e2' intType, intType))) + CEExp (empty, new_exp ~loc (BinOp(LOr, e1', e2', intType))) | _ -> CEOr (ce1, ce2) end diff --git a/src/kernel_services/abstract_interp/int_set.ml b/src/kernel_services/abstract_interp/int_set.ml index 41de93a6ba8128241681d3355269f07652180c93..a337b628b848bdcb910ad4827411b6d5290ce3a3 100644 --- a/src/kernel_services/abstract_interp/int_set.ml +++ b/src/kernel_services/abstract_interp/int_set.ml @@ -318,7 +318,7 @@ let apply_bin_1_strict_decr f x (s : Integer.t array) = in c 0 -let apply2_n f (s1 : Integer.t array) (s2 : Integer.t array) = +let apply2 f (s1 : Integer.t array) (s2 : Integer.t array) = let ps = ref empty_ps in let l1 = Array.length s1 in let l2 = Array.length s2 in @@ -588,7 +588,7 @@ let add_singleton = apply_bin_1_strict_incr Int.add let add s1 s2 = match s1, s2 with | [| x |], s | s, [| x |] -> `Set (apply_bin_1_strict_incr Int.add x s) - | _, _ -> apply2_n Int.add s1 s2 + | _, _ -> apply2 Int.add s1 s2 let add_under s1 s2 = match s1, s2 with @@ -619,7 +619,7 @@ let scale f s = let mul s1 s2 = match s1, s2 with | s, [| x |] | [| x |], s -> `Set (scale x s) - | _, _ -> apply2_n Int.mul s1 s2 + | _, _ -> apply2 Int.mul s1 s2 let scale_div ~pos f s = assert (not (Int.is_zero f)); diff --git a/src/kernel_services/abstract_interp/int_set.mli b/src/kernel_services/abstract_interp/int_set.mli index 6b81748ffc17c85e24ec1350c4f765a0af7f1989..a55b2e745b59a1db88dda4958a02c6d84d6d5b1a 100644 --- a/src/kernel_services/abstract_interp/int_set.mli +++ b/src/kernel_services/abstract_interp/int_set.mli @@ -97,6 +97,9 @@ type set_or_top = type set_or_top_or_bottom = [ `Bottom | set_or_top ] +(** [apply2 f s1 s2] applies [f i1 i2] for all integers i1 in s1 and i2 in s2. *) +val apply2: (Integer.t -> Integer.t -> Integer.t) -> t -> t -> set_or_top + (** {2 Lattice structure.} *) val is_included: t -> t -> bool diff --git a/src/kernel_services/abstract_interp/int_val.ml b/src/kernel_services/abstract_interp/int_val.ml index a98c8c40fee00a07cde4017134532cf00c085725..df1e9925d9db5c0e2f8cb9ea0486a9cc8bf71af4 100644 --- a/src/kernel_services/abstract_interp/int_val.ml +++ b/src/kernel_services/abstract_interp/int_val.ml @@ -660,6 +660,8 @@ end module type BitOperator = sig + (* Concrete version of the bitwise operator *) + val concrete_bitwise : Int.t -> Int.t -> Int.t (* Printable version of the operator *) val representation : string (* forward is given here as the lifted function of some bit operator op @@ -682,6 +684,8 @@ end module And : BitOperator = struct + let concrete_bitwise = Int.logand + let representation = "&" let forward v1 v2 = @@ -701,6 +705,8 @@ end module Or : BitOperator = struct + let concrete_bitwise = Int.logor + let representation = "|" let forward v1 v2 = @@ -720,6 +726,8 @@ end module Xor : BitOperator = struct + let concrete_bitwise = Int.logxor + let representation = "^" let forward v1 v2 = @@ -893,7 +901,15 @@ struct acc := List.fold_left (set_bit (Bit i)) [] !acc; if List.length !acc > small_cardinal () then raise Do_not_fit_small_sets done; - let list = List.map (fun (r, _, _) -> r) !acc in + (* Keep only values that can actually be obtained *) + let is_admissible (r, v1, v2) = + match v1, v2 with + | Set s1, Set s2 -> + let op = Op.concrete_bitwise in + Int_set.(exists (fun i1 -> exists (fun i2 -> op i1 i2 = r) s2) s1) + | _, _ -> true + in + let list = Extlib.filter_map is_admissible (fun (r, _, _) -> r) !acc in Set (Int_set.inject_list list) (* If lower is true (resp. false), compute the lower (resp. upper) bound of @@ -936,18 +952,22 @@ struct bound let bitwise_forward (v1 : t) (v2 : t) : t = - let r, modu = compute_modulo v1 v2 in - match result_size v1 v2 with - | None -> - (* We could do better here, as one of the bound may be finite. However, - this case should occur rarely or not at all. *) - inject_interval None None r modu - | Some size -> - try compute_small_set ~size v1 v2 r modu - with Do_not_fit_small_sets -> - let min = compute_bound ~size v1 v2 true - and max = compute_bound ~size v1 v2 false in - inject_interval (Some min) (Some max) r modu + match v1, v2 with + | Set s1, Set s2 -> + inject_set_or_top (Int_set.apply2 Op.concrete_bitwise s1 s2) + | _, _ -> + let r, modu = compute_modulo v1 v2 in + match result_size v1 v2 with + | None -> + (* We could do better here, as one of the bound may be finite. However, + this case should occur rarely or not at all. *) + inject_interval None None r modu + | Some size -> + try compute_small_set ~size v1 v2 r modu + with Do_not_fit_small_sets -> + let min = compute_bound ~size v1 v2 true + and max = compute_bound ~size v1 v2 false in + inject_interval (Some min) (Some max) r modu end let bitwise_or = let module M = BitwiseOperator (Or) in M.bitwise_forward diff --git a/src/kernel_services/ast_data/globals.ml b/src/kernel_services/ast_data/globals.ml index 9e7fc4010aba93779273e9d65cb4fc7d625a29ac..cae5f59e1f52990ea1df0ee8aa9ecab4caddfe69 100644 --- a/src/kernel_services/ast_data/globals.ml +++ b/src/kernel_services/ast_data/globals.ml @@ -359,6 +359,27 @@ module Functions = struct else res + let mem_name fct_name = + try + ignore (find_by_name fct_name); + true + with Not_found -> + false + + let mem_def_name fct_name = + try + ignore (find_def_by_name fct_name); + true + with Not_found -> + false + + let mem_decl_name fct_name = + try + ignore (find_decl_by_name fct_name); + true + with Not_found -> + false + let () = Parameter_builder.find_kf_by_name := find_by_name; Parameter_builder.find_kf_def_by_name := find_def_by_name; @@ -741,10 +762,18 @@ module Types = struct TypeNameToGlobal.mark_as_computed () end + let mem_enum_tag x = + resolve_types (); + Enums.mem x + let find_enum_tag x = resolve_types (); Enums.find x + let mem_type namespace s = + resolve_types (); + Types.mem (s, namespace) + let find_type namespace s = resolve_types (); Types.find (s, namespace) diff --git a/src/kernel_services/ast_data/globals.mli b/src/kernel_services/ast_data/globals.mli index c9866e785bfb78a40bbdb1777676d179c47a94c3..9e5293c20ff883cae5aebbac55abd97051e1e499 100644 --- a/src/kernel_services/ast_data/globals.mli +++ b/src/kernel_services/ast_data/globals.mli @@ -103,6 +103,20 @@ module Functions: sig val get_params: kernel_function -> varinfo list val get_vi: kernel_function -> varinfo + (** {2 Membership} *) + + val mem_name: string -> bool + (** @return [true] iff there is a function with such a name + @since Frama-C+dev *) + + val mem_def_name: string -> bool + (** @return [true] iff there is a function definition with such a name + @since Frama-C+dev *) + + val mem_decl_name: string -> bool + (** @return [true] iff there is a function declaration with such a name + @since Frama-C+dev *) + (** {2 Searching} *) val find_by_name : string -> kernel_function @@ -219,10 +233,20 @@ module Types : sig (** The two functions below are suitable for use in functor {!Logic_typing.Make} *) + val mem_enum_tag: string -> bool + (** @return [true] iff there is an enum constant with the given name in the + AST. + @since Frama-C+dev *) + val find_enum_tag: string -> exp * typ (** Find an enum constant from its name in the AST. @raise Not_found when no such constant exists. *) + val mem_type: Logic_typing.type_namespace -> string -> bool + (** @return [true] iff there is a type with the given name in the given + namespace in the AST. + @since Frama-C+dev *) + val find_type: Logic_typing.type_namespace -> string -> typ (** Find a type from its name in the AST. @raise Not_found when no such type exists. *) diff --git a/src/kernel_services/ast_data/property_status.ml b/src/kernel_services/ast_data/property_status.ml index 441c1594ac728b5cbb08d757ac1ee7eaea8413fa..ea653a36c45d240f33ab4f23cefd7f791e13e4fb 100644 --- a/src/kernel_services/ast_data/property_status.ml +++ b/src/kernel_services/ast_data/property_status.ml @@ -168,6 +168,7 @@ module Status = end) let self = Status.self +let () = Ast.add_monotonic_state self let iter_on_statuses f ip = try @@ -231,6 +232,7 @@ end = struct end) let self = S.self + let () = Ast.add_monotonic_state self let _mem e path = try diff --git a/src/kernel_services/ast_data/statuses_by_call.ml b/src/kernel_services/ast_data/statuses_by_call.ml index 2487ade6c495aebf89aeec1b7caa4891017410ce..24779c450073d235ac72fd02013a219e00163fd9 100644 --- a/src/kernel_services/ast_data/statuses_by_call.ml +++ b/src/kernel_services/ast_data/statuses_by_call.ml @@ -111,23 +111,27 @@ let replacement_visitor ~arguments = object (self) | TVar { lv_origin = Some vinfo } when vinfo.vformal -> if under_label then raise Non_Transposable; begin - let new_term = replace_formal_by_concrete vinfo arguments in - let add_offset lv = TLval (Logic_const.addTermOffsetLval t_offset lv) in - match new_term.term_node with - | TLval lv -> Cil.ChangeDoChildrenPost (add_offset lv, fun x -> x) - | _ -> - if t_offset = TNoOffset - then Cil.ChangeTo new_term.term_node - else - let ltyp = new_term.term_type in - let tmp_lvar = Cil.make_temp_logic_var ltyp in - let tmp_linfo = - { l_var_info = tmp_lvar; l_body = LBterm new_term; - l_type = None; l_tparams = []; l_labels = []; l_profile = []; } - in - let lval_node = TLval (TVar tmp_lvar, t_offset) in - let lval_term = Tlet (tmp_linfo, Logic_const.term lval_node ltyp) in - Cil.ChangeDoChildrenPost (lval_term, fun x -> x) + let post_replace _ = + let new_term = replace_formal_by_concrete vinfo arguments in + let add_offset lv = + TLval (Logic_const.addTermOffsetLval t_offset lv) + in + match new_term.term_node with + | TLval lv -> add_offset lv + | node -> + if t_offset = TNoOffset then node + else + let ltyp = new_term.term_type in + let tmp_lvar = Cil.make_temp_logic_var ltyp in + let tmp_linfo = + { l_var_info = tmp_lvar; l_body = LBterm new_term; + l_type = None; l_tparams = []; l_labels = []; + l_profile = []; } + in + let lval_node = TLval (TVar tmp_lvar, t_offset) in + Tlet (tmp_linfo, Logic_const.term lval_node ltyp) + in + Cil.DoChildrenPost post_replace end | _ -> Cil.DoChildren @@ -149,8 +153,7 @@ let replacement_visitor ~arguments = object (self) | _ -> Cil.DoChildren method! vlogic_label = function - | BuiltinLabel Pre -> - Cil.ChangeDoChildrenPost (Logic_const.here_label, fun x -> x) + | BuiltinLabel Pre -> Cil.DoChildrenPost (fun _ -> Logic_const.here_label) | _ -> Cil.DoChildren end diff --git a/src/kernel_services/ast_printing/cil_printer.ml b/src/kernel_services/ast_printing/cil_printer.ml index 4d3312bae1154f6a0a2ba915bb467a9e8db4e179..28adfb71881021c12926c4b1e354597c83d8448e 100644 --- a/src/kernel_services/ast_printing/cil_printer.ml +++ b/src/kernel_services/ast_printing/cil_printer.ml @@ -93,6 +93,7 @@ let () = register_shallow_attribute Cil.frama_c_ghost_else let () = register_shallow_attribute Cil.frama_c_ghost_formal let () = register_shallow_attribute Cil.frama_c_mutable let () = register_shallow_attribute Cil.frama_c_init_obj +let () = register_shallow_attribute Cil.frama_c_inlined let keep_attr = function | Attr _ as a -> not (List.mem (Cil.attributeName a) !reserved_attributes) diff --git a/src/kernel_services/ast_queries/cil.ml b/src/kernel_services/ast_queries/cil.ml index 544e912ca692472f847d2aa060ffd96c604f2c19..6ec527773bdcea5aa848bc4acbc9610d1a1269e9 100644 --- a/src/kernel_services/ast_queries/cil.ml +++ b/src/kernel_services/ast_queries/cil.ml @@ -605,6 +605,11 @@ let () = registerAttribute frama_c_mutable (AttrName false) let () = registerAttribute (Extlib.strip_underscore frama_c_mutable) (AttrName false) +let frama_c_inlined = "__fc_inlined" +let () = registerAttribute frama_c_inlined (AttrName false) +let () = + registerAttribute (Extlib.strip_underscore frama_c_inlined) (AttrName false) + let unrollType (t: typ) : typ = let rec withAttrs (al: attributes) (t: typ) : typ = match t with @@ -3583,11 +3588,13 @@ let isLongDoubleType t = | TFloat(FLongDouble,_) -> true | _ -> false -let isArithmeticOrPointerType t= +let isScalarType t= match unrollTypeSkel t with | TInt _ | TEnum _ | TFloat _ | TPtr _ -> true | _ -> false +let isArithmeticOrPointerType = isScalarType + let rec isLogicArithmeticType t = match t with | Ctype t -> isArithmeticType t @@ -6186,9 +6193,18 @@ let mkBinOp ~loc op e1 e2 = in constFoldBinOp ~loc machdep op e1 e2 intType in + let check_scalar op e t = + if not (isScalarType t) then + Kernel.fatal ~current:true "operand of %s is not scalar: %a" + op !pp_exp_ref e + in match op with (Mult|Div) -> doArithmetic () - | (Mod|BAnd|BOr|BXor|LAnd|LOr) -> doIntegralArithmetic () + | (Mod|BAnd|BOr|BXor) -> doIntegralArithmetic () + | LAnd | LOr -> + check_scalar "logical operator" e1 t1; + check_scalar "logical operator" e2 t2; + constFoldBinOp ~loc machdep op e1 e2 intType | (Shiftlt|Shiftrt) -> (* ISO 6.5.7. Only integral promotions. The result * has the same type as the left hand side *) if msvcMode () then diff --git a/src/kernel_services/ast_queries/cil.mli b/src/kernel_services/ast_queries/cil.mli index 16dae549fb4dd7a16f26e3e882bc34b7cc5967c9..df110d9e57e479c9d9642a4aa05770c490d6b758 100644 --- a/src/kernel_services/ast_queries/cil.mli +++ b/src/kernel_services/ast_queries/cil.mli @@ -546,8 +546,15 @@ val isLogicRealType: logic_type -> bool floating point *) val isArithmeticType: typ -> bool -(** True if the argument is an arithmetic or pointer type (i.e. integer, enum, - floating point or pointer *) +(** True if the argument is a scalar type (i.e. integral, enum, + floating point or pointer + @since Frama-C+dev +*) +val isScalarType: typ -> bool + +(** alias of isScalarType. + @deprecated Frama-C+dev use isScalarType instead +*) val isArithmeticOrPointerType: typ -> bool (** True if the argument is a logic arithmetic type (i.e. integer, enum or @@ -1241,6 +1248,11 @@ val frama_c_init_obj: string *) val frama_c_mutable: string +(** A block marked with this attribute is known to be inlined, i.e. + it replaces a call to an inline function. +*) +val frama_c_inlined: string + (** [true] if the given lval is allowed to be assigned to thanks to a [frama_c_init_obj] or a [frama_c_mutable] attribute. *) diff --git a/src/kernel_services/ast_queries/file.ml b/src/kernel_services/ast_queries/file.ml index 319f65e11a927a36afa0fcaff587ae6524aa7a0e..5e18e6c1492bb2e7be86a280efd6fb8e69d3aeff 100644 --- a/src/kernel_services/ast_queries/file.ml +++ b/src/kernel_services/ast_queries/file.ml @@ -410,7 +410,7 @@ let safe_remove_file (f : Datatype.Filepath.t) = if not (Kernel.is_debug_key_enabled Kernel.dkey_parser) then Extlib.safe_remove (f :> string) -let build_cpp_cmd cmdl supp_args in_file out_file = +let replace_in_cpp_cmd cmdl supp_args in_file out_file = (* using Filename.quote for filenames which contain space or shell metacharacters *) let in_file = Filename.quote in_file @@ -428,16 +428,10 @@ let build_cpp_cmd cmdl supp_args in_file out_file = ignore (Str.search_forward regexp cmdl 0); (* Try to find one match *) Str.global_substitute regexp substitute cmdl with Not_found -> - Format.sprintf "%s %s -o %s %s" cmdl supp_args out_file in_file + Format.sprintf "%s %s %s -o %s" cmdl supp_args in_file out_file -let parse_cabs = function - | NoCPP f -> - if not (Sys.file_exists (f:>string)) then - Kernel.abort "preprocessed file %a does not exist" - Filepath.Normalized.pretty f; - Kernel.feedback "Parsing %a (no preprocessing)" - Datatype.Filepath.pretty f; - Frontc.parse f () +let build_cpp_cmd = function + | NoCPP _ | External _ -> None | NeedCPP (f, cmdl, is_gnu_like) -> if not (Sys.file_exists (f :> string)) then Kernel.abort "source file %a does not exist" @@ -525,12 +519,24 @@ let parse_cabs = function (Kernel.CppExtraArgs.get () @ extra_args @ supported_cpp_arch_args) include_args define_args in + let cpp_command = replace_in_cpp_cmd cmdl supp_args (f:>string) (ppf:>string) in Kernel.feedback ~dkey:Kernel.dkey_pp - "@{<i>preprocessing@} with \"%s %s %a\"" - cmdl supp_args Filepath.Normalized.pretty f; + "@{<i>preprocessing@} with \"%s\"" + cpp_command; + Some (cpp_command, ppf, supported_cpp_arch_args) + +let parse_cabs cpp_command_no_output = function + | NoCPP f -> + if not (Sys.file_exists (f:>string)) then + Kernel.abort "preprocessed file %a does not exist" + Filepath.Normalized.pretty f; + Kernel.feedback "Parsing %a (no preprocessing)" + Datatype.Filepath.pretty f; + Frontc.parse f () + | NeedCPP (f, cmdl, is_gnu_like) -> + let cpp_command, ppf, supported_cpp_arch_args = Extlib.the cpp_command_no_output in Kernel.feedback "Parsing %a (with preprocessing)" Datatype.Filepath.pretty f; - let cpp_command = build_cpp_cmd cmdl supp_args (f:>string) (ppf:>string) in if Sys.command cpp_command <> 0 then begin safe_remove_file ppf; let possible_cause = @@ -579,7 +585,7 @@ let parse_cabs = function in let ppf' = try Logic_preprocess.file ".c" - (build_cpp_cmd cmdl pp_annot_supp_args) + (replace_in_cpp_cmd cmdl pp_annot_supp_args) (ppf : Filepath.Normalized.t :> string) with Sys_error _ as e -> safe_remove_file ppf; @@ -607,9 +613,10 @@ let parse_cabs = function "could not find a suitable plugin for parsing %a." Filepath.Normalized.pretty f -let to_cil_cabs f = +let to_cil_cabs cpp_cmds_and_args f = try - let a,c = parse_cabs f in + let cpp_command = List.assoc f cpp_cmds_and_args in + let a,c = parse_cabs cpp_command f in Kernel.debug ~dkey:Kernel.dkey_file_print_one "result of parsing %s:@\n%a" (get_name f) Cil_printer.pp_file a; if Errorloc.had_errors () then raise Exit; @@ -630,7 +637,7 @@ let to_cil_cabs f = let () = let handle f = let preprocess = - build_cpp_cmd (fst (get_preprocessor_command ())) "-nostdinc" + replace_in_cpp_cmd (fst (get_preprocessor_command ())) "-nostdinc" in let ppf = try Logic_preprocess.file ".c" preprocess f @@ -667,12 +674,12 @@ let isRoot g = keepTypes | _ -> false -let files_to_cabs_cil files = +let files_to_cabs_cil files cpp_commands = Kernel.feedback ~level:2 "parsing"; (* Parsing and merging must occur in the very same order. Otherwise the order of files on the command line will not be consistently handled. *) - let cil_cabs = List.fold_left (fun acc f -> to_cil_cabs f :: acc) [] files in + let cil_cabs = List.fold_left (fun acc f -> to_cil_cabs cpp_commands f :: acc) [] files in let cil_files, cabs_files = List.split cil_cabs in (* fold_left reverses the list order. This is an issue with pre-registered files. *) @@ -1601,7 +1608,18 @@ let init_cil () = let prepare_from_c_files () = init_cil (); let files = Files.get () in (* Allow pre-registration of prolog files *) - let cil, cabs_files = files_to_cabs_cil files in + let cpp_commands = List.map (fun f -> (f, build_cpp_cmd f)) files in + if Kernel.PrintCppCommands.get () then begin + List.iter (fun (_f, opt_cpp_cmd) -> + match opt_cpp_cmd with + | None -> () + | Some (cpp_cmd, _ppf, _) -> + Kernel.result + "Preprocessing command:@.%s" cpp_cmd + ) cpp_commands; + raise Cmdline.Exit + end; + let cil, cabs_files = files_to_cabs_cil files cpp_commands in prepare_cil_file cil; (* prepare_cil_file may call syntactic transformers, that will ultimately reset the untyped AST. Restore it here. *) diff --git a/src/kernel_services/ast_queries/json_compilation_database.ml b/src/kernel_services/ast_queries/json_compilation_database.ml index 5e0124ac2b1d59fb49d71896598f905243a8cec7..eb529f3c23932565e139de9604c6d29b95bc7f10 100644 --- a/src/kernel_services/ast_queries/json_compilation_database.ml +++ b/src/kernel_services/ast_queries/json_compilation_database.ml @@ -240,7 +240,7 @@ let parse_entry jcdb_dir r = Flags.add path flags let compute_flags_from_file () = - let database = Kernel.JsonCompilationDatabase.get () in + let database = (Kernel.JsonCompilationDatabase.get () :> string) in let jcdb_dir, jcdb_path = if Sys.is_directory database then database, Filename.concat database "compile_commands.json" @@ -264,7 +264,7 @@ let compute_flags_from_file () = Flags.mark_as_computed () let get_flags f = - if Kernel.JsonCompilationDatabase.get () <> "" then begin + if not (Filepath.Normalized.is_unknown (Kernel.JsonCompilationDatabase.get ())) then begin if not (Flags.is_computed ()) then compute_flags_from_file (); try let flags = Flags.find f in diff --git a/src/kernel_services/ast_transformations/inline.ml b/src/kernel_services/ast_transformations/inline.ml index b50798b0e70b5fa79be73f4ff36a9cd19e35fbc3..2c815da3e976eb9279ec522af5bb930e4f6ec7e9 100644 --- a/src/kernel_services/ast_transformations/inline.ml +++ b/src/kernel_services/ast_transformations/inline.ml @@ -260,6 +260,9 @@ let inliner functions_to_inline = object (self) (Extlib.the self#current_kf) callee return_aux args in + let fun_name = Kernel_function.get_name callee in + let new_attribute = (Attr (Cil.frama_c_inlined,[AStr fun_name])) in + block.battrs <- Cil.addAttribute new_attribute block.battrs; let skind = if needs_assign then begin match return_aux, return with diff --git a/src/kernel_services/cmdline_parameters/cmdline.ml b/src/kernel_services/cmdline_parameters/cmdline.ml index 808046e9e9180b7639fc2a73fe8091dfd354cae5..b9e34c5015cb39aed04e9a6ea38d14108cebe7e1 100644 --- a/src/kernel_services/cmdline_parameters/cmdline.ml +++ b/src/kernel_services/cmdline_parameters/cmdline.ml @@ -252,7 +252,11 @@ type option_setting = | Unit of (unit -> unit) | Int of (int -> unit) | String of (string -> unit) - | String_list of (string list -> unit) + +let option_setting_and_warn warn = function + | Unit f -> Unit (fun () -> warn (); f ()) + | Int f -> Int (fun i -> warn (); f i) + | String f -> String (fun s -> warn (); f s) exception Cannot_parse of string * string let raise_error name because = raise (Cannot_parse(name, because)) @@ -310,10 +314,6 @@ let parse known_options_list then_expected options_list = check_string_argname (); f arg; true - | String_list f -> - check_string_argname (); - f (Str.split (Str.regexp "[ \t]*,[ \t]*") arg); - true in unknown_options, use_arg && not explicit, true with Not_found -> @@ -441,7 +441,8 @@ module Plugin: sig val add_group: ?memo:bool -> plugin:string -> string -> string * bool val add_option: string -> group:string -> cmdline_option -> unit val add_aliases: - orig:string -> string -> group:string -> string list -> cmdline_option list + orig:string -> string -> group:string -> ?visible:bool -> ?deprecated:bool + -> string list -> cmdline_option list val replace_option_setting: string -> plugin:string -> group:string -> option_setting -> unit val replace_option_help: @@ -530,7 +531,7 @@ end = struct (* table name_of_the_original_option --> aliases *) let aliases_tbl = Hashtbl.create 7 - let add_aliases ~orig shortname ~group names = + let add_aliases ~orig shortname ~group ?(visible=true) ?(deprecated=false) names = (* mostly inline [add_option] and perform additional actions *) let options_group = find_group shortname group in let option = List.find (fun o -> o.oname = orig) !options_group in @@ -538,7 +539,19 @@ end = struct if name = "" then invalid_arg "empty alias name"; Hashtbl.replace all_options name option; Option_names.add name true; - let alias = { option with oname = name } in + let setting = + if deprecated + then + let warn () = + Kernel_log.warning ~once:true + "@[%s is@ a deprecated alias@ for option %s.@ \ + Please use %s instead.@]" + name option.oname option.oname + in + option_setting_and_warn warn option.setting + else option.setting + in + let alias = { option with oname = name; ovisible = visible; setting; } in options_group := alias :: !options_group; alias in @@ -728,8 +741,8 @@ let add_option_without_action ohelp = help; ext_help = ext_help; ovisible = visible; setting = Unit (fun () -> assert false) } -let add_aliases orig ~plugin ~group stage aliases = - let l = Plugin.add_aliases ~orig plugin ~group aliases in +let add_aliases orig ~plugin ~group ?visible ?deprecated stage aliases = + let l = Plugin.add_aliases ~orig plugin ~group ?visible ?deprecated aliases in let add = match stage with | Early -> Early_Stage.add_for_parsing | Extending -> Extending_Stage.add_for_parsing @@ -896,7 +909,6 @@ let low_print_option_help fmt print_invisible o = | Unit _ -> "" | Int _ -> " <n>" | String _ -> " <s>" - | String_list _ -> " <s1, ..., sn>" else " <" ^ s ^ ">" in @@ -905,7 +917,8 @@ let low_print_option_help fmt print_invisible o = print_helpline fmt (name ^ ty) o.ohelp o.ext_help; List.iter (fun o -> - print_helpline fmt (o.oname ^ ty) ("alias for option " ^ name) "") + if print_invisible || o.ovisible then + print_helpline fmt (o.oname ^ ty) ("alias for option " ^ name) "") (Plugin.find_option_aliases o) end; true diff --git a/src/kernel_services/cmdline_parameters/cmdline.mli b/src/kernel_services/cmdline_parameters/cmdline.mli index db33fb745847cabe9fa7b88dc972026eb8f64eaa..025cb25859989a8d7aaf8889f1ad4ae3d0c8ea16 100644 --- a/src/kernel_services/cmdline_parameters/cmdline.mli +++ b/src/kernel_services/cmdline_parameters/cmdline.mli @@ -270,7 +270,6 @@ type option_setting = | Unit of (unit -> unit) | Int of (int -> unit) | String of (string -> unit) - | String_list of (string list -> unit) val add_option: string -> @@ -314,13 +313,18 @@ val add_aliases: string -> plugin:string -> group:Group.t -> + ?visible: bool -> + ?deprecated: bool -> stage -> string list -> unit (** [add_aliases orig plugin group aliases] adds a list of aliases to the given option name [orig]. + If [visible] is set to false, the aliases do not appear in help messages. + If [deprecated] is set to true, the use of the aliases emits a warning. @Invalid_argument if an alias name is the empty string - @since Carbon-20110201 *) + @since Carbon-20110201 + @modify Frama-c+dev add [visible] and [deprecated] arguments. *) val replace_option_setting: string -> plugin:string -> group:Group.t -> option_setting -> unit diff --git a/src/kernel_services/cmdline_parameters/parameter_builder.ml b/src/kernel_services/cmdline_parameters/parameter_builder.ml index 533be6968e7c37f0b8e0eb30919a465623537770..5675500ced75e97c56b01bcc5e0cf583f2798f12 100644 --- a/src/kernel_services/cmdline_parameters/parameter_builder.ml +++ b/src/kernel_services/cmdline_parameters/parameter_builder.ml @@ -223,14 +223,15 @@ struct ~plugin X.option_name Typed_parameter.ty ~journalize:false p else p - let add_aliases list = - add_aliases list; + let add_aliases ?visible ?deprecated list = + add_aliases ?visible ?deprecated list; match !negative_option_ref with | None -> () | Some negative_option -> let negative_list = List.map negate_name list in let plugin = P.shortname in - Cmdline.add_aliases negative_option ~plugin ~group stage negative_list + Cmdline.add_aliases + negative_option ~plugin ~group ?visible ?deprecated stage negative_list end @@ -1719,8 +1720,8 @@ struct f (); end - let add_aliases list = - add_aliases list; + let add_aliases ?visible ?deprecated list = + add_aliases ?visible ?deprecated list; Output.add_aliases (List.map (fun alias -> alias ^ "-print") list) end diff --git a/src/kernel_services/cmdline_parameters/parameter_sig.mli b/src/kernel_services/cmdline_parameters/parameter_sig.mli index 9ab4f1cca7e940a4f2b0cc4ca127f70c19a78f68..89a439f71b324967ac4c0775bf8eaf4587a86af8 100644 --- a/src/kernel_services/cmdline_parameters/parameter_sig.mli +++ b/src/kernel_services/cmdline_parameters/parameter_sig.mli @@ -179,10 +179,13 @@ module type S_no_parameter = sig val equal: t -> t -> bool - val add_aliases: string list -> unit + val add_aliases: ?visible: bool -> ?deprecated:bool -> string list -> unit (** Add some aliases for this option. That is other option names which have exactly the same semantics that the initial option. - @raise Invalid_argument if one of the strings is empty *) + If [visible] is set to false, the aliases do not appear in help messages. + If [deprecated] is set to true, the use of the aliases emits a warning. + @raise Invalid_argument if one of the strings is empty + @modify Frama-c+dev add [visible] and [deprecated] arguments. *) (**/**) val is_set: unit -> bool diff --git a/src/kernel_services/cmdline_parameters/parameter_state.ml b/src/kernel_services/cmdline_parameters/parameter_state.ml index a61ea576898dec21a9e3a700a6231b9967de394e..8941eec275878ca1c8a2910fbc536089dd161f2a 100644 --- a/src/kernel_services/cmdline_parameters/parameter_state.ml +++ b/src/kernel_services/cmdline_parameters/parameter_state.ml @@ -270,8 +270,9 @@ struct let option_name = X.option_name - let add_aliases = - Cmdline.add_aliases option_name ~plugin:P.shortname ~group stage + let add_aliases ?visible ?deprecated = + Cmdline.add_aliases + option_name ~plugin:P.shortname ~group stage ?visible ?deprecated let print_help fmt = Cmdline.print_option_help fmt ~plugin:P.shortname ~group option_name diff --git a/src/kernel_services/plugin_entry_points/db.ml b/src/kernel_services/plugin_entry_points/db.ml index 9d0a42e6ebda2f54c326da5882d51ae0154901ce..f602bf07dcbe541966723f30099c0e4fd8d7cce7 100644 --- a/src/kernel_services/plugin_entry_points/db.ml +++ b/src/kernel_services/plugin_entry_points/db.ml @@ -526,8 +526,20 @@ module Value = struct let add_formals_to_state = mk_fun "add_formals_to_state" + let get_fundec_from_stmt stmt = + let kf = + try + Kernel_function.find_englobing_kf stmt + with Not_found -> + Kernel.fatal "Unknown statement '%a'" Printer.pp_stmt stmt + in + try + Kernel_function.get_definition kf + with Kernel_function.No_Definition -> + Kernel.fatal "No definition for function %a" Kernel_function.pretty kf + let noassert_get_stmt_state ~after s = - if !no_results (Kernel_function.(get_definition (find_englobing_kf s))) + if !no_results (get_fundec_from_stmt s) then Cvalue.Model.top else let (find, add), find_by_callstack = @@ -586,7 +598,7 @@ module Value = struct exception Is_reachable let is_reachable_stmt stmt = - if !no_results (Kernel_function.(get_definition (find_englobing_kf stmt))) + if !no_results (get_fundec_from_stmt stmt) then true else let ho = try Some (Table_By_Callstack.find stmt) with Not_found -> None in diff --git a/src/kernel_services/plugin_entry_points/db.mli b/src/kernel_services/plugin_entry_points/db.mli index 360b783ab48f9316db4ab3ffdc0212aa2e7e2f76..30c474f13e54fc9f343a44f0492a507f23476459 100644 --- a/src/kernel_services/plugin_entry_points/db.mli +++ b/src/kernel_services/plugin_entry_points/db.mli @@ -1317,8 +1317,7 @@ module Operational_inputs : sig val get_internal_precise: (?stmt:stmt -> kernel_function -> Inout_type.t) ref (** More precise version of [get_internal] function. If [stmt] is specified, and is a possible call to the given kernel_function, - returns the operational inputs for this call (if option -inout-callwise - has been set). *) + returns the operational inputs for this call. *) (**/**) (* Internal use *) diff --git a/src/kernel_services/plugin_entry_points/kernel.ml b/src/kernel_services/plugin_entry_points/kernel.ml index 0d5cfc8f14bd3213c0d186142b7ed97f41605dd9..c4b3ed0833f4d6aad22daa009a0cd4dcf39769bb 100644 --- a/src/kernel_services/plugin_entry_points/kernel.ml +++ b/src/kernel_services/plugin_entry_points/kernel.ml @@ -1002,6 +1002,17 @@ module CppGnuLike = have pre-processing issues with a custom pre-processor." end) +let () = Parameter_customize.set_group parsing +let () = Parameter_customize.do_not_reset_on_copy () +module PrintCppCommands = + False + (struct + let module_name = "PrintCppCommands" + let option_name = "-print-cpp-commands" + let help = "prints the preprocessing command(s) used by Frama-C \ + and exits." + end) + let () = Parameter_customize.set_group parsing let () = Parameter_customize.do_not_reset_on_copy () module FramaCStdLib = @@ -1110,12 +1121,12 @@ module C11 = let () = Parameter_customize.set_group parsing let () = Parameter_customize.do_not_reset_on_copy () module JsonCompilationDatabase = - String + P.Filepath (struct - let module_name = "JsonCompilationDatabase" let option_name = "-json-compilation-database" - let default = "" let arg_name = "path" + let file_kind = "directory or json" + let existence = Filepath.Must_exist let help = "when set, preprocessing of each file will include corresponding \ flags (e.g. -I, -D) from the JSON compilation database \ diff --git a/src/kernel_services/plugin_entry_points/kernel.mli b/src/kernel_services/plugin_entry_points/kernel.mli index c9dae9c7fd2a8eb422b6976f2bce1c8bf15cf982..fd3da8db17cc7c8674824bfa13295693e14ed8d9 100644 --- a/src/kernel_services/plugin_entry_points/kernel.mli +++ b/src/kernel_services/plugin_entry_points/kernel.mli @@ -371,7 +371,7 @@ module UnrollingForce: Parameter_sig.Bool called for well preparing the AST. *) module Machdep: Parameter_sig.String -(** Behavior of invisible option -keep-logical operator: +(** Behavior of invisible option -keep-logical-operators: Tries to avoid converting && and || into conditional statements. Note that this option is incompatible with many (most) plug-ins of the platform and thus should only be enabled with great care and for very @@ -394,6 +394,9 @@ module CppExtraArgsPerFile: Parameter_sig.Filepath_map with type value = string module CppGnuLike: Parameter_sig.Bool (** Behavior of option "-cpp-frama-c-compliant" *) +module PrintCppCommands: Parameter_sig.Bool +(** Behavior of option "-print-cpp-commands" *) + module FramaCStdLib: Parameter_sig.Bool (** Behavior of option "-frama-c-stdlib" *) @@ -465,7 +468,7 @@ module ImplicitFunctionDeclaration: Parameter_sig.String module C11: Parameter_sig.Bool (** Behavior of option "-c11" *) -module JsonCompilationDatabase: Parameter_sig.String +module JsonCompilationDatabase: Parameter_sig.Filepath (** Behavior of option "-json-compilation-database" *) (* ************************************************************************* *) diff --git a/src/kernel_services/plugin_entry_points/log.ml b/src/kernel_services/plugin_entry_points/log.ml index d40ae03aa1d0dff04bf3a7e4b7e9930d0989ff29..aae66eac586ef30524b4a062ecc16adb150dd63e 100644 --- a/src/kernel_services/plugin_entry_points/log.ml +++ b/src/kernel_services/plugin_entry_points/log.ml @@ -71,7 +71,7 @@ type terminal = { mutable delayed : (terminal -> unit) list ; mutable output : string -> int -> int -> unit ; (* Same as Format.make_formatter *) - mutable flush : unit -> unit ; + mutable flush : unit -> unit ; (* Same as Format.make_formatter *) } @@ -90,7 +90,7 @@ let is_ready t = | Locked | DelayedLock -> false | Ready -> true -let term_clean t = +let term_clean t = if t.isatty && not t.clean then begin let u = "\r\027[K" in @@ -126,7 +126,7 @@ let stdout = { let clean () = term_clean stdout -let set_output ?(isatty=false) output flush = +let set_output ?(isatty=false) output flush = set_terminal stdout isatty output flush (* -------------------------------------------------------------------------- *) @@ -204,7 +204,7 @@ let is_prefixed_event = function let is_single_line text = try ignore (String.index_from text 0 '\n') ; false - with Not_found -> true + with Not_found -> true let echo_firstline output text p q width = let t = try String.index_from text p '\n' with Not_found -> succ q in @@ -372,10 +372,13 @@ let () = Array.iteri (* -------------------------------------------------------------------------- *) let all_channels : (string,channelstate) Hashtbl.t = Hashtbl.create 31 -let default_emitters = Array.map (fun _ -> { listeners=[] ; echo=true }) all_kinds +let default_emitters = + Array.map (fun _ -> { listeners=[] ; echo=true }) + all_kinds let new_emitters () = - Array.map (fun e -> { listeners = e.listeners ; echo = e.echo }) default_emitters + Array.map (fun e -> { listeners = e.listeners ; echo = e.echo }) + default_emitters let get_emitters plugin = try @@ -477,6 +480,8 @@ let logtransient channel text = raise e ) buffer text +let locked_listeners = ref false + let logwithfinal finally channel ?(fire=true) (* fire channel listeners *) ?emitwith (* additional emitter *) @@ -498,7 +503,7 @@ let logwithfinal finally channel Format.pp_print_newline fmt () ; Format.pp_print_flush fmt () ; let p,q = Rich_text.trim buffer in - let output = + let output = if p <= q then let source = get_source current source in let message = Rich_text.range buffer p q in @@ -515,7 +520,16 @@ let logwithfinal finally channel if echo && e.echo then do_echo channel.terminal event ; Extlib.may (do_fire event) emitwith; - if fire then List.iter (do_fire event) e.listeners ; + if fire && not !locked_listeners then + begin + try + locked_listeners := true ; + List.iter (do_fire event) e.listeners ; + locked_listeners := false ; + with exn -> + locked_listeners := false ; + raise exn + end ; Some event end else None @@ -586,26 +600,26 @@ let deferred_raise ~fatal ~unreported event msg = logwithfinal finally channel ?append ~kind:event.evt_kind msg let treat_deferred_error () = - match !deferred_exn with - | DNo_exn -> () - | DWarn_as_error event -> - let unreported = unreported_event event in - let wkey = - match event.evt_category with - | None -> "" - | Some s when s = unreported_error -> "" - | Some s -> s - in - deferred_raise ~fatal:false ~unreported event - "warning %s treated as deferred error." wkey - | DError event -> - let unreported = unreported_event event in - deferred_raise ~fatal:false ~unreported event - "Deferred error message was emitted during execution." - | DFatal event -> - let unreported = unreported_event event in - deferred_raise ~fatal:true ~unreported event - "Deferred internal error message was emitted during execution." + match !deferred_exn with + | DNo_exn -> () + | DWarn_as_error event -> + let unreported = unreported_event event in + let wkey = + match event.evt_category with + | None -> "" + | Some s when s = unreported_error -> "" + | Some s -> s + in + deferred_raise ~fatal:false ~unreported event + "warning %s treated as deferred error." wkey + | DError event -> + let unreported = unreported_event event in + deferred_raise ~fatal:false ~unreported event + "Deferred error message was emitted during execution." + | DFatal event -> + let unreported = unreported_event event in + deferred_raise ~fatal:true ~unreported event + "Deferred internal error message was emitted during execution." (* -------------------------------------------------------------------------- *) (* --- Messages Interface --- *) @@ -1242,7 +1256,7 @@ struct with error -> unlock_terminal stdout fmt ; raise error end - else + else Pretty_utils.nullprintf text let pp_all_warn_categories_status () = diff --git a/src/kernel_services/plugin_entry_points/log.mli b/src/kernel_services/plugin_entry_points/log.mli index 9fd4675ec6b7d20a58043141b0257fdb14b50bbf..a01c5b99e605d977136ca4867624ab02c8df0a68 100644 --- a/src/kernel_services/plugin_entry_points/log.mli +++ b/src/kernel_services/plugin_entry_points/log.mli @@ -45,17 +45,17 @@ type 'a pretty_printer = (** Generic type for the various logging channels which are not aborting Frama-C. - - When [current] is [false] (default for most of the channels), - no location is output. When it is [true], the last registered location - is used as current (see {!Cil_const.CurrentLoc}). + - When [current] is [false] (default for most of the channels), + no location is output. When it is [true], the last registered location + is used as current (see {!Cil_const.CurrentLoc}). - [source] is the location to be output. If nil, [current] is used to - determine if a location should be output + determine if a location should be output - [emitwith] function which is called each time an event is processed - [echo] is [true] if the event should be output somewhere in addition - to [stdout] + to [stdout] - [append] adds some actions performed on the formatter after the event - has been processed. - @since Beryllium-20090601-beta1 *) + has been processed. + @since Beryllium-20090601-beta1 *) type ('a,'b) pretty_aborter = ?current:bool -> ?source:Filepath.position -> ?echo:bool -> @@ -120,7 +120,7 @@ module type Messages = sig type category (** category for debugging/verbose messages. Must be registered before - any use. + any use. Each column in the string defines a sub-category, e.g. a:b:c defines a subcategory c of b, which is itself a subcategory of a. Enabling a category (via -plugin-msg-category) will enable all its @@ -140,7 +140,7 @@ module type Messages = sig val debug_atleast : int -> bool (** @since Beryllium-20090601-beta1 *) - val printf : ?level:int -> ?dkey:category -> + val printf : ?level:int -> ?dkey:category -> ?current:bool -> ?source:Filepath.position -> ?append:(Format.formatter -> unit) -> ?header:(Format.formatter -> unit) -> @@ -202,7 +202,7 @@ module type Messages = sig [false]. The intended usage is: [assert (verify e "Bla...") ;]. - @since Beryllium-20090601-beta1 + @since Beryllium-20090601-beta1 @plugin development guide *) val not_yet_implemented : ('a,formatter,unit,'b) format4 -> 'a @@ -242,13 +242,13 @@ module type Messages = sig (** Generic log routine. The default kind is [Result]. Use cases (with [n,m > 0]): - [log ~verbose:n]: emit the message only when verbosity level is - at least [n]. + at least [n]. - [log ~debug:n]: emit the message only when debugging level is - at least [n]. + at least [n]. - [log ~verbose:n ~debug:m]: any debugging or verbosity level is - sufficient. - @since Beryllium-20090901 - @plugin development guide *) + sufficient. + @since Beryllium-20090901 + @plugin development guide *) val logwith : (event option -> 'b) -> ?wkey:warn_category -> ?emitwith:(event -> unit) -> ?once:bool -> @@ -397,14 +397,18 @@ module Register val set_echo : ?plugin:string -> ?kind:kind list -> bool -> unit (** Turns echo on or off. Applies to all channel unless specified, and all kind of messages unless specified. - @since Beryllium-20090601-beta1 + @since Beryllium-20090601-beta1 @plugin development guide *) val add_listener : ?plugin:string -> ?kind:kind list -> (event -> unit) -> unit (** Register a hook that is called each time an event is emitted. Applies to all channel unless specified, and all kind of messages unless specified. - @since Beryllium-20090601-beta1 + + Warning: when executing the listener, all listeners will be + temporarily deactivated in order to avoid infinite recursion. + + @since Beryllium-20090601-beta1 @plugin development guide *) val echo : event -> unit @@ -426,7 +430,7 @@ type channel (** @since Beryllium-20090601-beta1 *) val new_channel : string -> channel -(** @since Beryllium-20090901 +(** @since Beryllium-20090901 @plugin development guide *) val log_channel : channel -> @@ -447,7 +451,7 @@ val kernel_label_name: string val source : file:Filepath.Normalized.t -> line:int -> Filepath.position (** @since Chlorine-20180501 @modify 18.0-Argon change type of [file] - *) +*) val get_current_source : unit -> Filepath.position @@ -463,7 +467,7 @@ val clean : unit -> unit val null : formatter [@@ deprecated "Use 'Pretty_utils.null' instead"] (** Prints nothing. - @since Beryllium-20090901 + @since Beryllium-20090901 @deprecated Chlorine-20180501 use {!Pretty_utils} instead. *) val nullprintf : ('a,formatter,unit) format -> 'a @@ -480,7 +484,7 @@ val with_null : (unit -> 'b) -> ('a,formatter,unit,'b) format4 -> 'a val set_output : ?isatty:bool -> (string -> int -> int -> unit) -> (unit -> unit) -> unit (** This function has the same parameters as Format.make_formatter. - @since Beryllium-20090901 + @since Beryllium-20090901 @plugin development guide *) val print_on_output : (Format.formatter -> unit) -> unit @@ -490,8 +494,8 @@ val print_on_output : (Format.formatter -> unit) -> unit Notification of listeners is not delayed, however. Can not be recursively invoked. - @since Beryllium-20090901 - @modify Nitrogen-20111001 signature changed + @since Beryllium-20090901 + @modify Nitrogen-20111001 signature changed @plugin development guide *) val print_delayed : (Format.formatter -> unit) -> unit @@ -502,7 +506,7 @@ val print_delayed : (Format.formatter -> unit) -> unit Can not be recursively invoked. @since Beryllium-20090901 - @modify Nitrogen-20111001 signature changed + @modify Nitrogen-20111001 signature changed @plugin development guide *) (**/**) @@ -528,7 +532,7 @@ val treat_deferred_error: unit -> unit a delayed error or failure. Currently done: - after each command-line stage. - after each analysis step (as separated by -then and its derivatives), - including the last one. + including the last one. *) (**/**) diff --git a/src/kernel_services/plugin_entry_points/plugin.ml b/src/kernel_services/plugin_entry_points/plugin.ml index 06ec07489dc851480fc9b9964637474f4ba26b4c..067694ad12cb107d320981e31c57ea563506903a 100644 --- a/src/kernel_services/plugin_entry_points/plugin.ml +++ b/src/kernel_services/plugin_entry_points/plugin.ml @@ -44,7 +44,8 @@ module type S_no_log = sig module Config: Parameter_sig.Specific_dir val help: Cmdline.Group.t val messages: Cmdline.Group.t - val add_plugin_output_aliases: string list -> unit + val add_plugin_output_aliases: + ?visible:bool -> ?deprecated:bool -> string list -> unit end module type S = sig @@ -795,14 +796,14 @@ struct let is_kernel = is_kernel () in Warn_category.add_set_hook (parse_warn_directives is_kernel) - let add_plugin_output_aliases aliases = + let add_plugin_output_aliases ?visible ?deprecated aliases = let aliases = List.filter (fun alias -> alias <> "") aliases in let optname suffix = List.map (fun alias -> "-" ^ alias ^ suffix) aliases in - Help.add_aliases (optname "-help"); - Verbose.add_aliases (optname "-verbose"); - Debug_category.add_aliases (optname "-msg-key"); - Warn_category.add_aliases (optname "-warn-key"); - LogToFile.add_aliases (optname "-log") + Help.add_aliases ?visible ?deprecated (optname "-help"); + Verbose.add_aliases ?visible ?deprecated (optname "-verbose"); + Debug_category.add_aliases ?visible ?deprecated (optname "-msg-key"); + Warn_category.add_aliases ?visible ?deprecated (optname "-warn-key"); + LogToFile.add_aliases ?visible ?deprecated (optname "-log") let () = reset_plugin () diff --git a/src/kernel_services/plugin_entry_points/plugin.mli b/src/kernel_services/plugin_entry_points/plugin.mli index a5e41ee354ec50753ba9200ccb84281524757210..16c14c026ae910efbfd982597627c683983bf5ba 100644 --- a/src/kernel_services/plugin_entry_points/plugin.mli +++ b/src/kernel_services/plugin_entry_points/plugin.mli @@ -64,12 +64,14 @@ module type S_no_log = sig (** The group containing options -*-debug and -*-verbose. @since Boron-20100401 *) - val add_plugin_output_aliases: string list -> unit - (** Adds aliases to the options -plugin-help, -plugin-verbose, -plugin-log, - -plugin-msg-key, and -plugin-warn-key. - [add_plugin_output_aliases [alias]] adds the aliases -alias-help, - -alias-verbose, etc. - @since 18.0-Argon *) + val add_plugin_output_aliases: + ?visible:bool -> ?deprecated:bool -> string list -> unit + (** Adds aliases to the options -plugin-help, -plugin-verbose, -plugin-log, + -plugin-msg-key, and -plugin-warn-key. + [add_plugin_output_aliases [alias]] adds the aliases -alias-help, + -alias-verbose, etc. + @since 18.0-Argon + @modify Frama-c+dev add [visible] and [deprecated] arguments. *) end (** Provided plug-general services for plug-ins. diff --git a/src/libraries/utils/filepath.ml b/src/libraries/utils/filepath.ml index 4e5a859748ce24d79b52a441a180bfe9b23d351f..4e02418356f54681e995a49fb8bb5a9baca1d319 100644 --- a/src/libraries/utils/filepath.ml +++ b/src/libraries/utils/filepath.ml @@ -252,6 +252,10 @@ module Normalized = struct let pp_abs fmt p = Format.fprintf fmt "%s" p let unknown = normalize "" let is_unknown fp = equal fp unknown + let is_file fp = + try + (Unix.stat (fp :> string)).Unix.st_kind = Unix.S_REG + with _ -> false end type position = diff --git a/src/libraries/utils/filepath.mli b/src/libraries/utils/filepath.mli index 39c084bffa8cecef1fb71baca36e9870c5d834c1..41c56ec816717618e136353f659045276feadad5 100644 --- a/src/libraries/utils/filepath.mli +++ b/src/libraries/utils/filepath.mli @@ -144,6 +144,12 @@ module Normalized: sig (** @since 20.0-Calcium *) val is_unknown: t -> bool + + (** [is_file f] returns [true] iff [f] points to a regular file + (or a symbolic link pointing to a file). + Returns [false] if any errors happen when [stat]'ing the file. + @since Frama-C+dev *) + val is_file: t -> bool end (** Describes a position in a source file. diff --git a/src/plugins/aorai/aorai_option.ml b/src/plugins/aorai/aorai_option.ml index 850d0efb9068ee5b2b337cb725369ba283ac8f74..1dfe1a0504a9c33546d943fe3705f79c97373bf9 100644 --- a/src/plugins/aorai/aorai_option.ml +++ b/src/plugins/aorai/aorai_option.ml @@ -31,36 +31,44 @@ include Plugin.Register end) module Ltl_File = - Empty_string + Filepath (struct let option_name = "-aorai-ltl" let arg_name = "" + let file_kind = "ltl" + let existence = Fc_Filepath.Must_exist let help = "specifies file name for LTL property" end) module To_Buchi = - Empty_string + Filepath (struct let option_name = "-aorai-to-buchi" let arg_name = "f" + let file_kind = "Promela" + let existence = Fc_Filepath.Indifferent let help = "only generates the buchi automata (in Promela language) in file <s>" end) module Buchi = - Empty_string + Filepath (struct let option_name = "-aorai-buchi" let arg_name = "f" + let file_kind = "Promela" + let existence = Fc_Filepath.Must_exist let help = "considers the property described by the buchi automata \ (in Promela language) from file <f>." end) module Ya = - Empty_string + Filepath (struct let option_name = "-aorai-automata" let arg_name = "f" + let file_kind = "Ya" + let existence = Fc_Filepath.Must_exist let help = "considers the property described by the ya automata \ (in Ya language) from file <f>." end) @@ -74,10 +82,12 @@ module Output_Spec = end) module Output_C_File = - Empty_string + Filepath (struct let option_name = "-aorai-output-c-file" let arg_name = "" + let file_kind = "annotated C" + let existence = Fc_Filepath.Indifferent let help = "specifies generated file name for annotated C code" end) @@ -155,7 +165,7 @@ let is_on () = Buchi.is_default () && Ya.is_default () ) let promela_file () = - if Buchi.get () = "" then To_Buchi.get () else Buchi.get () + if Fc_Filepath.Normalized.is_unknown (Buchi.get ()) then To_Buchi.get () else Buchi.get () let advance_abstract_interpretation () = not (AbstractInterpretationOff.get ()) && not (AbstractInterpretation.get ()) diff --git a/src/plugins/aorai/aorai_option.mli b/src/plugins/aorai/aorai_option.mli index 66037798612cfea8300cd165c375b650f76d41b9..111cf0e74ea3f7ac344cb47ffd02be462f11734c 100644 --- a/src/plugins/aorai/aorai_option.mli +++ b/src/plugins/aorai/aorai_option.mli @@ -25,12 +25,12 @@ include Plugin.S -module Ltl_File: Parameter_sig.String -module To_Buchi: Parameter_sig.String -module Buchi: Parameter_sig.String -module Ya: Parameter_sig.String +module Ltl_File: Parameter_sig.Filepath +module To_Buchi: Parameter_sig.Filepath +module Buchi: Parameter_sig.Filepath +module Ya: Parameter_sig.Filepath module Output_Spec: Parameter_sig.Bool -module Output_C_File: Parameter_sig.String +module Output_C_File: Parameter_sig.Filepath module Dot: Parameter_sig.Bool module DotSeparatedLabels: Parameter_sig.Bool module AbstractInterpretation: Parameter_sig.Bool @@ -44,7 +44,7 @@ module AddingOperationNameAndStatusInSpecification: Parameter_sig.Bool module Deterministic: State_builder.Ref with type data = bool val is_on : unit -> bool -val promela_file: unit -> string +val promela_file: unit -> Filepath.Normalized.t val advance_abstract_interpretation: unit -> bool val emitter: Emitter.t diff --git a/src/plugins/aorai/aorai_register.ml b/src/plugins/aorai/aorai_register.ml index a9c5a2bcd068e6efecf8f92a956e28d7e7bf24e7..664f3289886e08fbe4ea271b3460dbfd5f3ba63f 100644 --- a/src/plugins/aorai/aorai_register.ml +++ b/src/plugins/aorai/aorai_register.ml @@ -27,13 +27,12 @@ open Logic_ptree open Promelaast (* [VP] Need to get rid of those global references at some point. *) -let promela_file = ref "" -let ya_file = ref "" -let c_file = ref "" -let output_c_file = ref "" -let ltl_tmp_file = ref "" -let ltl_file = ref "" -let dot_file = ref "" +let promela_file = ref Filepath.Normalized.unknown +let c_file = ref Filepath.Normalized.unknown +let output_c_file = ref Filepath.Normalized.unknown +let ltl_tmp_file = ref Filepath.Normalized.unknown +let ltl_file = ref Filepath.Normalized.unknown +let dot_file = ref Filepath.Normalized.unknown let generatesCFile = ref true let ltl2ba_params = " -l -p -o " @@ -81,63 +80,66 @@ let syntax_error loc msg = ((snd loc).Lexing.pos_cnum - (fst loc).Lexing.pos_bol) msg -let ltl_to_ltlLight f_ltl f_out = +(* Performs some checks before calling [open_in f], reporting ["errmsg: <f>"] + in case of error. *) +let check_and_open_in (f : Filepath.Normalized.t) errmsg = + if not (Filepath.Normalized.is_file f) then + Aorai_option.abort "%s: %a" errmsg Filepath.Normalized.pretty f; + open_in (f :> string) + +let ltl_to_ltlLight f_ltl (f_out : Filepath.Normalized.t) = try - let c = open_in f_ltl in + let c = check_and_open_in f_ltl "invalid LTL file" in let (ltl_form,exprs) = Ltllexer.parse c in close_in c; - Ltl_output.output ltl_form f_out; + Ltl_output.output ltl_form (f_out :> string); set_ltl_correspondence exprs - with - | Not_found -> Aorai_option.abort "Unknown LTL file %s" f_ltl - | Ltllexer.Error (loc,msg) -> syntax_error loc msg + with + | Ltllexer.Error (loc,msg) -> syntax_error loc msg -let load_ya_file f = +let load_ya_file f = try - let c = open_in f in + let c = check_and_open_in f "invalid Ya file" in let automata = Yalexer.parse c in close_in c; Data_for_aorai.setAutomata automata; with - | Not_found -> Aorai_option.abort "Unknown Ya file %s" f - | Yalexer.Error (loc,msg) -> syntax_error loc msg + | Yalexer.Error (loc,msg) -> syntax_error loc msg let load_promela_file f = try - let c = open_in f in + let c = check_and_open_in f "invalid Promela file" in let (s,t) = Promelalexer.parse c in let t = convert_ltl_exprs t in close_in c; Data_for_aorai.setAutomata (s,t); with - | Not_found -> Aorai_option.abort "Unknown Promela file %s" f - | Promelalexer.Error(loc,msg) -> syntax_error loc msg + | Promelalexer.Error(loc,msg) -> syntax_error loc msg -let load_promela_file_withexps f = +let load_promela_file_withexps f = try - let c = open_in f in + let c = check_and_open_in f "invalid Promela file" in let automata = Promelalexer_withexps.parse c in close_in c; Data_for_aorai.setAutomata automata; with - | Not_found -> Aorai_option.abort "Unknown Promela file %s" f - | Promelalexer_withexps.Error(loc,msg) -> syntax_error loc msg + | Promelalexer_withexps.Error(loc,msg) -> syntax_error loc msg let display_status () = if Aorai_option.verbose_atleast 2 then begin Aorai_option.feedback "\n" ; - Aorai_option.feedback "C file: '%s'\n" !c_file ; + Aorai_option.feedback "C file: '%a'\n" Filepath.Normalized.pretty !c_file ; Aorai_option.feedback "Entry point: '%a'\n" Kernel_function.pretty (fst (Globals.entry_point())) ; - Aorai_option.feedback "LTL property: '%s'\n" !ltl_file ; - Aorai_option.feedback "Files to generate: '%s' (Annotated code)\n" - (if !generatesCFile then !output_c_file else "(none)"); + Aorai_option.feedback "LTL property: '%a'\n" Filepath.Normalized.pretty !ltl_file ; + Aorai_option.feedback "Files to generate: '%a' (Annotated code)\n" + (if !generatesCFile then Filepath.Normalized.pretty else (fun fmt _ -> Format.fprintf fmt "(none)")) !output_c_file; if Aorai_option.Dot.get () then - Aorai_option.feedback "Dot file: '%s'\n" !dot_file; - Aorai_option.feedback "Tmp files: '%s' (Light LTL file)\n" - !ltl_tmp_file ; - Aorai_option.feedback " '%s' (Promela file)\n" - !promela_file ; + Aorai_option.feedback "Dot file: '%a'\n" Filepath.Normalized.pretty !dot_file; + Aorai_option.feedback "Tmp files: '%a' (Light LTL file)\n" + Filepath.Normalized.pretty !ltl_tmp_file ; + Aorai_option.feedback " '%a' (Promela file)\n" + Filepath.Normalized.pretty !promela_file ; Aorai_option.feedback "\n" end @@ -146,10 +148,13 @@ let init_file_names () = generation *) let err= ref false in let dispErr mesg f = - Aorai_option.error "Error. File '%s' %s.\n" f mesg; + Aorai_option.error "Error. File '%a' %s.\n" Filepath.Normalized.pretty f mesg; err:=true in - let freshname pre suf = + let freshname ?opt_suf file suf = + let name = Filepath.Normalized.to_pretty_string file in + let pre = Filename.remove_extension name in + let pre = match opt_suf with None -> pre | Some s -> pre ^ s in let rec fn p s n = if not (Sys.file_exists (p^(string_of_int n)^s)) then (p^(string_of_int n)^s) else fn p s (n+1) @@ -157,55 +162,52 @@ let init_file_names () = let name = if not (Sys.file_exists (pre^suf)) then pre^suf else fn pre suf 0 - in name + in Filepath.Normalized.of_string name in (* c_file name is given and has to point out a valid file. *) c_file := (match Kernel.Files.get () with - | [] -> "dummy.i" - | f :: _ -> Filepath.Normalized.to_pretty_string f); - if (!c_file="") then dispErr ": invalid C file name" !c_file; - if (not (Sys.file_exists !c_file)) then dispErr "not found" !c_file; + | [] -> Filepath.Normalized.of_string "dummy.i" + | f :: _ -> f); + if (Filepath.Normalized.is_unknown !c_file) then dispErr ": invalid C file name" !c_file; (* The output C file has to be a valid file name if it is used. *) - output_c_file := (Aorai_option.Output_C_File.get ()) ; - if (!output_c_file="") then output_c_file:=freshname ((Filename.chop_extension !c_file)^"_annot") ".c"; + output_c_file := Aorai_option.Output_C_File.get (); + if (Filepath.Normalized.is_unknown !output_c_file) then + output_c_file := freshname ~opt_suf:"_annot" !c_file ".c"; (* else if Sys.file_exists !output_c_file then dispErr "already exists" !output_c_file; *) if Aorai_option.Dot.get () then - dot_file:=freshname (Filename.chop_extension !c_file) ".dot"; + dot_file:= freshname !c_file ".dot"; - if Aorai_option.Ya.get () = "" then - if Aorai_option.Buchi.get () = "" then begin + if Filepath.Normalized.is_unknown (Aorai_option.Ya.get ()) then + if Filepath.Normalized.is_unknown (Aorai_option.Buchi.get ()) then begin (* ltl_file name is given and has to point out a valid file. *) ltl_file := Aorai_option.Ltl_File.get (); - if (!ltl_file="") then dispErr ": invalid LTL file name" !ltl_file; - if (not (Sys.file_exists !ltl_file)) then dispErr "not found" !ltl_file; (* The LTL file is always used. *) (* The promela file can be given or not. *) - if Aorai_option.To_Buchi.get () <> "" then begin + if not (Filepath.Normalized.is_unknown (Aorai_option.To_Buchi.get ())) then begin ltl_tmp_file:= - freshname - (Filename.chop_extension - (Aorai_option.promela_file ())) ".ltl"; + freshname (Aorai_option.promela_file ()) ".ltl"; promela_file:= Aorai_option.promela_file (); - Extlib.cleanup_at_exit !ltl_tmp_file + Extlib.cleanup_at_exit (!ltl_tmp_file :> string) end else begin ltl_tmp_file:= (try - Extlib.temp_file_cleanup_at_exit - (Filename.basename !c_file) ".ltl" + Filepath.Normalized.of_string + (Extlib.temp_file_cleanup_at_exit + (Filename.basename (!c_file:>string)) ".ltl") with Extlib.Temp_file_error s -> Aorai_option.abort "cannot create temporary file: %s" s); promela_file:= - freshname (Filename.chop_extension !ltl_tmp_file) ".promela"; - Extlib.cleanup_at_exit !promela_file; + freshname !ltl_tmp_file ".promela"; + Extlib.cleanup_at_exit (!promela_file :> string); end end else begin - if Aorai_option.To_Buchi.get () <> "" && - Aorai_option.Ltl_File.get () <> "" + if not (Filepath.Normalized.is_unknown (Aorai_option.To_Buchi.get ())) && + not (Filepath.Normalized.is_unknown (Aorai_option.Ltl_File.get ())) then begin Aorai_option.error "Error. '-buchi' option is incompatible with '-to-buchi' and '-ltl' \ @@ -217,9 +219,8 @@ options."; promela_file := Aorai_option.promela_file (); end else begin - ya_file := Aorai_option.Ya.get (); - if (!ya_file="") then dispErr ": invalid Ya file name" !ya_file; - if (not (Sys.file_exists !ya_file)) then dispErr "not found" !ya_file + let ya_file = Aorai_option.Ya.get () in + if (Filepath.Normalized.is_unknown ya_file) then dispErr ": invalid Ya file name" ya_file; end; display_status (); !err @@ -236,7 +237,7 @@ let output () = if (Aorai_option.Dot.get()) then begin Promelaoutput.output_dot_automata (Data_for_aorai.getAutomata ()) - !dot_file; + (!dot_file:>string); printverb "Generating dot file : done\n" end; @@ -245,7 +246,7 @@ let output () = printverb "C file generation : skipped\n" else begin - let cout = open_out !output_c_file in + let cout = open_out (!output_c_file:>string) in let fmt = Format.formatter_of_out_channel cout in Kernel.Unicode.without_unicode (fun () -> @@ -258,33 +259,35 @@ let output () = printverb "Finished.\n"; (* Some test traces. *) Data_for_aorai.debug_computed_state (); - if !generatesCFile then Kernel.Files.set [ Datatype.Filepath.of_string !output_c_file ] + if !generatesCFile then Kernel.Files.set [ !output_c_file ] let work () = let file = Ast.get () in Aorai_utils.initFile file; printverb "C file loading : done\n"; - if Aorai_option.Ya.get () = "" then - if Aorai_option.Buchi.get () = "" then begin + if Filepath.Normalized.is_unknown (Aorai_option.Ya.get ()) then + if Filepath.Normalized.is_unknown (Aorai_option.Buchi.get ()) then begin ltl_to_ltlLight !ltl_file !ltl_tmp_file; printverb "LTL loading : done\n"; - let cmd = Format.sprintf "ltl2ba %s -F %s > %s" - ltl2ba_params !ltl_tmp_file !promela_file + let cmd = Format.asprintf "ltl2ba %s -F %a > %a" + ltl2ba_params + Filepath.Normalized.pretty !ltl_tmp_file + Filepath.Normalized.pretty !promela_file in if Sys.command cmd <> 0 then Aorai_option.abort "failed to run: %s" cmd ; printverb "LTL ~> Promela (ltl2ba): done\n" end; - if Aorai_option.To_Buchi.get () <> "" then - printverb ("Finished.\nGenerated file: '"^(!promela_file)^"'\n") + if not (Filepath.Normalized.is_unknown (Aorai_option.To_Buchi.get ())) then + printverb ("Finished.\nGenerated file: '"^(Filepath.Normalized.to_pretty_string !promela_file)^"'\n") else begin (* Step 3 : Loading promela_file and checking the consistency between informations from C code and LTL property *) (* Such as functions name and global variables. *) - if Aorai_option.Buchi.get () <> "" then + if not (Filepath.Normalized.is_unknown (Aorai_option.Buchi.get ())) then load_promela_file_withexps !promela_file - else if Aorai_option.Ya.get () <> "" then - load_ya_file !ya_file + else if not (Filepath.Normalized.is_unknown (Aorai_option.Ya.get ())) then + load_ya_file (Aorai_option.Ya.get ()) else load_promela_file !promela_file; printverb "Loading promela : done\n"; diff --git a/src/plugins/aorai/tests/aorai/assigns.c b/src/plugins/aorai/tests/aorai/assigns.c index c8d63fdb9dba75b9fb13a0021f32cf20f1435241..843e5dd51192b344faa975e2e7cf0ffc85e39ae2 100644 --- a/src/plugins/aorai/tests/aorai/assigns.c +++ b/src/plugins/aorai/tests/aorai/assigns.c @@ -1,8 +1,8 @@ /* run.config* - EXECNOW: make -s @PTEST_DIR@/name_projects.cmxs OPT: -aorai-automata tests/aorai/assigns.ya -aorai-test 1 -load-module tests/aorai/Aorai_test.cmxs -aorai-test-number @PTEST_NUMBER@ @PROVE_OPTIONS@ OPT: -aorai-automata tests/aorai/assigns_det.ya -aorai-test 1 -load-module tests/aorai/Aorai_test.cmxs -aorai-test-number @PTEST_NUMBER@ @PROVE_OPTIONS@ - OPT: -aorai-automata tests/aorai/assigns.ya -load-module @PTEST_DIR@/name_projects -aorai-test 1 -then -print + MODULE: @PTEST_DIR@/name_projects.cmxs + OPT: -aorai-automata tests/aorai/assigns.ya -aorai-test 1 -then -print */ int X; diff --git a/src/plugins/e-acsl/Makefile.in b/src/plugins/e-acsl/Makefile.in index e7380d160ca17283c96d9b3684fdb3a4a7bc0d2c..06edca935965881a93c24f23401dc0211922ed8e 100644 --- a/src/plugins/e-acsl/Makefile.in +++ b/src/plugins/e-acsl/Makefile.in @@ -44,6 +44,13 @@ SRC_LIBRARIES:= \ varname SRC_LIBRARIES:=$(addprefix src/libraries/, $(SRC_LIBRARIES)) +# project initializer +SRC_PROJECT_INITIALIZER:= \ + rtl \ + prepare_ast +SRC_PROJECT_INITIALIZER:=\ + $(addprefix src/project_initializer/, $(SRC_PROJECT_INITIALIZER)) + # analyses SRC_ANALYSES:= \ rte \ @@ -55,16 +62,10 @@ SRC_ANALYSES:= \ typing SRC_ANALYSES:=$(addprefix src/analyses/, $(SRC_ANALYSES)) -# project initializer -SRC_PROJECT_INITIALIZER:= \ - keep_status \ - prepare_ast -SRC_PROJECT_INITIALIZER:=\ - $(addprefix src/project_initializer/, $(SRC_PROJECT_INITIALIZER)) - # code generator SRC_CODE_GENERATOR:= \ - constructor \ + smart_exp \ + smart_stmt \ gmp \ label \ env \ @@ -74,6 +75,7 @@ SRC_CODE_GENERATOR:= \ at_with_lscope \ mmodel_translate \ logic_functions \ + logic_array \ translate \ temporal \ memory_observer \ @@ -99,8 +101,8 @@ PLUGIN_NAME:=E_ACSL PLUGIN_CMO:= src/local_config \ src/options \ $(SRC_LIBRARIES) \ - $(SRC_ANALYSES) \ $(SRC_PROJECT_INITIALIZER) \ + $(SRC_ANALYSES) \ $(SRC_CODE_GENERATOR) \ src/main diff --git a/src/plugins/e-acsl/doc/Changelog b/src/plugins/e-acsl/doc/Changelog index d32d106def951ea26c47935ac6322519fd02208d..541d6252e8d8b64cc742d235bc164582829e1afc 100644 --- a/src/plugins/e-acsl/doc/Changelog +++ b/src/plugins/e-acsl/doc/Changelog @@ -25,20 +25,24 @@ Plugin E-ACSL <next-release> ############################ -- E-ACSL [2020-07-28] Add support of bitwise operators. - (frama-c/e-acsl#33) --* E-ACSL [2020-07-20] Fix unstable order of generated globals. - (frama-c/e-acsl#124) --* E-ACSL [2020-07-10] Fix translation of trange (incorrect length). --* E-ACSL [2020-07-09] Decrease the number of allocated blocks when one - block is freed. +-* E-ACSL [2020-08-28] Fix crash that may occur when translating + properties that have been proved valid by another plug-in + (frama-c/e-acsl#106). +-! E-ACSL [2020-08-28] Remove option -e-acsl-prepare-ast. +-! E-ACSL [2020-08-28] Remove option -e-acsl-check. +- E-ACSL [2020-08-07] Add support for logical array comparison + (frama-c/e-acsl#99). +- E-ACSL [2020-07-28] Add support of bitwise operators + (frama-c/e-acsl#33). +-* E-ACSL [2020-07-20] Fix unstable order of generated globals + (frama-c/e-acsl#124). -* E-ACSL [2020-07-10] Fix translation of trange (incorrect length). -* E-ACSL [2020-07-09] Decrease the number of allocated blocks when one block is freed. - E-ACSL [2020-06-19] Add support to create GMP rational from GMP - integer. (frama-c/e-acsl#120) --* E-ACSL [2020-06-18] Fix support of VLA memory tracking. - (frama-c/e-acsl#119) + integer (frama-c/e-acsl#120). +-* E-ACSL [2020-06-18] Fix support of VLA memory tracking + (frama-c/e-acsl#119). ############################# Plugin E-ACSL 21.0 (Scandium) diff --git a/src/plugins/e-acsl/doc/refman/changes_modern.tex b/src/plugins/e-acsl/doc/refman/changes_modern.tex index 4266ddd7e32525ee9990447e923a4d91831c2c42..4f0069fb4e7c0d7e473ef5906dc90906f4b35de0 100644 --- a/src/plugins/e-acsl/doc/refman/changes_modern.tex +++ b/src/plugins/e-acsl/doc/refman/changes_modern.tex @@ -128,6 +128,7 @@ in \lstinline|\\at|} \begin{itemize} \item \changeinsection{expressions}{support of bitwise operations} +\item \changeinsection{aggregates}{support of logic arrays} \end{itemize} \subsection*{Version Scandium-21} diff --git a/src/plugins/e-acsl/doc/refman/speclang_modern.tex b/src/plugins/e-acsl/doc/refman/speclang_modern.tex index df96f85ecbf85ece5c33083aace3c1af24a8f013..686b9c95d324a5d4874fc700060a33647aed493d 100644 --- a/src/plugins/e-acsl/doc/refman/speclang_modern.tex +++ b/src/plugins/e-acsl/doc/refman/speclang_modern.tex @@ -277,9 +277,18 @@ It is not possible to define logic types introduced by the specification writer %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Structures, Unions and Arrays in logic} +\label{sec:aggregates} \nodiff -\difficults{\notimplemented{Logic arrays} without an explicit length} +\difficults{Logic arrays without an explicit length} + +\begin{notimplementedenv} + The \lstinline|\length| function is currently not supported by the \eacsl + plug-in. + + The comparison of unions and structures is currently not supported by the + \eacsl plug-in. +\end{notimplementedenv} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/plugins/e-acsl/doc/userman/biblio.bib b/src/plugins/e-acsl/doc/userman/biblio.bib index 27d9be4791f802dbe9eebcb8cd3ed69c8cbe2139..63e742e131e03df9a6f38531c3b56c3ad2b18246 100644 --- a/src/plugins/e-acsl/doc/userman/biblio.bib +++ b/src/plugins/e-acsl/doc/userman/biblio.bib @@ -59,6 +59,25 @@ url = {publis/hdr.pdf} } +@inproceedings{kosmatov20rv, + author = {Kosmatov, Nikolai and Maurica, Fonenantsoa and Signoles, Julien}, + title = {{Efficient Runtime Assertion Checking for Properties over + Mathematical Numbers}}, + booktitle = {International Conference on Runtime Verification (RV)}, + year = 2020, + month = oct, +} + +@inproceedings{ly18hilt, + author = {Dara Ly and Nikolai Kosmatov and Fr\'ed\'eric Loulergue + and Julien Signoles}, + title = {Soundness of a Dataflow Analysis for Memory Monitoring}, + booktitle = {Workshop on Languages and Tools for Ensuring Cyber-Resilience in +Critical Software-Intensive Systems (HILT)}, + year = 2018, + month = nov, +} + @inproceedings{rvcubes17tool, author = {Julien Signoles and Nikolai Kosmatov and Kostyantyn Vorobyov}, title = {{E-ACSL, a Runtime Verification Tool for Safety and Security of C diff --git a/src/plugins/e-acsl/doc/userman/changes.tex b/src/plugins/e-acsl/doc/userman/changes.tex index c69ab6038c6d344e0bbf612f2d171f4c96482979..034766eaca3e2ae51a6764834055cbb5dc55777e 100644 --- a/src/plugins/e-acsl/doc/userman/changes.tex +++ b/src/plugins/e-acsl/doc/userman/changes.tex @@ -5,6 +5,14 @@ release. First we list changes of the last release. \section*{E-ACSL \eacslpluginversion} +\begin{itemize} +\item \textbf{Simple Example}: Remove option \texttt{-e-acsl-check} +\item \textbf{Combining E-ACSL with Other PLug-ins}: \texttt{-e-acsl-prepare} is + no more necessary. +\end{itemize} + +\section*{E-ACSL 19.0 Potassium} + \begin{itemize} \item \textbf{Runtime Monitor Behavior}: Document global variable \texttt{\_\_e\_acsl\_sound\_verdict} usable in \texttt{\_\_e\_acsl\_assert}. diff --git a/src/plugins/e-acsl/doc/userman/limitations.tex b/src/plugins/e-acsl/doc/userman/limitations.tex index ec0d86ba6c26d28e71a791c5268787dcd87b2908..c42ab93808d1fb2fbfb644ce3e4293bbeb443485 100644 --- a/src/plugins/e-acsl/doc/userman/limitations.tex +++ b/src/plugins/e-acsl/doc/userman/limitations.tex @@ -152,9 +152,6 @@ $f$ such that: \end{itemize} 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} diff --git a/src/plugins/e-acsl/doc/userman/main.tex b/src/plugins/e-acsl/doc/userman/main.tex index 172397d5d4013c43680dd271eb5b4d7420805874..f2f73c8229cab00bfd68472c81be15710c4f45ae 100644 --- a/src/plugins/e-acsl/doc/userman/main.tex +++ b/src/plugins/e-acsl/doc/userman/main.tex @@ -50,8 +50,9 @@ evolve in the future. \section*{Acknowledgements} We gratefully thank the people who contributed to this document: -Pierre-Lo\"ic Garoche, Jens Gerlach, Florent Kirchner, Nikola\"i Kosmatov, -Andr\'e Oliveira Maroneze, Fonenantsoa Maurica, and Guillaume Petiot. +Basile Desloges, Pierre-Lo\"ic Garoche, Jens Gerlach, Florent Kirchner, +Nikola\"i Kosmatov, Andr\'e Oliveira Maroneze, Fonenantsoa Maurica, and +Guillaume Petiot. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/plugins/e-acsl/doc/userman/provides.tex b/src/plugins/e-acsl/doc/userman/provides.tex index 18df5fe9d39c61acac7b65e4a931299f9e7f7c71..accd222ac1c299c54589bc2c69647b8855ab3ec6 100644 --- a/src/plugins/e-acsl/doc/userman/provides.tex +++ b/src/plugins/e-acsl/doc/userman/provides.tex @@ -416,7 +416,7 @@ script. mathematical integers which does not fit in any integral \C type. To circumvent this issue, \eacsl uses the \gmp library\footnote{\url{http://gmplib.org}}. Thus, even if \eacsl does its best to use standard integral types instead of -\gmp~\cite{sac13,jfla15}, it may generate such integers from time to time. It is +\gmp~\cite{kosmatov20rv}, it may generate such integers from time to time. It is notably the case if your program contains \lstinline|long long|, either signed or unsigned. @@ -544,8 +544,8 @@ model~\cite{pldi16}. \subsubsection{Maximized Memory Tracking} By default \eacsl uses static analysis to reduce instrumentation and therefore -runtime and memory overheads~\cite{scp16}. With respect to memory tracking this -means that +runtime and memory overheads~\cite{ly18hilt}. With respect to memory tracking +this means that \eacsl may omit recording memory blocks irrelevant for runtime analysis. It is, however, still possible to systematically instrument the code for handling potential memory-related annotations even when it is not required. This @@ -980,22 +980,6 @@ The present implementation of \eacslgcc does not fully support combining \eacsl with other \framac plug-ins. However it is still possible to instrument programs with \eacsl directly and use \eacslgcc to compile the generated code. -If you run the \eacsl plug-in after another one, it first generates -a new temporary project in which it links the analyzed program against its own -library in order to generate the \framac internal representation of the \C -program (\emph{aka} AST), as explained in Section~\ref{sec:run}. Consequently, -even if the \eacsl plug-in keeps the maximum amount of information, the results -of already executed analyzers (such as validity status of annotations) are not -known in this new project. - -\begin{important} -If you want to keep results of former analysis, you have to set the option -\shortopt{e-acsl-prepare} when the first analysis is asked for. The standard -example is running \eacsl after \Eva\index{Eva}: in such a case, -\shortopt{e-acsl-prepare} must be provided together with the \Eva's -\shortopt{val} option. -\end{important} - In this context, the \eacsl plug-in does not generate code for annotations proven valid by another plug-in, except if you explicitly set the option \shortopt{e-acsl-valid}. For instance, \Eva~\cite{eva} is able to @@ -1003,21 +987,14 @@ prove that there is no potential overflow in the previous program, so the \eacsl plug-in does not generate additional code for checking them if you run the following command. \begin{shell} -\$ frama-c -e-acsl-prepare -rte combine.i -then -val -then -e-acsl \ +\$ frama-c -rte combine.i -then -val -then -e-acsl \ -then-last -print -ocode monitored_combine.i \end{shell} -The additional code will be generated with one of the two following commands. +The additional code will be generated with the two following command. \begin{shell} -\$ frama-c -e-acsl-prepare -rte combine.i -then -val -then -e-acsl \ - -e-acsl-valid -then-last -print -ocode monitored_combine.i \$ frama-c -rte combine.i -then -val -then -e-acsl \ - -then-last -print -ocode monitored_combine.i + -e-acsl-valid -then-last -print -ocode monitored_combine.i \end{shell} -In the first case, that is because it is explicitly required by the option -\shortopt{e-acsl-valid} while, in the second case, that is because the option -\shortopt{e-acsl-prepare} is not provided on the command line which results in -the fact that the result of the value analysis are unknown when the \eacsl -plug-in is running. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1044,20 +1021,6 @@ check.i:4:[e-acsl] warning: E-ACSL construct `right shift' is not yet supported. [e-acsl] translation done in project "foobar". \end{shell} -Further, the \eacsl plug-in option \shortopt{e-acsl-check} does not generate a -new project but verifies that each annotation is translatable. Then it produces -a summary as shown in the following example (left or right shifts in annotations -are not yet supported by the \eacsl plug-in~\cite{eacsl-implem}). - -\begin{shell} -\$ frama-c -e-acsl-check check.i -<skip preprocessing commands> -check.i:4:[e-acsl] warning: E-ACSL construct `left/right shift' is not yet supported. - Ignoring annotation. -[e-acsl] 0 annotation was ignored, being untypable. -[e-acsl] 1 annotation was ignored, being unsupported. -\end{shell} - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%>>> diff --git a/src/plugins/e-acsl/headers/header_spec.txt b/src/plugins/e-acsl/headers/header_spec.txt index 1d8b97641ff92e1b8763d1549cddb241cbe27b5e..f5d1c3fe39a487370af0db226395887366102ade 100644 --- a/src/plugins/e-acsl/headers/header_spec.txt +++ b/src/plugins/e-acsl/headers/header_spec.txt @@ -52,8 +52,6 @@ src/analyses/typing.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/analyses/typing.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/at_with_lscope.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/at_with_lscope.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL -src/code_generator/constructor.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL -src/code_generator/constructor.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/env.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/env.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/global_observer.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL @@ -66,6 +64,8 @@ src/code_generator/label.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/label.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/literal_observer.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/literal_observer.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL +src/code_generator/logic_array.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL +src/code_generator/logic_array.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/logic_functions.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/logic_functions.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/loops.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL @@ -78,6 +78,10 @@ src/code_generator/quantif.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/quantif.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/rational.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/rational.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL +src/code_generator/smart_exp.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL +src/code_generator/smart_exp.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL +src/code_generator/smart_stmt.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL +src/code_generator/smart_stmt.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/temporal.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/temporal.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/translate.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL @@ -98,8 +102,8 @@ src/local_config.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/main.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/options.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/options.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL -src/project_initializer/keep_status.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL -src/project_initializer/keep_status.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL +src/project_initializer/rtl.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL +src/project_initializer/rtl.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/project_initializer/prepare_ast.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/project_initializer/prepare_ast.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL tests/print.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL diff --git a/src/plugins/e-acsl/man/e-acsl-gcc.sh.1 b/src/plugins/e-acsl/man/e-acsl-gcc.sh.1 index d4eb7bdfe5078af7e5664c03d0d13925f7e028b7..e4c6801d21f29c194931cca19852edad9f241f9f 100644 --- a/src/plugins/e-acsl/man/e-acsl-gcc.sh.1 +++ b/src/plugins/e-acsl/man/e-acsl-gcc.sh.1 @@ -206,8 +206,7 @@ executable found in the system path is used. .TP .B --then separate with a \fB-then\fP the first \fBFrama-C\fP options from the actual -launch of the \fBE-ACSL\fP plugin. Prepends \fB-e-acsl-prepare\fP to the list -of options passed to \fBFrama-C\fP. +launch of the \fBE-ACSL\fP plugin. .TP .B --e-acsl-extra=\fI<OPTS> add \fI<OPTS>\fP to the list of options that will be given to the \fBE-ACSL\fP diff --git a/src/plugins/e-acsl/scripts/e-acsl-gcc.sh b/src/plugins/e-acsl/scripts/e-acsl-gcc.sh index 3038810fbf9bd7f54a963b46de85a3d8c94c5129..c81e38218fb5c94dd3c75e247668f17b12f8e554 100755 --- a/src/plugins/e-acsl/scripts/e-acsl-gcc.sh +++ b/src/plugins/e-acsl/scripts/e-acsl-gcc.sh @@ -557,7 +557,6 @@ do --then) shift; OPTION_THEN=-then - FRAMAC_FLAGS="-e-acsl-prepare $FRAMAC_FLAGS" ;; # Extra E-ACSL options --e-acsl-extra) @@ -754,7 +753,9 @@ CPPFLAGS="$OPTION_CPPFLAGS" LDFLAGS="$OPTION_LDFLAGS" # Extra Frama-C Flags E-ACSL needs -FRAMAC_FLAGS="$FRAMAC_FLAGS -variadic-no-translation" +FRAMAC_FLAGS="$FRAMAC_FLAGS \ + -remove-unused-specified-functions \ + -variadic-no-translation" # C, CPP and LD flags for compilation of E-ACSL-generated sources EACSL_CFLAGS="$OPTION_EXTERNAL_ASSERT" diff --git a/src/plugins/e-acsl/src/analyses/lscope.ml b/src/plugins/e-acsl/src/analyses/lscope.ml index ccf0726b033dfa66f046a0593117e3f4de5f6525..56a9e7ff0fd4d13e4598f15b369e0333686ea6bd 100644 --- a/src/plugins/e-acsl/src/analyses/lscope.ml +++ b/src/plugins/e-acsl/src/analyses/lscope.ml @@ -47,6 +47,8 @@ let exists lv t = in List.exists is_lv t +type pred_or_term = PoT_pred of predicate | PoT_term of term + exception Lscope_used let is_used lscope pot = let o = object inherit Visitor.frama_c_inplace @@ -57,8 +59,14 @@ let is_used lscope pot = in try (match pot with - | Misc.PoT_pred p -> ignore (Visitor.visitFramacPredicate o p) - | Misc.PoT_term t -> ignore (Visitor.visitFramacTerm o t)); + | PoT_pred p -> ignore (Visitor.visitFramacPredicate o p) + | PoT_term t -> ignore (Visitor.visitFramacTerm o t)); false with Lscope_used -> true + +(* +Local Variables: +compile-command: "make -C ../../../../.." +End: +*) diff --git a/src/plugins/e-acsl/src/analyses/lscope.mli b/src/plugins/e-acsl/src/analyses/lscope.mli index f84968eeaa3926b0ca8cefff034d58659b81fc1b..56728c2bdd002181bb5c4a62743ab6cfaac7afd9 100644 --- a/src/plugins/e-acsl/src/analyses/lscope.mli +++ b/src/plugins/e-acsl/src/analyses/lscope.mli @@ -48,6 +48,13 @@ val get_all: t -> lscope_var list The first element is the first [lscope_var] that was added to [t], the second element is the second [lscope_var] that was added to [t], an so on. *) -val is_used: t -> Misc.pred_or_term -> bool +type pred_or_term = PoT_pred of predicate | PoT_term of term +val is_used: t -> pred_or_term -> bool (* [is_used lscope pot] returns [true] iff [pot] uses a variable from [lscope]. *) + +(* +Local Variables: +compile-command: "make -C ../../../../.." +End: +*) diff --git a/src/plugins/e-acsl/src/analyses/mmodel_analysis.ml b/src/plugins/e-acsl/src/analyses/mmodel_analysis.ml index 3b655683995066f05739e1669e5e359c33ed4ddd..db85a8c4c96a1d183f0b84ae424531901996fb3d 100644 --- a/src/plugins/e-acsl/src/analyses/mmodel_analysis.ml +++ b/src/plugins/e-acsl/src/analyses/mmodel_analysis.ml @@ -27,7 +27,7 @@ module Dataflow = Dataflow2 let must_never_monitor vi = (* E-ACSL, please do not monitor yourself! *) - Functions.RTL.is_rtl_name vi.vname + Rtl.Symbols.mem_vi vi.vname || (* extern ghost variables are usually used (by the Frama-C libc) to represent some internal invisible states in ACSL specifications. They do @@ -138,11 +138,11 @@ end = struct try Kernel_function.Hashtbl.iter (fun _ h -> - Stmt.Hashtbl.iter - (fun _ set -> match set with - | None -> () - | Some s -> if not (Varinfo.Hptset.is_empty s) then raise Exit) - h) + Stmt.Hashtbl.iter + (fun _ set -> match set with + | None -> () + | Some s -> if not (Varinfo.Hptset.is_empty s) then raise Exit) + h) tbl; true with Exit -> @@ -162,7 +162,7 @@ let reset () = module rec Transfer : Dataflow.BackwardsTransfer with type t = Varinfo.Hptset.t option - = struct += struct let name = "E_ACSL.Pre_analysis" @@ -217,8 +217,8 @@ module rec Transfer let rec base_addr_node = function | Lval lv | AddrOf lv | StartOf lv -> (match lv with - | Var vi, _ -> Some vi - | Mem e, _ -> base_addr e) + | Var vi, _ -> Some vi + | Mem e, _ -> base_addr e) | BinOp((PlusPI | IndexPI | MinusPI), e1, e2, _) -> if is_ptr_or_array_exp e1 then base_addr e1 else begin @@ -227,7 +227,7 @@ module rec Transfer end | Info(e, _) | CastE(_, e) -> base_addr e | BinOp((MinusPP | PlusA | MinusA | Mult | Div | Mod |Shiftlt | Shiftrt - | Lt | Gt | Le | Ge | Eq | Ne | BAnd | BXor | BOr | LAnd | LOr), + | Lt | Gt | Le | Ge | Eq | Ne | BAnd | BXor | BOr | LAnd | LOr), _, _, _) | UnOp _ | Const _ | SizeOf _ | SizeOfE _ | SizeOfStr _ | AlignOf _ | AlignOfE _ -> @@ -314,20 +314,20 @@ module rec Transfer register_term kf varinfos t2 | TBinOp((PlusPI | IndexPI | MinusPI), t1, t2) -> (match t1.term_type with - | Ctype ty when is_ptr_or_array ty -> register_term kf varinfos t1 - | _ -> - match t2.term_type with - | Ctype ty when is_ptr_or_array ty -> register_term kf varinfos t2 - | _ -> - if Misc.is_set_of_ptr_or_array t1.term_type || - Misc.is_set_of_ptr_or_array t2.term_type then - (* Occurs for example from: - \valid(&multi_dynamic[2..4][1..7]) - where multi_dynamic has been dynamically allocated *) - let varinfos = register_term kf varinfos t1 in - register_term kf varinfos t2 - else - assert false) + | Ctype ty when is_ptr_or_array ty -> register_term kf varinfos t1 + | _ -> + match t2.term_type with + | Ctype ty when is_ptr_or_array ty -> register_term kf varinfos t2 + | _ -> + if Misc.is_set_of_ptr_or_array t1.term_type || + Misc.is_set_of_ptr_or_array t2.term_type then + (* Occurs for example from: + \valid(&multi_dynamic[2..4][1..7]) + where multi_dynamic has been dynamically allocated *) + let varinfos = register_term kf varinfos t1 in + register_term kf varinfos t2 + else + assert false) | TConst _ | TSizeOf _ | TSizeOfE _ | TSizeOfStr _ | TAlignOf _ | TAlignOfE _ | Tnull | Ttype _ | TUnOp _ | TBinOp _ -> varinfos @@ -359,73 +359,73 @@ module rec Transfer let register_object kf state_ref = object inherit Visitor.frama_c_inplace method !vpredicate_node = function - | Pvalid(_, t) | Pvalid_read(_, t) - | Pobject_pointer(_, t) | Pvalid_function t - | Pinitialized(_, t) | Pfreeable(_, t) -> - (* Options.feedback "REGISTER %a" Cil.d_term t;*) - state_ref := register_term kf !state_ref t; - Cil.DoChildren - | Pallocable _ -> Error.not_yet "\\allocable" - | Pfresh _ -> Error.not_yet "\\fresh" - | Pseparated _ -> Error.not_yet "\\separated" - | Pdangling _ -> Error.not_yet "\\dangling" - | Ptrue | Pfalse | Papp _ | Prel _ - | Pand _ | Por _ | Pxor _ | Pimplies _ | Piff _ | Pnot _ | Pif _ - | Pforall _ | Pexists _ | Pat _ -> - Cil.DoChildren - | Plet(li, _) -> - if may_alias li then Error.not_yet "let-binding on array or pointer" - else begin - state_ref := register_term kf !state_ref (Misc.term_of_li li); + | Pvalid(_, t) | Pvalid_read(_, t) + | Pobject_pointer(_, t) | Pvalid_function t + | Pinitialized(_, t) | Pfreeable(_, t) -> + (* Options.feedback "REGISTER %a" Cil.d_term t;*) + state_ref := register_term kf !state_ref t; Cil.DoChildren - end + | Pallocable _ -> Error.not_yet "\\allocable" + | Pfresh _ -> Error.not_yet "\\fresh" + | Pseparated _ -> Error.not_yet "\\separated" + | Pdangling _ -> Error.not_yet "\\dangling" + | Ptrue | Pfalse | Papp _ | Prel _ + | Pand _ | Por _ | Pxor _ | Pimplies _ | Piff _ | Pnot _ | Pif _ + | Pforall _ | Pexists _ | Pat _ -> + Cil.DoChildren + | Plet(li, _) -> + if may_alias li then Error.not_yet "let-binding on array or pointer" + else begin + state_ref := register_term kf !state_ref (Misc.term_of_li li); + Cil.DoChildren + end method !vterm term = match term.term_node with - | Tbase_addr(_, t) | Toffset(_, t) | Tblock_length(_, t) | Tlet(_, t) -> - state_ref := register_term kf !state_ref t; - Cil.DoChildren - | TConst _ | TSizeOf _ | TSizeOfStr _ | TAlignOf _ | Tnull | Ttype _ - | Tempty_set -> - (* no left-value inside inside: skip for efficiency *) - Cil.SkipChildren - | TUnOp _ | TBinOp _ | Ttypeof _ | TSizeOfE _ - | TLval _ | TAlignOfE _ | TCastE _ | TAddrOf _ - | TStartOf _ | Tapp _ | Tlambda _ | TDataCons _ | Tif _ | Tat _ - | TUpdate _ | Tunion _ | Tinter _ - | Tcomprehension _ | Trange _ | TLogic_coerce _ -> - (* potential sub-term inside *) - Cil.DoChildren + | Tbase_addr(_, t) | Toffset(_, t) | Tblock_length(_, t) | Tlet(_, t) -> + state_ref := register_term kf !state_ref t; + Cil.DoChildren + | TConst _ | TSizeOf _ | TSizeOfStr _ | TAlignOf _ | Tnull | Ttype _ + | Tempty_set -> + (* no left-value inside inside: skip for efficiency *) + Cil.SkipChildren + | TUnOp _ | TBinOp _ | Ttypeof _ | TSizeOfE _ + | TLval _ | TAlignOfE _ | TCastE _ | TAddrOf _ + | TStartOf _ | Tapp _ | Tlambda _ | TDataCons _ | Tif _ | Tat _ + | TUpdate _ | Tunion _ | Tinter _ + | Tcomprehension _ | Trange _ | TLogic_coerce _ -> + (* potential sub-term inside *) + Cil.DoChildren method !vlogic_label _ = Cil.SkipChildren method !vterm_lhost = function - | TMem t -> - (* potential RTE *) - state_ref := register_term kf !state_ref t; - Cil.DoChildren - | TVar _ | TResult _ -> - Cil.SkipChildren + | TMem t -> + (* potential RTE *) + state_ref := register_term kf !state_ref t; + Cil.DoChildren + | TVar _ | TResult _ -> + Cil.SkipChildren end -let register_predicate kf pred state = - let state_ref = ref state in - Error.handle - (fun () -> - ignore - (Visitor.visitFramacIdPredicate (register_object kf state_ref) pred)) - (); - !state_ref + let register_predicate kf pred state = + let state_ref = ref state in + Error.handle + (fun () -> + ignore + (Visitor.visitFramacIdPredicate (register_object kf state_ref) pred)) + (); + !state_ref let register_code_annot kf a state = let state_ref = ref state in Error.handle (fun () -> - ignore - (Visitor.visitFramacCodeAnnotation (register_object kf state_ref) a)) + ignore + (Visitor.visitFramacCodeAnnotation (register_object kf state_ref) a)) (); !state_ref - let rec do_init vi init state = match init with - | SingleInit e -> handle_assignment state (Var vi, NoOffset) e - | CompoundInit(_, l) -> - List.fold_left (fun state (_, init) -> do_init vi init state) state l + let rec do_init vi init state = match init with + | SingleInit e -> handle_assignment state (Var vi, NoOffset) e + | CompoundInit(_, l) -> + List.fold_left (fun state (_, init) -> do_init vi init state) state l let register_initializers state = let do_one vi init state = match init.init with @@ -433,9 +433,9 @@ let register_predicate kf pred state = | Some init -> do_init vi init state in Globals.Vars.fold_in_file_rev_order do_one state -(* below: compatibility with Fluorine *) -(* let l = Globals.Vars.fold_in_file_order (fun v i l -> (v, i) :: l) [] in - List.fold_left (fun state (v, i) -> do_one v i state) state l*) + (* below: compatibility with Fluorine *) + (* let l = Globals.Vars.fold_in_file_order (fun v i l -> (v, i) :: l) [] in + List.fold_left (fun state (v, i) -> do_one v i state) state l*) (** The (backwards) transfer function for a branch. The [(Cil.CurrentLoc.get ())] is set before calling this. If it returns None, then we have some @@ -447,59 +447,63 @@ let register_predicate kf pred state = let is_last = Kernel_function.is_return_stmt kf stmt in Dataflow.Post (fun state -> - let state = Env.default_varinfos state in - let state = - if Functions.check kf then - let state = - if (is_first || is_last) && Functions.RTL.is_generated_kf kf then - Annotations.fold_behaviors - (fun _ bhv s -> - let handle_annot test f s = - if test then - f - (fun _ p s -> register_predicate kf p s) - kf - bhv.b_name + let state = Env.default_varinfos state in + let state = + if Functions.check kf then + let state = + if (is_first || is_last) && Functions.RTL.is_generated_kf kf then + Annotations.fold_behaviors + (fun _ bhv s -> + let handle_annot test f s = + if test then + f + (fun _ p s -> register_predicate kf p s) + kf + bhv.b_name + s + else s - else - s - in - let s = handle_annot is_first Annotations.fold_requires s in - let s = handle_annot is_first Annotations.fold_assumes s in - handle_annot - is_last - (fun f -> - Annotations.fold_ensures (fun e (_, p) -> f e p)) s) - kf - state - else - state - in - let state = - Annotations.fold_code_annot - (fun _ -> register_code_annot kf) stmt state - in - if stmt.ghost then - let rtes = Rte.stmt kf stmt in - List.fold_left - (fun state a -> register_code_annot kf a state) state rtes - else - state - else (* not (Options.Functions.check kf): do not monitor [kf] *) - state - in - let state = - (* take initializers into account *) - if is_first then - let main, lib = Globals.entry_point () in - if Kernel_function.equal kf main && not lib then - register_initializers state - else - state - else - state - in - Some state) + in + let s = + handle_annot is_first Annotations.fold_requires s + in + let s = + handle_annot is_first Annotations.fold_assumes s + in + handle_annot + is_last + (fun f -> + Annotations.fold_ensures (fun e (_, p) -> f e p)) s) + kf + state + else + state + in + let state = + Annotations.fold_code_annot + (fun _ -> register_code_annot kf) stmt state + in + if stmt.ghost then + let rtes = Rte.stmt kf stmt in + List.fold_left + (fun state a -> register_code_annot kf a state) state rtes + else + state + else (* not (Options.Functions.check kf): do not monitor [kf] *) + state + in + let state = + (* take initializers into account *) + if is_first then + let main, lib = Globals.entry_point () in + if Kernel_function.equal kf main && not lib then + register_initializers state + else + state + else + state + in + Some state) let do_call res f args state = let kf = Globals.Functions.get f in @@ -512,11 +516,11 @@ let register_predicate kf pred state = let init = List.fold_left2 (fun acc p a -> match base_addr a with - | None -> acc - | Some vi -> - if Varinfo.Hptset.mem vi state - then Varinfo.Hptset.add p acc - else acc) + | None -> acc + | Some vi -> + if Varinfo.Hptset.mem vi state + then Varinfo.Hptset.add p acc + else acc) state params args @@ -536,10 +540,10 @@ let register_predicate kf pred state = corresponding formals must be kept *) List.fold_left2 (fun acc p a -> match base_addr a with - | None -> acc - | Some vi -> - if Varinfo.Hptset.mem p state then Varinfo.Hptset.add vi acc - else acc) + | None -> acc + | Some vi -> + if Varinfo.Hptset.mem p state then Varinfo.Hptset.add vi acc + else acc) state params args @@ -589,19 +593,19 @@ let register_predicate kf pred state = do_call (Some (Cil.var v)) f args state | Call(result, f_exp, l, _) -> (match f_exp.enode with - | Lval(Var vi, NoOffset) -> do_call result vi l state - | _ -> - Options.warning ~current:true - "function pointers may introduce too limited instrumentation."; -(* imprecise function call: keep each argument *) - Dataflow.Done - (Some - (List.fold_left - (fun acc e -> match base_addr e with - | None -> acc - | Some vi -> Varinfo.Hptset.add vi acc) - state - l))) + | Lval(Var vi, NoOffset) -> do_call result vi l state + | _ -> + Options.warning ~current:true + "function pointers may introduce too limited instrumentation."; + (* imprecise function call: keep each argument *) + Dataflow.Done + (Some + (List.fold_left + (fun acc e -> match base_addr e with + | None -> acc + | Some vi -> Varinfo.Hptset.add vi acc) + state + l))) | Asm _ -> Error.not_yet "asm" | Skip _ | Code_annot _ -> Dataflow.Default @@ -620,7 +624,7 @@ end = struct let compute init_set kf = Options.feedback ~dkey ~level:2 "entering in function %a." Kernel_function.pretty kf; - assert (not (Misc.is_library_loc (Kernel_function.get_location kf))); + assert (not (Rtl.Symbols.mem_kf kf)); let tbl, is_init = try Env.find kf, true with Not_found -> Stmt.Hashtbl.create 17, false @@ -633,23 +637,25 @@ end = struct if is_init then Extlib.may (fun set -> - List.iter - (fun s -> - let old = - try Extlib.the (Stmt.Hashtbl.find tbl s) - with Not_found -> assert false - in - Stmt.Hashtbl.replace - tbl - s - (Some (Varinfo.Hptset.union set old))) - returns) + List.iter + (fun s -> + let old = + try Extlib.the (Stmt.Hashtbl.find tbl s) + with Not_found -> assert false + in + Stmt.Hashtbl.replace + tbl + s + (Some (Varinfo.Hptset.union set old))) + returns) init_set else begin List.iter (fun s -> Stmt.Hashtbl.add tbl s None) stmts; Extlib.may (fun set -> - List.iter (fun s -> Stmt.Hashtbl.replace tbl s (Some set)) returns) + List.iter + (fun s -> Stmt.Hashtbl.replace tbl s (Some set)) + returns) init_set end; D.compute stmts @@ -660,17 +666,17 @@ end = struct tbl let get ?init kf = - if Misc.is_library_loc (Kernel_function.get_location kf) then + if Rtl.Symbols.mem_kf kf then Varinfo.Hptset.empty else try let stmt = Kernel_function.find_first_stmt kf in -(* Options.feedback "GETTING %a" Kernel_function.pretty kf;*) + (* Options.feedback "GETTING %a" Kernel_function.pretty kf;*) let tbl = if Env.mem_init kf init then try Env.find kf with Not_found -> assert false else begin - (* WARN: potentially incorrect in case of recursive call *) + (* WARN: potentially incorrect in case of recursive call *) Env.add_init kf init; Env.apply (compute init) kf end @@ -691,16 +697,18 @@ let consolidated_must_model_vi vi = Env.consolidated_mem vi else begin Options.feedback ~level:2 "performing pre-analysis for minimal memory \ -instrumentation."; + instrumentation."; (try let main, _ = Globals.entry_point () in let set = Compute.get main in Env.consolidate set with Globals.No_such_entry_point s -> - Options.warning ~once:true "%s@ \ -@[The generated program may miss memory instrumentation@ \ -if there are memory-related annotations.@]" - s); + Options.warning + ~once:true + "%s@ \ + @[The generated program may miss memory instrumentation@ \ + if there are memory-related annotations.@]" + s); Options.feedback ~level:2 "pre-analysis done."; Env.consolidated_mem vi end @@ -715,24 +723,24 @@ let must_model_vi ?kf ?stmt vi = TODO: could be optimized though *) consolidated_must_model_vi vi (* match stmt, kf with - | None, _ -> consolidated_must_model_vi vi - | Some _, None -> + | None, _ -> consolidated_must_model_vi vi + | Some _, None -> assert false - | Some stmt, Some kf -> + | Some stmt, Some kf -> if not (Env.is_consolidated ()) then ignore (consolidated_must_model_vi vi); try let tbl = Env.find kf in try -let set = Stmt.Hashtbl.find tbl stmt in -Varinfo.Hptset.mem vi (Env.default_varinfos set) + let set = Stmt.Hashtbl.find tbl stmt in + Varinfo.Hptset.mem vi (Env.default_varinfos set) with Not_found -> -(* new statement *) -consolidated_must_model_vi vi + (* new statement *) + consolidated_must_model_vi vi with Not_found -> (* [kf] is dead code *) false - *) +*) let rec apply_on_vi_base_from_lval f ?kf ?stmt = function | Var vi, _ -> f ?kf ?stmt vi @@ -748,7 +756,7 @@ and apply_on_vi_base_from_exp f ?kf ?stmt e = match e.enode with || apply_on_vi_base_from_exp f ?kf ?stmt e2 | Info(e, _) | CastE(_, e) -> apply_on_vi_base_from_exp f ?kf ?stmt e | BinOp((PlusA | MinusA | Mult | Div | Mod |Shiftlt | Shiftrt | Lt | Gt | Le - | Ge | Eq | Ne | BAnd | BXor | BOr | LAnd | LOr), _, _, _) + | 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 @@ -777,20 +785,20 @@ let must_never_monitor_exp ?kf ?stmt lv = let must_model_vi ?kf ?stmt vi = not (must_never_monitor vi) && - (Options.Full_mmodel.get () - || Error.generic_handle (must_model_vi ?kf ?stmt) false vi) + (Options.Full_mmodel.get () + || Error.generic_handle (must_model_vi ?kf ?stmt) false vi) let must_model_lval ?kf ?stmt lv = not (must_never_monitor_lval ?kf ?stmt lv) && - (Options.Full_mmodel.get () - || Error.generic_handle (must_model_lval ?kf ?stmt) false lv) + (Options.Full_mmodel.get () + || Error.generic_handle (must_model_lval ?kf ?stmt) false lv) let must_model_exp ?kf ?stmt exp = not (must_never_monitor_exp ?kf ?stmt exp) && - (Options.Full_mmodel.get () - || Error.generic_handle (must_model_exp ?kf ?stmt) false exp) + (Options.Full_mmodel.get () + || Error.generic_handle (must_model_exp ?kf ?stmt) false exp) let use_model () = not (Env.is_empty ()) @@ -799,6 +807,6 @@ let use_model () = (* Local Variables: -compile-command: "make -C ../.." +compile-command: "make -C ../../../../.." End: *) diff --git a/src/plugins/e-acsl/src/analyses/mmodel_analysis.mli b/src/plugins/e-acsl/src/analyses/mmodel_analysis.mli index 39090f0dfa07a4100864ff0c20883bd9d79e7f3a..8c4967c2797f9c936b3c230b40a9cb0d476f6a37 100644 --- a/src/plugins/e-acsl/src/analyses/mmodel_analysis.mli +++ b/src/plugins/e-acsl/src/analyses/mmodel_analysis.mli @@ -44,6 +44,6 @@ val must_model_exp: ?kf:kernel_function -> ?stmt:stmt -> exp -> bool (* Local Variables: - compile-command: "make" + compile-command: "make -C ../../../../.." End: *) diff --git a/src/plugins/e-acsl/src/analyses/rte.ml b/src/plugins/e-acsl/src/analyses/rte.ml index d02641f2bc68d2b157c557ea4ab5272b7fe4768d..9305eff3a55b06c68106628a229bb27afd265565 100644 --- a/src/plugins/e-acsl/src/analyses/rte.ml +++ b/src/plugins/e-acsl/src/analyses/rte.ml @@ -24,21 +24,10 @@ (** {2 Generic code} *) (* ************************************************************************** *) -let apply_rte f x = - let signed = Kernel.SignedOverflow.get () in - let unsigned = Kernel.UnsignedOverflow.get () in - Kernel.SignedOverflow.off (); - Kernel.UnsignedOverflow.off (); - let finally () = - Kernel.SignedOverflow.set signed; - Kernel.UnsignedOverflow.set unsigned - in - Extlib.try_finally ~finally f x - let warn_rte warn exn = if warn then Options.warning "@[@[cannot run RTE:@ %s.@]@ \ -Ignoring potential runtime errors in annotations." + Ignoring potential runtime errors in annotations." (Printexc.to_string exn) (* ************************************************************************** *) @@ -48,37 +37,31 @@ Ignoring potential runtime errors in annotations." open Cil_datatype let stmt ?(warn=true) = - try - let f = - Dynamic.get - ~plugin:"RteGen" - "stmt_annotations" - (Datatype.func2 Kernel_function.ty Stmt.ty - (let module L = Datatype.List(Code_annotation) in L.ty)) - in - (fun x y -> apply_rte (f x) y) + try + Dynamic.get + ~plugin:"RteGen" + "stmt_annotations" + (Datatype.func2 Kernel_function.ty Stmt.ty + (let module L = Datatype.List(Code_annotation) in L.ty)) with Failure _ | Dynamic.Unbound_value _ | Dynamic.Incompatible_type _ as exn -> - warn_rte warn exn; - fun _ _ -> [] + warn_rte warn exn; + fun _ _ -> [] let exp ?(warn=true) = - try - let f = - Dynamic.get - ~plugin:"RteGen" - "exp_annotations" - (Datatype.func3 Kernel_function.ty Stmt.ty Exp.ty - (let module L = Datatype.List(Code_annotation) in L.ty)) - in - (fun x y z -> apply_rte (f x y) z) + try + Dynamic.get + ~plugin:"RteGen" + "exp_annotations" + (Datatype.func3 Kernel_function.ty Stmt.ty Exp.ty + (let module L = Datatype.List(Code_annotation) in L.ty)) with Failure _ | Dynamic.Unbound_value _ | Dynamic.Incompatible_type _ as exn -> - warn_rte warn exn; - fun _ _ _ -> [] + warn_rte warn exn; + fun _ _ _ -> [] (* Local Variables: -compile-command: "make" +compile-command: "make -C ../../../../.." End: *) diff --git a/src/plugins/e-acsl/src/analyses/rte.mli b/src/plugins/e-acsl/src/analyses/rte.mli index 96d971650079a343cd33cd699d52260720907fe7..6f177451eddc0de564679ef1dbb4e7c8f825e862 100644 --- a/src/plugins/e-acsl/src/analyses/rte.mli +++ b/src/plugins/e-acsl/src/analyses/rte.mli @@ -32,6 +32,6 @@ val exp: ?warn:bool -> kernel_function -> stmt -> exp -> code_annotation list (* Local Variables: -compile-command: "make" +compile-command: "make -C ../../../../.." End: *) diff --git a/src/plugins/e-acsl/src/analyses/typing.ml b/src/plugins/e-acsl/src/analyses/typing.ml index a2612ee906f2595622dd37a63cc835b93b44fd9f..04731a08f3ce28a805afc6e0a7f4c52d064976fd 100644 --- a/src/plugins/e-acsl/src/analyses/typing.ml +++ b/src/plugins/e-acsl/src/analyses/typing.ml @@ -512,7 +512,7 @@ let rec type_term ~use_gmp_opt ?(arith_operand=false) ?ctx t = | LBreads _ -> Error.not_yet "logic functions performing read accesses" | LBinductive _ -> - Error.not_yet "logic functions inductively defined" + Error.not_yet "inductive logic functions" end | Tunion _ -> Error.not_yet "tset union" @@ -585,8 +585,13 @@ let rec type_predicate p = c_int | LBnone -> (* Eg: \is_finite *) Error.not_yet "predicate with no definition nor reads clause" - | LBreads _ | LBterm _ | LBinductive _ -> + | LBreads _ -> + Error.not_yet "predicate performing read accesses" + | LBinductive _ -> + Error.not_yet "inductive predicate" + | LBterm _ -> Options.fatal "unexpected logic definition" + Printer.pp_predicate p end | Pseparated _ -> Error.not_yet "\\separated" | Pdangling _ -> Error.not_yet "\\dangling" diff --git a/src/plugins/e-acsl/src/code_generator/at_with_lscope.ml b/src/plugins/e-acsl/src/code_generator/at_with_lscope.ml index c80f627edd31c06ace8f3d5f9b9e03ad07ff3159..671ea306b1f641e8cacba62184345c3256d526fd 100644 --- a/src/plugins/e-acsl/src/code_generator/at_with_lscope.ml +++ b/src/plugins/e-acsl/src/code_generator/at_with_lscope.ml @@ -39,8 +39,8 @@ let term_to_exp_ref (*****************************************************************************) (* Remove all the bindings for [kf]. [Cil_datatype.Kf.Hashtbl] does not - provide the [remove_all] function. Thus we need to keep calling [remove] - until all entries are removed. *) + provide the [remove_all] function. Thus we need to keep calling [remove] + until all entries are removed. *) let rec remove_all tbl kf = if Cil_datatype.Kf.Hashtbl.mem tbl kf then begin Cil_datatype.Kf.Hashtbl.remove tbl kf; @@ -66,10 +66,10 @@ end (**************************************************************************) (* Builds the terms [t_size] and [t_shifted] from each - [Lvs_quantif(tmin, lv, tmax)] from [lscope] - where [t_size = tmax - tmin + (-1|0|1)] depending on whether the + [Lvs_quantif(tmin, lv, tmax)] from [lscope] + where [t_size = tmax - tmin + (-1|0|1)] depending on whether the inequalities are strict or large - and [t_shifted = lv - tmin + (-1|0)] (so that we start indexing at 0) *) + and [t_shifted = lv - tmin + (-1|0)] (so that we start indexing at 0) *) let rec sizes_and_shifts_from_quantifs ~loc kf lscope sizes_and_shifts = match lscope with | [] -> @@ -97,29 +97,29 @@ let rec sizes_and_shifts_from_quantifs ~loc kf lscope sizes_and_shifts = in let iv = Interval.(extract_ival (infer t_size)) in (* The EXACT amount of memory that is needed can be known at runtime. This - is because the tightest bounds for the variables can be known at runtime. - Example: In the following predicate + is because the tightest bounds for the variables can be known at runtime. + Example: In the following predicate [\exists integer u; 9 <= u <= 13 && \forall integer v; -5 < v <= (u <= 11 ? u + 6 : u - 9) ==> \at(u + v > 0, K)] the upper bound [M] for [v] depends on [u]. In chronological order, [M] equals to 15, 16, 17, 3 and 4. Thus the tightest upper bound for [v] is [max(M)=17]. - HOWEVER, computing that exact information requires extra nested loops, - prior to the [malloc] stmts, that will try all the possible values of the - variables involved in the bounds. - Instead of sacrificing time over memory (by performing these extra - computations), we consider that sacrificing memory over time is more - beneficial. In particular, though we may allocate more memory than - needed, the number of reads/writes into it is the same in both cases. - Conclusion: over-approximate [t_size] *) + HOWEVER, computing that exact information requires extra nested loops, + prior to the [malloc] stmts, that will try all the possible values of the + variables involved in the bounds. + Instead of sacrificing time over memory (by performing these extra + computations), we consider that sacrificing memory over time is more + beneficial. In particular, though we may allocate more memory than + needed, the number of reads/writes into it is the same in both cases. + Conclusion: over-approximate [t_size] *) let t_size = match Ival.min_and_max iv with | _, Some max -> Logic_const.tint ~loc max | _, None -> Error.not_yet "\\at on purely logic variables and with quantifier that uses \ - too complex bound (E-ACSL cannot infer a finite upper bound to it)" + too complex bound (E-ACSL cannot infer a finite upper bound to it)" in (* Index *) let t_lv = Logic_const.tvar ~loc lv in @@ -148,13 +148,13 @@ let rec sizes_and_shifts_from_quantifs ~loc kf lscope sizes_and_shifts = let size_from_sizes_and_shifts ~loc = function | [] -> (* No quantified variable. But still need to allocate [1*sizeof(_)] amount - of memory to store purely logic variables that are NOT quantified - (example: from \let). *) + of memory to store purely logic variables that are NOT quantified + (example: from \let). *) Cil.lone ~loc () | (size, _) :: sizes_and_shifts -> List.fold_left (fun t_size (t_s, _) -> - Logic_const.term ~loc (TBinOp(Mult, t_size, t_s)) Linteger) + Logic_const.term ~loc (TBinOp(Mult, t_size, t_s)) Linteger) size sizes_and_shifts @@ -171,35 +171,35 @@ let lval_at_index ~loc kf env (e_at, vi_at, t_index) = lval_at_index, env (* Associate to each possible tuple of quantifiers - a unique index from the set {n | 0 <= n < n_max}. - That index will serve to identify the memory location where the evaluation - of the term/predicate is stored for the given tuple of quantifier. - The following gives the smallest set of such indexes (hence we use the - smallest amount of memory in some respect): - To (t_shifted_n, t_shifted_n-1, ..., t_shifted_1) - where 0 <= t_shifted_i < beta_i - corresponds: \sum_{i=1}^n( t_shifted_i * \pi_{j=1}^{i-1}(beta_j) ) *) + a unique index from the set {n | 0 <= n < n_max}. + That index will serve to identify the memory location where the evaluation + of the term/predicate is stored for the given tuple of quantifier. + The following gives the smallest set of such indexes (hence we use the + smallest amount of memory in some respect): + To (t_shifted_n, t_shifted_n-1, ..., t_shifted_1) + where 0 <= t_shifted_i < beta_i + corresponds: \sum_{i=1}^n( t_shifted_i * \pi_{j=1}^{i-1}(beta_j) ) *) let index_from_sizes_and_shifts ~loc sizes_and_shifts = let product terms = List.fold_left - (fun product t -> - Logic_const.term ~loc (TBinOp(Mult, product, t)) Linteger) - (Cil.lone ~loc ()) - terms + (fun product t -> + Logic_const.term ~loc (TBinOp(Mult, product, t)) Linteger) + (Cil.lone ~loc ()) + terms in let sum, _ = List.fold_left - (fun (index, sizes) (t_size, t_shifted) -> - let pi_beta_j = product sizes in - let bi_mult_pi_beta_j = - Logic_const.term ~loc (TBinOp(Mult, t_shifted, pi_beta_j)) Linteger - in - let sum = Logic_const.term - ~loc - (TBinOp(PlusA, bi_mult_pi_beta_j, index)) - Linteger - in - sum, t_size :: sizes) - (Cil.lzero ~loc (), []) - sizes_and_shifts + (fun (index, sizes) (t_size, t_shifted) -> + let pi_beta_j = product sizes in + let bi_mult_pi_beta_j = + Logic_const.term ~loc (TBinOp(Mult, t_shifted, pi_beta_j)) Linteger + in + let sum = Logic_const.term + ~loc + (TBinOp(PlusA, bi_mult_pi_beta_j, index)) + Linteger + in + sum, t_size :: sizes) + (Cil.lzero ~loc (), []) + sizes_and_shifts in sum @@ -225,62 +225,63 @@ let to_exp ~loc kf env pot label = in (* Creating the pointer *) let ty = match pot with - | Misc.PoT_pred _ -> - Cil.intType - | Misc.PoT_term t -> - begin match Typing.get_number_ty t with - | Typing.(C_integer _ | C_float _ | Nan) -> - Typing.get_typ t - | Typing.(Rational | Real) -> - Error.not_yet "\\at on purely logic variables and over real type" - | Typing.Gmpz -> - Error.not_yet "\\at on purely logic variables and over gmp type" - end + | Lscope.PoT_pred _ -> + Cil.intType + | Lscope.PoT_term t -> + begin match Typing.get_number_ty t with + | Typing.(C_integer _ | C_float _ | Nan) -> + Typing.get_typ t + | Typing.(Rational | Real) -> + Error.not_yet "\\at on purely logic variables and over real type" + | Typing.Gmpz -> + Error.not_yet "\\at on purely logic variables and over gmp type" + end in let ty_ptr = TPtr(ty, []) in let vi_at, e_at, env = Env.new_var - ~loc - ~name:"at" - ~scope:Varname.Function - env - kf - None - ty_ptr - (fun vi e -> - (* Handle [malloc] and [free] stmts *) - let lty_sizeof = Ctype Cil.(theMachine.typeOfSizeOf) in - let t_sizeof = Logic_const.term ~loc (TSizeOf ty) lty_sizeof in - let t_size = size_from_sizes_and_shifts ~loc sizes_and_shifts in - let t_size = - Logic_const.term ~loc (TBinOp(Mult, t_sizeof, t_size)) lty_sizeof - in - Typing.type_term ~use_gmp_opt:false t_size; - let malloc_stmt = match Typing.get_number_ty t_size with - | Typing.C_integer IInt -> - let e_size, _ = term_to_exp kf env t_size in - let e_size = Cil.constFold false e_size in - let malloc_stmt = - Constructor.mk_lib_call ~loc - ~result:(Cil.var vi) - "malloc" - [ e_size ] - in - malloc_stmt - | Typing.(C_integer _ | C_float _ | Gmpz) -> - Error.not_yet - "\\at on purely logic variables that needs to allocate \ - too much memory (bigger than int_max bytes)" - | Typing.(Rational | Real | Nan) -> - Error.not_yet "quantification over non-integer type" - in - let free_stmt = Constructor.mk_lib_call ~loc "free" [e] in - (* The list of stmts returned by the current closure are inserted - LOCALLY to the block where the new var is FIRST used, whatever scope - is indicated to [Env.new_var]. - Thus we need to add [malloc] and [free] through dedicated functions. *) - Malloc.add kf malloc_stmt; - Free.add kf free_stmt; - []) + ~loc + ~name:"at" + ~scope:Varname.Function + env + kf + None + ty_ptr + (fun vi e -> + (* Handle [malloc] and [free] stmts *) + let lty_sizeof = Ctype Cil.(theMachine.typeOfSizeOf) in + let t_sizeof = Logic_const.term ~loc (TSizeOf ty) lty_sizeof in + let t_size = size_from_sizes_and_shifts ~loc sizes_and_shifts in + let t_size = + Logic_const.term ~loc (TBinOp(Mult, t_sizeof, t_size)) lty_sizeof + in + Typing.type_term ~use_gmp_opt:false t_size; + let malloc_stmt = match Typing.get_number_ty t_size with + | Typing.C_integer IInt -> + let e_size, _ = term_to_exp kf env t_size in + let e_size = Cil.constFold false e_size in + let malloc_stmt = + Smart_stmt.lib_call ~loc + ~result:(Cil.var vi) + "malloc" + [ e_size ] + in + malloc_stmt + | Typing.(C_integer _ | C_float _ | Gmpz) -> + Error.not_yet + "\\at on purely logic variables that needs to allocate \ + too much memory (bigger than int_max bytes)" + | Typing.(Rational | Real | Nan) -> + Error.not_yet "quantification over non-integer type" + in + let free_stmt = Smart_stmt.lib_call ~loc "free" [e] in + (* The list of stmts returned by the current closure are inserted + LOCALLY to the block where the new var is FIRST used, whatever scope + is indicated to [Env.new_var]. + Thus we need to add [malloc] and [free] through dedicated functions. + *) + Malloc.add kf malloc_stmt; + Free.add kf free_stmt; + []) in (* Index *) let t_index = index_from_sizes_and_shifts ~loc sizes_and_shifts in @@ -289,40 +290,40 @@ let to_exp ~loc kf env pot label = let term_to_exp = !term_to_exp_ref in let named_predicate_to_exp = !predicate_to_exp_ref in match pot with - | Misc.PoT_pred p -> + | Lscope.PoT_pred p -> let env = Env.push env in let lval, env = lval_at_index ~loc kf env (e_at, vi_at, t_index) in let e, env = named_predicate_to_exp kf env p in let e = Cil.constFold false e in let storing_stmt = - Cil.mkStmtOneInstr ~valid_sid:true (Set(lval, e, loc)) + Smart_stmt.assigns ~loc ~result:lval e in let block, env = Env.pop_and_get env storing_stmt ~global_clear:false Env.After in (* We CANNOT return [block.bstmts] because it does NOT contain - variable declarations. *) - [ Cil.mkStmt ~valid_sid:true (Block block) ], env - | Misc.PoT_term t -> + variable declarations. *) + [ Smart_stmt.block_stmt block ], env + | Lscope.PoT_term t -> begin match Typing.get_number_ty t with - | Typing.(C_integer _ | C_float _ | Nan) -> - let env = Env.push env in - let lval, env = lval_at_index ~loc kf env (e_at, vi_at, t_index) in - let e, env = term_to_exp kf env t in - let e = Cil.constFold false e in - let storing_stmt = - Cil.mkStmtOneInstr ~valid_sid:true (Set(lval, e, loc)) - in - let block, env = - Env.pop_and_get env storing_stmt ~global_clear:false Env.After - in - (* We CANNOT return [block.bstmts] because it does NOT contain - variable declarations. *) - [ Cil.mkStmt ~valid_sid:true (Block block) ], env - | Typing.(Rational | Real) -> - Error.not_yet "\\at on purely logic variables and over real type" - | Typing.Gmpz -> - Error.not_yet "\\at on purely logic variables and over gmp type" + | Typing.(C_integer _ | C_float _ | Nan) -> + let env = Env.push env in + let lval, env = lval_at_index ~loc kf env (e_at, vi_at, t_index) in + let e, env = term_to_exp kf env t in + let e = Cil.constFold false e in + let storing_stmt = + Smart_stmt.assigns ~loc ~result:lval e + in + let block, env = + Env.pop_and_get env storing_stmt ~global_clear:false Env.After + in + (* We CANNOT return [block.bstmts] because it does NOT contain + variable declarations. *) + [ Smart_stmt.block_stmt block ], env + | Typing.(Rational | Real) -> + Error.not_yet "\\at on purely logic variables and over real type" + | Typing.Gmpz -> + Error.not_yet "\\at on purely logic variables and over gmp type" end in (* Storing loops *) @@ -333,20 +334,20 @@ let to_exp ~loc kf env pot label = in let storing_loops_block = Cil.mkBlock storing_loops_stmts in let storing_loops_block, env = Env.pop_and_get - env - (Cil.mkStmt ~valid_sid:true (Block storing_loops_block)) - ~global_clear:false - Env.After + env + (Smart_stmt.block_stmt storing_loops_block) + ~global_clear:false + Env.After in (* Put at label *) let env = put_block_at_label env kf storing_loops_block label in (* Returning *) let lval_at_index, env = lval_at_index ~loc kf env (e_at, vi_at, t_index) in - let e = Cil.new_exp ~loc (Lval lval_at_index) in + let e = Smart_exp.lval ~loc lval_at_index in e, env (* Local Variables: -compile-command: "make -C ../.." +compile-command: "make -C ../../../../.." End: *) diff --git a/src/plugins/e-acsl/src/code_generator/at_with_lscope.mli b/src/plugins/e-acsl/src/code_generator/at_with_lscope.mli index 3b6dda222774a0cde05bdce183bc273ef75c4742..0a971045fddfe3d0cc9ec1f9a90a6fdf982a46ed 100644 --- a/src/plugins/e-acsl/src/code_generator/at_with_lscope.mli +++ b/src/plugins/e-acsl/src/code_generator/at_with_lscope.mli @@ -24,7 +24,7 @@ open Cil_types open Cil_datatype (* Convert \at on terms or predicates in which we can find purely - logic variable. *) + logic variable. *) (**************************************************************************) (*************************** Translation **********************************) @@ -32,15 +32,15 @@ open Cil_datatype val to_exp: loc:Location.t -> kernel_function -> Env.t -> - Misc.pred_or_term -> logic_label -> exp * Env.t + Lscope.pred_or_term -> logic_label -> exp * Env.t (*****************************************************************************) (**************************** Handling memory ********************************) (*****************************************************************************) (* The different possible evaluations of the [\at] under study are - stored in a memory location that needs to be alloted then freed. - This part is designed for that purpose. *) + stored in a memory location that needs to be alloted then freed. + This part is designed for that purpose. *) module Malloc: sig val find_all: kernel_function -> stmt list @@ -70,6 +70,6 @@ val term_to_exp_ref: (* Local Variables: -compile-command: "make -C ../.." +compile-command: "make -C ../../../../.." End: *) diff --git a/src/plugins/e-acsl/src/code_generator/env.ml b/src/plugins/e-acsl/src/code_generator/env.ml index b41dd240b6cdee12cb1cc7c9489fd8b94ee6aaf4..cfdbe5fdda47bb9b3ea0aab39423b7e26bf8c5c6 100644 --- a/src/plugins/e-acsl/src/code_generator/env.ml +++ b/src/plugins/e-acsl/src/code_generator/env.ml @@ -56,7 +56,7 @@ type local_env = { type t = { lscope: Lscope.t; lscope_reset: bool; - annotation_kind: Constructor.annotation_kind; + annotation_kind: Smart_stmt.annotation_kind; new_global_vars: (varinfo * localized_scope) list; (* generated variables. The scope indicates the level where the variable should be added. *) @@ -88,7 +88,7 @@ let empty_local_env = let empty = { lscope = Lscope.empty; lscope_reset = true; - annotation_kind = Constructor.Assertion; + annotation_kind = Smart_stmt.Assertion; new_global_vars = []; global_mp_tbl = empty_mp_tbl; env_stack = []; @@ -246,6 +246,21 @@ let new_var_and_mpz_init ~loc ?scope ?name env kf t mk_stmts = (Gmp_types.Z.t ()) (fun v e -> Gmp.init ~loc e :: mk_stmts v e) +let rtl_call_to_new_var ~loc ?scope ?name env kf t ty func_name args = + let _, exp, env = + new_var + ~loc + ?scope + ?name + env + kf + t + ty + (fun v _ -> + [ Smart_stmt.rtl_call ~loc ~result:(Cil.var v) func_name args ]) + in + exp, env + module Logic_binding = struct let add_binding env logic_v vi = @@ -336,9 +351,9 @@ let add_stmt ?(post=false) ?before env kf stmt = { env with env_stack = local_env :: tl } let extend_stmt_in_place env stmt ~label block = - let new_stmt = Cil.mkStmt ~valid_sid:true (Block block) in + let new_stmt = Smart_stmt.block_stmt block in let sk = stmt.skind in - stmt.skind <- Block (Cil.mkBlock [ new_stmt; Cil.mkStmt ~valid_sid:true sk ]); + stmt.skind <- Block (Cil.mkBlock [ new_stmt; Smart_stmt.stmt sk ]); let pre = match label with | BuiltinLabel(Here | Post) -> true | BuiltinLabel(Old | Pre | LoopEntry | LoopCurrent | Init) @@ -432,7 +447,7 @@ let pop_and_get ?(split=false) env stmt ~global_clear where = add the given [stmt] afterwards. This way, we have the guarantee that the final block does not contain any local, so may be transient. *) if split then - let sblock = Cil.mkStmt ~valid_sid:true (Block b) in + let sblock = Smart_stmt.block_stmt b in Cil.transient_block (Cil.mkBlock [ sblock; stmt ]) else b diff --git a/src/plugins/e-acsl/src/code_generator/env.mli b/src/plugins/e-acsl/src/code_generator/env.mli index 31abba5dfff6980ca097d352239a898d790d8f01..94c11335f1c96bbcee2a1def0150be956bb81435 100644 --- a/src/plugins/e-acsl/src/code_generator/env.mli +++ b/src/plugins/e-acsl/src/code_generator/env.mli @@ -59,6 +59,15 @@ val new_var_and_mpz_init: (** Same as [new_var], but dedicated to mpz_t variables initialized by {!Mpz.init}. *) +val rtl_call_to_new_var: + loc:location -> ?scope:Varname.scope -> ?name:string -> + t -> kernel_function -> term option -> typ -> + string -> exp list -> + exp * t +(** [rtl_call_to_new_var env t ty name args] Same as [new_var] but initialize + the variable with a call to the RTL function [name] with the given [args]. +*) + module Logic_binding: sig val add: ?ty:typ -> t -> kernel_function -> logic_var -> varinfo * exp * t (* Add a new C binding to the list of bindings for the logic variable. *) @@ -139,8 +148,8 @@ end (** {2 Current annotation kind} *) (* ************************************************************************** *) -val annotation_kind: t -> Constructor.annotation_kind -val set_annotation_kind: t -> Constructor.annotation_kind -> t +val annotation_kind: t -> Smart_stmt.annotation_kind +val set_annotation_kind: t -> Smart_stmt.annotation_kind -> t (* ************************************************************************** *) (** {2 Loop invariants} *) diff --git a/src/plugins/e-acsl/src/code_generator/global_observer.ml b/src/plugins/e-acsl/src/code_generator/global_observer.ml index a89178c89937f87f01466e80690473f37d7f64e6..0e6a3ac2302a17cae489c61671fb46e4f7946ecc 100644 --- a/src/plugins/e-acsl/src/code_generator/global_observer.ml +++ b/src/plugins/e-acsl/src/code_generator/global_observer.ml @@ -123,8 +123,8 @@ let mk_init_function () = if Misc.is_fc_or_compiler_builtin vi then stmts else (* a global is both allocated and initialized *) - Constructor.mk_store_stmt vi - :: Constructor.mk_initialize ~loc:Location.unknown (Cil.var vi) + Smart_stmt.store_stmt vi + :: Smart_stmt.initialize ~loc:Location.unknown (Cil.var vi) :: stmts) tbl stmts @@ -136,10 +136,10 @@ let mk_init_function () = let loc = Location.unknown in let e = Cil.new_exp ~loc:loc (Const (CStr s)) in let str_size = Cil.new_exp loc (SizeOfStr s) in - Cil.mkStmtOneInstr ~valid_sid:true (Set(Cil.var vi, e, loc)) - :: Constructor.mk_store_stmt ~str_size vi - :: Constructor.mk_full_init_stmt vi - :: Constructor.mk_mark_readonly vi + Smart_stmt.assigns ~loc ~result:(Cil.var vi) e + :: Smart_stmt.store_stmt ~str_size vi + :: Smart_stmt.full_init_stmt vi + :: Smart_stmt.mark_readonly vi :: stmts) stmts in @@ -150,7 +150,7 @@ let mk_init_function () = let b, _env = Env.pop_and_get env stmt ~global_clear:true Env.Before in b, stmts in - let stmts = Cil.mkStmt ~valid_sid:true (Block b) :: stmts in + let stmts = Smart_stmt.block_stmt b :: stmts in (* prevent multiple calls to [__e_acsl_globals_init] *) let loc = Location.unknown in let vi_already_run = @@ -168,14 +168,18 @@ let mk_init_function () = (Local_init (vi_already_run, init, loc)) in let already_run = - Cil.mkStmtOneInstr ~valid_sid:true - (Set (Cil.var vi_already_run, Cil.one ~loc, loc)) + Smart_stmt.assigns + ~loc + ~result:(Cil.var vi_already_run) + (Cil.one ~loc) in let stmts = already_run :: stmts in let guard = - Cil.mkStmt - ~valid_sid:true - (If (Cil.evar vi_already_run, Cil.mkBlock [], Cil.mkBlock stmts, loc)) + Smart_stmt.if_stmt + ~loc + ~cond:(Cil.evar vi_already_run) + (Cil.mkBlock []) + ~else_blk:(Cil.mkBlock stmts) in let return = Cil.mkStmt ~valid_sid:true (Return (None, loc)) in let stmts = [ init_stmt; guard; return ] in @@ -191,7 +195,7 @@ let mk_delete_function () = Varinfo.Hashtbl.fold_sorted (fun vi _l acc -> if Misc.is_fc_or_compiler_builtin vi then acc - else Constructor.mk_delete_stmt vi :: acc) + else Smart_stmt.delete_stmt vi :: acc) tbl [] in diff --git a/src/plugins/e-acsl/src/code_generator/gmp.ml b/src/plugins/e-acsl/src/code_generator/gmp.ml index b35afd1163cd65d1ab4ff68e9c93e18a94fa0323..8a2b5385f1cb1830a92ff5272cb14bd0cd3d7c69 100644 --- a/src/plugins/e-acsl/src/code_generator/gmp.ml +++ b/src/plugins/e-acsl/src/code_generator/gmp.ml @@ -33,7 +33,7 @@ let apply_on_var ~loc funname e = else if Gmp_types.Q.is_t ty then "__gmpq_" else assert false in - Constructor.mk_lib_call ~loc (prefix ^ funname) [ e ] + Smart_stmt.lib_call ~loc (prefix ^ funname) [ e ] let init ~loc e = apply_on_var "init" ~loc e let clear ~loc e = apply_on_var "clear" ~loc e @@ -90,9 +90,9 @@ let generic_affect ~loc fname lv ev e = let ty = Cil.typeOf ev in if Gmp_types.Z.is_t ty || Gmp_types.Q.is_t ty then begin let suf, args = get_set_suffix_and_arg ty e in - Constructor.mk_lib_call ~loc (fname ^ suf) (ev :: args) + Smart_stmt.lib_call ~loc (fname ^ suf) (ev :: args) end else - Cil.mkStmtOneInstr ~valid_sid:true (Set(lv, e, e.eloc)) + Smart_stmt.assigns ~loc:e.eloc ~result:lv e let init_set ~loc lv ev e = let fname = @@ -111,7 +111,7 @@ let init_set ~loc lv ev e = | Lval elv -> assert (Gmp_types.Z.is_t (Cil.typeOf ev)); let call = - Constructor.mk_lib_call ~loc + Smart_stmt.lib_call ~loc "__gmpz_import" [ ev; Cil.one ~loc; @@ -121,7 +121,7 @@ let init_set ~loc lv ev e = Cil.zero ~loc; Cil.mkAddrOf ~loc elv ] in - Cil.mkStmt ~valid_sid:true (Block (Cil.mkBlock [ init ~loc ev; call ])) + Smart_stmt.block_stmt (Cil.mkBlock [ init ~loc ev; call ]) | _ -> Error.not_yet "unsigned long long expression requiring GMP") | Longlong ILongLong -> diff --git a/src/plugins/e-acsl/src/code_generator/injector.ml b/src/plugins/e-acsl/src/code_generator/injector.ml index a0357a168fdf9772d83de8409e5734b3062a43da..cdc6486702d1fbcc234a0f0f7bf19b1f616e74c9 100644 --- a/src/plugins/e-acsl/src/code_generator/injector.ml +++ b/src/plugins/e-acsl/src/code_generator/injector.ml @@ -60,7 +60,7 @@ let inject_in_local_init loc env kf vi = function | ConsInit (fvi, sz :: _, _) as init when Functions.Libc.is_vla_alloc_name fvi.vname -> (* add a store statement when creating a variable length array *) - let store = Constructor.mk_store_stmt ~str_size:sz vi in + let store = Smart_stmt.store_stmt ~str_size:sz vi in let env = Env.add_stmt ~post:true env kf store in init, env @@ -68,9 +68,9 @@ let inject_in_local_init loc env kf vi = function when Options.Validate_format_strings.get () && Functions.Libc.is_printf_name fvi.vname -> - (* rewrite format functions (e.g., [printf]). *) - let name = Functions.RTL.get_rtl_replacement_name fvi.vname in - let new_vi = Misc.get_lib_fun_vi name in + (* rewrite libc function names (e.g., [printf]). *) + let name = Functions.RTL.libc_replacement_name fvi.vname in + let new_vi = try Builtins.find name with Not_found -> assert false in let fmt = Functions.Libc.get_printf_argument_str ~loc fvi.vname args in ConsInit(new_vi, fmt :: args, kind), env @@ -80,7 +80,7 @@ let inject_in_local_init loc env kf vi = function -> (* rewrite names of functions for which we have alternative definitions in the RTL. *) - fvi.vname <- Functions.RTL.get_rtl_replacement_name fvi.vname; + fvi.vname <- Functions.RTL.libc_replacement_name fvi.vname; init, env | AssignInit init -> @@ -109,7 +109,7 @@ let rename_caller loc args exp = match exp.enode with when Options.Replace_libc_functions.get () && Functions.RTL.has_rtl_replacement vi.vname -> - vi.vname <- Functions.RTL.get_rtl_replacement_name vi.vname; + vi.vname <- Functions.RTL.libc_replacement_name vi.vname; exp, args | Lval(Var vi, _) @@ -120,12 +120,12 @@ let rename_caller loc args exp = match exp.enode with from the above because argument list of format functions is extended with an argument describing actual variadic arguments *) (* replacement name, e.g., [printf] -> [__e_acsl_builtin_printf] *) - let name = Functions.RTL.get_rtl_replacement_name vi.vname in + let name = Functions.RTL.libc_replacement_name vi.vname in (* variadic arguments descriptor *) let fmt = Functions.Libc.get_printf_argument_str ~loc vi.vname args in - (* get the name of the library function we need. Cannot just rewrite the - name as AST check will then fail *) - let vi = Misc.get_lib_fun_vi name in + (* get the library function we need. Cannot just rewrite the name as AST + check will then fail *) + let vi = try Rtl.Symbols.find_vi name with Not_found -> assert false in Cil.evar vi, fmt :: args | _ -> @@ -145,13 +145,13 @@ let add_initializer loc ?vi lv ?(post=false) stmt env kf = (* bitfields are not yet supported ==> no initializer. a [not_yet] will be raised in [Translate]. *) if Cil.isBitfield lv then Cil.mkEmptyStmt () - else Constructor.mk_initialize ~loc lv + else Smart_stmt.initialize ~loc lv in let env = Env.add_stmt ~post ~before env kf new_stmt in let env = match vi with | None -> env | Some vi -> - let new_stmt = Constructor.mk_store_stmt vi in + let new_stmt = Smart_stmt.store_stmt vi in Env.add_stmt ~post ~before env kf new_stmt in env @@ -189,7 +189,7 @@ let inject_in_instr env kf stmt = function if Functions.Libc.is_vla_free caller then match args with | [ { enode = CastE (_, { enode = Lval (Var vi, NoOffset) }) } ] -> - let delete_block = Constructor.mk_delete_stmt ~is_addr:true vi in + let delete_block = Smart_stmt.delete_stmt ~is_addr:true vi in Env.add_stmt env kf delete_block | _ -> Options.fatal "The normalization of __fc_vla_free() has changed" else @@ -232,7 +232,7 @@ let add_new_block_in_stmt env kf stmt = in let mk_post_env env stmt = Annotations.fold_code_annot - (fun _ a env -> Translate.translate_post_code_annotation kf env a) + (fun _ a env -> Translate.translate_post_code_annotation kf stmt env a) stmt env in @@ -252,7 +252,7 @@ let add_new_block_in_stmt env kf stmt = let env = mk_post_env env stmt in (* also handle the postcondition of the function and clear the env *) - Translate.translate_post_spec kf env (Annotations.funspec kf) + Translate.translate_post_spec kf Kglobal env (Annotations.funspec kf) else env in @@ -263,7 +263,7 @@ let add_new_block_in_stmt env kf stmt = let b, env = Env.pop_and_get env new_stmt ~global_clear:true Env.After in - let new_stmt = Constructor.mk_block stmt b in + let new_stmt = Smart_stmt.block stmt b in if not (Cil_datatype.Stmt.equal stmt new_stmt) then begin (* move the labels of the return to the new block in order to evaluate the postcondition when jumping to them. *) @@ -293,7 +293,7 @@ let add_new_block_in_stmt env kf stmt = let post_block, env = Env.pop_and_get env - (Constructor.mk_block new_stmt pre_block) + (Smart_stmt.block new_stmt pre_block) ~global_clear:false Env.Before in @@ -302,7 +302,7 @@ let add_new_block_in_stmt env kf stmt = then Cil.transient_block post_block else post_block in - let res = Constructor.mk_block new_stmt post_block in + let res = Smart_stmt.block new_stmt post_block in if not (Cil_datatype.Stmt.equal new_stmt res) then E_acsl_label.move kf new_stmt res; res, env @@ -337,7 +337,7 @@ let insert_as_last_stmts_in_innermost_block ~last_stmts kf outer_block = match return_stmt with | Some return_stmt -> let b = Cil.mkBlock new_stmts in - let new_stmt = Constructor.mk_block return_stmt b in + let new_stmt = Smart_stmt.block return_stmt b in E_acsl_label.move kf return_stmt new_stmt; [ new_stmt ] | None -> new_stmts @@ -450,7 +450,7 @@ and inject_in_stmt env kf stmt = (* translate the precondition of the function *) if Functions.check kf then let funspec = Annotations.funspec kf in - Translate.translate_pre_spec kf env funspec + Translate.translate_pre_spec kf Kglobal env funspec else env else env @@ -459,7 +459,7 @@ and inject_in_stmt env kf stmt = let env = if Functions.check kf then Annotations.fold_code_annot - (fun _ a env -> Translate.translate_pre_code_annotation kf env a) + (fun _ a env -> Translate.translate_pre_code_annotation kf stmt env a) stmt env else @@ -516,7 +516,7 @@ and inject_in_block (env: Env.t) kf blk = List.fold_left (fun acc vi -> if Mmodel_analysis.must_model_vi ~kf vi - then Constructor.mk_delete_stmt vi :: acc + then Smart_stmt.delete_stmt vi :: acc else acc) stmts blk.blocals @@ -531,7 +531,7 @@ and inject_in_block (env: Env.t) kf blk = List.fold_left (fun acc vi -> if Mmodel_analysis.must_model_vi vi && not vi.vdefined - then Constructor.mk_store_stmt vi :: acc + then Smart_stmt.store_stmt vi :: acc else acc) blk.bstmts blk.blocals; @@ -589,6 +589,7 @@ let inject_in_fundec main fundec = in List.iter unghost_formal fundec.sformals; (* update environments *) + (* TODO: do it only for built-ins *) Builtins.update vi.vname vi; (* track function addresses but the main function that is tracked internally via RTL *) @@ -628,17 +629,15 @@ let unghost_vi vi = let inject_in_global (env, main) = function (* library functions and built-ins *) | GVarDecl(vi, _) | GVar(vi, _, _) - | GFunDecl(_, vi, _) | GFun({ svar = vi }, _) - when Misc.is_library_loc vi.vdecl || Builtins.mem vi.vname -> - Misc.register_library_function vi; - if Builtins.mem vi.vname then Builtins.update vi.vname vi; + | GFunDecl(_, vi, _) | GFun({ svar = vi }, _) when Builtins.mem vi.vname -> + Builtins.update vi.vname vi; env, main (* Cil built-ins and other library globals: nothing to do *) | GVarDecl(vi, _) | GVar(vi, _, _) | GFun({ svar = vi }, _) when Misc.is_fc_or_compiler_builtin vi -> env, main - | g when Misc.is_library_loc (Global.loc g) -> + | g when Rtl.Symbols.mem_global g -> env, main (* variable declarations *) @@ -822,8 +821,8 @@ let inject_mmodel_handler main = in let ptr_size = Cil.sizeOf loc Cil.voidPtrType in let args = args @ [ ptr_size ] in - let init = Constructor.mk_rtl_call loc "memory_init" args in - let clean = Constructor.mk_rtl_call loc "memory_clean" [] in + let init = Smart_stmt.rtl_call loc "memory_init" args in + let clean = Smart_stmt.rtl_call loc "memory_clean" [] in surround_function_with main fundec init (Some clean) in Extlib.may handle_main main @@ -845,7 +844,6 @@ let reset_all ast = Options.Run.off (); (* reset all the E-ACSL environments to their original states *) Mmodel_analysis.reset (); - Misc.reset (); Logic_functions.reset (); Literal_strings.reset (); Global_observer.reset (); @@ -862,8 +860,6 @@ let inject () = Options.feedback ~level:2 "injecting annotations as code in project %a" Project.pretty (Project.current ()); - Keep_status.before_translation (); - Misc.reorder_ast (); Gmp_types.init (); let ast = Ast.get () in inject_in_file ast; diff --git a/src/plugins/e-acsl/src/code_generator/logic_array.ml b/src/plugins/e-acsl/src/code_generator/logic_array.ml new file mode 100644 index 0000000000000000000000000000000000000000..08e9eda66c45e2f5e0967f4cd49c3a9340a85703 --- /dev/null +++ b/src/plugins/e-acsl/src/code_generator/logic_array.ml @@ -0,0 +1,294 @@ +(**************************************************************************) +(* *) +(* This file is part of the Frama-C's E-ACSL plug-in. *) +(* *) +(* Copyright (C) 2012-2020 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(* *) +(**************************************************************************) + +open Cil_types + +(* Forward references *) +let translate_rte_ref: + (?filter:(code_annotation -> bool) -> kernel_function -> Env.t -> exp -> + Env.t) ref = + let func ?filter _kf _env _e = + let _ = filter in + Extlib.mk_labeled_fun "translate_rte_ref" + in + ref func + +(** @return the content of the array type if [ty] is an array, or None + otherwise. *) +let rec get_array_typ_opt ty = + if Gmp_types.is_t ty then + (* GMP pointer types are declared as arrays of one element. They are treated + as a special case here to ensure that they are not considered as arrays. + *) + None + else + match ty with + | TNamed (r, _) -> get_array_typ_opt r.ttype + | TArray (t, eo, bsot, a) -> Some (t, eo, bsot, a) + | _ -> None + +let is_array ty = + match get_array_typ_opt ty with + | Some _ -> true + | None -> false + +(** Retrieve the length of the [array] expression in a new variable [name] and + return it as an expression. + If the length is present in the type then the function directly assigns the + length to the variable, otherwise it is computed with the formula + [length = (\block_length(array) - \offset(array)) / sizeof(elem_typ)]. *) +let length_exp ~loc kf env ~name array = + let elem_typ, array_len = + match get_array_typ_opt (Cil.typeOf array) with + | None -> Options.fatal "Trying to retrieve the length of a non-array" + | Some (t, len, _, _) -> t, len + in + try + let len = Cil.lenOfArray64 array_len in + (Cil.kinteger64 ~loc len), env + with Cil.LenOfArray -> + (* check RTE on the array before accessing its block length and offset *) + let env = !translate_rte_ref kf env array in + (* helper function *) + let rtl env name = + Env.rtl_call_to_new_var + ~loc + env + kf + None + Cil.theMachine.typeOfSizeOf + name + [ array ] + in + (* block_length(array) *) + let block_length_exp, env = rtl env "block_length" in + (* offset(array) *) + let offset_exp, env = rtl env "offset" in + (* sizeof(elem_typ) *) + let sizeof_exp = Cil.new_exp ~loc (SizeOf elem_typ) in + (* Create var and compute length *) + let _, len_exp, env = + Env.new_var + ~loc + env + kf + None + ~name + Cil.theMachine.typeOfSizeOf + (fun v _ -> [ + Smart_stmt.assigns + ~loc + ~result:(Cil.var v) + (Cil.mkBinOp + ~loc + Div + (Cil.mkBinOp ~loc MinusA block_length_exp offset_exp) + sizeof_exp) + ]) + in + len_exp, env + +let comparison_to_exp ~loc kf env ~name bop array1 array2 = + (match bop with + | Eq | Ne -> () (* Ok *) + | _ -> + Options.fatal ~current:true "Something else than comparison of equality\ + between two arrays."); + + (* The generated code can be the same for [Ne] and [Eq] if we just adjust the + values for the result. + [res_value()] returns the initial value for + the result and [res_flip_value()] returns the flipped value of the result. + If the arrays have been coerced in ACSL to a different array size, then we + add a check to see if the coerced size is lesser or equal to then actual + length of the array. + The generated code returned by this function is equivalent to: + int result = res_value(); + size_t len1 = length(array1); + size_t len2 = length(array2); + if (len1 == len2) { + // Here we add check that the coerced length doesn't exceed the + // actual length of the arrays. + // Then we compare the content of the arrays, using the coerced + // length. + for (int i = 0 ; i < len1 ; ++i) { + if (array1[i] != array2[i]) { + result = res_value(flip); + break; + } + } + } else { + result = res_value(flip); + } + result + *) + let res_value ?(flip=false) () = + match flip, bop with + | false, Eq | true, Ne -> Cil.one ~loc + | true, Eq | false, Ne -> Cil.zero ~loc + | _ -> assert false + in + + (* Helper function: call [Env.pop_and_get] with [global_clear] and [where] + pre-set *) + let pop_and_get_env env stmt = + Env.pop_and_get + env + stmt + ~global_clear:false + Env.Middle + in + + (* Create var that will hold the result of the comparison between the + two arrays *) + let comparison_vi, comparison_exp, env = + Env.new_var + ~loc + env + kf + None + ~name + Cil.intType + (fun v _ -> [ Smart_stmt.assigns ~loc ~result:(Cil.var v) (res_value ()) ]) + in + + (* Retrieve the length of the arrays *) + let len1_exp, env = length_exp ~loc kf env ~name:"length1" array1 in + let len2_exp, env = length_exp ~loc kf env ~name:"length2" array2 in + + (* Push a new env to declare the variable that will hold the iterator of the + loop *) + let env = Env.push env in + let iter, iter_e, env = + Env.new_var + ~loc + env + kf + None + ~name:"iter" + Cil.theMachine.typeOfSizeOf + (fun _ _ -> []) + in + + (* Push a new env to do the innermost comparison between two elements of the + arrays. This env will enable us to also check RTEs *) + let env = Env.push env in + (* Create the access to the arrays *) + let array1_iter_e = Smart_exp.subscript ~loc array1 iter_e in + let array2_iter_e = Smart_exp.subscript ~loc array2 iter_e in + (* Check RTE on the arrays, filtering out bounding checks since the accesses + are built already in bounds *) + let filter a = + let index_bound = + Alarms.get_name (Index_out_of_bound (iter_e, Some len1_exp)) + in + match a.annot_content with + | AAssert (_, _, { pred_name = hd :: _ }) + when Datatype.String.equal hd index_bound -> false + | _ -> true + in + let env = !translate_rte_ref ~filter kf env array1_iter_e in + let env = !translate_rte_ref ~filter kf env array2_iter_e in + (* Create the condition *) + let cond = Cil.mkBinOp ~loc Ne array1_iter_e array2_iter_e in + (* Create the statement representing the body of the for loop *) + let body = + Smart_stmt.if_stmt + ~loc + ~cond + (Cil.mkBlock [ + Smart_stmt.assigns ~loc ~result:(Cil.var comparison_vi) (res_value ~flip:true ()); + Smart_stmt.break ~loc + ]) + in + (* Pop the env to build the body of the for loop *) + let body_blk, env = pop_and_get_env env body in + + (* Create the statement representing the full for loop *) + let for_loop = + (Smart_stmt.block_stmt + (Cil.mkBlock + (Cil.mkForIncr + ~iter + ~first:(Cil.zero ~loc) + ~stopat:len1_exp + ~incr:(Cil.one ~loc) + ~body:[ Smart_stmt.block_stmt body_blk ] + ) + ) + ) + in + + (* Create the list of statements that will be in the `then` block of the + top-level if *) + let then_stmts = [ for_loop ] in + + (* Add the check for the length before the for loop *) + let prepend_coercion_check ~name env stmts array len = + let array_orig = Option.get (Misc.extract_uncoerced_lval array) in + if array_orig == array then + stmts, env + else + let len_orig, env = + length_exp ~loc kf env ~name:(name ^ "_orig") array_orig + in + let e = Cil.mkBinOp ~loc Le len len_orig in + let p = + Logic_const.prel + ~loc + (Rle, Logic_utils.expr_to_term len, Logic_utils.expr_to_term len_orig) + in + let p = { p with pred_name = "array_coercion" :: p.pred_name } in + let stmt = + Smart_stmt.runtime_check Smart_stmt.RTE kf e p + in + stmt :: stmts, env + in + let then_stmts, env = + prepend_coercion_check ~name:"length2" env then_stmts array2 len2_exp + in + let then_stmts, env = + prepend_coercion_check ~name:"length1" env then_stmts array1 len1_exp + in + + (* Pop the env to build the full then block *) + let then_blk, env = + pop_and_get_env env (Smart_stmt.block_stmt (Cil.mkBlock then_stmts)) + in + + (* Create the statement representing the whole generated code *) + let stmt = + Smart_stmt.if_stmt + ~loc + ~cond:(Cil.mkBinOp ~loc Eq len1_exp len2_exp) + then_blk + ~else_blk:(Cil.mkBlock + [ Smart_stmt.assigns + ~loc + ~result:(Cil.var comparison_vi) + (res_value ~flip:true ()) ]) + in + (* Build the statement in the current env *) + let env = Env.add_stmt env kf stmt in + + (* Return the result expression with the result of the comparison *) + comparison_exp, env diff --git a/src/plugins/value/utils/state_import.mli b/src/plugins/e-acsl/src/code_generator/logic_array.mli similarity index 53% rename from src/plugins/value/utils/state_import.mli rename to src/plugins/e-acsl/src/code_generator/logic_array.mli index b1c140858e281e095bf70f5e95b955d2ea462db9..e6ca3976f85d4fba9837cafe40bd9f674d85f446 100644 --- a/src/plugins/value/utils/state_import.mli +++ b/src/plugins/e-acsl/src/code_generator/logic_array.mli @@ -1,8 +1,8 @@ (**************************************************************************) (* *) -(* This file is part of Frama-C. *) +(* This file is part of the Frama-C's E-ACSL plug-in. *) (* *) -(* Copyright (C) 2007-2020 *) +(* Copyright (C) 2012-2020 *) (* CEA (Commissariat à l'énergie atomique et aux énergies *) (* alternatives) *) (* *) @@ -20,24 +20,23 @@ (* *) (**************************************************************************) -(** Saving/loading of Value states, possibly among different ASTs. - Used by the command-line options defined by - [Value_parameters.SaveFunctionState] and - [Value_parameters.LoadFunctionState]. - @since Aluminium-20160501 *) +open Cil_types -(** Loads the saved initial global state, and merges it with the given state - (locals plus new globals which were not present in the original AST). - The saved state may come from a different project. - Note that, to ensure soundness of the merge, some constraints must be - respected according to where the merge takes place. - The intended use is to replace costly function calls, in which case - the state of local variables should not be modified by the function. *) -val load_and_merge_function_state: Cvalue.Model.t -> Cvalue.Model.t +val is_array: typ -> bool +(** @return true iff the type is an array *) -(** Saves the final state of globals variables after the return statement of - the function defined via [Value_parameters.SaveFunctionState]. The result - is saved in the file defined by the same option. - The function must have been called exactly once during the value analysis, - otherwise the saved state is unspecified. *) -val save_globals_state: unit -> unit +val comparison_to_exp: loc:location -> kernel_function -> Env.t -> + name:string -> binop -> exp -> exp -> exp * Env.t +(** [comparison_to_exp ~loc kf env ~name bop e1 e2] generate the C code + equivalent to [e1 bop e2]. + Requires that [bop] is either [Ne] or [Eq] and that [e1] and [e2] are + arrays. *) + + +(**************************************************************************) +(********************** Forward references ********************************) +(**************************************************************************) + +val translate_rte_ref: + (?filter:(code_annotation -> bool) -> kernel_function -> Env.t -> exp -> + Env.t) ref diff --git a/src/plugins/e-acsl/src/code_generator/logic_functions.ml b/src/plugins/e-acsl/src/code_generator/logic_functions.ml index c51d4190fe76bfd16f63f4daed9ac65f219607ff..97c6523575a25720e3316e1fd0a532bf7331894a 100644 --- a/src/plugins/e-acsl/src/code_generator/logic_functions.ml +++ b/src/plugins/e-acsl/src/code_generator/logic_functions.ml @@ -98,7 +98,7 @@ let term_to_block ~loc kf env ret_ty ret_vi t = function (by reference). *) let set = let lv_star_ret = Cil.mkMem ~addr:(Cil.evar ~loc ret_vi) ~off:NoOffset in - let star_ret = Cil.new_exp ~loc (Lval lv_star_ret) in + let star_ret = Smart_exp.lval ~loc lv_star_ret in Gmp.init_set ~loc lv_star_ret star_ret e in let return_void = Cil.mkStmt ~valid_sid:true (Return (None, loc)) in diff --git a/src/plugins/e-acsl/src/code_generator/loops.ml b/src/plugins/e-acsl/src/code_generator/loops.ml index d76bac69fc4f89b825141d83ccc88461fb9f0289..c8a5f714ddc2b23fab8a20edded2bd7ea2b6d663 100644 --- a/src/plugins/e-acsl/src/code_generator/loops.ml +++ b/src/plugins/e-acsl/src/code_generator/loops.ml @@ -59,11 +59,11 @@ let preserve_invariant env kf stmt = match stmt.skind with let blk, env = Env.pop_and_get env last ~global_clear:false Env.Before in - Constructor.mk_block last blk :: stmts, env + Smart_stmt.block last blk :: stmts, env | s :: tl -> handle_invariants (s :: stmts, env) tl in - let env = Env.set_annotation_kind env Constructor.Invariant in + let env = Env.set_annotation_kind env Smart_stmt.Invariant in let stmts, env = handle_invariants ([], env) stmts in let new_blk = { blk with bstmts = List.rev stmts } in { stmt with skind = Loop([], new_blk, loc, cont, break) }, @@ -212,7 +212,7 @@ let rec mk_nested_loops ~loc mk_innermost_block kf env lscope_vars = Env.Middle in (* generate the guard [x bop t2] *) - let block_to_stmt b = mkStmt ~valid_sid:true (Block b) in + let block_to_stmt b = Smart_stmt.block_stmt b in let tlv = Logic_const.tvar ~loc logic_x in let guard = (* must copy [t2] to force being typed again *) @@ -221,16 +221,14 @@ let rec mk_nested_loops ~loc mk_innermost_block kf env lscope_vars = in Typing.type_term ~use_gmp_opt:false ~ctx:Typing.c_int guard; let guard_exp, env = term_to_exp kf (Env.push env) guard in - let break_stmt = mkStmt ~valid_sid:true (Break guard_exp.eloc) in + let break_stmt = Smart_stmt.break ~loc:guard_exp.eloc in let guard_blk, env = Env.pop_and_get env - (mkStmt - ~valid_sid:true - (If( - guard_exp, - mkBlock [ mkEmptyStmt ~loc () ], - mkBlock [ break_stmt ], - guard_exp.eloc))) + (Smart_stmt.if_stmt + ~loc:guard_exp.eloc + ~cond:guard_exp + (mkBlock [ mkEmptyStmt ~loc () ]) + ~else_blk:(mkBlock [ break_stmt ])) ~global_clear:false Env.Middle in @@ -253,10 +251,10 @@ let rec mk_nested_loops ~loc mk_innermost_block kf env lscope_vars = | Some p -> let e, env = !named_predicate_ref kf (Env.push env) p in let stmt, env = - Constructor.mk_runtime_check Constructor.RTE kf e p, env + Smart_stmt.runtime_check Smart_stmt.RTE kf e p, env in let b, env = Env.pop_and_get env stmt ~global_clear:false Env.After in - let guard_for_small_type = Cil.mkStmt ~valid_sid:true (Block b) in + let guard_for_small_type = Smart_stmt.block_stmt b in guard_for_small_type :: guard :: body @ [ next ], env in let start = block_to_stmt init_blk in diff --git a/src/plugins/e-acsl/src/code_generator/memory_observer.ml b/src/plugins/e-acsl/src/code_generator/memory_observer.ml index 0ec5cda04ef5f39be1210766ebaca866b748dd37..629e30432278b7a6912f33453939a7476c31632e 100644 --- a/src/plugins/e-acsl/src/code_generator/memory_observer.ml +++ b/src/plugins/e-acsl/src/code_generator/memory_observer.ml @@ -39,7 +39,7 @@ let store ?before env kf vars = tracking_stmt ?before List.fold_right (* small list *) - Constructor.mk_store_stmt + Smart_stmt.store_stmt env kf vars @@ -48,7 +48,7 @@ let duplicate_store ?before env kf vars = tracking_stmt ?before Varinfo.Set.fold - Constructor.mk_duplicate_store_stmt + Smart_stmt.duplicate_store_stmt env kf vars @@ -57,7 +57,7 @@ let delete_from_list ?before env kf vars = tracking_stmt ?before List.fold_right (* small list *) - Constructor.mk_delete_stmt + Smart_stmt.delete_stmt env kf vars @@ -66,7 +66,7 @@ let delete_from_set ?before env kf vars = tracking_stmt ?before Varinfo.Set.fold - Constructor.mk_delete_stmt + Smart_stmt.delete_stmt env kf vars diff --git a/src/plugins/e-acsl/src/code_generator/mmodel_translate.ml b/src/plugins/e-acsl/src/code_generator/mmodel_translate.ml index 41a1245eed32cade67ec277a16e931e21de66282..654433624a3147fc868f052b6d16ab13c9adfaa1 100644 --- a/src/plugins/e-acsl/src/code_generator/mmodel_translate.ml +++ b/src/plugins/e-acsl/src/code_generator/mmodel_translate.ml @@ -116,19 +116,15 @@ let call ~loc kf name ctx env t = assert (name = "base_addr" || name = "block_length" || name = "offset" || name ="freeable"); let e, env = !term_to_exp_ref kf (Env.rte env true) t in - let _, res, env = - Env.new_var - ~loc - ~name - env - kf - None - ctx - (fun v _ -> - let name = Functions.RTL.mk_api_name name in - [ Constructor.mk_lib_call ~loc ~result:(Cil.var v) name [ e ] ]) - in - res, env + Env.rtl_call_to_new_var + ~loc + ~name + env + kf + None + ctx + name + [ e ] (*****************************************************************************) (************************* Calls with Range Elimination **********************) @@ -159,8 +155,8 @@ let gmp_to_sizet ~loc kf env size p = None sizet (fun vi _ -> - [ Constructor.mk_runtime_check Constructor.RTE kf guard p; - Constructor.mk_lib_call ~loc + [ Smart_stmt.runtime_check Smart_stmt.RTE kf guard p; + Smart_stmt.lib_call ~loc ~result:(Cil.var vi) "__gmpz_get_ui" [ size ] ]) @@ -234,24 +230,20 @@ let call_memory_block ~loc kf name ctx env ptr r p = | _ -> assert false in (* generating env *) - let _, e, env = - Env.new_var - ~loc - ~name - env - kf - None - ctx - (fun v _ -> - let fname = Functions.RTL.mk_api_name name in - let args = match name with - | "valid" | "valid_read" -> [ ptr; size; base; base_addr ] - | "initialized" -> [ ptr; size ] - | _ -> Error.not_yet ("builtin " ^ name) - in - [ Constructor.mk_lib_call ~loc ~result:(Cil.var v) fname args ]) + let args = match name with + | "valid" | "valid_read" -> [ ptr; size; base; base_addr ] + | "initialized" -> [ ptr; size ] + | _ -> Error.not_yet ("builtin " ^ name) in - e, env + Env.rtl_call_to_new_var + ~loc + ~name + env + kf + None + ctx + name + args (* [call_with_ranges] handles ranges in [t] when calling builtin [name]. It only supports the following cases for the time being: @@ -342,23 +334,17 @@ let call_with_size ~loc kf name ctx env t p = let call_for_unsupported_constructs ~loc kf name ctx env t = let term_to_exp = !term_to_exp_ref in let e, env = term_to_exp kf (Env.rte env true) t in - let _, res, env = - Env.new_var - ~loc - ~name - env - kf - None - ctx - (fun v _ -> - let ty = Misc.cty t.term_type in - let sizeof = Misc.mk_ptr_sizeof ty loc in - [ Constructor.mk_rtl_call ~loc - ~result:(Cil.var v) - name - [ e; sizeof ] ]) - in - res, env + let ty = Misc.cty t.term_type in + let sizeof = Misc.mk_ptr_sizeof ty loc in + Env.rtl_call_to_new_var + ~loc + ~name + env + kf + None + ctx + name + [ e; sizeof ] in call_with_ranges ~loc @@ -382,21 +368,18 @@ let call_valid ~loc kf name ctx env t p = | Lval lv | StartOf lv -> Cil.mkAddrOrStartOf ~loc lv | _ -> assert false in - let _, res, env = - Env.new_var - ~loc - ~name - env - kf - None - ctx - (fun v _ -> - let ty = Misc.cty t.term_type in - let sizeof = Misc.mk_ptr_sizeof ty loc in - let args = [ e; sizeof; base; base_addr ] in - [ Constructor.mk_rtl_call ~loc ~result:(Cil.var v) name args ]) - in - res, env + let ty = Misc.cty t.term_type in + let sizeof = Misc.mk_ptr_sizeof ty loc in + let args = [ e; sizeof; base; base_addr ] in + Env.rtl_call_to_new_var + ~loc + ~name + env + kf + None + ctx + name + args in call_with_ranges ~loc diff --git a/src/plugins/e-acsl/src/code_generator/quantif.ml b/src/plugins/e-acsl/src/code_generator/quantif.ml index 7298f8c82bc652078a24a71b2a86d24010bf5b40..b32d939f05d87cf39e1b798480a59e53a44b6d52 100644 --- a/src/plugins/e-acsl/src/code_generator/quantif.ml +++ b/src/plugins/e-acsl/src/code_generator/quantif.ml @@ -174,7 +174,7 @@ let convert kf env loc is_forall p bounded_vars hyps goal = intType (fun v _ -> let lv = var v in - [ mkStmtOneInstr ~valid_sid:true (Set(lv, init_val, loc)) ]) + [ Smart_stmt.assigns ~loc ~result:lv init_val ]) in let end_loop_ref = ref dummyStmt in (* innermost block *) @@ -183,29 +183,28 @@ let convert kf env loc is_forall p bounded_vars hyps goal = to evaluation of the goal *) let named_predicate_to_exp = !predicate_to_exp_ref in let test, env = named_predicate_to_exp kf (Env.push env) goal in - let then_block = mkBlock [ mkEmptyStmt ~loc () ] in - let else_block = + let then_blk = mkBlock [ mkEmptyStmt ~loc () ] in + let else_blk = (* use a 'goto', not a simple 'break' in order to handle 'forall' with multiple binders (leading to imbricated loops) *) mkBlock - [ mkStmtOneInstr ~valid_sid:true (Set(var var_res, found_val, loc)); + [ Smart_stmt.assigns ~loc ~result:(var var_res) found_val; mkStmt ~valid_sid:true (Goto(end_loop_ref, loc)) ] in let blk, env = Env.pop_and_get env - (mkStmt ~valid_sid:true - (If(mk_guard test, then_block, else_block, loc))) + (Smart_stmt.if_stmt ~loc ~cond:(mk_guard test) then_blk ~else_blk) ~global_clear:false Env.After in let blk = Cil.flatten_transient_sub_blocks blk in - [ mkStmt ~valid_sid:true (Block blk) ], env + [ Smart_stmt.block_stmt blk ], env in let stmts, env = Loops.mk_nested_loops ~loc mk_innermost_block kf env lvs_guards in let env = - Env.add_stmt env kf (mkStmt ~valid_sid:true (Block (mkBlock stmts))) + Env.add_stmt env kf (Smart_stmt.block_stmt (mkBlock stmts)) in (* where to jump to go out of the loop *) let end_loop = mkEmptyStmt ~loc () in diff --git a/src/plugins/e-acsl/src/code_generator/rational.ml b/src/plugins/e-acsl/src/code_generator/rational.ml index 4c0ae922b43921e75e447b0fd6e5660a77f44a26..2f4417b0191213b6730879074147a5f66f68fe43 100644 --- a/src/plugins/e-acsl/src/code_generator/rational.ml +++ b/src/plugins/e-acsl/src/code_generator/rational.ml @@ -24,11 +24,10 @@ open Cil_types (* No init_set for GMPQ: init then set separately *) let init_set ~loc lval vi_e e = - Cil.mkStmt - ~valid_sid:true - (Block (Cil.mkBlock - [ Gmp.init ~loc vi_e ; - Gmp.affect ~loc lval vi_e e ])) + Smart_stmt.block_stmt + (Cil.mkBlock + [ Gmp.init ~loc vi_e ; + Gmp.affect ~loc lval vi_e e ]) let create ~loc ?name e env kf t_opt = let ty = Cil.typeOf e in @@ -149,7 +148,7 @@ let add_cast ~loc ?name e env kf ty = None Cil.doubleType (fun v _ -> - [ Constructor.mk_lib_call ~loc + [ Smart_stmt.lib_call ~loc ~result:(Cil.var v) "__gmpq_get_d" [ e ] ]) @@ -198,7 +197,7 @@ let cmp ~loc bop e1 e2 env kf t_opt = ~name Cil.intType (fun v _ -> - [ Constructor.mk_lib_call ~loc ~result:(Cil.var v) fname [ e1; e2 ] ]) + [ Smart_stmt.lib_call ~loc ~result:(Cil.var v) fname [ e1; e2 ] ]) in Cil.new_exp ~loc (BinOp(bop, e, Cil.zero ~loc, Cil.intType)), env @@ -227,7 +226,7 @@ let binop ~loc bop e1 e2 env kf t_opt = [e2] *) let e1, env = create ~loc e1 env kf None in let e2, env = create ~loc e2 env kf None in - let mk_stmts _ e = [ Constructor.mk_lib_call ~loc name [ e; e1; e2 ] ] in + let mk_stmts _ e = [ Smart_stmt.lib_call ~loc name [ e; e1; e2 ] ] in let name = Misc.name_of_binop bop in let _, e, env = new_var_and_init ~loc ~name env kf t_opt mk_stmts in e, env diff --git a/src/plugins/e-acsl/src/code_generator/smart_exp.ml b/src/plugins/e-acsl/src/code_generator/smart_exp.ml new file mode 100644 index 0000000000000000000000000000000000000000..f3dac85ffd20bd197d046e874ae3a7a40f68e207 --- /dev/null +++ b/src/plugins/e-acsl/src/code_generator/smart_exp.ml @@ -0,0 +1,46 @@ +(**************************************************************************) +(* *) +(* This file is part of the Frama-C's E-ACSL plug-in. *) +(* *) +(* Copyright (C) 2012-2020 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(* *) +(**************************************************************************) + +open Cil_types + +let lval ~loc lv = + Cil.new_exp ~loc (Lval lv) + +let deref ~loc lv = lval ~loc (Mem lv, NoOffset) + +let subscript ~loc array idx = + match Misc.extract_uncoerced_lval array with + | Some { enode = Lval lv } -> + let subscript_lval = Cil.addOffsetLval (Index(idx, NoOffset)) lv in + lval ~loc subscript_lval + | Some _ | None -> + Options.fatal + ~current:true + "Trying to create a subscript on an array that is not an Lval: %a" + Cil_types_debug.pp_exp + array + +(* +Local Variables: +compile-command: "make -C ../../../../.." +End: +*) diff --git a/src/plugins/e-acsl/src/code_generator/smart_exp.mli b/src/plugins/e-acsl/src/code_generator/smart_exp.mli new file mode 100644 index 0000000000000000000000000000000000000000..566702f1e8012f361cfb3beaf9e3683bf50f94a4 --- /dev/null +++ b/src/plugins/e-acsl/src/code_generator/smart_exp.mli @@ -0,0 +1,43 @@ +(**************************************************************************) +(* *) +(* This file is part of the Frama-C's E-ACSL plug-in. *) +(* *) +(* Copyright (C) 2012-2020 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(* *) +(**************************************************************************) + +open Cil_types + +(* ********************************************************************** *) +(* Helper functions to build expressions *) +(* ********************************************************************** *) + +val lval: loc:location -> lval -> exp +(** Construct an lval expression from an lval. *) + +val deref: loc:location -> exp -> exp +(** Construct a dereference of an expression. *) + +val subscript: loc:location -> exp -> exp -> exp +(** [mk_subscript ~loc array idx] Create an expression to access the [idx]'th + element of the [array]. *) + +(* +Local Variables: +compile-command: "make -C ../../../../.." +End: +*) diff --git a/src/plugins/e-acsl/src/code_generator/constructor.ml b/src/plugins/e-acsl/src/code_generator/smart_stmt.ml similarity index 77% rename from src/plugins/e-acsl/src/code_generator/constructor.ml rename to src/plugins/e-acsl/src/code_generator/smart_stmt.ml index eb010f92eb65a2cf9cacdd39a3e5ea53a47dd8d4..dec6438762f3afb494812fa1799af9bb3557ebc6 100644 --- a/src/plugins/e-acsl/src/code_generator/constructor.ml +++ b/src/plugins/e-acsl/src/code_generator/smart_stmt.ml @@ -23,18 +23,20 @@ open Cil_types (* ********************************************************************** *) -(* Expressions *) +(* Statements *) (* ********************************************************************** *) -let mk_deref ~loc lv = Cil.new_exp ~loc (Lval(Mem(lv), NoOffset)) +let stmt sk = Cil.mkStmt ~valid_sid:true sk +let instr i = stmt (Instr i) +let block_stmt blk = stmt (Block blk) +let call ~loc ?result e args = instr (Call(result, e, args, loc)) -(* ********************************************************************** *) -(* Statements *) -(* ********************************************************************** *) +let assigns ~loc ~result e = instr (Set(result, e, loc)) + +let if_stmt ~loc ~cond ?(else_blk=Cil.mkBlock []) then_blk = + stmt (If (cond, then_blk, else_blk, loc)) -let mk_stmt sk = Cil.mkStmt ~valid_sid:true sk -let mk_instr i = mk_stmt (Instr i) -let mk_call ~loc ?result e args = mk_instr (Call(result, e, args, loc)) +let break ~loc = stmt (Break loc) type annotation_kind = | Assertion @@ -53,20 +55,25 @@ let kind_to_string loc k = | Invariant -> "Invariant" | RTE -> "RTE") -let mk_block stmt b = match b.bstmts with +let block stmt b = match b.bstmts with | [] -> (match stmt.skind with | Instr(Skip _) -> stmt | _ -> assert false) | [ s ] -> s - | _ :: _ -> mk_stmt (Block b) + | _ :: _ -> block_stmt b (* ********************************************************************** *) (* E-ACSL specific code *) (* ********************************************************************** *) -let mk_lib_call ~loc ?result fname args = - let vi = Misc.get_lib_fun_vi fname in +let lib_call ~loc ?result fname args = + let vi = + try Rtl.Symbols.find_vi fname + with Rtl.Symbols.Unregistered _ as exn -> + try Builtins.find fname + with Not_found -> raise exn + in let f = Cil.evar ~loc vi in vi.vreferenced <- true; let make_args ~variadic args param_ty = @@ -96,32 +103,32 @@ let mk_lib_call ~loc ?result fname args = | TFun(_, None, _, _) -> [] | _ -> assert false in - mk_call ~loc ?result f args + call ~loc ?result f args -let mk_rtl_call ~loc ?result fname args = - mk_lib_call ~loc ?result (Functions.RTL.mk_api_name fname) args +let rtl_call ~loc ?result fname args = + lib_call ~loc ?result (Functions.RTL.mk_api_name fname) args (* ************************************************************************** *) (** {2 Handling the E-ACSL's C-libraries, part II} *) (* ************************************************************************** *) -let mk_full_init_stmt vi = +let full_init_stmt vi = let loc = vi.vdecl in - mk_rtl_call ~loc "full_init" [ Cil.evar ~loc vi ] + rtl_call ~loc "full_init" [ Cil.evar ~loc vi ] -let mk_initialize ~loc (host, offset as lv) = match host, offset with +let initialize ~loc (host, offset as lv) = match host, offset with | Var _, NoOffset -> - mk_rtl_call ~loc "full_init" [ Cil.mkAddrOf ~loc lv ] + rtl_call ~loc "full_init" [ Cil.mkAddrOf ~loc lv ] | _ -> let typ = Cil.typeOfLval lv in - mk_rtl_call ~loc + rtl_call ~loc "initialize" [ Cil.mkAddrOf ~loc lv; Cil.new_exp loc (SizeOf typ) ] -let mk_named_store_stmt name ?str_size vi = +let named_store_stmt name ?str_size vi = let ty = Cil.unrollType vi.vtype in let loc = vi.vdecl in - let store = mk_rtl_call ~loc name in + let store = rtl_call ~loc name in match ty, str_size with | TArray(_, Some _,_,_), None -> store [ Cil.evar ~loc vi; Cil.sizeOf ~loc ty ] @@ -141,27 +148,27 @@ let mk_named_store_stmt name ?str_size vi = Printer.pp_typ ty Printer.pp_exp size -let mk_store_stmt ?str_size vi = - mk_named_store_stmt "store_block" ?str_size vi +let store_stmt ?str_size vi = + named_store_stmt "store_block" ?str_size vi -let mk_duplicate_store_stmt ?str_size vi = - mk_named_store_stmt "store_block_duplicate" ?str_size vi +let duplicate_store_stmt ?str_size vi = + named_store_stmt "store_block_duplicate" ?str_size vi -let mk_delete_stmt ?(is_addr=false) vi = +let delete_stmt ?(is_addr=false) vi = let loc = vi.vdecl in - let mk = mk_rtl_call ~loc "delete_block" in + let mk = rtl_call ~loc "delete_block" in match is_addr, Cil.unrollType vi.vtype with | _, TArray(_, Some _, _, _) | true, _ -> mk [ Cil.evar ~loc vi ] | _ -> mk [ Cil.mkAddrOfVi vi ] -let mk_mark_readonly vi = +let mark_readonly vi = let loc = vi.vdecl in - mk_rtl_call ~loc "mark_readonly" [ Cil.evar ~loc vi ] + rtl_call ~loc "mark_readonly" [ Cil.evar ~loc vi ] -let mk_runtime_check_with_msg ~loc msg kind kf e = +let runtime_check_with_msg ~loc msg kind kf e = let file = (fst loc).Filepath.pos_path in let line = (fst loc).Filepath.pos_lnum in - mk_rtl_call ~loc + rtl_call ~loc "assert" [ e; kind_to_string loc kind; @@ -170,13 +177,13 @@ let mk_runtime_check_with_msg ~loc msg kind kf e = Cil.mkString ~loc (Filepath.Normalized.to_pretty_string file); Cil.integer loc line ] -let mk_runtime_check kind kf e p = +let runtime_check kind kf e p = let loc = p.pred_loc in let msg = Kernel.Unicode.without_unicode (Format.asprintf "%a@?" Printer.pp_predicate) p in - mk_runtime_check_with_msg ~loc msg kind kf e + runtime_check_with_msg ~loc msg kind kf e (* Local Variables: diff --git a/src/plugins/e-acsl/src/code_generator/constructor.mli b/src/plugins/e-acsl/src/code_generator/smart_stmt.mli similarity index 64% rename from src/plugins/e-acsl/src/code_generator/constructor.mli rename to src/plugins/e-acsl/src/code_generator/smart_stmt.mli index 676bfe14af6286cc19179f2d0c8c0aa1a6badc4e..e0c919a7f8847b7c23e71d536b619837ed59a2f5 100644 --- a/src/plugins/e-acsl/src/code_generator/constructor.mli +++ b/src/plugins/e-acsl/src/code_generator/smart_stmt.mli @@ -20,56 +20,73 @@ (* *) (**************************************************************************) -(** Smart constructors for building C code. *) - open Cil_types -open Cil_datatype -val mk_deref: loc:Location.t -> exp -> exp -(** Construct a dereference of an expression. *) +(* ********************************************************************** *) +(* Helper functions to build statements *) +(* ********************************************************************** *) + +val stmt: stmtkind -> stmt +(** Create a statement from a statement kind. *) -val mk_block: stmt -> block -> stmt +val block: stmt -> block -> stmt (** Create a block statement from a block to replace a given statement. Requires that (1) the block is not empty, or (2) the statement is a skip. *) +val block_stmt: block -> stmt +(** Create a block statement from a block *) + +val assigns: loc:location -> result:lval -> exp -> stmt +(** [assigns ~loc ~result value] create a statement to assign the [value] + expression to the [result] lval. *) + +val if_stmt: + loc:location -> cond:exp -> ?else_blk:block -> block -> stmt +(** [if ~loc ~cond ~then_blk ~else_blk] create an if statement with [cond] + as condition and [then_blk] and [else_blk] as respectively "then" block and + "else" block. *) + +val break: loc:location -> stmt +(** Create a break statement *) + (* ********************************************************************** *) (* E-ACSL specific code: build calls to its RTL API *) (* ********************************************************************** *) -val mk_lib_call: loc:Location.t -> ?result:lval -> string -> exp list -> stmt +val lib_call: loc:location -> ?result:lval -> string -> exp list -> stmt (** Construct a call to a library function with the given name. - @raise Unregistered_library_function if the given string does not represent + @raise Rtl.Symbols.Unregistered if the given string does not represent such a function or if library functions were never registered (only possible when using E-ACSL through its API). *) -val mk_rtl_call: loc:Location.t -> ?result:lval -> string -> exp list -> stmt -(** Special version of [mk_lib_call] for E-ACSL's RTL functions. *) +val rtl_call: loc:location -> ?result:lval -> string -> exp list -> stmt +(** Special version of [lib_call] for E-ACSL's RTL functions. *) -val mk_store_stmt: ?str_size:exp -> varinfo -> stmt +val store_stmt: ?str_size:exp -> varinfo -> stmt (** Construct a call to [__e_acsl_store_block] that observes the allocation of the given varinfo. See [share/e-acsl/e_acsl.h] for details about this function. *) -val mk_duplicate_store_stmt: ?str_size:exp -> varinfo -> stmt -(** Same as [mk_store_stmt] for [__e_acsl_duplicate_store_block] that first +val duplicate_store_stmt: ?str_size:exp -> varinfo -> stmt +(** Same as [store_stmt] for [__e_acsl_duplicate_store_block] that first checks for a previous allocation of the given varinfo. *) -val mk_delete_stmt: ?is_addr:bool -> varinfo -> stmt -(** Same as [mk_store_stmt] for [__e_acsl_delete_block] that observes the +val delete_stmt: ?is_addr:bool -> varinfo -> stmt +(** Same as [store_stmt] for [__e_acsl_delete_block] that observes the de-allocation of the given varinfo. If [is_addr] is false (default), take the address of varinfo. *) -val mk_full_init_stmt: varinfo -> stmt -(** Same as [mk_store_stmt] for [__e_acsl_full_init] that observes the +val full_init_stmt: varinfo -> stmt +(** Same as [store_stmt] for [__e_acsl_full_init] that observes the initialization of the given varinfo. The varinfo is the address to fully initialize, no [addrOf] is taken. *) -val mk_initialize: loc:location -> lval -> stmt -(** Same as [mk_store_stmt] for [__e_acsl_initialize] that observes the +val initialize: loc:location -> lval -> stmt +(** Same as [store_stmt] for [__e_acsl_initialize] that observes the initialization of the given left-value. *) -val mk_mark_readonly: varinfo -> stmt -(** Same as [mk_store_stmt] for [__e_acsl_markreadonly] that observes the +val mark_readonly: varinfo -> stmt +(** Same as [store_stmt] for [__e_acsl_markreadonly] that observes the read-onlyness of the given varinfo. *) type annotation_kind = @@ -79,16 +96,16 @@ type annotation_kind = | Invariant | RTE -val mk_runtime_check: +val runtime_check: annotation_kind -> kernel_function -> exp -> predicate -> stmt -(** [mk_runtime_check kind kf e p] generates a runtime check for predicate [p] +(** [runtime_check kind kf e p] generates a runtime check for predicate [p] by building a call to [__e_acsl_assert]. [e] (or [!e] if [reverse] is set to [true]) is the C translation of [p], [kf] is the current kernel_function and [kind] is the annotation kind of [p]. *) -val mk_runtime_check_with_msg: +val runtime_check_with_msg: loc:location -> string -> annotation_kind -> kernel_function -> exp -> stmt -(** [mk_runtime_check_with_msg kind kf e msg] generates a runtime check for [e] +(** [runtime_check_with_msg kind kf e msg] generates a runtime check for [e] (or [!e] if [reverse] is [true]) by building a call to [__e_acsl_assert]. [msg] is the message printed if the runtime check fails. [loc] is the location printed in the message if the runtime check fails. [kf] is the diff --git a/src/plugins/e-acsl/src/code_generator/temporal.ml b/src/plugins/e-acsl/src/code_generator/temporal.ml index 8686559615068533ec432a081e927c87e4ec9ea7..96f5c22ee29764fd99bded8ea64abf265fabb0d0 100644 --- a/src/plugins/e-acsl/src/code_generator/temporal.ml +++ b/src/plugins/e-acsl/src/code_generator/temporal.ml @@ -51,9 +51,9 @@ type flow = module Mk: sig (* Generate either - - [store_nblock(lhs, rhs)], or - - [store_nreferent(lhs, rhs)] - function call based on the value of [flow] *) + - [store_nblock(lhs, rhs)], or + - [store_nreferent(lhs, rhs)] + function call based on the value of [flow] *) val store_reference: loc:location -> flow -> lval -> exp -> stmt (* Generate a [save_*_parameter] call *) @@ -81,7 +81,7 @@ end = struct | Copy -> Options.fatal "Copy flow type in store_reference" in let fname = RTL.mk_temporal_name fname in - Constructor.mk_lib_call ~loc fname [ Cil.mkAddrOf ~loc lhs; rhs ] + Smart_stmt.lib_call ~loc fname [ Cil.mkAddrOf ~loc lhs; rhs ] let save_param ~loc flow lhs pos = let infix = match flow with @@ -91,13 +91,13 @@ end = struct in let fname = "save_" ^ infix ^ "_parameter" in let fname = RTL.mk_temporal_name fname in - Constructor.mk_lib_call ~loc fname [ lhs ; Cil.integer ~loc pos ] + Smart_stmt.lib_call ~loc fname [ lhs ; Cil.integer ~loc pos ] let pull_param ~loc vi pos = let exp = Cil.mkAddrOfVi vi in let fname = RTL.mk_temporal_name "pull_parameter" in let sz = Cil.kinteger ~loc IULong (Cil.bytesSizeOf vi.vtype) in - Constructor.mk_lib_call ~loc fname [ exp ; Cil.integer ~loc pos ; sz ] + Smart_stmt.lib_call ~loc fname [ exp ; Cil.integer ~loc pos ; sz ] let handle_return_referent ~save ~loc lhs = let fname = match save with @@ -106,17 +106,17 @@ end = struct in (* TODO: Returning structs is unsupported so far *) (match (Cil.typeOf lhs) with - | TPtr _ -> () - | _ -> Error.not_yet "Struct in return"); - Constructor.mk_lib_call ~loc (RTL.mk_temporal_name fname) [ lhs ] + | TPtr _ -> () + | _ -> Error.not_yet "Struct in return"); + Smart_stmt.lib_call ~loc (RTL.mk_temporal_name fname) [ lhs ] let reset_return_referent ~loc = - Constructor.mk_lib_call ~loc (RTL.mk_temporal_name "reset_return") [] + Smart_stmt.lib_call ~loc (RTL.mk_temporal_name "reset_return") [] let temporal_memcpy_struct ~loc lhs rhs = let fname = RTL.mk_temporal_name "memcpy" in let size = Cil.sizeOf ~loc (Cil.typeOfLval lhs) in - Constructor.mk_lib_call ~loc fname [ Cil.mkAddrOf ~loc lhs; rhs; size ] + Smart_stmt.lib_call ~loc fname [ Cil.mkAddrOf ~loc lhs; rhs; size ] end (* }}} *) @@ -125,10 +125,10 @@ end (* ************************************************************************** *) (* Given an lvalue [lhs] representing LHS of an assignment, and an expression - [rhs] representing its RHS compute triple (l,r,f), such that: + [rhs] representing its RHS compute triple (l,r,f), such that: - lval [l] and exp [r] are addresses of a pointer and a memory block, and - flow [f] indicates how to update the meta-data of [l] using information - stored by [r]. The values of [f] indicate the following + stored by [r]. The values of [f] indicate the following + Direct - referent number of [l] is assigned the referent number of [r] + Indirect - referent number of [l] is assigned the origin number of [r] + Copy - metadata of [r] is copied to metadata of [l] *) @@ -145,51 +145,52 @@ let assign ?(ltype) lhs rhs loc = let base, _ = Misc.ptr_index rhs in let rhs, flow = (match base.enode with - | AddrOf _ - | StartOf _ -> rhs, Direct - (* Unary operator describes !, ~ or -: treat it same as Const since - it implies integer or logical operations. This case is rare but - happens: for instance in Gap SPEC CPU benchmark the returned pointer - is assigned -1 (for whatever bizarre reason) *) - | Const _ | UnOp _ -> base, Direct - (* Special case for literal strings which E-ACSL rewrites into - global variables: take the origin number of a string *) - | Lval(Var vi, _) when RTL.is_generated_name vi.vname -> - base, Direct - (* Lvalue of a pointer type can be a cast of an integral type, for - instance for the case when address is taken by value (shown via the - following example). - uintptr_t addr = ...; - char *p = (char* )addr; - If this is the case then the analysis takes the value of a variable. *) - | Lval lv -> - if Cil.isPointerType (Cil.unrollType (Cil.typeOfLval lv)) then - Cil.mkAddrOf ~loc lv, Indirect - else - rhs, Direct - (* Binary operation which yields an integer (or FP) type. - Since LHS is of pointer type we assume that the whole integer - expression computes to an address for which there is no - outer container, so the only thing to do is to take origin number *) - | BinOp(op, _, _, _) -> - (* At this point [ptr_index] should have split pointer arithmetic into - base pointer and index so there should be no pointer arithmetic - operations there. The following bit is to make sure of it. *) - (match op with + | AddrOf _ + | StartOf _ -> rhs, Direct + (* Unary operator describes !, ~ or -: treat it same as Const since + it implies integer or logical operations. This case is rare but + happens: for instance in Gap SPEC CPU benchmark the returned pointer + is assigned -1 (for whatever bizarre reason) *) + | Const _ | UnOp _ -> base, Direct + (* Special case for literal strings which E-ACSL rewrites into + global variables: take the origin number of a string *) + | Lval(Var vi, _) when RTL.is_generated_name vi.vname -> + base, Direct + (* Lvalue of a pointer type can be a cast of an integral type, for + instance for the case when address is taken by value (shown via the + following example). + uintptr_t addr = ...; + char *p = (char* )addr; + If this is the case then the analysis takes the value of a variable. + *) + | Lval lv -> + if Cil.isPointerType (Cil.unrollType (Cil.typeOfLval lv)) then + Cil.mkAddrOf ~loc lv, Indirect + else + rhs, Direct + (* Binary operation which yields an integer (or FP) type. + Since LHS is of pointer type we assume that the whole integer + expression computes to an address for which there is no + outer container, so the only thing to do is to take origin number *) + | BinOp(op, _, _, _) -> + (* At this point [ptr_index] should have split pointer arithmetic into + base pointer and index so there should be no pointer arithmetic + operations there. The following bit is to make sure of it. *) + (match op with | MinusPI | PlusPI | IndexPI -> assert false | _ -> ()); - base, Direct - | _ -> assert false) + base, Direct + | _ -> assert false) in Some (lhs, rhs, flow) | TNamed _ -> assert false | TInt _ | TFloat _ | TEnum _ -> None | TComp _ -> let rhs = match rhs.enode with - | AddrOf _ -> rhs - | Lval lv -> Cil.mkAddrOf ~loc lv - | Const _ | SizeOf _ | SizeOfE _ | SizeOfStr _ | AlignOf _ | AlignOfE _ - | UnOp _ | BinOp _ | CastE _ | StartOf _ | Info _ -> - Options.abort "unsupported RHS %a" Printer.pp_exp rhs + | AddrOf _ -> rhs + | Lval lv -> Cil.mkAddrOf ~loc lv + | Const _ | SizeOf _ | SizeOfE _ | SizeOfStr _ | AlignOf _ | AlignOfE _ + | UnOp _ | BinOp _ | CastE _ | StartOf _ | Info _ -> + Options.abort "unsupported RHS %a" Printer.pp_exp rhs in Some (lhs, rhs, Copy) (* va_list is a builtin type, we assume it has no pointers here and treat it as a "big" integer rather than a struct *) @@ -240,29 +241,29 @@ end = struct structure so they can be retrieved once that function is called *) let save_params current_stmt loc args env kf = let (env, _) = List.fold_left - (fun (env, index) param -> - let lv = Mem(param), NoOffset in - let ltype = Cil.typeOf param in - let vals = assign ~ltype lv param loc in - Extlib.may_map - (fun (_, rhs, flow) -> - let env = - if Mmodel_analysis.must_model_exp ~kf param then - let stmt = Mk.save_param ~loc flow rhs index in - Env.add_stmt ~before:current_stmt ~post:false env kf stmt - else env - in - (env, index+1)) - ~dft:(env, index+1) - vals) - (env, 0) - args + (fun (env, index) param -> + let lv = Mem(param), NoOffset in + let ltype = Cil.typeOf param in + let vals = assign ~ltype lv param loc in + Extlib.may_map + (fun (_, rhs, flow) -> + let env = + if Mmodel_analysis.must_model_exp ~kf param then + let stmt = Mk.save_param ~loc flow rhs index in + Env.add_stmt ~before:current_stmt ~post:false env kf stmt + else env + in + (env, index+1)) + ~dft:(env, index+1) + vals) + (env, 0) + args in env (* Update local environment with a statement tracking temporal metadata associated with assignment [ret] = [func(args)]. *) let call_with_ret ?(alloc=false) current_stmt loc ret env kf = - let rhs = Cil.new_exp ~loc (Lval ret) in + let rhs = Smart_exp.lval ~loc ret in let vals = assign ret rhs loc in (* Track referent numbers of assignments via function calls. Library functions (i.e., with no source code available) that return @@ -282,17 +283,17 @@ end = struct [pull_return] added via a call to [Mk.handle_return_referent] *) Extlib.may_map (fun (lhs, rhs, flow) -> - let flow, rhs = match flow with - | Indirect when alloc -> Direct, (Constructor.mk_deref ~loc rhs) - | _ -> flow, rhs - in - let stmt = - if alloc then - Mk.store_reference ~loc flow lhs rhs - else - Mk.handle_return_referent ~save:false ~loc (Cil.mkAddrOf ~loc lhs) - in - Env.add_stmt ~before:current_stmt ~post:true env kf stmt) + let flow, rhs = match flow with + | Indirect when alloc -> Direct, (Smart_exp.deref ~loc rhs) + | _ -> flow, rhs + in + let stmt = + if alloc then + Mk.store_reference ~loc flow lhs rhs + else + Mk.handle_return_referent ~save:false ~loc (Cil.mkAddrOf ~loc lhs) + in + Env.add_stmt ~before:current_stmt ~post:true env kf stmt) ~dft:env vals @@ -305,7 +306,7 @@ end = struct | _ -> Options.fatal "[Temporal.call_memxxx] not a left-value" in let stmt = - Constructor.mk_lib_call ~loc (RTL.mk_temporal_name name) args + Smart_stmt.lib_call ~loc (RTL.mk_temporal_name name) args in Env.add_stmt ~before:current_stmt ~post:false env kf stmt else @@ -320,7 +321,7 @@ end = struct the implementation of the function should be empty and compiler should be able to optimize that code out. *) let name = (RTL.mk_temporal_name "reset_parameters") in - let stmt = Constructor.mk_lib_call ~loc name [] in + let stmt = Smart_stmt.lib_call ~loc name [] in let env = Env.add_stmt ~before:current_stmt ~post:false env kf stmt in let stmt = Mk.reset_return_referent ~loc in let env = Env.add_stmt ~before:current_stmt ~post:false env kf stmt in @@ -340,9 +341,9 @@ end = struct let alloc = not has_def in Extlib.may_map (fun lhs -> - if Mmodel_analysis.must_model_lval ~kf lhs then - call_with_ret ~alloc current_stmt loc lhs env kf - else env) + if Mmodel_analysis.must_model_lval ~kf lhs then + call_with_ret ~alloc current_stmt loc lhs env kf + else env) ~dft:env ret end @@ -465,15 +466,15 @@ let mk_global_init ~loc vi off init = corresponding variable which that literal string has been converted to *) let exp = try let rec get_string e = match e.enode with - | Const(CStr str) -> str - | CastE(_, exp) -> get_string exp - | _ -> raise Not_found - in - let str = get_string exp in - Cil.evar ~loc (Literal_strings.find str) - with + | Const(CStr str) -> str + | CastE(_, exp) -> get_string exp + | _ -> raise Not_found + in + let str = get_string exp in + Cil.evar ~loc (Literal_strings.find str) + with (* Not a literal string: just use the expression at hand *) - Not_found -> exp + Not_found -> exp in (* The input [vi] is from the old project, so get the corresponding variable from the new one, otherwise AST integrity is violated *) @@ -488,15 +489,15 @@ let mk_global_init ~loc vi off init = let handle_function_parameters kf env = if is_enabled () then let env, _ = List.fold_left - (fun (env, index) param -> - let env = - if Mmodel_analysis.must_model_vi ~kf param - then track_argument param index env kf - else env - in - env, index + 1) - (env, 0) - (Kernel_function.get_formals kf) + (fun (env, index) param -> + let env = + if Mmodel_analysis.must_model_vi ~kf param + then track_argument param index env kf + else env + in + env, index + 1) + (env, 0) + (Kernel_function.get_formals kf) in env else env @@ -505,8 +506,8 @@ let handle_stmt stmt env kf = if is_enabled () then begin match stmt.skind with | Instr instr -> handle_instruction stmt instr env kf - | Return(ret, loc) -> Extlib.may_map - (fun ret -> handle_return_stmt loc ret env kf) ~dft:env ret + | Return(ret, loc) -> + Extlib.may_map (fun ret -> handle_return_stmt loc ret env kf) ~dft:env ret | Goto _ | Break _ | Continue _ | If _ | Switch _ | Loop _ | Block _ | UnspecifiedSequence _ | Throw _ | TryCatch _ | TryFinally _ | TryExcept _ -> env diff --git a/src/plugins/e-acsl/src/code_generator/temporal.mli b/src/plugins/e-acsl/src/code_generator/temporal.mli index 087683efea0f91666aa6e29ad8d8b3f98fe1179d..469df071656ebe7278c7090343e8ab85e3a71959 100644 --- a/src/plugins/e-acsl/src/code_generator/temporal.mli +++ b/src/plugins/e-acsl/src/code_generator/temporal.mli @@ -43,8 +43,8 @@ val handle_stmt: stmt -> Env.t -> kernel_function -> Env.t properties of memory blocks *) val generate_global_init: varinfo -> offset -> init -> stmt option - (** Generate [Some s], where [s] is a statement tracking global initializer - or [None] if there is no need to track it *) +(** Generate [Some s], where [s] is a statement tracking global initializer + or [None] if there is no need to track it *) (* Local Variables: diff --git a/src/plugins/e-acsl/src/code_generator/translate.ml b/src/plugins/e-acsl/src/code_generator/translate.ml index 4e310e1b4adfbc577e2aaa98178f4be15ed50693..2df14a6f11f222d8a098245d820b8623e232d83d 100644 --- a/src/plugins/e-acsl/src/code_generator/translate.ml +++ b/src/plugins/e-acsl/src/code_generator/translate.ml @@ -141,7 +141,7 @@ let add_cast ~loc ?name env kf ctx strnum t_opt e = None new_ty (fun v _ -> - [ Constructor.mk_lib_call ~loc ~result:(Cil.var v) fname [ e ] ]) + [ Smart_stmt.lib_call ~loc ~result:(Cil.var v) fname [ e ] ]) in e, env else if Gmp_types.Q.is_t ty || strnum = Str_R then @@ -221,15 +221,15 @@ let conditional_to_exp ?(name="if") loc kf t_opt e1 (e2, env2) (e3, env3) = Gmp.init_set in let affect e = init_set ~loc lv ev e in - let then_block, _ = + let then_blk, _ = let s = affect e2 in Env.pop_and_get env2 s ~global_clear:false Env.Middle in - let else_block, _ = + let else_blk, _ = let s = affect e3 in Env.pop_and_get env3 s ~global_clear:false Env.Middle in - [ Cil.mkStmt ~valid_sid:true (If(e1, then_block, else_block, loc)) ]) + [ Smart_stmt.if_stmt ~loc ~cond:e1 then_blk ~else_blk ]) in e, env @@ -276,7 +276,7 @@ and context_insensitive_term_to_exp kf env t = c, env, strnum, "" | TLval lv -> let lv, env, name = tlval_to_lval kf env lv in - Cil.new_exp ~loc (Lval lv), env, C_number, name + Smart_exp.lval ~loc lv, env, C_number, name | TSizeOf ty -> Cil.sizeOf ~loc ty, env, C_number, "sizeof" | TSizeOfE t -> let e, env = term_to_exp kf env t in @@ -303,7 +303,7 @@ and context_insensitive_term_to_exp kf env t = kf ~name:vname (Some t) - (fun _ ev -> [ Constructor.mk_lib_call ~loc name [ ev; e ] ]) + (fun _ ev -> [ Smart_stmt.lib_call ~loc name [ ev; e ] ]) in e, env, C_number, "" else if Gmp_types.Q.is_t ty then @@ -332,7 +332,7 @@ and context_insensitive_term_to_exp kf env t = let e2, env = term_to_exp kf env t2 in if Gmp_types.Z.is_t ty then let name = name_of_mpz_arith_bop bop in - let mk_stmts _ e = [ Constructor.mk_lib_call ~loc name [ e; e1; e2 ] ] in + let mk_stmts _ e = [ Smart_stmt.lib_call ~loc name [ e; e1; e2 ] ] in let name = Misc.name_of_binop bop in let _, e, env = Env.new_var_and_mpz_init ~loc ~name env kf (Some t) mk_stmts @@ -370,14 +370,14 @@ and context_insensitive_term_to_exp kf env t = let mk_stmts _v e = assert (Gmp_types.Z.is_t ty); let cond = - Constructor.mk_runtime_check + Smart_stmt.runtime_check (Env.annotation_kind env) kf guard p in Env.add_assert kf cond p; - let instr = Constructor.mk_lib_call ~loc name [ e; e1; e2 ] in + let instr = Smart_stmt.lib_call ~loc name [ e; e1; e2 ] in [ cond; instr ] in let name = Misc.name_of_binop bop in @@ -435,7 +435,7 @@ and context_insensitive_term_to_exp kf env t = (fun vi _e -> let result = Cil.var vi in let fname = "__gmpz_fits_ulong_p" in - [ Constructor.mk_lib_call ~loc ~result fname [ e2 ] ]) + [ Smart_stmt.lib_call ~loc ~result fname [ e2 ] ]) in e, env in @@ -454,8 +454,8 @@ and context_insensitive_term_to_exp kf env t = in let pname = bop_name ^ "_rhs_fits_in_mp_bitcnt_t" in let pred = { pred with pred_name = pname :: pred.pred_name } in - let cond = Constructor.mk_runtime_check - Constructor.RTE + let cond = Smart_stmt.runtime_check + Smart_stmt.RTE kf coerce_guard pred @@ -465,7 +465,7 @@ and context_insensitive_term_to_exp kf env t = in let result = Cil.var vi in let name = "__gmpz_get_ui" in - let instr = Constructor.mk_lib_call ~loc ~result name [ e2 ] in + let instr = Smart_stmt.lib_call ~loc ~result name [ e2 ] in [ coerce_guard_cond; instr ] in let name = e2_name ^ bop_name ^ "_coerced" in @@ -484,7 +484,7 @@ and context_insensitive_term_to_exp kf env t = (* Create the shift instruction *) let mk_shift_instr result_e = let name = name_of_mpz_arith_bop bop in - Constructor.mk_lib_call ~loc name [ result_e; e1; e2_as_bitcnt_e ] + Smart_stmt.lib_call ~loc name [ result_e; e1; e2_as_bitcnt_e ] in (* Put t in an option to use with comparison_to_exp and @@ -515,8 +515,8 @@ and context_insensitive_term_to_exp kf env t = in let e1_guard_cond = let pred = Logic_const.prel ~loc (Rge, t1, zero) in - let cond = Constructor.mk_runtime_check - Constructor.RTE + let cond = Smart_stmt.runtime_check + Smart_stmt.RTE kf e1_guard pred @@ -568,7 +568,7 @@ and context_insensitive_term_to_exp kf env t = if Gmp_types.Z.is_t ty then let mk_stmts _v e = let name = name_of_mpz_arith_bop bop in - let instr = Constructor.mk_lib_call ~loc name [ e; e1; e2 ] in + let instr = Smart_stmt.lib_call ~loc name [ e; e1; e2 ] in [ instr ] in let name = Misc.name_of_binop bop in @@ -646,7 +646,7 @@ and context_insensitive_term_to_exp kf env t = (Some t) (Misc.cty (Extlib.the li.l_type)) (fun vi _ -> - [ Constructor.mk_lib_call ~loc ~result:(Cil.var vi) fname args ]) + [ Smart_stmt.lib_call ~loc ~result:(Cil.var vi) fname args ]) else (* build the arguments and compute the integer_ty of the parameters *) let params_ty, args, env = @@ -686,7 +686,7 @@ and context_insensitive_term_to_exp kf env t = e, env, C_number, "" | Tat(t', label) -> let lscope = Env.Logic_scope.get env in - let pot = Misc.PoT_term t' in + let pot = Lscope.PoT_term t' in if Lscope.is_used lscope pot then let e, env = At_with_lscope.to_exp ~loc kf env pot label in e, env, C_number, "" @@ -762,29 +762,46 @@ and comparison_to_exp | Some e1 -> e1, env in + let ty1 = Cil.typeOf e1 in let e2, env = term_to_exp kf env t2 in - match ity with - | Typing.C_integer _ | Typing.C_float _ | Typing.Nan -> - Cil.mkBinOp ~loc bop e1 e2, env - | Typing.Gmpz -> - let _, e, env = Env.new_var - ~loc - env - kf - t_opt - ~name - Cil.intType - (fun v _ -> - [ Constructor.mk_lib_call ~loc - ~result:(Cil.var v) - "__gmpz_cmp" - [ e1; e2 ] ]) - in - Cil.new_exp ~loc (BinOp(bop, e, Cil.zero ~loc, Cil.intType)), env - | Typing.Rational -> - Rational.cmp ~loc bop e1 e2 env kf t_opt - | Typing.Real -> - Error.not_yet "comparison involving real numbers" + let ty2 = Cil.typeOf e2 in + match Logic_array.is_array ty1, Logic_array.is_array ty2 with + | true, true -> + Logic_array.comparison_to_exp + ~loc + kf + env + ~name + bop + e1 + e2 + | false, false -> ( + match ity with + | Typing.C_integer _ | Typing.C_float _ | Typing.Nan -> + Cil.mkBinOp ~loc bop e1 e2, env + | Typing.Gmpz -> + let _, e, env = Env.new_var + ~loc + env + kf + t_opt + ~name + Cil.intType + (fun v _ -> + [ Smart_stmt.lib_call ~loc + ~result:(Cil.var v) + "__gmpz_cmp" + [ e1; e2 ] ]) + in + Cil.new_exp ~loc (BinOp(bop, e, Cil.zero ~loc, Cil.intType)), env + | Typing.Rational -> + Rational.cmp ~loc bop e1 e2 env kf t_opt + | Typing.Real -> + Error.not_yet "comparison involving real numbers" + ) + | _, _ -> + Options.fatal ~current:true "Comparison involving an array with something \ + else." and at_to_exp_no_lscope env kf t_opt label e = let stmt = E_acsl_label.get_stmt kf label in @@ -838,7 +855,7 @@ and env_of_li li kf env loc = let e, env = term_to_exp kf env t in let stmt = match Typing.get_number_ty t with | Typing.(C_integer _ | C_float _ | Nan) -> - Cil.mkStmtOneInstr ~valid_sid:true (Set (Cil.var vi, e, loc)) + Smart_stmt.assigns ~loc ~result:(Cil.var vi) e | Typing.Gmpz -> Gmp.init_set ~loc (Cil.var vi) vi_e e | Typing.Rational -> @@ -930,7 +947,7 @@ and named_predicate_content_to_exp ?name kf env p = named_predicate_to_exp kf env p | Pat(p', label) -> let lscope = Env.Logic_scope.get env in - let pot = Misc.PoT_pred p' in + let pot = Lscope.PoT_pred p' in if Lscope.is_used lscope pot then At_with_lscope.to_exp ~loc kf env pot label else begin @@ -1016,7 +1033,7 @@ and translate_rte_annots: fun pp elt kf env l -> let old_valid = !is_visiting_valid in let old_kind = Env.annotation_kind env in - let env = Env.set_annotation_kind env Constructor.RTE in + let env = Env.set_annotation_kind env Smart_stmt.RTE in let env = List.fold_left (fun env a -> match a.annot_content with @@ -1040,9 +1057,14 @@ and translate_rte_annots: is_visiting_valid := old_valid; Env.set_annotation_kind env old_kind -and translate_rte kf env e = +and translate_rte ?filter kf env e = let stmt = Cil.mkStmtOneInstr ~valid_sid:true (Skip e.eloc) in let l = Rte.exp kf stmt e in + let l = + match filter with + | Some f -> List.filter f l + | None -> l + in translate_rte_annots Printer.pp_exp e kf env l and translate_named_predicate kf env p = @@ -1056,7 +1078,7 @@ and translate_named_predicate kf env p = Env.add_stmt env kf - (Constructor.mk_runtime_check + (Smart_stmt.runtime_check (Env.annotation_kind env) kf e @@ -1075,7 +1097,8 @@ let () = Mmodel_translate.term_to_exp_ref := term_to_exp; Mmodel_translate.predicate_to_exp_ref := named_predicate_to_exp; Logic_functions.term_to_exp_ref := term_to_exp; - Logic_functions.named_predicate_to_exp_ref := named_predicate_to_exp + Logic_functions.named_predicate_to_exp_ref := named_predicate_to_exp; + Logic_array.translate_rte_ref := translate_rte (* This function is used by Guillaume. However, it is correct to use it only in specific contexts. *) @@ -1105,19 +1128,35 @@ let term_to_exp typ t = let env = Env.rte env false in let e, env = try term_to_exp (Kernel_function.dummy ()) env t - with Misc.Unregistered_library_function _ -> raise (No_simple_translation t) + with Rtl.Symbols.Unregistered _ -> raise (No_simple_translation t) in if not (Env.has_no_new_stmt env) then raise (No_simple_translation t); e (* ************************************************************************** *) (* [translate_*] translates a given ACSL annotation into the corresponding C - statement (if any) for runtime assertion checking. - - IMPORTANT: the order of translation of pre-/post-spec must be consistent with - the pushes done in [Keep_status] *) + statement (if any) for runtime assertion checking. *) (* ************************************************************************** *) +let must_translate ppt = + Options.Valid.get () + || match Property_status.get ppt with + | Never_tried + | Inconsistent _ + | Best ((False_if_reachable | False_and_reachable | Dont_know), _) -> + true + | Best (True, _) -> + (* [TODO] generating code for "valid under hypotheses" properties could be + useful for some use cases (in particular, when E-ACSL does not stop on + the very first error). + ==> introduce a new option or modify the behavior of -e-acsl-valid, + see e-acsl#35 *) + false + +let must_translate_opt = function + | None -> false + | Some ppt -> must_translate ppt + let assumes_predicate bhv = List.fold_left (fun acc p -> @@ -1128,14 +1167,14 @@ let assumes_predicate bhv = Logic_const.ptrue bhv.b_assumes -let translate_preconditions kf env behaviors = - let env = Env.set_annotation_kind env Constructor.Precondition in +let translate_preconditions kf kinstr env behaviors = + let env = Env.set_annotation_kind env Smart_stmt.Precondition in let do_behavior env b = let assumes_pred = assumes_predicate b in List.fold_left (fun env p -> let do_it env = - if Keep_status.must_translate kf Keep_status.K_Requires then + if must_translate (Property.ip_of_requires kf kinstr b p) then let loc = p.ip_content.pred_loc in let p = Logic_const.pimplies @@ -1153,16 +1192,16 @@ let translate_preconditions kf env behaviors = in List.fold_left do_behavior env behaviors -let translate_postconditions kf env behaviors = - let env = Env.set_annotation_kind env Constructor.Postcondition in +let translate_postconditions kf kinstr env behaviors = + let env = Env.set_annotation_kind env Smart_stmt.Postcondition in (* generate one guard by postcondition of each behavior *) let do_behavior env b = let env = handle_error (fun env -> - (* test ordering does matter for keeping statuses consistent *) - if b.b_assigns <> WritesAny - && Keep_status.must_translate kf Keep_status.K_Assigns + let active = [] in (* TODO: 'for' behaviors, e-acsl#109 *) + let ppt = Property.ip_assigns_of_behavior kf kinstr ~active b in + if b.b_assigns <> WritesAny && must_translate_opt ppt then not_yet env "assigns clause in behavior"; (* ignore b.b_extended since we never translate them *) env) @@ -1170,8 +1209,8 @@ let translate_postconditions kf env behaviors = in let assumes_pred = assumes_predicate b in List.fold_left - (fun env (t, p) -> - if Keep_status.must_translate kf Keep_status.K_Ensures then + (fun env ((t, p) as tp) -> + if must_translate (Property.ip_of_ensures kf kinstr b tp) then let do_it env = match t with | Normal -> @@ -1198,57 +1237,54 @@ let translate_postconditions kf env behaviors = in List.fold_left do_behavior env bhvs -let translate_pre_spec kf env spec = +let translate_pre_spec kf kinstr env spec = let unsupported f x = ignore (handle_error (fun env -> f x; env) env) in let convert_unsupported_clauses env = unsupported - (Extlib.may - (fun _ -> - if Keep_status.must_translate kf Keep_status.K_Decreases then - not_yet env "variant clause")) - spec.spec_variant; + (fun spec -> + let ppt = Property.ip_decreases_of_spec kf kinstr spec in + if must_translate_opt ppt then not_yet env "variant clause") + spec; (* TODO: spec.spec_terminates is not part of the E-ACSL subset *) unsupported - (Extlib.may - (fun _ -> - if Keep_status.must_translate kf Keep_status.K_Terminates then - not_yet env "terminates clause")) - spec.spec_terminates; - (match spec.spec_complete_behaviors with - | [] -> () - | l -> - unsupported - (List.iter - (fun _ -> - if Keep_status.must_translate kf Keep_status.K_Complete then - not_yet env "complete behaviors")) - l); - (match spec.spec_disjoint_behaviors with - | [] -> () - | l -> - unsupported - (List.iter - (fun _ -> - if Keep_status.must_translate kf Keep_status.K_Disjoint then - not_yet env "disjoint behaviors")) - l); + (fun spec -> + let ppt = Property.ip_terminates_of_spec kf kinstr spec in + if must_translate_opt ppt then not_yet env "terminates clause") + spec; + let active = [] in (* TODO: 'for' behaviors, e-acsl#109 *) + let ppts = Property.ip_complete_of_spec kf kinstr ~active spec in + unsupported + (fun ppts -> + List.iter + (fun ppt -> + if must_translate ppt then not_yet env "complete behaviors") + ppts) + ppts; + let ppts = Property.ip_disjoint_of_spec kf kinstr ~active spec in + unsupported + (fun ppts -> + List.iter + (fun ppt -> + if must_translate ppt then not_yet env "disjoint behaviors") + ppts) + ppts; env in let env = convert_unsupported_clauses env in handle_error - (fun env -> translate_preconditions kf env spec.spec_behavior) + (fun env -> translate_preconditions kf kinstr env spec.spec_behavior) env -let translate_post_spec kf env spec = +let translate_post_spec kf kinstr env spec = handle_error - (fun env -> translate_postconditions kf env spec.spec_behavior) + (fun env -> translate_postconditions kf kinstr env spec.spec_behavior) env -let translate_pre_code_annotation kf env annot = +let translate_pre_code_annotation kf stmt env annot = let convert env = match annot.annot_content with | AAssert(l, _, p) -> - if Keep_status.must_translate kf Keep_status.K_Assert then - let env = Env.set_annotation_kind env Constructor.Assertion in + if must_translate (Property.ip_of_code_annot_single kf stmt annot) then + let env = Env.set_annotation_kind env Smart_stmt.Assertion in if l <> [] then not_yet env "@[assertion applied only on some behaviors@]"; translate_named_predicate kf env p @@ -1257,10 +1293,10 @@ let translate_pre_code_annotation kf env annot = | AStmtSpec(l, spec) -> if l <> [] then not_yet env "@[statement contract applied only on some behaviors@]"; - translate_pre_spec kf env spec ; + translate_pre_spec kf (Kstmt stmt) env spec ; | AInvariant(l, loop_invariant, p) -> - if Keep_status.must_translate kf Keep_status.K_Invariant then - let env = Env.set_annotation_kind env Constructor.Invariant in + if must_translate (Property.ip_of_code_annot_single kf stmt annot) then + let env = Env.set_annotation_kind env Smart_stmt.Invariant in if l <> [] then not_yet env "@[invariant applied only on some behaviors@]"; let env = translate_named_predicate kf env p in @@ -1268,26 +1304,31 @@ let translate_pre_code_annotation kf env annot = else env | AVariant _ -> - if Keep_status.must_translate kf Keep_status.K_Variant + if must_translate (Property.ip_of_code_annot_single kf stmt annot) then not_yet env "variant" else env | AAssigns _ -> - (* TODO: it is not a precondition *) - if Keep_status.must_translate kf Keep_status.K_Assigns - then not_yet env "assigns" - else env + (* TODO: it is not a precondition --> should not be handled here, + to be fixed when implementing e-acsl#29 *) + let ppts = Property.ip_of_code_annot kf stmt annot in + List.iter + (fun ppt -> if must_translate ppt then not_yet env "assigns") + ppts; + env | AAllocation _ -> - if Keep_status.must_translate kf Keep_status.K_Allocation - then not_yet env "allocation" - else env + let ppts = Property.ip_of_code_annot kf stmt annot in + List.iter + (fun ppt -> if must_translate ppt then not_yet env "allocation") + ppts; + env | APragma _ -> not_yet env "pragma" | AExtended _ -> env (* never translate extensions. *) in handle_error convert env -let translate_post_code_annotation kf env annot = +let translate_post_code_annotation kf stmt env annot = let convert env = match annot.annot_content with - | AStmtSpec(_, spec) -> translate_post_spec kf env spec + | AStmtSpec(_, spec) -> translate_post_spec kf (Kstmt stmt) env spec | AAssert _ | AInvariant _ | AVariant _ diff --git a/src/plugins/e-acsl/src/code_generator/translate.mli b/src/plugins/e-acsl/src/code_generator/translate.mli index b38599d54403b537afbb1dec5277430e3b4d0a6c..64a83c76113bbe3e29142f4d4d6981e74ae81d00 100644 --- a/src/plugins/e-acsl/src/code_generator/translate.mli +++ b/src/plugins/e-acsl/src/code_generator/translate.mli @@ -26,12 +26,12 @@ open Cil_types statement (if any) for runtime assertion checking. This C statements are part of the resulting environment. *) -val translate_pre_spec: kernel_function -> Env.t -> funspec -> Env.t -val translate_post_spec: kernel_function -> Env.t -> funspec -> Env.t +val translate_pre_spec: kernel_function -> kinstr -> Env.t -> funspec -> Env.t +val translate_post_spec: kernel_function -> kinstr -> Env.t -> funspec -> Env.t val translate_pre_code_annotation: - kernel_function -> Env.t -> code_annotation -> Env.t + kernel_function -> stmt -> Env.t -> code_annotation -> Env.t val translate_post_code_annotation: - kernel_function -> Env.t -> code_annotation -> Env.t + kernel_function -> stmt -> Env.t -> code_annotation -> Env.t val translate_named_predicate: kernel_function -> Env.t -> predicate -> Env.t @@ -50,6 +50,6 @@ val predicate_to_exp: kernel_function -> predicate -> exp (* Local Variables: -compile-command: "make -C ../.." +compile-command: "make -C ../../../../.." End: *) diff --git a/src/plugins/e-acsl/src/libraries/builtins.ml b/src/plugins/e-acsl/src/libraries/builtins.ml index 9bfe9fe7d7bf79638487c00e265ee2a35b533a79..fa5d9adf70ae5c12f251f9ba96bbcea4bc56558c 100644 --- a/src/plugins/e-acsl/src/libraries/builtins.ml +++ b/src/plugins/e-acsl/src/libraries/builtins.ml @@ -83,6 +83,6 @@ let () = Cmdline.run_after_configuring_stage init (* Local Variables: -compile-command: "make" +compile-command: "make -C ../../../../.." End: *) diff --git a/src/plugins/e-acsl/src/libraries/builtins.mli b/src/plugins/e-acsl/src/libraries/builtins.mli index 95dce5b8aab5bc88615f90a2274bccc9b79d521c..d15f53f6ef5284904b9f4c709a95cb78e7c6d5fc 100644 --- a/src/plugins/e-acsl/src/libraries/builtins.mli +++ b/src/plugins/e-acsl/src/libraries/builtins.mli @@ -35,6 +35,6 @@ val update: string -> Cil_types.varinfo -> unit (* Local Variables: -compile-command: "make" +compile-command: "make -C ../../../../.." End: *) diff --git a/src/plugins/e-acsl/src/libraries/functions.ml b/src/plugins/e-acsl/src/libraries/functions.ml index b939bcff401d0ea330544988bf4e96d8c43e0c02..37cf8f8319f67d966635e0704b8ed32bd6a5f91e 100644 --- a/src/plugins/e-acsl/src/libraries/functions.ml +++ b/src/plugins/e-acsl/src/libraries/functions.ml @@ -92,12 +92,10 @@ module RTL = struct let is_generated_kf kf = is_generated_name (Kernel_function.get_name kf) - let is_rtl_name name = startswith e_acsl_api_prefix name - let is_generated_literal_string_name name = startswith e_acsl_lit_string_prefix name - let get_rtl_replacement_name fn = e_acsl_builtin_prefix ^ fn + let libc_replacement_name fn = e_acsl_builtin_prefix ^ fn let has_rtl_replacement = function | "strcpy" | "strncpy" | "strlen" | "strcat" | "strncat" | "strcmp" diff --git a/src/plugins/e-acsl/src/libraries/functions.mli b/src/plugins/e-acsl/src/libraries/functions.mli index a99291b585ff361c53aafa6450d5f06da1ea33bc..4963870c28539b1b89d055be1bb0285158b71366 100644 --- a/src/plugins/e-acsl/src/libraries/functions.mli +++ b/src/plugins/e-acsl/src/libraries/functions.mli @@ -59,10 +59,6 @@ module RTL: sig val is_generated_kf: kernel_function -> bool (** Same as [is_generated_name] but for kernel functions *) - val is_rtl_name: string -> bool - (** @return [true] if the prefix of the given name indicates that it - belongs to the public API of the E-ACSL Runtime Library *) - val is_generated_literal_string_name: string -> bool (** Same as [is_generated_name] but indicates that the name represents a local variable that replaced a literal string. *) @@ -71,7 +67,7 @@ module RTL: sig (** Retrieve the name of the kernel function and strip prefix that indicates that it has been generated by the instrumentation. *) - val get_rtl_replacement_name: string -> string + val libc_replacement_name: string -> string (** Given the name of C library function return the name of the RTL function that potentially replaces it. *) @@ -178,3 +174,9 @@ module Libc: sig In GCC/Clang [alloca] is typically implemented via [__builtin_alloca] *) end (* Libc *) + +(* +Local Variables: +compile-command: "make -C ../../../../.." +End: +*) diff --git a/src/plugins/e-acsl/src/libraries/gmp_types.ml b/src/plugins/e-acsl/src/libraries/gmp_types.ml index 6b89bba519386a97b974f290eca81a5e3ba0933b..2022682fa13c33f0c73268591b97b0181baaa564 100644 --- a/src/plugins/e-acsl/src/libraries/gmp_types.ml +++ b/src/plugins/e-acsl/src/libraries/gmp_types.ml @@ -123,6 +123,9 @@ let init () = end in try Cil.visitCilFileSameGlobals set_mp_t (Ast.get ()) with Exit -> () +let is_t ty = + Z.is_t ty || Q.is_t ty + (* Local Variables: compile-command: "make -C ../../../../.." diff --git a/src/plugins/e-acsl/src/libraries/gmp_types.mli b/src/plugins/e-acsl/src/libraries/gmp_types.mli index 3c9db48c536ba039e7e9bba155e2824170828161..fc818fbe4b66450710ded247878f46daa944102a 100644 --- a/src/plugins/e-acsl/src/libraries/gmp_types.mli +++ b/src/plugins/e-acsl/src/libraries/gmp_types.mli @@ -27,6 +27,9 @@ open Cil_types val init: unit -> unit (** Must be called before any use of GMP *) +val is_t: typ -> bool +(** @return true iff the given type is equivalent to one of the GMP type. *) + (**************************************************************************) (******************************** Types ***********************************) (**************************************************************************) diff --git a/src/plugins/e-acsl/src/libraries/misc.ml b/src/plugins/e-acsl/src/libraries/misc.ml index 0f4d38ef3fb6f37bd2ab33dd37c1f0d1ff021063..284d57621d5e2f242f8ada787f1acc8c0d8648af 100644 --- a/src/plugins/e-acsl/src/libraries/misc.ml +++ b/src/plugins/e-acsl/src/libraries/misc.ml @@ -20,7 +20,6 @@ (* *) (**************************************************************************) -module RTL = Functions.RTL open Cil_types open Cil_datatype @@ -28,20 +27,6 @@ open Cil_datatype (** {2 Handling the E-ACSL's C-libraries, part I} *) (* ************************************************************************** *) -let library_files () = - List.map - (fun d -> Options.Share.get_file ~mode:`Must_exist d) - [ "e_acsl_gmp_api.h"; - "e_acsl.h" ] - -let is_library_loc (loc, _) = List.mem loc.Filepath.pos_path (library_files ()) - -let library_functions = Datatype.String.Hashtbl.create 17 -let register_library_function vi = - Datatype.String.Hashtbl.add library_functions vi.vname vi - -let reset () = Datatype.String.Hashtbl.clear library_functions - let is_fc_or_compiler_builtin vi = Cil.is_builtin vi || @@ -51,20 +36,6 @@ let is_fc_or_compiler_builtin vi = let prefix = String.sub vi.vname 0 prefix_length in Datatype.String.equal prefix "__builtin_") -(* ************************************************************************** *) -(** {2 Builders} *) -(* ************************************************************************** *) - -exception Unregistered_library_function of string -let get_lib_fun_vi fname = - try Datatype.String.Hashtbl.find library_functions fname - with Not_found -> - try Builtins.find fname - with Not_found -> - (* should not happen in normal mode, but could be raised when E-ACSL is - used as a library *) - raise (Unregistered_library_function fname) - (* ************************************************************************** *) (** {2 Handling \result} *) (* ************************************************************************** *) @@ -89,17 +60,6 @@ let result_vi kf = match result_lhost kf with let term_addr_of ~loc tlv ty = Logic_const.taddrof ~loc tlv (Ctype (TPtr(ty, []))) -let reorder_ast () = - let ast = Ast.get() in - let is_from_library = function - | GType(ti, _) when ti.tname = "size_t" || ti.tname = "FILE" - || RTL.is_rtl_name ti.tname -> true - | GCompTag (ci, _) when RTL.is_rtl_name ci.cname -> true - | GFunDecl(_, _, loc) | GVarDecl(_, loc) when is_library_loc loc -> true - | _ -> false in - let rtl, other = List.partition is_from_library ast.globals in - ast.globals <- rtl @ other - let cty = function | Ctype ty -> ty | lty -> Options.fatal "Expecting a C type. Got %a" Printer.pp_logic_type lty @@ -186,8 +146,6 @@ let term_has_lv_from_vi t = with Lv_from_vi_found -> true -type pred_or_term = PoT_pred of predicate | PoT_term of term - let mk_ptr_sizeof typ loc = match Cil.unrollType typ with | TPtr (t', _) -> Cil.new_exp ~loc (SizeOf t') @@ -231,6 +189,15 @@ module Id_term = let mem_project = Datatype.never_any_project end) +let extract_uncoerced_lval e = + let rec aux e = + match e.enode with + | Lval _ -> Some e + | CastE (_, e) -> aux e + | _ -> None + in + aux e + (* Local Variables: compile-command: "make -C ../../../../.." diff --git a/src/plugins/e-acsl/src/libraries/misc.mli b/src/plugins/e-acsl/src/libraries/misc.mli index 1d2359202f752f482e32557377726c0719f23d3f..6ea105fd88a00e4e4c3621fc90511f9eb943bdc0 100644 --- a/src/plugins/e-acsl/src/libraries/misc.mli +++ b/src/plugins/e-acsl/src/libraries/misc.mli @@ -24,14 +24,6 @@ open Cil_types -(* ************************************************************************** *) -(** {2 Builders} *) -(* ************************************************************************** *) - -exception Unregistered_library_function of string -val get_lib_fun_vi: string -> varinfo -(** @return varinfo corresponding to a name of a given library function *) - (* ************************************************************************** *) (** {2 Handling \result} *) (* ************************************************************************** *) @@ -43,27 +35,13 @@ val result_vi: kernel_function -> varinfo (** @return the varinfo corresponding to \result in the given function *) (* ************************************************************************** *) -(** {2 Handling the E-ACSL's C-libraries} *) +(** {2 Other stuff} *) (* ************************************************************************** *) -val library_files: unit -> Datatype.Filepath.t list -val is_library_loc: location -> bool -val register_library_function: varinfo -> unit -val reset: unit -> unit - val is_fc_or_compiler_builtin: varinfo -> bool -(* ************************************************************************** *) -(** {2 Other stuff} *) -(* ************************************************************************** *) - val term_addr_of: loc:location -> term_lval -> typ -> term -val reorder_ast: unit -> unit -(* Reorder current AST by bringing all global declarations belonging to the - * E-ACSL runtime library and their dependencies (e.g., typedef size_t) to - * the very top of the file. *) - val cty: logic_type -> typ (** Assume that the logic type is indeed a C type. Just return it. *) @@ -90,8 +68,6 @@ val term_has_lv_from_vi: term -> bool (** @return true iff the given term contains a variables that originates from a C varinfo, that is a non-purely logic variable. *) -type pred_or_term = PoT_pred of predicate | PoT_term of term - val mk_ptr_sizeof: typ -> location -> exp (** [mk_ptr_sizeof ptr_typ loc] takes the pointer typ [ptr_typ] that points to a [typ] typ and returns [sizeof(typ)]. *) @@ -105,6 +81,13 @@ val finite_min_and_max: Ival.t -> Integer.t * Integer.t module Id_term: Datatype.S_with_collections with type t = term (** Datatype for terms that relies on physical equality. *) +val extract_uncoerced_lval: exp -> exp option +(** Unroll the [CastE] part of the expression until an [Lval] is found, and + return it. + + If at some point the expression is neither a [CastE] nor an [Lval], then + return [None]. *) + (* Local Variables: compile-command: "make -C ../../../../.." diff --git a/src/plugins/e-acsl/src/main.ml b/src/plugins/e-acsl/src/main.ml index 0c6c931c4754a04db314b86e69710985c304155f..703ef6b8c0d8d8d7e6683ebf4a88a48c84c572ce 100644 --- a/src/plugins/e-acsl/src/main.ml +++ b/src/plugins/e-acsl/src/main.ml @@ -20,101 +20,6 @@ (* *) (**************************************************************************) -let check () = assert false (* [TODO ARCHI] kill check *) - -let check = - Dynamic.register - ~plugin:"e-acsl" - ~journalize:true - "check" - (Datatype.func Datatype.unit Datatype.bool) - check - -type extended_project = - | To_be_extended - | Already_extended of Project.t option (* None = keep the current project *) - -let extended_ast_project: extended_project ref = ref To_be_extended - -let unmemoized_extend_ast () = - let extend () = - let share = Options.Share.get_dir ~mode:`Must_exist "." in - Options.feedback ~level:3 "setting kernel options for E-ACSL."; - Kernel.CppExtraArgs.add - (Format.asprintf " -DE_ACSL_MACHDEP=%s -I%a/memory_model" - (Kernel.Machdep.get ()) - Datatype.Filepath.pp_abs share); - Kernel.Keep_unused_specified_functions.off (); - if Plugin.is_present "variadic" then - Dynamic.Parameter.Bool.off "-variadic-translation" (); - let ppc, ppk = File.get_preprocessor_command () in - let register s = - File.pre_register - (File.NeedCPP - (s, - ppc - ^ Format.asprintf " -I%a" Datatype.Filepath.pp_abs share, - ppk)) - in - List.iter register (Misc.library_files ()) - in - if Ast.is_computed () then begin - (* do not modify the existing project: work on a copy. - Must also extend the current AST with the E-ACSL's library files. *) - Options.feedback ~level:2 - "AST already computed: E-ACSL is going to work on a copy."; - let name = Project.get_name (Project.current ()) in - let tmpfile = - Extlib.temp_file_cleanup_at_exit ("e_acsl_" ^ name) ".i" in - let cout = open_out tmpfile in - let fmt = Format.formatter_of_out_channel cout in - File.pretty_ast ~fmt (); - let selection = - State_selection.diff - State_selection.full - (State_selection.with_dependencies Ast.self) - in - let prj = - Project.create_by_copy - ~last:false - ~selection - (Format.asprintf "%s for E-ACSL" name) - in - Project.on prj - (fun () -> - Kernel.Files.set [ Datatype.Filepath.of_string tmpfile ]; - extend ()) - (); - Some prj - end else begin - extend (); - None - end - -let extend_ast () = match !extended_ast_project with - | To_be_extended -> - let prj = unmemoized_extend_ast () in - extended_ast_project := Already_extended prj; - (match prj with - | None -> Project.current () - | Some prj -> prj) - | Already_extended None -> - Project.current () - | Already_extended(Some prj) -> - prj - -let apply_on_e_acsl_ast f x = - let tmp_prj = extend_ast () in - let res = Project.on tmp_prj f x in - (match !extended_ast_project with - | To_be_extended -> assert false - | Already_extended None -> () - | Already_extended (Some prj) -> - assert (Project.equal prj tmp_prj); - extended_ast_project := To_be_extended; - if Options.Debug.get () = 0 then Project.remove ~project:tmp_prj ()); - res - module Resulting_projects = State_builder.Hashtbl (Datatype.String.Hashtbl) @@ -133,32 +38,65 @@ let () = let generate_code = Resulting_projects.memo (fun name -> - apply_on_e_acsl_ast + Options.feedback "beginning translation."; + Temporal.enable (Options.Temporal_validity.get ()); + if Plugin.is_present "variadic" then begin + let opt_name = "-variadic-translation" in + if Dynamic.Parameter.Bool.get opt_name () then begin + if Ast.is_computed () then + Options.abort + "The variadic translation must be turned off for E-ACSL. \ + Please use option '-variadic-no-translation'"; + Options.warning "deactivating variadic translation"; + Dynamic.Parameter.Bool.off opt_name (); + end + end; + (* slightly more efficient to copy the project before computing the AST + if it is not yet computed *) + let rtl_prj_name = Options.Project_name.get () ^ " RTL" in + let rtl_prj = Project.create_by_copy ~last:false rtl_prj_name in + (* force AST computation before copying the project it belongs to *) + Ast.compute (); + let copied_prj = Project.create_by_copy ~last:true name in + Project.on + copied_prj (fun () -> - Options.feedback "beginning translation."; - Temporal.enable (Options.Temporal_validity.get ()); - let copied_prj = - Project.create_by_copy name ~last:true + (* preparation of the AST does not concern the E-ACSL RTL: + do it first *) + Prepare_ast.prepare (); + Rtl.link rtl_prj; + (* the E-ACSL type system ensures the soundness of the generated + arithmetic operations. Therefore, deactivate the corresponding + options in order to prevent RTE to generate spurious alarms. *) + let signed = Kernel.SignedOverflow.get () in + let unsigned = Kernel.UnsignedOverflow.get () in + (* we do know that setting these flags does not modify the program's + semantics: using their unsafe variants is thus safe and preserve + all emitted property statuses. *) + Kernel.SignedOverflow.unsafe_set false; + Kernel.UnsignedOverflow.unsafe_set false; + let finally () = + Kernel.SignedOverflow.unsafe_set signed; + Kernel.UnsignedOverflow.unsafe_set unsigned + in + Extlib.try_finally ~finally Injector.inject (); + (* remove the RTE's results computed from E-ACSL: they are partial + and associated with the wrong kernel function (the one of the old + project). *) + (* [TODO] what if RTE was already computed? To be fixed when + redoing the RTE management system *) + let selection = + State_selection.union + (State_selection.with_dependencies !Db.RteGen.self) + (State_selection.with_dependencies Options.Run.self) in - Project.on - copied_prj - (fun () -> - Prepare_ast.prepare (); - Injector.inject (); - (* remove the RTE's results computed from E-ACSL: they are - partial and associated with the wrong kernel function (the - one of the old project). *) - (* [TODO ARCHI] what if RTE was already computed? *) - let selection = - State_selection.with_dependencies !Db.RteGen.self - in - Project.clear ~selection ~project:copied_prj (); - Resulting_projects.mark_as_computed ()) - (); - Options.feedback "translation done in project \"%s\"." - (Options.Project_name.get ()); - copied_prj) - ()) + Project.clear ~selection ~project:copied_prj (); + Resulting_projects.mark_as_computed ()) + (); + if not (Options.debug_atleast 1) then Project.remove ~project:rtl_prj (); + Options.feedback "translation done in project \"%s\"." + (Options.Project_name.get ()); + copied_prj) let generate_code = Dynamic.register @@ -177,15 +115,6 @@ let predicate_to_exp = Kernel_function.ty Cil_datatype.Predicate.ty Cil_datatype.Exp.ty) Translate.predicate_to_exp -let add_e_acsl_library _files = - if Options.must_visit () || Options.Prepare.get () then ignore (extend_ast ()) - -(* extending the AST as soon as possible reduce the amount of time the AST is - duplicated: - - that is faster - - locations are better (indicate an existing file, and not a temp file) *) -let () = Cmdline.run_after_configuring_stage add_e_acsl_library - (* The Frama-C standard library contains specific built-in variables prefixed by "__fc_" and declared as extern: they prevent the generated code to be linked. This modification of the default printer replaces them by their @@ -248,17 +177,10 @@ let change_printer = end let main () = - Keep_status.clear (); if Options.Run.get () then begin change_printer (); - ignore (generate_code (Options.Project_name.get ())) - end else - if Options.Check.get () then - apply_on_e_acsl_ast - (fun () -> - Gmp_types.init (); - ignore (check ())) - () + ignore (generate_code (Options.Project_name.get ())); + end let () = Db.Main.extend main diff --git a/src/plugins/e-acsl/src/options.ml b/src/plugins/e-acsl/src/options.ml index da21806929227ab689d12a3f31fcd40632a80445..8c98ca1657933ca519eef73fa5697877efa50842 100644 --- a/src/plugins/e-acsl/src/options.ml +++ b/src/plugins/e-acsl/src/options.ml @@ -31,13 +31,6 @@ module P = Plugin.Register module PP = P (* [PP] required to avoid an ocamldoc error in OCaml 4.02 *) include PP -module Check = - False - (struct - let option_name = "-e-acsl-check" - let help = "only type check E-ACSL annotated program" - end) - module Run = False (struct @@ -63,13 +56,6 @@ module Valid = let help = "translate annotation which have been proven valid" end) -module Prepare = - False - (struct - let option_name = "-e-acsl-prepare" - let help = "prepare the AST to be directly usable by E-ACSL" - end) - module Gmp_only = False (struct @@ -163,7 +149,9 @@ let parameter_states = Functions.self; Instrument.self ] -let must_visit () = Run.get () || Check.get () +let emitter = Emitter.create "E-ACSL" [ Funspec ] ~correctness:[] ~tuning:[] + +let must_visit () = Run.get () let dkey_analysis = register_category "analysis" let dkey_prepare = register_category "preparation" @@ -172,6 +160,6 @@ let dkey_typing = register_category "typing" (* Local Variables: -compile-command: "make" +compile-command: "make -C ../../../.." End: *) diff --git a/src/plugins/e-acsl/src/options.mli b/src/plugins/e-acsl/src/options.mli index 8e8114594f8b8da0f1dac3d204fef317ac144a57..d5065c6a51dbbade2b491b5cf91fea75d17e7f23 100644 --- a/src/plugins/e-acsl/src/options.mli +++ b/src/plugins/e-acsl/src/options.mli @@ -22,10 +22,8 @@ include Plugin.S (** implementation of Log.S for E-ACSL *) -module Check: Parameter_sig.Bool module Run: Parameter_sig.Bool module Valid: Parameter_sig.Bool -module Prepare: Parameter_sig.Bool module Gmp_only: Parameter_sig.Bool module Full_mmodel: Parameter_sig.Bool module Project_name: Parameter_sig.String @@ -38,6 +36,7 @@ module Functions: Parameter_sig.Kernel_function_set module Instrument: Parameter_sig.Kernel_function_set val parameter_states: State.t list +val emitter: Emitter.t val must_visit: unit -> bool @@ -48,6 +47,6 @@ val dkey_typing: category (* Local Variables: -compile-command: "make" +compile-command: "make -C ../../../.." End: *) diff --git a/src/plugins/e-acsl/src/project_initializer/keep_status.ml b/src/plugins/e-acsl/src/project_initializer/keep_status.ml deleted file mode 100644 index f4b83a501b0900b1e0599e48031a3a0f033a82b9..0000000000000000000000000000000000000000 --- a/src/plugins/e-acsl/src/project_initializer/keep_status.ml +++ /dev/null @@ -1,162 +0,0 @@ -(**************************************************************************) -(* *) -(* This file is part of the Frama-C's E-ACSL plug-in. *) -(* *) -(* Copyright (C) 2012-2020 *) -(* CEA (Commissariat à l'énergie atomique et aux énergies *) -(* alternatives) *) -(* *) -(* you can redistribute it and/or modify it under the terms of the GNU *) -(* Lesser General Public License as published by the Free Software *) -(* Foundation, version 2.1. *) -(* *) -(* It is distributed in the hope that it will be useful, *) -(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) -(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) -(* GNU Lesser General Public License for more details. *) -(* *) -(* See the GNU Lesser General Public License version 2.1 *) -(* for more details (enclosed in the file licenses/LGPLv2.1). *) -(* *) -(**************************************************************************) - -(* E-ACSL needs to access to the property status of every property (in - particular for the option -e-acsl-valid). However, the necessary elements for - building a property are copied/modified several times from the original - project to the final project and the property statuses are destroyed when - creating the intermediate projects; so there is no easy way to access to - property statuses from the final project. - - This module aims at solving this issue by providing an access to property - statuses from the final project. To work properly, it requires to visit every - property during the final visit in the very same order than during the AST - preparation visit. Indeed, for each function, it associates to each - property an unique integer corresponding to its visit ordering. *) - -(* the kind is only used for a few additional consistency checks between [push] - and [must_translate]*) -type kind = - | K_Assert - | K_Invariant - | K_Variant - | K_StmtSpec - | K_Allocation - | K_Assigns - | K_Decreases - | K_Terminates - | K_Complete - | K_Disjoint - | K_Requires - | K_Ensures - -let pretty_kind fmt k = - Format.fprintf fmt "%s" - (match k with - | K_Assert -> "assert" - | K_Invariant -> "invariant" - | K_Variant -> "variant" - | K_StmtSpec -> "stmtspec" - | K_Allocation -> "allocation" - | K_Assigns -> "assigns" - | K_Decreases -> "decreases" - | K_Terminates -> "terminates" - | K_Complete -> "complete" - | K_Disjoint -> "disjoint" - | K_Requires -> "requires" - | K_Ensures -> "ensures") - -(* information attached to every kernel_function containing an annotation *) -type kf_info = - { mutable cpt: int - (* counter building the relationship between [push] and [must_translate] *); - mutable statuses: (kind * bool) Datatype.Int.Map.t - (* map associating a property as an integer to its kind and status - ([true] = proved) *) } - -(* statuses for each function represented by its name (because the [kf] itself - changes from a project to another). *) -let keep_status - : kf_info Datatype.String.Hashtbl.t - = Datatype.String.Hashtbl.create 17 - -(* will contain the value of a few options from the original project - in order to safely use them from the final project. *) -let option_valid = ref false -let option_check = ref false - -let clear () = - Datatype.String.Hashtbl.clear keep_status; - option_valid := Options.Valid.get (); - option_check := Options.Check.get () - -let push kf kind ppt = - (* Options.feedback "PUSHING %a for %a" - pretty_kind kind - Kernel_function.pretty kf;*) - (* no registration when -e-acsl-check or -e-acsl-valid *) - if not (!option_check || !option_valid) then - let keep = - let open Property_status in - match get ppt with - | Never_tried - | Inconsistent _ - | Best ((False_if_reachable | False_and_reachable | Dont_know), _) -> - true - | Best (True, _) -> - false - in - let status = kind, keep in - let name = Kernel_function.get_name kf in - try - let info = Datatype.String.Hashtbl.find keep_status name in - info.cpt <- info.cpt + 1; - info.statuses <- Datatype.Int.Map.add info.cpt status info.statuses - with Not_found -> - let info = { cpt = 1; statuses = Datatype.Int.Map.singleton 1 status } in - Datatype.String.Hashtbl.add keep_status name info - -let before_translation () = - (* reset all counters *) - Datatype.String.Hashtbl.iter (fun _ info -> info.cpt <- 0) keep_status - -let must_translate kf kind = - (* Options.feedback "GETTING %a for %a" - pretty_kind kind - Kernel_function.pretty kf;*) - !option_check - || - !option_valid - || - (* function contracts have been moved from the original function to its - duplicate by [Dup_function] but they are still associated to the original - function here *) - let name = Functions.RTL.get_original_name kf in - try - let info = - try Datatype.String.Hashtbl.find keep_status name - with Not_found -> - Options.fatal "[keep_status] unbound function" Datatype.String.pretty kf - in - info.cpt <- info.cpt + 1; - let kind', keep = - try Datatype.Int.Map.find info.cpt info.statuses - with Not_found -> - Options.fatal "[keep_status] unbound annotation (id %d)@ in function %a" - info.cpt - Kernel_function.pretty kf - in - (* check kind consistency in order to detect more abnormal behaviors *) - if kind <> kind' then - Options.fatal - "[keep_status] incorrect kind '%a' (expected: '%a')@ in function %a" - pretty_kind kind - pretty_kind kind' - Kernel_function.pretty kf; - keep - with Not_found -> true - -(* -Local Variables: -compile-command: "make -C ../../../../.." -End: -*) diff --git a/src/plugins/e-acsl/src/project_initializer/prepare_ast.ml b/src/plugins/e-acsl/src/project_initializer/prepare_ast.ml index 57458a5688878cb8930006420b56b818aa7905d5..2f167b55c03dbf9eb5fc203cdc93d569dfcd8323 100644 --- a/src/plugins/e-acsl/src/project_initializer/prepare_ast.ml +++ b/src/plugins/e-acsl/src/project_initializer/prepare_ast.ml @@ -21,6 +21,7 @@ (**************************************************************************) open Cil_types +open Cil_datatype let dkey = Options.dkey_prepare @@ -28,81 +29,69 @@ let dkey = Options.dkey_prepare (* Environment *) (* ********************************************************************** *) -let fct_tbl: unit Kernel_function.Hashtbl.t = Kernel_function.Hashtbl.create 7 - -(* The purpose of [actions] is similar to the Frama-C visitor's - [get_filling_actions] but we need to fill it outside the visitor. So it is - our own version. *) -let actions = Queue.create () - -(* global table for ensuring that logic info are not shared between a function - definition and its duplicate *) -module Global: sig - val add_logic_info: logic_info -> unit - val mem_logic_info: logic_info -> bool +module Dup_functions: sig + val generate_vi: varinfo -> varinfo (* return the new varinfo *) + val mem: varinfo -> bool + val find: varinfo -> varinfo val reset: unit -> unit end = struct - let tbl = Cil_datatype.Logic_info.Hashtbl.create 7 - let add_logic_info x = Cil_datatype.Logic_info.Hashtbl.add tbl x () - let mem_logic_info x = Cil_datatype.Logic_info.Hashtbl.mem tbl x - let reset () = Cil_datatype.Logic_info.Hashtbl.clear tbl + let tbl: varinfo Varinfo.Hashtbl.t = Varinfo.Hashtbl.create 7 + + (* assume [vi] is not already in [tbl] *) + let generate_vi vi = + let new_name = Functions.RTL.mk_gen_name vi.vname in + let new_vi = + Cil.makeGlobalVar + ~referenced:vi.vreferenced + ~loc:vi.vdecl + new_name + vi.vtype + in + Varinfo.Hashtbl.add tbl vi new_vi; + new_vi -end + let mem = Varinfo.Hashtbl.mem tbl + let find = Varinfo.Hashtbl.find tbl + let reset () = Varinfo.Hashtbl.clear tbl -let reset () = - Kernel_function.Hashtbl.clear fct_tbl; - Global.reset (); - Queue.clear actions +end (* ********************************************************************** *) (* Duplicating a function *) (* ********************************************************************** *) -(* [tbl] associates the old formals to the new ones *) -let dup_funspec tbl bhv spec = +(* [formals] associates the old formals to the new ones in order to + substitute them in [spec]. *) +let dup_funspec formals spec = (* Options.feedback "DUP SPEC %a" Cil.d_funspec spec;*) let o = object - inherit Cil.genericCilVisitor bhv - - val already_visited = Cil_datatype.Logic_var.Hashtbl.create 7 - - method !vlogic_info_use li = - if Global.mem_logic_info li then - Cil.ChangeDoChildrenPost - ({ li with l_var_info = li.l_var_info } (* force a copy *), - Visitor_behavior.Get.logic_info bhv) - else - Cil.JustCopy + inherit Visitor.frama_c_refresh (Project.current ()) - method !vterm_offset _ = - Cil.DoChildrenPost - (function (* no way to directly visit fieldinfo and model_info uses *) - | TField(fi, off) -> - TField(Visitor_behavior.Get.fieldinfo bhv fi, off) - | TModel(mi, off) -> - TModel(Visitor_behavior.Get.model_info bhv mi, off) - | off -> - off) + val already_visited = Logic_var.Hashtbl.create 7 + (* just substituting in [!vvrbl] (when using a varinfo) does not work + because varinfo's occurrences are shared in logic_vars, so modifying the + varinfo would modify any logic_var based on it, even if it is not part of + this [spec] (e.g., if it is in another annotation of the same + function) *) method !vlogic_var_use orig_lvi = match orig_lvi.lv_origin with | None -> Cil.JustCopy | Some vi -> try - let new_lvi = - Cil_datatype.Logic_var.Hashtbl.find already_visited orig_lvi - in + let new_lvi = Logic_var.Hashtbl.find already_visited orig_lvi in + (* recreate sharing of the logic_var in this [spec] *) Cil.ChangeTo new_lvi with Not_found -> + (* first time visiting this logic var *) Cil.ChangeDoChildrenPost ({ orig_lvi with lv_id = orig_lvi.lv_id } (* force a copy *), fun lvi -> try - let new_vi = Cil_datatype.Varinfo.Hashtbl.find tbl vi in - Cil_datatype.Logic_var.Hashtbl.add - already_visited orig_lvi lvi; + let new_vi = Varinfo.Hashtbl.find formals vi in + Logic_var.Hashtbl.add already_visited orig_lvi lvi; (* [lvi] is the logic counterpart of a formal varinfo that has been replaced by a new one: propagate this change *) lvi.lv_id <- new_vi.vid; @@ -112,20 +101,12 @@ let dup_funspec tbl bhv spec = lvi with Not_found -> assert vi.vglob; - (* using [Visitor_behavior.Get.logic_var bhv lvi] is correct - only because the lv_id used to compare the lvi does not - change between the original one and this copy *) - Visitor_behavior.Get.logic_var bhv lvi) + lvi) - method !videntified_term _ = - Cil.DoChildrenPost Logic_const.refresh_identified_term - - method !videntified_predicate _ = - Cil.DoChildrenPost Logic_const.refresh_predicate end in - Cil.visitCilFunspec o spec + Cil.visitCilFunspec (o :> Cil.cilVisitor) spec -let dup_fundec loc spec bhv sound_verdict_vi kf vi new_vi = +let dup_fundec loc spec sound_verdict_vi kf vi new_vi = new_vi.vdefined <- true; let formals = Kernel_function.get_formals kf in let mk_formal vi = @@ -174,9 +155,9 @@ let dup_fundec loc spec bhv sound_verdict_vi kf vi new_vi = let locals = match res with None -> [] | Some r -> [ r ] in let body = Cil.mkBlock stmts in body.blocals <- locals; - let tbl = Cil_datatype.Varinfo.Hashtbl.create 7 in - List.iter2 (Cil_datatype.Varinfo.Hashtbl.add tbl) formals new_formals; - let new_spec = dup_funspec tbl bhv spec in + let tbl = Varinfo.Hashtbl.create 7 in + List.iter2 (Varinfo.Hashtbl.add tbl) formals new_formals; + let new_spec = dup_funspec tbl spec in let fundec = { svar = new_vi; sformals = new_formals; @@ -192,54 +173,69 @@ let dup_fundec loc spec bhv sound_verdict_vi kf vi new_vi = Cfg.cfgFun fundec; fundec -let dup_global loc actions spec bhv sound_verdict_vi kf vi new_vi = +let dup_global loc spec sound_verdict_vi kf vi new_vi = let name = vi.vname in Options.feedback ~dkey ~level:2 "entering in function %s" name; - let fundec = dup_fundec loc spec bhv sound_verdict_vi kf vi new_vi in - let fct = Definition(fundec, loc) in - let new_spec = fundec.sspec in - let new_kf = { fundec = fct; spec = new_spec } in - Queue.add - (fun () -> - Kernel_function.Hashtbl.add fct_tbl new_kf (); - Globals.Functions.register new_kf; - Globals.Functions.replace_by_definition new_spec fundec loc; - Annotations.register_funspec new_kf; - if new_vi.vname = "main" then begin - (* recompute the info about the old main since its name has changed; - see the corresponding part in the main visitor *) - Globals.Functions.remove vi; - Globals.Functions.register kf - end) - actions; - (* remove the specs attached to the previous kf iff it is a definition: - it is necessary to keep stable the number of annotations in order to get - [Keep_status] working fine. *) - let kf = Visitor_behavior.Get.kernel_function bhv kf in + let new_fundec = dup_fundec loc spec sound_verdict_vi kf vi new_vi in + let new_fct = Definition(new_fundec, loc) in + let new_spec = new_fundec.sspec in + let new_kf = { fundec = new_fct; spec = new_spec } in + Globals.Functions.register new_kf; + Globals.Functions.replace_by_definition new_spec new_fundec loc; + Annotations.register_funspec new_kf; + if Datatype.String.equal new_vi.vname "main" then begin + (* recompute kernel's info about the old main since its name has changed; + see the corresponding part in the main visitor *) + Globals.Functions.remove vi; + Globals.Functions.register kf + end; + (* copy property statuses to the new spec *) + let copy old_ip new_ip = + let open Property_status in + let cp status ep = + let e = Emitter.Usable_emitter.get ep.emitter in + if ep.logical_consequence + then logical_consequence e new_ip ep.properties + else emit e new_ip ~hyps:ep.properties status + in + match get old_ip with + | Never_tried -> + () + | Best(s, epl) -> + List.iter (cp s) epl + | Inconsistent icst -> + List.iter (cp True) icst.valid; + (* either the program is reachable and [False_and_reachable] is + fine, or the program point is not reachable and it does not + matter for E-ACSL that checks it at runtime. *) + List.iter (cp False_and_reachable) icst.invalid + in + let ips kf s = Property.ip_of_spec kf Kglobal ~active:[] s in + List.iter2 copy (ips kf spec) (ips new_kf new_spec); + (* remove annotations from the old spec. Yet keep them in functions only + declared since, otherwise, the kernel would complain about functions + with neither contract nor body *) if Kernel_function.is_definition kf then begin - Queue.add - (fun () -> - let bhvs = - Annotations.fold_behaviors (fun e b acc -> (e, b) :: acc) kf [] - in - List.iter - (fun (e, b) -> Annotations.remove_behavior ~force:true e kf b) - bhvs; - Annotations.iter_decreases - (fun e _ -> Annotations.remove_decreases e kf) - kf; - Annotations.iter_terminates - (fun e _ -> Annotations.remove_terminates e kf) - kf; - Annotations.iter_complete - (fun e l -> Annotations.remove_complete e kf l) - kf; - Annotations.iter_disjoint - (fun e l -> Annotations.remove_disjoint e kf l) - kf) - actions + let old_bhvs = + Annotations.fold_behaviors (fun e b acc -> (e, b) :: acc) kf [] + in + List.iter + (fun (e, b) -> Annotations.remove_behavior ~force:true e kf b) + old_bhvs; + Annotations.iter_decreases + (fun e _ -> Annotations.remove_decreases e kf) + kf; + Annotations.iter_terminates + (fun e _ -> Annotations.remove_terminates e kf) + kf; + Annotations.iter_complete + (fun e l -> Annotations.remove_complete e kf l) + kf; + Annotations.iter_disjoint + (fun e l -> Annotations.remove_disjoint e kf l) + kf end; - GFun(fundec, loc), GFunDecl(new_spec, new_vi, loc) + GFun(new_fundec, loc), GFunDecl(new_spec, new_vi, loc) (* ********************************************************************** *) (* Alignment *) @@ -293,356 +289,187 @@ let require_alignment vi algn = Cil.bitsSizeOf vi.vtype < algn*8 && not (sufficiently_aligned vi algn) (* ********************************************************************** *) -(* Visitor *) +(* Visiting the globals *) (* ********************************************************************** *) -class prepare_visitor = object (self) - inherit Visitor.frama_c_inplace - - val mutable has_new_stmt_in_fundec = false - - (* ---------------------------------------------------------------------- *) - (* visitor's local variable *) - (* ---------------------------------------------------------------------- *) - - val terms = Misc.Id_term.Hashtbl.create 7 - (* table for ensuring absence of term sharing *) - - val unduplicable_functions = - let white_list = - [ "__builtin_va_arg"; - "__builtin_va_end"; - "__builtin_va_start"; - "__builtin_va_copy" ] - in - List.fold_left - (fun acc s -> Datatype.String.Set.add s acc) - Datatype.String.Set.empty - white_list - - val fct_tbl = Cil_datatype.Varinfo.Hashtbl.create 7 - val mutable new_definitions: global list = [] - (* new definitions of the annotated functions which will contain the - translation of the E-ACSL contract *) - - (* the variable [sound_verdict] belongs to the E-ACSL's RTL and indicates - whether the verdict emitted by E-ACSL is sound. It needs to be visible at - that point because it is set in all function duplicates - (see [dup_fundec]). *) - val mutable sound_verdict_vi = - let name = Functions.RTL.mk_api_name "sound_verdict" in - let vi = Cil.makeGlobalVar name Cil.intType in - vi.vstorage <- Extern; - vi.vreferenced <- true; - vi - - (* ---------------------------------------------------------------------- *) - (* visitor's private methods *) - (* ---------------------------------------------------------------------- *) - - method private is_variadic_function vi = - match Cil.unrollType vi.vtype with - | TFun(_, _, variadic, _) -> variadic - | _ -> true - - (* IMPORTANT: for keeping property statuses, we must preserve the ordering of - translation, see function [Translate.translate_pre_spec] and - [Translate.translate_post_spec]: be careful when modifying it. *) - - method private push_pre_spec s = - let kf = Extlib.the self#current_kf in - let kinstr = self#current_kinstr in - let open Keep_status in - Extlib.may - (fun v -> push kf K_Decreases (Property.ip_of_decreases kf kinstr v)) - s.spec_variant; - Extlib.may - (fun t -> push kf K_Terminates (Property.ip_of_terminates kf kinstr t)) - s.spec_terminates; - List.iter - (fun l -> - push kf K_Complete (Property.ip_of_complete kf kinstr ~active:[] l)) - s.spec_complete_behaviors; - List.iter - (fun l -> - push kf K_Disjoint (Property.ip_of_disjoint kf kinstr ~active:[] l)) - s.spec_disjoint_behaviors; - List.iter - (fun b -> - List.iter - (fun p -> push kf K_Requires (Property.ip_of_requires kf kinstr b p)) - b.b_requires) - s.spec_behavior - - method private push_post_spec spec = - let do_behavior b = - let kf = Extlib.the self#current_kf in - let ki = match self#current_stmt with - | None -> Kglobal - | Some stmt -> Kstmt stmt - in - let open Keep_status in - Extlib.may - (push kf K_Assigns) - (Property.ip_of_assigns - kf - ki - (Property.Id_contract (Datatype.String.Set.empty (* TODO *), b)) - b.b_assigns); - List.iter - (fun p -> push kf K_Ensures (Property.ip_of_ensures kf ki b p)) - b.b_post_cond - in - (* fix ordering of behaviors' iterations *) - let bhvs = - List.sort - (fun b1 b2 -> String.compare b1.b_name b2.b_name) - spec.spec_behavior - in - List.iter do_behavior bhvs - - method private push_pre_code_annot a = - let kf = Extlib.the self#current_kf in - let stmt = Extlib.the self#current_stmt in - let push_single k a = - Keep_status.push kf k (Property.ip_of_code_annot_single kf stmt a) - in - let open Keep_status in - match a.annot_content with - | AAssert _ -> push_single K_Assert a - | AStmtSpec(_ (* TODO *), s) -> self#push_pre_spec s - | AInvariant _ -> push_single K_Invariant a - | AVariant v -> - push kf K_Variant (Property.ip_of_decreases kf (Kstmt stmt) v) - | AAssigns _ -> - (* TODO: should be a postcondition, but considered as an unhandled - precondition in translate.ml right now; and we need to preserve the - same ordering *) - Extlib.may - (push kf K_Assigns) - (Property.ip_assigns_of_code_annot kf (Kstmt stmt) a) - | AAllocation(_ (* TODO *), alloc) -> - Extlib.may - (push kf K_Allocation) - (Property.ip_of_allocation kf (Kstmt stmt) (Property.Id_loop a) alloc) - | APragma _ -> - (* not yet translated *) - () - | AExtended _ -> - (* never translate extensions *) - () - - method private push_post_code_annot a = match a.annot_content with - | AStmtSpec(_ (* TODO *), s) -> self#push_post_spec s - | AAssert _ - | AInvariant _ - | AVariant _ - | AAssigns _ - | AAllocation _ - | APragma _ - | AExtended _ -> () - - (* ---------------------------------------------------------------------- *) - (* visitor's method overloading *) - (* ---------------------------------------------------------------------- *) - - method !vlogic_info_decl li = - Global.add_logic_info li; - Cil.SkipChildren - - method !vvrbl vi = - try - let new_vi = Cil_datatype.Varinfo.Hashtbl.find fct_tbl vi in - (* replace functions at callsite by its duplicated version *) - Cil.ChangeTo new_vi - with Not_found -> - Cil.SkipChildren - - method !vterm _t = - Cil.DoChildrenPost - (fun t -> - if Misc.Id_term.Hashtbl.mem terms t then - (* remove term sharing for soundness of E-ACSL typing - (see typing.ml) *) - { t with term_node = t.term_node } - else begin - Misc.Id_term.Hashtbl.add terms t (); - t - end) - - (* Add align attributes to local variables (required by temporal analysis) *) - method !vblock _ = - if Options.Temporal_validity.get () then - Cil.DoChildrenPost - (fun blk -> - List.iter - (fun vi -> - (* 4 bytes alignment is required to allow sufficient space for - storage of 32-bit timestamps in a 1:1 shadow. *) - if require_alignment vi 4 then - vi.vattr <- - Attr("aligned", [ AInt Integer.four ]) :: vi.vattr) - blk.blocals; - blk) - else - Cil.DoChildren - - method !vstmt_aux stmt = - Annotations.iter_code_annot - (fun _ a -> self#push_pre_code_annot a) - stmt; - Cil.DoChildrenPost - (fun _ -> - Annotations.iter_code_annot - (fun _ a -> self#push_post_code_annot a) - stmt; - stmt) - - method !vfunc fundec = - Cil.DoChildrenPost - (fun _ -> - if has_new_stmt_in_fundec then begin - has_new_stmt_in_fundec <- false; - (* recompute the CFG *) - Cfg.clearCFGinfo ~clear_id:false fundec; - Cfg.cfgFun fundec; - end; - fundec) - - method !vglob_aux = function - | GFunDecl(_, vi, loc) | GFun({ svar = vi }, loc) - when (* duplicate a function iff: *) - (* it is not already duplicated *) - not (Cil_datatype.Varinfo.Hashtbl.mem fct_tbl vi) - && (* it is duplicable *) - not (Datatype.String.Set.mem vi.vname unduplicable_functions) - && (* it is not a variadic function *) - not (self#is_variadic_function vi) - && (* it is not in the E-ACSL's RTL *) - not (Misc.is_library_loc loc) - && (* it is not a built-in *) - not (Misc.is_fc_or_compiler_builtin vi) - && - (let kf = - try Globals.Functions.get vi with Not_found -> assert false - in - (* either explicitely listed as to be not instrumented *) - not (Functions.instrument kf) - || - (* or: *) - ((* it has a function contract *) - not (Cil.is_empty_funspec - (Annotations.funspec ~populate:false - (Extlib.the self#current_kf))) - && (* its annotations must be monitored *) - Functions.check kf)) - -> - let name = Functions.RTL.mk_gen_name vi.vname in - let new_vi = Cil.makeGlobalVar name vi.vtype in - Cil_datatype.Varinfo.Hashtbl.add fct_tbl vi new_vi; - Cil.DoChildrenPost - (fun l -> match l with - | [ GFunDecl(_, vi, _) | GFun({ svar = vi }, _) as g ] - -> - let kf = Extlib.the self#current_kf in - (match g with - | GFunDecl _ -> - if not (Kernel_function.is_definition kf) - && vi.vname <> "malloc" && vi.vname <> "free" - then - Options.warning - "@[annotating undefined function `%a':@ \ - the generated program may miss memory instrumentation@ \ - if there are memory-related annotations.@]" - Printer.pp_varinfo vi - | GFun _ -> () - | _ -> assert false); - let spec = Annotations.funspec ~populate:false kf in - self#push_pre_spec spec; - self#push_post_spec spec; - let tmp = vi.vname in - if tmp = "main" then begin - (* the new function becomes the new main: *) - (* 1. swap the name of both functions *) - vi.vname <- new_vi.vname; - new_vi.vname <- tmp; - (* 2. force recomputation of the entry point if necessary *) - if Kernel.MainFunction.get () = tmp then begin - let selection = - State_selection.with_dependencies Kernel.MainFunction.self - in - Project.clear ~selection () - end - (* 3. recompute what is necessary in [Globals.Functions]: - done in [dup_global] *) - end; - let new_g, new_decl = - dup_global - loc - self#get_filling_actions - spec - self#behavior - sound_verdict_vi - kf - vi - new_vi - in - (* postpone the introduction of the new function definition to the - end *) - new_definitions <- new_g :: new_definitions; - (* put the declaration before the original function in order to - solve issue with recursive functions *) - [ new_decl; g ] - | _ -> assert false) - - | GVarDecl(vi, loc) | GFunDecl(_, vi, loc) | GFun({ svar = vi }, loc) - when Misc.is_library_loc loc || Misc.is_fc_or_compiler_builtin vi -> - Cil.DoChildren +(* perform a few modifications in the [kf]'s code and annotations that are + required by E-ACSL's analyses and transformations *) +let prepare_fundec kf = + let o = object + inherit Visitor.frama_c_inplace + + (* table for ensuring absence of term sharing *) + val terms = Misc.Id_term.Hashtbl.create 7 + + (* substitute function's varinfos by their duplicate in function calls *) + method !vvrbl vi = + try Cil.ChangeTo (Dup_functions.find vi) + with Not_found -> Cil.SkipChildren + + (* temporal analysis requires that attributes are aligned to local + variables *) + method !vblock _ = + if Options.Temporal_validity.get () then + Cil.DoChildrenPost + (fun blk -> + List.iter + (fun vi -> + (* 4 bytes alignment is required to allow sufficient space for + storage of 32-bit timestamps in a 1:1 shadow. *) + if require_alignment vi 4 then + vi.vattr <- + Attr("aligned", [ AInt Integer.four ]) :: vi.vattr) + blk.blocals; + blk) + else + Cil.DoChildren - | GVarDecl(vi, loc) | GFunDecl(_, vi, loc) | GFun({ svar = vi }, loc) - when not (self#is_variadic_function vi) - -> - assert (* handled by the 2 cases above *) - (not (Misc.is_library_loc loc || Misc.is_fc_or_compiler_builtin vi)); - let kf = Extlib.the self#current_kf in - let s = Annotations.funspec ~populate:false kf in + (* remove term sharing introduced by the Frama-C kernel. For instance, an + annotation such as [a <= t <= b] is replaced by [a <= t && t <= b] with + both occurrences of [t] being shared. Yet, the E-ACSL type system may + require to assign them different types. *) + method !vterm _ = Cil.DoChildrenPost - (fun f -> - self#push_pre_spec s; - self#push_post_spec s; - f) + (fun t -> + if Misc.Id_term.Hashtbl.mem terms t then + { t with term_node = t.term_node } + else begin + Misc.Id_term.Hashtbl.add terms t (); + t + end) - | _ -> + method !videntified_predicate _ = + (* when entering a new annotation, clear the context to keep it small: + anyway, no sharing is possible between two identified predicates *) + Misc.Id_term.Hashtbl.clear terms; Cil.DoChildren - method !vfile f = - Cil.DoChildrenPost - (fun _ -> - match new_definitions with - | [] -> f - | _ :: _ -> - (* add the generated definitions of libc at the end of - [new_definitions]. This way, we are sure that they have access to - all of it (in particular, the memory model, GMP and the soundness - variable). Also add the [__e_acsl_sound_verdict] variable at the - beginning *) - let new_globals = - GVarDecl(sound_verdict_vi, Cil_datatype.Location.unknown) - :: f.globals - @ new_definitions - in - f.globals <- new_globals; - f) - - initializer - reset () - -end + end in + ignore (Visitor.visitFramacKf o kf) + +(* the variable [sound_verdict] belongs to the E-ACSL's RTL and indicates + whether the verdict emitted by E-ACSL is sound. It needs to be visible at + that point because it is set in all function duplicates (see + [dup_fundec]). *) +let sound_verdict_vi = + lazy + (let name = Functions.RTL.mk_api_name "sound_verdict" in + let vi = Cil.makeGlobalVar name Cil.intType in + vi.vstorage <- Extern; + vi.vreferenced <- true; + vi) + +let is_variadic_function vi = match Cil.unrollType vi.vtype with + | TFun(_, _, variadic, _) -> variadic + | _ -> false + +(* set of functions that must never be duplicated *) +let unduplicable_functions = + let white_list = + [ "__builtin_va_arg"; + "__builtin_va_end"; + "__builtin_va_start"; + "__builtin_va_copy"; + (* *alloc and free should not be duplicated. *) + (* [TODO:] it preserves the former behavior. Should be modified latter by + checking only preconditions for any libc functions, see e-acsl#35 *) + "malloc"; + "calloc"; + "realloc"; + "free" ] + in + List.fold_left + (fun acc s -> Datatype.String.Set.add s acc) + Datatype.String.Set.empty + white_list + +let must_duplicate kf vi = + (* it is not already duplicated *) + not (Dup_functions.mem vi) + && (* it is duplicable *) + not (Datatype.String.Set.mem vi.vname unduplicable_functions) + && (* it is not a variadic function *) + not (is_variadic_function vi) + && (* it is not a built-in *) + not (Misc.is_fc_or_compiler_builtin vi) + && + ((* either explicitely listed as to be not instrumented *) + not (Functions.instrument kf) + || + (* or: *) + ((* it has a function contract *) + not (Cil.is_empty_funspec (Annotations.funspec ~populate:false kf)) + && (* its annotations must be monitored *) + Functions.check kf)) + +let prepare_global (globals, new_defs) = function + | GFunDecl(_, vi, loc) | GFun({ svar = vi }, loc) as g -> + let kf = try Globals.Functions.get vi with Not_found -> assert false in + if must_duplicate kf vi then begin + let new_vi = Dup_functions.generate_vi vi in + if Kernel_function.is_definition kf then + prepare_fundec kf + else + (* TODO: this warning could be more precise if emitted during code + generation; see also E-ACSL issue #85 about partial verdicts *) + Options.warning + "@[annotating undefined function `%a':@ \ + the generated program may miss memory instrumentation@ \ + if there are memory-related annotations.@]" + Printer.pp_varinfo vi; + let tmp = vi.vname in + if Datatype.String.equal tmp "main" then begin + (* the new function becomes the new main: *) + (* 1. swap the name of both functions *) + vi.vname <- new_vi.vname; + new_vi.vname <- tmp; + (* 2. force recomputation of the entry point if necessary *) + if Kernel.MainFunction.get () = tmp then begin + let selection = + State_selection.with_dependencies Kernel.MainFunction.self + in + Project.clear ~selection () + end + end; + let new_def, new_decl = + dup_global + loc + (Annotations.funspec ~populate:false kf) + (Lazy.force sound_verdict_vi) + kf + vi + new_vi + in + (* postpone the introduction of the new function definition *) + let new_defs = new_def :: new_defs in + (* put the declaration before the original function in order to solve + issues with recursive functions *) + g :: new_decl :: globals, new_defs + end else begin (* not duplicated *) + prepare_fundec kf; + g :: globals, new_defs + end + | g -> + (* nothing to do for globals that are not functions *) + g :: globals, new_defs + +let prepare_file file = + Dup_functions.reset (); + let rev_globals, new_defs = + List.fold_left prepare_global ([], []) file.globals + in + match new_defs with + | [] -> () + | _ :: _ -> + (* insert the new_definitions at the end and reverse back the globals *) + let globals = List.fold_left (fun acc g -> g :: acc) new_defs rev_globals in + (* insert [__e_acsl_sound_verdict] at the beginning *) + let sg = GVarDecl(Lazy.force sound_verdict_vi, Location.unknown) in + file.globals <- sg :: globals let prepare () = Options.feedback ~level:2 "prepare AST for E-ACSL transformations"; - Visitor.visitFramacFile (new prepare_visitor) (Ast.get ()); - Queue.iter (fun f -> f ()) actions; + prepare_file (Ast.get ()); Ast.mark_as_grown () (* diff --git a/src/plugins/e-acsl/src/project_initializer/prepare_ast.mli b/src/plugins/e-acsl/src/project_initializer/prepare_ast.mli index 5237a7d39d59ca87564a0f4d6329972f641c9f42..65ea62daf1854443f8523737c7f519d9e18e9dd6 100644 --- a/src/plugins/e-acsl/src/project_initializer/prepare_ast.mli +++ b/src/plugins/e-acsl/src/project_initializer/prepare_ast.mli @@ -25,7 +25,6 @@ More precisely, this module performs the following tasks: - generating a new definition for functions with contract; - removing term sharing; - - storing what is necessary to translate in [Keep_status]; - in case of temporal validity checks, adding the attribute "aligned" to variables that are not sufficiently aligned. *) diff --git a/src/plugins/e-acsl/src/project_initializer/rtl.ml b/src/plugins/e-acsl/src/project_initializer/rtl.ml new file mode 100644 index 0000000000000000000000000000000000000000..38f3fb5809f3adc1a37e721dbb726d3a46f31393 --- /dev/null +++ b/src/plugins/e-acsl/src/project_initializer/rtl.ml @@ -0,0 +1,270 @@ +(**************************************************************************) +(* *) +(* This file is part of the Frama-C's E-ACSL plug-in. *) +(* *) +(* Copyright (C) 2012-2020 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(* *) +(**************************************************************************) + +open Cil_types +open Cil_datatype + +let rtl_files () = + List.map + (fun d -> Options.Share.get_file ~mode:`Must_exist d) + [ "e_acsl_gmp_api.h"; + "e_acsl.h" ] + +(* create the RTL AST in a fresh project *) +let create_rtl_ast prj = + Project.on + prj + (fun () -> + (* compute the RTL AST in the standard E-ACSL setting *) + if Plugin.is_present "variadic" then + Dynamic.Parameter.Bool.off "-variadic-translation" (); + Kernel.Keep_unused_specified_functions.off (); + Kernel.CppExtraArgs.add + (Format.asprintf " -DE_ACSL_MACHDEP=%s" (Kernel.Machdep.get ())); + Kernel.Files.set (rtl_files ()); + Ast.get ()) + () + +(* Note: vids, sids and eids are shared between projects (see implementation of + [Cil_const]). Therefore, no need to set them when inserting the corresponding + global into the AST. *) + +(* Tables that contain RTL's symbols. Useful to know whether some symbols is + part of the RTL. *) +module Symbols: sig + val add_global: global -> unit + val mem_global: global -> bool + val add_kf: kernel_function -> unit + val mem_kf: kernel_function -> bool + val add_vi: string -> varinfo -> unit + val mem_vi: string -> bool + exception Unregistered of string + val find_vi: string -> varinfo (* may raise Unregistered *) + (* val debug: unit -> unit*) +end = struct + + let globals: unit Global.Hashtbl.t = Global.Hashtbl.create 17 + let kfs: unit Kernel_function.Hashtbl.t = Kernel_function.Hashtbl.create 17 + let vars + : varinfo Datatype.String.Hashtbl.t + = Datatype.String.Hashtbl.create 17 + + let add_global g = Global.Hashtbl.add globals g () + let mem_global g = Global.Hashtbl.mem globals g + + let add_kf g = Kernel_function.Hashtbl.add kfs g () + let mem_kf g = Kernel_function.Hashtbl.mem kfs g + + let add_vi s vi = Datatype.String.Hashtbl.add vars s vi + let mem_vi s = Datatype.String.Hashtbl.mem vars s + exception Unregistered of string + let find_vi s = + try Datatype.String.Hashtbl.find vars s + with Not_found -> raise (Unregistered s) + +(* + let debug () = + Global.Hashtbl.iter + (fun g1 () -> Format.printf "RTL %a@." Printer.pp_global g1) + rtl; + Varinfo.Hashtbl.iter + (fun g1 g2 -> Format.printf "VAR %a -> %a@." + Printer.pp_varinfo g1 + Printer.pp_varinfo g2) + vars; + Typ.Hashtbl.iter + (fun g1 g2 -> Format.printf "TYP %a -> %a@." + Printer.pp_typ g1 + Printer.pp_typ g2) + types; + Global_annotation.Hashtbl.iter + (fun g1 g2 -> Format.printf "ANNOT %a -> %a@." + Printer.pp_global_annotation g1 + Printer.pp_global_annotation g2) + annots +*) +end + +(* NOTE: do not use [Mergecil.merge] since all [ast]'s symbols must be kept + unchanged: so do it ourselves. Thanksfully, we merge in a particular + setting because we know what the RTL is. Therefore merging is far from being + as complicated as [Mergecil]. *) + +(* lookup globals from [rtl_ast] in the current [ast] and fill the [Symbols]' + tables. + @return the list of globals to be inserted into [ast], in reverse order. *) +let lookup_rtl_globals rtl_ast = + (* [do_it ~add mem acc l g] checks whether the global does exist in the user's + AST. If not, add it to the corresponding symbol table(s). *) + let rec do_it ?(add=fun _g -> ()) mem acc l g = + if mem g then do_globals (g :: acc) l + else begin + add g; + Symbols.add_global g; + do_globals (g :: acc) l + end + (* [do_ty] is [do_it] for types *) + and do_ty acc l g kind tname = + do_it (fun _ -> Globals.Types.mem_type kind tname) acc l g + and do_globals acc globs = + match globs with + | [] -> + acc + | GType(ti, _loc) as g :: l -> + do_ty acc l g Logic_typing.Typedef ti.tname + | GCompTag(ci, _loc) | GCompTagDecl(ci, _loc) as g :: l -> + let k = if ci.cstruct then Logic_typing.Struct else Logic_typing.Union in + do_ty acc l g k ci.cname + | GEnumTag(ei, _loc) | GEnumTagDecl(ei, _loc) as g :: l -> + do_ty acc l g Logic_typing.Enum ei.ename + | GVarDecl(vi, (pos, _)) | GVar(vi, _, (pos, _)) as g :: l -> + let tunit = Translation_unit pos.Filepath.pos_path in + let mem _g = + let g = Globals.Syntactic_search.find_in_scope vi.vorig_name tunit in + Option.is_some g + in + let add g = + Symbols.add_vi vi.vname vi; + match g with + | GVarDecl _ -> Globals.Vars.add_decl vi + | GVar(_, ii, _) -> Globals.Vars.add vi ii + | _ -> assert false + in + do_it ~add mem acc l g + | GFunDecl(_, vi, _loc) | GFun({ svar = vi }, _loc) as g :: l -> + let add _g = + Symbols.add_vi vi.vname vi; + (* functions will be registered in kernel's table after substitution of + RTL's symbols inside them *) + in + do_it ~add (fun _ -> Globals.Functions.mem_name vi.vname) acc l g + | GAnnot _ :: l -> + (* ignoring annotations from the AST *) + do_globals acc l + | GAsm _ | GPragma _ | GText _ as g :: _l -> + Kernel.fatal "unexpected global %a" Printer.pp_global g + in + do_globals [] rtl_ast.globals + +(* [substitute_rtl_symbols] registers the correct symbols for RTL's functions *) +let substitute_rtl_symbols rtl_prj = function + | GVarDecl _ | GVar _ as g -> + g + | GFunDecl(_, vi, loc) | GFun({ svar = vi }, loc) as g -> + let get_kf vi = + try + Globals.Functions.get vi + with Not_found -> + Options.fatal "unknown function %s in project %a" + vi.vname + Project.pretty (Project.current ()) + in + let selection = + State_selection.of_list + [ Globals.Functions.self; Annotations.funspec_state ] + in + (* get the RTL's formals and spec *) + let formals, spec = + Project.on + rtl_prj + ~selection + (fun vi -> + let kf = get_kf vi in + Kernel_function.get_formals kf, + Annotations.funspec ~populate:false kf) + vi + in + (match g with + | GFunDecl _ -> + Globals.Functions.replace_by_declaration spec vi loc + | GFun(fundec, _) -> + Globals.Functions.replace_by_definition spec fundec loc + | _ -> assert false); + (* [Globals.Functions.replace_by_declaration] assigns new vids to formals: + get them back to their original ids in order to have the correct ids in + [spec] *) + let kf = get_kf vi in + List.iter2 + (fun rtl_vi src_vi -> src_vi.vid <- rtl_vi.vid) + formals + (Kernel_function.get_formals kf); + Cil.unsafeSetFormalsDecl vi formals; + Annotations.register_funspec ~emitter:Options.emitter kf; + Symbols.add_kf kf; + g + | GType _ | GCompTag _ | GCompTagDecl _ | GEnumTag _ | GEnumTagDecl _ + | GAnnot _ | GAsm _ | GPragma _ | GText _ -> + assert false + +(* [insert_rtl_globals] adds the rtl symbols into the user's AST *) +let insert_rtl_globals rtl_prj rtl_globals ast = + let add_ty acc old_g new_g = + let g = if Symbols.mem_global old_g then old_g else new_g in + (* keep them in the AST even if already in the user's one to prevent forward + references *) + g :: acc + in + let rec add acc = function + | [] -> + acc + | GType _ | GCompTagDecl _ | GEnumTagDecl _ as g :: l -> + (* RTL types contain no libc values: no need to substitute inside them *) + let acc = add_ty acc g g in + add acc l + | GCompTag(ci, loc) as g :: l -> + (* RTL's structure definitions that are already defined in the AST shall + be only declared *) + let acc = add_ty acc g (GCompTagDecl(ci, loc)) in + add acc l + | GEnumTag(ei, loc) as g :: l -> + (* RTL's enum definitions that are already defined in the AST shall be + only declared *) + let acc = add_ty acc g (GEnumTagDecl(ei, loc)) in + add acc l + | GVarDecl _ | GVar _ | GFunDecl _ | GFun _ as g :: l -> + let acc = + if Symbols.mem_global g then + let g = substitute_rtl_symbols rtl_prj g in + g :: acc + else + acc + in + add acc l + | GAnnot _ | GAsm _ | GPragma _ | GText _ as g :: _l -> + Kernel.fatal "unexpected global %a" Printer.pp_global g + in + ast.globals <- add ast.globals rtl_globals + +let link rtl_prj = + Options.feedback ~level:2 "link the E-ACSL RTL with the user source code"; + let rtl_ast = create_rtl_ast rtl_prj in + let ast = Ast.get () in + let rtl_globals = lookup_rtl_globals rtl_ast in + (* Symbols.debug ();*) + insert_rtl_globals rtl_prj rtl_globals ast; + Ast.mark_as_grown () + +(* +Local Variables: +compile-command: "make -C ../../../../.." +End: +*) diff --git a/src/plugins/e-acsl/src/project_initializer/keep_status.mli b/src/plugins/e-acsl/src/project_initializer/rtl.mli similarity index 61% rename from src/plugins/e-acsl/src/project_initializer/keep_status.mli rename to src/plugins/e-acsl/src/project_initializer/rtl.mli index 455662756b7abdf51f79185ee20d09bf03fddd8a..ff7cf96526a68a6ab7a22d40c14865cf2825326c 100644 --- a/src/plugins/e-acsl/src/project_initializer/keep_status.mli +++ b/src/plugins/e-acsl/src/project_initializer/rtl.mli @@ -20,41 +20,29 @@ (* *) (**************************************************************************) -(** Make the property statuses of the initial project accessible when - doing the main translation *) +(** This module links the E-ACSL's RTL to the user source code. *) -type kind = - | K_Assert - | K_Invariant - | K_Variant - | K_StmtSpec - | K_Allocation - | K_Assigns - | K_Decreases - | K_Terminates (* TODO: should be removed: not part of the E-ACSL subset *) - | K_Complete - | K_Disjoint - | K_Requires - | K_Ensures +val link: Project.t -> unit +(** [link prj] links the RTL's AST contained in [prj] to the AST of the current + project. *) -val clear: unit -> unit -(** to be called before any program transformation *) +(** Tables that contain RTL's symbols. Useful to know whether some symbols is + part of the RTL. *) +module Symbols: sig + open Cil_types -val push: Kernel_function.t -> kind -> Property.t -> unit -(** store the given property of the given kind for the given function *) + val mem_global: global -> bool + val mem_kf: kernel_function -> bool -val before_translation: unit -> unit -(** to be called just before injecting the code *) + val mem_vi: string -> bool + exception Unregistered of string + val find_vi: string -> varinfo + (** @raise Unregistered if the given name is not part of the RTL. *) -val must_translate: Kernel_function.t -> kind -> bool -(** To be called just before transforming a property of the given kind for the - given function. - VERY IMPORTANT: the property of the n-th call to this function exactly - correspond to the n-th pushed property (see {!push}). - @return true if and only if the translation must occur. *) +end (* Local Variables: -compile-command: "make -C ../.." +compile-command: "make -C ../../../../.." End: *) diff --git a/src/plugins/e-acsl/tests/arith/array.i b/src/plugins/e-acsl/tests/arith/array.i index 6211cf0950134f6a9c05becab68884473392be21..4ef7b8e882fb2b7aa57e48eb425b5436fd70349b 100644 --- a/src/plugins/e-acsl/tests/arith/array.i +++ b/src/plugins/e-acsl/tests/arith/array.i @@ -1,10 +1,106 @@ /* run.config_ci COMMENT: arrays - STDOPT: #"-slevel 5" + STDOPT: #"-eva-slevel 5" */ int T1[3],T2[4]; +void arrays() { + // Pure logic arrays + // (Unsupported at the moment by the kernel) + // /*@ assert {[0] = 1, [1] = 2, [2] = 3} == {[0] = 1, [1] = 2, [2] = 3}; */ + // /*@ assert {[0] = 1, [1] = 2, [2] = 3} != {[0] = 4, [1] = 5, [2] = 6}; */ + // /*@ assert {[0] = 1, [1] = 2, [2] = 3} != + // {[0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = 6}; */ + + // C arrays + int a[] = {1, 2, 3}; + int b[] = {4, 5, 6}; + int c[] = {1, 2, 3}; + int d[] = {1, 2, 3, 4, 5, 6}; + /*@ assert a != b; */ + /*@ assert a == c; */ + /*@ assert a != d; */ + + // Pointers to arrays + int * e = a; + int * f = b; + int * g = c; + int * h = a; + /*@ assert e != f; */ + /*@ assert e != g; */ + /*@ assert e == h; */ + + // Comparison between C arrays, logic arrays and pointer to arrays + // /*@ assert a == {[0] = 1, [1] = 2, [2] = 3}; */ UNSUPPORTED by the kernel + /*@ assert e == (int *) a; */ + /*@ assert e != (int *) c; */ + // /*@ assert (int[3])e == {[0] = 1, [1] = 2, [2] = 3}; */ UNSUPPORTED by the kernel + // /*@ assert (int[])e == {[0] = 1, [1] = 2, [2] = 3}; */ UNSUPPORTED by the kernel + /*@ assert a == (int[3])g; */ + /*@ assert a == (int[])g; */ + /*@ assert a != (int[3])f; */ + /*@ assert a != (int[])f; */ + + // Comparison between sub-arrays + int i[] = {1, 2, 3, 4, 5, 6}; + int j[] = {4, 5, 6, 1, 2, 3}; + int k[] = {4, 5, 6, 4, 5, 6}; + /*@ assert i != j; */ + /*@ assert i != k; */ + /*@ assert j != k; */ + int * l = &i[3]; + int * m = &j[3]; + int * n = &k[3]; + /*@ assert (int[3])l != (int[3])m; */ + /*@ assert (int[3])l == (int[3])n; */ + + // Array truncation + /*@ assert (int[3])i != (int[3])k; */ + /*@ assert (int[3])j == (int[3])k; */ + /*@ assert (int[2])l != (int[2])m; */ + /*@ assert (int[2])l == (int[2])n; */ + + // Errors if trying an array extension + /*ERROR assert (int[10])i != (int[10])k; */ + /*ERROR assert (int[10])j != (int[10])k; */ + /*ERROR assert (int[6])l != (int[6])m; */ + /*ERROR assert (int[6])l == (int[6])n; */ + + + // Errors while comparing a pointer to array with an array (logic or C) + /*ERROR: assert e == a; */ + /*ERROR: assert e == {[0] = 1, [1] = 2, [2] = 3}; */ + + // Error while casting a logic array to a pointer to array + /*ERROR: assert e != (int*){[0] = 1, [1] = 2, [2] = 3}; */ +} + +void vlas(int n) { + // FIXME: There is currently an error with the support of VLA in E-ACSL + // https://git.frama-c.com/frama-c/e-acsl/-/issues/119 + + // // Declare VLAs + // int a[n+1]; + // int b[n+1]; + // int c[n+1]; + + // // Initialize arrays + // for (int i = 0; i < (n+1) ; ++i) { + // a[i] = i; + // b[i] = n + 1 - i; + // c[i] = i; + // } + + // // // Compare VLAs + // // // The naive comparison compare pointers + // // /*@ assert a != b; */ + // // /*@ assert a == c; */ + // // // We need to cast to int[] to have an array comparison + // // /*@ assert (int[])a != (int[])b; */ + // // /*@ assert (int[])a == (int[])c; */ +} + int main(void) { for(int i = 0; i < 3; i++) T1[i] = i; @@ -13,5 +109,8 @@ int main(void) { /*@ assert T1[0] == T2[0]; */ /*@ assert T1[1] != T2[1]; */ + arrays(); + vlas(3); + return 0; } diff --git a/src/plugins/e-acsl/tests/arith/oracle_ci/array.res.oracle b/src/plugins/e-acsl/tests/arith/oracle_ci/array.res.oracle index efd026311297e55d8fefb674326118e6ece88624..c1008f0532893f6c5af5afe4bb908dfae70f97b0 100644 --- a/src/plugins/e-acsl/tests/arith/oracle_ci/array.res.oracle +++ b/src/plugins/e-acsl/tests/arith/oracle_ci/array.res.oracle @@ -1,2 +1,18 @@ [e-acsl] beginning translation. [e-acsl] translation done in project "e-acsl". +[eva:alarm] tests/arith/array.i:21: Warning: assertion got status unknown. +[eva:alarm] tests/arith/array.i:22: Warning: assertion got status unknown. +[eva:alarm] tests/arith/array.i:23: Warning: assertion got status unknown. +[eva:alarm] tests/arith/array.i:40: Warning: assertion got status unknown. +[eva:alarm] tests/arith/array.i:41: Warning: assertion got status unknown. +[eva:alarm] tests/arith/array.i:42: Warning: assertion got status unknown. +[eva:alarm] tests/arith/array.i:43: Warning: assertion got status unknown. +[eva:alarm] tests/arith/array.i:49: Warning: assertion got status unknown. +[eva:alarm] tests/arith/array.i:50: Warning: assertion got status unknown. +[eva:alarm] tests/arith/array.i:51: Warning: assertion got status unknown. +[eva:alarm] tests/arith/array.i:55: Warning: assertion got status unknown. +[eva:alarm] tests/arith/array.i:56: Warning: assertion got status unknown. +[eva:alarm] tests/arith/array.i:59: Warning: assertion got status unknown. +[eva:alarm] tests/arith/array.i:60: Warning: assertion got status unknown. +[eva:alarm] tests/arith/array.i:61: Warning: assertion got status unknown. +[eva:alarm] tests/arith/array.i:62: Warning: assertion got status unknown. diff --git a/src/plugins/e-acsl/tests/arith/oracle_ci/gen_array.c b/src/plugins/e-acsl/tests/arith/oracle_ci/gen_array.c index 334e1f1891acd45ad6414ea94e962a4e8325adf2..b65d0e8fe7686a76b411ddaa1c26c7d331c15ce1 100644 --- a/src/plugins/e-acsl/tests/arith/oracle_ci/gen_array.c +++ b/src/plugins/e-acsl/tests/arith/oracle_ci/gen_array.c @@ -3,9 +3,535 @@ #include "stdlib.h" int T1[3]; int T2[4]; +void arrays(void) +{ + int a[3] = {1, 2, 3}; + int b[3] = {4, 5, 6}; + __e_acsl_store_block((void *)(b),(size_t)12); + __e_acsl_full_init((void *)(& b)); + int c[3] = {1, 2, 3}; + __e_acsl_store_block((void *)(c),(size_t)12); + __e_acsl_full_init((void *)(& c)); + int d[6] = {1, 2, 3, 4, 5, 6}; + { + int __gen_e_acsl_ne; + __gen_e_acsl_ne = 0; + if (1) { + unsigned long __gen_e_acsl_iter; + __gen_e_acsl_iter = 0; + while (__gen_e_acsl_iter < 3) { + if (a[__gen_e_acsl_iter] != b[__gen_e_acsl_iter]) { + __gen_e_acsl_ne = 1; + break; + } + __gen_e_acsl_iter ++; + } + } + else __gen_e_acsl_ne = 1; + __e_acsl_assert(__gen_e_acsl_ne,"Assertion","arrays","a != b", + "tests/arith/array.i",21); + } + /*@ assert a ≢ b; */ ; + { + int __gen_e_acsl_eq; + __gen_e_acsl_eq = 1; + if (1) { + unsigned long __gen_e_acsl_iter_2; + __gen_e_acsl_iter_2 = 0; + while (__gen_e_acsl_iter_2 < 3) { + if (a[__gen_e_acsl_iter_2] != c[__gen_e_acsl_iter_2]) { + __gen_e_acsl_eq = 0; + break; + } + __gen_e_acsl_iter_2 ++; + } + } + else __gen_e_acsl_eq = 0; + __e_acsl_assert(__gen_e_acsl_eq,"Assertion","arrays","a == c", + "tests/arith/array.i",22); + } + /*@ assert a ≡ c; */ ; + { + int __gen_e_acsl_ne_2; + __gen_e_acsl_ne_2 = 0; + if (0) { + unsigned long __gen_e_acsl_iter_3; + __gen_e_acsl_iter_3 = 0; + while (__gen_e_acsl_iter_3 < 3) { + if (a[__gen_e_acsl_iter_3] != d[__gen_e_acsl_iter_3]) { + __gen_e_acsl_ne_2 = 1; + break; + } + __gen_e_acsl_iter_3 ++; + } + } + else __gen_e_acsl_ne_2 = 1; + __e_acsl_assert(__gen_e_acsl_ne_2,"Assertion","arrays","a != d", + "tests/arith/array.i",23); + } + /*@ assert a ≢ d; */ ; + int *e = a; + int *f = b; + __e_acsl_store_block((void *)(& f),(size_t)8); + __e_acsl_full_init((void *)(& f)); + int *g = c; + __e_acsl_store_block((void *)(& g),(size_t)8); + __e_acsl_full_init((void *)(& g)); + int *h = a; + __e_acsl_assert(e != f,"Assertion","arrays","e != f","tests/arith/array.i", + 30); + /*@ assert e ≢ f; */ ; + __e_acsl_assert(e != g,"Assertion","arrays","e != g","tests/arith/array.i", + 31); + /*@ assert e ≢ g; */ ; + __e_acsl_assert(e == h,"Assertion","arrays","e == h","tests/arith/array.i", + 32); + /*@ assert e ≡ h; */ ; + __e_acsl_assert(e == a,"Assertion","arrays","e == (int *)a", + "tests/arith/array.i",36); + /*@ assert e ≡ (int *)a; */ ; + __e_acsl_assert(e != c,"Assertion","arrays","e != (int *)c", + "tests/arith/array.i",37); + /*@ assert e ≢ (int *)c; */ ; + { + int __gen_e_acsl_eq_2; + __gen_e_acsl_eq_2 = 1; + if (1) { + unsigned long __gen_e_acsl_iter_4; + __gen_e_acsl_iter_4 = 0; + while (__gen_e_acsl_iter_4 < 3) { + { + int __gen_e_acsl_valid_read; + __gen_e_acsl_valid_read = __e_acsl_valid_read((void *)(& (*((int (*)[3])g))[__gen_e_acsl_iter_4]), + sizeof(int), + (void *)(& (*((int (*)[3])g))[__gen_e_acsl_iter_4]), + (void *)0); + __e_acsl_assert(__gen_e_acsl_valid_read,"RTE","arrays", + "mem_access: \\valid_read(&(*((int (*)[3])g))[__gen_e_acsl_iter_4])", + "tests/arith/array.i",40); + if (a[__gen_e_acsl_iter_4] != (*((int (*)[3])g))[__gen_e_acsl_iter_4]) { + __gen_e_acsl_eq_2 = 0; + break; + } + } + __gen_e_acsl_iter_4 ++; + } + } + else __gen_e_acsl_eq_2 = 0; + __e_acsl_assert(__gen_e_acsl_eq_2,"Assertion","arrays", + "a == *((int (*)[3])g)","tests/arith/array.i",40); + } + /*@ assert a ≡ *((int (*)[3])g); */ ; + { + int __gen_e_acsl_eq_3; + int __gen_e_acsl_valid_read_2; + unsigned long __gen_e_acsl_; + unsigned long __gen_e_acsl__2; + unsigned long __gen_e_acsl_length2; + __gen_e_acsl_eq_3 = 1; + __gen_e_acsl_valid_read_2 = __e_acsl_valid_read((void *)(*((int (*)[])g)), + sizeof(int), + (void *)(*((int (*)[])g)), + (void *)(*((int (*)[])g))); + __e_acsl_assert(__gen_e_acsl_valid_read_2,"RTE","arrays", + "mem_access: \\valid_read((int *)*((int (*)[])g))", + "tests/arith/array.i",41); + __gen_e_acsl_ = __e_acsl_block_length((void *)(*((int (*)[])g))); + __gen_e_acsl__2 = __e_acsl_offset((void *)(*((int (*)[])g))); + __gen_e_acsl_length2 = (__gen_e_acsl_ - __gen_e_acsl__2) / sizeof(int); + if (3UL == __gen_e_acsl_length2) { + unsigned long __gen_e_acsl_iter_5; + __gen_e_acsl_iter_5 = 0; + while (__gen_e_acsl_iter_5 < 3) { + { + int __gen_e_acsl_valid_read_3; + __gen_e_acsl_valid_read_3 = __e_acsl_valid_read((void *)(& (*((int (*)[])g))[__gen_e_acsl_iter_5]), + sizeof(int), + (void *)(& (*((int (*)[])g))[__gen_e_acsl_iter_5]), + (void *)0); + __e_acsl_assert(__gen_e_acsl_valid_read_3,"RTE","arrays", + "mem_access: \\valid_read(&(*((int (*)[])g))[__gen_e_acsl_iter_5])", + "tests/arith/array.i",41); + if (a[__gen_e_acsl_iter_5] != (*((int (*)[])g))[__gen_e_acsl_iter_5]) { + __gen_e_acsl_eq_3 = 0; + break; + } + } + __gen_e_acsl_iter_5 ++; + } + } + else __gen_e_acsl_eq_3 = 0; + __e_acsl_assert(__gen_e_acsl_eq_3,"Assertion","arrays", + "a == *((int (*)[])g)","tests/arith/array.i",41); + } + /*@ assert a ≡ *((int (*)[])g); */ ; + { + int __gen_e_acsl_ne_3; + __gen_e_acsl_ne_3 = 0; + if (1) { + unsigned long __gen_e_acsl_iter_6; + __gen_e_acsl_iter_6 = 0; + while (__gen_e_acsl_iter_6 < 3) { + { + int __gen_e_acsl_valid_read_4; + __gen_e_acsl_valid_read_4 = __e_acsl_valid_read((void *)(& (*((int (*)[3])f))[__gen_e_acsl_iter_6]), + sizeof(int), + (void *)(& (*((int (*)[3])f))[__gen_e_acsl_iter_6]), + (void *)0); + __e_acsl_assert(__gen_e_acsl_valid_read_4,"RTE","arrays", + "mem_access: \\valid_read(&(*((int (*)[3])f))[__gen_e_acsl_iter_6])", + "tests/arith/array.i",42); + if (a[__gen_e_acsl_iter_6] != (*((int (*)[3])f))[__gen_e_acsl_iter_6]) { + __gen_e_acsl_ne_3 = 1; + break; + } + } + __gen_e_acsl_iter_6 ++; + } + } + else __gen_e_acsl_ne_3 = 1; + __e_acsl_assert(__gen_e_acsl_ne_3,"Assertion","arrays", + "a != *((int (*)[3])f)","tests/arith/array.i",42); + } + /*@ assert a ≢ *((int (*)[3])f); */ ; + { + int __gen_e_acsl_ne_4; + int __gen_e_acsl_valid_read_5; + unsigned long __gen_e_acsl__3; + unsigned long __gen_e_acsl__4; + unsigned long __gen_e_acsl_length2_2; + __gen_e_acsl_ne_4 = 0; + __gen_e_acsl_valid_read_5 = __e_acsl_valid_read((void *)(*((int (*)[])f)), + sizeof(int), + (void *)(*((int (*)[])f)), + (void *)(*((int (*)[])f))); + __e_acsl_assert(__gen_e_acsl_valid_read_5,"RTE","arrays", + "mem_access: \\valid_read((int *)*((int (*)[])f))", + "tests/arith/array.i",43); + __gen_e_acsl__3 = __e_acsl_block_length((void *)(*((int (*)[])f))); + __gen_e_acsl__4 = __e_acsl_offset((void *)(*((int (*)[])f))); + __gen_e_acsl_length2_2 = (__gen_e_acsl__3 - __gen_e_acsl__4) / sizeof(int); + if (3UL == __gen_e_acsl_length2_2) { + unsigned long __gen_e_acsl_iter_7; + __gen_e_acsl_iter_7 = 0; + while (__gen_e_acsl_iter_7 < 3) { + { + int __gen_e_acsl_valid_read_6; + __gen_e_acsl_valid_read_6 = __e_acsl_valid_read((void *)(& (*((int (*)[])f))[__gen_e_acsl_iter_7]), + sizeof(int), + (void *)(& (*((int (*)[])f))[__gen_e_acsl_iter_7]), + (void *)0); + __e_acsl_assert(__gen_e_acsl_valid_read_6,"RTE","arrays", + "mem_access: \\valid_read(&(*((int (*)[])f))[__gen_e_acsl_iter_7])", + "tests/arith/array.i",43); + if (a[__gen_e_acsl_iter_7] != (*((int (*)[])f))[__gen_e_acsl_iter_7]) { + __gen_e_acsl_ne_4 = 1; + break; + } + } + __gen_e_acsl_iter_7 ++; + } + } + else __gen_e_acsl_ne_4 = 1; + __e_acsl_assert(__gen_e_acsl_ne_4,"Assertion","arrays", + "a != *((int (*)[])f)","tests/arith/array.i",43); + } + /*@ assert a ≢ *((int (*)[])f); */ ; + int i[6] = {1, 2, 3, 4, 5, 6}; + __e_acsl_store_block((void *)(i),(size_t)24); + __e_acsl_full_init((void *)(& i)); + int j[6] = {4, 5, 6, 1, 2, 3}; + __e_acsl_store_block((void *)(j),(size_t)24); + __e_acsl_full_init((void *)(& j)); + int k[6] = {4, 5, 6, 4, 5, 6}; + __e_acsl_store_block((void *)(k),(size_t)24); + __e_acsl_full_init((void *)(& k)); + { + int __gen_e_acsl_ne_5; + __gen_e_acsl_ne_5 = 0; + if (1) { + unsigned long __gen_e_acsl_iter_8; + __gen_e_acsl_iter_8 = 0; + while (__gen_e_acsl_iter_8 < 6) { + if (i[__gen_e_acsl_iter_8] != j[__gen_e_acsl_iter_8]) { + __gen_e_acsl_ne_5 = 1; + break; + } + __gen_e_acsl_iter_8 ++; + } + } + else __gen_e_acsl_ne_5 = 1; + __e_acsl_assert(__gen_e_acsl_ne_5,"Assertion","arrays","i != j", + "tests/arith/array.i",49); + } + /*@ assert i ≢ j; */ ; + { + int __gen_e_acsl_ne_6; + __gen_e_acsl_ne_6 = 0; + if (1) { + unsigned long __gen_e_acsl_iter_9; + __gen_e_acsl_iter_9 = 0; + while (__gen_e_acsl_iter_9 < 6) { + if (i[__gen_e_acsl_iter_9] != k[__gen_e_acsl_iter_9]) { + __gen_e_acsl_ne_6 = 1; + break; + } + __gen_e_acsl_iter_9 ++; + } + } + else __gen_e_acsl_ne_6 = 1; + __e_acsl_assert(__gen_e_acsl_ne_6,"Assertion","arrays","i != k", + "tests/arith/array.i",50); + } + /*@ assert i ≢ k; */ ; + { + int __gen_e_acsl_ne_7; + __gen_e_acsl_ne_7 = 0; + if (1) { + unsigned long __gen_e_acsl_iter_10; + __gen_e_acsl_iter_10 = 0; + while (__gen_e_acsl_iter_10 < 6) { + if (j[__gen_e_acsl_iter_10] != k[__gen_e_acsl_iter_10]) { + __gen_e_acsl_ne_7 = 1; + break; + } + __gen_e_acsl_iter_10 ++; + } + } + else __gen_e_acsl_ne_7 = 1; + __e_acsl_assert(__gen_e_acsl_ne_7,"Assertion","arrays","j != k", + "tests/arith/array.i",51); + } + /*@ assert j ≢ k; */ ; + int *l = & i[3]; + __e_acsl_store_block((void *)(& l),(size_t)8); + __e_acsl_full_init((void *)(& l)); + int *m = & j[3]; + __e_acsl_store_block((void *)(& m),(size_t)8); + __e_acsl_full_init((void *)(& m)); + int *n = & k[3]; + __e_acsl_store_block((void *)(& n),(size_t)8); + __e_acsl_full_init((void *)(& n)); + { + int __gen_e_acsl_ne_8; + __gen_e_acsl_ne_8 = 0; + if (1) { + unsigned long __gen_e_acsl_iter_11; + __gen_e_acsl_iter_11 = 0; + while (__gen_e_acsl_iter_11 < 3) { + { + int __gen_e_acsl_valid_read_7; + int __gen_e_acsl_valid_read_8; + __gen_e_acsl_valid_read_7 = __e_acsl_valid_read((void *)(& (*((int (*)[3])l))[__gen_e_acsl_iter_11]), + sizeof(int), + (void *)(& (*((int (*)[3])l))[__gen_e_acsl_iter_11]), + (void *)0); + __e_acsl_assert(__gen_e_acsl_valid_read_7,"RTE","arrays", + "mem_access: \\valid_read(&(*((int (*)[3])l))[__gen_e_acsl_iter_11])", + "tests/arith/array.i",55); + __gen_e_acsl_valid_read_8 = __e_acsl_valid_read((void *)(& (*((int (*)[3])m))[__gen_e_acsl_iter_11]), + sizeof(int), + (void *)(& (*((int (*)[3])m))[__gen_e_acsl_iter_11]), + (void *)0); + __e_acsl_assert(__gen_e_acsl_valid_read_8,"RTE","arrays", + "mem_access: \\valid_read(&(*((int (*)[3])m))[__gen_e_acsl_iter_11])", + "tests/arith/array.i",55); + if ((*((int (*)[3])l))[__gen_e_acsl_iter_11] != (*((int (*)[3])m))[__gen_e_acsl_iter_11]) { + __gen_e_acsl_ne_8 = 1; + break; + } + } + __gen_e_acsl_iter_11 ++; + } + } + else __gen_e_acsl_ne_8 = 1; + __e_acsl_assert(__gen_e_acsl_ne_8,"Assertion","arrays", + "*((int (*)[3])l) != *((int (*)[3])m)", + "tests/arith/array.i",55); + } + /*@ assert *((int (*)[3])l) ≢ *((int (*)[3])m); */ ; + { + int __gen_e_acsl_eq_4; + __gen_e_acsl_eq_4 = 1; + if (1) { + unsigned long __gen_e_acsl_iter_12; + __gen_e_acsl_iter_12 = 0; + while (__gen_e_acsl_iter_12 < 3) { + { + int __gen_e_acsl_valid_read_9; + int __gen_e_acsl_valid_read_10; + __gen_e_acsl_valid_read_9 = __e_acsl_valid_read((void *)(& (*((int (*)[3])l))[__gen_e_acsl_iter_12]), + sizeof(int), + (void *)(& (*((int (*)[3])l))[__gen_e_acsl_iter_12]), + (void *)0); + __e_acsl_assert(__gen_e_acsl_valid_read_9,"RTE","arrays", + "mem_access: \\valid_read(&(*((int (*)[3])l))[__gen_e_acsl_iter_12])", + "tests/arith/array.i",56); + __gen_e_acsl_valid_read_10 = __e_acsl_valid_read((void *)(& (*((int (*)[3])n))[__gen_e_acsl_iter_12]), + sizeof(int), + (void *)(& (*((int (*)[3])n))[__gen_e_acsl_iter_12]), + (void *)0); + __e_acsl_assert(__gen_e_acsl_valid_read_10,"RTE","arrays", + "mem_access: \\valid_read(&(*((int (*)[3])n))[__gen_e_acsl_iter_12])", + "tests/arith/array.i",56); + if ((*((int (*)[3])l))[__gen_e_acsl_iter_12] != (*((int (*)[3])n))[__gen_e_acsl_iter_12]) { + __gen_e_acsl_eq_4 = 0; + break; + } + } + __gen_e_acsl_iter_12 ++; + } + } + else __gen_e_acsl_eq_4 = 0; + __e_acsl_assert(__gen_e_acsl_eq_4,"Assertion","arrays", + "*((int (*)[3])l) == *((int (*)[3])n)", + "tests/arith/array.i",56); + } + /*@ assert *((int (*)[3])l) ≡ *((int (*)[3])n); */ ; + { + int __gen_e_acsl_ne_9; + __gen_e_acsl_ne_9 = 0; + if (1) { + unsigned long __gen_e_acsl_iter_13; + __e_acsl_assert(1,"RTE","arrays","array_coercion: (int)3 <= (int)6", + "tests/arith/array.i",59); + __e_acsl_assert(1,"RTE","arrays","array_coercion: (int)3 <= (int)6", + "tests/arith/array.i",59); + __gen_e_acsl_iter_13 = 0; + while (__gen_e_acsl_iter_13 < 3) { + if (i[__gen_e_acsl_iter_13] != k[__gen_e_acsl_iter_13]) { + __gen_e_acsl_ne_9 = 1; + break; + } + __gen_e_acsl_iter_13 ++; + } + } + else __gen_e_acsl_ne_9 = 1; + __e_acsl_assert(__gen_e_acsl_ne_9,"Assertion","arrays", + "(int [3])i != (int [3])k","tests/arith/array.i",59); + } + /*@ assert (int [3])i ≢ (int [3])k; */ ; + { + int __gen_e_acsl_eq_5; + __gen_e_acsl_eq_5 = 1; + if (1) { + unsigned long __gen_e_acsl_iter_14; + __e_acsl_assert(1,"RTE","arrays","array_coercion: (int)3 <= (int)6", + "tests/arith/array.i",60); + __e_acsl_assert(1,"RTE","arrays","array_coercion: (int)3 <= (int)6", + "tests/arith/array.i",60); + __gen_e_acsl_iter_14 = 0; + while (__gen_e_acsl_iter_14 < 3) { + if (j[__gen_e_acsl_iter_14] != k[__gen_e_acsl_iter_14]) { + __gen_e_acsl_eq_5 = 0; + break; + } + __gen_e_acsl_iter_14 ++; + } + } + else __gen_e_acsl_eq_5 = 0; + __e_acsl_assert(__gen_e_acsl_eq_5,"Assertion","arrays", + "(int [3])j == (int [3])k","tests/arith/array.i",60); + } + /*@ assert (int [3])j ≡ (int [3])k; */ ; + { + int __gen_e_acsl_ne_10; + __gen_e_acsl_ne_10 = 0; + if (1) { + unsigned long __gen_e_acsl_iter_15; + __gen_e_acsl_iter_15 = 0; + while (__gen_e_acsl_iter_15 < 2) { + { + int __gen_e_acsl_valid_read_11; + int __gen_e_acsl_valid_read_12; + __gen_e_acsl_valid_read_11 = __e_acsl_valid_read((void *)(& (*((int (*)[2])l))[__gen_e_acsl_iter_15]), + sizeof(int), + (void *)(& (*((int (*)[2])l))[__gen_e_acsl_iter_15]), + (void *)0); + __e_acsl_assert(__gen_e_acsl_valid_read_11,"RTE","arrays", + "mem_access: \\valid_read(&(*((int (*)[2])l))[__gen_e_acsl_iter_15])", + "tests/arith/array.i",61); + __gen_e_acsl_valid_read_12 = __e_acsl_valid_read((void *)(& (*((int (*)[2])m))[__gen_e_acsl_iter_15]), + sizeof(int), + (void *)(& (*((int (*)[2])m))[__gen_e_acsl_iter_15]), + (void *)0); + __e_acsl_assert(__gen_e_acsl_valid_read_12,"RTE","arrays", + "mem_access: \\valid_read(&(*((int (*)[2])m))[__gen_e_acsl_iter_15])", + "tests/arith/array.i",61); + if ((*((int (*)[2])l))[__gen_e_acsl_iter_15] != (*((int (*)[2])m))[__gen_e_acsl_iter_15]) { + __gen_e_acsl_ne_10 = 1; + break; + } + } + __gen_e_acsl_iter_15 ++; + } + } + else __gen_e_acsl_ne_10 = 1; + __e_acsl_assert(__gen_e_acsl_ne_10,"Assertion","arrays", + "*((int (*)[2])l) != *((int (*)[2])m)", + "tests/arith/array.i",61); + } + /*@ assert *((int (*)[2])l) ≢ *((int (*)[2])m); */ ; + { + int __gen_e_acsl_eq_6; + __gen_e_acsl_eq_6 = 1; + if (1) { + unsigned long __gen_e_acsl_iter_16; + __gen_e_acsl_iter_16 = 0; + while (__gen_e_acsl_iter_16 < 2) { + { + int __gen_e_acsl_valid_read_13; + int __gen_e_acsl_valid_read_14; + __gen_e_acsl_valid_read_13 = __e_acsl_valid_read((void *)(& (*((int (*)[2])l))[__gen_e_acsl_iter_16]), + sizeof(int), + (void *)(& (*((int (*)[2])l))[__gen_e_acsl_iter_16]), + (void *)0); + __e_acsl_assert(__gen_e_acsl_valid_read_13,"RTE","arrays", + "mem_access: \\valid_read(&(*((int (*)[2])l))[__gen_e_acsl_iter_16])", + "tests/arith/array.i",62); + __gen_e_acsl_valid_read_14 = __e_acsl_valid_read((void *)(& (*((int (*)[2])n))[__gen_e_acsl_iter_16]), + sizeof(int), + (void *)(& (*((int (*)[2])n))[__gen_e_acsl_iter_16]), + (void *)0); + __e_acsl_assert(__gen_e_acsl_valid_read_14,"RTE","arrays", + "mem_access: \\valid_read(&(*((int (*)[2])n))[__gen_e_acsl_iter_16])", + "tests/arith/array.i",62); + if ((*((int (*)[2])l))[__gen_e_acsl_iter_16] != (*((int (*)[2])n))[__gen_e_acsl_iter_16]) { + __gen_e_acsl_eq_6 = 0; + break; + } + } + __gen_e_acsl_iter_16 ++; + } + } + else __gen_e_acsl_eq_6 = 0; + __e_acsl_assert(__gen_e_acsl_eq_6,"Assertion","arrays", + "*((int (*)[2])l) == *((int (*)[2])n)", + "tests/arith/array.i",62); + } + /*@ assert *((int (*)[2])l) ≡ *((int (*)[2])n); */ ; + __e_acsl_delete_block((void *)(& n)); + __e_acsl_delete_block((void *)(& m)); + __e_acsl_delete_block((void *)(& l)); + __e_acsl_delete_block((void *)(k)); + __e_acsl_delete_block((void *)(j)); + __e_acsl_delete_block((void *)(i)); + __e_acsl_delete_block((void *)(& g)); + __e_acsl_delete_block((void *)(& f)); + __e_acsl_delete_block((void *)(c)); + __e_acsl_delete_block((void *)(b)); + return; +} + +void vlas(int n) +{ + return; +} + int main(void) { int __retres; + __e_acsl_memory_init((int *)0,(char ***)0,(size_t)8); { int i = 0; while (i < 3) { @@ -21,12 +547,15 @@ int main(void) } } __e_acsl_assert(T1[0] == T2[0],"Assertion","main","T1[0] == T2[0]", - "tests/arith/array.i",13); + "tests/arith/array.i",109); /*@ assert T1[0] ≡ T2[0]; */ ; __e_acsl_assert(T1[1] != T2[1],"Assertion","main","T1[1] != T2[1]", - "tests/arith/array.i",14); + "tests/arith/array.i",110); /*@ assert T1[1] ≢ T2[1]; */ ; + arrays(); + vlas(3); __retres = 0; + __e_acsl_memory_clean(); return __retres; } diff --git a/src/plugins/e-acsl/tests/bts/oracle_ci/gen_bts1386_complex_flowgraph.c b/src/plugins/e-acsl/tests/bts/oracle_ci/gen_bts1386_complex_flowgraph.c index 5f3956f765f048f6cac3858217ecfd51bfe4f7ea..b3d1e5df6a10a1ce8fb80e3003fc4f942cdff13b 100644 --- a/src/plugins/e-acsl/tests/bts/oracle_ci/gen_bts1386_complex_flowgraph.c +++ b/src/plugins/e-acsl/tests/bts/oracle_ci/gen_bts1386_complex_flowgraph.c @@ -1,4 +1,5 @@ /* Generated by Frama-C */ +#include "stddef.h" #include "stdio.h" #include "stdlib.h" void duffcopy(char *to, char *from, int count) diff --git a/src/plugins/e-acsl/tests/bts/oracle_ci/gen_bts1398.c b/src/plugins/e-acsl/tests/bts/oracle_ci/gen_bts1398.c index 6c992808644dc2b1a22a287bec261511fb770b8d..8f4aa78a77722c4c1bc7163cc8680bf7cc800d3a 100644 --- a/src/plugins/e-acsl/tests/bts/oracle_ci/gen_bts1398.c +++ b/src/plugins/e-acsl/tests/bts/oracle_ci/gen_bts1398.c @@ -1,4 +1,5 @@ /* Generated by Frama-C */ +#include "stddef.h" #include "stdio.h" #include "stdlib.h" char *__gen_e_acsl_literal_string; diff --git a/src/plugins/e-acsl/tests/bts/oracle_ci/gen_issue-eacsl-91.c b/src/plugins/e-acsl/tests/bts/oracle_ci/gen_issue-eacsl-91.c index 519c77cc7f1e326c2caa8402207cbea2b6564600..14dd1ab575af5a0d4560ecc5a1ac7ae3bc49a5d3 100644 --- a/src/plugins/e-acsl/tests/bts/oracle_ci/gen_issue-eacsl-91.c +++ b/src/plugins/e-acsl/tests/bts/oracle_ci/gen_issue-eacsl-91.c @@ -36,24 +36,6 @@ void __e_acsl_globals_init(void) __e_acsl_full_init((void *)(& b)); __e_acsl_store_block((void *)(& a),(size_t)2); __e_acsl_full_init((void *)(& a)); - __e_acsl_store_block((void *)(& __fc_p_tmpnam),(size_t)8); - __e_acsl_full_init((void *)(& __fc_p_tmpnam)); - __e_acsl_store_block((void *)(__fc_tmpnam),(size_t)2048); - __e_acsl_full_init((void *)(& __fc_tmpnam)); - __e_acsl_store_block((void *)(& __fc_p_fopen),(size_t)8); - __e_acsl_full_init((void *)(& __fc_p_fopen)); - __e_acsl_store_block((void *)(__fc_fopen),(size_t)128); - __e_acsl_full_init((void *)(& __fc_fopen)); - __e_acsl_store_block((void *)(& stdin),(size_t)8); - __e_acsl_full_init((void *)(& stdin)); - __e_acsl_store_block((void *)(& __fc_p_random48_counter),(size_t)8); - __e_acsl_full_init((void *)(& __fc_p_random48_counter)); - __e_acsl_store_block((void *)(random48_counter),(size_t)6); - __e_acsl_full_init((void *)(& random48_counter)); - __e_acsl_store_block((void *)(& __fc_random48_init),(size_t)4); - __e_acsl_full_init((void *)(& __fc_random48_init)); - __e_acsl_store_block((void *)(& __fc_rand_max),(size_t)8); - __e_acsl_full_init((void *)(& __fc_rand_max)); } return; } @@ -62,15 +44,6 @@ void __e_acsl_globals_delete(void) { __e_acsl_delete_block((void *)(& b)); __e_acsl_delete_block((void *)(& a)); - __e_acsl_delete_block((void *)(& __fc_p_tmpnam)); - __e_acsl_delete_block((void *)(__fc_tmpnam)); - __e_acsl_delete_block((void *)(& __fc_p_fopen)); - __e_acsl_delete_block((void *)(__fc_fopen)); - __e_acsl_delete_block((void *)(& stdin)); - __e_acsl_delete_block((void *)(& __fc_p_random48_counter)); - __e_acsl_delete_block((void *)(random48_counter)); - __e_acsl_delete_block((void *)(& __fc_random48_init)); - __e_acsl_delete_block((void *)(& __fc_rand_max)); } int main(void) diff --git a/src/plugins/e-acsl/tests/constructs/invariant.i b/src/plugins/e-acsl/tests/constructs/invariant.i index 76cbdb63c7169236217d0cb3a519aea09562eafd..8bc1eeee091a422a69c6b9ad3d8f2454f1b6e7c8 100644 --- a/src/plugins/e-acsl/tests/constructs/invariant.i +++ b/src/plugins/e-acsl/tests/constructs/invariant.i @@ -1,6 +1,6 @@ /* run.config_ci COMMENT: invariant - STDOPT: +"-slevel 11" + STDOPT: +"-eva-slevel 11" */ int main(void) { diff --git a/src/plugins/e-acsl/tests/constructs/loop.i b/src/plugins/e-acsl/tests/constructs/loop.i index 4b0b3193ee1d889a17180daf26e085cd7a67cd0c..bbab3b09f21b67d29a1dda970db34f0b93f9f35b 100644 --- a/src/plugins/e-acsl/tests/constructs/loop.i +++ b/src/plugins/e-acsl/tests/constructs/loop.i @@ -1,6 +1,6 @@ /* run.config_ci COMMENT: loop invariants - STDOPT: +"-slevel 160" + STDOPT: +"-eva-slevel 160" */ void simple_loop() { diff --git a/src/plugins/e-acsl/tests/full-mmodel/oracle_ci/gen_addrOf.c b/src/plugins/e-acsl/tests/full-mmodel/oracle_ci/gen_addrOf.c index e7da245320f44ca617784993e0bf842400a92cff..574d904ff3e9f01ffb34f47c1945664f8330ef7b 100644 --- a/src/plugins/e-acsl/tests/full-mmodel/oracle_ci/gen_addrOf.c +++ b/src/plugins/e-acsl/tests/full-mmodel/oracle_ci/gen_addrOf.c @@ -35,24 +35,6 @@ void __e_acsl_globals_init(void) __e_acsl_already_run = 1; __e_acsl_store_block((void *)(& f),(size_t)1); __e_acsl_full_init((void *)(& f)); - __e_acsl_store_block((void *)(& __fc_p_tmpnam),(size_t)8); - __e_acsl_full_init((void *)(& __fc_p_tmpnam)); - __e_acsl_store_block((void *)(__fc_tmpnam),(size_t)2048); - __e_acsl_full_init((void *)(& __fc_tmpnam)); - __e_acsl_store_block((void *)(& __fc_p_fopen),(size_t)8); - __e_acsl_full_init((void *)(& __fc_p_fopen)); - __e_acsl_store_block((void *)(__fc_fopen),(size_t)128); - __e_acsl_full_init((void *)(& __fc_fopen)); - __e_acsl_store_block((void *)(& stdin),(size_t)8); - __e_acsl_full_init((void *)(& stdin)); - __e_acsl_store_block((void *)(& __fc_p_random48_counter),(size_t)8); - __e_acsl_full_init((void *)(& __fc_p_random48_counter)); - __e_acsl_store_block((void *)(random48_counter),(size_t)6); - __e_acsl_full_init((void *)(& random48_counter)); - __e_acsl_store_block((void *)(& __fc_random48_init),(size_t)4); - __e_acsl_full_init((void *)(& __fc_random48_init)); - __e_acsl_store_block((void *)(& __fc_rand_max),(size_t)8); - __e_acsl_full_init((void *)(& __fc_rand_max)); } return; } @@ -60,15 +42,6 @@ void __e_acsl_globals_init(void) void __e_acsl_globals_delete(void) { __e_acsl_delete_block((void *)(& f)); - __e_acsl_delete_block((void *)(& __fc_p_tmpnam)); - __e_acsl_delete_block((void *)(__fc_tmpnam)); - __e_acsl_delete_block((void *)(& __fc_p_fopen)); - __e_acsl_delete_block((void *)(__fc_fopen)); - __e_acsl_delete_block((void *)(& stdin)); - __e_acsl_delete_block((void *)(& __fc_p_random48_counter)); - __e_acsl_delete_block((void *)(random48_counter)); - __e_acsl_delete_block((void *)(& __fc_random48_init)); - __e_acsl_delete_block((void *)(& __fc_rand_max)); } int main(void) diff --git a/src/plugins/e-acsl/tests/memory/local_init.c b/src/plugins/e-acsl/tests/memory/local_init.c index 483a08acdeca626a3024b416c9922f1356da660c..8de0529d5b4ebe3a34852ca95b5cd4d28c4e9816 100644 --- a/src/plugins/e-acsl/tests/memory/local_init.c +++ b/src/plugins/e-acsl/tests/memory/local_init.c @@ -1,7 +1,7 @@ /* run.config_ci COMMENT: test of a local initializer which contains an annotation LOG: gen_@PTEST_NAME@.c - STDOPT: #"@MACHDEP@ @EACSL_PREPARE@ -lib-entry -eva -then -no-lib-entry" + STDOPT: #"@MACHDEP@ -lib-entry -eva -then -no-lib-entry" */ int X = 0; diff --git a/src/plugins/e-acsl/tests/memory/oracle_ci/gen_constructor.c b/src/plugins/e-acsl/tests/memory/oracle_ci/gen_constructor.c index 15a99b43c04dacb8866abecb8ce0ef28e7db4bbf..4e43d7e9cff59e04b077b46a1e9d90fc81d9e076 100644 --- a/src/plugins/e-acsl/tests/memory/oracle_ci/gen_constructor.c +++ b/src/plugins/e-acsl/tests/memory/oracle_ci/gen_constructor.c @@ -1,4 +1,5 @@ /* Generated by Frama-C */ +#include "stddef.h" #include "stdio.h" #include "stdlib.h" char *__gen_e_acsl_literal_string_2; diff --git a/src/plugins/e-acsl/tests/memory/oracle_ci/gen_errno.c b/src/plugins/e-acsl/tests/memory/oracle_ci/gen_errno.c index cc458e4e367b7f4f52387e3d42d727f7ff9f4df6..f38474ba466e667532e9d52c1e92653513013858 100644 --- a/src/plugins/e-acsl/tests/memory/oracle_ci/gen_errno.c +++ b/src/plugins/e-acsl/tests/memory/oracle_ci/gen_errno.c @@ -1,5 +1,6 @@ /* Generated by Frama-C */ #include "errno.h" +#include "stddef.h" #include "stdio.h" #include "stdlib.h" void __e_acsl_globals_init(void) diff --git a/src/plugins/e-acsl/tests/memory/oracle_ci/gen_local_goto.c b/src/plugins/e-acsl/tests/memory/oracle_ci/gen_local_goto.c index 2cf1cc44c0cd0dd389bce183c8fa9c4fdb3ef873..3d26e79512a996e7a619a62f0c495e06bb09a0ee 100644 --- a/src/plugins/e-acsl/tests/memory/oracle_ci/gen_local_goto.c +++ b/src/plugins/e-acsl/tests/memory/oracle_ci/gen_local_goto.c @@ -1,4 +1,5 @@ /* Generated by Frama-C */ +#include "stddef.h" #include "stdio.h" #include "stdlib.h" char *__gen_e_acsl_literal_string_2; diff --git a/src/plugins/e-acsl/tests/memory/oracle_ci/gen_mainargs.c b/src/plugins/e-acsl/tests/memory/oracle_ci/gen_mainargs.c index cd9cd223bf692bfcd3df82812937c41f4ebd306e..86e9de278227b7ff043988d6464c7b6120e761ae 100644 --- a/src/plugins/e-acsl/tests/memory/oracle_ci/gen_mainargs.c +++ b/src/plugins/e-acsl/tests/memory/oracle_ci/gen_mainargs.c @@ -1,4 +1,5 @@ /* Generated by Frama-C */ +#include "stddef.h" #include "stdio.h" #include "stdlib.h" #include "string.h" diff --git a/src/plugins/e-acsl/tests/memory/oracle_ci/gen_memalign.c b/src/plugins/e-acsl/tests/memory/oracle_ci/gen_memalign.c index 7e7362461bb1ec5e09bc5b26370fcda40ddbc4c3..f0a98343e01d91146897001094205c0d8d01a50e 100644 --- a/src/plugins/e-acsl/tests/memory/oracle_ci/gen_memalign.c +++ b/src/plugins/e-acsl/tests/memory/oracle_ci/gen_memalign.c @@ -1,6 +1,46 @@ /* Generated by Frama-C */ #include "stdio.h" #include "stdlib.h" +extern int __e_acsl_sound_verdict; + +/*@ requires valid_memptr: \valid(memptr); + requires + alignment_is_a_suitable_power_of_two: + alignment ≥ sizeof(void *) ∧ + ((size_t)alignment & ((size_t)alignment - 1)) ≡ 0; + assigns __fc_heap_status, \result; + assigns __fc_heap_status + \from (indirect: alignment), size, __fc_heap_status; + assigns \result + \from (indirect: alignment), (indirect: size), + (indirect: __fc_heap_status); + allocates *\old(memptr); + + behavior allocation: + assumes can_allocate: is_allocable(size); + ensures allocation: \fresh{Old, Here}(*\old(memptr),\old(size)); + ensures result_zero: \result ≡ 0; + assigns __fc_heap_status, \result; + assigns __fc_heap_status + \from (indirect: alignment), size, __fc_heap_status; + assigns \result + \from (indirect: alignment), (indirect: size), + (indirect: __fc_heap_status); + + behavior no_allocation: + assumes cannot_allocate: ¬is_allocable(size); + ensures result_non_zero: \result < 0 ∨ \result > 0; + assigns \result; + assigns \result \from (indirect: alignment); + allocates \nothing; + + complete behaviors no_allocation, allocation; + disjoint behaviors no_allocation, allocation; + */ +int __gen_e_acsl_posix_memalign(void **memptr, size_t alignment, size_t size); + +void *aligned_alloc(size_t alignment, size_t size); + int main(int argc, char const **argv) { int __retres; @@ -11,7 +51,8 @@ int main(int argc, char const **argv) __e_acsl_store_block((void *)(& memptr),(size_t)8); __e_acsl_full_init((void *)(& memptr)); int res2 = - posix_memalign((void **)memptr,(unsigned long)256,(unsigned long)15); + __gen_e_acsl_posix_memalign((void **)memptr,(unsigned long)256, + (unsigned long)15); /*@ assert Eva: initialization: \initialized(memptr); */ char *p = *memptr; __e_acsl_store_block((void *)(& p),(size_t)8); @@ -138,4 +179,82 @@ int main(int argc, char const **argv) return __retres; } +/*@ requires valid_memptr: \valid(memptr); + requires + alignment_is_a_suitable_power_of_two: + alignment ≥ sizeof(void *) ∧ + ((size_t)alignment & ((size_t)alignment - 1)) ≡ 0; + assigns __fc_heap_status, \result; + assigns __fc_heap_status + \from (indirect: alignment), size, __fc_heap_status; + assigns \result + \from (indirect: alignment), (indirect: size), + (indirect: __fc_heap_status); + allocates *\old(memptr); + + behavior allocation: + assumes can_allocate: is_allocable(size); + ensures allocation: \fresh{Old, Here}(*\old(memptr),\old(size)); + ensures result_zero: \result ≡ 0; + assigns __fc_heap_status, \result; + assigns __fc_heap_status + \from (indirect: alignment), size, __fc_heap_status; + assigns \result + \from (indirect: alignment), (indirect: size), + (indirect: __fc_heap_status); + + behavior no_allocation: + assumes cannot_allocate: ¬is_allocable(size); + ensures result_non_zero: \result < 0 ∨ \result > 0; + assigns \result; + assigns \result \from (indirect: alignment); + allocates \nothing; + + complete behaviors no_allocation, allocation; + disjoint behaviors no_allocation, allocation; + */ +int __gen_e_acsl_posix_memalign(void **memptr, size_t alignment, size_t size) +{ + int __retres; + { + int __gen_e_acsl_valid; + int __gen_e_acsl_and; + __e_acsl_store_block((void *)(& memptr),(size_t)8); + __gen_e_acsl_valid = __e_acsl_valid((void *)memptr,sizeof(void *), + (void *)memptr,(void *)(& memptr)); + __e_acsl_assert(__gen_e_acsl_valid,"Precondition","posix_memalign", + "\\valid(memptr)","FRAMAC_SHARE/libc/stdlib.h",666); + if (alignment >= 8UL) { + __e_acsl_mpz_t __gen_e_acsl_; + __e_acsl_mpz_t __gen_e_acsl__2; + __e_acsl_mpz_t __gen_e_acsl_sub; + __e_acsl_mpz_t __gen_e_acsl_band; + unsigned long __gen_e_acsl__3; + __gmpz_init_set_ui(__gen_e_acsl_,alignment); + __gmpz_init_set_si(__gen_e_acsl__2,1L); + __gmpz_init(__gen_e_acsl_sub); + __gmpz_sub(__gen_e_acsl_sub, + (__e_acsl_mpz_struct const *)(__gen_e_acsl_), + (__e_acsl_mpz_struct const *)(__gen_e_acsl__2)); + __gmpz_init(__gen_e_acsl_band); + __gmpz_and(__gen_e_acsl_band, + (__e_acsl_mpz_struct const *)(__gen_e_acsl_), + (__e_acsl_mpz_struct const *)(__gen_e_acsl_sub)); + __gen_e_acsl__3 = __gmpz_get_ui((__e_acsl_mpz_struct const *)(__gen_e_acsl_band)); + __gen_e_acsl_and = __gen_e_acsl__3 == 0UL; + __gmpz_clear(__gen_e_acsl_); + __gmpz_clear(__gen_e_acsl__2); + __gmpz_clear(__gen_e_acsl_sub); + __gmpz_clear(__gen_e_acsl_band); + } + else __gen_e_acsl_and = 0; + __e_acsl_assert(__gen_e_acsl_and,"Precondition","posix_memalign", + "alignment >= sizeof(void *) &&\n((size_t)alignment & ((size_t)alignment - 1)) == 0", + "FRAMAC_SHARE/libc/stdlib.h",668); + } + __retres = posix_memalign(memptr,alignment,size); + __e_acsl_delete_block((void *)(& memptr)); + return __retres; +} + diff --git a/src/plugins/e-acsl/tests/memory/oracle_ci/gen_memsize.c b/src/plugins/e-acsl/tests/memory/oracle_ci/gen_memsize.c index 60fc5642381eca2bf0accc0e9093530f27e8f3c0..afc1d47904c708484482355ef4be0aaf6fcd4c2b 100644 --- a/src/plugins/e-acsl/tests/memory/oracle_ci/gen_memsize.c +++ b/src/plugins/e-acsl/tests/memory/oracle_ci/gen_memsize.c @@ -1,6 +1,8 @@ /* Generated by Frama-C */ #include "stdio.h" #include "stdlib.h" +extern size_t __e_acsl_heap_allocation_size; + int main(int argc, char **argv) { int __retres; diff --git a/src/plugins/e-acsl/tests/memory/oracle_ci/gen_stdout.c b/src/plugins/e-acsl/tests/memory/oracle_ci/gen_stdout.c index 49ec6cf163ec5ba0edfad147a4fa237e95bb0678..75bddabfbe9edd97d7bff4bac71129cf540e7428 100644 --- a/src/plugins/e-acsl/tests/memory/oracle_ci/gen_stdout.c +++ b/src/plugins/e-acsl/tests/memory/oracle_ci/gen_stdout.c @@ -1,4 +1,5 @@ /* Generated by Frama-C */ +#include "stddef.h" #include "stdio.h" #include "stdlib.h" void __e_acsl_globals_init(void) diff --git a/src/plugins/e-acsl/tests/memory/oracle_ci/memalign.res.oracle b/src/plugins/e-acsl/tests/memory/oracle_ci/memalign.res.oracle index 674eddac861dff410a723d4a8016853a5ce17ca5..bcfe10a812c72940b682369df2ac5f11caaaecba 100644 --- a/src/plugins/e-acsl/tests/memory/oracle_ci/memalign.res.oracle +++ b/src/plugins/e-acsl/tests/memory/oracle_ci/memalign.res.oracle @@ -1,4 +1,33 @@ [e-acsl] beginning translation. +[e-acsl] Warning: annotating undefined function `posix_memalign': + the generated program may miss memory instrumentation + if there are memory-related annotations. +[e-acsl] FRAMAC_SHARE/libc/stdlib.h:665: Warning: + E-ACSL construct `\fresh' is not yet supported. Ignoring annotation. +[e-acsl] tests/memory/memalign.c:38: Warning: + E-ACSL construct `complete behaviors' is not yet supported. + Ignoring annotation. +[e-acsl] tests/memory/memalign.c:38: Warning: + E-ACSL construct `disjoint behaviors' is not yet supported. + Ignoring annotation. +[e-acsl] FRAMAC_SHARE/libc/stdlib.h:669: Warning: + E-ACSL construct `assigns clause in behavior' is not yet supported. + Ignoring annotation. +[e-acsl] FRAMAC_SHARE/libc/stdlib.h:675: Warning: + E-ACSL construct `predicate performing read accesses' is not yet supported. + Ignoring annotation. +[e-acsl] FRAMAC_SHARE/libc/stdlib.h:675: Warning: + E-ACSL construct `assigns clause in behavior' is not yet supported. + Ignoring annotation. +[e-acsl] FRAMAC_SHARE/libc/stdlib.h:682: Warning: + E-ACSL construct `predicate performing read accesses' is not yet supported. + Ignoring annotation. [e-acsl] translation done in project "e-acsl". +[eva:alarm] FRAMAC_SHARE/libc/stdlib.h:668: Warning: + function __e_acsl_assert: precondition got status unknown. +[eva] FRAMAC_SHARE/libc/stdlib.h:665: Warning: + ignoring unsupported \allocates clause +[eva:alarm] FRAMAC_SHARE/libc/stdlib.h:679: Warning: + function __gen_e_acsl_posix_memalign, behavior allocation: postcondition 'allocation' got status unknown. [eva:alarm] tests/memory/memalign.c:14: Warning: accessing uninitialized left-value. assert \initialized(memptr); diff --git a/src/plugins/e-acsl/tests/special/e-acsl-valid.c b/src/plugins/e-acsl/tests/special/e-acsl-valid.c index 8cdb54fbcec93c33303e8fdebfa537406b57fb98..f84464d00758640dd8187876d1d0cd3bcefbcf50 100644 --- a/src/plugins/e-acsl/tests/special/e-acsl-valid.c +++ b/src/plugins/e-acsl/tests/special/e-acsl-valid.c @@ -1,6 +1,6 @@ /* run.config_ci, run.config_dev COMMENT: test option -e-acsl-no-valid - STDOPT: #"@MACHDEP@ @EACSL_PREPARE@ -eva -eva-verbose 0 -then -no-eva -e-acsl-no-valid" + STDOPT: #"@GLOBAL@ -eva -eva-verbose 0 -then -no-eva -e-acsl-no-valid" MACRO: ROOT_EACSL_GCC_FC_EXTRA_EXT -eva -eva-verbose 0 MACRO: ROOT_EACSL_GCC_OPTS_EXT --then --e-acsl-extra -e-acsl-no-valid */ diff --git a/src/plugins/e-acsl/tests/temporal/oracle_ci/gen_t_args.c b/src/plugins/e-acsl/tests/temporal/oracle_ci/gen_t_args.c index 666d954b82bcc4f6965b8b8b575a7f5f11c3a01e..3e24ef3f308c7f68f1fb6accf0ea4b6e604afe72 100644 --- a/src/plugins/e-acsl/tests/temporal/oracle_ci/gen_t_args.c +++ b/src/plugins/e-acsl/tests/temporal/oracle_ci/gen_t_args.c @@ -1,4 +1,5 @@ /* Generated by Frama-C */ +#include "stddef.h" #include "stdio.h" #include "stdlib.h" int main(int argc, char const **argv) diff --git a/src/plugins/e-acsl/tests/temporal/oracle_ci/gen_t_local_init.c b/src/plugins/e-acsl/tests/temporal/oracle_ci/gen_t_local_init.c index 9ccb27aa258ca9cd5f58e030f4523d3535aec27f..007456238249612053c6ccc263073ada9d9840ba 100644 --- a/src/plugins/e-acsl/tests/temporal/oracle_ci/gen_t_local_init.c +++ b/src/plugins/e-acsl/tests/temporal/oracle_ci/gen_t_local_init.c @@ -1,4 +1,5 @@ /* Generated by Frama-C */ +#include "stddef.h" #include "stdio.h" #include "stdlib.h" char *__gen_e_acsl_literal_string_4; diff --git a/src/plugins/e-acsl/tests/temporal/oracle_ci/gen_t_memcpy.c b/src/plugins/e-acsl/tests/temporal/oracle_ci/gen_t_memcpy.c index 0f86c7371d4c879dc64808a673a75ca10dbe1a7a..3b0511fa9b1b81d990817fb3c5eb74072f572a8d 100644 --- a/src/plugins/e-acsl/tests/temporal/oracle_ci/gen_t_memcpy.c +++ b/src/plugins/e-acsl/tests/temporal/oracle_ci/gen_t_memcpy.c @@ -1,4 +1,5 @@ /* Generated by Frama-C */ +#include "stddef.h" #include "stdio.h" #include "stdlib.h" #include "string.h" diff --git a/src/plugins/e-acsl/tests/test_config_ci.in b/src/plugins/e-acsl/tests/test_config_ci.in index 0a68607fc713abce8bf5ac09479dd477ff07e1dd..2c9748e535a049455c62e15f0f0ed3469bc5df95 100644 --- a/src/plugins/e-acsl/tests/test_config_ci.in +++ b/src/plugins/e-acsl/tests/test_config_ci.in @@ -1,7 +1,6 @@ MACRO: DEST @PTEST_RESULT@/gen_@PTEST_NAME@ MACRO: MACHDEP -machdep gcc_x86_64 -MACRO: EACSL_PREPARE -e-acsl-prepare -e-acsl-share ./share/e-acsl -MACRO: GLOBAL @MACHDEP@ -variadic-no-translation -verbose 0 +MACRO: GLOBAL @MACHDEP@ -remove-unused-specified-functions -variadic-no-translation -verbose 0 MACRO: EACSL -e-acsl -e-acsl-share ./share/e-acsl -e-acsl-verbose 1 MACRO: EVA -eva -eva-no-alloc-returns-null -eva-no-results -eva-no-print -eva-warn-key libc:unsupported-spec=inactive MACRO: EVENTUALLY -print -ocode @DEST@.c -load-script ./tests/print.cmxs diff --git a/src/plugins/inout/inout_parameters.ml b/src/plugins/inout/inout_parameters.ml index d40e57102efed31295867246403399efe4718591..eef83915883414ce93655863cb71e4030f8c9086 100644 --- a/src/plugins/inout/inout_parameters.ml +++ b/src/plugins/inout/inout_parameters.ml @@ -77,21 +77,6 @@ module ForceInout = let help = "Compute operational inputs, an over-approximation of the set of locations whose initial value is used; and the sure outputs, an under-approximation of the set of the certainly written locations" end) -(* Remove in Frama-C Chlorine *) -let () = Parameter_customize.is_invisible () -module ForceCallwiseInout = - True - (struct - let option_name = "-inout-callwise" - let help = "Compute callsite-wide operational inputs; this results in more precise results for -inout and -out options" - end) -let () = - ForceCallwiseInout.add_update_hook - (fun _ new_ -> - if not new_ then - Kernel.abort "@[option -inout-callwise can no longer be unset.@]") - - module ForceInoutExternalWithFormals = False (struct diff --git a/src/plugins/inout/inout_parameters.mli b/src/plugins/inout/inout_parameters.mli index 3f5390706a6d4f95a9ff23e157d11e5ea6d36998..d59478b1bb4b6d5abc66fda2febf90f8cc2f0aa6 100644 --- a/src/plugins/inout/inout_parameters.mli +++ b/src/plugins/inout/inout_parameters.mli @@ -28,7 +28,6 @@ module ForceExternalOut: Parameter_sig.Bool module ForceInput: Parameter_sig.Bool module ForceInputWithFormals: Parameter_sig.Bool module ForceInout: Parameter_sig.Bool -module ForceCallwiseInout: Parameter_sig.Bool module ForceInoutExternalWithFormals: Parameter_sig.Bool module ForceDeref: Parameter_sig.Bool diff --git a/src/plugins/inout/operational_inputs.ml b/src/plugins/inout/operational_inputs.ml index 777c7ce0892b7a680201d7920f83d8fca3b58014..f1c1fe4aa452b3b1a1754a8f07e2041f695d55e9 100644 --- a/src/plugins/inout/operational_inputs.ml +++ b/src/plugins/inout/operational_inputs.ml @@ -215,16 +215,14 @@ module Internals = module CallsiteHash = Value_types.Callsite.Hashtbl (* Results of an an entire call, represented by a pair (stmt, kernel_function). - This table is filled by the [-inout-callwise] option, or for functions for - which only the specification is used. *) +*) module CallwiseResults = State_builder.Hashtbl (Value_types.Callsite.Hashtbl) (Inout_type) (struct let size = 17 - let dependencies = [Internals.self; - Inout_parameters.ForceCallwiseInout.self] + let dependencies = [Internals.self] let name = "Inout.Operational_inputs.CallwiseResults" end) @@ -565,10 +563,6 @@ let extract_inout_from_froms froms = module Callwise = struct - let compute_callwise () = - Inout_parameters.ForceCallwiseInout.get () || - Dynamic.Parameter.Bool.get "-memexec-all" () - let merge_call_in_local_table call local_table v = let prev = try CallsiteHash.find local_table call @@ -600,41 +594,39 @@ module Callwise = struct let call_inout_stack = ref [] let call_for_callwise_inout (call_type, state, call_stack) = - if compute_callwise () then begin - let (current_function, ki as call_site) = List.hd call_stack in - let merge_inout inout = - if ki = Kglobal - then merge_call_in_global_tables call_site inout - else - let _above_function, table = - try List.hd !call_inout_stack - with Failure _ -> assert false - in - merge_call_in_local_table call_site table inout - in - match call_type with - | `Builtin {Value_types.c_from = Some (froms,sure_out) } -> - let in_, out_ = extract_inout_from_froms froms in - let inout = { - over_inputs_if_termination = in_; - over_inputs = in_; - over_logic_inputs = Zone.bottom; - over_outputs_if_termination = out_ ; - over_outputs = out_; - under_outputs_if_termination = sure_out; - } in - merge_inout inout - | `Def | `Memexec -> - let table_current_function = CallsiteHash.create 7 in - call_inout_stack := - (current_function, table_current_function) :: !call_inout_stack - | `Spec spec -> - let inout =compute_using_given_spec_state state spec current_function in - merge_inout inout - | `Builtin { Value_types.c_from = None } -> - let inout = compute_using_prototype_state state current_function in - merge_inout inout - end;; + let (current_function, ki as call_site) = List.hd call_stack in + let merge_inout inout = + if ki = Kglobal + then merge_call_in_global_tables call_site inout + else + let _above_function, table = + try List.hd !call_inout_stack + with Failure _ -> assert false + in + merge_call_in_local_table call_site table inout + in + match call_type with + | `Builtin {Value_types.c_from = Some (froms,sure_out) } -> + let in_, out_ = extract_inout_from_froms froms in + let inout = { + over_inputs_if_termination = in_; + over_inputs = in_; + over_logic_inputs = Zone.bottom; + over_outputs_if_termination = out_ ; + over_outputs = out_; + under_outputs_if_termination = sure_out; + } in + merge_inout inout + | `Def | `Memexec -> + let table_current_function = CallsiteHash.create 7 in + call_inout_stack := + (current_function, table_current_function) :: !call_inout_stack + | `Spec spec -> + let inout =compute_using_given_spec_state state spec current_function in + merge_inout inout + | `Builtin { Value_types.c_from = None } -> + let inout = compute_using_prototype_state state current_function in + merge_inout inout module MemExec = @@ -711,31 +703,30 @@ module Callwise = struct Computer.end_dataflow () let record_for_callwise_inout ((call_stack: Db.Value.callstack), value_res) = - if compute_callwise () then - let inout = match value_res with - | Value_types.Normal (states, _after_states) - | Value_types.NormalStore ((states, _after_states), _) -> - let kf, _ = List.hd call_stack in - let inout = - try - if !Db.Value.no_results (Kernel_function.get_definition kf) then - top - else - compute_call_from_value_states kf call_stack (Lazy.force states) - with Kernel_function.No_Definition -> top - in - (match value_res with - | Value_types.NormalStore (_, memexec_counter) -> - MemExec.replace memexec_counter inout - | _ -> ()); - inout - - | Value_types.Reuse counter -> - MemExec.find counter - in - Db.Operational_inputs.Record_Inout_Callbacks.apply - (call_stack, inout); - end_record call_stack inout + let inout = match value_res with + | Value_types.Normal (states, _after_states) + | Value_types.NormalStore ((states, _after_states), _) -> + let kf, _ = List.hd call_stack in + let inout = + try + if !Db.Value.no_results (Kernel_function.get_definition kf) then + top + else + compute_call_from_value_states kf call_stack (Lazy.force states) + with Kernel_function.No_Definition -> top + in + (match value_res with + | Value_types.NormalStore (_, memexec_counter) -> + MemExec.replace memexec_counter inout + | _ -> ()); + inout + + | Value_types.Reuse counter -> + MemExec.find counter + in + Db.Operational_inputs.Record_Inout_Callbacks.apply + (call_stack, inout); + end_record call_stack inout (* Register our callbacks inside the value analysis *) @@ -816,8 +807,8 @@ let get_internal = Internals.memo (fun kf -> !Db.Value.compute (); - try Internals.find kf (* If [-inout-callwise] is set, the results may - have been computed by the call to Value.compute *) + try Internals.find kf (* The results may have been computed by the call + to Value.compute *) with | Not_found -> if!Db.Value.use_spec_instead_of_definition kf then diff --git a/src/plugins/loop_analysis/tests/loop_analysis/with_value.i b/src/plugins/loop_analysis/tests/loop_analysis/with_value.i index b147374aa576d736dc929426f708f2517ac1377e..b030fa5e58dbcbe8a8d388fcc49097265f53ec38 100644 --- a/src/plugins/loop_analysis/tests/loop_analysis/with_value.i +++ b/src/plugins/loop_analysis/tests/loop_analysis/with_value.i @@ -1,5 +1,5 @@ /*run.config -OPT: -no-autoload-plugins -load-module from,inout,loopanalysis,eva,scope -val -val-show-progress -then -loop +OPT: -no-autoload-plugins -load-module from,inout,loopanalysis,eva,scope -eva -eva-show-progress -then -loop */ void f1(int n) { diff --git a/src/plugins/markdown-report/mdr_params.ml b/src/plugins/markdown-report/mdr_params.ml index aa1f44492edcbf6bf96b42274c482d762f36f279..ce052fa96fddda7cf1c709be133ad75ca4847083 100644 --- a/src/plugins/markdown-report/mdr_params.ml +++ b/src/plugins/markdown-report/mdr_params.ml @@ -20,6 +20,8 @@ (* *) (**************************************************************************) +module Pervasives_string = String + include Plugin.Register( struct let name = "Markdown report" @@ -27,14 +29,6 @@ include Plugin.Register( let help = "generates a report in markdown format" end) -module Output = String( - struct - let option_name = "-mdr-out" - let arg_name = "f" - let default = "report.md" - let help = "sets the name of the output file to <f>" - end) - module Generate = String( struct let option_name = "-mdr-gen" @@ -45,6 +39,26 @@ module Generate = String( none (default), md, draft and sarif" end) +module Output : Parameter_sig.String = +struct + include String( + struct + let option_name = "-mdr-out" + let arg_name = "f" + let default = "report" + let help = "sets the name of the output file to <f>. \ + If <f> has no extension, it is chosen automatically based on \ + the report kind" + end) + let get () = + let s = get () in + if Pervasives_string.contains (Filename.basename s) '.' then s + else + let kind = Generate.get () in + let ext = if kind = "sarif" then ".sarif" else ".md" in + s ^ ext +end + let () = Generate.set_possible_values [ "none"; "md"; "draft"; "sarif" ] diff --git a/src/plugins/markdown-report/sarif.ml b/src/plugins/markdown-report/sarif.ml index 00977f9a56c77251ec178b290ee62451f9c83358..e50d9262a43d86b80a48ebdccb28b14f4bc8a12c 100644 --- a/src/plugins/markdown-report/sarif.ml +++ b/src/plugins/markdown-report/sarif.ml @@ -20,7 +20,7 @@ (* *) (**************************************************************************) -(** OCaml representation for the sarif 2.0 schema. *) +(** OCaml representation for the sarif 2.1 schema. *) (** ppx_deriving_yojson generates parser and printer that are recursive by default: we must thus silence spurious let rec warning (39). *) @@ -32,6 +32,15 @@ module type Json_type = sig val to_yojson: t -> Yojson.Safe.t end +module Json_string: Json_type with type t = string = +struct + type t = string + let of_yojson = function + | `String s -> Ok s + | _ -> Error "string" + let to_yojson s = `String s +end + module Json_dictionary(J: Json_type): Json_type with type t = (string * J.t) list = struct @@ -55,6 +64,8 @@ struct `Assoc json_l end +module JsonStringDictionary = Json_dictionary(Json_string) + module Uri: sig include Json_type with type t = private string val sarif_github:t @@ -63,74 +74,141 @@ end struct type t = string[@@deriving yojson] let sarif_github = - "https://github.com/oasis-tcs/sarif-spec/blob/master/Documents/CommitteeSpecificationDrafts/v2.0-CSD.1/sarif-schema.json" + "https://github.com/oasis-tcs/sarif-spec/blob/master/Documents/CommitteeSpecificationDrafts/v2.1.0-CSD.1/sarif-schema-2.1.0.json" end module Version: sig include Json_type with type t = private string - val v2_0_0: t + val v2_1_0: t end = struct type t = string[@@deriving yojson] - let v2_0_0 = "2.0.0" + let v2_1_0 = "2.1.0" +end + +module ArtifactLocation = struct + type t = { + uri: string; + uriBaseId: (string [@default ""]) + }[@@deriving yojson] + + let create ~uri ?(uriBaseId = "") () = { uri; uriBaseId } + + let default = create ~uri:"" () + + let of_loc loc = + let open Filepath in + (* by construction, we have an absolute path here, no need for uriBase *) + let uri = ((fst loc).pos_path :> string) in + create ~uri () +end + +module ArtifactLocationDictionary = Json_dictionary(ArtifactLocation) + +module Custom_properties = + Json_dictionary(struct + type t = Yojson.Safe.t + let of_yojson x = Ok x + let to_yojson x = x + end) + +module Properties = struct + type tags = string list [@@deriving yojson] + + type t = { + tags: tags; + additional_properties: Custom_properties.t + } + + let default = { tags = []; additional_properties = [] } + + let create additional_properties = + let tags = List.map fst additional_properties in + { tags; additional_properties } + + let of_yojson = function + | `Null -> Ok default + | `Assoc l -> + (match List.assoc_opt "tags" l with + | None -> Error "properties" + | Some json -> + (match tags_of_yojson json with + | Ok tags -> + let additional_properties = List.remove_assoc "tags" l in + Ok { tags; additional_properties } + | Error loc -> Error ("properties." ^ loc))) + | _ -> Error "properties" + + let to_yojson { tags; additional_properties } = + match tags with + | [] -> `Null + | _ -> `Assoc (("tags", tags_to_yojson tags)::additional_properties) end module Message = struct type t = { text: (string [@default ""]); - messageId: (string [@default ""]); - richText: (string [@default ""]); - richMessageId: (string [@default ""]); + id: (string [@default ""]); + markdown: (string [@default ""]); arguments: (string list [@default []]); + properties: (Properties.t [@default Properties.default]); }[@@deriving yojson] let create ?(text="") - ?(messageId="") - ?(richText="") - ?(richMessageId="") + ?(id="") + ?(markdown="") ?(arguments=[]) + ?(properties=Properties.default) () = - { text; messageId; richText; richMessageId; arguments } + { text; id; markdown; arguments; properties } - let plain_text ~text ?id:messageId ?arguments () = - create ~text ?messageId ?arguments () + let plain_text ~text ?id ?arguments () = + create ~text ?id ?arguments () - let markdown ~markdown ?id:richMessageId ?arguments () = + let markdown ~markdown ?id ?arguments () = let pp fmt = Markdown.pp_elements fmt in - let richText = String.trim (Format.asprintf "@[%a@]" pp markdown) + let markdown = String.trim (Format.asprintf "@[%a@]" pp markdown) in - create ~richText ?richMessageId ?arguments () + create ~markdown ?id ?arguments () let default = create () end -module FileLocation = struct +module MultiformatMessageString = struct type t = { - uri: string; - uriBaseId: (string [@default ""]) + text: string; + markdown: (string [@default ""]); + properties: (Properties.t [@default Properties.default]) }[@@deriving yojson] - let create ~uri ?(uriBaseId = "") () = { uri; uriBaseId } + let create ~text ?(markdown="") ?(properties=Properties.default) () = + { text; markdown; properties } - let default = create ~uri:"" () - - let of_loc loc = - let open Filepath in - (* by construction, we have an absolute path here, no need for uriBase *) - let uri = ((fst loc).pos_path :> string) in - create ~uri () + let default = create ~text:"default" () end -module FileContent = struct +module MultiformatMessageStringDictionary = + Json_dictionary(MultiformatMessageString) + +module ArtifactContent = struct type t = - | Text of string [@name "text"] - | Binary of string [@name "binary"] + { text: (string [@default ""]); + binary: (string [@default ""]); + rendered: + (MultiformatMessageString.t [@default MultiformatMessageString.default]); + properties: (Properties.t [@default Properties.default]) + } [@@deriving yojson] - let default = Text "" + let create ?(text="") ?(binary="") + ?(rendered=MultiformatMessageString.default) + ?(properties=Properties.default) () = + { text; binary; rendered; properties } + + let default = create () end module Region = struct @@ -143,7 +221,7 @@ module Region = struct charLength: (int [@default 0]); byteOffset: (int [@default 0]); byteLength: (int [@default 0]); - snippet: (FileContent.t [@default FileContent.default]); + snippet: (ArtifactContent.t [@default ArtifactContent.default]); message: (Message.t [@default Message.default]) }[@@deriving yojson] @@ -156,7 +234,7 @@ module Region = struct ?(charLength = 0) ?(byteOffset = 0) ?(byteLength = 0) - ?(snippet = FileContent.default) + ?(snippet = ArtifactContent.default) ?(message = Message.default) () = @@ -187,69 +265,29 @@ module Rectangle = struct [@@deriving yojson] end -module Custom_properties = - Json_dictionary(struct - type t = Yojson.Safe.t - let of_yojson x = Ok x - let to_yojson x = x - end) - -module Properties = struct - type tags = string list [@@deriving yojson] - - type t = { - tags: tags; - additional_properties: Custom_properties.t - } - - let default = { tags = []; additional_properties = [] } - - let create additional_properties = - let tags = List.map fst additional_properties in - { tags; additional_properties } - - let of_yojson = function - | `Null -> Ok default - | `Assoc l -> - (match List.assoc_opt "tags" l with - | None -> Error "properties" - | Some json -> - (match tags_of_yojson json with - | Ok tags -> - let additional_properties = List.remove_assoc "tags" l in - Ok { tags; additional_properties } - | Error loc -> Error ("properties." ^ loc))) - | _ -> Error "properties" - - let to_yojson { tags; additional_properties } = - match tags with - | [] -> `Null - | _ -> `Assoc (("tags", tags_to_yojson tags)::additional_properties) -end - module PhysicalLocation = struct type t = { id: (string [@default ""]); - fileLocation: FileLocation.t; + artifactLocation: ArtifactLocation.t; region: (Region.t [@default Region.default]); contextRegion: (Region.t [@default Region.default]); }[@@deriving yojson] let create ?(id = "") - ~fileLocation + ~artifactLocation ?(region = Region.default) ?(contextRegion = Region.default) () = - { id; fileLocation; region; contextRegion } + { id; artifactLocation; region; contextRegion } - let default = create ~fileLocation:FileLocation.default () + let default = create ~artifactLocation:ArtifactLocation.default () let of_loc loc = - let fileLocation = FileLocation.of_loc loc in + let artifactLocation = ArtifactLocation.of_loc loc in let region = Region.of_loc loc in - create ~fileLocation ~region () + create ~artifactLocation ~region () end @@ -356,7 +394,7 @@ end module Attachment = struct type t = { description: (Message.t [@default Message.default ]); - fileLocation: FileLocation.t; + artifactLocation: ArtifactLocation.t; regions: (Region.t list [@default []]); rectangles: (Rectangle.t list [@default []]) } [@@deriving yojson] @@ -416,7 +454,7 @@ module Notification = struct }[@@deriving yojson] end -module Tool = struct +module Driver = struct type t = { name: string; fullName: (string [@default ""]); @@ -445,7 +483,16 @@ module Tool = struct downloadUri; sarifLoggerVersion; language; properties } let default = create ~name:"" () +end + +module Tool = struct + type t = { + driver: Driver.t + }[@@deriving yojson] + let create driver = { driver; } + + let default = create Driver.default end module Invocation = struct @@ -453,7 +500,7 @@ module Invocation = struct type t = { commandLine: string; arguments: string list; - responseFiles: (FileLocation.t list [@default []]); + responseFiles: (ArtifactLocation.t list [@default []]); attachments: (Attachment.t list [@default []]); startTime: (string [@default ""]); endTime: (string [@default ""]); @@ -464,18 +511,18 @@ module Invocation = struct exitSignalName: (string [@default ""]); exitSignalNumber: (int [@default 0]); processStartFailureMessage: (string [@default ""]); - toolExecutionSuccessful: bool; + executionSuccessful: bool; machine: (string [@default ""]); account: (string [@default ""]); processId: (int [@default 0]); - executableLocation: (FileLocation.t [@default FileLocation.default]); - workingDirectory: (FileLocation.t [@default FileLocation.default]); + executableLocation: (ArtifactLocation.t [@default ArtifactLocation.default]); + workingDirectory: (ArtifactLocation.t [@default ArtifactLocation.default]); environmentVariables: (Additional_properties.t [@default Additional_properties.default]); - stdin: (FileLocation.t [@default FileLocation.default]); - stdout: (FileLocation.t [@default FileLocation.default]); - stderr: (FileLocation.t [@default FileLocation.default]); - stdoutStderr: (FileLocation.t [@default FileLocation.default]); + stdin: (ArtifactLocation.t [@default ArtifactLocation.default]); + stdout: (ArtifactLocation.t [@default ArtifactLocation.default]); + stderr: (ArtifactLocation.t [@default ArtifactLocation.default]); + stdoutStderr: (ArtifactLocation.t [@default ArtifactLocation.default]); properties: (Properties.t [@default Properties.default]); }[@@deriving yojson] @@ -493,17 +540,17 @@ module Invocation = struct ?(exitSignalName = "") ?(exitSignalNumber = 0) ?(processStartFailureMessage = "") - ?(toolExecutionSuccessful = true) + ?(executionSuccessful = true) ?(machine = "") ?(account = "") ?(processId = 0) - ?(executableLocation = FileLocation.default) - ?(workingDirectory = FileLocation.default) + ?(executableLocation = ArtifactLocation.default) + ?(workingDirectory = ArtifactLocation.default) ?(environmentVariables = Additional_properties.default) - ?(stdin = FileLocation.default) - ?(stdout = FileLocation.default) - ?(stderr = FileLocation.default) - ?(stdoutStderr = FileLocation.default) + ?(stdin = ArtifactLocation.default) + ?(stdout = ArtifactLocation.default) + ?(stderr = ArtifactLocation.default) + ?(stdoutStderr = ArtifactLocation.default) ?(properties = Properties.default) () = @@ -521,7 +568,7 @@ module Invocation = struct exitSignalName; exitSignalNumber; processStartFailureMessage; - toolExecutionSuccessful; + executionSuccessful; machine; account; processId; @@ -543,13 +590,13 @@ module Conversion = struct type t = { tool: Tool.t; invocation: (Invocation.t [@default Invocation.default]); - analysisToolLogFiles: (FileLocation.t [@default FileLocation.default]); + analysisToolLogFiles: (ArtifactLocation.t [@default ArtifactLocation.default]); } [@@deriving yojson] let default = { - tool = Tool.default; + tool = {driver = Driver.default}; invocation = Invocation.default; - analysisToolLogFiles = FileLocation.default; + analysisToolLogFiles = ArtifactLocation.default; } end @@ -650,48 +697,53 @@ end module Replacement = struct type t = { deletedRegion: Region.t; - insertedContent: (FileContent.t [@default FileContent.default]) + insertedContent: (ArtifactContent.t [@default ArtifactContent.default]) }[@@deriving yojson] end -module File = struct +module Artifact = struct type t = { - fileLocation: (FileLocation.t [@default FileLocation.default]); - parentKey: (string [@default ""]); + description: (Message.t [@default Message.default]); + location: (ArtifactLocation.t [@default ArtifactLocation.default]); + parentIndex: (int [@default -1]); offset: (int [@default 0]); - length: (int [@default 0]); + length: (int [@default -1]); roles: (Role.t list [@default []]); mimeType: (string [@default ""]); - contents: (FileContent.t [@default FileContent.default]); + contents: (ArtifactContent.t [@default ArtifactContent.default]); encoding: (string [@default ""]); - hashes: (Hash.t list [@default []]); - lastModifiedTime: (string [@default ""]); + sourceLanguage: (string [@default ""]); + hashes: (JsonStringDictionary.t [@default []]); + lastModifiedTimeUtc: (string [@default ""]); properties: (Properties.t [@default Properties.default]); }[@@deriving yojson] let create - ?(fileLocation = FileLocation.default) - ?(parentKey = "") + ?(description = Message.default) + ?(location = ArtifactLocation.default) + ?(parentIndex = -1) ?(offset = 0) - ?(length = 0) + ?(length = -1) ?(roles = []) ?(mimeType = "") - ?(contents = FileContent.default) + ?(contents = ArtifactContent.default) ?(encoding = "") + ?(sourceLanguage = "") ?(hashes = []) - ?(lastModifiedTime = "") + ?(lastModifiedTimeUtc = "") ?(properties = Properties.default) () = { - fileLocation; parentKey; offset; length; roles; mimeType; contents; - encoding; hashes; lastModifiedTime; properties + description; location; parentIndex; offset; length; roles; mimeType; + contents; encoding; sourceLanguage; hashes; lastModifiedTimeUtc; + properties } end module FileChange = struct type t = { - fileLocation: FileLocation.t; + artifactLocation: ArtifactLocation.t; replacements: Replacement.t list }[@@deriving yojson] end @@ -705,13 +757,13 @@ end module ExternalFiles = struct type t = { - conversion: (FileLocation.t [@default FileLocation.default]); - files: (FileLocation.t [@default FileLocation.default]); - graphs: (FileLocation.t [@default FileLocation.default]); - invocations: (FileLocation.t list [@default []]); - logicalLocations: (FileLocation.t [@default FileLocation.default]); - resources: (FileLocation.t [@default FileLocation.default]); - results: (FileLocation.t [@default FileLocation.default]); + conversion: (ArtifactLocation.t [@default ArtifactLocation.default]); + files: (ArtifactLocation.t [@default ArtifactLocation.default]); + graphs: (ArtifactLocation.t [@default ArtifactLocation.default]); + invocations: (ArtifactLocation.t list [@default []]); + logicalLocations: (ArtifactLocation.t [@default ArtifactLocation.default]); + resources: (ArtifactLocation.t [@default ArtifactLocation.default]); + results: (ArtifactLocation.t [@default ArtifactLocation.default]); }[@@deriving yojson] end @@ -728,104 +780,169 @@ end module RuleConfigLevel: sig include Json_type with type t = private string + val cl_none: t val cl_note: t val cl_warning: t val cl_error: t - val cl_open: t end = struct type t = string [@@deriving yojson] + let cl_none = "none" let cl_note = "note" let cl_warning = "warning" let cl_error = "error" - let cl_open = "open" end -module RuleConfiguration = struct +module ReportingConfiguration = struct type t = { enabled: (bool [@default false]); - defaultLevel: (RuleConfigLevel.t [@default RuleConfigLevel.cl_open]); - parameters: (Properties.t [@default Properties.default]) + defaultLevel: (RuleConfigLevel.t [@default RuleConfigLevel.cl_none]); + rank: (int [@default -1]); + parameters: (Properties.t [@default Properties.default]); + properties: (Properties.t [@default Properties.default]); }[@@deriving yojson] let default = { enabled = false; - defaultLevel = RuleConfigLevel.cl_open; + defaultLevel = RuleConfigLevel.cl_none; + rank = -1; parameters = Properties.default; + properties = Properties.default; } end -module Rule = struct +module ToolComponentReference =struct type t = { - id: (string [@default ""]); name: (string [@default ""]); - shortDescription: (Message.t [@default Message.default]); - fullDescription: (Message.t [@default Message.default]); - messageStrings: - (Additional_properties.t [@default Additional_properties.default]); - richMessageStrings: - (Additional_properties.t [@default Additional_properties.default]); - configuration: (RuleConfiguration.t [@default RuleConfiguration.default]); - helpUri: (string [@default ""]); + index: (int [@default -1]); + guid: (string [@default ""]); properties: (Properties.t [@default Properties.default]); }[@@deriving yojson] - let default = { - id = ""; - name = ""; - shortDescription = Message.default; - fullDescription = Message.default; - messageStrings = Additional_properties.default; - richMessageStrings = Additional_properties.default; - configuration = RuleConfiguration.default; - helpUri = ""; - properties = Properties.default; - } + let create + ?(name="") ?(index = -1) ?(guid = "") ?(properties=Properties.default) () = + { name; index; guid; properties } + + let default = create () + +end + +module ReportingDescriptorReference = +struct + type t = { + id: (string [@default ""]); + index: (int [@default -1]); + guid: (string [@default ""]); + toolComponent: + (ToolComponentReference.t [@default ToolComponentReference.default]); + properties: (Properties.t [@default Properties.default]); + }[@@deriving yojson] let create - ~id - ?(name="") - ?(shortDescription=Message.default) - ?(fullDescription=Message.default) - ?(messageStrings=Additional_properties.default) - ?(richMessageStrings=Additional_properties.default) - ?(configuration=RuleConfiguration.default) - ?(helpUri="") - ?(properties=Properties.default) - () - = - { id; name; shortDescription; fullDescription; messageStrings; - richMessageStrings; configuration; helpUri; properties } + ?(id="") ?(index = -1) ?(guid="") + ?(toolComponent=ToolComponentReference.default) + ?(properties=Properties.default) () = + { id; index; guid; toolComponent; properties } + let default = create () end -module Rule_dictionary = Json_dictionary(Rule) +module ReportingDescriptorRelationship = struct + type t = { + target: ReportingDescriptorReference.t; + kinds: (string list [@default ["relevant"]]); + description: (Message.t [@default Message.default]); + properties: (Properties.t [@default Properties.default]); + }[@@deriving yojson] -module Resources = struct + let create + ~target + ?(kinds=["relevant"]) + ?(description=Message.default) + ?(properties=Properties.default) () = + { target; kinds; description; properties } + + let default = create ~target:ReportingDescriptorReference.default () +end + +module ReportingDescriptor = struct type t = { + id: string; + deprecatedIds: (string list [@default []]); + guid: (string [@default ""]); + deprecatedGuids: (string list [@default []]); + name: (string [@default ""]); + deprecatedNames: (string list [@default []]); + shortDescription: + (MultiformatMessageString.t [@default MultiformatMessageString.default]); + fullDescription: + (MultiformatMessageString.t [@default MultiformatMessageString.default]); messageStrings: - (Additional_properties.t [@default Additional_properties.default]); - rules: (Rule_dictionary.t [@default []]); + (MultiformatMessageStringDictionary.t [@default []]); + defaultConfiguration: + (ReportingConfiguration.t [@default ReportingConfiguration.default]); + helpUri: (string [@default ""]); + help: + (MultiformatMessageString.t [@default MultiformatMessageString.default]); + relationships: + (ReportingDescriptorRelationship.t list [@default []]); + properties: (Properties.t [@default Properties.default]); }[@@deriving yojson] - let default = { - messageStrings = Additional_properties.default; - rules = [] } - let create - ?(messageStrings=Additional_properties.default) - ?(rules=[]) + ~id + ?(deprecatedIds=[]) + ?(guid="") + ?(deprecatedGuids=[]) + ?(name="") + ?(deprecatedNames=[]) + ?(shortDescription=MultiformatMessageString.default) + ?(fullDescription=MultiformatMessageString.default) + ?(messageStrings=[]) + ?(defaultConfiguration=ReportingConfiguration.default) + ?(helpUri="") + ?(help=MultiformatMessageString.default) + ?(relationships=[]) + ?(properties=Properties.default) () = - { messageStrings; rules } + { id; deprecatedIds; guid; deprecatedGuids; name; deprecatedNames; + shortDescription; fullDescription; messageStrings; + defaultConfiguration; helpUri; help; relationships; properties } + + let default = create ~id:"id" () + end -module Result_level: +module Result_kind: sig type t = private string val notApplicable: t val pass: t + val fail: t + val review: t + val open_: t + val informational: t + + val to_yojson: t -> Yojson.Safe.t + val of_yojson: Yojson.Safe.t -> (t,string) result +end += +struct + type t = string[@@deriving yojson] + let notApplicable = "notApplicable" + let pass = "pass" + let fail = "fail" + let review = "review" + let open_ = "open" + let informational = "informational" +end + +module Result_level: +sig + type t = private string + val none: t val note: t val warning: t val error: t @@ -836,8 +953,7 @@ end = struct type t = string[@@deriving yojson] - let notApplicable = "notApplicable" - let pass = "pass" + let none = "none" let note = "note" let warning = "warning" let error = "error" @@ -875,9 +991,10 @@ end module Sarif_result = struct type t = { ruleId: (string [@default ""]); - level: (Result_level.t[@default Result_level.notApplicable]); + kind: (Result_kind.t[@default Result_kind.fail]); + level: (Result_level.t[@default Result_level.warning]); message: (Message.t [@default Message.default]); - analysisTarget: (FileLocation.t [@default FileLocation.default]); + analysisTarget: (ArtifactLocation.t [@default ArtifactLocation.default]); locations: (Location.t list [@default []]); instanceGuid: (string [@default ""]); correlationGuid: (string [@default ""]); @@ -902,10 +1019,11 @@ module Sarif_result = struct }[@@deriving yojson] let create - ?(ruleId = "") - ?(level=Result_level.notApplicable) + ~ruleId + ?(kind=Result_kind.pass) + ?(level=Result_level.none) ?(message=Message.default) - ?(analysisTarget=FileLocation.default) + ?(analysisTarget=ArtifactLocation.default) ?(locations=[]) ?(instanceGuid="") ?(correlationGuid="") @@ -927,7 +1045,7 @@ module Sarif_result = struct () = { - ruleId;level; message; analysisTarget; locations; instanceGuid; + ruleId; kind; level; message; analysisTarget; locations; instanceGuid; correlationGuid; occurrenceCount; partialFingerprints; fingerprints; stacks; codeFlows; graphs; graphTraversals; relatedLocations; suppressionStates; baselineState; attachments; workItemsUris; @@ -946,10 +1064,6 @@ module VersionControlDetails = struct }[@@deriving yojson] end -module File_dictionary = Json_dictionary(File) - -module LogicalLocation_dictionary = Json_dictionary(LogicalLocation) - module ColumnKind: sig include Json_type with type t = private string val utf16CodeUnits: t @@ -962,75 +1076,355 @@ struct let unicodeCodePoints = "unicodeCodePoints" end +module RunAutomationDetails = struct + type t = { + description: (Message.t [@default Message.default]); + id: (string [@default ""]); + guid: (string [@default ""]); + correlationGuid: (string [@default ""]); + properties: (Properties.t [@default Properties.default]); + } [@@deriving yojson] + + let create + ?(description=Message.default) ?(id="") ?(guid="") ?(correlationGuid="") + ?(properties=Properties.default) () = + { description; id; guid; correlationGuid; properties } + + let default = create () +end + +module ExternalPropertyFileReferences = struct + type t = { + location: (ArtifactLocation.t [@default ArtifactLocation.default]); + guid: (string [@default ""]); + itemCount: (int [@default -1]); + properties: (Properties.t [@default Properties.default]); + } [@@deriving yojson] + + let create + ?(location = ArtifactLocation.default) + ?(guid = "") + ?(itemCount = -1) + ?(properties = Properties.default) + () = + { location; guid; itemCount; properties } + + let default = create () +end + +module TranslationMetadata = struct + type t = { + name: (string [@default ""]); + fullName: (string [@default ""]); + shortDescription: + (MultiformatMessageString.t [@default MultiformatMessageString.default]); + fullDescription: + (MultiformatMessageString.t [@default MultiformatMessageString.default]); + downloadUri: (string [@default ""]); + informationUri: (string [@default ""]); + properties: (Properties.t [@default Properties.default]); + } [@@deriving yojson] + + let create + ~name + ?(fullName = "") + ?(shortDescription = MultiformatMessageString.default) + ?(fullDescription = MultiformatMessageString.default) + ?(downloadUri = "") + ?(informationUri = "") + ?(properties = Properties.default) + () + = + { name; fullName; shortDescription; fullDescription; + downloadUri; informationUri; properties } + + let default = create ~name:"" () +end + +module ToolComponent = struct + module Contents: sig + include Json_type with type t = private string + val localizedData: t + val nonLocalizedData: t + end = struct + type t = string [@@deriving yojson] + let localizedData = "localizedData" + let nonLocalizedData = "nonLocalizedData" + end + type t = { + guid: (string [@default ""]); + name: (string [@default ""]); + organization: (string [@default ""]); + product: (string [@default ""]); + productSuite: (string [@default ""]); + shortDescription: + (MultiformatMessageString.t [@default MultiformatMessageString.default]); + fullDescription: + (MultiformatMessageString.t [@default MultiformatMessageString.default]); + fullName: (string [@default ""]); + version: (string [@default ""]); + semanticVersion: (string [@default ""]); + dottedQuadFileVersion: (string [@default ""]); + releaseDateUtc: (string [@default ""]); + downloadUri: (string [@default ""]); + informationUri: (string [@default ""]); + globalMessageStrings: (MultiformatMessageStringDictionary.t [@default []]); + notifications: (ReportingDescriptor.t list [@default []]); + rules: (ReportingDescriptor.t list [@default []]); + taxa: (ReportingDescriptor.t list [@default []]); + locations: (ArtifactLocation.t list [@default []]); + language: (string [@default "en-US"]); + contents: (Contents.t list [@default []]); + isComprehensive: (bool [@default false]); + localizedDataSemanticVersion: (string [@default ""]); + minimumRequiredLocalizedDataSemanticVersion: (string [@default ""]); + associateComponent: + (ToolComponentReference.t [@default ToolComponentReference.default]); + translationMetadata: + (TranslationMetadata.t [@default TranslationMetadata.default]); + supportedTaxonomies: (ToolComponentReference.t list [@default []]); + properties: (Properties.t [@default Properties.default]); + }[@@deriving yojson] + let create + ?(guid="") + ~name + ?(organization="") + ?(product="") + ?(productSuite="") + ?(shortDescription=MultiformatMessageString.default) + ?(fullDescription=MultiformatMessageString.default) + ?(fullName="") + ?(version="") + ?(semanticVersion="") + ?(dottedQuadFileVersion="") + ?(releaseDateUtc="") + ?(downloadUri="") + ?(informationUri="") + ?(globalMessageStrings=[]) + ?(notifications=[]) + ?(rules=[]) + ?(taxa=[]) + ?(locations=[]) + ?(language="en-US") + ?(contents=[Contents.nonLocalizedData]) + ?(isComprehensive=false) + ?(localizedDataSemanticVersion="") + ?(minimumRequiredLocalizedDataSemanticVersion="") + ?(associateComponent=ToolComponentReference.default) + ?(translationMetadata=TranslationMetadata.default) + ?(supportedTaxonomies=[]) + ?(properties=Properties.default) + () + = + { guid; name; organization; product; productSuite; shortDescription; + fullDescription; fullName; version; semanticVersion; + dottedQuadFileVersion; releaseDateUtc; downloadUri; informationUri; + globalMessageStrings; notifications; rules; taxa; locations; language; + contents; isComprehensive; localizedDataSemanticVersion; + minimumRequiredLocalizedDataSemanticVersion; + associateComponent; translationMetadata; supportedTaxonomies; properties } + let default = create ~name:"" () +end + +module Address = struct + type t = { + absoluteAddress: (int [@default -1]); + relativeAddress: (int [@default 0]); + length: (int [@default 0]); + kind: (string [@default ""]); + name: (string [@default ""]); + fullyQualifiedName: (string [@default ""]); + offsetFromParent: (int [@default 0]); + index: (int [@default -1]); + parentIndex: (int [@default -1]); + properties: (Properties.t [@default Properties.default]); + } [@@deriving yojson] + + let create + ?(absoluteAddress = -1) + ?(relativeAddress = 0) + ?(length = 0) + ?(kind = "") + ?(name = "") + ?(fullyQualifiedName = "") + ?(offsetFromParent = 0) + ?(index = -1) + ?(parentIndex = -1) + ?(properties = Properties.default) + () + = + { absoluteAddress; relativeAddress; length; kind; name; + fullyQualifiedName; offsetFromParent; index; parentIndex; properties } + + let default = create () +end + +module WebRequest = struct + type t = { + index: (int [@default -1]); + protocol: (string [@default ""]); + version: (string [@default ""]); + target: (string [@default ""]); + method_: (string [@default ""]) [@key "method"]; + headers: (JsonStringDictionary.t [@default []]); + parameters: (JsonStringDictionary.t [@default []]); + body: (ArtifactContent.t [@default ArtifactContent.default]); + properties: (Properties.t [@default Properties.default]); + } [@@deriving yojson] + + let create + ?(index = -1) + ?(protocol = "") + ?(version = "") + ?(target = "") + ?(method_ = "") + ?(headers = []) + ?(parameters = []) + ?(body = ArtifactContent.default) + ?(properties = Properties.default) + () + = + { index; protocol; version; target; method_; headers; parameters; + body; properties } + + let default = create () + +end + +module WebResponse = struct + type t = { + index: (int [@default -1]); + protocol: (string [@default ""]); + version: (string [@default ""]); + statusCode: (int [@default 0]); + reasonPhrase: (string [@default ""]); + headers: (JsonStringDictionary.t [@default []]); + body: (ArtifactContent.t [@default ArtifactContent.default]); + noResponseReceived: (bool [@default false]); + properties: (Properties.t [@default Properties.default]); + } [@@deriving yojson] + + let create + ?(index = -1) + ?(protocol = "") + ?(version = "") + ?(statusCode = 0) + ?(reasonPhrase = "") + ?(headers = []) + ?(body = ArtifactContent.default) + ?(noResponseReceived = false) + ?(properties = Properties.default) + () + = + { index; protocol; version; statusCode; reasonPhrase; + headers; body; noResponseReceived; properties } + + let default = create () + +end + +module SpecialLocations = struct + type t = { + displayBase: (ArtifactLocation.t [@default ArtifactLocation.default]); + properties: (Properties.t [@default Properties.default]) + } [@@deriving yojson] + let create + ?(displayBase = ArtifactLocation.default) + ?(properties = Properties.default) + () + = + { displayBase; properties } + + let default = create () +end + module Run = struct type t = { tool: Tool.t; invocations: (Invocation.t list [@default []]); conversion: (Conversion.t [@default Conversion.default]); + language: (string [@default "en-US"]); versionControlProvenance: (VersionControlDetails.t list [@default []]); originalUriBaseIds: - (Additional_properties.t [@default Additional_properties.default]); - files: (File_dictionary.t [@default []]); - logicalLocations: (LogicalLocation_dictionary.t [@default []]); - graphs: (Graph_dictionary.t [@default []]); + (ArtifactLocationDictionary.t [@default []]); + artifacts: (Artifact.t list [@default []]); + logicalLocations: (LogicalLocation.t list [@default []]); + graphs: (Graph.t list [@default []]); results: (Sarif_result.t list [@default []]); - resources: (Resources.t [@default Resources.default]); - instanceGuid: (string [@default ""]); - correlationGuid: (string [@default ""]); - logicalId: (string [@default ""]); - description: (Message.t [@default Message.default]); - automationLogicalId: (string [@default ""]); - baselineInstanceGuid: (string [@default ""]); - architecture: (string [@default ""]); - richMessageMimeType: (string [@default "text/markdown;variant=GFM" ]); - redactionToken: (string [@default ""]); - defaultFileEncoding: (string [@default "utf-8"]); + automationDetails: + (RunAutomationDetails.t [@default RunAutomationDetails.default]); + runAggregates: (RunAutomationDetails.t list [@default []]); + baselineGuid: (string [@default ""]); + redactionToken: (string list [@default []]); + defaultEncoding: (string [@default "utf-8"]); + defaultSourceLanguage: (string [@default ""]); + newlineSequences: (string list [@default ["\r\n"; "\n"]]); columnKind: (ColumnKind.t [@default ColumnKind.unicodeCodePoints]); + externalPropertyFileReferences: + (ExternalPropertyFileReferences.t + [@default ExternalPropertyFileReferences.default]); + threadFlowLocations: (ThreadFlowLocation.t list [@default []]); + taxonomies: (ToolComponent.t list [@default []]); + addresses: (Address.t list [@default []]); + translations: (ToolComponent.t list [@default []]); + policies: (ToolComponent.t list [@default[]]); + webRequests: (WebRequest.t list [@default[]]); + webResponses: (WebResponse.t list [@default[]]); + specialLocations: (SpecialLocations.t [@default SpecialLocations.default]); properties: (Properties.t [@default Properties.default]); } [@@deriving yojson] let create ~tool - ~invocations + ?(invocations=[]) ?(conversion=Conversion.default) + ?(language="en-US") ?(versionControlProvenance=[]) - ?(originalUriBaseIds=Additional_properties.default) - ?(files=[]) + ?(originalUriBaseIds=[]) + ?(artifacts=[]) ?(logicalLocations=[]) ?(graphs=[]) ?(results=[]) - ?(resources=Resources.default) - ?(instanceGuid="") - ?(correlationGuid="") - ?(logicalId="") - ?(description=Message.default) - ?(automationLogicalId="") - ?(baselineInstanceGuid="") - ?(architecture="") - ?(richMessageMimeType="text/markdown;variant=GFM") - ?(redactionToken="") - ?(defaultFileEncoding="utf-8") + ?(automationDetails=RunAutomationDetails.default) + ?(runAggregates=[]) + ?(baselineGuid="") + ?(redactionToken=[]) + ?(defaultEncoding="utf-8") + ?(defaultSourceLanguage="C") + ?(newlineSequences=["\r\n"; "\n"]) ?(columnKind=ColumnKind.unicodeCodePoints) + ?(externalPropertyFileReferences=ExternalPropertyFileReferences.default) + ?(threadFlowLocations=[]) + ?(taxonomies=[]) + ?(addresses=[]) + ?(translations=[]) + ?(policies=[]) + ?(webRequests=[]) + ?(webResponses=[]) + ?(specialLocations=SpecialLocations.default) ?(properties=Properties.default) () = { - tool; invocations; conversion; versionControlProvenance; originalUriBaseIds; - files; logicalLocations; graphs; results; resources; instanceGuid; - correlationGuid; logicalId; description; automationLogicalId; - baselineInstanceGuid; architecture; richMessageMimeType; - redactionToken; defaultFileEncoding; columnKind; properties + tool; invocations; conversion; versionControlProvenance; + language; originalUriBaseIds; + artifacts; logicalLocations; graphs; results; + automationDetails; runAggregates; baselineGuid; redactionToken; + defaultEncoding; defaultSourceLanguage; newlineSequences; columnKind; + externalPropertyFileReferences; threadFlowLocations; taxonomies; + addresses; translations; policies; webRequests; webResponses; + specialLocations; properties; } end module Schema = struct type t = { - schema: (Uri.t [@default Uri.sarif_github]) [@key "$schema"]; + schema: Uri.t [@key "$schema"]; version: Version.t; runs: Run.t list } [@@deriving yojson] - let create ?(schema=Uri.sarif_github) ?(version=Version.v2_0_0) ~runs () = + let create ?(schema=Uri.sarif_github) ?(version=Version.v2_1_0) ~runs () = { schema; version; runs } end diff --git a/src/plugins/markdown-report/sarif_gen.ml b/src/plugins/markdown-report/sarif_gen.ml index f3e3ed9226d9aefc42ce456d75c9be0db374004c..278073346ff33b4e1250082da7ab6c53033016af 100644 --- a/src/plugins/markdown-report/sarif_gen.ml +++ b/src/plugins/markdown-report/sarif_gen.ml @@ -29,8 +29,7 @@ let frama_c_sarif = let fullName = name ^ "-" ^ version in let downloadUri = "https://frama-c.com/download.html" in Tool.create - ~name ~version ~semanticVersion ~fullName ~downloadUri () - + (Driver.create ~name ~version ~semanticVersion ~fullName ~downloadUri ()) let get_remarks () = let f = Mdr_params.Remarks.get () in @@ -63,22 +62,32 @@ let gen_remark alarm = [ Block [ Text (plain - (Printf.sprintf "This alarms represents a potential %s." + (Printf.sprintf "This alarm represents a potential %s." (Alarms.get_description alarm) ) ) ] ] -let level_of_status = +let kind_of_status = let open Property_status.Feedback in - let open Sarif.Result_level in + let open Sarif.Result_kind in function | Never_tried -> notApplicable | Considered_valid | Valid | Valid_under_hyp | Valid_but_dead -> pass - | Unknown | Unknown_but_dead -> warning + | Unknown | Unknown_but_dead -> open_ + | Invalid | Invalid_under_hyp | Invalid_but_dead -> fail + | Inconsistent -> review + +let level_of_status = + let open Property_status.Feedback in + let open Sarif.Result_level in + function + | Never_tried -> none + | Considered_valid | Valid | Valid_under_hyp | Valid_but_dead -> none + | Unknown | Unknown_but_dead -> none | Invalid | Invalid_under_hyp | Invalid_but_dead -> error - | Inconsistent -> note + | Inconsistent -> none let make_message alarm annot remark = let open Markdown in @@ -92,11 +101,15 @@ let make_message alarm annot remark = | [] -> summary :: gen_remark alarm | _ -> summary :: remark in - let richText = + let markdown = String.trim (Format.asprintf "@[%a@]" (Markdown.pp_elements ~page:"") markdown) in - Message.create ~text ~richText () + Message.create ~text ~markdown () + +let opt_physical_location_of_loc loc = + if loc = Cil_datatype.Location.unknown then [] + else [ Location.of_loc loc ] let gen_results remarks = let treat_alarm _e kf s ~rank:_ alarm annot (i, rules, content) = @@ -106,12 +119,13 @@ let gen_results remarks = Datatype.String.Map.add ruleId (Alarms.get_description alarm) rules in let label = "Alarm-" ^ string_of_int i in + let kind = kind_of_status (Property_status.Feedback.get prop) in let level = level_of_status (Property_status.Feedback.get prop) in let remark = get_remark remarks label in let message = make_message alarm annot remark in - let locations = [ Location.of_loc (Cil_datatype.Stmt.loc s) ] in + let locations = opt_physical_location_of_loc (Cil_datatype.Stmt.loc s) in let res = - Sarif_result.create ~level ~ruleId ~message ~locations () + Sarif_result.create ~kind ~level ~ruleId ~message ~locations () in (i+1, rules, res :: content) in @@ -128,12 +142,14 @@ let make_ip_message ip = let text = Format.asprintf "@[%a.@]" Property.short_pretty ip in Message.plain_text ~text () +let user_annot_id = "user-spec" + let gen_status ip = let status = Property_status.Feedback.get ip in let level = level_of_status status in - let locations = [ Location.of_loc (Property.location ip) ] in + let locations = opt_physical_location_of_loc (Property.location ip) in let message = make_ip_message ip in - Sarif_result.create ~level ~locations ~message () + Sarif_result.create ~ruleId:user_annot_id ~level ~locations ~message () let gen_statuses () = let f ip content = @@ -141,29 +157,27 @@ let gen_statuses () = in List.rev (Property_status.fold f []) -let gen_files () = +let gen_artifacts () = let add_src_file f = - let key = - let fname = Filepath.Normalized.to_pretty_string f in - Filename.chop_extension (Filename.basename fname) - in - let fileLocation = FileLocation.create ~uri:(f :> string) () in + let uri = (f:Filepath.Normalized.t :> string) in + let location = ArtifactLocation.create ~uri () in let roles = [ Role.analysisTarget ] in let mimeType = "text/x-csrc" in - key, File.create ~fileLocation ~roles ~mimeType () + Artifact.create ~location ~roles ~mimeType () in List.map add_src_file (Kernel.Files.get ()) let add_rule id desc l = let text = desc ^ "." in - let shortDescription = Message.plain_text ~text () in - let rule = Rule.create ~id ~shortDescription () in - (id, rule) :: l + let shortDescription = MultiformatMessageString.create ~text () in + let rule = ReportingDescriptor.create ~id ~shortDescription () in + rule :: l -let make_rule_dictionary rules = Datatype.String.Map.fold add_rule rules [] +let make_taxonomies rules = Datatype.String.Map.fold add_rule rules [] let gen_run remarks = let tool = frama_c_sarif in + let name = "frama-c" in let invocations = [gen_invocation ()] in let rules, results = gen_results remarks in let user_annot_results = gen_statuses () in @@ -172,13 +186,13 @@ let gen_run remarks = | [] -> rules | _ -> Datatype.String.Map.add - "user-spec" "User written ACSL specification" rules + user_annot_id "User-written ACSL specification" rules in - let rules = make_rule_dictionary rules in - let resources = Resources.create ~rules () in + let rules = make_taxonomies rules in + let taxonomies = [ToolComponent.create ~name ~rules ()] in let results = results @ user_annot_results in - let files = gen_files () in - Run.create ~tool ~invocations ~results ~resources ~files () + let artifacts = gen_artifacts () in + Run.create ~tool ~invocations ~results ~taxonomies ~artifacts () let generate () = let remarks = get_remarks () in diff --git a/src/plugins/metrics/metrics_base.ml b/src/plugins/metrics/metrics_base.ml index c4c0934db605687aeb685d16abaebc37a0b4e5d6..baf2ca5fd2b43f6e3bb9a1f82b6e8621948e722e 100644 --- a/src/plugins/metrics/metrics_base.ml +++ b/src/plugins/metrics/metrics_base.ml @@ -256,11 +256,11 @@ let get_file_type filename = | "html" | "htm" -> Html | "txt" | "text" -> Text | s -> - Metrics_parameters.fatal + Metrics_parameters.abort "Unknown file extension %s. Cannot produce output.@." s with | No_suffix -> - Metrics_parameters.fatal + Metrics_parameters.abort "File %s has no suffix. Cannot produce output.@." filename module VarinfoByName = struct diff --git a/src/plugins/nonterm/tests/nonterm/builtin_termination.c b/src/plugins/nonterm/tests/nonterm/builtin_termination.c index 514e4202b09dcbed1e566fe0dd3d9ad6259937fe..dff850dc8ae96f040640768d57556b09b73aeedb 100644 --- a/src/plugins/nonterm/tests/nonterm/builtin_termination.c +++ b/src/plugins/nonterm/tests/nonterm/builtin_termination.c @@ -1,5 +1,5 @@ /* run.config - STDOPT: #"-val-builtin strlen:Frama_C_strlen" + STDOPT: #"-eva-builtin strlen:Frama_C_strlen" */ #include <string.h> diff --git a/src/plugins/nonterm/tests/nonterm/n6.c b/src/plugins/nonterm/tests/nonterm/n6.c index 1e4af5d6d67b75e8bb8b4124e1bda8e552a45444..e75e048ec1fc1ff024374bca11425471f09bc9f3 100644 --- a/src/plugins/nonterm/tests/nonterm/n6.c +++ b/src/plugins/nonterm/tests/nonterm/n6.c @@ -1,5 +1,5 @@ /* run.config - STDOPT: #"-val-builtin memcpy:Frama_C_memcpy" + STDOPT: #"-eva-builtin memcpy:Frama_C_memcpy" */ #include <string.h> diff --git a/src/plugins/nonterm/tests/test_config b/src/plugins/nonterm/tests/test_config index 1d678ae3e1a635f06f7c8fbf7e30a0da5d6f7ffe..91f0e5ec1ff948b34ba561fc9d7369be7fd38b87 100644 --- a/src/plugins/nonterm/tests/test_config +++ b/src/plugins/nonterm/tests/test_config @@ -1 +1 @@ -OPT: -no-autoload-plugins -load-module from,inout,nonterm,scope -val -val-show-progress -eva-msg-key=-summary -then -nonterm -nonterm-verbose 2 +OPT: -no-autoload-plugins -load-module from,inout,nonterm,scope -eva -eva-show-progress -eva-msg-key=-summary -then -nonterm -nonterm-verbose 2 diff --git a/src/plugins/report/tests/report/csv.c b/src/plugins/report/tests/report/csv.c index 3bd7c80288ace2904e9724cdcea46b67ba38123c..536cfb432f2702af8035011868cad8ee785095d9 100644 --- a/src/plugins/report/tests/report/csv.c +++ b/src/plugins/report/tests/report/csv.c @@ -1,6 +1,6 @@ /* run.config LOG: csv.csv - OPT: -no-autoload-plugins -load-module from,inout,report,scope,eva -eva-warn-copy-indeterminate=-main4 -eva -eva-show-progress -remove-redundant-alarms -eva-warn-key=alarm=inactive -then -report-csv @PTEST_RESULT@/csv.csv -report-no-proven -then -report-csv= -eva-warn-key=alarm -slevel 1 + OPT: -no-autoload-plugins -load-module from,inout,report,scope,eva -eva-warn-copy-indeterminate=-main4 -eva -eva-show-progress -eva-remove-redundant-alarms -eva-warn-key=alarm=inactive -then -report-csv @PTEST_RESULT@/csv.csv -report-no-proven -then -report-csv= -eva-warn-key=alarm -eva-slevel 1 COMMENT: first, do an analysis without any message, but check that the .csv is complete. Then, redo the analysis with value warnings. slevel 1 is just there to force Value to restart */ volatile v; diff --git a/src/plugins/slicing/slicingCmds.ml b/src/plugins/slicing/slicingCmds.ml index a549613bcff45232e21da27a3c709cae9b1b14da..f4f31d5622ae6f8614aff90945b21ee9aa54ed87 100644 --- a/src/plugins/slicing/slicingCmds.ml +++ b/src/plugins/slicing/slicingCmds.ml @@ -529,6 +529,7 @@ let select_stmt_annots set mark ~spare ~threat ~user_assert ~slicing_pragma ~lo (** Registered as a slicing selection function: Add a selection of the annotations related to a function. *) let select_func_annots set mark ~spare ~threat ~user_assert ~slicing_pragma ~loop_inv ~loop_var kf = + try let zones_decl_vars,pragmas = !Db.Properties.Interp.To_zone.from_func_annots Kinstr.iter_from_func (Some @@ -538,6 +539,13 @@ let select_func_annots set mark ~spare ~threat ~user_assert ~slicing_pragma ~loo kf in let set = select_ZoneAnnot_pragmas set ~spare pragmas kf in select_ZoneAnnot_zones_decl_vars set mark (get_or_raise zones_decl_vars) kf + with Kernel_function.No_Definition -> + SlicingParameters.warning ~wkey:SlicingParameters.wkey_cmdline + "No definition for function '%a'. \ + Slicing requests from the command line are ignored." + Kernel_function.pretty kf; + Cil_datatype.Varinfo.Map.empty + (** Registered as a slicing selection function: Add selection of function outputs. diff --git a/src/plugins/studia/tests/test_config b/src/plugins/studia/tests/test_config index 0875cfb7318e90da7861ddc6596bba50d8040b3d..dc79c97068c8125cbff6a916b7fed6d7b881d5f2 100644 --- a/src/plugins/studia/tests/test_config +++ b/src/plugins/studia/tests/test_config @@ -1 +1 @@ -OPT: -val -journal-disable -out -input -deps +OPT: -eva -journal-disable -out -input -deps diff --git a/src/plugins/value/engine/compute_functions.ml b/src/plugins/value/engine/compute_functions.ml index 6fbf9dbd503689a5cbbdf2bec599130f24442f68..e7d1b0f5a427acca6b2d5b7e2bc89d6c8adc0b33 100644 --- a/src/plugins/value/engine/compute_functions.ml +++ b/src/plugins/value/engine/compute_functions.ml @@ -91,12 +91,9 @@ let post_analysis_cleanup ~aborted = if Value_parameters.JoinResults.get () then Db.Value.Table_By_Callstack.iter (fun s _ -> ignore (Db.Value.get_stmt_state s)); - if not aborted then begin + if not aborted then (* Keep memexec results for users that want to resume the analysis *) - Mem_exec.cleanup_results (); - if not (Value_parameters.SaveFunctionState.is_empty ()) then - State_import.save_globals_state (); - end + Mem_exec.cleanup_results () let post_analysis () = (* Garbled mix must be dumped here -- at least before the call to diff --git a/src/plugins/value/partitioning/auto_loop_unroll.ml b/src/plugins/value/partitioning/auto_loop_unroll.ml index ac50025173cccc8707fe4d6e5385fd79365d821c..b2c114233e6414c9ea5823d06d9abe7f2cd0a7f2 100644 --- a/src/plugins/value/partitioning/auto_loop_unroll.ml +++ b/src/plugins/value/partitioning/auto_loop_unroll.ml @@ -415,7 +415,8 @@ module Make (Abstract: Abstractions.Eva) = struct try let zero_delta = { current = `Value Val.zero; final = `Bottom; } in let delta = delta_block zero_delta loop in - final_delta delta >> fun d -> Some d + final_delta delta >> fun d -> + if is_true (Val.assume_non_zero d) then Some d else None with NoIncrement -> None (* If in the block [loop], [lval] is assigned once to the value of another diff --git a/src/plugins/value/register.ml b/src/plugins/value/register.ml index 1a396420b8edc343b6cbcffbebca0fb02c996ada..00dc42fad17577e1bf50f5a2c2114c41342b46a7 100644 --- a/src/plugins/value/register.ml +++ b/src/plugins/value/register.ml @@ -138,8 +138,7 @@ let use_spec_instead_of_definition kf = not (Kernel_function.is_definition kf) || Ast_info.is_frama_c_builtin (Kernel_function.get_name kf) || Builtins.is_builtin_overridden kf || - Kernel_function.Set.mem kf (Value_parameters.UsePrototype.get ()) || - Value_parameters.LoadFunctionState.mem kf + Kernel_function.Set.mem kf (Value_parameters.UsePrototype.get ()) let eval_predicate ~pre ~here p = let open Eval_terms in diff --git a/src/plugins/value/utils/state_import.ml b/src/plugins/value/utils/state_import.ml deleted file mode 100644 index f20c361e9917300ae24e9bc8741cb91a3ddd0d52..0000000000000000000000000000000000000000 --- a/src/plugins/value/utils/state_import.ml +++ /dev/null @@ -1,308 +0,0 @@ -(**************************************************************************) -(* *) -(* This file is part of Frama-C. *) -(* *) -(* Copyright (C) 2007-2020 *) -(* CEA (Commissariat à l'énergie atomique et aux énergies *) -(* alternatives) *) -(* *) -(* you can redistribute it and/or modify it under the terms of the GNU *) -(* Lesser General Public License as published by the Free Software *) -(* Foundation, version 2.1. *) -(* *) -(* It is distributed in the hope that it will be useful, *) -(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) -(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) -(* GNU Lesser General Public License for more details. *) -(* *) -(* See the GNU Lesser General Public License version 2.1 *) -(* for more details (enclosed in the file licenses/LGPLv2.1). *) -(* *) -(**************************************************************************) - -open Cvalue -open Cil_types - -let dkey = Value_parameters.register_category "restart" - -let base_cache : (int, Base.t) Hashtbl.t = Hashtbl.create 41 -let v_cache = V.Hashtbl.create 53 - -(* Used to identify and remove escaping values from globals *) -exception Possibly_escaping_value - -let import_varinfo (vi : varinfo) ~importing_value = - try - if Cil.isFunctionType vi.vtype then - let kf = Globals.Functions.find_by_name vi.vname in - Kernel_function.get_vi kf - else begin - let vi' = Globals.Vars.find_from_astinfo vi.vname VGlobal in - if vi.vstorage = Static then - Value_parameters.warning ~once:true - "loaded state contains static variables;@ AST ordering@ \ - cannot be enforced and must be manually checked for soundness@ \ - (e.g. ensure that files are processed in the same order)"; - vi' - end - with Not_found -> - (* search in the state *) - if importing_value then begin - (* Variable may be an escaping local value *) - Value_parameters.warning "variable `%a' is not global, \ - possibly an escaping value; ignoring" - Printer.pp_varinfo vi; - raise Possibly_escaping_value - end else - Value_parameters.abort "global not found: `%a'" - Printer.pp_varinfo vi - -let import_validity = function - | Base.Empty | Base.Known _ | Base.Unknown _ | Base.Invalid as v -> v - | Base.Variable { Base.weak; min_alloc; max_alloc; max_allocable } -> - let var = Base.create_variable_validity ~weak ~min_alloc ~max_alloc in - if Integer.equal max_allocable var.Base.max_allocable then - Base.Variable var - else Kernel.abort "Incompatible maximum size for variable %a vs. %a" - Abstract_interp.Int.pretty max_allocable - Abstract_interp.Int.pretty var.Base.max_allocable - -let import_base (base : Base.t) ~importing_value = - let make_base = function - | Base.Var (vi, _validity) -> - Base.of_varinfo (import_varinfo vi ~importing_value) - | Base.CLogic_Var (lv, _ty, _validity) -> - (* Value states do not contain logic variables anyway - (except when evaluating ACSL clauses, which is not the case here *) - Value_parameters.fatal "importing logic variables (%a) is unsupported" - Printer.pp_logic_var lv - | Base.Null -> Base.null - | Base.String (_, s) -> - (* TODO: currently, we recreate a new string unrelated to the original - one. This is probably not the good solution *) - let c = match s with - | Base.CSString s -> Const (CStr s) - | Base.CSWstring s -> Const (CWStr s) - in - let e = Cil.new_exp Cil_datatype.Location.unknown c in - Base.of_string_exp e - | Base.Allocated (vi, deallocation, validity) -> - Value_parameters.feedback ~dkey "recreating allocated base for alloc: `%a'" - Printer.pp_varinfo vi; - let new_vi = Value_util.create_new_var vi.vname vi.vtype in - let validity = import_validity validity in - let new_base = Base.register_allocated_var new_vi deallocation validity in - Builtins_malloc.register_malloced_base new_base; - new_base - in - let id = Base.id base in - try - let res = Hashtbl.find base_cache id in - res - with Not_found -> - let base' = make_base base in - Hashtbl.replace base_cache id base'; - base' - -let import_base_setlattice (sl : Base.SetLattice.t) ~importing_value = - Base.SetLattice.fold (fun base acc -> - let b' = import_base base ~importing_value in - Base.Hptset.add b' acc - ) sl Base.Hptset.empty - -let import_ival = Ival.rehash - -let import_map (m : Cvalue.V.M.t) = - let add base ival m = - let new_base = import_base base ~importing_value:true in - let new_ival = import_ival ival in - Cvalue.V.add new_base new_ival m - in - Cvalue.V.M.fold add m Cvalue.V.bottom - -let import_v (v : Cvalue.V.t) = - match v with - | Cvalue.V.Top (sl, o) -> - Value_parameters.warning ~once:true - "importing garbled mix, locations may have changed"; - (*let o' = import_origin o in*) - let s = import_base_setlattice sl ~importing_value:true in - Cvalue.V.inject_top_origin o s - | Cvalue.V.Map m -> - import_map m - -let import_v_or_uninit (vu : Cvalue.V_Or_Uninitialized.t) = - let find v = - try - let res = V.Hashtbl.find v_cache v in - res - with Not_found -> - let v' = import_v v - in - V.Hashtbl.replace v_cache v v'; - v' - in - try - V_Or_Uninitialized.map find vu - with Possibly_escaping_value -> - (* replace variable with ESCAPINGADDR *) - Cvalue.V_Or_Uninitialized.C_init_esc V.bottom - -let import_offsetmap (offsetmap : V_Offsetmap.t) = - V_Offsetmap.map_on_values import_v_or_uninit offsetmap - -let import_model (state : Model.t) = - match state with - | Model.Bottom -> Model.bottom - | Model.Top -> Model.top - | Model.Map map -> - let add base offsetmap map = - let new_offsetmap = import_offsetmap offsetmap in - let new_base = import_base base ~importing_value:false in - Model.add_base new_base new_offsetmap map - in - Model.fold add map Model.empty_map - -(*and import_origin (o : Origin.t) = - (* the "new" origin location is arbitrary, since no guarantees about the - actual location can be given *) - let loc = Origin.LocationSetLattice.currentloc_singleton () in - match o with - | Origin.Misalign_read _ -> Origin.Misalign_read loc - | Origin.Leaf _ -> Origin.Leaf loc - | Origin.Merge _ -> Origin.Merge loc - | Origin.Arith _ -> Origin.Arith loc - | Origin.Well | Origin.Unknown -> o*) - -let load_globals_from_file filename : Model.t = - let ic = open_in_bin filename in - let (state : Model.t) = Marshal.from_channel ic in - close_in ic; - Value_parameters.feedback ~dkey "DE-MARSHALLED STATE (before import):@.%a" - Cvalue.Model.pretty state; - import_model state - -let save_globals_to_file kf state_with_locals filename = - Value_parameters.feedback "Saving globals state after call to function: %a" - Kernel_function.pretty kf; - let state = Model.filter_base Base.is_global state_with_locals in - Value_parameters.feedback ~dkey "SAVED STATE:@.%a" Model.pretty state; - let oc = open_out_bin filename in - Marshal.to_channel oc state []; - close_out oc - -let load_and_merge_function_state state : Model.t = - let (kf, filename) = Value_parameters.get_LoadFunctionState () in - Value_parameters.feedback - "@[<hov 0>Skipping call to %a,@ loading globals state from file:@ %s@]" - Kernel_function.pretty kf filename; - let saved_state = load_globals_from_file filename in - Value_parameters.debug ~dkey "LOADED STATE:@.%a" - Cvalue.Model.pretty saved_state; - (* warn about missing globals in the new AST, and add new globals that were - not present before *) - let saved_map = match saved_state with - | Model.Map m -> m - | _ -> assert false - in - let locals = - Model.filter_base (fun base -> not (Base.is_global base)) state - in - let state_without_locals = - Model.filter_base (fun base -> Base.is_global base) state - in - Value_parameters.debug ~dkey "Merging state with locals: %a@." - Model.pretty locals; - let new_globals = - Model.filter_base - (fun base -> - try - let _ = Model.find_base base saved_state in - false (* previously existing global *) - with - | Not_found -> - Value_parameters.warning "found new global variable `%a'" - Base.pretty base; - true (* new global *) - ) state_without_locals - in - let merged_globals_state = - Model.fold (fun new_base offsm acc -> - Model.add_base new_base offsm acc - ) saved_map new_globals - in - let map_with_globals = match merged_globals_state with - | Model.Map m -> m - | _ -> Value_parameters.fatal "invalid saved state: %a" - Model.pretty saved_state - in - let merged_globals_and_locals = - Model.fold (fun new_base offsm acc -> - Model.add_base new_base offsm acc - ) map_with_globals locals - in - merged_globals_and_locals - -let save_globals_state () : unit = - let (kf, filename) = Value_parameters.get_SaveFunctionState () in - let ret_stmt = Kernel_function.find_return kf in - try - let ret_state = Db.Value.get_stmt_state ret_stmt in - match ret_state with - | Model.Top -> - Value_parameters.abort "cannot save state at return statement of %a \ - (too imprecise)" Kernel_function.pretty kf - | Model.Bottom -> - Value_parameters.abort "cannot save state at return statement of %a \ - (bottom)" Kernel_function.pretty kf - | Model.Map _ -> save_globals_to_file kf ret_state filename - with Not_found -> - if Value_parameters.LoadFunctionState.is_set () then - let (load_kf, _) = Value_parameters.get_LoadFunctionState () in - Value_parameters.abort "could not find saved state for function `%a';@ \ - this can happen if it is called from `%a'" - Kernel_function.pretty kf Kernel_function.pretty load_kf; - else - Value_parameters.failure "could not find saved state for function `%a'" - Kernel_function.pretty kf - - -exception Warn_local_addresses -(* visitor used by frama_c_load_state *) -class locals_visitor = object(_self) inherit Visitor.frama_c_inplace - method! vlval (lhost, _) = - match lhost with - | Var vi -> - if not vi.vglob then raise Warn_local_addresses; - Cil.DoChildren - | Mem _ -> Cil.DoChildren -end - - -(* Builtin to load a saved analysis state *) -let frama_c_load_state state actuals = - (* Warn if arguments contain pointers to local variables, - in which case the loaded state may be unsound. *) - begin - try - List.iter (fun (exp_arg, arg, _) -> - let vis = new locals_visitor in - if Cil.isPointerType (Cil.typeOf exp_arg) then - ignore (Visitor.visitFramacExpr vis exp_arg); - if Cvalue.V.contains_addresses_of_any_locals arg then - raise Warn_local_addresses - ) actuals; - with Warn_local_addresses -> - Value_parameters.warning ~current:true ~once:true - "arguments to loaded function state contain local addresses,@ \ - possible unsoundness"; - end; - let merged_loaded_state = load_and_merge_function_state state in - { - Value_types.c_values = [None, merged_loaded_state]; - c_clobbered = Base.SetLattice.empty; - c_cacheable = Value_types.NoCacheCallers; - c_from = None - } - -let () = Builtins.register_builtin "Frama_C_load_state" frama_c_load_state diff --git a/src/plugins/value/value_parameters.ml b/src/plugins/value/value_parameters.ml index cd4ef32136c15f52f83a89a6089bee1d4f98f126..1446dd8d796c00da0756d64a22a00301a6bbaa0f 100644 --- a/src/plugins/value/value_parameters.ml +++ b/src/plugins/value/value_parameters.ml @@ -25,6 +25,7 @@ let kernel_parameters_correctness = [ Kernel.MainFunction.parameter; Kernel.LibEntry.parameter; Kernel.AbsoluteValidRange.parameter; + Kernel.InitializedPaddingLocals.parameter; Kernel.SafeArrays.parameter; Kernel.UnspecifiedAccess.parameter; Kernel.SignedOverflow.parameter; @@ -33,6 +34,10 @@ let kernel_parameters_correctness = [ Kernel.RightShiftNegative.parameter; Kernel.SignedDowncast.parameter; Kernel.UnsignedDowncast.parameter; + Kernel.PointerDowncast.parameter; + Kernel.SpecialFloat.parameter; + Kernel.InvalidBool.parameter; + Kernel.InvalidPointer.parameter; ] let parameters_correctness = ref Typed_parameter.Set.empty @@ -64,8 +69,8 @@ include Plugin.Register "automatically computes variation domains for the variables of the program" end) -let () = Help.add_aliases [ "-value-h"; "-val-h" ] -let () = add_plugin_output_aliases [ "value" ] +let () = Help.add_aliases ~visible:false [ "-value-h"; "-val-h" ] +let () = add_plugin_output_aliases ~visible:false ~deprecated:true [ "value" ] (* Debug categories. *) let dkey_initial_state = register_category "initial-state" @@ -106,10 +111,10 @@ module ForceValues = WithOutput (struct let option_name = "-eva" - let help = "compute values" + let help = "Compute values" let output_by_default = true end) -let () = ForceValues.add_aliases ["-val"] +let () = ForceValues.add_aliases ~deprecated:true ["-val"] let domains = add_group "Abstract Domains" let precision_tuning = add_group "Precision vs. time" @@ -225,7 +230,7 @@ module DomainsFunction = end) (struct let option_name = "-eva-domains-function" - let help = "Enables a domain only for the given functions. \ + let help = "Enable a domain only for the given functions. \ <d:f+> enables the domain [d] from function [f] \ (the domain is enabled in all functions called from [f]). \ <d:f-> disables the domain [d] from function [f]." @@ -248,12 +253,13 @@ module EqualityCall = String (struct let option_name = "-eva-equality-through-calls" - let help = "Equalities propagated through function calls (from the caller \ + let help = "Propagate equalities through function calls (from the caller \ to the called function): none, only equalities between formal \ parameters and concrete arguments, or all. " let default = "formals" let arg_name = "none|formals|all" end) +let () = EqualityCall.set_possible_values ["none"; "formals"; "all"] let () = add_precision_dep EqualityCall.parameter let () = Parameter_customize.set_group domains @@ -269,7 +275,7 @@ module EqualityCallFunction = end) (struct let option_name = "-eva-equality-through-calls-function" - let help = "Equalities propagated through calls to specific functions. \ + let help = "Propagate equalities through calls to specific functions. \ Overrides -eva-equality-call." let default = Kernel_function.Map.empty let arg_name = "f:none|formals|all" @@ -281,8 +287,8 @@ module OctagonCall = Bool (struct let option_name = "-eva-octagon-through-calls" - let help = "Whether the relations inferred by the octagon domain are \ - propagated through function calls. Disabled by default: \ + let help = "Propagate relations inferred by the octagon domain \ + through function calls. Disabled by default: \ the octagon analysis is intra-procedural, starting \ each function with an empty octagon state, \ and losing the octagons inferred at the end. \ @@ -299,9 +305,10 @@ module Numerors_Real_Size = let option_name = "-eva-numerors-real-size" let arg_name = "n" let help = - "set <n> as the significand size of the MPFR representation \ + "Set <n> as the significand size of the MPFR representation \ of reals used by the numerors domain (defaults to 128)" end) +let () = Numerors_Real_Size.set_range 1 max_int let () = add_precision_dep Numerors_Real_Size.parameter let () = Parameter_customize.set_group domains @@ -309,7 +316,7 @@ module Numerors_Mode = String (struct let option_name = "-eva-numerors-interaction" - let help = "defines how the numerors domain infers the absolute and the \ + let help = "Define how the numerors domain infers the absolute and the \ relative errors:\n\ - relative: the relative is deduced from the absolute;\n\ - absolute: the absolute is deduced from the relative;\n\ @@ -369,38 +376,35 @@ module NoResultsFunctions = (struct let option_name = "-eva-no-results-function" let arg_name = "f" - let help = "do not record the values obtained for the statements of \ + let help = "Do not record the values obtained for the statements of \ function f" end) let () = add_dep NoResultsFunctions.parameter -let () = NoResultsFunctions.add_aliases ["-no-results-function"] let () = Parameter_customize.set_group performance module ResultsAll = True (struct let option_name = "-eva-results" - let help = "record values for any of the statements of the program." + let help = "Record values for each of the statements of the program." end) let () = add_dep ResultsAll.parameter -let () = ResultsAll.add_aliases ["-results"] let () = Parameter_customize.set_group performance module JoinResults = Bool (struct let option_name = "-eva-join-results" - let help = "precompute consolidated states once value is computed" + let help = "Precompute consolidated states once Eva is computed" let default = true end) -let () = JoinResults.add_aliases ["-val-join-results"] let () = Parameter_customize.set_group performance module EqualityStorage = Bool (struct let option_name = "-eva-equality-storage" - let help = "Stores the states of the equality domain during \ + let help = "Store the states of the equality domain during \ the analysis." let default = true end) @@ -411,7 +415,7 @@ module SymbolicLocsStorage = Bool (struct let option_name = "-eva-symbolic-locations-storage" - let help = "Stores the states of the symbolic locations domain during \ + let help = "Store the states of the symbolic locations domain during \ the analysis." let default = true end) @@ -422,7 +426,7 @@ module GaugesStorage = Bool (struct let option_name = "-eva-gauges-storage" - let help = "Stores the states of the gauges domain during the analysis." + let help = "Store the states of the gauges domain during the analysis." let default = true end) let () = add_precision_dep GaugesStorage.parameter @@ -432,7 +436,7 @@ module ApronStorage = Bool (struct let option_name = "-eva-apron-storage" - let help = "Stores the states of the apron domains during the \ + let help = "Store the states of the apron domains during the \ analysis." let default = false end) @@ -443,7 +447,7 @@ module BitwiseOffsmStorage = Bool (struct let option_name = "-eva-bitwise-storage" - let help = "Stores the states of the bitwise domain during the \ + let help = "Store the states of the bitwise domain during the \ analysis." let default = true end) @@ -458,53 +462,35 @@ module AllRoundingModesConstants = False (struct let option_name = "-eva-all-rounding-modes-constants" - let help = "Take into account the possibility of constants not being converted to the nearest representable value, or being converted to higher precision" + let help = "Take into account the possibility of constants not being \ + converted to the nearest representable value, \ + or being converted to higher precision" end) let () = add_correctness_dep AllRoundingModesConstants.parameter -let () = AllRoundingModesConstants.add_aliases ["-all-rounding-modes-constants"] let () = Parameter_customize.set_group alarms module UndefinedPointerComparisonPropagateAll = False (struct let option_name = "-eva-undefined-pointer-comparison-propagate-all" - let help = "if the target program appears to contain undefined pointer comparisons, propagate both outcomes {0; 1} in addition to the emission of an alarm" + let help = "If the target program appears to contain undefined pointer \ + comparisons, propagate both outcomes {0; 1} in addition to \ + the emission of an alarm" end) let () = add_correctness_dep UndefinedPointerComparisonPropagateAll.parameter -let () = - UndefinedPointerComparisonPropagateAll.add_aliases - ["-undefined-pointer-comparison-propagate-all"] let () = Parameter_customize.set_group alarms module WarnPointerComparison = String (struct let option_name = "-eva-warn-undefined-pointer-comparison" - let help = "warn on all pointer comparisons, on comparisons where \ + let help = "Warn on all pointer comparisons, on comparisons where \ the arguments have pointer type (default), or never warn" let default = "pointer" let arg_name = "all|pointer|none" end) let () = WarnPointerComparison.set_possible_values ["all"; "pointer"; "none"] let () = add_correctness_dep WarnPointerComparison.parameter -let () = WarnPointerComparison.add_aliases ["-val-warn-undefined-pointer-comparison"] - - -let () = Parameter_customize.set_group alarms -let () = Parameter_customize.is_invisible () -module WarnLeftShiftNegative = - True - (struct - let option_name = "-val-warn-left-shift-negative" - let help = - "Emit alarms when left-shifting negative integers" - end) -let () = add_correctness_dep WarnLeftShiftNegative.parameter -let () = WarnLeftShiftNegative.add_update_hook - (fun _ v -> - warning "This option is deprecated. Use %s instead" - Kernel.LeftShiftNegative.name; - Kernel.LeftShiftNegative.set v) let () = Parameter_customize.set_group alarms module WarnSignedConvertedDowncast = @@ -517,9 +503,6 @@ module WarnSignedConvertedDowncast = destination range." end) let () = add_correctness_dep WarnSignedConvertedDowncast.parameter -let () = - WarnSignedConvertedDowncast.add_aliases - ["-val-warn-signed-converted-downcast"] let () = Parameter_customize.set_group alarms @@ -533,7 +516,6 @@ module WarnPointerSubstraction = offsets. When unset, do not warn but generate imprecise offsets." end) let () = add_correctness_dep WarnPointerSubstraction.parameter -let () = WarnPointerSubstraction.add_aliases ["-val-warn-pointer-subtraction"] let () = Parameter_customize.set_group alarms module IgnoreRecursiveCalls = @@ -544,7 +526,6 @@ module IgnoreRecursiveCalls = "Pretend function calls that would be recursive do not happen. Causes unsoundness" end) let () = add_correctness_dep IgnoreRecursiveCalls.parameter -let () = IgnoreRecursiveCalls.add_aliases ["-val-ignore-recursive-calls"] let () = Parameter_customize.set_group alarms @@ -553,13 +534,12 @@ module WarnCopyIndeterminate = (struct let option_name = "-eva-warn-copy-indeterminate" let arg_name = "f | @all" - let help = "warn when a statement of the specified functions copies a \ + let help = "Warn when a statement of the specified functions copies a \ value that may be indeterminate (uninitialized or containing escaping address). \ Set by default; can be deactivated for function 'f' by '=-f', or for all \ functions by '=-@all'." end) let () = add_correctness_dep WarnCopyIndeterminate.parameter -let () = WarnCopyIndeterminate.add_aliases ["-val-warn-copy-indeterminate"] let () = WarnCopyIndeterminate.Category.(set_default (all ())) let () = Parameter_customize.set_group alarms @@ -568,10 +548,9 @@ module ReduceOnLogicAlarms = (struct let option_name = "-eva-reduce-on-logic-alarms" let help = "Force reductions by a predicate to ignore logic alarms \ - emitted while the predicated is evaluated (experimental)" + emitted while the predicate is evaluated (experimental)" end) let () = add_correctness_dep ReduceOnLogicAlarms.parameter -let () = ReduceOnLogicAlarms.add_aliases ["-val-reduce-on-logic-alarms"] let () = Parameter_customize.set_group alarms module InitializedLocals = @@ -583,7 +562,6 @@ module InitializedLocals = initialization." end) let () = add_correctness_dep InitializedLocals.parameter -let () = InitializedLocals.add_aliases ["-val-initialized-locals"] (* ------------------------------------------------------------------------- *) (* --- Initial context --- *) @@ -596,10 +574,10 @@ module AutomaticContextMaxDepth = let option_name = "-eva-context-depth" let default = 2 let arg_name = "n" - let help = "use <n> as the depth of the default context for Eva. (defaults to 2)" + let help = "Use <n> as the depth of the default context for Eva. (defaults to 2)" end) +let () = AutomaticContextMaxDepth.set_range 0 max_int let () = add_correctness_dep AutomaticContextMaxDepth.parameter -let () = AutomaticContextMaxDepth.add_aliases ["-context-depth"] let () = Parameter_customize.set_group initial_context module AutomaticContextMaxWidth = @@ -608,21 +586,20 @@ module AutomaticContextMaxWidth = let option_name = "-eva-context-width" let default = 2 let arg_name = "n" - let help = "use <n> as the width of the default context for Eva. (defaults to 2)" + let help = "Use <n> as the width of the default context for Eva. (defaults to 2)" end) let () = AutomaticContextMaxWidth.set_range ~min:1 ~max:max_int let () = add_correctness_dep AutomaticContextMaxWidth.parameter -let () = AutomaticContextMaxWidth.add_aliases ["-context-width"] let () = Parameter_customize.set_group initial_context module AllocatedContextValid = False (struct let option_name = "-eva-context-valid-pointers" - let help = "only allocate valid pointers until context-depth, and then use NULL (defaults to false)" + let help = "Only allocate valid pointers until context-depth, \ + and then use NULL (defaults to false)" end) let () = add_correctness_dep AllocatedContextValid.parameter -let () = AllocatedContextValid.add_aliases ["-context-valid-pointers"] let () = Parameter_customize.set_group initial_context module InitializationPaddingGlobals = @@ -638,7 +615,6 @@ module InitializationPaddingGlobals = end) let () = InitializationPaddingGlobals.set_possible_values ["yes"; "no"; "maybe"] let () = add_correctness_dep InitializationPaddingGlobals.parameter -let () = InitializationPaddingGlobals.add_aliases ["-val-initialization-padding-globals"] (* ------------------------------------------------------------------------- *) (* --- Tuning --- *) @@ -669,7 +645,7 @@ module HierarchicalConvergence = (struct let option_name = "-eva-hierarchical-convergence" let help = "Experimental and unsound. Separate the convergence process \ - of each levels of nested loops. This implies that the convergence of \ + of each level of nested loops. This implies that the convergence of \ inner loops will be completely recomputed when doing another iteration \ of the outer loops." end) @@ -683,10 +659,9 @@ module WideningDelay = let option_name = "-eva-widening-delay" let arg_name = "n" let help = - "do not widen before the <n>-th iteration (defaults to 3)" + "Do not widen before the <n>-th iteration (defaults to 3)" end) let () = WideningDelay.set_range ~min:1 ~max:max_int -let () = WideningDelay.add_aliases ["-wlevel"] let () = add_precision_dep WideningDelay.parameter let () = Parameter_customize.set_group precision_tuning @@ -697,9 +672,9 @@ module WideningPeriod = let option_name = "-eva-widening-period" let arg_name = "n" let help = - "after the first widening, widen each <n> iterations (defaults to 2)" + "After the first widening, widen each <n> iterations (defaults to 2)" end) -let () = WideningDelay.set_range ~min:1 ~max:max_int +let () = WideningPeriod.set_range ~min:1 ~max:max_int let () = add_precision_dep WideningPeriod.parameter (* --- Partitioning --- *) @@ -711,10 +686,12 @@ module SemanticUnrollingLevel = let option_name = "-eva-slevel" let arg_name = "n" let help = - "superpose up to <n> states when unrolling control flow. The larger n, the more precise and expensive the analysis (defaults to 0)" + "Superpose up to <n> states when unrolling control flow. \ + The larger n, the more precise and expensive the analysis \ + (defaults to 0)" end) +let () = SemanticUnrollingLevel.set_range 0 max_int let () = add_precision_dep SemanticUnrollingLevel.parameter -let () = SemanticUnrollingLevel.add_aliases ["-slevel"] let () = Parameter_customize.set_group precision_tuning let () = Parameter_customize.argument_may_be_fundecl () @@ -735,11 +712,10 @@ module SlevelFunction = (struct let option_name = "-eva-slevel-function" let arg_name = "f:n" - let help = "override slevel with <n> when analyzing <f>" + let help = "Override slevel with <n> when analyzing <f>" let default = Kernel_function.Map.empty end) let () = add_precision_dep SlevelFunction.parameter -let () = SlevelFunction.add_aliases ["-slevel-function"] let () = Parameter_customize.set_group precision_tuning module SlevelMergeAfterLoop = @@ -748,11 +724,10 @@ module SlevelMergeAfterLoop = let option_name = "-eva-slevel-merge-after-loop" let arg_name = "f | @all" let help = - "when set, the different execution paths that originate from the body \ + "When set, the different execution paths that originate from the body \ of a loop are merged before entering the next excution." end) let () = add_precision_dep SlevelMergeAfterLoop.parameter -let () = SlevelMergeAfterLoop.add_aliases ["-val-slevel-merge-after-loop"] let () = Parameter_customize.set_group precision_tuning module MinLoopUnroll = @@ -762,9 +737,9 @@ module MinLoopUnroll = let arg_name = "n" let default = 0 let help = - "unroll <n> loop iterations for each loop, regardless of the slevel \ + "Unroll <n> loop iterations for each loop, regardless of the slevel \ settings and the number of states already propagated. \ - Can be overwritten on a case by case basis by loop unroll annotations." + Can be overwritten on a case-by-case basis by loop unroll annotations." end) let () = add_precision_dep MinLoopUnroll.parameter let () = MinLoopUnroll.set_range 0 max_int @@ -776,7 +751,7 @@ module AutoLoopUnroll = let option_name = "-eva-auto-loop-unroll" let arg_name = "n" let default = 0 - let help = "limit of the automatic loop unrolling: all loops whose \ + let help = "Limit of the automatic loop unrolling: all loops whose \ number of iterations can be easily bounded by <n> \ are completely unrolled." end) @@ -791,8 +766,8 @@ module DefaultLoopUnroll = let arg_name = "n" let default = 100 let help = - "defines the default limit for loop unroll annotations that do\ - not explicitely provide a limit." + "Define the default limit for loop unroll annotations that do \ + not explicitly provide a limit." end) let () = add_precision_dep DefaultLoopUnroll.parameter let () = DefaultLoopUnroll.set_range 0 max_int @@ -805,7 +780,7 @@ module HistoryPartitioning = let arg_name = "n" let default = 0 let help = - "keep states distincts as long as the <n> last branching in their\ + "Keep states distinct as long as the <n> last branching in their \ traces are also distinct. (A value of 0 deactivates this feature)" end) let () = add_precision_dep HistoryPartitioning.parameter @@ -816,7 +791,7 @@ module ValuePartitioning = String_set (struct let option_name = "-eva-partition-value" - let help = "partition the space of reachable states according to the \ + let help = "Partition the space of reachable states according to the \ possible values of the global(s) variable(s) V." let arg_name = "V" end) @@ -829,8 +804,8 @@ module SplitLimit = let option_name = "-eva-split-limit" let arg_name = "N" let default = 100 - let help = "prevents the split annotations or -eva-partition-value to \ - enumerate more than N cases" + let help = "Prevent split annotations or -eva-partition-value from \ + enumerating more than N cases" end) let () = add_precision_dep SplitLimit.parameter let () = SplitLimit.set_range 0 max_int @@ -853,12 +828,11 @@ module SplitReturnFunction = (struct let option_name = "-eva-split-return-function" let arg_name = "f:n" - let help = "split return states of function <f> according to \ + let help = "Split return states of function <f> according to \ \\result == n and \\result != n" let default = Kernel_function.Map.empty end) let () = add_precision_dep SplitReturnFunction.parameter -let () = SplitReturnFunction.add_aliases ["-val-split-return-function"] let () = Parameter_customize.set_group precision_tuning module SplitReturn = @@ -867,8 +841,8 @@ module SplitReturn = let option_name = "-eva-split-return" let arg_name = "mode" let default = "" - let help = "when 'mode' is a number, or 'full', this is equivalent \ - to -val-split-return-function f:mode for all functions f. \ + let help = "When 'mode' is a number, or 'full', this is equivalent \ + to -eva-split-return-function f:mode for all functions f. \ When mode is 'auto', automatically split states at the end \ of all functions, according to the function return code" end) @@ -886,7 +860,6 @@ let () = abort "@[@[incorrect argument for option %s@ (%s).@]" SplitReturn.name s)) let () = add_precision_dep SplitReturn.parameter -let () = SplitReturn.add_aliases ["-val-split-return"] (* --- Misc --- *) @@ -903,7 +876,6 @@ module ILevel = (defaults to 8, must be between 4 and 128)" end) let () = add_precision_dep ILevel.parameter -let () = ILevel.add_aliases ["-val-ilevel"] let () = ILevel.add_update_hook (fun _ i -> Int_set.set_small_cardinal i) let () = ILevel.set_range 4 256 @@ -934,13 +906,12 @@ module BuiltinsOverrides = (struct let option_name = "-eva-builtin" let arg_name = "f:ffc" - let help = "when analyzing function <f>, try to use Frama-C builtin \ + let help = "When analyzing function <f>, try to use Frama-C builtin \ <ffc> instead. \ Fall back to <f> if <ffc> cannot handle its arguments." let default = Kernel_function.Map.empty end) -let () = add_precision_dep BuiltinsOverrides.parameter -let () = BuiltinsOverrides.add_aliases ["-val-builtin"] +let () = add_correctness_dep BuiltinsOverrides.parameter (* Exported in Eva.mli. *) let use_builtin key name = @@ -957,17 +928,16 @@ module BuiltinsAuto = known C functions" end) let () = add_correctness_dep BuiltinsAuto.parameter -let () = BuiltinsAuto.add_aliases ["-val-builtins-auto"] let () = Parameter_customize.set_group precision_tuning +let () = Parameter_customize.set_negative_option_name "" module BuiltinsList = False (struct let option_name = "-eva-builtins-list" - let help = "Lists the existing builtins, and which functions they \ + let help = "List existing builtins, and which functions they \ are automatically associated to (if any)" end) -let () = BuiltinsList.add_aliases ["-val-builtins-list"] let () = Parameter_customize.set_group precision_tuning module LinearLevel = @@ -980,8 +950,8 @@ module LinearLevel = appears multiple times, by splitting its value at most n times. \ Defaults to 0." end) +let () = LinearLevel.set_range 0 max_int let () = add_precision_dep LinearLevel.parameter -let () = LinearLevel.add_aliases ["-val-subdivide-non-linear"] let () = Parameter_customize.set_group precision_tuning module LinearLevelFunction = @@ -1001,7 +971,7 @@ module LinearLevelFunction = (struct let option_name = "-eva-subdivide-non-linear-function" let arg_name = "f:n" - let help = "override the global option -eva-subdivide-non-linear with <n>\ + let help = "Override the global option -eva-subdivide-non-linear with <n>\ when analyzing the function <f>." let default = Kernel_function.Map.empty end) @@ -1014,21 +984,20 @@ module UsePrototype = (struct let option_name = "-eva-use-spec" let arg_name = "f1,..,fn" - let help = "use the ACSL specification of the functions instead of their definitions" + let help = "Use the ACSL specification of the functions instead of \ + their definitions" end) -let () = add_precision_dep UsePrototype.parameter -let () = UsePrototype.add_aliases ["-val-use-spec"] +let () = add_correctness_dep UsePrototype.parameter let () = Parameter_customize.set_group precision_tuning module SkipLibcSpecs = True (struct let option_name = "-eva-skip-stdlib-specs" - let help = "skip ACSL specifications on functions originating from the \ + let help = "Skip ACSL specifications on functions originating from the \ standard library of Frama-C, when their bodies are evaluated" end) let () = add_precision_dep SkipLibcSpecs.parameter -let () = SkipLibcSpecs.add_aliases ["-val-skip-stdlib-specs"] let () = Parameter_customize.set_group precision_tuning @@ -1036,10 +1005,10 @@ module RmAssert = True (struct let option_name = "-eva-remove-redundant-alarms" - let help = "after the analysis, try to remove redundant alarms, so that the user needs inspect fewer of them" + let help = "After the analysis, try to remove redundant alarms, \ + so that the user needs to inspect fewer of them" end) let () = add_precision_dep RmAssert.parameter -let () = RmAssert.add_aliases ["-remove-redundant-alarms"] let () = Parameter_customize.set_group precision_tuning module MemExecAll = @@ -1047,20 +1016,10 @@ module MemExecAll = (struct let option_name = "-eva-memexec" let help = "Speed up analysis by not recomputing functions already \ - analyzed in the same context. Forces -inout-callwise. \ + analyzed in the same context. \ Callstacks for which the analysis has not been recomputed \ are incorrectly shown as dead in the GUI." end) -let () = MemExecAll.add_aliases ["-memexec-all"] -let () = - MemExecAll.add_set_hook - (fun _bold bnew -> - if bnew then - try - Dynamic.Parameter.Bool.set "-inout-callwise" true - with Dynamic.Unbound_value _ | Dynamic.Incompatible_type _ -> - abort "Cannot set option -eva-memexec. Is plugin Inout registered?" - ) let () = Parameter_customize.set_group precision_tuning module ArrayPrecisionLevel = @@ -1069,106 +1028,15 @@ module ArrayPrecisionLevel = let default = 200 let option_name = "-eva-plevel" let arg_name = "n" - let help = "use <n> as the precision level for arrays accesses. \ + let help = "Use <n> as the precision level for arrays accesses. \ Array accesses are precise as long as the interval for the index contains \ less than n values. (defaults to 200)" end) +let () = ArrayPrecisionLevel.set_range 0 max_int let () = add_precision_dep ArrayPrecisionLevel.parameter -let () = ArrayPrecisionLevel.add_aliases ["-plevel"] let () = ArrayPrecisionLevel.add_update_hook (fun _ v -> Offsetmap.set_plevel v) -(* Options SaveFunctionState and LoadFunctionState are related - and mutually dependent for sanity checking. - Also, they depend on BuiltinsOverrides, so they cannot be defined before it. *) -let () = Parameter_customize.set_group initial_context -module SaveFunctionState = - Kernel_function_map - (struct - include Datatype.String - type key = Cil_types.kernel_function - let of_string ~key:_ ~prev:_ file = file - let to_string ~key:_ file = file - end) - (struct - let option_name = "-eva-save-fun-state" - let arg_name = "function:filename" - let help = "save state of function <function> in file <filename>" - let default = Kernel_function.Map.empty - end) -let () = SaveFunctionState.add_aliases ["-val-save-fun-state"] -let () = Parameter_customize.set_group initial_context -module LoadFunctionState = - Kernel_function_map - (struct - include Datatype.String - type key = Cil_types.kernel_function - let of_string ~key:_ ~prev:_ file = file - let to_string ~key:_ file = file - end) - (struct - let option_name = "-eva-load-fun-state" - let arg_name = "function:filename" - let help = "load state of function <function> from file <filename>" - let default = Kernel_function.Map.empty - end) -let () = LoadFunctionState.add_aliases ["-val-load-fun-state"] -let () = add_correctness_dep SaveFunctionState.parameter -let () = add_correctness_dep LoadFunctionState.parameter -(* checks that SaveFunctionState has a unique argument pair, and returns it. *) -let get_SaveFunctionState () = - let is_first = ref true in - let (kf, filename) = SaveFunctionState.fold - (fun (kf, opt_filename) _acc -> - if !is_first then is_first := false - else abort "option `%s' requires a single function:filename pair" - SaveFunctionState.name; - let filename = Extlib.the opt_filename in - kf, filename - ) (Kernel_function.dummy (), "") - in - if filename = "" then abort "option `%s' requires a function:filename pair" - SaveFunctionState.name - else kf, filename -(* checks that LoadFunctionState has a unique argument pair, and returns it. *) -let get_LoadFunctionState () = - let is_first = ref true in - let (kf, filename) = LoadFunctionState.fold - (fun (kf, opt_filename) _acc -> - if !is_first then is_first := false - else abort "option `%s' requires a single function:filename pair" - LoadFunctionState.name; - let filename = Extlib.the opt_filename in - kf, filename - ) (Kernel_function.dummy (), "") - in - if filename = "" then abort "option `%s' requires a function:filename pair" - LoadFunctionState.name - else kf, filename -(* perform early sanity checks to avoid aborting the analysis only at the end *) -let () = Ast.apply_after_computed (fun _ -> - (* check the function to save returns 'void' *) - if SaveFunctionState.is_set () then begin - let (kf, _) = get_SaveFunctionState () in - if not (Kernel_function.returns_void kf) then - abort "option `%s': function `%a' must return void" - SaveFunctionState.name Kernel_function.pretty kf - end; - if SaveFunctionState.is_set () && LoadFunctionState.is_set () then begin - (* check that if both save and load are set, they do not specify the - same function name (note: cannot compare using function ids) *) - let (save_kf, _) = get_SaveFunctionState () in - let (load_kf, _) = get_LoadFunctionState () in - if Kernel_function.equal save_kf load_kf then - abort "options `%s' and `%s' cannot save/load the same function `%a'" - SaveFunctionState.name LoadFunctionState.name - Kernel_function.pretty save_kf - end; - if LoadFunctionState.is_set () then - let (kf, _) = get_LoadFunctionState () in - BuiltinsOverrides.add (kf, Some "Frama_C_load_state"); - ) - (* ------------------------------------------------------------------------- *) (* --- Messages --- *) (* ------------------------------------------------------------------------- *) @@ -1180,51 +1048,26 @@ module ValShowProgress = let option_name = "-eva-show-progress" let help = "Show progression messages during analysis" end) -let () = ValShowProgress.add_aliases ["-val-show-progress"] - -let () = Parameter_customize.set_group messages -let () = Parameter_customize.is_invisible () -module ValShowInitialState = - True - (struct - let option_name = "-val-show-initial-state" - (* deprecated in Silicon *) - let help = "[deprecated] Show initial state before analysis starts. \ - This option has been replaced by \ - -value-msg-key=[-]initial-state and has no effect anymore." - end) -let () = - ValShowInitialState.add_set_hook - (fun _ new_ -> - if new_ then - Kernel.warning "@[Option -val-show-initial-state has no effect, \ - it has been replaced by -eva-msg-key=initial-state@]" - else - Kernel.warning "@[Option -no-val-show-initial-state has no effect, \ - it has been replaced by -eva-msg-key=-initial-state@]" - ) let () = Parameter_customize.set_group messages module ValShowPerf = False (struct let option_name = "-eva-show-perf" - let help = "Compute and shows a summary of the time spent analyzing function calls" + let help = "Compute and show a summary of the time spent analyzing function calls" end) -let () = ValShowPerf.add_aliases ["-val-show-perf"] let () = Parameter_customize.set_group messages module ValPerfFlamegraphs = String (struct let option_name = "-eva-flamegraph" - let help = "Dumps a summary of the time spent analyzing function calls \ + let help = "Dump a summary of the time spent analyzing function calls \ in a format suitable for the Flamegraph tool \ (http://www.brendangregg.com/flamegraphs.html)" let arg_name = "file" let default = "" end) -let () = ValPerfFlamegraphs.add_aliases ["-val-flamegraph"] let () = Parameter_customize.set_group messages @@ -1236,7 +1079,6 @@ module ShowSlevel = let arg_name = "n" let help = "Period for showing consumption of the alloted slevel during analysis" end) -let () = ShowSlevel.add_aliases ["-val-show-slevel"] let () = ShowSlevel.set_range ~min:1 ~max:max_int let () = Parameter_customize.set_group messages @@ -1246,35 +1088,6 @@ module PrintCallstacks = let option_name = "-eva-print-callstacks" let help = "When printing a message, also show the current call stack" end) -let () = PrintCallstacks.add_aliases ["-val-print-callstacks"] - -let () = Parameter_customize.set_group messages -let () = Parameter_customize.is_invisible () -module AlarmsWarnings = - True - (struct - let option_name = "-val-warn-on-alarms" - let help = "[DEPRECATED: use warning key alarm to manage alarms] \ - if set (default), possible alarms are printed in \ - the analysis log as warnings, otherwise as plain feedback" - end) - -let () = - AlarmsWarnings.add_set_hook - (fun _ f -> - match get_warn_status wkey_alarm with - | Log.Wabort | Log.Werror | Log.Werror_once -> - warning "alarms already set to produce an error. \ - Ignoring -val-warn-on-alarms" - | Log.Winactive | Log.Wactive | Log.Wfeedback -> - set_warn_status wkey_alarm (if f then Log.Wactive else Log.Wfeedback) - | Log.Wonce | Log.Wfeedback_once -> - (* Keep the 'once' status. Note that this will only happen if user - is mixing old and new style of warning management, thus it becomes - difficult to interpret the desired action. - *) - set_warn_status wkey_alarm - (if f then Log.Wonce else Log.Wfeedback_once)) let () = Parameter_customize.set_group messages module ReportRedStatuses = @@ -1283,7 +1096,7 @@ module ReportRedStatuses = let option_name = "-eva-report-red-statuses" let arg_name = "filename" let default = "" - let help = "output the list of \"red properties\" in a csv file of the \ + let help = "Output the list of \"red properties\" in a csv file of the \ given name. These are the properties which were invalid for \ some states. Their consolidated status may not be invalid, \ but they should often be investigated first." @@ -1294,7 +1107,7 @@ module NumerorsLogFile = String (struct let option_name = "-eva-numerors-log-file" - let help = "The Numerors Domain will save each call to the DPRINT \ + let help = "The Numerors domain will save each call to the DPRINT \ function in the given file" let arg_name = "file" let default = "" @@ -1312,36 +1125,6 @@ module InterpreterMode = let help = "Stop at first call to a library function, if main() has \ arguments, on undecided branches" end) -let () = InterpreterMode.add_aliases ["-val-interpreter-mode"] - -let () = Parameter_customize.set_group interpreter -let () = Parameter_customize.is_invisible () -module ObviouslyTerminatesFunctions = - Fundec_set - (struct - let option_name = "-obviously-terminates-function" - let arg_name = "f" - let help = "deprecated" - end) -let () = add_dep ObviouslyTerminatesFunctions.parameter -let () = ObviouslyTerminatesFunctions.add_update_hook - (fun _ _ -> - warning "Option -obviously-terminates-function is no longer supported. \ - Ignoring.") - -let () = Parameter_customize.set_group interpreter -let () = Parameter_customize.is_invisible () -module ObviouslyTerminatesAll = - False - (struct - let option_name = "-obviously-terminates" - let help = "undocumented and deprecated" - end) -let () = add_dep ObviouslyTerminatesAll.parameter -let () = ObviouslyTerminatesAll.add_update_hook - (fun _ _ -> - warning "Option -obviously-terminates is no longer supported. \ - Ignoring.") let () = Parameter_customize.set_group interpreter module StopAtNthAlarm = @@ -1349,9 +1132,9 @@ module StopAtNthAlarm = let option_name = "-eva-stop-at-nth-alarm" let default = max_int let arg_name = "n" - let help = "Aborts the analysis when the nth alarm is emitted." + let help = "Abort the analysis when the nth alarm is emitted." end) -let () = StopAtNthAlarm.add_aliases ["-val-stop-at-nth-alarm"] +let () = StopAtNthAlarm.set_range 0 max_int (* -------------------------------------------------------------------------- *) (* --- Ugliness required for correctness --- *) @@ -1402,6 +1185,7 @@ module OracleDepth = let default = 2 let arg_name = "" end) +let () = OracleDepth.set_range 0 max_int let () = add_precision_dep OracleDepth.parameter let () = Parameter_customize.set_group precision_tuning @@ -1414,6 +1198,7 @@ module ReductionDepth = let default = 4 let arg_name = "" end) +let () = ReductionDepth.set_range 0 max_int let () = add_precision_dep ReductionDepth.parameter @@ -1446,7 +1231,7 @@ module AllocFunctions = (struct let option_name = "-eva-alloc-functions" let arg_name = "f1,...,fn" - let help = "Controls call site creation for dynamically allocated bases. \ + let help = "Control call site creation for dynamically allocated bases. \ Dynamic allocation builtins use the call sites of \ malloc/calloc/realloc to know \ where to create new bases. This detection does not work for \ @@ -1455,7 +1240,6 @@ module AllocFunctions = By default, contains malloc, calloc and realloc." let default = Datatype.String.Set.of_list ["malloc"; "calloc"; "realloc"] end) -let () = AllocFunctions.add_aliases ["-val-malloc-functions"] let () = AllocFunctions.add_aliases ["-eva-malloc-functions"] let () = Parameter_customize.set_group malloc @@ -1466,7 +1250,7 @@ module AllocReturnsNull= let help = "Memory allocation built-ins (malloc, calloc, realloc) are \ modeled as nondeterministically returning a null pointer" end) -let () = AllocReturnsNull.add_aliases ["-val-alloc-returns-null"] +let () = add_correctness_dep AllocReturnsNull.parameter let () = Parameter_customize.set_group malloc module MallocLevel = @@ -1475,10 +1259,66 @@ module MallocLevel = let option_name = "-eva-mlevel" let default = 0 let arg_name = "m" - let help = "sets to [m] the number of precise dynamic allocations \ + let help = "Set to [m] the number of precise dynamic allocations \ besides the initial one, for each callstack (defaults to 0)" end) -let () = MallocLevel.add_aliases ["-val-mlevel"] +let () = MallocLevel.set_range 0 max_int +let () = add_precision_dep MallocLevel.parameter + +(* -------------------------------------------------------------------------- *) +(* --- Deprecated aliases --- *) +(* -------------------------------------------------------------------------- *) + +let deprecated_aliases : ((module Parameter_sig.S) * string) list = + [ (module SemanticUnrollingLevel), "-slevel" + ; (module SlevelFunction), "-slevel-function" + ; (module NoResultsFunctions), "-no-results-function" + ; (module ResultsAll), "-results" + ; (module JoinResults), "-val-join-results" + ; (module AllRoundingModesConstants), "-all-rounding-modes-constants" + ; (module UndefinedPointerComparisonPropagateAll), "-undefined-pointer-comparison-propagate-all" + ; (module WarnPointerComparison), "-val-warn-undefined-pointer-comparison" + ; (module WarnSignedConvertedDowncast), "-val-warn-signed-converted-downcast" + ; (module WarnPointerSubstraction), "-val-warn-pointer-subtraction" + ; (module IgnoreRecursiveCalls), "-val-ignore-recursive-calls" + ; (module WarnCopyIndeterminate), "-val-warn-copy-indeterminate" + ; (module ReduceOnLogicAlarms), "-val-reduce-on-logic-alarms" + ; (module InitializedLocals), "-val-initialized-locals" + ; (module AutomaticContextMaxDepth), "-context-depth" + ; (module AutomaticContextMaxWidth), "-context-width" + ; (module AllocatedContextValid), "-context-valid-pointers" + ; (module InitializationPaddingGlobals), "-val-initialization-padding-globals" + ; (module WideningDelay), "-wlevel" + ; (module SlevelMergeAfterLoop), "-val-slevel-merge-after-loop" + ; (module SplitReturnFunction), "-val-split-return-function" + ; (module SplitReturn), "-val-split-return" + ; (module ILevel), "-val-ilevel" + ; (module BuiltinsOverrides), "-val-builtin" + ; (module BuiltinsAuto), "-val-builtins-auto" + ; (module BuiltinsList), "-val-builtins-list" + ; (module LinearLevel), "-val-subdivide-non-linear" + ; (module UsePrototype), "-val-use-spec" + ; (module SkipLibcSpecs), "-val-skip-stdlib-specs" + ; (module RmAssert), "-remove-redundant-alarms" + ; (module MemExecAll), "-memexec-all" + ; (module ArrayPrecisionLevel), "-plevel" + ; (module ValShowProgress), "-val-show-progress" + ; (module ValShowPerf), "-val-show-perf" + ; (module ValPerfFlamegraphs), "-val-flamegraph" + ; (module ShowSlevel), "-val-show-slevel" + ; (module PrintCallstacks), "-val-print-callstacks" + ; (module InterpreterMode), "-val-interpreter-mode" + ; (module StopAtNthAlarm), "-val-stop-at-nth-alarm" + ; (module AllocFunctions), "-val-malloc-functions" + ; (module AllocReturnsNull), "-val-alloc-returns-null" + ; (module MallocLevel), "-val-mlevel" + ] + +let add_deprecated_alias ((module P: Parameter_sig.S), name) = + P.add_aliases ~visible:false ~deprecated:true [name] + +let () = List.iter add_deprecated_alias deprecated_aliases + (* -------------------------------------------------------------------------- *) (* --- Meta options --- *) diff --git a/src/plugins/value/value_parameters.mli b/src/plugins/value/value_parameters.mli index 495d7b1fa9a873b7736c2651944fe2a0f9843cf3..6e126920273e4ea41476063cae9e3dad627250ff 100644 --- a/src/plugins/value/value_parameters.mli +++ b/src/plugins/value/value_parameters.mli @@ -91,15 +91,6 @@ module ArrayPrecisionLevel: Parameter_sig.Int module AllocatedContextValid: Parameter_sig.Bool module InitializationPaddingGlobals: Parameter_sig.String -module SaveFunctionState: - Parameter_sig.Map with type key = Cil_types.kernel_function - and type value = string -module LoadFunctionState: - Parameter_sig.Map with type key = Cil_types.kernel_function - and type value = string -val get_SaveFunctionState : unit -> Cil_types.kernel_function * string -val get_LoadFunctionState : unit -> Cil_types.kernel_function * string - module Numerors_Real_Size : Parameter_sig.Int module Numerors_Mode : Parameter_sig.String @@ -131,12 +122,10 @@ module SplitReturnFunction: module SplitGlobalStrategy: State_builder.Ref with type data = Split_strategy.t module ValShowProgress: Parameter_sig.Bool -module ValShowInitialState: Parameter_sig.Bool module ValShowPerf: Parameter_sig.Bool module ValPerfFlamegraphs: Parameter_sig.String module ShowSlevel: Parameter_sig.Int module PrintCallstacks: Parameter_sig.Bool -module AlarmsWarnings: Parameter_sig.Bool module ReportRedStatuses: Parameter_sig.String module NumerorsLogFile: Parameter_sig.String diff --git a/src/plugins/variadic/tests/defined/multiple-va_start.c b/src/plugins/variadic/tests/defined/multiple-va_start.c index f10b950af4c838805aba204a01e12bd156170ff5..9a3ff2627482f4dafd5936536c0cca47f9c85bf0 100644 --- a/src/plugins/variadic/tests/defined/multiple-va_start.c +++ b/src/plugins/variadic/tests/defined/multiple-va_start.c @@ -1,5 +1,5 @@ /* run.config -STDOPT: +"-no-val-alloc-returns-null" +STDOPT: +"-eva-no-alloc-returns-null" */ diff --git a/src/plugins/variadic/tests/defined/va_copy.c b/src/plugins/variadic/tests/defined/va_copy.c index 3ad479a98de2c3ca4ad8c618d41f9c81fd0ac54f..129708fa9f349eddef4af0f3f4c241ea17a7987a 100644 --- a/src/plugins/variadic/tests/defined/va_copy.c +++ b/src/plugins/variadic/tests/defined/va_copy.c @@ -1,5 +1,5 @@ /* run.config -STDOPT: +"-no-val-alloc-returns-null" +STDOPT: +"-eva-no-alloc-returns-null" */ diff --git a/src/plugins/variadic/tests/test_config b/src/plugins/variadic/tests/test_config index 9d83090791bf7d3f4f62b2e69990d30fefd28fc8..e076935b23463006f8f89ffcddb93f7f2748c691 100644 --- a/src/plugins/variadic/tests/test_config +++ b/src/plugins/variadic/tests/test_config @@ -1 +1 @@ -OPT: -no-autoload-plugins -load-module from,inout,eva,variadic,scope -check -print -kernel-verbose 0 -variadic-verbose 2 -eva -slevel 10 -eva-msg-key=-initial-state,-summary -eva-no-show-progress -eva-print +OPT: -no-autoload-plugins -load-module from,inout,eva,variadic,scope -check -print -kernel-verbose 0 -variadic-verbose 2 -eva -eva-slevel 10 -eva-msg-key=-initial-state,-summary -eva-no-show-progress -eva-print diff --git a/tests/builtins/Longinit_sequencer.i b/tests/builtins/Longinit_sequencer.i deleted file mode 100644 index 919f247cf5d6fb7f63b2b76707794dbf2b09428a..0000000000000000000000000000000000000000 --- a/tests/builtins/Longinit_sequencer.i +++ /dev/null @@ -1,4 +0,0 @@ -/* run.config* - EXECNOW: make -s @PTEST_DIR@/@PTEST_NAME@.cmxs - OPT: @EVA_OPTIONS@ -load-module @PTEST_DIR@/@PTEST_NAME@.cmxs -res-file @PTEST_RESULT@ -*/ diff --git a/tests/builtins/Longinit_sequencer.ml b/tests/builtins/Longinit_sequencer.ml deleted file mode 100644 index e08e24d518d009ebab3543964451095e79f1f765..0000000000000000000000000000000000000000 --- a/tests/builtins/Longinit_sequencer.ml +++ /dev/null @@ -1,67 +0,0 @@ -(* Small script to test long_init*.c files, which require one test to run - before the other. *) - -open Kernel - -include Plugin.Register -(struct - let name = "long init testing module" - let shortname = "test-long-init" - let help = "utility script for tests" - end) - -module Res = String(struct - let option_name = "-res-file" - let help = "" - let arg_name = "file" - let default = "result" - end) - -let ok = ref false - -let tmpfile () = Res.get () ^ "/Longinit_sequencer.sav" - -let () = - at_exit (fun () -> - let tmpfile = tmpfile () in - if Debug.get () >= 1 || not !ok then - result "Keeping temp file %s" tmpfile - else - try Sys.remove tmpfile with Sys_error _ -> ()) - -let main () = - let tmpfile = tmpfile () in - let fmt = Format.std_formatter in - let display_results state = Format.fprintf fmt "@[%a@]@\n" !Db.Value.display state in - Dynamic.Parameter.String.set "" "tests/builtins/long_init.c"; - Dynamic.Parameter.String.set "-eva-save-fun-state" ("init_inner:" ^ tmpfile); - Dynamic.Parameter.String.set "-eva-alloc-builtin" "fresh"; - Dynamic.Parameter.Bool.set "-eva-alloc-returns-null" false; - Dynamic.Parameter.String.set "-eva-warn-key" "builtins:override=inactive"; - !Db.Value.compute (); - Callgraph.Uses.iter_in_rev_order display_results; - Files.clear (); - Dynamic.Parameter.String.set "" "tests/builtins/long_init2.c"; - (* clear and set parameters to the same value to recompute - kernel function IDs *) - Dynamic.Parameter.String.clear "-eva-save-fun-state" (); - Dynamic.Parameter.String.set "-eva-save-fun-state" ("init_outer:" ^ tmpfile); - Dynamic.Parameter.String.set "-eva-load-fun-state" ("init_inner:" ^ tmpfile); - (* set builtins in a different order to force kernel to recompute - kernel function IDs *) - Dynamic.Parameter.String.set "-eva-alloc-builtin" "fresh"; - !Db.Value.compute (); - Callgraph.Uses.iter_in_rev_order display_results; - Files.clear (); - Dynamic.Parameter.String.set "" "tests/builtins/long_init3.c"; - Dynamic.Parameter.String.clear "-eva-save-fun-state" (); - Dynamic.Parameter.String.clear "-eva-load-fun-state" (); - Dynamic.Parameter.String.set "-eva-load-fun-state" ("init_outer:" ^ tmpfile); - (* set builtins in a different order to force kernel to recompute - kernel function IDs *) - Dynamic.Parameter.String.set "-eva-alloc-builtin" "fresh"; - !Db.Value.compute (); - Callgraph.Uses.iter_in_rev_order display_results; - ok:=true (* no error, we can erase the file *) - -let () = Db.Main.extend main diff --git a/tests/builtins/allocated.c b/tests/builtins/allocated.c index b09b532881c9ef6a322b5ad7292035bbdfd3d66e..3015ea59f137e0993b6a6c5d782d1c38e07fb3c3 100644 --- a/tests/builtins/allocated.c +++ b/tests/builtins/allocated.c @@ -1,6 +1,6 @@ /* run.config* - STDOPT: +"-slevel 1 -eva-mlevel 0" - STDOPT: +"-slevel 999 -eva-alloc-builtin fresh" + STDOPT: +"-eva-slevel 1 -eva-mlevel 0" + STDOPT: +"-eva-slevel 999 -eva-alloc-builtin fresh" */ #define assert_bottom(exp) if (nondet) {exp; Frama_C_show_each_unreachable();} diff --git a/tests/builtins/gcc_zero_length_array.c b/tests/builtins/gcc_zero_length_array.c index b990a598b0e4f9c25888f70e5a482fa9dfc4757f..18d39c75f5f6b3902363c7cbff8fb3da2689e321 100644 --- a/tests/builtins/gcc_zero_length_array.c +++ b/tests/builtins/gcc_zero_length_array.c @@ -1,5 +1,5 @@ /* run.config* - STDOPT: +"-machdep gcc_x86_32 -eva-alloc-builtin fresh -slevel 11" + STDOPT: +"-machdep gcc_x86_32 -eva-alloc-builtin fresh -eva-slevel 11" */ #include <stdlib.h> diff --git a/tests/builtins/linked_list.c b/tests/builtins/linked_list.c index 8ae291e74744e1efa73304be82e7569309ae407f..dfa85bbfb98d8203d21c9e88aef1012bfc63a6f1 100644 --- a/tests/builtins/linked_list.c +++ b/tests/builtins/linked_list.c @@ -1,7 +1,7 @@ /* run.config* STDOPT: #"-load-module variadic -eva-no-builtins-auto" - STDOPT: #"-load-module variadic -plevel 100 -big-ints-hex 257 -eva-no-builtins-auto" - STDOPT: #"-load-module variadic -slevel 12 -big-ints-hex 257 -eva-no-builtins-auto" + STDOPT: #"-load-module variadic -eva-plevel 100 -big-ints-hex 257 -eva-no-builtins-auto" + STDOPT: #"-load-module variadic -eva-slevel 12 -big-ints-hex 257 -eva-no-builtins-auto" */ #include "__fc_define_size_t.h" diff --git a/tests/builtins/malloc-deps.c b/tests/builtins/malloc-deps.c index 312e2534df54f1c9d390c49abe5465673dc598cb..1bb43e5021c1eb4b3d88ff639219613a9f099871 100644 --- a/tests/builtins/malloc-deps.c +++ b/tests/builtins/malloc-deps.c @@ -1,5 +1,5 @@ /* run.config* - OPT: -eva @EVA_CONFIG@ -deps -calldeps -inout -slevel 5 -eva-msg-key malloc + OPT: -eva @EVA_CONFIG@ -deps -calldeps -inout -eva-slevel 5 -eva-msg-key malloc */ #include <stdlib.h> diff --git a/tests/builtins/malloc-optimistic.c b/tests/builtins/malloc-optimistic.c index d5a922355cef26fc4fd6fd482771381ce6dea6ba..8b2a9551ec09b64cec7500533acb4043d6d4df68 100644 --- a/tests/builtins/malloc-optimistic.c +++ b/tests/builtins/malloc-optimistic.c @@ -1,5 +1,5 @@ /* run.config* - STDOPT: +"-slevel 30 -eva-slevel-merge-after-loop @all -eva-memexec" + STDOPT: +"-eva-slevel 30 -eva-slevel-merge-after-loop @all -eva-memexec" */ #include <stddef.h> //@ assigns \result \from \nothing; diff --git a/tests/builtins/malloc.c b/tests/builtins/malloc.c index fb9377fa0041f543e133230dab5ca534fcc32b61..989d36b908624a16151ca3120929f4bce1961862 100644 --- a/tests/builtins/malloc.c +++ b/tests/builtins/malloc.c @@ -1,5 +1,5 @@ /* run.config* - OPT: -eva @EVA_CONFIG@ -slevel 10 -eva-mlevel 0 -eva-alloc-builtin by_stack + OPT: -eva @EVA_CONFIG@ -eva-slevel 10 -eva-mlevel 0 -eva-alloc-builtin by_stack */ #include <stdlib.h> diff --git a/tests/builtins/malloc_multiple.c b/tests/builtins/malloc_multiple.c index 6c807d486a22e8a16f05c7447c7342a1fe0d8f18..81e2a9cc9f717679e7e98ff2047b2c5360f23bdc 100644 --- a/tests/builtins/malloc_multiple.c +++ b/tests/builtins/malloc_multiple.c @@ -1,5 +1,5 @@ /* run.config* - OPT: -eva @EVA_CONFIG@ -slevel 50 -eva-mlevel 5 + OPT: -eva @EVA_CONFIG@ -eva-slevel 50 -eva-mlevel 5 */ #include<stdlib.h> #define MAX 10 diff --git a/tests/builtins/memcpy.c b/tests/builtins/memcpy.c index 3b438a803377db9cfbd9a59047e0389b70807c0d..97d2feee02e28b3480fb59d201ccdef64954943e 100644 --- a/tests/builtins/memcpy.c +++ b/tests/builtins/memcpy.c @@ -1,5 +1,5 @@ /* run.config* - STDOPT: +"-calldeps -slevel-function init:2000 -eva-msg-key imprecision -plevel 150 -main main_all -inout -no-deps -absolute-valid-range 100000-100001 -then -load-module report -report" + STDOPT: +"-calldeps -eva-slevel-function init:2000 -eva-msg-key imprecision -eva-plevel 150 -main main_all -inout -no-deps -absolute-valid-range 100000-100001 -then -load-module report -report" */ #include "string.h" diff --git a/tests/builtins/memset.c b/tests/builtins/memset.c index 2cbdd6386c6b0dddcd8e89164c9bc57d1e9d6e1b..bb8f0dfe496fc13e55f5da853a8c84c7c4f858f1 100644 --- a/tests/builtins/memset.c +++ b/tests/builtins/memset.c @@ -1,5 +1,5 @@ /* run.config* - STDOPT: #"-calldeps -eva-msg-key imprecision -plevel 500" +"-inout -no-deps" + STDOPT: #"-calldeps -eva-msg-key imprecision -eva-plevel 500" +"-inout -no-deps" */ #include "string.h" diff --git a/tests/builtins/oracle/Longinit_sequencer.res.oracle b/tests/builtins/oracle/Longinit_sequencer.res.oracle deleted file mode 100644 index c07049acaa7e5c069d9802a28b3ea799f330be44..0000000000000000000000000000000000000000 --- a/tests/builtins/oracle/Longinit_sequencer.res.oracle +++ /dev/null @@ -1,733 +0,0 @@ -[kernel] Parsing tests/builtins/Longinit_sequencer.i (no preprocessing) -[kernel] Parsing tests/builtins/long_init.c (with preprocessing) -[eva] Analyzing a complete application starting at main -[eva] Computing initial state -[eva:alarm] tests/builtins/long_init.c:34: Warning: - pointer downcast. assert (unsigned int)"abc" ≤ 127; -[eva] Initial state computed -[eva:initial-state] Values of globals at initialization - nondet ∈ [--..--] - a1[0..9] ∈ {0} - stuff ∈ {0} - garbled_mix ∈ {{ "abc" }} - s ∈ {{ "abc" }} - pr ∈ {0} - pr2 ∈ {0} - pr_escaping ∈ {0} - ppr ∈ {0} - alloc1 ∈ {0} - alloc2 ∈ {0} - alloc3 ∈ {0} - fp ∈ {{ &fun }} - inited ∈ {0} -[eva] computing for function init_outer <- main. - Called from tests/builtins/long_init.c:90. -[eva] computing for function init_inner <- init_outer <- main. - Called from tests/builtins/long_init.c:85. -[eva] tests/builtins/long_init.c:61: starting to merge loop iterations -[eva] computing for function analyze <- init_inner <- init_outer <- main. - Called from tests/builtins/long_init.c:68. -[eva] computing for function subanalyze <- analyze <- init_inner <- init_outer <- - main. - Called from tests/builtins/long_init.c:29. -[eva] Recording results for subanalyze -[eva] Done for function subanalyze -[eva] computing for function subanalyze <- analyze <- init_inner <- init_outer <- - main. - Called from tests/builtins/long_init.c:29. -[eva] Recording results for subanalyze -[eva] Done for function subanalyze -[eva] computing for function subanalyze <- analyze <- init_inner <- init_outer <- - main. - Called from tests/builtins/long_init.c:29. -[eva] Recording results for subanalyze -[eva] Done for function subanalyze -[eva] computing for function subanalyze <- analyze <- init_inner <- init_outer <- - main. - Called from tests/builtins/long_init.c:29. -[eva] Recording results for subanalyze -[eva] Done for function subanalyze -[eva] computing for function subanalyze <- analyze <- init_inner <- init_outer <- - main. - Called from tests/builtins/long_init.c:29. -[eva] Recording results for subanalyze -[eva] Done for function subanalyze -[eva] Recording results for analyze -[eva] Done for function analyze -[eva] computing for function analyze <- init_inner <- init_outer <- main. - Called from tests/builtins/long_init.c:69. -[eva] tests/builtins/long_init.c:29: Reusing old results for call to subanalyze -[eva] tests/builtins/long_init.c:29: Reusing old results for call to subanalyze -[eva] tests/builtins/long_init.c:29: Reusing old results for call to subanalyze -[eva] tests/builtins/long_init.c:29: Reusing old results for call to subanalyze -[eva] computing for function subanalyze <- analyze <- init_inner <- init_outer <- - main. - Called from tests/builtins/long_init.c:29. -[eva] Recording results for subanalyze -[eva] Done for function subanalyze -[eva] Recording results for analyze -[eva] Done for function analyze -[eva] tests/builtins/long_init.c:73: Call to builtin malloc -[eva] tests/builtins/long_init.c:73: allocating variable __malloc_init_inner_l73 -[eva:alarm] tests/builtins/long_init.c:74: Warning: - pointer downcast. assert (unsigned int)alloc1 ≤ 2147483647; -[eva] tests/builtins/long_init.c:75: Call to builtin malloc -[eva] tests/builtins/long_init.c:75: allocating variable __malloc_init_inner_l75 -[eva] tests/builtins/long_init.c:77: Call to builtin free -[eva] tests/builtins/long_init.c:77: - function free: precondition 'freeable' got status valid. -[eva:malloc] tests/builtins/long_init.c:77: - strong free on bases: {__malloc_init_inner_l75} -[eva] Recording results for init_inner -[eva] Done for function init_inner -[eva:locals-escaping] tests/builtins/long_init.c:85: Warning: - locals {r, r2} escaping the scope of init_inner through pr -[eva:locals-escaping] tests/builtins/long_init.c:85: Warning: - locals {r2} escaping the scope of init_inner through pr2 -[eva:locals-escaping] tests/builtins/long_init.c:85: Warning: - locals {r2} escaping the scope of init_inner through pr_escaping -[eva] Recording results for init_outer -[eva] Done for function init_outer -[eva] tests/builtins/long_init.c:92: - Frama_C_dump_each: - # Cvalue domain: - __fc_heap_status ∈ [--..--] - __fc_random_counter ∈ [--..--] - __fc_rand_max ∈ {32767} - __fc_random48_init ∈ {0} - __fc_random48_counter[0..2] ∈ [--..--] - __fc_p_random48_counter ∈ {{ &__fc_random48_counter[0] }} - __fc_env[0] ∈ {{ NULL ; &S_0___fc_env[0] }} - [1] ∈ {{ NULL ; &S_1___fc_env[0] }} - [2..4095] ∈ {{ NULL ; &S_0___fc_env[0] ; &S_1___fc_env[0] }} - __fc_mblen_state ∈ [--..--] - __fc_mbtowc_state ∈ [--..--] - __fc_wctomb_state ∈ [--..--] - nondet ∈ [--..--] - a1[0] ∈ {0} - [1] ∈ {1} - [2] ∈ {2} - [3] ∈ {3} - [4] ∈ {4} - [5] ∈ {5} - [6] ∈ {6} - [7] ∈ {7} - [8] ∈ {8} - [9] ∈ {9} - stuff.t[0..4] ∈ {3} - .t[5..9] ∈ {4} - .t[10..49] ∈ [0..12] - .d[0] ∈ {0} - .d[1] ∈ {3.125} - .d[2] ∈ {6.25} - .d[3] ∈ {9.375} - .d[4] ∈ {12.5} - .d[5] ∈ {15.625} - .d[6] ∈ {18.75} - .d[7] ∈ {21.875} - .d[8] ∈ {25.} - .d[9] ∈ {28.125} - garbled_mix ∈ {{ "abc" }} - s ∈ {{ "abc" }} - pr ∈ ESCAPINGADDR - pr2 ∈ ESCAPINGADDR - pr_escaping ∈ ESCAPINGADDR - ppr ∈ {0} - alloc1 ∈ {{ &__malloc_init_inner_l73 }} - alloc2 ∈ ESCAPINGADDR - alloc3 ∈ {0} - fp ∈ {{ &fun }} - inited ∈ {1} - sa ∈ {{ "abc" }} - tmp_2 ∈ UNINITIALIZED - __retres ∈ UNINITIALIZED - S_0___fc_env[0..1] ∈ [--..--] - S_1___fc_env[0..1] ∈ [--..--] - __malloc_init_inner_l73 ∈ {{ (int)&__malloc_init_inner_l73 }} - ==END OF DUMP== -[eva] tests/builtins/long_init.c:93: Reusing old results for call to analyze -[eva] tests/builtins/long_init.c:94: Reusing old results for call to analyze -[eva] computing for function dmin <- main. - Called from tests/builtins/long_init.c:98. -[eva] Recording results for dmin -[eva] Done for function dmin -[eva] computing for function fun <- main. - Called from tests/builtins/long_init.c:99. -[eva] Recording results for fun -[eva] Done for function fun -[eva] tests/builtins/long_init.c:103: Call to builtin free -[eva] tests/builtins/long_init.c:103: - function free: precondition 'freeable' got status valid. -[eva:malloc] tests/builtins/long_init.c:103: - strong free on bases: {__malloc_init_inner_l73} -[eva] tests/builtins/long_init.c:104: Call to builtin malloc -[eva] tests/builtins/long_init.c:104: allocating variable __malloc_main_l104 -[eva] Recording results for main -[eva] done for function main -[eva] tests/builtins/long_init.c:34: - cannot evaluate ACSL term, unsupported ACSL construct: constant strings -[eva] Saving globals state after call to function: init_inner -Values at end of function dmin: - __retres ∈ [93.9166666667 .. 110.791666667] - - -Values at end of function fun: - __retres ∈ {32} - - -Values at end of function subanalyze: - - -Values at end of function analyze: - i ∈ {5} - res ∈ [93.9166666667 .. 110.791666667] - -Values at end of function init_inner: - __fc_heap_status ∈ [--..--] - a1[0] ∈ {0} - [1] ∈ {1} - [2] ∈ {2} - [3] ∈ {3} - [4] ∈ {4} - [5] ∈ {5} - [6] ∈ {6} - [7] ∈ {7} - [8] ∈ {8} - [9] ∈ {9} - stuff.t[0..4] ∈ {3} - .t[5..9] ∈ {4} - .t[10..49] ∈ [0..12] - .d[0] ∈ {0} - .d[1] ∈ {3.125} - .d[2] ∈ {6.25} - .d[3] ∈ {9.375} - .d[4] ∈ {12.5} - .d[5] ∈ {15.625} - .d[6] ∈ {18.75} - .d[7] ∈ {21.875} - .d[8] ∈ {25.} - .d[9] ∈ {28.125} - pr ∈ {{ &r ; &r2 }} - pr2 ∈ {{ &r2 }} - pr_escaping ∈ {{ &r2 }} - alloc1 ∈ {{ &__malloc_init_inner_l73 }} - alloc2 ∈ ESCAPINGADDR - i ∈ {10} - r ∈ {93.9166666667} - r2 ∈ {110.791666667} - __malloc_init_inner_l73 ∈ {{ (int)&__malloc_init_inner_l73 }} - -Values at end of function init_outer: - __fc_heap_status ∈ [--..--] - a1[0] ∈ {0} - [1] ∈ {1} - [2] ∈ {2} - [3] ∈ {3} - [4] ∈ {4} - [5] ∈ {5} - [6] ∈ {6} - [7] ∈ {7} - [8] ∈ {8} - [9] ∈ {9} - stuff.t[0..4] ∈ {3} - .t[5..9] ∈ {4} - .t[10..49] ∈ [0..12] - .d[0] ∈ {0} - .d[1] ∈ {3.125} - .d[2] ∈ {6.25} - .d[3] ∈ {9.375} - .d[4] ∈ {12.5} - .d[5] ∈ {15.625} - .d[6] ∈ {18.75} - .d[7] ∈ {21.875} - .d[8] ∈ {25.} - .d[9] ∈ {28.125} - pr ∈ ESCAPINGADDR - pr2 ∈ ESCAPINGADDR - pr_escaping ∈ ESCAPINGADDR - alloc1 ∈ {{ &__malloc_init_inner_l73 }} - alloc2 ∈ ESCAPINGADDR - inited ∈ {1} - __malloc_init_inner_l73 ∈ {{ (int)&__malloc_init_inner_l73 }} - -Values at end of function main: - __fc_heap_status ∈ [--..--] - a1[0] ∈ {0} - [1] ∈ {1} - [2] ∈ {2} - [3] ∈ {3} - [4] ∈ {4} - [5] ∈ {5} - [6] ∈ {6} - [7] ∈ {7} - [8] ∈ {8} - [9] ∈ {9} - stuff.t[0..4] ∈ {3} - .t[5..9] ∈ {4} - .t[10..49] ∈ [0..12] - .d[0] ∈ {0} - .d[1] ∈ {3.125} - .d[2] ∈ {6.25} - .d[3] ∈ {9.375} - .d[4] ∈ {12.5} - .d[5] ∈ {15.625} - .d[6] ∈ {18.75} - .d[7] ∈ {21.875} - .d[8] ∈ {25.} - .d[9] ∈ {28.125} - pr ∈ {{ &r ; &r2 }} - pr2 ∈ {{ &r ; &r2 }} - pr_escaping ∈ ESCAPINGADDR - ppr ∈ {{ &pr ; &pr2 }} - alloc1 ∈ ESCAPINGADDR - alloc2 ∈ ESCAPINGADDR - alloc3 ∈ {{ &__malloc_main_l104 }} - inited ∈ {1} - sa ∈ {{ "abc" }} - r ∈ {93.9166666667} - r2 ∈ {110.791666667} - dm ∈ [93.9166666667 .. 110.791666667] - res_from_fp ∈ {32} - res ∈ {93} - local ∈ {1} - __retres ∈ {0}[kernel] Parsing tests/builtins/long_init2.c (with preprocessing) -[eva] Analyzing a complete application starting at main -[eva] Computing initial state -[eva:alarm] tests/builtins/long_init2.c:34: Warning: - pointer downcast. assert (unsigned int)"abc" ≤ 127; -[eva] Initial state computed -[eva:initial-state] Values of globals at initialization - nondet ∈ [--..--] - a1[0..9] ∈ {0} - stuff ∈ {0} - garbled_mix ∈ {{ "abc" }} - s ∈ {{ "abc" }} - another_global ∈ {42} - pr ∈ {0} - pr2 ∈ {0} - pr_escaping ∈ {0} - ppr ∈ {0} - alloc1 ∈ {0} - alloc2 ∈ {0} - alloc3 ∈ {0} - fp ∈ {{ &fun }} - inited ∈ {0} -[eva] computing for function init_outer <- main. - Called from tests/builtins/long_init2.c:90. -[eva] tests/builtins/long_init2.c:85: - Call to builtin Frama_C_load_state for function init_inner -[eva] Skipping call to init_inner, loading globals state from file: - tests/builtins/result/Longinit_sequencer.sav -[eva] Warning: variable `r' is not global, possibly an escaping value; ignoring -[eva] Warning: variable `r2' is not global, possibly an escaping value; ignoring -[eva] Warning: variable `r2' is not global, possibly an escaping value; ignoring -[eva] Warning: found new global variable `another_global' -[eva] Recording results for init_outer -[eva] Done for function init_outer -[eva] tests/builtins/long_init2.c:92: - Frama_C_dump_each: - # Cvalue domain: - __fc_heap_status ∈ [--..--] - __fc_random_counter ∈ [--..--] - __fc_rand_max ∈ {32767} - __fc_random48_init ∈ {0} - __fc_random48_counter[0..2] ∈ [--..--] - __fc_p_random48_counter ∈ {{ &__fc_random48_counter[0] }} - __fc_env[0] ∈ {{ NULL ; &S_0___fc_env[0] }} - [1] ∈ {{ NULL ; &S_1___fc_env[0] }} - [2..4095] ∈ {{ NULL ; &S_0___fc_env[0] ; &S_1___fc_env[0] }} - __fc_mblen_state ∈ [--..--] - __fc_mbtowc_state ∈ [--..--] - __fc_wctomb_state ∈ [--..--] - nondet ∈ [--..--] - a1[0] ∈ {0} - [1] ∈ {1} - [2] ∈ {2} - [3] ∈ {3} - [4] ∈ {4} - [5] ∈ {5} - [6] ∈ {6} - [7] ∈ {7} - [8] ∈ {8} - [9] ∈ {9} - stuff.t[0..4] ∈ {3} - .t[5..9] ∈ {4} - .t[10..49] ∈ [0..12] - .d[0] ∈ {0} - .d[1] ∈ {3.125} - .d[2] ∈ {6.25} - .d[3] ∈ {9.375} - .d[4] ∈ {12.5} - .d[5] ∈ {15.625} - .d[6] ∈ {18.75} - .d[7] ∈ {21.875} - .d[8] ∈ {25.} - .d[9] ∈ {28.125} - garbled_mix ∈ {{ "abc" }} - s ∈ {{ "abc" }} - another_global ∈ {42} - pr ∈ ESCAPINGADDR - pr2 ∈ ESCAPINGADDR - pr_escaping ∈ ESCAPINGADDR - ppr ∈ {0} - alloc1 ∈ {{ &__malloc_init_inner_l73 }} - alloc2 ∈ ESCAPINGADDR - alloc3 ∈ {0} - fp ∈ {{ &fun }} - inited ∈ {1} - sa ∈ {{ "abc" }} - tmp_2 ∈ UNINITIALIZED - __retres ∈ UNINITIALIZED - S_0___fc_env[0..1] ∈ [--..--] - S_1___fc_env[0..1] ∈ [--..--] - __malloc_init_inner_l73 ∈ {{ (int)&__malloc_init_inner_l73 }} - ==END OF DUMP== -[eva] computing for function analyze <- main. - Called from tests/builtins/long_init2.c:93. -[eva] computing for function subanalyze <- analyze <- main. - Called from tests/builtins/long_init2.c:29. -[eva] Recording results for subanalyze -[eva] Done for function subanalyze -[eva] computing for function subanalyze <- analyze <- main. - Called from tests/builtins/long_init2.c:29. -[eva] Recording results for subanalyze -[eva] Done for function subanalyze -[eva] computing for function subanalyze <- analyze <- main. - Called from tests/builtins/long_init2.c:29. -[eva] Recording results for subanalyze -[eva] Done for function subanalyze -[eva] computing for function subanalyze <- analyze <- main. - Called from tests/builtins/long_init2.c:29. -[eva] Recording results for subanalyze -[eva] Done for function subanalyze -[eva] computing for function subanalyze <- analyze <- main. - Called from tests/builtins/long_init2.c:29. -[eva] Recording results for subanalyze -[eva] Done for function subanalyze -[eva] Recording results for analyze -[eva] Done for function analyze -[eva] computing for function analyze <- main. - Called from tests/builtins/long_init2.c:94. -[eva] tests/builtins/long_init2.c:29: Reusing old results for call to subanalyze -[eva] tests/builtins/long_init2.c:29: Reusing old results for call to subanalyze -[eva] tests/builtins/long_init2.c:29: Reusing old results for call to subanalyze -[eva] tests/builtins/long_init2.c:29: Reusing old results for call to subanalyze -[eva] computing for function subanalyze <- analyze <- main. - Called from tests/builtins/long_init2.c:29. -[eva] Recording results for subanalyze -[eva] Done for function subanalyze -[eva] Recording results for analyze -[eva] Done for function analyze -[eva] computing for function dmin <- main. - Called from tests/builtins/long_init2.c:98. -[eva] Recording results for dmin -[eva] Done for function dmin -[eva] computing for function fun <- main. - Called from tests/builtins/long_init2.c:99. -[eva] Recording results for fun -[eva] Done for function fun -[eva] tests/builtins/long_init2.c:103: Call to builtin free -[eva] tests/builtins/long_init2.c:103: - function free: precondition 'freeable' got status valid. -[eva:malloc] tests/builtins/long_init2.c:103: - strong free on bases: {__malloc_init_inner_l73} -[eva] tests/builtins/long_init2.c:104: Call to builtin malloc -[eva] tests/builtins/long_init2.c:104: allocating variable __malloc_main_l104 -[eva] Recording results for main -[eva] done for function main -[eva] tests/builtins/long_init2.c:34: - cannot evaluate ACSL term, unsupported ACSL construct: constant strings -[eva] Saving globals state after call to function: init_outer - - -Values at end of function dmin: - __retres ∈ [93.9166666667 .. 110.791666667] - - -Values at end of function fun: - __retres ∈ {32} - - -Values at end of function init_outer: - a1[0] ∈ {0} - [1] ∈ {1} - [2] ∈ {2} - [3] ∈ {3} - [4] ∈ {4} - [5] ∈ {5} - [6] ∈ {6} - [7] ∈ {7} - [8] ∈ {8} - [9] ∈ {9} - stuff.t[0..4] ∈ {3} - .t[5..9] ∈ {4} - .t[10..49] ∈ [0..12] - .d[0] ∈ {0} - .d[1] ∈ {3.125} - .d[2] ∈ {6.25} - .d[3] ∈ {9.375} - .d[4] ∈ {12.5} - .d[5] ∈ {15.625} - .d[6] ∈ {18.75} - .d[7] ∈ {21.875} - .d[8] ∈ {25.} - .d[9] ∈ {28.125} - pr ∈ ESCAPINGADDR - pr2 ∈ ESCAPINGADDR - pr_escaping ∈ ESCAPINGADDR - alloc1 ∈ {{ &__malloc_init_inner_l73 }} - alloc2 ∈ ESCAPINGADDR - inited ∈ {1} - - -Values at end of function subanalyze: - - -Values at end of function analyze: - i ∈ {5} - res ∈ [93.9166666667 .. 110.791666667] - -Values at end of function main: - __fc_heap_status ∈ [--..--] - a1[0] ∈ {0} - [1] ∈ {1} - [2] ∈ {2} - [3] ∈ {3} - [4] ∈ {4} - [5] ∈ {5} - [6] ∈ {6} - [7] ∈ {7} - [8] ∈ {8} - [9] ∈ {9} - stuff.t[0..4] ∈ {3} - .t[5..9] ∈ {4} - .t[10..49] ∈ [0..12] - .d[0] ∈ {0} - .d[1] ∈ {3.125} - .d[2] ∈ {6.25} - .d[3] ∈ {9.375} - .d[4] ∈ {12.5} - .d[5] ∈ {15.625} - .d[6] ∈ {18.75} - .d[7] ∈ {21.875} - .d[8] ∈ {25.} - .d[9] ∈ {28.125} - pr ∈ {{ &r ; &r2 }} - pr2 ∈ {{ &r ; &r2 }} - pr_escaping ∈ ESCAPINGADDR - ppr ∈ {{ &pr ; &pr2 }} - alloc1 ∈ ESCAPINGADDR - alloc2 ∈ ESCAPINGADDR - alloc3 ∈ {{ &__malloc_main_l104 }} - inited ∈ {1} - sa ∈ {{ "abc" }} - r ∈ {93.9166666667} - r2 ∈ {110.791666667} - dm ∈ [93.9166666667 .. 110.791666667] - res_from_fp ∈ {32} - res ∈ {93} - local ∈ {42} - __retres ∈ {0}[kernel] Parsing tests/builtins/long_init3.c (with preprocessing) -[eva] Analyzing a complete application starting at main -[eva] Computing initial state -[eva:alarm] tests/builtins/long_init3.c:34: Warning: - pointer downcast. assert (unsigned int)"abc" ≤ 127; -[eva] Initial state computed -[eva:initial-state] Values of globals at initialization - nondet ∈ [--..--] - a1[0..9] ∈ {0} - stuff ∈ {0} - garbled_mix ∈ {{ "abc" }} - s ∈ {{ "abc" }} - another_global ∈ {42} - yet_another_global ∈ {43} - pr ∈ {0} - pr2 ∈ {0} - pr_escaping ∈ {0} - ppr ∈ {0} - alloc1 ∈ {0} - alloc2 ∈ {0} - alloc3 ∈ {0} - fp ∈ {{ &fun }} - inited ∈ {0} -[eva] tests/builtins/long_init3.c:90: - Call to builtin Frama_C_load_state for function init_outer -[eva] Skipping call to init_outer, loading globals state from file: - tests/builtins/result/Longinit_sequencer.sav -[eva] Warning: found new global variable `yet_another_global' -[eva] tests/builtins/long_init3.c:92: - Frama_C_dump_each: - # Cvalue domain: - __fc_heap_status ∈ [--..--] - __fc_random_counter ∈ [--..--] - __fc_rand_max ∈ {32767} - __fc_random48_init ∈ {0} - __fc_random48_counter[0..2] ∈ [--..--] - __fc_p_random48_counter ∈ {{ &__fc_random48_counter[0] }} - __fc_env[0] ∈ {{ NULL ; &S_0___fc_env[0] }} - [1] ∈ {{ NULL ; &S_1___fc_env[0] }} - [2..4095] ∈ {{ NULL ; &S_0___fc_env[0] ; &S_1___fc_env[0] }} - __fc_mblen_state ∈ [--..--] - __fc_mbtowc_state ∈ [--..--] - __fc_wctomb_state ∈ [--..--] - nondet ∈ [--..--] - a1[0] ∈ {0} - [1] ∈ {1} - [2] ∈ {2} - [3] ∈ {3} - [4] ∈ {4} - [5] ∈ {5} - [6] ∈ {6} - [7] ∈ {7} - [8] ∈ {8} - [9] ∈ {9} - stuff.t[0..4] ∈ {3} - .t[5..9] ∈ {4} - .t[10..49] ∈ [0..12] - .d[0] ∈ {0} - .d[1] ∈ {3.125} - .d[2] ∈ {6.25} - .d[3] ∈ {9.375} - .d[4] ∈ {12.5} - .d[5] ∈ {15.625} - .d[6] ∈ {18.75} - .d[7] ∈ {21.875} - .d[8] ∈ {25.} - .d[9] ∈ {28.125} - garbled_mix ∈ {{ "abc" }} - s ∈ {{ "abc" }} - another_global ∈ {42} - yet_another_global ∈ {43} - pr ∈ ESCAPINGADDR - pr2 ∈ ESCAPINGADDR - pr_escaping ∈ ESCAPINGADDR - ppr ∈ {0} - alloc1 ∈ {{ &__malloc_init_inner_l73 }} - alloc2 ∈ ESCAPINGADDR - alloc3 ∈ {0} - fp ∈ {{ &fun }} - inited ∈ {1} - sa ∈ {{ "abc" }} - tmp_2 ∈ UNINITIALIZED - __retres ∈ UNINITIALIZED - S_0___fc_env[0..1] ∈ [--..--] - S_1___fc_env[0..1] ∈ [--..--] - __malloc_init_inner_l73 ∈ {{ (int)&__malloc_init_inner_l73 }} - ==END OF DUMP== -[eva] computing for function analyze <- main. - Called from tests/builtins/long_init3.c:93. -[eva] computing for function subanalyze <- analyze <- main. - Called from tests/builtins/long_init3.c:29. -[eva] Recording results for subanalyze -[eva] Done for function subanalyze -[eva] computing for function subanalyze <- analyze <- main. - Called from tests/builtins/long_init3.c:29. -[eva] Recording results for subanalyze -[eva] Done for function subanalyze -[eva] computing for function subanalyze <- analyze <- main. - Called from tests/builtins/long_init3.c:29. -[eva] Recording results for subanalyze -[eva] Done for function subanalyze -[eva] computing for function subanalyze <- analyze <- main. - Called from tests/builtins/long_init3.c:29. -[eva] Recording results for subanalyze -[eva] Done for function subanalyze -[eva] computing for function subanalyze <- analyze <- main. - Called from tests/builtins/long_init3.c:29. -[eva] Recording results for subanalyze -[eva] Done for function subanalyze -[eva] Recording results for analyze -[eva] Done for function analyze -[eva] computing for function analyze <- main. - Called from tests/builtins/long_init3.c:94. -[eva] tests/builtins/long_init3.c:29: Reusing old results for call to subanalyze -[eva] tests/builtins/long_init3.c:29: Reusing old results for call to subanalyze -[eva] tests/builtins/long_init3.c:29: Reusing old results for call to subanalyze -[eva] tests/builtins/long_init3.c:29: Reusing old results for call to subanalyze -[eva] computing for function subanalyze <- analyze <- main. - Called from tests/builtins/long_init3.c:29. -[eva] Recording results for subanalyze -[eva] Done for function subanalyze -[eva] Recording results for analyze -[eva] Done for function analyze -[eva] computing for function dmin <- main. - Called from tests/builtins/long_init3.c:98. -[eva] Recording results for dmin -[eva] Done for function dmin -[eva] computing for function fun <- main. - Called from tests/builtins/long_init3.c:99. -[eva] Recording results for fun -[eva] Done for function fun -[eva] tests/builtins/long_init3.c:103: Call to builtin free -[eva] tests/builtins/long_init3.c:103: - function free: precondition 'freeable' got status valid. -[eva:malloc] tests/builtins/long_init3.c:103: - strong free on bases: {__malloc_init_inner_l73} -[eva] tests/builtins/long_init3.c:104: Call to builtin malloc -[eva] tests/builtins/long_init3.c:104: allocating variable __malloc_main_l104 -[eva] Recording results for main -[eva] done for function main -[eva] tests/builtins/long_init3.c:34: - cannot evaluate ACSL term, unsupported ACSL construct: constant strings - - -Values at end of function dmin: - __retres ∈ [93.9166666667 .. 110.791666667] - - -Values at end of function fun: - __retres ∈ {32} - - - - -Values at end of function subanalyze: - - -Values at end of function analyze: - i ∈ {5} - res ∈ [93.9166666667 .. 110.791666667] - -Values at end of function main: - __fc_heap_status ∈ [--..--] - a1[0] ∈ {0} - [1] ∈ {1} - [2] ∈ {2} - [3] ∈ {3} - [4] ∈ {4} - [5] ∈ {5} - [6] ∈ {6} - [7] ∈ {7} - [8] ∈ {8} - [9] ∈ {9} - stuff.t[0..4] ∈ {3} - .t[5..9] ∈ {4} - .t[10..49] ∈ [0..12] - .d[0] ∈ {0} - .d[1] ∈ {3.125} - .d[2] ∈ {6.25} - .d[3] ∈ {9.375} - .d[4] ∈ {12.5} - .d[5] ∈ {15.625} - .d[6] ∈ {18.75} - .d[7] ∈ {21.875} - .d[8] ∈ {25.} - .d[9] ∈ {28.125} - pr ∈ {{ &r ; &r2 }} - pr2 ∈ {{ &r ; &r2 }} - pr_escaping ∈ ESCAPINGADDR - ppr ∈ {{ &pr ; &pr2 }} - alloc1 ∈ ESCAPINGADDR - alloc2 ∈ ESCAPINGADDR - alloc3 ∈ {{ &__malloc_main_l104 }} - inited ∈ {1} - sa ∈ {{ "abc" }} - r ∈ {93.9166666667} - r2 ∈ {110.791666667} - dm ∈ [93.9166666667 .. 110.791666667] - res_from_fp ∈ {32} - res ∈ {93} - local ∈ {42} - local2 ∈ {43} - __retres ∈ {0} - diff --git a/tests/builtins/realloc.c b/tests/builtins/realloc.c index 77b69e12e8cb4c541f63607aa0e74f438c74bb10..bb11b50a7a742bc565e774e73a1fb06614a3c025 100644 --- a/tests/builtins/realloc.c +++ b/tests/builtins/realloc.c @@ -1,5 +1,5 @@ /* run.config* - STDOPT: +"-slevel 10 -eva-alloc-builtin by_stack -eva-warn-copy-indeterminate @all" + STDOPT: +"-eva-slevel 10 -eva-alloc-builtin by_stack -eva-warn-copy-indeterminate @all" */ #include <stdlib.h> diff --git a/tests/builtins/realloc2.c b/tests/builtins/realloc2.c index 6614f80f06f487e9e7e554c4f8bbb3651c1ccb46..3636bd1ea2aabd007dea12859d0cdc44c069b87e 100644 --- a/tests/builtins/realloc2.c +++ b/tests/builtins/realloc2.c @@ -1,5 +1,5 @@ /* run.config* - STDOPT: #"-eva-mlevel 0 -inout-callwise -inout-no-print " + STDOPT: #"-eva-mlevel 0 -inout-no-print " */ #include <stdlib.h> diff --git a/tests/builtins/realloc_multiple.c b/tests/builtins/realloc_multiple.c index 1e5825544465ea4e4bc1ffee2f459fdbb5a5ef05..f5ceb25223f231da7434d019c3ddbca738ff6925 100644 --- a/tests/builtins/realloc_multiple.c +++ b/tests/builtins/realloc_multiple.c @@ -1,6 +1,6 @@ /* run.config* - STDOPT: +"-slevel 10 -eva-alloc-builtin fresh -eva-malloc-functions malloc,realloc" - STDOPT: +"-slevel 10 -eva-alloc-builtin fresh -eva-malloc-functions malloc,realloc -eva-alloc-returns-null" + STDOPT: +"-eva-slevel 10 -eva-alloc-builtin fresh -eva-alloc-functions malloc,realloc" + STDOPT: +"-eva-slevel 10 -eva-alloc-builtin fresh -eva-alloc-functions malloc,realloc -eva-alloc-returns-null" */ #include <stdlib.h> #include "__fc_builtin.h" diff --git a/tests/builtins/vla.c b/tests/builtins/vla.c index 1bfefb182d06e2679293d8d33e3554699c84ebdf..8e8c0eaaad38f34dc565f043ee5dccb8aa962b0a 100644 --- a/tests/builtins/vla.c +++ b/tests/builtins/vla.c @@ -1,5 +1,5 @@ /* run.config* - STDOPT: #"-slevel 10 -eva-builtins-auto" + STDOPT: #"-eva-slevel 10 -eva-builtins-auto" */ void f(int i) { diff --git a/tests/float/const3.i b/tests/float/const3.i index e4bbf48c12d42cb84187e6d84c89c9c3d513f7ee..4e06fb90429a435a24a5ca0d21bbe6d7bb7a307c 100644 --- a/tests/float/const3.i +++ b/tests/float/const3.i @@ -1,6 +1,6 @@ /* run.config* STDOPT: #"-warn-decimal-float all" - STDOPT: #"-warn-decimal-float all -all-rounding-modes-constants -float-hex" + STDOPT: #"-warn-decimal-float all -eva-all-rounding-modes-constants -float-hex" */ double f1 = 1e-40f; diff --git a/tests/float/const4.i b/tests/float/const4.i index 0a2be77cb0a4cd47298e3221d20b0e40eba2d0dc..605bad01de2fd3490a144ba6fc2f01c551ed731f 100644 --- a/tests/float/const4.i +++ b/tests/float/const4.i @@ -1,6 +1,6 @@ /* run.config* STDOPT: #"-warn-decimal-float all" - STDOPT: #"-warn-decimal-float all -all-rounding-modes-constants" + STDOPT: #"-warn-decimal-float all -eva-all-rounding-modes-constants" */ double f1 = 3.4e38f; diff --git a/tests/float/dr.i b/tests/float/dr.i index 8c2a6c88e235ce2ee009b2016a1176d877dcfe37..b3322030be3ae533c195c498cb48389105283c45 100644 --- a/tests/float/dr.i +++ b/tests/float/dr.i @@ -1,7 +1,7 @@ /* run.config* STDOPT: STDOPT: #"-float-hex" - STDOPT: #"-all-rounding-modes-constants" + STDOPT: #"-eva-all-rounding-modes-constants" */ float big = 100e30f; diff --git a/tests/float/extract_bits.i b/tests/float/extract_bits.i index 2f1c3b541cf97a2988bad93da7b58dca27a567bf..083727447193a64d526f1560c853c0a34b6c084e 100644 --- a/tests/float/extract_bits.i +++ b/tests/float/extract_bits.i @@ -1,6 +1,6 @@ /* run.config* - OPT: -eva @EVA_CONFIG@ -slevel 10 -big-ints-hex 0 -machdep ppc_32 -float-normal -warn-decimal-float all - OPT: -eva @EVA_CONFIG@ -slevel 10 -big-ints-hex 0 -machdep x86_32 -float-normal -warn-decimal-float all + OPT: -eva @EVA_CONFIG@ -eva-slevel 10 -big-ints-hex 0 -machdep ppc_32 -float-normal -warn-decimal-float all + OPT: -eva @EVA_CONFIG@ -eva-slevel 10 -big-ints-hex 0 -machdep x86_32 -float-normal -warn-decimal-float all */ float f = 3.14; diff --git a/tests/float/nonlin.c b/tests/float/nonlin.c index 4d258f382ae1e2e040e0e55988c3b6a782ca1b64..d210fe4a31538f2594517d4668c813392b557e6b 100644 --- a/tests/float/nonlin.c +++ b/tests/float/nonlin.c @@ -1,10 +1,10 @@ /* run.config* - OPT: -eva-msg-key nonlin -slevel 30 -eva @EVA_CONFIG@ -cpp-extra-args="-DFLOAT=double" -float-hex -journal-disable -eva-subdivide-non-linear 0 - OPT: -eva-msg-key nonlin -slevel 30 -eva @EVA_CONFIG@ -cpp-extra-args="-DFLOAT=double" -float-hex -journal-disable -eva-subdivide-non-linear 10 - OPT: -eva-msg-key nonlin -slevel 30 -eva @EVA_CONFIG@ -cpp-extra-args="-DFLOAT=double" -float-hex -journal-disable -eva-subdivide-non-linear 10 -warn-special-float none - OPT: -eva-msg-key nonlin -slevel 30 -eva @EVA_CONFIG@ -cpp-extra-args="-DFLOAT=float" -float-hex -journal-disable -eva-subdivide-non-linear 0 - OPT: -eva-msg-key nonlin -slevel 30 -eva @EVA_CONFIG@ -cpp-extra-args="-DFLOAT=float" -float-hex -journal-disable -eva-subdivide-non-linear 10 - OPT: -eva-msg-key nonlin -slevel 30 -eva @EVA_CONFIG@ -cpp-extra-args="-DFLOAT=float" -float-hex -journal-disable -eva-subdivide-non-linear 10 -warn-special-float none + OPT: -eva-msg-key nonlin -eva-slevel 30 -eva @EVA_CONFIG@ -cpp-extra-args="-DFLOAT=double" -float-hex -journal-disable -eva-subdivide-non-linear 0 + OPT: -eva-msg-key nonlin -eva-slevel 30 -eva @EVA_CONFIG@ -cpp-extra-args="-DFLOAT=double" -float-hex -journal-disable -eva-subdivide-non-linear 10 + OPT: -eva-msg-key nonlin -eva-slevel 30 -eva @EVA_CONFIG@ -cpp-extra-args="-DFLOAT=double" -float-hex -journal-disable -eva-subdivide-non-linear 10 -warn-special-float none + OPT: -eva-msg-key nonlin -eva-slevel 30 -eva @EVA_CONFIG@ -cpp-extra-args="-DFLOAT=float" -float-hex -journal-disable -eva-subdivide-non-linear 0 + OPT: -eva-msg-key nonlin -eva-slevel 30 -eva @EVA_CONFIG@ -cpp-extra-args="-DFLOAT=float" -float-hex -journal-disable -eva-subdivide-non-linear 10 + OPT: -eva-msg-key nonlin -eva-slevel 30 -eva @EVA_CONFIG@ -cpp-extra-args="-DFLOAT=float" -float-hex -journal-disable -eva-subdivide-non-linear 10 -warn-special-float none */ #include "__fc_builtin.h" diff --git a/tests/float/precise_cos_sin.c b/tests/float/precise_cos_sin.c index 19fde982cfb2f8367bf5c8b2c201a61dec312b8b..f6e6f36e9077b0036d3ebd983c20cc6a0e5f4eb0 100644 --- a/tests/float/precise_cos_sin.c +++ b/tests/float/precise_cos_sin.c @@ -1,5 +1,5 @@ /* run.config* - OPT: -eva @EVA_CONFIG@ -slevel 1000 -journal-disable -float-normal + OPT: -eva @EVA_CONFIG@ -eva-slevel 1000 -journal-disable -float-normal */ #include <__fc_builtin.h> diff --git a/tests/float/round10d.i b/tests/float/round10d.i index a11f0172affbc62e6d6e3c270aa8887463b70d62..1d6ebe39de506c8e31fe6ea441ba25cfbd408cbd 100644 --- a/tests/float/round10d.i +++ b/tests/float/round10d.i @@ -1,5 +1,5 @@ /* run.config* - OPT: -eva @EVA_CONFIG@ -float-normal -journal-disable -no-results + OPT: -eva @EVA_CONFIG@ -float-normal -journal-disable -eva-no-results */ int main() diff --git a/tests/float/some.c b/tests/float/some.c index d7713ce8d71d088a7ba48407e83dfc02d1901648..8eb3f38ea73da66b5c52a6779382e274a9a6a3ee 100644 --- a/tests/float/some.c +++ b/tests/float/some.c @@ -1,6 +1,6 @@ /* run.config* - OPT: -eva-show-slevel 10 -slevel 100 -eva @EVA_CONFIG@ -cpp-extra-args="-DFLOAT=double -DN=55" -float-normal -journal-disable -no-results - OPT: -slevel 100 -eva @EVA_CONFIG@ -cpp-extra-args="-DFLOAT=float -DN=26" -float-normal -journal-disable -no-results + OPT: -eva-show-slevel 10 -eva-slevel 100 -eva @EVA_CONFIG@ -cpp-extra-args="-DFLOAT=double -DN=55" -float-normal -journal-disable -eva-no-results + OPT: -eva-slevel 100 -eva @EVA_CONFIG@ -cpp-extra-args="-DFLOAT=float -DN=26" -float-normal -journal-disable -eva-no-results */ FLOAT t[N] = { 1. } ; diff --git a/tests/float/sqrt.c b/tests/float/sqrt.c index 02a8d3995c82eddf9ff4ccc105a5652f10113a7a..da6743b0866b14d00ea51c2886806bc546008c96 100644 --- a/tests/float/sqrt.c +++ b/tests/float/sqrt.c @@ -1,6 +1,6 @@ /* run.config* - STDOPT: #"-slevel 10 -big-ints-hex 257" - STDOPT: #"-slevel 10 -big-ints-hex 257 -machdep ppc_32" + STDOPT: #"-eva-slevel 10 -big-ints-hex 257" + STDOPT: #"-eva-slevel 10 -big-ints-hex 257 -machdep ppc_32" */ #include <math.h> diff --git a/tests/float/widen.c b/tests/float/widen.c index 8ad29d4d152106a1e0431b2e410abdd38a783694..c685b88be02d1fea3968895deb8f5587c021a88f 100644 --- a/tests/float/widen.c +++ b/tests/float/widen.c @@ -1,6 +1,6 @@ /* run.config* - STDOPT: #"-warn-special-float non-finite -wlevel 3" - STDOPT: #"-warn-special-float none -wlevel 3" + STDOPT: #"-warn-special-float non-finite -eva-widening-delay 3" + STDOPT: #"-warn-special-float none -eva-widening-delay 3" */ volatile int rand; diff --git a/tests/idct/ieee_1180_1990.c b/tests/idct/ieee_1180_1990.c index 6c5b0285d74841904ecffe54670abca54e6c0b93..d0dce5401ae9737d1baa182b6bbd0bd2d46f4209 100644 --- a/tests/idct/ieee_1180_1990.c +++ b/tests/idct/ieee_1180_1990.c @@ -1,6 +1,6 @@ /* run.config* GCC: - STDOPT: +"-eva-msg-key=summary -load-module report,scope,variadic -float-normal -no-warn-signed-overflow tests/idct/idct.c -remove-redundant-alarms -eva-memexec -eva-builtin sqrt:Frama_C_sqrt,cos:Frama_C_cos -then -report -report-print-properties" + STDOPT: +"-eva-msg-key=summary -load-module report,scope,variadic -float-normal -no-warn-signed-overflow tests/idct/idct.c -eva-remove-redundant-alarms -eva-memexec -eva-builtin sqrt:Frama_C_sqrt,cos:Frama_C_cos -then -report -report-print-properties" */ /* IEEE_1180_1990: a testbed for IDCT accuracy * Copyright (C) 2001 Renaud Pacalet diff --git a/tests/impact/alias.i b/tests/impact/alias.i index f1cc091ed52634e22d631e54007aef47f741febe..1b4edfb05d19133efb9ed8b7154bdd0dce8041cd 100644 --- a/tests/impact/alias.i +++ b/tests/impact/alias.i @@ -1,5 +1,5 @@ /* run.config - STDOPT: +"-impact-pragma f" +"-lib-entry" +"-main f" +"-remove-redundant-alarms" + STDOPT: +"-impact-pragma f" +"-lib-entry" +"-main f" +"-eva-remove-redundant-alarms" */ int P,c; diff --git a/tests/jcdb/compile_commands.json b/tests/jcdb/compile_commands.json index 52a0f039c5ba20d81bf77a3dd803b8579d285c75..0592cf2b0799160bb9d83ce1b7aa103c2fc15b7c 100644 --- a/tests/jcdb/compile_commands.json +++ b/tests/jcdb/compile_commands.json @@ -7,12 +7,12 @@ "command": "g++ -DDUPLICATE_FLAGS_THAT_WILL_BE_OVERWRITTEN", "file": "jcdb.c" }, - { "directory": ".", - "command": "/usr/bin/clang++ -D'MSG=\"a \\\" \\\"b\"' -D'SINGLE_DOUBLE(a)=\"a \\\"with spaces and tab \"' -DSOMEDEF=\"With spaces, quotes and \\-es.\" -D\"DOUBLE_SINGLE(a)=a \\\"macro with spaces and non-escaped \\\\'\\\"\" -DEMPTY='' -DEMPTY2= -DTEST=42 -D'MACRO_FOR_INCR(s)=s+1' -DTOUNDEF -UTOUNDEF", + { + "command": "testing entry without 'directory' key -DFLAG_TO_BE_FORGOTTEN", "file": "jcdb.c" }, - { - "command": "testing entry without 'directory' key", + { "directory": ".", + "command": "/usr/bin/clang++ -D'MSG=\"a \\\" \\\"b\"' -D'SINGLE_DOUBLE(a)=\"a \\\"with spaces and tab \"' -DSOMEDEF=\"With spaces, quotes and \\-es.\" -D\"DOUBLE_SINGLE(a)=a \\\"macro with spaces and non-escaped \\\\'\\\"\" -DEMPTY='' -DEMPTY2= -DTEST=42 -D'MACRO_FOR_INCR(s)=s+1' -DTOUNDEF -UTOUNDEF", "file": "jcdb.c" } ] diff --git a/tests/jcdb/jcdb.ml b/tests/jcdb/jcdb.ml index 4d0408048a1f47720c6605ccf9fdeb18669e8f57..d9163defa210d991acf8362bd59ac34d9f9c57ac 100644 --- a/tests/jcdb/jcdb.ml +++ b/tests/jcdb/jcdb.ml @@ -1,8 +1,8 @@ let print_json () = Kernel.feedback - "Value of -json-compilation-database in %s is %s" + "Value of -json-compilation-database in %s is %a" (Project.get_name (Project.current())) - (Kernel.JsonCompilationDatabase.get()) + Filepath.Normalized.pretty (Kernel.JsonCompilationDatabase.get()) let run () = print_json (); diff --git a/tests/jcdb/oracle/jcdb.0.res.oracle b/tests/jcdb/oracle/jcdb.0.res.oracle index 1a80090d55b0c602628524a47fa26ba90e0cf493..aca498a1f0268f3109f7298d7a4bf3fd11a6d37d 100644 --- a/tests/jcdb/oracle/jcdb.0.res.oracle +++ b/tests/jcdb/oracle/jcdb.0.res.oracle @@ -1,6 +1,6 @@ [kernel:pp:compilation-db] Warning: found duplicate flags for 'tests/jcdb/jcdb.c', replacing old flags. - Old flags no longer present: -D'MSG="a \" \"b"' -D'SINGLE_DOUBLE(a)="a \"with spaces and tab "' -DSOMEDEF="With spaces, quotes and \-es." -D"DOUBLE_SINGLE(a)=a \"macro with spaces and non-escaped \\'\"" -DEMPTY='' -DEMPTY2= -DTEST=42 -D'MACRO_FOR_INCR(s)=s+1' -DTOUNDEF -UTOUNDEF + Old flags no longer present: -DFLAG_TO_BE_FORGOTTEN New flags not previously present: -DDUPLICATE_FLAGS_THAT_WILL_BE_OVERWRITTEN (warn-once: no further messages from category 'pp:compilation-db' will be emitted) [kernel] Parsing tests/jcdb/jcdb.c (with preprocessing) diff --git a/tests/libc/coverage.c b/tests/libc/coverage.c index 2fa988b1e5dc0edf41ab46dd4743b4a77b728a36..342d79af62894d72d30d5a03c8e9c215baf37229 100644 --- a/tests/libc/coverage.c +++ b/tests/libc/coverage.c @@ -1,5 +1,5 @@ /* run.config* - OPT: -eva-no-builtins-auto @EVA_OPTIONS@ share/libc/string.c -eva -slevel 6 -metrics-eva-cover -then -metrics-libc + OPT: -eva-no-builtins-auto @EVA_OPTIONS@ share/libc/string.c -eva -eva-slevel 6 -metrics-eva-cover -then -metrics-libc */ #include "string.h" diff --git a/tests/libc/ctype.c b/tests/libc/ctype.c index a874a223d2888bdcbd9b35573a073beae5a94a42..a54bd13b6a3e38d4186600899a89e5bdf886a15b 100644 --- a/tests/libc/ctype.c +++ b/tests/libc/ctype.c @@ -1,5 +1,5 @@ /* run.config - STDOPT: #"-slevel 4" + STDOPT: #"-eva-slevel 4" */ #include <stdio.h> #include <ctype.h> diff --git a/tests/libc/netdb_c.c b/tests/libc/netdb_c.c index 6e8f905b5d80c9afc8f77fadc6e5de394469710c..c2f9a8c9d3440b2ab3533704693e336e39164350 100644 --- a/tests/libc/netdb_c.c +++ b/tests/libc/netdb_c.c @@ -1,5 +1,5 @@ /*run.config - STDOPT: #"-eva-split-return auto -slevel 2" + STDOPT: #"-eva-split-return auto -eva-slevel 2" */ // Extract based on Linux Programmer's Manual, GETADDRINFO(3) man page #include <sys/types.h> diff --git a/tests/libc/signal_h.c b/tests/libc/signal_h.c index f8aa063de2edf99c21e12b0d14a974e35ab24b0c..c0d539f925a32964ca7764d56389e9467bf68d3d 100644 --- a/tests/libc/signal_h.c +++ b/tests/libc/signal_h.c @@ -1,5 +1,5 @@ /* run.config - STDOPT: #"-slevel 2" + STDOPT: #"-eva-slevel 2" */ #include <signal.h> diff --git a/tests/libc/stdlib_c.c b/tests/libc/stdlib_c.c index d1dbd85a5a3e9ed1ac0f06f6f455c15bd8006039..33dc8110214a11851008f465801601bf39f23e1b 100644 --- a/tests/libc/stdlib_c.c +++ b/tests/libc/stdlib_c.c @@ -1,6 +1,6 @@ /* run.config - STDOPT: #"-eva-no-builtins-auto -slevel 10 -eva-builtin calloc:Frama_C_calloc -eva-alloc-builtin by_stack -eva-msg-key malloc" - STDOPT: #"-eva-no-builtins-auto -slevel 10 -eva-builtin calloc:Frama_C_calloc -eva-alloc-builtin by_stack -eva-no-alloc-returns-null -eva-msg-key malloc" + STDOPT: #"-eva-no-builtins-auto -eva-slevel 10 -eva-builtin calloc:Frama_C_calloc -eva-alloc-builtin by_stack -eva-msg-key malloc" + STDOPT: #"-eva-no-builtins-auto -eva-slevel 10 -eva-builtin calloc:Frama_C_calloc -eva-alloc-builtin by_stack -eva-no-alloc-returns-null -eva-msg-key malloc" STDOPT: #"-eva-no-builtins-auto" */ // slevel is used to unroll loops diff --git a/tests/libc/string_c.c b/tests/libc/string_c.c index 05e5dc7c140cd844555e21f6bfb9dbbdd56a3635..e5bff29eaf38398b3cf99d6cddebd238e1d08fc0 100644 --- a/tests/libc/string_c.c +++ b/tests/libc/string_c.c @@ -1,5 +1,5 @@ /* run.config - STDOPT: #"-eva-no-builtins-auto -slevel 1000 -eva-no-skip-stdlib-specs" + STDOPT: #"-eva-no-builtins-auto -eva-slevel 1000 -eva-no-skip-stdlib-specs" */ // slevel is used to unroll loops #include "string.c" diff --git a/tests/libc/string_c_generic.c b/tests/libc/string_c_generic.c index 9168f43d7369f9d476d037a417f24a713326f6c4..4470a3d07b525b8b4e45e785be34dd8d5dcfa151 100644 --- a/tests/libc/string_c_generic.c +++ b/tests/libc/string_c_generic.c @@ -1,5 +1,5 @@ /* run.config - STDOPT: #"-eva-no-builtins-auto -cpp-extra-args=-includeshare/libc/string.c -slevel-function strcpy:20,strncpy:5,strcmp:6,strchr:20,strrchr:20,strncat:4,memset:32,strlen:20,memcmp:8 -eva-no-skip-stdlib-specs" + STDOPT: #"-eva-no-builtins-auto -cpp-extra-args=-includeshare/libc/string.c -eva-slevel-function strcpy:20,strncpy:5,strcmp:6,strchr:20,strrchr:20,strncat:4,memset:32,strlen:20,memcmp:8 -eva-no-skip-stdlib-specs" */ /* This file has been adapted from libc-test, which is licensed under the following standard MIT license: diff --git a/tests/libc/string_c_strchr.c b/tests/libc/string_c_strchr.c index 54ed8fab06ee3065c2a13d88a927732181b67b38..83ea787bc73c2df126834751d060407781a888b1 100644 --- a/tests/libc/string_c_strchr.c +++ b/tests/libc/string_c_strchr.c @@ -1,5 +1,5 @@ /* run.config - STDOPT: #"-cpp-extra-args=-includeshare/libc/string.c -slevel-function strchr:256,main:256 -eva-slevel-merge-after-loop main -eva-no-builtins-auto -eva-no-skip-stdlib-specs" + STDOPT: #"-cpp-extra-args=-includeshare/libc/string.c -eva-slevel-function strchr:256,main:256 -eva-slevel-merge-after-loop main -eva-no-builtins-auto -eva-no-skip-stdlib-specs" */ /* This file has been adapted from libc-test, which is licensed under the following standard MIT license: diff --git a/tests/libc/string_c_strstr.c b/tests/libc/string_c_strstr.c index 9f0613b351594afcadd9c41bc092315d666f320e..3dd1d13d8904d0e92b9b44ca207323abdd1715f6 100644 --- a/tests/libc/string_c_strstr.c +++ b/tests/libc/string_c_strstr.c @@ -1,5 +1,5 @@ /* run.config - STDOPT: #"-cpp-extra-args=-includeshare/libc/string.c -slevel-function strstr:30 -eva-no-skip-stdlib-specs" + STDOPT: #"-cpp-extra-args=-includeshare/libc/string.c -eva-slevel-function strstr:30 -eva-no-skip-stdlib-specs" */ /* This file has been adapted from libc-test, which is licensed under the following standard MIT license: diff --git a/tests/libc/sys_stat_h.c b/tests/libc/sys_stat_h.c index 65ddbfc889097a4af94054d53d6bdac3dc8a428c..24a4b3335118005af0fc3e28cfd303f9d32a1b7e 100644 --- a/tests/libc/sys_stat_h.c +++ b/tests/libc/sys_stat_h.c @@ -1,5 +1,5 @@ /*run.config - STDOPT: #"-slevel 2" + STDOPT: #"-eva-slevel 2" */ #include <sys/stat.h> #include <fcntl.h> diff --git a/tests/libc/sys_wait_h.c b/tests/libc/sys_wait_h.c index 9eec66c206b1cf766f568412161746f6c6576255..0fe9b221ce15d3d053c1dcccfbe1bbf98007212e 100644 --- a/tests/libc/sys_wait_h.c +++ b/tests/libc/sys_wait_h.c @@ -1,5 +1,5 @@ /* run.config - STDOPT: #"-slevel 4" + STDOPT: #"-eva-slevel 4" */ #include <sys/wait.h> diff --git a/tests/libc/termios.c b/tests/libc/termios.c index 6ba105607a2194a45ec1f905eadd6c9dfa0727a8..78100d57f84a221223fb79f5d0bbf1f2558699c1 100644 --- a/tests/libc/termios.c +++ b/tests/libc/termios.c @@ -1,5 +1,5 @@ /* run.config* - STDOPT: +"-slevel 2" + STDOPT: +"-eva-slevel 2" */ #include <termios.h> #include <fcntl.h> diff --git a/tests/libc/time_h.c b/tests/libc/time_h.c index c56c8ef3b96cdefead7c20068c10df481f78ba28..30db0860b50e42b76f98891bfd19e15bd06b8d86 100644 --- a/tests/libc/time_h.c +++ b/tests/libc/time_h.c @@ -1,5 +1,5 @@ /* run.config - STDOPT: #"-slevel 4" + STDOPT: #"-eva-slevel 4" */ #include <time.h> diff --git a/tests/libc/unistd_h.c b/tests/libc/unistd_h.c index 8c3104215bf71005b84e6d834a103ebe75056110..8f0f40681fda9b3925c1fc47c67b7fc35893b381 100644 --- a/tests/libc/unistd_h.c +++ b/tests/libc/unistd_h.c @@ -1,6 +1,6 @@ /*run.config - STDOPT: #"-slevel 12" #"-val-split-return auto" - STDOPT: #"-variadic-no-translation" #"-slevel 12" #"-val-split-return auto" + STDOPT: #"-eva-slevel 12" #"-eva-split-return auto" + STDOPT: #"-variadic-no-translation" #"-eva-slevel 12" #"-eva-split-return auto" */ #define _GNU_SOURCE #define _XOPEN_SOURCE 600 diff --git a/tests/libc/wchar_c_h.c b/tests/libc/wchar_c_h.c index ff2b3f2a7d1855818d0732ce7f70aa47fd13be19..8dadb46e2f8bf6ed9d7b3339bb0b193e6a4a08b8 100644 --- a/tests/libc/wchar_c_h.c +++ b/tests/libc/wchar_c_h.c @@ -1,6 +1,6 @@ /* run.config - STDOPT: +"-cpp-extra-args=-DTEST_IMPLEMENTATION=1" +"-slevel 1000" - STDOPT: +"-slevel 1000" + STDOPT: +"-cpp-extra-args=-DTEST_IMPLEMENTATION=1" +"-eva-slevel 1000" + STDOPT: +"-eva-slevel 1000" COMMENT: slevel is used to ensure all loops are unrolled (including in the COMMENT: implementation). 'goto exit' avoids recomputing split branches. */ diff --git a/tests/misc/issue109.i b/tests/misc/issue109.i index e6d7a20671adcc1bc1e8fd39bb40fec6d3986a45..3d9d35c81d6a7ba665b909e1634f71e3af5289a6 100644 --- a/tests/misc/issue109.i +++ b/tests/misc/issue109.i @@ -1,6 +1,6 @@ /* run.config EXECNOW: make -s @PTEST_DIR@/@PTEST_NAME@.cmxs - OPT: -eva @EVA_CONFIG@ -slevel-function main:10 -load-module @PTEST_DIR@/@PTEST_NAME@.cmxs + OPT: -eva @EVA_CONFIG@ -eva-slevel-function main:10 -load-module @PTEST_DIR@/@PTEST_NAME@.cmxs */ void main() { int i, j = 0; diff --git a/tests/misc/log_selfrec.i b/tests/misc/log_selfrec.i new file mode 100644 index 0000000000000000000000000000000000000000..f65505058bbf38d898556e25d04c0ff4d7b3ee35 --- /dev/null +++ b/tests/misc/log_selfrec.i @@ -0,0 +1,3 @@ +/* run.config + OPT: -foobar -report-unclassified-error jazz +*/ diff --git a/tests/misc/oracle/log_selfrec.res.oracle b/tests/misc/oracle/log_selfrec.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..a6950e931a0ec56f8a87657fbc4d32fd71e54c8d --- /dev/null +++ b/tests/misc/oracle/log_selfrec.res.oracle @@ -0,0 +1,5 @@ +[report] Monitoring events +[kernel] User Error: option `-foobar' is unknown. + use `bin/toplevel.opt -help' for more information. +[report] User Error: Invalid action ("JAZZ") +[kernel] Plug-in report aborted: invalid user input. diff --git a/tests/misc/widen_hints.c b/tests/misc/widen_hints.c index 9791791713a0969b77c7df865881d4d485122d32..e4f063807c12972b188952fa735a10024d17c844 100644 --- a/tests/misc/widen_hints.c +++ b/tests/misc/widen_hints.c @@ -1,7 +1,7 @@ /* run.config OPT: -eva @EVA_CONFIG@ -cpp-extra-args=-DSYNTAX_ERRORS -kernel-warn-key=annot-error=active OPT: -eva @EVA_CONFIG@ -cpp-extra-args=-DNONCONST - OPT: -eva @EVA_CONFIG@ -slevel 1 -eva-msg-key widen-hints + OPT: -eva @EVA_CONFIG@ -eva-slevel 1 -eva-msg-key widen-hints OPT: -eva @EVA_CONFIG@ -cpp-extra-args=-DALLGLOBAL -eva-msg-key widen-hints */ #define N 2 diff --git a/tests/misc/widen_hints_float.c b/tests/misc/widen_hints_float.c index db243cd089d58c8bd1eed80efc483b44fd8ec6fc..a01f0a357842a423528cc508dfc39663b307f0a8 100644 --- a/tests/misc/widen_hints_float.c +++ b/tests/misc/widen_hints_float.c @@ -1,5 +1,5 @@ /* run.config* - STDOPT: #"-val-subdivide-non-linear 20" + STDOPT: #"-eva-subdivide-non-linear 20" */ diff --git a/tests/pdg/top_pdg_input.c b/tests/pdg/top_pdg_input.c index 7a0e2f57246d1bb5247027af4152bb4142fbe4ff..1fa9bc5856422277ce593946c82f6b026885afe5 100644 --- a/tests/pdg/top_pdg_input.c +++ b/tests/pdg/top_pdg_input.c @@ -1,5 +1,5 @@ /* run.config - STDOPT: +"-eva -pdg -out -input -deps -no-results-function no_results -eva-no-builtins-auto -load-module pdg -pdg -then -main main_asm" + STDOPT: +"-eva -pdg -out -input -deps -eva-no-results-function no_results -eva-no-builtins-auto -load-module pdg -pdg -then -main main_asm" */ volatile int nondet; int no_results() {return 1;} diff --git a/tests/scope/bts383.c b/tests/scope/bts383.c index db156cbcfc2619ecba73c24ce6c579bdeec6daee..1f9c07e1e441d144e289dbb78e776694a126d944 100644 --- a/tests/scope/bts383.c +++ b/tests/scope/bts383.c @@ -1,5 +1,5 @@ /* run.config - OPT: -eva @EVA_CONFIG@ -print -journal-disable -scope-verbose 1 -remove-redundant-alarms -context-width 3 + OPT: -eva @EVA_CONFIG@ -print -journal-disable -scope-verbose 1 -eva-remove-redundant-alarms -eva-context-width 3 */ /* echo '!Db.Scope.check_asserts();;' \ diff --git a/tests/scope/no-effect.i b/tests/scope/no-effect.i index 47f41d8fb6b43f9b3a8da29ecc200377f28d7d1b..7b75f9e1d9f28d1b4893aa62a97fa4c8ca2eb3a7 100644 --- a/tests/scope/no-effect.i +++ b/tests/scope/no-effect.i @@ -1,5 +1,5 @@ /* run.config - OPT: @EVA_CONFIG@ -eva -print -journal-disable -scope-verbose 1 -remove-redundant-alarms + OPT: @EVA_CONFIG@ -eva -print -journal-disable -scope-verbose 1 -eva-remove-redundant-alarms */ typedef struct { diff --git a/tests/slicing/if_many_values.i b/tests/slicing/if_many_values.i index 11bf03bc16c2907a4eb2eb466a28e8bac5de15d6..55807dadf286d3685bc3ee45af146cde7b69d55c 100644 --- a/tests/slicing/if_many_values.i +++ b/tests/slicing/if_many_values.i @@ -1,5 +1,5 @@ /* run.config - STDOPT: +"-slice-value r -journal-disable -slevel 101 -then-on 'Slicing export' -set-project-as-default -print -check -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -check -no-deps" + STDOPT: +"-slice-value r -journal-disable -eva-slevel 101 -then-on 'Slicing export' -set-project-as-default -print -check -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -check -no-deps" **/ int r=1; diff --git a/tests/slicing/keep_annot.i b/tests/slicing/keep_annot.i index ae570853dfd277f7d4d21ce5cd9431a8ffa98a79..adbfac557cdd72ec714389f10b6ff0cd2d834f07 100644 --- a/tests/slicing/keep_annot.i +++ b/tests/slicing/keep_annot.i @@ -1,8 +1,8 @@ /* run.config - STDOPT: +"-context-valid-pointers -lib-entry -main f -slice-assert f -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -no-deps" - STDOPT: +"-context-valid-pointers -lib-entry -main f -slice-assert f -slicing-keep-annotations -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -no-deps" - STDOPT: +"-context-valid-pointers -lib-entry -main L -slice-pragma L -slicing-keep-annotations -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -no-deps" - STDOPT: +"-context-valid-pointers -lib-entry -main L -slice-pragma L -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -no-deps" + STDOPT: +"-eva-context-valid-pointers -lib-entry -main f -slice-assert f -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -no-deps" + STDOPT: +"-eva-context-valid-pointers -lib-entry -main f -slice-assert f -slicing-keep-annotations -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -no-deps" + STDOPT: +"-eva-context-valid-pointers -lib-entry -main L -slice-pragma L -slicing-keep-annotations -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -no-deps" + STDOPT: +"-eva-context-valid-pointers -lib-entry -main L -slice-pragma L -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -no-deps" STDOPT: +"-slice-return bts1110 -main bts1110 -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -no-deps" diff --git a/tests/slicing/unravel-variance.i b/tests/slicing/unravel-variance.i index e30a4aebcb2fa7acd21f6d33caa29b6cfa798426..554c7a94398639cd00d2809946b0248bb1bb4726 100644 --- a/tests/slicing/unravel-variance.i +++ b/tests/slicing/unravel-variance.i @@ -1,9 +1,9 @@ /* run.config - STDOPT: +"-slice-calls printf1 -journal-disable -float-normal -remove-redundant-alarms -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i " - STDOPT: +"-slice-calls printf2 -journal-disable -float-normal -remove-redundant-alarms -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i " - STDOPT: +"-slice-calls printf3 -journal-disable -float-normal -remove-redundant-alarms -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i " - STDOPT: +"-slice-calls printf4 -journal-disable -float-normal -remove-redundant-alarms -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i " - STDOPT: +"-slice-calls printf5 -journal-disable -float-normal -remove-redundant-alarms -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i " + STDOPT: +"-slice-calls printf1 -journal-disable -float-normal -eva-remove-redundant-alarms -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i " + STDOPT: +"-slice-calls printf2 -journal-disable -float-normal -eva-remove-redundant-alarms -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i " + STDOPT: +"-slice-calls printf3 -journal-disable -float-normal -eva-remove-redundant-alarms -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i " + STDOPT: +"-slice-calls printf4 -journal-disable -float-normal -eva-remove-redundant-alarms -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i " + STDOPT: +"-slice-calls printf5 -journal-disable -float-normal -eva-remove-redundant-alarms -then-on 'Slicing export' -set-project-as-default -print -then -print -ocode @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i -then @PTEST_DIR@/result/ocode_@PTEST_NUMBER@_@PTEST_NAME@.i " */ /* Small example devired from examples given for UNRAVEL tool : */ diff --git a/tests/spec/oracle/status_by_call_issue_890.res.oracle b/tests/spec/oracle/status_by_call_issue_890.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..33e76da4d07f848c16531e3c1fa56d9c8828261c --- /dev/null +++ b/tests/spec/oracle/status_by_call_issue_890.res.oracle @@ -0,0 +1,24 @@ +[kernel] Parsing tests/spec/status_by_call_issue_890.i (no preprocessing) +/* Generated by Frama-C */ +struct list { + struct list *next ; +}; +/*@ axiomatic Ax { + predicate P(struct list *root) ; + + } + */ +/*@ requires P(l); */ +int len(struct list *l) +{ + int tmp_0; + if (l == (struct list *)0) tmp_0 = 0; + else { + int tmp; + tmp = len(l->next); + tmp_0 = 1 + tmp; + } + return tmp_0; +} + + diff --git a/tests/spec/status_by_call_issue_890.i b/tests/spec/status_by_call_issue_890.i new file mode 100644 index 0000000000000000000000000000000000000000..d3209b6bea950aca95d9ac3a3ec582596fade641 --- /dev/null +++ b/tests/spec/status_by_call_issue_890.i @@ -0,0 +1,12 @@ +/* run.config + MODULE: @PTEST_DIR@/@PTEST_NAME@.cmxs +*/ + +struct list { struct list *next; }; + +/*@ axiomatic Ax { predicate P(struct list * root) ; } */ + +/*@ requires P(l); @*/ +int len(struct list * l){ + return (l == (void*)0) ? 0 : 1 + len(l->next); +} diff --git a/tests/spec/status_by_call_issue_890.ml b/tests/spec/status_by_call_issue_890.ml new file mode 100644 index 0000000000000000000000000000000000000000..374e927700b937885f27c029f3d1744110d9ea39 --- /dev/null +++ b/tests/spec/status_by_call_issue_890.ml @@ -0,0 +1,3 @@ +let () = + Db.Main.extend + (fun () -> Globals.Functions.iter Statuses_by_call.setup_all_preconditions_proxies) diff --git a/tests/syntax/cpp-command.c b/tests/syntax/cpp-command.c index e3f75a6e3fc85ab81beec8cbb436b8cf9564b2b5..8032aac2c727b39fde918c2e425095ad179846ad 100644 --- a/tests/syntax/cpp-command.c +++ b/tests/syntax/cpp-command.c @@ -1,7 +1,8 @@ /* run.config* - FILTER: sed 's:/\(tmp\|var\|build\)/[^ ]*\.i:/tmp/FILE.i:g' + FILTER: sed "s:/\(tmp\|var\|build\)/[^ ]*\.i:/tmp/FILE.i:g; s:$PWD/::" OPT: -no-autoload-plugins -cpp-frama-c-compliant -cpp-command "echo [\$(basename '%1') \$(basename '%1') \$(basename '%i') \$(basename '%input')] ['%2' '%2' '%o' '%output'] ['%args']" OPT: -no-autoload-plugins -cpp-frama-c-compliant -cpp-command "echo %%1 = \$(basename '%1') %%2 = '%2' %%args = '%args'" OPT: -no-autoload-plugins -cpp-frama-c-compliant -cpp-command "printf \"%s\" \"using \\% has no effect : \$(basename \"\%input\")\"" OPT: -no-autoload-plugins -cpp-frama-c-compliant -cpp-command "echo %var is not an interpreted placeholder" + OPT: -no-autoload-plugins -print-cpp-commands */ diff --git a/tests/syntax/inline_calls.i b/tests/syntax/inline_calls.i index 6c24ee22069c16673cbc3851d597a1df63d975c4..a71073677d14b7d1b989f2d667f54b3d2bb917ac 100644 --- a/tests/syntax/inline_calls.i +++ b/tests/syntax/inline_calls.i @@ -1,5 +1,5 @@ /* run.config - STDOPT: +"-inline-calls @all" + STDOPT: +"-inline-calls @all -kernel-msg-key printer:attrs" STDOPT: +"-inline-calls @inline" STDOPT: +"-inline-calls @inline -remove-inlined @inline" */ diff --git a/tests/syntax/keep_logical_operators.i b/tests/syntax/keep_logical_operators.i index dd05ac45a1b8248ca184a8f2f613b7cc86c17bd9..5f7901e2354bbae4862204d9d79ba3abc49e044d 100644 --- a/tests/syntax/keep_logical_operators.i +++ b/tests/syntax/keep_logical_operators.i @@ -9,3 +9,13 @@ int test(int a, int b, int c) { return 2; } + +int test_ptr(int* a, int* b, int* c) { + if (a && (b || c)) { + return 1; + } + if (a) + if (b) + return 2; + return 3; +} diff --git a/tests/syntax/loop-case-switch-for-unroll.c b/tests/syntax/loop-case-switch-for-unroll.c index c379555af57ec055957c8c275177345fa51eb177..7785be51b6a9e2495750bee02becb6c8fd846b61 100644 --- a/tests/syntax/loop-case-switch-for-unroll.c +++ b/tests/syntax/loop-case-switch-for-unroll.c @@ -1,7 +1,7 @@ /* run.config - STDOPT: +"-slevel 100 -eva" - STDOPT: +"-ulevel 1 -slevel 100 -eva" - STDOPT: +"-ulevel 2 -slevel 100 -eva" + STDOPT: +"-eva-slevel 100 -eva" + STDOPT: +"-ulevel 1 -eva-slevel 100 -eva" + STDOPT: +"-ulevel 2 -eva-slevel 100 -eva" COMMENT: compile and run with GCC, save output to a file, and compare it to the result of Frama-C piped to: "| grep Frama_C_show_each | sed 's/^.*Frama_C_show_each_//'" diff --git a/tests/syntax/oracle/cpp-command.4.res.oracle b/tests/syntax/oracle/cpp-command.4.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..bce7863f91059c3146bb69d762b5317a1cc86cea --- /dev/null +++ b/tests/syntax/oracle/cpp-command.4.res.oracle @@ -0,0 +1,2 @@ +[kernel] Preprocessing command: + gcc -E -C -I. -I./share/libc -D__FRAMAC__ -D__FC_MACHDEP_X86_32 -dD -nostdinc -m32 'tests/syntax/cpp-command.c' -o '/tmp/FILE.i' diff --git a/tests/syntax/oracle/inline_calls.0.res.oracle b/tests/syntax/oracle/inline_calls.0.res.oracle index 9a39abc4f7c8f1abdb7d831ec56509b35dbc82a9..fd9c8a925f562d51ed31387053cb1386b94bde5c 100644 --- a/tests/syntax/oracle/inline_calls.0.res.oracle +++ b/tests/syntax/oracle/inline_calls.0.res.oracle @@ -23,7 +23,7 @@ int g(void) if (v) { int tmp; { - int __retres_5; + /* __blockattribute__(____fc_inlined__("f")) */int __retres_5; __retres_5 = 2; tmp = __retres_5; } @@ -33,7 +33,7 @@ int g(void) else { int tmp_0; { - int __retres_6; + /* __blockattribute__(____fc_inlined__("in_f__fc_inline")) */int __retres_6; __retres_6 = 3; tmp_0 = __retres_6; } @@ -47,11 +47,11 @@ int h(void) { int tmp; { - int __retres; + /* __blockattribute__(____fc_inlined__("g")) */int __retres; if (v) { int tmp_3; { - int __retres_5; + /* __blockattribute__(____fc_inlined__("f")) */int __retres_5; __retres_5 = 2; tmp_3 = __retres_5; } @@ -61,6 +61,7 @@ int h(void) else { int tmp_0; { + /* __blockattribute__(____fc_inlined__("in_f__fc_inline")) */ int __retres_6; __retres_6 = 3; tmp_0 = __retres_6; @@ -90,8 +91,8 @@ int rec(int x_0) goto return_label; } { - int __retres_7; - int tmp_6; + /* __blockattribute__(____fc_inlined__("rec")) */int __retres_7; + int tmp_6; int x_0_5 = x_0 - 1; if (x_0_5 < 0) { __retres_7 = x_0_5; @@ -116,7 +117,7 @@ int f1(int a) if (nondet) { int __inline_tmp; { - int a_5 = 1; + /* __blockattribute__(____fc_inlined__("g1")) */int a_5 = 1; if (nondet) g1(4); __inline_tmp = a_5; } @@ -125,12 +126,12 @@ int f1(int a) if (nondet) { int __inline_tmp_6; { - int __retres_9; + /* __blockattribute__(____fc_inlined__("f1")) */int __retres_9; int a_8 = 2; if (nondet) { int __inline_tmp_10; { - int a_5_11 = 1; + /* __blockattribute__(____fc_inlined__("g1")) */int a_5_11 = 1; if (nondet) g1(4); __inline_tmp_10 = a_5_11; } @@ -155,7 +156,7 @@ int g1(int a) if (nondet) { int __inline_tmp; { - int a_4 = 4; + /* __blockattribute__(____fc_inlined__("g1")) */int a_4 = 4; if (nondet) { int __inline_tmp_5; g1(4); @@ -173,23 +174,23 @@ int main(void) int __inline_tmp; int tmp_1; { - int __retres; + /* __blockattribute__(____fc_inlined__("i")) */int __retres; /*@ assert i: \true; */ ; __retres = 0; __inline_tmp = __retres; } int local_init = __inline_tmp; { - int __retres_10; - int tmp; + /* __blockattribute__(____fc_inlined__("rec")) */int __retres_10; + int tmp; int x_0 = local_init; if (x_0 < 0) { __retres_10 = x_0; goto return_label; } { - int __retres_7; - int tmp_6; + /* __blockattribute__(____fc_inlined__("rec")) */int __retres_7; + int tmp_6; int x_0_5 = x_0 - 1; if (x_0_5 < 0) { __retres_7 = x_0_5; @@ -204,12 +205,12 @@ int main(void) } int t = __inline_tmp_8; { - int __retres_13; + /* __blockattribute__(____fc_inlined__("f1")) */int __retres_13; int a = 2; if (nondet) { int __inline_tmp_14; { - int a_5 = 1; + /* __blockattribute__(____fc_inlined__("g1")) */int a_5 = 1; if (nondet) g1(4); __inline_tmp_14 = a_5; } @@ -218,12 +219,13 @@ int main(void) if (nondet) { int __inline_tmp_6; { - int __retres_9; + /* __blockattribute__(____fc_inlined__("f1")) */int __retres_9; int a_8 = 2; if (nondet) { int __inline_tmp_10; { - int a_5_11 = 1; + /* __blockattribute__(____fc_inlined__("g1")) */int a_5_11 = + 1; if (nondet) g1(4); __inline_tmp_10 = a_5_11; } @@ -243,13 +245,13 @@ int main(void) __inline_tmp_11 = __retres_13; } { - int tmp_15; + /* __blockattribute__(____fc_inlined__("h")) */int tmp_15; { - int __retres_16; + /* __blockattribute__(____fc_inlined__("g")) */int __retres_16; if (v) { int tmp_3; { - int __retres_5; + /* __blockattribute__(____fc_inlined__("f")) */int __retres_5; __retres_5 = 2; tmp_3 = __retres_5; } @@ -259,6 +261,7 @@ int main(void) else { int tmp_0; { + /* __blockattribute__(____fc_inlined__("in_f__fc_inline")) */ int __retres_6; __retres_6 = 3; tmp_0 = __retres_6; @@ -285,8 +288,10 @@ int with_static(void) int call_with_static(void) { int tmp; - with_static_count ++; - tmp = with_static_count; + { + /* __blockattribute__(____fc_inlined__("with_static")) */with_static_count ++; + tmp = with_static_count; + } return tmp; } @@ -300,7 +305,8 @@ void builtin_acsl(void) void call_builtin_acsl(void) { { - float g_0 = 0.f; + /* __blockattribute__(____fc_inlined__("builtin_acsl")) */float g_0 = + 0.f; /*@ assert ¬\is_NaN(g_0); */ ; ; } @@ -315,8 +321,10 @@ void f_slevel(void) void call_f_slevel(void) { - /*@ slevel 0; */ ; - ; + { + /* __blockattribute__(____fc_inlined__("f_slevel")) *//*@ slevel 0; */ ; + ; + } return; } @@ -330,10 +338,12 @@ void post_decl(void); void middle_decl(void) { - x ++; - y ++; - post_decl(); - ; + { + /* __blockattribute__(____fc_inlined__("pre_decl")) */x ++; + y ++; + post_decl(); + ; + } return; } diff --git a/tests/syntax/oracle/keep_logical_operators.res.oracle b/tests/syntax/oracle/keep_logical_operators.res.oracle index 99261e5e4c556aee8b36123f86d1860c3680b298..2bfe2908271a7891c4bc6d0e497dd1c9871d9fb6 100644 --- a/tests/syntax/oracle/keep_logical_operators.res.oracle +++ b/tests/syntax/oracle/keep_logical_operators.res.oracle @@ -11,4 +11,20 @@ int test(int a, int b, int c) return_label: return __retres; } +int test_ptr(int *a, int *b, int *c) +{ + int __retres; + if (a && (b || c)) { + __retres = 1; + goto return_label; + } + if (a) + if (b) { + __retres = 2; + goto return_label; + } + __retres = 3; + return_label: return __retres; +} + diff --git a/tests/syntax/oracle/sizeof_incomplete_type.res.oracle b/tests/syntax/oracle/sizeof_incomplete_type.res.oracle index 861a044c35515cb6bbc08d712471e57789843deb..37dab603578cf0871a5a4db6574b22f76161a385 100644 --- a/tests/syntax/oracle/sizeof_incomplete_type.res.oracle +++ b/tests/syntax/oracle/sizeof_incomplete_type.res.oracle @@ -1,6 +1,6 @@ [kernel] Parsing tests/syntax/sizeof_incomplete_type.c (with preprocessing) [kernel] tests/syntax/sizeof_incomplete_type.c:21: User Error: - sizeof on incomplete type + sizeof on incomplete type 'struct inexistent' [kernel] User Error: stopping on file "tests/syntax/sizeof_incomplete_type.c" that has errors. Add '-kernel-msg-key pp' for preprocessing command. [kernel] Frama-C aborted: invalid user input. diff --git a/tests/syntax/unroll_labels.i b/tests/syntax/unroll_labels.i index 4ccad645f15c61425fcf07b5c25f80d4d7bc3108..66da8b7cf4882b0214a9cc46294e20ff7f81668b 100644 --- a/tests/syntax/unroll_labels.i +++ b/tests/syntax/unroll_labels.i @@ -1,6 +1,6 @@ /* run.config STDOPT: +"-eva @EVA_CONFIG@" - STDOPT: +"-eva @EVA_CONFIG@ -main main2 -slevel 3" + STDOPT: +"-eva @EVA_CONFIG@ -main main2 -eva-slevel 3" */ enum { SIX = 6 } ; volatile foo; diff --git a/tests/value/CruiseControl.c b/tests/value/CruiseControl.c index eb8c3acf07ffdf0a1248b0bbd0cbd3c6ffc8edc0..868f2ad6eb779e75abf4b56ef98017892d881cef 100644 --- a/tests/value/CruiseControl.c +++ b/tests/value/CruiseControl.c @@ -1,6 +1,6 @@ /* run.config* GCC: - STDOPT: #"-float-normal tests/value/CruiseControl_const.c -lib-entry -main CruiseControl -context-depth 10 -context-valid-pointers" + STDOPT: #"-float-normal tests/value/CruiseControl_const.c -lib-entry -main CruiseControl -eva-context-depth 10 -eva-context-valid-pointers" */ /*$************* SCADE_KCG KCG Version 5.1.1 (build i10) ************** diff --git a/tests/value/ai_annot.i b/tests/value/ai_annot.i index 9a531689e600c192c4a5ac0c314b0cd7c1f58d93..16034a0e0f48ea1185d1aca2066ddbc5c08bdcde 100644 --- a/tests/value/ai_annot.i +++ b/tests/value/ai_annot.i @@ -1,5 +1,5 @@ /* run.config* - STDOPT: #"-load-module scope -scope-verbose 2 -remove-redundant-alarms -context-width 3" + STDOPT: #"-load-module scope -scope-verbose 2 -eva-remove-redundant-alarms -eva-context-width 3" */ diff --git a/tests/value/alias.i b/tests/value/alias.i index 048db0914217733f9dd52f7839b5144870d7f2b9..4b91cf96a5b9397faf75c5a65279b01cff0312ba 100644 --- a/tests/value/alias.i +++ b/tests/value/alias.i @@ -1,5 +1,5 @@ /* run.config* - STDOPT: #"-no-results-function f" + STDOPT: #"-eva-no-results-function f" STDOPT: #"-main main3" STDOPT: #"-main main4 -absolute-valid-range 0-0xFF" STDOPT: #"-main main5" diff --git a/tests/value/base_addr_offset_block_length.i b/tests/value/base_addr_offset_block_length.i index 4a20889d500dc60519782ff4c15c287bfb360174..b3aad4d14b7a622e69f1e547cd8f84ef8434dfbd 100644 --- a/tests/value/base_addr_offset_block_length.i +++ b/tests/value/base_addr_offset_block_length.i @@ -1,5 +1,5 @@ /* run.config* - OPT: -no-autoload-plugins -load-module inout,eva -eva @EVA_CONFIG@ -context-width 3 -then -slevel 3 + OPT: -no-autoload-plugins -load-module inout,eva -eva @EVA_CONFIG@ -eva-context-width 3 -then -eva-slevel 3 */ diff --git a/tests/value/big_lib_entry.i b/tests/value/big_lib_entry.i index 88a7fbc821ae225258a104cb7fd8e57aa28b6445..0c2770eab0fefe3254629223350644dbbf8493e2 100644 --- a/tests/value/big_lib_entry.i +++ b/tests/value/big_lib_entry.i @@ -1,5 +1,5 @@ /* run.config* - OPT: -no-autoload-plugins -load-module inout,eva -eva @EVA_CONFIG@ -lib-entry -context-width 4 -eva-initialization-padding-globals no + OPT: -no-autoload-plugins -load-module inout,eva -eva @EVA_CONFIG@ -lib-entry -eva-context-width 4 -eva-initialization-padding-globals no */ typedef struct { diff --git a/tests/value/bitwise.i b/tests/value/bitwise.i index 10db311b22c2b3ce8099b118afa2d099e5afbc11..92a3bc59753007005c262734211c8a2d0d8f4aa6 100644 --- a/tests/value/bitwise.i +++ b/tests/value/bitwise.i @@ -2,11 +2,16 @@ STDOPT: +"-big-ints-hex 256" */ -/*@ assigns \result \from min, max; - ensures min <= \result <= max ; +/*@ assigns \result \from a, b; + ensures result_a_or_b: \result == a || \result == b ; */ -int Frama_C_interval(int min, int max); +extern int Frama_C_nondet(int a, int b); +/*@ requires order: min <= max; + assigns \result \from min, max; + ensures result_bounded: min <= \result <= max ; + */ +extern int Frama_C_interval(int min, int max); volatile long v; volatile unsigned char input[3]; @@ -67,13 +72,22 @@ int test4(void) if (something & 0x80000000) { Frama_C_show_each_true(something); return 0; - } + } else { Frama_C_show_each_false(something); return 1; } } +void test5(void) +{ + int x = Frama_C_nondet(-1, 0); + int y = Frama_C_nondet(-1, 0); + int a = x & y; + int b = x | y; + int c = x ^ y; +} + void and_or_rel(void) { long x, r1, r2, r3; @@ -150,6 +164,7 @@ void main(void) { test2(); test3(); test4(); + test5(); and_or_rel(); double_neg(); bug1(); diff --git a/tests/value/bts1306.i b/tests/value/bts1306.i index f6b51b857843812b7e4d12234621aee910cce851..81f9cc8f329ead372748ebd5eea97821b99bc0bd 100644 --- a/tests/value/bts1306.i +++ b/tests/value/bts1306.i @@ -1,5 +1,5 @@ /* run.config* - OPT: -no-autoload-plugins -load-module from,inout,eva -constfold -slevel 0 -eva @EVA_CONFIG@ -print -then -slevel 10 -eva -print + OPT: -no-autoload-plugins -load-module from,inout,eva -constfold -eva-slevel 0 -eva @EVA_CONFIG@ -print -then -eva-slevel 10 -eva -print */ void g(double x) { double y= x*x; } diff --git a/tests/value/bug0245.i b/tests/value/bug0245.i index 584d53f784613d1e5fdaf284e2aab0cdaf4d85c2..1408f3e7deeb0460eecff7c912685185868d8438 100644 --- a/tests/value/bug0245.i +++ b/tests/value/bug0245.i @@ -1,5 +1,5 @@ /* run.config* - STDOPT: #"-slevel 4" + STDOPT: #"-eva-slevel 4" */ int R,*p,S,*q; diff --git a/tests/value/builtins_split.c b/tests/value/builtins_split.c index a04c5fcd46b8fc0e048b6a8e50fc2fce6d7b9639..cc38f28c313dbd9e2c022b8eabe768de8f2a38c8 100644 --- a/tests/value/builtins_split.c +++ b/tests/value/builtins_split.c @@ -1,5 +1,5 @@ /* run.config* - STDOPT: +"-eva-show-progress -slevel 100" + STDOPT: +"-eva-show-progress -eva-slevel 100" */ int *p; diff --git a/tests/value/case_analysis.i b/tests/value/case_analysis.i index 7d9214dd079a84c2c58e219dd718d5a27b99bb24..40be501257b9f1b5edca5e3a305db685148deb04 100644 --- a/tests/value/case_analysis.i +++ b/tests/value/case_analysis.i @@ -1,5 +1,5 @@ /* run.config* - OPT: -no-autoload-plugins -load-module inout,eva -eva @EVA_CONFIG@ -slevel 30 -journal-disable -float-normal + OPT: -no-autoload-plugins -load-module inout,eva -eva @EVA_CONFIG@ -eva-slevel 30 -journal-disable -float-normal */ diff --git a/tests/value/cmp_ptr.i b/tests/value/cmp_ptr.i index 198a11aacafb3b00f5ac7bc29616a246c9dfba81..da2355d605ce612d4dc434c9509789e2602949a7 100644 --- a/tests/value/cmp_ptr.i +++ b/tests/value/cmp_ptr.i @@ -1,6 +1,6 @@ /* run.config* STDOPT: #"-main main -eva-msg-key pointer-comparison" - STDOPT: #"-undefined-pointer-comparison-propagate-all -eva-msg-key pointer-comparison" + STDOPT: #"-eva-undefined-pointer-comparison-propagate-all -eva-msg-key pointer-comparison" */ int *p,T[10]={0,1,2,3,4,5,6,7,8,9}; diff --git a/tests/value/cmp_ptr_follow_all_branches.i b/tests/value/cmp_ptr_follow_all_branches.i index 2e5292ae2db3c924c1586872f139a8dfd3a55378..71e72fec503aa835b228de03a8e238e7ac627b69 100644 --- a/tests/value/cmp_ptr_follow_all_branches.i +++ b/tests/value/cmp_ptr_follow_all_branches.i @@ -1,6 +1,6 @@ /* run.config* STDOPT: #"-eva-msg-key pointer-comparison" - STDOPT: #"-undefined-pointer-comparison-propagate-all -eva-msg-key pointer-comparison" + STDOPT: #"-eva-undefined-pointer-comparison-propagate-all -eva-msg-key pointer-comparison" */ int a; diff --git a/tests/value/cond_integer_cast_of_float.i b/tests/value/cond_integer_cast_of_float.i index 3a6d8768ec945afce02f2c361459b3d97e9903f7..9d1350ea671348d2759998a9ec5b3f9a2473455b 100644 --- a/tests/value/cond_integer_cast_of_float.i +++ b/tests/value/cond_integer_cast_of_float.i @@ -1,5 +1,5 @@ /* run.config* - OPT: -no-autoload-plugins -load-module eva -eva @EVA_CONFIG@ -no-results -then -float-hex -main mainbis + OPT: -no-autoload-plugins -load-module eva -eva @EVA_CONFIG@ -eva-no-results -then -float-hex -main mainbis */ typedef double D; typedef float F; diff --git a/tests/value/context_width.i b/tests/value/context_width.i index b9209213bc3f93315d7fdb4fbd476f53caee2776..e2f3d39895a2dbbebc76cb98c263efac2e5aa080 100644 --- a/tests/value/context_width.i +++ b/tests/value/context_width.i @@ -1,5 +1,5 @@ /* run.config* - STDOPT: +"-context-width 3 -then -print -then -context-width 1" + STDOPT: +"-eva-context-width 3 -then -print -then -eva-context-width 1" */ int a; diff --git a/tests/value/div.i b/tests/value/div.i index dcea8cf46d46eb257041662c2645467b92d170aa..3ac38b6068dae4271ea190752b7b1efcac5fe878 100644 --- a/tests/value/div.i +++ b/tests/value/div.i @@ -1,5 +1,5 @@ /* run.config* - STDOPT: #"-load-module scope -remove-redundant-alarms" + STDOPT: #"-load-module scope -eva-remove-redundant-alarms" OPT: -no-autoload-plugins -load-module eva,inout -rte -then -eva @EVA_CONFIG@ */ int X,Y,Z1,Z2,T,U1,U2,V,W1,W2; diff --git a/tests/value/domains.i b/tests/value/domains.i index 434324fc2f5dd1047505aed2df088c06631bdccb..22b198ea39fc8bd5e37848ce41c3dbf82294acd3 100644 --- a/tests/value/domains.i +++ b/tests/value/domains.i @@ -1,5 +1,5 @@ /* run.config* - STDOPT: #"-eva-domains sign,equality,bitwise,symbolic-locations,gauges -slevel 2" + STDOPT: #"-eva-domains sign,equality,bitwise,symbolic-locations,gauges -eva-slevel 2" */ /* Tests five domains together. */ diff --git a/tests/value/exit_paths.i b/tests/value/exit_paths.i index 9182998fe6295a704b306442e1a23c2847412ba3..3d0ac19e03486b4f1ec0f3113323621116a48f5c 100644 --- a/tests/value/exit_paths.i +++ b/tests/value/exit_paths.i @@ -1,5 +1,5 @@ /* run.config* - STDOPT: +"-wlevel 1" + STDOPT: +"-eva-widening-delay 1" */ #include "__fc_builtin.h" diff --git a/tests/value/gauges.c b/tests/value/gauges.c index ab2963f70b41dbb3f18e2a7915fc2d81a7c0d5d4..8acfac2c4118ae76f68f363d01f00159e02e04f9 100644 --- a/tests/value/gauges.c +++ b/tests/value/gauges.c @@ -1,5 +1,5 @@ /* run.config* - STDOPT: +" -slevel-function main8_aux:2,main5_bis:4 -eva-msg-key d-gauges" + STDOPT: +" -eva-slevel-function main8_aux:2,main5_bis:4 -eva-msg-key d-gauges" */ #include <stdlib.h> diff --git a/tests/value/invalid_loc_return.i b/tests/value/invalid_loc_return.i index 729b0a9038c108492f02071ee645ab7160d7b6ba..7cdc2deecad080c2053ea4fc300c48efb525a793 100644 --- a/tests/value/invalid_loc_return.i +++ b/tests/value/invalid_loc_return.i @@ -1,5 +1,5 @@ /* run.config* - STDOPT: +"-main main1 -then -slevel 3 -main main2" + STDOPT: +"-main main1 -then -eva-slevel 3 -main main2" */ int foo() { diff --git a/tests/value/lazy.i b/tests/value/lazy.i index 11f7d183bfbe11ea5176b9d9d758e079701fafbc..5b4b95d35dcbe6e6dade2a74277075ba902d34b7 100644 --- a/tests/value/lazy.i +++ b/tests/value/lazy.i @@ -1,6 +1,6 @@ /* run.config* STDOPT: #"-eva-msg-key pointer-comparison" - STDOPT: #"-undefined-pointer-comparison-propagate-all -eva-msg-key pointer-comparison" + STDOPT: #"-eva-undefined-pointer-comparison-propagate-all -eva-msg-key pointer-comparison" */ int a=-1; int b, d; diff --git a/tests/value/library.i b/tests/value/library.i index bbb69d46eb94dd04abf1dc6f3a0f186c14c315f0..6f7615e06383c9692c4e0050d7f06e36194411b3 100644 --- a/tests/value/library.i +++ b/tests/value/library.i @@ -1,6 +1,6 @@ /* run.config* GCC: - STDOPT: +"-eva-msg-key initial-state -eva-initialization-padding-globals no -lib-entry -main main -context-depth 3 -then -main main2 -then -context-width 4" + STDOPT: +"-eva-msg-key initial-state -eva-initialization-padding-globals no -lib-entry -main main -eva-context-depth 3 -then -main main2 -then -eva-context-width 4" */ int f_int(int x); diff --git a/tests/value/local_slevel.i b/tests/value/local_slevel.i index 985751249a226ba99972a87bab0d0d6f723ede39..f8a28e1829933eca449024a9d5c635fb03a98f24 100644 --- a/tests/value/local_slevel.i +++ b/tests/value/local_slevel.i @@ -1,5 +1,5 @@ /* run.config* - STDOPT: +" -load-module frama-c-constant_propagation -slevel-function main2:100000 -print -then -scf -then-on propagated -eva -eva-show-progress -no-scf" + STDOPT: +" -load-module frama-c-constant_propagation -eva-slevel-function main2:100000 -print -then -scf -then-on propagated -eva -eva-show-progress -no-scf" */ int *p; diff --git a/tests/value/logic_ptr_cast.i b/tests/value/logic_ptr_cast.i index 6f4c7af2f12976ac4cab2c017bad0db2d826d135..64eb43489d69f0c135df3a29dda3d8eee22bb6c2 100644 --- a/tests/value/logic_ptr_cast.i +++ b/tests/value/logic_ptr_cast.i @@ -1,5 +1,5 @@ /* run.config* - OPT: -no-autoload-plugins -load-module eva -eva @EVA_CONFIG@ -print -journal-disable -no-results + OPT: -no-autoload-plugins -load-module eva -eva @EVA_CONFIG@ -print -journal-disable -eva-no-results */ int *p; int t[90]; diff --git a/tests/value/loopfun.i b/tests/value/loopfun.i index 030e2654b43ef017571f659a983d660c59ed3315..2db5a9837a566a70e3ab9b52f690bedb21f26e14 100644 --- a/tests/value/loopfun.i +++ b/tests/value/loopfun.i @@ -1,5 +1,5 @@ /* run.config* - STDOPT: +"-slevel 50 -no-results" + STDOPT: +"-eva-slevel 50 -eva-no-results" STDOPT: +"-eva-warn-key=missing-loop-unroll=feedback -eva-warn-key=missing-loop-unroll:for=active -main main2" */ static int a = 7; diff --git a/tests/value/loopinv.c b/tests/value/loopinv.c index fbb89b089a48133c41a3cfa20648cb9a5b2c633d..26f3a1e37b27e5b099b572084544f16092a6d911 100644 --- a/tests/value/loopinv.c +++ b/tests/value/loopinv.c @@ -1,5 +1,5 @@ /* run.config* -OPT: @EVA_CONFIG@ -no-autoload-plugins -load-module from,inout,eva,report -slevel-function main2:20 -pp-annot -eva -then -report +OPT: @EVA_CONFIG@ -no-autoload-plugins -load-module from,inout,eva,report -eva-slevel-function main2:20 -pp-annot -eva -then -report */ /*@ requires valid: \valid(&t[0..s-1]); diff --git a/tests/value/modulo.i b/tests/value/modulo.i index 81d342ce9470528e1e0573acd12de263133c6269..70e4fe6ceec0abdb7f206548ce5e2a3274d0dc25 100644 --- a/tests/value/modulo.i +++ b/tests/value/modulo.i @@ -1,5 +1,5 @@ /* run.config* - STDOPT: #"-slevel-function pgcd1:100,pgcd2:100,pgcd3:100" + STDOPT: #"-eva-slevel-function pgcd1:100,pgcd2:100,pgcd3:100" */ int A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R; volatile v; diff --git a/tests/value/narrow_behaviors.i b/tests/value/narrow_behaviors.i index 64d98062b974c7c2c08a6c2cd4fecf86ea31f830..ba639b21956aaca1ad7e86a4a7f6159bafa98f78 100644 --- a/tests/value/narrow_behaviors.i +++ b/tests/value/narrow_behaviors.i @@ -1,5 +1,5 @@ /* run.config* - STDOPT: +"-slevel 10 -eva-verbose 2" + STDOPT: +"-eva-slevel 10 -eva-verbose 2" */ extern int nondet; diff --git a/tests/value/no_results.c b/tests/value/no_results.c index 1f2355186c9fb157e5d69aa965e1476a3dee0c14..39549decf2a333dd2d54028da0eba8b96aa41c0a 100644 --- a/tests/value/no_results.c +++ b/tests/value/no_results.c @@ -1,5 +1,5 @@ /* run.config* - STDOPT: #"-no-results-function init -calldeps -slevel 10000" +"-inout" + STDOPT: #"-eva-no-results-function init -calldeps -eva-slevel 10000" +"-inout" */ #define N 3000 diff --git a/tests/value/oracle/bitwise.res.oracle b/tests/value/oracle/bitwise.res.oracle index 5bd9c79813b7339a8da28995f913223872b77d97..20f6783fe6514a1335d5f58836344cf7e4ee34e3 100644 --- a/tests/value/oracle/bitwise.res.oracle +++ b/tests/value/oracle/bitwise.res.oracle @@ -7,76 +7,95 @@ input[0..2] ∈ [--..--] s ∈ [--..--] [eva] computing for function test1 <- main. - Called from tests/value/bitwise.i:149. + Called from tests/value/bitwise.i:163. [eva] computing for function Frama_C_interval <- test1 <- main. - Called from tests/value/bitwise.i:23. + Called from tests/value/bitwise.i:28. [eva] using specification for function Frama_C_interval +[eva] tests/value/bitwise.i:28: + function Frama_C_interval: precondition 'order' got status valid. [eva] Done for function Frama_C_interval [eva] computing for function Frama_C_interval <- test1 <- main. - Called from tests/value/bitwise.i:24. + Called from tests/value/bitwise.i:29. +[eva] tests/value/bitwise.i:29: + function Frama_C_interval: precondition 'order' got status valid. [eva] Done for function Frama_C_interval [eva] computing for function Frama_C_interval <- test1 <- main. - Called from tests/value/bitwise.i:25. + Called from tests/value/bitwise.i:30. +[eva] tests/value/bitwise.i:30: + function Frama_C_interval: precondition 'order' got status valid. [eva] Done for function Frama_C_interval [eva] Recording results for test1 [eva] Done for function test1 [eva] computing for function test2 <- main. - Called from tests/value/bitwise.i:150. + Called from tests/value/bitwise.i:164. [eva] computing for function Frama_C_interval <- test2 <- main. - Called from tests/value/bitwise.i:50. + Called from tests/value/bitwise.i:55. +[eva] tests/value/bitwise.i:55: + function Frama_C_interval: precondition 'order' got status valid. [eva] Done for function Frama_C_interval [eva] Recording results for test2 [eva] Done for function test2 [eva] computing for function test3 <- main. - Called from tests/value/bitwise.i:151. + Called from tests/value/bitwise.i:165. [eva] Recording results for test3 [eva] Done for function test3 [eva] computing for function test4 <- main. - Called from tests/value/bitwise.i:152. -[eva] tests/value/bitwise.i:62: assertion got status valid. -[eva] tests/value/bitwise.i:64: + Called from tests/value/bitwise.i:166. +[eva] tests/value/bitwise.i:67: assertion got status valid. +[eva] tests/value/bitwise.i:69: Frama_C_show_each_1: [0x80000000..0xFFFFFFFF], {0x80000000} -[eva] tests/value/bitwise.i:64: Frama_C_show_each_1: [0..0x7FFFFFFF], {0} -[eva] tests/value/bitwise.i:66: +[eva] tests/value/bitwise.i:69: Frama_C_show_each_1: [0..0x7FFFFFFF], {0} +[eva] tests/value/bitwise.i:71: Frama_C_show_each_2: [0..0x7FFFFFFF], {0}, {0x80000000} -[eva] tests/value/bitwise.i:66: Frama_C_show_each_2: [0..0x7FFFFFFF], {0}, {0} -[eva] tests/value/bitwise.i:72: Frama_C_show_each_false: [0..0x7FFFFFFF] -[eva] tests/value/bitwise.i:72: Frama_C_show_each_false: [0..0x7FFFFFFF] +[eva] tests/value/bitwise.i:71: Frama_C_show_each_2: [0..0x7FFFFFFF], {0}, {0} +[eva] tests/value/bitwise.i:77: Frama_C_show_each_false: [0..0x7FFFFFFF] +[eva] tests/value/bitwise.i:77: Frama_C_show_each_false: [0..0x7FFFFFFF] [eva] Recording results for test4 [eva] Done for function test4 +[eva] computing for function test5 <- main. + Called from tests/value/bitwise.i:167. +[eva] computing for function Frama_C_nondet <- test5 <- main. + Called from tests/value/bitwise.i:84. +[eva] using specification for function Frama_C_nondet +[eva] Done for function Frama_C_nondet +[eva] computing for function Frama_C_nondet <- test5 <- main. + Called from tests/value/bitwise.i:85. +[eva] Done for function Frama_C_nondet +[eva] Recording results for test5 +[eva] Done for function test5 [eva] computing for function and_or_rel <- main. - Called from tests/value/bitwise.i:153. -[eva:alarm] tests/value/bitwise.i:87: Warning: assertion got status unknown. + Called from tests/value/bitwise.i:168. +[eva:alarm] tests/value/bitwise.i:101: Warning: assertion got status unknown. [eva] Recording results for and_or_rel [eva] Done for function and_or_rel [eva] computing for function double_neg <- main. - Called from tests/value/bitwise.i:154. + Called from tests/value/bitwise.i:169. [eva] Recording results for double_neg [eva] Done for function double_neg [eva] computing for function bug1 <- main. - Called from tests/value/bitwise.i:155. + Called from tests/value/bitwise.i:170. [eva] Recording results for bug1 [eva] Done for function bug1 [eva] computing for function bug2 <- main. - Called from tests/value/bitwise.i:156. -[eva] tests/value/bitwise.i:114: Frama_C_show_each_then: -[eva] tests/value/bitwise.i:114: Frama_C_show_each_else: + Called from tests/value/bitwise.i:171. +[eva] tests/value/bitwise.i:128: Frama_C_show_each_then: +[eva] tests/value/bitwise.i:128: Frama_C_show_each_else: [eva] Recording results for bug2 [eva] Done for function bug2 [eva] computing for function bug3 <- main. - Called from tests/value/bitwise.i:157. -[eva] tests/value/bitwise.i:121: Frama_C_show_each: {0x41F656F}, {0xFBE09A91} + Called from tests/value/bitwise.i:172. +[eva] tests/value/bitwise.i:135: Frama_C_show_each: {0x41F656F}, {0xFBE09A91} [eva] Recording results for bug3 [eva] Done for function bug3 [eva] computing for function bug4 <- main. - Called from tests/value/bitwise.i:158. -[eva] tests/value/bitwise.i:131: Frama_C_show_each_then: -[eva] tests/value/bitwise.i:133: Frama_C_show_each_else: + Called from tests/value/bitwise.i:173. +[eva] tests/value/bitwise.i:145: Frama_C_show_each_then: +[eva] tests/value/bitwise.i:147: Frama_C_show_each_else: [eva] Recording results for bug4 [eva] Done for function bug4 [eva] computing for function bug5 <- main. - Called from tests/value/bitwise.i:159. -[eva] tests/value/bitwise.i:144: Frama_C_show_each_dead: {0} + Called from tests/value/bitwise.i:174. +[eva] tests/value/bitwise.i:158: Frama_C_show_each_dead: {0} [eva] Recording results for bug5 [eva] Done for function bug5 [eva] Recording results for main @@ -136,6 +155,12 @@ something ∈ [0..0x7FFFFFFF] topBitOnly ∈ {0; 0x80000000} __retres ∈ {1} +[eva:final-states] Values at end of function test5: + x ∈ {-1; 0} + y ∈ {-1; 0} + a ∈ {-1; 0} + b ∈ {-1; 0} + c ∈ {-1; 0} [eva:final-states] Values at end of function main: [from] Computing for function and_or_rel @@ -162,12 +187,18 @@ [from] Done for function test3 [from] Computing for function test4 [from] Done for function test4 +[from] Computing for function test5 +[from] Computing for function Frama_C_nondet <-test5 +[from] Done for function Frama_C_nondet +[from] Done for function test5 [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 Frama_C_interval: \result FROM min; max +[from] Function Frama_C_nondet: + \result FROM a; b [from] Function and_or_rel: NO EFFECTS [from] Function bug1: @@ -190,6 +221,8 @@ NO EFFECTS [from] Function test4: \result FROM v +[from] Function test5: + NO EFFECTS [from] Function main: NO EFFECTS [from] ====== END OF DEPENDENCIES ====== @@ -238,6 +271,10 @@ something; topBitOnly; __retres [inout] Inputs for function test4: v +[inout] Out (internal) for function test5: + x; y; a; b; c +[inout] Inputs for function test5: + \nothing [inout] Out (internal) for function main: \nothing [inout] Inputs for function main: diff --git a/tests/value/oracle/summary.4.res.oracle b/tests/value/oracle/summary.4.res.oracle index 3e988afe4882c009bbfa39e4f7c73ed77f551148..7bfb7aff0243d6fb76ac66ee9a5adf16a98cbed9 100644 --- a/tests/value/oracle/summary.4.res.oracle +++ b/tests/value/oracle/summary.4.res.oracle @@ -1,3 +1,5 @@ +[kernel] Warning: -slevel is a deprecated alias for option -eva-slevel. + Please use -eva-slevel instead. [kernel] Parsing tests/value/summary.i (no preprocessing) [rte] annotating function alarms [rte] annotating function bottom diff --git a/tests/value/plevel.i b/tests/value/plevel.i index 01f7e73dd47f3ea92749bdb166413b7fdaca4c8a..202526dc0dec493b2a96fdf8f34786145210a30e 100644 --- a/tests/value/plevel.i +++ b/tests/value/plevel.i @@ -1,5 +1,5 @@ /* run.config* - STDOPT: #"-plevel 40 -big-ints-hex 0x55" + STDOPT: #"-eva-plevel 40 -big-ints-hex 0x55" */ int t[0xFFFF]; diff --git a/tests/value/pointer_comparison.c b/tests/value/pointer_comparison.c index 2dcf42073538d749686ebbd0fe38cc7fc6cb9e30..40717af44c5547544a81941d440e3e5673642187 100644 --- a/tests/value/pointer_comparison.c +++ b/tests/value/pointer_comparison.c @@ -1,6 +1,6 @@ /* run.config* STDOPT: +" -load-module report -report-print-properties -eva-warn-undefined-pointer-comparison none -eva-msg-key pointer-comparison -then -report -then -eva-warn-undefined-pointer-comparison pointer -then -report -then -eva-warn-undefined-pointer-comparison all -then -report" - STDOPT: +" -load-module report -report-print-properties -undefined-pointer-comparison-propagate-all -eva-warn-undefined-pointer-comparison none -eva-msg-key pointer-comparison -then -report -then -eva-warn-undefined-pointer-comparison pointer -then -report -then -eva-warn-undefined-pointer-comparison all -then -report" + STDOPT: +" -load-module report -report-print-properties -eva-undefined-pointer-comparison-propagate-all -eva-warn-undefined-pointer-comparison none -eva-msg-key pointer-comparison -then -report -then -eva-warn-undefined-pointer-comparison pointer -then -report -then -eva-warn-undefined-pointer-comparison all -then -report" */ int x,y,*p; int main(){ diff --git a/tests/value/precise_locations.i b/tests/value/precise_locations.i index 06340dba48ae65c8c9ed814351463b7a34cc27ab..942739895819533255887b5f61ec8f7e124fd806 100644 --- a/tests/value/precise_locations.i +++ b/tests/value/precise_locations.i @@ -1,5 +1,5 @@ /* run.config* - STDOPT: +"-eva-widening-period 3 -then -inout -load-module report -report -then -plevel 250" + STDOPT: +"-eva-widening-period 3 -then -inout -load-module report -report -then -eva-plevel 250" */ struct s { diff --git a/tests/value/ptr_call_object.c b/tests/value/ptr_call_object.c index f8872244f28601965d84fa91fbc764ea07d893ea..b02914deb9630d848e1bcbfaa8c4f4b0d00af6ae 100644 --- a/tests/value/ptr_call_object.c +++ b/tests/value/ptr_call_object.c @@ -1,5 +1,5 @@ /* run.config* - STDOPT: +"-slevel 2" + STDOPT: +"-eva-slevel 2" */ struct obj { diff --git a/tests/value/recol.c b/tests/value/recol.c index 5d0d3e258cafc1c7999e035c68337ba922a2b1db..46f6de92f5ab375b405205aee08f18c3c344ddcf 100644 --- a/tests/value/recol.c +++ b/tests/value/recol.c @@ -1,6 +1,6 @@ /* run.config* - OPT: -no-autoload-plugins -load-module eva,inout -eva @EVA_CONFIG@ -slevel 100 -cpp-extra-args="-DPTEST " -journal-disable -no-warn-signed-overflow - OPT: -no-autoload-plugins -load-module eva,inout -eva @EVA_CONFIG@ -slevel 100 -cpp-extra-args="-DPTEST " -journal-disable -machdep ppc_32 -no-warn-signed-overflow + OPT: -no-autoload-plugins -load-module eva,inout -eva @EVA_CONFIG@ -eva-slevel 100 -cpp-extra-args="-DPTEST " -journal-disable -no-warn-signed-overflow + OPT: -no-autoload-plugins -load-module eva,inout -eva @EVA_CONFIG@ -eva-slevel 100 -cpp-extra-args="-DPTEST " -journal-disable -machdep ppc_32 -no-warn-signed-overflow */ #ifndef PTEST diff --git a/tests/value/redundant_alarms.c b/tests/value/redundant_alarms.c index cd26fec1a2c7ab4b10c2b944536d16f4ceff23ee..a6b1785cd3d19a218c1a13b55ca62b8bda5344d0 100644 --- a/tests/value/redundant_alarms.c +++ b/tests/value/redundant_alarms.c @@ -1,5 +1,5 @@ /* run.config* - OPT: -no-autoload-plugins -load-module inout,scope,slicing,sparecode @EVA_CONFIG@ -eva-warn-copy-indeterminate=-@all,main3 -scope-msg-key rm_asserts -scope-verbose 2 -remove-redundant-alarms -print -slice-threat main1 -then-on 'Slicing export' -print + OPT: -no-autoload-plugins -load-module inout,scope,slicing,sparecode @EVA_CONFIG@ -eva-warn-copy-indeterminate=-@all,main3 -scope-msg-key rm_asserts -scope-verbose 2 -eva-remove-redundant-alarms -print -slice-threat main1 -then-on 'Slicing export' -print **/ volatile int v; diff --git a/tests/value/reevaluate_alarms.i b/tests/value/reevaluate_alarms.i index c0fc49d5b7698af6fe344bb15d79cd2b2d8686c3..9085a0a7185533f1b36bbf543d4b94b45f86db36 100644 --- a/tests/value/reevaluate_alarms.i +++ b/tests/value/reevaluate_alarms.i @@ -1,5 +1,5 @@ /* run.config* - STDOPT: +"-load-module report -report -then -slevel 10" + STDOPT: +"-load-module report -report -then -eva-slevel 10" */ diff --git a/tests/value/slevelex.i b/tests/value/slevelex.i index ed8cb52583d2b6106297347ee22912b246e0d648..2c2546796fb9969c93cfc2ca1e32577ee02f9b91 100644 --- a/tests/value/slevelex.i +++ b/tests/value/slevelex.i @@ -1,5 +1,5 @@ /* run.config* - STDOPT: #"-slevel 5 -slevel-function main:0 -slevel-function gu:21 -slevel-function ginc:21" + STDOPT: #"-eva-slevel 5 -eva-slevel-function main:0 -eva-slevel-function gu:21 -eva-slevel-function ginc:21" */ volatile int c; diff --git a/tests/value/split_return.i b/tests/value/split_return.i index 3873c1b9d225aa0b381b5f54405ac272f630d88f..8cfc8a21a7528455accae9f91f3678fc12e51767 100644 --- a/tests/value/split_return.i +++ b/tests/value/split_return.i @@ -1,10 +1,10 @@ /* run.config* - STDOPT: +"-deterministic -eva-no-memexec -slevel-function init:3,main1:3,f2:4,main2:4,f4:3,main5:3,uninit:2,main9:2 -eva-split-return-function f2:0,f3:-2:-4,f4:4,f5:-2,NON_EXISTING:4,uninit:0,escaping:0 -eva-warn-copy-indeterminate=-uninit,-escaping,-main9 -permissive -then -load-module report -report" - STDOPT: +"-deterministic -eva-no-memexec -eva -journal-disable -out -input -deps -slevel 6 -eva-split-return auto -eva-split-return-function f7:0:3 -eva-warn-copy-indeterminate=-uninit,-escaping,-main9 -then -load-module report -report" + STDOPT: +"-deterministic -eva-no-memexec -eva-slevel-function init:3,main1:3,f2:4,main2:4,f4:3,main5:3,uninit:2,main9:2 -eva-split-return-function f2:0,f3:-2:-4,f4:4,f5:-2,NON_EXISTING:4,uninit:0,escaping:0 -eva-warn-copy-indeterminate=-uninit,-escaping,-main9 -permissive -then -load-module report -report" + STDOPT: +"-deterministic -eva-no-memexec -eva -journal-disable -out -input -deps -eva-slevel 6 -eva-split-return auto -eva-split-return-function f7:0:3 -eva-warn-copy-indeterminate=-uninit,-escaping,-main9 -then -load-module report -report" COMMENT: below command must fail, as -permissive is not set - STDOPT: +"-deterministic -eva-no-memexec -eva -slevel-function NON_EXISTING:4 -eva-warn-copy-indeterminate=-uninit,-escaping,-main9" - STDOPT: +"-deterministic -eva-no-memexec -eva -journal-disable -out -input -deps -slevel 6 -eva-split-return full -eva-warn-copy-indeterminate=-uninit,-escaping,-main9" - STDOPT: +"-deterministic -eva-no-memexec -eva -journal-disable -out -input -deps -slevel 6 -eva-split-return full -eva-split-return-function f7:0:3 -eva-split-return-function f2:full -eva-warn-copy-indeterminate=-uninit,-escaping,-main9 -then -eva-split-return-function f2:auto" + STDOPT: +"-deterministic -eva-no-memexec -eva -eva-slevel-function NON_EXISTING:4 -eva-warn-copy-indeterminate=-uninit,-escaping,-main9" + STDOPT: +"-deterministic -eva-no-memexec -eva -journal-disable -out -input -deps -eva-slevel 6 -eva-split-return full -eva-warn-copy-indeterminate=-uninit,-escaping,-main9" + STDOPT: +"-deterministic -eva-no-memexec -eva -journal-disable -out -input -deps -eva-slevel 6 -eva-split-return full -eva-split-return-function f7:0:3 -eva-split-return-function f2:full -eva-warn-copy-indeterminate=-uninit,-escaping,-main9 -then -eva-split-return-function f2:auto" */ /*@ assigns \result \from \nothing; diff --git a/tests/value/summary.i b/tests/value/summary.i index d73b4b42d73532f315dedb80d1c927415566d9eb..8d5d6efd3f583a37f9ef638481739269650a8d07 100644 --- a/tests/value/summary.i +++ b/tests/value/summary.i @@ -3,7 +3,7 @@ STDOPT: +"-eva-msg-key=summary -main minimal" STDOPT: +"-eva-msg-key=summary -main bottom" STDOPT: +"-eva-msg-key=summary -main main" - STDOPT: +"-rte -eva-msg-key=summary -main main" + STDOPT: +"-rte -eva-msg-key=summary -main main -slevel 0" */ /* Tests the summary on the smallest possible program. */ diff --git a/tests/value/traces/test1.c b/tests/value/traces/test1.c index b6097db5d277c05f882ffbd7b5794ca3be9eaf55..2eda2c29eb845ca3b7a6c489f0be9bbd3a1b7c14 100644 --- a/tests/value/traces/test1.c +++ b/tests/value/traces/test1.c @@ -1,5 +1,5 @@ /* run.config - STDOPT: #"-eva-domains traces -value-msg-key d-traces -slevel 10 -eva-traces-project" +"-then-last -val -print -value-msg-key=-d-traces" + STDOPT: #"-eva-domains traces -eva-msg-key d-traces -eva-slevel 10 -eva-traces-project" +"-then-last -eva -print -eva-msg-key=-d-traces" */ extern volatile int entropy_source; diff --git a/tests/value/traces/test2.i b/tests/value/traces/test2.i index 506b765112f7299a247614388e37f77a0529ca2e..11d8611c60a21d9fa6a6fa1869ebc776758e2f7b 100644 --- a/tests/value/traces/test2.i +++ b/tests/value/traces/test2.i @@ -1,5 +1,5 @@ /* run.config - STDOPT: #"-eva-domains traces -value-msg-key d-traces -slevel 10 -eva-traces-project" +"-then-last -val -print -value-msg-key=-d-traces" + STDOPT: #"-eva-domains traces -eva-msg-key d-traces -eva-slevel 10 -eva-traces-project" +"-then-last -eva -print -eva-msg-key=-d-traces" */ diff --git a/tests/value/traces/test3.i b/tests/value/traces/test3.i index 80f30b09d39867dbe21a746c0ab0eb775ec9cc98..1878979fbfec0ed04f1df12c27e4377881fa2b30 100644 --- a/tests/value/traces/test3.i +++ b/tests/value/traces/test3.i @@ -1,5 +1,5 @@ /* run.config - STDOPT: #"-eva-domains traces -value-msg-key d-traces -slevel 10 -eva-traces-project" +"-then-last -val -print -value-msg-key=-d-traces" + STDOPT: #"-eva-domains traces -eva-msg-key d-traces -eva-slevel 10 -eva-traces-project" +"-then-last -eva -print -eva-msg-key=-d-traces" */ int g; diff --git a/tests/value/traces/test4.i b/tests/value/traces/test4.i index 5cb5ad20e108eb43f8bd401375b2f9eaa8b35790..ef512f629ee089ba990926f3d9abde6584129e19 100644 --- a/tests/value/traces/test4.i +++ b/tests/value/traces/test4.i @@ -1,5 +1,5 @@ /* run.config - STDOPT: #"-eva-domains traces -value-msg-key d-traces -slevel 10" + STDOPT: #"-eva-domains traces -eva-msg-key d-traces -eva-slevel 10" */ /* Test of join inside a loop */ diff --git a/tests/value/traces/test5.i b/tests/value/traces/test5.i index 60775951cadfd3c59496c198156438b766b3451e..d3f122845da8990429ab62d1f98d30ebd81bfb4b 100644 --- a/tests/value/traces/test5.i +++ b/tests/value/traces/test5.i @@ -1,5 +1,5 @@ /* run.config - STDOPT: #"-eva-domains traces -value-msg-key d-traces -slevel 10" +"-then-last -val -slevel 10 -print -no-eva-traces-domain" + STDOPT: #"-eva-domains traces -eva-msg-key d-traces -eva-slevel 10" +"-then-last -eva -eva-slevel 10 -print -no-eva-traces-domain" */ diff --git a/tests/value/uninit_callstack.i b/tests/value/uninit_callstack.i index 3c1d29d57655fbf18f9134cfc186dd1b45ace78a..6adb7e5120047524db8d21d776a7d7f5d76c9abc 100644 --- a/tests/value/uninit_callstack.i +++ b/tests/value/uninit_callstack.i @@ -1,5 +1,5 @@ /* run.config* - OPT: -no-autoload-plugins -load-module eva -eva @EVA_CONFIG@ -eva-no-show-progress -eva-print-callstacks -journal-disable -no-results + OPT: -no-autoload-plugins -load-module eva -eva @EVA_CONFIG@ -eva-no-show-progress -eva-print-callstacks -journal-disable -eva-no-results */ int *p, x; diff --git a/tests/value/widen_on_non_monotonic.i b/tests/value/widen_on_non_monotonic.i index c20b8bc79102a5e523696f80da4ed5c5508ef0b0..1242896475e2675dda3c994f558ac1da7d0e512c 100644 --- a/tests/value/widen_on_non_monotonic.i +++ b/tests/value/widen_on_non_monotonic.i @@ -1,5 +1,5 @@ /* run.config* - STDOPT: #"-slevel 20" + STDOPT: #"-eva-slevel 20" */ /* Problem with Value's memory model, that does not guarantee that we call