diff --git a/.gitattributes b/.gitattributes
index 2de3f44bc5c94ecb9a00c9f01bf5c2623cad104a..98a33b2e7a7d605133a0d1ec07f46c5dbe7d2893 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -254,6 +254,7 @@ README* header_spec=.ignore
 
 /nix/empty header_spec=.ignore
 /nix/external-plugins.txt header_spec=.ignore
+/nix/ocaml-versions.txt header_spec=.ignore
 /nix/frama-c-public/known_hosts header_spec=.ignore
 /nix/sources.json header_spec=.ignore
 
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index cf3978f471c3fc5736397dd21ca512042d6c54d0..0da7cb8d103c08e31b433e145826ddff1a428b7c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -428,19 +428,58 @@ internal-nightly:
   only:
     - schedules
 
+# Linux ARM & MacOS
+
+.build_template: &additional_arch_template
+  stage: compatibility
+  script:
+    - opam update
+    - opam switch create --empty .
+    - eval $(opam env --switch=. --set-switch)
+    # Note: we use this to get an exact version corresponding to a minor version
+    - opam pin add ocaml $(grep $OCAML nix/ocaml-versions.txt) -n
+    - opam install . --deps-only --with-test -y
+    - dune build --display short --error-reporting=twice @install
+    - dune exec -- frama-c-ptests tests src/plugins/*/tests
+    - dune build --display short @ptests_config
+  timeout: 2h
+  tags:
+    - ${ARCH}
+
+additional-arch:
+  <<: *additional_arch_template
+  <<: *manual_when_not_special_pipeline
+  parallel:
+    matrix:
+      - ARCH: [linux-arm, macos-x86, macos-arm]
+
+additional-arch-nightly:
+  <<: *additional_arch_template
+  <<: *when_publish
+  parallel:
+    matrix:
+      - ARCH: [linux-arm, macos-x86, macos-arm]
+
+additional-arch-release:
+  <<: *additional_arch_template
+  <<: *when_release
+  parallel:
+    matrix:
+      - ARCH: [linux-arm, macos-x86, macos-arm]
+
 # OCaml versions
 
 .build_template: &ocaml_always_additional_versions_template
   parallel:
     matrix:
-      - OCAML: ["4.14"]
+      - OCAML: ["5.1"]
 
 # Uncomment this block when there are intermediate versions to check manully
-#.build_template: &ocaml_manual_additional_versions_template
-#  parallel:
-#    matrix:
-#      - OCAML: ["4.14"]
-#  when: manual
+.build_template: &ocaml_manual_additional_versions_template
+  parallel:
+    matrix:
+      - OCAML: ["4.14"]
+  when: manual
 
 .build_template: &ocaml_versions_template
   stage: compatibility
@@ -455,14 +494,14 @@ ocaml-versions:
     - schedules
 
 # Uncomment this section when there are additional versions of OCaml to test
-# ocaml-versions-more:
-#   <<: *ocaml_versions_template
-#   <<: *ocaml_manual_additional_versions_template
+ocaml-versions-more:
+  <<: *ocaml_versions_template
+  <<: *ocaml_manual_additional_versions_template
 
 ocaml-versions-nightly:
   <<: *ocaml_versions_template
   <<: *ocaml_always_additional_versions_template
-  # we still check them for the publisher pipeline job
+  # in publish schedule, we still check additional versions of OCaml
   <<: *when_publish
 
 # Opam pin
diff --git a/Changelog b/Changelog
index 4ed236880d5a0c55a79d1b8f70ce24be8126a57b..c025fd79af4f75b046477d0c89e88c14e2305ceb 100644
--- a/Changelog
+++ b/Changelog
@@ -18,11 +18,26 @@
 Open Source Release <next-release>
 ###############################################################################
 
-o   Kernel    [2024-01-29] Db is now mostly empty, the only remaining value is
+-*   Variadic [2024-03-07] Make sure that generated functions have fresh names
+o!   Kernel   [2024-03-07] More coherent naming of functions determining if a
+                           symbol is a Frama-C built-in.
+-*   Kernel   [2024-03-04] Accept conditional expr whose 2d and 3d operands
+                           have type void, as per C11 6.5.15§3
+-*   Kernel   [2024-02-22] When an array is declared with a fixed length l,
+                           raise an error if l * sizeof(elem) > SIZE_MAX
+o!  Kernel    [2024-02-22] Merged AST nodes TCastE and TLogic_coerce
+o!  Kernel    [2024-01-29] Db is now mostly empty, the only remaining value is
                            Db.Main.extend which is deprecated and replaced by
                            Boot.Main.extend. Features related to asynchronous
                            interactions are now handled in module Async
 
+###############################################################################
+Open Source Release 28.1 (Nickel)
+###############################################################################
+
+-*  Kernel    [2024-01-18] Fix Cil.isConstant on lvalues with offset.
+-*  Ivette    [2024-01-11] Fix Ivette shell wrapper on macOS.
+
 ###############################################################################
 Open Source Release 28.0 (Nickel)
 ###############################################################################
diff --git a/VERSION b/VERSION
index 3b5a3833b21df5acb77bae75f31a0f429c84077c..9263b4da4adabeb62cb32baaa15964ee53c523ad 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-28.0+dev
+28.1+dev
diff --git a/bin/frama-c-build-scripts.sh b/bin/frama-c-build-scripts.sh
index 3823d537a85a2f2460371e3557b42c28429d585c..4aa1c579abc5786b38313fde6951719d8a8f0fa8 100755
--- a/bin/frama-c-build-scripts.sh
+++ b/bin/frama-c-build-scripts.sh
@@ -91,7 +91,7 @@ DuneProject () {
     echo "(maintainers \"anonymous\")"
     echo "(package (name ${PACKAGE})"
     echo "  (depends"
-    echo "    (\"frama-c\" (>= 28.0))"
+    echo "    (\"frama-c\" (>= 28.1))"
     echo "  )"
     echo " (tags (\"Frama-C scripts\"))"
     echo ")"
diff --git a/bin/frama-c-script b/bin/frama-c-script
index a6be7954558452f567495c4f6f3ba056611e8962..3c61ac10c6d4ba98eb5d0316077a0e070926a95c 100755
--- a/bin/frama-c-script
+++ b/bin/frama-c-script
@@ -195,7 +195,7 @@ flamegraph() {
   </body>
 </html>
 EOF
-    if [ -z "$NOGUI" ]; then
+    if [ -z "${NOGUI-}" ]; then
         open_file "$out_html"
     fi
 }
diff --git a/doc/developer/changes.tex b/doc/developer/changes.tex
index 6395dc53dcf44833ff1413475f562443346dfa9e..a5767954867ead16b224f920b07110216516c8d1 100644
--- a/doc/developer/changes.tex
+++ b/doc/developer/changes.tex
@@ -17,6 +17,11 @@ This chapter summarizes the major changes in this documentation between each
   \end{itemize}
 \end{itemize}
 
+\section*{28.0 (Nickel)}
+\begin{itemize}
+\item \textbf{Logical Annotations}: Add sections about specification generation.
+\end{itemize}
+
 \section*{27.0 (Cobalt)}
 \begin{itemize}
 \item \textbf{Customizing the machine model}: Rewrite section according to new
diff --git a/doc/release/deploy.tex b/doc/release/deploy.tex
index f337d71d615756556248b10c91104639bc898e5a..9509289dd29dd93c7004509b3d5003c2b7a2d465 100644
--- a/doc/release/deploy.tex
+++ b/doc/release/deploy.tex
@@ -128,7 +128,8 @@ version in \url{https://git.frama-c.com/pub/frama-c/-/tags}.
 
 \begin{itemize}
 \item Send an e-mail to \texttt{frama-c-discuss} announcing the release.
-\item Tweet the release, pointing to the Downloads page.
+\item Toot the release (\url{https://fosstodon.org/@frama_c}),
+  pointing to the Downloads page.
 \item Ideally, a blog post should arrive in a few days, with some interesting
   new features.
 \end{itemize}
diff --git a/doc/release/intro.tex b/doc/release/intro.tex
index 7a0434bb42c4edf95410699141d9898e27f4883e..a732ba024edc2c9c0af6b7edaa82d05b0186c3f8 100644
--- a/doc/release/intro.tex
+++ b/doc/release/intro.tex
@@ -45,7 +45,7 @@ A \FramaC release consists of the following main steps:
   Manager starts the release pipeline in the continuous integration. The last
   stage releases the branch, the GitLab release, the website, the wiki and
   creates an opam repository branch on the Frama-C organisation on GitHub. Time
-  to send an email on the Frama-C discuss mailing list, tweet and spread the
+  to send an email on the Frama-C discuss mailing list, toot and spread the
   world!
 
 \end{enumerate}
diff --git a/ivette/package.json b/ivette/package.json
index 5c7f570893ed8f47c798c6d588beb36ca1274f06..f879ae27a6cb94b8e43ae78423dc7e9c90f2ed20 100644
--- a/ivette/package.json
+++ b/ivette/package.json
@@ -1,7 +1,7 @@
 {
   "name": "ivette",
   "productName": "Ivette",
-  "version": "28.0.0",
+  "version": "28.1.0",
   "main": "index.js",
   "repository": "git@git.frama-c.com:frama-c/Ivette.git",
   "author": "Loïc Correnson <loic.correnson@cea.fr>",
diff --git a/ivette/src/dome/renderer/layout/forms.tsx b/ivette/src/dome/renderer/layout/forms.tsx
index 621ff83af522ab9ae1d13ac623ed0642753ecd44..12cc162f1f588fda7bd846e7b161af5f93d51943 100644
--- a/ivette/src/dome/renderer/layout/forms.tsx
+++ b/ivette/src/dome/renderer/layout/forms.tsx
@@ -126,6 +126,7 @@ export type ResetCallback = () => void;
  */
 export class BufferController {
   private readonly evt = new Events();
+  private errors = 0;
 
   /** Notify all reset listener events. */
   reset(): void { this.evt.emit('reset'); }
@@ -139,18 +140,33 @@ export class BufferController {
   /** There are active listeners for Commit event. */
   hasCommit(): boolean { return this.evt.listenerCount('commit') > 0; }
 
+  /** Get the number of errors */
+  getErrors(): number { return  this.errors; }
+
   /** @internal */
   onReset(fn: ResetCallback): void { this.evt.addListener('reset', fn); }
 
   /** @internal */
-  offReset(fn: ResetCallback): void { this.evt.addListener('reset', fn); }
+  offReset(fn: ResetCallback): void { this.evt.removeListener('reset', fn); }
 
   /** @internal */
   onCommit(fn: ResetCallback): void { this.evt.addListener('commit', fn); }
 
   /** @internal */
-  offCommit(fn: ResetCallback): void { this.evt.addListener('commit', fn); }
+  offCommit(fn: ResetCallback): void { this.evt.removeListener('commit', fn); }
+
+  /** @internal */
+  addError(): void { this.errors++; }
+
+  /** @internal */
+  removeError(): void { this.errors--; }
+}
 
+export type Equal<A> = (a:A, b:A) => boolean;
+
+function compare<A>(equal: Equal<A> | undefined, a: A, b: A): boolean
+{
+  return equal ? equal(a, b) : a === b;
 }
 
 /**
@@ -162,7 +178,8 @@ export class BufferController {
 
    - on Reset event, the buffered state is restored to the input value.
 
-   - on Commit event, the buffered state is sent to the input callback.
+   - on Commit event,
+     the buffered state is sent to the input callback or restored.
 
    The returned field state reflects the internal buffer state. Its local
    reset value is either the input reset value or the current input value.
@@ -170,39 +187,55 @@ export class BufferController {
  */
 export function useBuffer<A>(
   remote : BufferController,
-  state: FieldState<A>
+  state: FieldState<A>,
+  equal?: Equal<A>,
 ): FieldState<A>
 {
   const { value, error, reset, onChanged } = state;
   const [ modified, setModified ] = React.useState(false);
   const [ buffer, setBuffer ] = React.useState<A>(value);
   const [ berror, setBerror ] = React.useState<FieldError>(error);
-  const staged = modified && !berror;
+
+  const valid = !isValid(berror);
+  const rollback = reset ?? value;
+
+  // --- Error Count
+  React.useEffect(() => {
+      if (valid) return;
+    remote.addError();
+    return () => remote.removeError();
+  }, [remote, valid]);
 
   // --- Reset
   React.useEffect(() => {
     if (modified) {
       const doReset = (): void => {
         setModified(false);
-        setBuffer(value);
-        setBerror(error);
+        setBuffer(rollback);
+        setBerror(undefined);
       };
       remote.onReset(doReset);
       return () => remote.offReset(doReset);
     } else return;
-  }, [remote, modified, value, error]);
+  }, [remote, modified, rollback]);
 
   // --- Commit
   React.useEffect(() => {
-    if (staged) {
+    if(modified) {
       const doCommit = (): void => {
-        setModified(false);
-        onChanged(buffer, undefined, false);
+        if (valid) {
+          setModified(false);
+          onChanged(buffer, undefined, false);
+        } else {
+          setModified(false);
+          setBuffer(rollback);
+          setBerror(undefined);
+        }
       };
       remote.onCommit(doCommit);
       return () => remote.offCommit(doCommit);
     } else return;
-  }, [remote, staged, buffer, onChanged]);
+  }, [remote, modified, valid, buffer, rollback, onChanged]);
 
   // --- Callback
   const onLocalChange = React.useCallback(
@@ -210,9 +243,9 @@ export function useBuffer<A>(
       setModified(!isReset);
       setBuffer(newValue);
       setBerror(newError);
-      if (isReset && newValue !== value)
+      if (isReset && !compare(equal, newValue, value))
         onChanged(newValue, newError, isReset);
-    }, [value, onChanged]);
+    }, [equal, value, onChanged]);
 
   return {
     value: modified ? buffer : value,
diff --git a/ivette/src/frama-c/states.ts b/ivette/src/frama-c/states.ts
index 13644db3a403696352168de1b8cc81d216b26b53..f7e4f52f1aa74f27084b091525efea40a2dc1751 100644
--- a/ivette/src/frama-c/states.ts
+++ b/ivette/src/frama-c/states.ts
@@ -36,6 +36,7 @@ import { Order } from 'dome/data/compare';
 import { GlobalState, useGlobalState } from 'dome/data/states';
 import { Client, useModel } from 'dome/table/models';
 import { CompactModel } from 'dome/table/arrays';
+import { FieldState, FieldError, isValid } from 'dome/layout/forms';
 import * as Ast from 'frama-c/kernel/api/ast';
 import * as Server from './server';
 
@@ -307,6 +308,32 @@ export function useSyncValue<A>(value: Value<A>): A | undefined {
   return v;
 }
 
+/** Synchronize FieldState and server state only if there is no error. */
+export function useServerField<A>(
+  state: State<A>,
+  defaultValue: A,
+): FieldState<A> {
+  const [value, setState] = useSyncState(state);
+  const stateValue = value !== undefined ? value : defaultValue;
+  const [local, setLocal] = React.useState(stateValue);
+  const [error, setError] = React.useState<FieldError>(undefined);
+
+  const update = React.useCallback((newValue: A, newError: FieldError) => {
+    setLocal(newValue);
+    setError(newError);
+    if (isValid(newError)) {
+      setState(newValue);
+    }
+  }, [setState]);
+
+  return {
+    error,
+    value: isValid(error) ? stateValue : local,
+    reset: isValid(error) ? undefined : stateValue,
+    onChanged: update
+  };
+}
+
 // --------------------------------------------------------------------------
 // --- Synchronized Arrays
 // --------------------------------------------------------------------------
diff --git a/nix/alt-ergo.nix b/nix/alt-ergo.nix
index 75288b5ff80bfb9a250f48bf2fd1964af1188222..0bdce24403b1564fbe1e4ca9972665643a4cba9d 100644
--- a/nix/alt-ergo.nix
+++ b/nix/alt-ergo.nix
@@ -1,4 +1,18 @@
-{ fetchFromGitHub, fetchpatch, lib, which, ocamlPackages }:
+{ lib
+, buildDunePackage
+, fetchFromGitHub
+, camlzip
+, cmdliner
+, dune-configurator
+, menhir
+, num
+, ocplib-simplex
+, psmt2-frontend
+, seq
+, stdlib-shims
+, which
+, zarith
+}:
 
 let
   pname = "alt-ergo";
@@ -14,34 +28,34 @@ let
   };
 in
 
-let alt-ergo-lib = ocamlPackages.buildDunePackage rec {
+let alt-ergo-lib = buildDunePackage rec {
   pname = "alt-ergo-lib";
   inherit version src configureScript;
   configureFlags = [ pname ];
   nativeBuildInputs = [ which ];
-  buildInputs = with ocamlPackages; [ dune-configurator ];
-  propagatedBuildInputs = with ocamlPackages; [ num ocplib-simplex seq stdlib-shims zarith ];
+  buildInputs = [ dune-configurator ];
+  propagatedBuildInputs = [ num ocplib-simplex seq stdlib-shims zarith ];
   preBuild = ''
     substituteInPlace src/lib/util/version.ml --replace 'version="dev"' 'version="${version}"'
   '';
 }; in
 
-let alt-ergo-parsers = ocamlPackages.buildDunePackage rec {
+let alt-ergo-parsers = buildDunePackage rec {
   pname = "alt-ergo-parsers";
   inherit version src configureScript;
   configureFlags = [ pname ];
-  nativeBuildInputs = [ which ocamlPackages.menhir ];
-  propagatedBuildInputs = [ alt-ergo-lib ] ++ (with ocamlPackages; [ camlzip psmt2-frontend ]);
+  nativeBuildInputs = [ which menhir ];
+  propagatedBuildInputs = [ alt-ergo-lib camlzip psmt2-frontend ];
 }; in
 
-ocamlPackages.buildDunePackage {
+buildDunePackage {
 
   inherit pname version src configureScript;
 
   configureFlags = [ pname ];
 
-  nativeBuildInputs = [ which ocamlPackages.menhir ];
-  buildInputs = [ alt-ergo-parsers ocamlPackages.cmdliner ];
+  nativeBuildInputs = [ which menhir ];
+  buildInputs = [ alt-ergo-parsers cmdliner ];
 
   meta = {
     description = "High-performance theorem prover and SMT solver";
diff --git a/nix/frama-c-checkers-shell.nix b/nix/frama-c-checkers-shell.nix
index 1456c7a6e92c47759ec74d112db5ef7ec9bee7aa..356f25ed92e76e4dbf3920f7376a23a7958e6531 100644
--- a/nix/frama-c-checkers-shell.nix
+++ b/nix/frama-c-checkers-shell.nix
@@ -1,7 +1,7 @@
 { lib
 , stdenv
 , black
-, clang_10
+, clang_11
 , combinetura
 , frama-c-hdrck
 , frama-c-lint
@@ -16,7 +16,7 @@ stdenv.mkDerivation rec {
   name = "frama-c-checkers-shell";
   buildInputs = [
     black
-    clang_10
+    clang_11
     combinetura
     frama-c-hdrck
     frama-c-lint
diff --git a/nix/headache.nix b/nix/headache.nix
deleted file mode 100644
index 258016810ddcf07992f3c430e46afd05c8b05135..0000000000000000000000000000000000000000
--- a/nix/headache.nix
+++ /dev/null
@@ -1,32 +0,0 @@
-{ lib
-, camomile
-, fetchFromGitHub
-, buildDunePackage
-, cmdliner
-}:
-
-buildDunePackage rec {
-  version = "v1.05";
-  pname = "headache";
-
-  src = fetchFromGitHub {
-    owner = "Frama-C";
-    repo = pname;
-    rev = version;
-    sha256 = "036lrcxh23j2rrj91wlgq9piyyv1vh82wjy63z1l1ggkkhfs7d8r";
-  };
-
-  useDune2 = true;
-
-  buildInputs = [
-    cmdliner
-    camomile
-  ];
-
-  meta = with lib; {
-    homepage = https://github.com/Frama-C/headache/;
-    description = "Automatic generation of files headers";
-    license = licenses.gpl2;
-    maintainers = [ ];
-  };
-}
diff --git a/nix/internal-tests.nix b/nix/internal-tests.nix
index bef1ffdc48e296581309ef715d9f971583fdf197..48e04ae1ac9118583330ef6b08b856f875d7ac2c 100644
--- a/nix/internal-tests.nix
+++ b/nix/internal-tests.nix
@@ -145,8 +145,12 @@ stdenvNoCC.mkDerivation rec {
     export FRAMAC_WP_CACHEDIR=$wp_cache
   '';
 
+  # The export NIX_GCC_DONT_MANGLE_PREFIX_MAP is meant to disable the
+  # transformation of the path of Frama-C into uppercase when using the
+  # __FILE__ macro.
   checkPhase = ''
     runHook preCheck
+    export NIX_GCC_DONT_MANGLE_PREFIX_MAP=
     dune exec -- frama-c-ptests -never-disabled tests src/plugins/*/tests
     dune build -j1 --display short @ptests_config
   '';
diff --git a/nix/mk_plugin.nix b/nix/mk_plugin.nix
index 4cb2f5f666e6cf5b48e160315a1a765849643c01..dbf03c6ba483b3692831c64dec7588863aea1803 100644
--- a/nix/mk_plugin.nix
+++ b/nix/mk_plugin.nix
@@ -106,9 +106,13 @@ stdenv.mkDerivation {
     ''
   else "") ;
 
+  # The export NIX_GCC_DONT_MANGLE_PREFIX_MAP is meant to disable the
+  # transformation of the path of Frama-C into uppercase when using the
+  # __FILE__ macro.
   checkPhase = ''
     runHook preCheck
     make run-ptests
+    export NIX_GCC_DONT_MANGLE_PREFIX_MAP=
     dune build -j1 --display short @tests/ptests
   '';
 
diff --git a/nix/mk_tests.nix b/nix/mk_tests.nix
index 4d35f6a6a678191b21d4f63da3969eb28169a327..9d71cbf776d6cb7f4c005b4d14be62c03abce397 100644
--- a/nix/mk_tests.nix
+++ b/nix/mk_tests.nix
@@ -103,8 +103,12 @@ stdenvNoCC.mkDerivation {
     ''
     else "" ;
 
+  # The export NIX_GCC_DONT_MANGLE_PREFIX_MAP is meant to disable the
+  # transformation of the path of Frama-C into uppercase when using the
+  # __FILE__ macro.
   buildPhase = ''
     runHook preBuild
+    export NIX_GCC_DONT_MANGLE_PREFIX_MAP=
   '' +
   tests-command + ''
     runHook postBuild
diff --git a/nix/ocaml-versions.txt b/nix/ocaml-versions.txt
new file mode 100644
index 0000000000000000000000000000000000000000..641cb6bc2e393abad444454a7f66179bbc21ebbd
--- /dev/null
+++ b/nix/ocaml-versions.txt
@@ -0,0 +1,3 @@
+4.13.1
+4.14.1
+5.1.1
diff --git a/nix/ocplib-simplex.nix b/nix/ocplib-simplex.nix
index 474f69546d1a10929c579a3bf0366fed1f392414..0e1226479dc2ddc1711afe6ab00695898c4608ba 100644
--- a/nix/ocplib-simplex.nix
+++ b/nix/ocplib-simplex.nix
@@ -2,7 +2,7 @@
 
 let
   pname = "ocplib-simplex";
-  version = "0.4";
+  version = "0.4.1";
 in
 
 stdenv.mkDerivation {
@@ -12,7 +12,7 @@ stdenv.mkDerivation {
     owner = "OCamlPro-Iguernlala";
     repo = pname;
     rev = "v${version}";
-    sha256 = "09niyidrjzrj8g1qwx4wgsdf5m6cwrnzg7zsgala36jliic4di60";
+    sha256 = "sha256-bhlTBpJg031x2lUjwuVrhQgOGmDLW/+0naN8wRjv6i4=";
   };
 
   nativeBuildInputs = [ autoreconfHook ocaml findlib ];
diff --git a/nix/odoc-parser.nix b/nix/odoc-parser.nix
new file mode 100644
index 0000000000000000000000000000000000000000..805d7ce87c36fa388e41dde9bdf45c57d3a55978
--- /dev/null
+++ b/nix/odoc-parser.nix
@@ -0,0 +1,23 @@
+{ lib, fetchurl, buildDunePackage, ocaml, astring, result, camlp-streams }:
+
+buildDunePackage rec {
+  pname = "odoc-parser";
+  version = "2.4.1";
+
+  minimalOCamlVersion = "4.02";
+
+  src = fetchurl {
+    url = "https://github.com/ocaml/odoc/releases/download/${version}/odoc-${version}.tbz";
+    sha256 = "sha256-uBSguQILUD62fxfR2alp0FK2PYzcfN+l+3k7E3VYzts=";
+  };
+
+  propagatedBuildInputs = [ astring result camlp-streams ];
+
+  meta = {
+    description = "Parser for Ocaml documentation comments";
+    license = lib.licenses.isc;
+    maintainers = [ lib.maintainers.marsam ];
+    homepage = "https://github.com/ocaml-doc/odoc-parser";
+    changelog = "https://github.com/ocaml-doc/odoc-parser/raw/${version}/CHANGES.md";
+  };
+}
diff --git a/nix/odoc.nix b/nix/odoc.nix
new file mode 100644
index 0000000000000000000000000000000000000000..88cb8669a4b0a073e4e1416cfc091cbf5bfc99c7
--- /dev/null
+++ b/nix/odoc.nix
@@ -0,0 +1,27 @@
+{ lib, fetchurl, buildDunePackage, ocaml
+, astring, cmdliner, cppo, fpath, result, tyxml
+, odoc-parser, fmt, crunch
+}:
+
+buildDunePackage rec {
+  pname = "odoc";
+  version = "2.4.1";
+
+  src = fetchurl {
+    url = "https://github.com/ocaml/odoc/releases/download/${version}/odoc-${version}.tbz";
+    sha256 = "sha256-uBSguQILUD62fxfR2alp0FK2PYzcfN+l+3k7E3VYzts=";
+  };
+
+  nativeBuildInputs = [ cppo crunch ];
+  buildInputs = [ astring cmdliner fpath result tyxml odoc-parser fmt ];
+
+  doCheck = false;
+
+  meta = {
+    description = "A documentation generator for OCaml";
+    license = lib.licenses.isc;
+    maintainers = [ lib.maintainers.vbgl ];
+    homepage = "https://github.com/ocaml/odoc";
+    changelog = "https://github.com/ocaml/odoc/blob/${version}/CHANGES.md";
+  };
+}
diff --git a/nix/pkgs.nix b/nix/pkgs.nix
index 5e313453a1d3197210c2ab33b4c32445228ca169..2f44490542624d697cdbba9787863e8e8b550e53 100644
--- a/nix/pkgs.nix
+++ b/nix/pkgs.nix
@@ -4,9 +4,11 @@ let
     # External Packages
     alt-ergo = oself.callPackage ./alt-ergo.nix {};
     combinetura = oself.callPackage ./combinetura.nix {};
-    headache = oself.callPackage ./headache.nix {};
     mlmpfr = oself.callPackage ./mlmpfr.nix {};
     ocplib-simplex = oself.callPackage ./ocplib-simplex.nix {};
+    odoc = oself.callPackage ./odoc.nix {};
+    odoc-parser = oself.callPackage ./odoc-parser.nix {};
+    ppxlib = oself.callPackage ./ppxlib.nix {};
     why3 = oself.callPackage ./why3.nix {};
 
     # Helpers
@@ -68,8 +70,8 @@ let
     niv = (import sources.niv {}).niv;
     ocaml-ng = super.lib.mapAttrs (
       name: value:
-        if builtins.hasAttr "overrideScope'" value
-        then value.overrideScope' ocamlOverlay
+        if builtins.hasAttr "overrideScope" value
+        then value.overrideScope ocamlOverlay
         else value
     ) super.ocaml-ng;
     inherit (super.callPackage sources."gitignore.nix" {}) gitignoreSource;
diff --git a/nix/plugin-checkers-shell.nix b/nix/plugin-checkers-shell.nix
index d64816338da7d7eac446892378de4787df1d1d90..cc1d340f645b600ff7866b883cbbf6927d686804 100644
--- a/nix/plugin-checkers-shell.nix
+++ b/nix/plugin-checkers-shell.nix
@@ -1,6 +1,6 @@
 { lib
 , stdenv
-, clang_10
+, clang_11
 , frama-c
 , frama-c-hdrck
 , frama-c-lint
@@ -12,7 +12,7 @@
 stdenv.mkDerivation rec {
   name = "plugin-checkers-shell";
   buildInputs = [
-    clang_10
+    clang_11
     frama-c
     frama-c-hdrck
     frama-c-lint
diff --git a/nix/ppxlib.nix b/nix/ppxlib.nix
new file mode 100644
index 0000000000000000000000000000000000000000..03b1aaee58165d13e3345b84e772466a36ca0094
--- /dev/null
+++ b/nix/ppxlib.nix
@@ -0,0 +1,29 @@
+{ lib, fetchurl, buildDunePackage, ocaml,
+  stdlib-shims, ocaml-compiler-libs, ppx_derivers, stdio
+}:
+
+buildDunePackage rec {
+  pname = "ppxlib";
+  version = "0.32.0";
+
+  duneVersion = "3";
+
+  src = fetchurl {
+    url = "https://github.com/ocaml-ppx/ppxlib/releases/download/${version}/ppxlib-${version}.tbz";
+    sha256 = "sha256-UHzHPM+JXyLutSV6IkODjBijigkQX8/1Xu75FIVVQis=";
+  };
+
+  propagatedBuildInputs = [
+    ocaml-compiler-libs
+    ppx_derivers
+    stdio
+    stdlib-shims
+  ];
+
+  meta = {
+    description = "Comprehensive ppx tool set";
+    license = lib.licenses.mit;
+    maintainers = [ lib.maintainers.vbgl ];
+    homepage = "https://github.com/ocaml-ppx/ppxlib";
+  };
+}
diff --git a/nix/sources.json b/nix/sources.json
index cb4337bbbcbea7ea7b46ef3304ea1af627b0eb28..3619413b613e0e82ab0567486afc34865891c6d4 100644
--- a/nix/sources.json
+++ b/nix/sources.json
@@ -29,10 +29,10 @@
         "homepage": "https://github.com/NixOS/nixpkgs",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "fdd898f8f79e8d2f99ed2ab6b3751811ef683242",
-        "sha256": "05i97acjry4pk1br8glwl97gbfjafq058kblpfpd39r0qr8j6x4s",
+        "rev": "3030f185ba6a4bf4f18b87f345f104e6a6961f34",
+        "sha256": "0v5q4zadnmdiv8hwcsx804l8radx562aqdw0r5nld127c8f7jzz8",
         "type": "tarball",
-        "url": "https://github.com/NixOS/nixpkgs/archive/fdd898f8f79e8d2f99ed2ab6b3751811ef683242.tar.gz",
+        "url": "https://github.com/NixOS/nixpkgs/archive/3030f185ba6a4bf4f18b87f345f104e6a6961f34.tar.gz",
         "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
     },
     "why3": {
diff --git a/nix/src-distrib.nix b/nix/src-distrib.nix
deleted file mode 100644
index 053764b047c9969dca16a2dd0b715c3bd300399b..0000000000000000000000000000000000000000
--- a/nix/src-distrib.nix
+++ /dev/null
@@ -1,35 +0,0 @@
-{ lib
-, stdenv
-, frama-c
-# , headache
-, git
-} :
-
-stdenv.mkDerivation rec {
-  pname = "src-distrib";
-  version = frama-c.version;
-  slang = frama-c.slang;
-
-  src = ./.. ;
-
-  nativeBuildInputs = frama-c.nativeBuildInputs;
-
-  buildInputs = frama-c.buildInputs ++ [
-    # headache
-    git
-  ];
-
-  preBuild = ''
-    patchShebangs ./devel_tools/make-distrib.sh
-  '';
-
-  buildPhase = ''
-    runHook preBuild
-    ./devel_tools/make-distrib.sh
-  '';
-
-  installPhase = ''
-    mkdir -p $out
-    cp frama-c.tar.gz $out
-  '';
-}
diff --git a/nix/wp-cache.nix.sh b/nix/wp-cache.nix.sh
index d633e7332bdf09a1cacce6dea479c35e6ce5b846..0130917c1d86739e019ffd66683a9ecbcdb5d634 100755
--- a/nix/wp-cache.nix.sh
+++ b/nix/wp-cache.nix.sh
@@ -32,5 +32,6 @@ stdenv.mkDerivation rec {
            rev = "$commit" ;
            shallow = true ;
          };
+  installPhase = "touch \$out";
 }
 EOL
diff --git a/opam b/opam
index 5089492c9c3f4e26a334c6c1f12655d696456d86..8553ce6ee227c1ba56ed079f4269024f7e5b91fd 100644
--- a/opam
+++ b/opam
@@ -1,7 +1,7 @@
 opam-version: "2.0"
 name: "frama-c"
 synopsis: "Platform dedicated to the analysis of source code written in C"
-version: "28.0+dev"
+version: "28.1+dev"
 description:"""
 Frama-C gathers several analysis techniques in a single collaborative
 framework, based on analyzers (called "plug-ins") that can build upon the
@@ -72,7 +72,7 @@ authors: [
 homepage: "https://frama-c.com/"
 license: "LGPL-2.1-only"
 dev-repo: "git+https://git.frama-c.com/pub/frama-c.git"
-doc: "http://frama-c.com/download/user-manual-28.0-Nickel.pdf"
+doc: "http://frama-c.com/download/user-manual-28.1-Nickel.pdf"
 bug-reports: "https://git.frama-c.com/pub/frama-c/issues"
 tags: [
   "deductive"
@@ -119,9 +119,13 @@ run-test: [
 ]
 
 depends: [
-  "dune" { >= "3.7.0" & < "3.13.0" }
+  "dune" { >= "3.7.0"
+         & != "3.13.0" # performance problem
+         }
   "dune-configurator"
-  "dune-site" { >= "3.7.0" & < "3.13.0" }
+  "dune-site" { >= "3.7.0"
+              & != "3.13.0" # performance problem
+              }
 
   ( "alt-ergo-free" | "alt-ergo" )
   "conf-graphviz" { post }
diff --git a/reference-configuration.md b/reference-configuration.md
index 2d2c04e085ede305d82ea7c00af824efca15e6b6..5ba397866c50985d0bdb5339e4d27166b587467a 100644
--- a/reference-configuration.md
+++ b/reference-configuration.md
@@ -1,5 +1,5 @@
 The following set of packages is known to be a working configuration for
-compiling Frama-C 28.0.
+compiling Frama-C 28.1.
 
 - OCaml 4.13.1
 - alt-ergo.2.4.2 (for wp, optional)
diff --git a/releases/28.1.md b/releases/28.1.md
new file mode 100644
index 0000000000000000000000000000000000000000..7430d89eb41dcc522b9b1258ea9b1fa7871b94ae
--- /dev/null
+++ b/releases/28.1.md
@@ -0,0 +1,11 @@
+# Kernel
+
+- Fix Cil.isConstant on lvalues with offset.
+
+# Ivette
+
+- Fix Ivette shell wrapper on macOS.
+
+# WP
+
+- Fix interactive prover startup.
diff --git a/share/analysis-scripts/analysis.mk b/share/analysis-scripts/analysis.mk
index 479753a326111a812e8c8a78c65ff1fc7ed82287..dc9e7e41e9c6d3a108c5a10e99352c74dffca705 100644
--- a/share/analysis-scripts/analysis.mk
+++ b/share/analysis-scripts/analysis.mk
@@ -121,7 +121,7 @@ EVAFLAGS   ?= \
   -eva-no-print -eva-no-show-progress -eva-msg-key=-initial-state \
   -eva-print-callstacks -eva-warn-key alarm=inactive \
   -no-deps-print -no-calldeps-print \
-  -eva-warn-key garbled-mix=active,garbled-mix:write=feedback \
+  -eva-warn-key garbled-mix=active,garbled-mix:write=active \
   -calldeps -from-verbose 0 \
   $(if $(EVABUILTINS), -eva-builtin=$(call fc_list,$(EVABUILTINS)),) \
   $(if $(EVAUSESPECS), -eva-use-spec $(call fc_list,$(EVAUSESPECS)),)
diff --git a/share/analysis-scripts/build.py b/share/analysis-scripts/build.py
index a373e31c752c4b188bfa33e7e75f29a37d86adb5..98161b80f3d2e5e2572a0300d73a31c7efdbb5a1 100755
--- a/share/analysis-scripts/build.py
+++ b/share/analysis-scripts/build.py
@@ -73,6 +73,12 @@ parser.add_argument(
     default="main",
     help="name of the main function (default: main)",
 )
+parser.add_argument(
+    "--no-source-filter",
+    action="store_false",
+    dest="source_filter",
+    help="disable source filters (less precise, but speeds up large projects)",
+)
 parser.add_argument(
     "--sources",
     metavar="FILE",
@@ -93,6 +99,7 @@ force = args.force
 jbdb_path = args.jbdb
 machdep = args.machdep
 main = args.main
+do_filter_source = args.source_filter
 sources = args.sources
 targets = args.targets
 debug = args.debug
@@ -197,11 +204,17 @@ def make_target_name(target: Path) -> str:
 # sources are pretty-printed relatively to the .frama-c directory, where the
 # GNUmakefile will reside
 def rel_prefix(path: Path) -> str:
-    return str(path) if os.path.isabs(path) else os.path.relpath(path, start=dot_framac_dir)
+    # heuristics: try a relative path, but if too many ".."'s, then give up
+    # and use an absolute one.
+    relp = os.path.relpath(path, start=dot_framac_dir)
+    if relp.startswith(os.path.join("..", "..")):
+        return path
+    else:
+        return relp
 
 
 def pretty_sources(sources: list[Path]) -> list[str]:
-    return [f"  {rel_prefix(source)} \\" for source in sources]
+    return [f"  {rel_prefix(source)} \\" for source in sorted(sources)]
 
 
 def lines_of_file(path: Path) -> list[str]:
@@ -234,7 +247,7 @@ def copy_fc_stubs() -> Path:
 # [funcname] in [filename].
 # [has_args] is used to distinguish between main(void) and main(int, char**).
 def find_definitions(funcname: str, filename: str) -> list[tuple[str, bool]]:
-    file_content = source_filter.open_and_filter(filename, not under_test)
+    file_content = source_filter.open_and_filter(filename, not under_test and do_filter_source)
     file_lines = file_content.splitlines(keepends=True)
     newlines = function_finder.compute_newline_offsets(file_lines)
     defs = function_finder.find_definitions_and_declarations(
@@ -349,7 +362,7 @@ if unknown_sources:
 # signature, to patch fc_stubs.c.
 
 main_definitions: dict[Path, list[tuple[Path, str, bool]]] = {}
-for target, sources in sources_map.items():
+for target, sources in sorted(sources_map.items()):
     main_definitions[target] = []
     for source in sources:
         fundefs = find_definitions(main, source)
@@ -387,7 +400,7 @@ for defs in main_definitions.values():
 
 if any_has_arguments:
     fc_stubs = copy_fc_stubs()
-    for target in targets:
+    for target in sorted(targets):
         if any(d[2] for d in main_definitions[target]):
             logging.debug(
                 "target %s has main with args, adding fc_stubs.c to its sources",
@@ -416,13 +429,13 @@ if jbdb_path:
         [f"  -json-compilation-database {rel_prefix(jbdb_path)} \\"],
     )
 
-targets_eva = [f"  {make_target_name(target)}.eva \\" for target in targets]
+targets_eva = [f"  {make_target_name(target)}.eva \\" for target in sorted(targets)]
 replace_line(template, "^TARGETS = main.eva", "TARGETS = \\")
 insert_lines_after(template, r"^TARGETS = \\", targets_eva)
 
 delete_line(template, r"^main.parse: \\")
 delete_line(template, r"^  main.c \\")
-for target, sources in reversed(sources_map.items()):
+for target, sources in sorted(sources_map.items(), reverse=True):
     pp_target = make_target_name(target)
     new_lines = [f"{pp_target}.parse: \\"] + pretty_sources(sources) + [""]
     if any(d[2] for d in main_definitions[target]):
diff --git a/share/libc/unistd.h b/share/libc/unistd.h
index a5ba5bf7da343d2590a12be9a56d68c547ecd89e..9be09d430cf2857e1dbc173429c9282abef1bb46 100644
--- a/share/libc/unistd.h
+++ b/share/libc/unistd.h
@@ -1226,6 +1226,14 @@ extern int optind, opterr, optopt;
  */
 extern int getopt(int argc, char * const argv[], const char *optstring);
 
+/*@
+  // missing: assigns 'filesystem' \from name[0..];
+  // missing: assigns errno one of 13 different possible values
+  requires valid_name: valid_read_string(name);
+  assigns \result \from indirect:name[0..strlen(name)];
+  ensures result_ok_or_error: \result == 0 || \result == -1;
+*/
+extern int rmdir(const char *name);
 
 __END_DECLS
 
diff --git a/src/init/boot/dune b/src/init/boot/dune
index efc35b44550f7dd6480f351b65583393b20b4ca6..2dd90880b34d919c0a1d8e5923d94ef48b388390 100644
--- a/src/init/boot/dune
+++ b/src/init/boot/dune
@@ -44,6 +44,7 @@
 (executable
   (name empty_file)
   (public_name frama-c)
+  (modes byte (best exe))
   (modules empty_file)
   (package frama-c)
   (flags :standard -open Frama_c_kernel -linkall)
diff --git a/src/kernel_internals/parsing/cparser.mly b/src/kernel_internals/parsing/cparser.mly
index acab6245091876b01d6013a235a8bbeb7b616c95..a023f02eea1f8f38c1b441d860f4e07316d39d0e 100644
--- a/src/kernel_internals/parsing/cparser.mly
+++ b/src/kernel_internals/parsing/cparser.mly
@@ -929,7 +929,7 @@ else_part:
     {
       let loc = Cil_datatype.Location.of_lexing_loc $sloc in
       Kernel.warning ~wkey:Kernel.wkey_ghost_bad_use ~source:(fst loc)
-        "Invalid ghost else ignored@." ;
+        "Invalid ghost else ignored" ;
       in_block $5
     }
 
@@ -1296,9 +1296,27 @@ enumerator:
       let loc = Cil_datatype.Location.of_lexing_loc $sloc in
       ($1, { expr_node = NOTHING; expr_loc = loc }, loc)
     }
+|   IDENT just_attributes {
+      let attrs = $2 in
+      let loc = Cil_datatype.Location.of_lexing_loc $sloc in
+      Kernel.warning ~wkey:Kernel.wkey_parser_unsupported_attributes
+        ~source:(fst loc)
+        "Discarding attributes in enumerator (unsupported feature): %a"
+        Cprint.print_attributes attrs;
+      ($1, { expr_node = NOTHING; expr_loc = loc }, loc)
+    }
 |   IDENT EQ expression		{
       ($1, $3, Cil_datatype.Location.of_lexing_loc $sloc)
     }
+|   IDENT just_attributes EQ expression {
+      let attrs = $2 in
+      let loc = Cil_datatype.Location.of_lexing_loc $sloc in
+      Kernel.warning ~wkey:Kernel.wkey_parser_unsupported_attributes
+        ~source:(fst loc)
+        "Discarding attributes in enumerator (unsupported feature): %a"
+        Cprint.print_attributes attrs;
+      ($1, $4, loc)
+    }
 ;
 
 
diff --git a/src/kernel_internals/runtime/special_hooks.ml b/src/kernel_internals/runtime/special_hooks.ml
index 96deb0afdae6330f7d383b4a44339077ae9435f0..9c4ebad617365527cf71277e10a5884b17703b79 100644
--- a/src/kernel_internals/runtime/special_hooks.ml
+++ b/src/kernel_internals/runtime/special_hooks.ml
@@ -277,7 +277,7 @@ let warn_if_another_compiler_builtin name =
    depends on Ast_info *)
 let on_call_to_undeclared_function vi =
   let name = vi.Cil_types.vname in
-  if not (Ast_info.is_frama_c_builtin name) then begin
+  if not (Ast_info.start_with_frama_c_builtin name) then begin
     if not (warn_if_another_compiler_builtin name) then
       Kernel.warning ~wkey:Kernel.wkey_implicit_function_declaration
         ~current:true ~once:true
diff --git a/src/kernel_internals/typing/asm_contracts.ml b/src/kernel_internals/typing/asm_contracts.ml
index 836d52abf98bf694478a9bc751b40d327a219cf1..5a117f927511e8f2311654d2cd108b9298b3a675 100644
--- a/src/kernel_internals/typing/asm_contracts.ml
+++ b/src/kernel_internals/typing/asm_contracts.ml
@@ -82,7 +82,7 @@ let access_ptr_elts ~loc tlv =
   let base, basetype =
     if Logic_utils.isLogicVoidPointerType basetype then begin
       let typ = Ctype Cil.charPtrType in
-      Logic_const.term ~loc (TCastE(Cil.charPtrType,base)) typ, typ
+      Logic_const.term ~loc (TCast(false, Ctype Cil.charPtrType,base)) typ, typ
     end else base, basetype
   in
   let offset = Logic_const.term ~loc (TBinOp (PlusPI, base, range)) basetype in
diff --git a/src/kernel_internals/typing/cabs2cil.ml b/src/kernel_internals/typing/cabs2cil.ml
index 734680610c0fdb7ab6044b46f411a7816e4f6070..c440701e41cd2e4d98ad1cab896990b17a35d205 100644
--- a/src/kernel_internals/typing/cabs2cil.ml
+++ b/src/kernel_internals/typing/cabs2cil.ml
@@ -2879,6 +2879,7 @@ let conditionalConversion (t2: typ) (t3: typ) : typ =
       arithmeticConversion t2 t3
     | TComp (comp2,_), TComp (comp3,_)
       when comp2.ckey = comp3.ckey -> t2
+    | TVoid _, TVoid _ -> t2
     | TPtr(_, _), TPtr(TVoid _, _) -> t2
     | TPtr(TVoid _, _), TPtr(_, _) -> t3
     | TPtr _, TPtr _ when Cil_datatype.Typ.equal t2 t3 -> t2
@@ -4794,9 +4795,41 @@ and doType (ghost:bool) isFuncArg
           let cst = constFold true len' in
           (match cst.enode with
            | Const(CInt64(i, _, _)) ->
-             if Integer.lt i Integer.zero then
-               Kernel.error ~once:true ~current:true
-                 "Array length is negative."
+             begin
+               if Integer.lt i Integer.zero then
+                 Kernel.error ~once:true ~current:true
+                   "Array length is negative."
+               else
+                 (* Check if array size (nb elem * size elem) is smaller than
+                    max size. *)
+                 try
+                   let elem_size =
+                     if Cil.isCompleteType bt &&
+                        not (Cil.is_variably_modified_type bt)
+                     then
+                       Integer.of_int @@ bytesSizeOf bt
+                     else
+                       (* Incomplete types can't be array elements,
+                          and multi-dimensional VLAs are currently unsupported.
+                          In both cases an error has already been raised,
+                          we just check here that the size is not widely off.*)
+                       Integer.one
+                   in
+                   let size_t = bitsSizeOfInt theMachine.kindOfSizeOf in
+                   let size_max = Cil.max_unsigned_number size_t in
+                   let array_size = Integer.mul i elem_size in
+                   if Integer.gt array_size size_max then
+                     Kernel.error ~once:true ~current:true
+                       "Array length is too large.";
+                 with
+                 | SizeOfError (msg,_) ->
+                   Kernel.error ~once:true ~current:true
+                     "Unable to compute the size of array element '%a': %s"
+                     Cil_printer.pp_typ bt
+                     msg
+                 | Invalid_argument msg ->
+                   Kernel.fatal ~current:true "%s" msg
+             end
            | _  when not allowVarSizeArrays ->
              if isConstant cst then
                (* e.g., there may be a float constant involved.
@@ -7033,6 +7066,7 @@ and doExp local_env
         (* Now we must find the type of both branches, in order to compute
          * the type of the result *)
         let r2, se2, e2'o (* is an option. None means use e1 *), t2 =
+          (* A GCC extension. [x ? : y;] is equivalent to [x ? x : y;] *)
           match e2.expr_node with
           | Cabs.NOTHING -> begin (* The same as the type of e1 *)
               match ce1 with
diff --git a/src/kernel_internals/typing/ghost_accesses.ml b/src/kernel_internals/typing/ghost_accesses.ml
index aba019286b2148db0fc9d9689ff377d4bc3298dc..3d017490d7d37b0099814ee2fd6e4e67ef584c78 100644
--- a/src/kernel_internals/typing/ghost_accesses.ml
+++ b/src/kernel_internals/typing/ghost_accesses.ml
@@ -172,22 +172,18 @@ class visitor = object(self)
         if not (isGhostType (typeOfLval lv)) then
           Error.assigns_non_ghost_lvalue ~current:true lv
       in
-      let is_builtin vi =
-        Ast_info.is_frama_c_builtin vi.vname ||
-        Cil_builtins.is_builtin vi
-      in
       let failed = match i with
         | Call(_, fexp, _, _) ->
           begin match Kernel_function.(Option.map get_vi @@ get_called fexp) with
             | Some fct
-              when not (is_builtin fct) && not fct.vghost ->
+              when not (Ast_info.is_frama_c_builtin fct) && not fct.vghost ->
               Error.non_ghost_function_call_in_ghost ~current:true () ; true
             | None ->
               Error.function_pointer_call ~current:true () ; true
             | _ -> false
           end
         | Local_init(_, ConsInit(fct, _, _), _)
-          when not (is_builtin fct) && not fct.vghost ->
+          when not (Ast_info.is_frama_c_builtin fct) && not fct.vghost ->
           Error.non_ghost_function_call_in_ghost ~current:true () ; true
         | _ -> false
       in
@@ -200,10 +196,10 @@ class visitor = object(self)
               | Call(_, fexp, _, _) ->
                 let vi =
                   Kernel_function.(get_vi @@ Option.get @@ get_called fexp) in
-                if not (is_builtin vi) then
+                if not (Ast_info.is_frama_c_builtin vi) then
                   error_if_incompatible lv (getReturnType (typeOf fexp)) fexp
               | Local_init(_, ConsInit(fct, _, _), _) ->
-                if not (is_builtin fct) then
+                if not (Ast_info.is_frama_c_builtin fct) then
                   error_if_incompatible lv (getReturnType fct.vtype) (evar fct)
               | _ -> ()
             end
diff --git a/src/kernel_services/abstract_interp/cvalue.ml b/src/kernel_services/abstract_interp/cvalue.ml
index cd0302182f097efe009c8ea7585809ed908c4857..f401f1594ad1c808bca9fa2c2909eaba6f127dd5 100644
--- a/src/kernel_services/abstract_interp/cvalue.ml
+++ b/src/kernel_services/abstract_interp/cvalue.ml
@@ -240,7 +240,7 @@ module V = struct
 
   let pretty_typ typ fmt v =
     let pretty_org fmt org =
-      if not (Origin.is_top org) then
+      if not (Origin.is_unknown org) then
         Format.fprintf fmt "@ @[(origin: %a)@]" Origin.pretty org
     in
     match v with
@@ -510,7 +510,7 @@ module V = struct
           (topify_with_origin_kind topify e2)
       end
 
-  let arithmetic_function = import_function ~topify:Origin.K_Arith
+  let arithmetic_function = import_function ~topify:Origin.Arith
 
   (* Compute the pointwise difference between two Locations_Bytes.t. *)
   let sub_untyped_pointwise = sub_pointwise
@@ -600,13 +600,13 @@ module V = struct
     else if equal singleton_zero v2 then v1
     else if equal v1 v2 && cardinal_zero_or_one v1 then v1
     else
-      import_function ~topify:Origin.K_Arith Ival.bitwise_or v1 v2
+      import_function ~topify:Origin.Arith Ival.bitwise_or v1 v2
 
   let bitwise_and v1 v2 =
     if equal v1 v2 && cardinal_zero_or_one v1 then v1
     else
       let f i1 i2 = Ival.bitwise_and i1 i2 in
-      import_function ~topify:Origin.K_Arith f v1 v2
+      import_function ~topify:Origin.Arith f v1 v2
 
   let shift_right e1 e2 =
     arithmetic_function Ival.shift_right e1 e2
@@ -706,7 +706,7 @@ module V = struct
       Int.min card (Int.two_power size)
 
   let add_untyped ~factor v1 v2 =
-    add_untyped ~topify:Origin.K_Arith ~factor v1 v2
+    add_untyped ~topify:Origin.Arith ~factor v1 v2
 
 end
 
diff --git a/src/kernel_services/abstract_interp/lmap.ml b/src/kernel_services/abstract_interp/lmap.ml
index c289a18af63691b080c6045239c82b5ba653d95a..e09243ea9c2a696788354c95601053fd8a269e08 100644
--- a/src/kernel_services/abstract_interp/lmap.ml
+++ b/src/kernel_services/abstract_interp/lmap.ml
@@ -187,7 +187,7 @@ struct
           let offm' =
             match size with
             | Int_Base.Top ->
-              let orig = Origin.current Origin.K_Arith in
+              let orig = Origin.current Origin.Misalign_write in
               Offsetmap.update_imprecise_everywhere ~validity orig v offm
             | Int_Base.Value size ->
               assert (Int.ge size Int.zero);
diff --git a/src/kernel_services/abstract_interp/locations.ml b/src/kernel_services/abstract_interp/locations.ml
index c6e327fac31841eacbf50aebd569c2ee1b8e1ab1..4e951a71e40ac0261ed1587cde7b900bb860f053 100644
--- a/src/kernel_services/abstract_interp/locations.ml
+++ b/src/kernel_services/abstract_interp/locations.ml
@@ -190,57 +190,9 @@ module Location_Bytes = struct
       in
       M.fold aux_base m (Some Int.zero)
 
-  (* These two states contain the garbled mix that we track. The list preserves
-     the creation order (except it is reversed), while the set is used to test
-     inclusion efficiently so far. Only "original" garbled mix are tracked,
-     i.e. operations that _transform a garbled mix are not tracked. *)
-  module ListGarbledMix = State_builder.List_ref(MapSetLattice)
-      (struct
-        let name = "Locations.ListGarbledMix"
-        let dependencies = [M.self]
-      end)
-  module SetGarbledMix = State_builder.Set_ref(MapSetLattice.Set)
-      (struct
-        let name = "Locations.SetGarbledMix"
-        let dependencies = [M.self]
-      end)
-
-  let get_garbled_mix () = List.rev (ListGarbledMix.get ())
-  let clear_garbled_mix () =
-    ListGarbledMix.clear ();
-    SetGarbledMix.clear ();
-  ;;
-
-  (* We skip Well origins, because they have no location information and can be
-     tracked in the initial state. Unknown origins have no location, and are
-     only built as a side-product of the analysis. Leaf origins are also
-     skipped, because we may create tons of those, that get reduced to precise
-     values by the specifications of the function. *)
-  let is_gm_to_log m =
-    let open Origin in
-    match m with
-    | Map _ | Top (_, (Well | Unknown | Leaf _)) -> false
-    | Top (_, (Misalign_read _ | Merge _ | Arith _)) -> true
-
-  let ref_track_garbled_mix = ref true
-  let do_track_garbled_mix b = ref_track_garbled_mix := b
-
-  (* track a garbled mix if needed, then return it (more convenient for the
-     caller). *)
-  let track_garbled_mix gm =
-    if !ref_track_garbled_mix && is_gm_to_log gm && not (SetGarbledMix.mem gm)
-    then begin
-      SetGarbledMix.set (MapSetLattice.Set.add gm (SetGarbledMix.get ()));
-      ListGarbledMix.set (gm :: ListGarbledMix.get ());
-    end;
-    gm
-
-  let top_with_origin origin =
-    track_garbled_mix (Top(Base.SetLattice.top, origin))
-
-  (* This internal function builds a garbled mix, but does *not* track its
-     creation. This is useful for functions that transform existing GMs. *)
-  let inject_top_origin_internal o b =
+  let top_with_origin origin = Top (Base.SetLattice.top, origin)
+
+  let inject_top_origin o b =
     if Base.Hptset.(equal b empty || equal b Base.null_set) then
       top_int
     else begin
@@ -250,15 +202,12 @@ module Location_Bytes = struct
         Top (Base.(SetLattice.inject (Hptset.add null b)), o)
     end
 
-  let inject_top_origin o b =
-    track_garbled_mix (inject_top_origin_internal o b)
-
   (** some functions can reduce a garbled mix, make sure to normalize
       the result when only NULL remains *)
   let normalize_top m =
     match m with
     | Top (Base.SetLattice.Top, _) | Map _ -> m
-    | Top (Base.SetLattice.Set s, o) -> inject_top_origin_internal o s
+    | Top (Base.SetLattice.Set s, o) -> inject_top_origin o s
 
   let narrow m1 m2 = normalize_top (narrow m1 m2)
   let meet m1 m2 = normalize_top (meet m1 m2)
@@ -273,8 +222,7 @@ module Location_Bytes = struct
       else
         match get_keys v with
         | Base.SetLattice.Top -> top_with_origin o
-        | Base.SetLattice.Set b ->
-          track_garbled_mix (inject_top_origin_internal o b)
+        | Base.SetLattice.Set b -> inject_top_origin o b
 
   let topify_with_origin_kind ok v =
     let o = Origin.current ok in
@@ -291,16 +239,16 @@ module Location_Bytes = struct
     with Not_found -> false
 
   let topify_merge_origin v =
-    topify_with_origin_kind Origin.K_Merge v
+    topify_with_origin_kind Origin.Merge v
 
   let topify_misaligned_read_origin v =
-    topify_with_origin_kind Origin.K_Misalign_read v
+    topify_with_origin_kind Origin.Misalign_read v
 
   let topify_arith_origin v =
-    topify_with_origin_kind Origin.K_Arith v
+    topify_with_origin_kind Origin.Arith v
 
   let topify_leaf_origin v =
-    topify_with_origin_kind Origin.K_Leaf v
+    topify_with_origin_kind Origin.Leaf v
 
   let may_reach base loc =
     if Base.is_null base then true
@@ -331,7 +279,7 @@ module Location_Bytes = struct
       if Base.Hptset.equal garble nonlocals then
         false, v
       else
-        true, inject_top_origin_internal orig nonlocals
+        true, inject_top_origin orig nonlocals
     | Map m ->
       let nonlocals = M.filter non_local m in
       if M.equal nonlocals m then
@@ -370,7 +318,7 @@ module Location_Bytes = struct
     match v with
     | Top (Base.SetLattice.Top, _) -> false, v
     | Top (Base.SetLattice.Set set, origin) ->
-      substitute Base.Hptset.replace (inject_top_origin_internal origin) set
+      substitute Base.Hptset.replace (inject_top_origin origin) set
     | Map map ->
       let decide _key  = Ival.join in
       substitute (M.replace_key ~decide) (fun m -> Map m) map
diff --git a/src/kernel_services/abstract_interp/locations.mli b/src/kernel_services/abstract_interp/locations.mli
index fe99c8a4a3830755707a30b1d4d46dcaf655c9ca..c00226fda5c88eb32e638f77ccfe6857cb1b8a60 100644
--- a/src/kernel_services/abstract_interp/locations.mli
+++ b/src/kernel_services/abstract_interp/locations.mli
@@ -216,17 +216,6 @@ module Location_Bytes : sig
   val may_reach : Base.t -> t -> bool
   (** [may_reach base loc] is true if [base] might be accessed from [loc]. *)
 
-
-  val get_garbled_mix: unit -> t list
-  (** All the garbled mix that have been created so far, sorted by "temporal"
-      order of emission. *)
-
-  val clear_garbled_mix: unit -> unit
-  (** Clear the information on created garbled mix. *)
-
-  val do_track_garbled_mix: bool -> unit
-  val track_garbled_mix: t -> t
-
   (**/**)
   val pretty_debug: t Pretty_utils.formatter
   val clear_caches: unit -> unit
diff --git a/src/kernel_services/abstract_interp/map_lattice.ml b/src/kernel_services/abstract_interp/map_lattice.ml
index 7a64bce7a05c21606a7fe6076943933e596c80fd..46c8138c810a831fb0e3ebf926354588849c5788 100644
--- a/src/kernel_services/abstract_interp/map_lattice.ml
+++ b/src/kernel_services/abstract_interp/map_lattice.ml
@@ -286,7 +286,7 @@ module Make_MapSet_Lattice
 
   type t = Top of KSet.t * Origin.t | Map of KVMap.t
 
-  let top = Top (KSet.top, Origin.top)
+  let top = Top (KSet.top, Origin.unknown)
 
   let bottom = Map KVMap.empty
 
@@ -366,12 +366,12 @@ module Make_MapSet_Lattice
     match t1, t2 with
     | Top _ as x, Map _
     | Map _, (Top _ as x) -> x (* arbitrary, may be approximated *)
-    | Top (s1, o1), Top (s2, o2) -> Top (KSet.link s1 s2, Origin.link o1 o2)
+    | Top (s1, o1), Top (s2, o2) -> Top (KSet.link s1 s2, Origin.join o1 o2)
     | Map m1, Map m2 -> Map (KVMap.link m1 m2)
 
   let meet t1 t2 =
     match t1, t2 with
-    | Top (s1, o1), Top (s2, o2) -> Top (KSet.meet s1 s2, Origin.meet o1 o2)
+    | Top (s1, o1), Top (s2, o2) -> Top (KSet.meet s1 s2, Origin.join o1 o2)
     | Top (KSet.Top, _), (Map _ as m)
     | (Map _ as m), Top (KSet.Top, _) -> m
     | Top (KSet.Set s, _), (Map m)
@@ -382,7 +382,7 @@ module Make_MapSet_Lattice
   let narrow t1 t2 =
     match t1, t2 with
     | Top (s1, o1), Top (s2, o2) ->
-      Top (KSet.narrow s1 s2, Origin.narrow o1 o2)
+      Top (KSet.narrow s1 s2, Origin.join o1 o2)
     | Top (KSet.Top, _), (Map _ as m)
     | (Map _ as m), Top (KSet.Top, _) -> m
     | Top (KSet.Set set, _), (Map m)
@@ -392,8 +392,7 @@ module Make_MapSet_Lattice
 
   let is_included t1 t2 =
     match t1, t2 with
-    | Top (s1, o1), Top (s2, o2)   ->
-      KSet.is_included s1 s2 && Origin.is_included o1 o2
+    | Top (s1, _), Top (s2, _)   -> KSet.is_included s1 s2
     | Map _, Top (KSet.Top, _)   -> true
     | Map m, Top (KSet.Set s, _) -> KVMap.for_all (fun k _ -> KSet.O.mem k s) m
     | Top _, Map _               -> false
diff --git a/src/kernel_services/abstract_interp/offsetmap.ml b/src/kernel_services/abstract_interp/offsetmap.ml
index aea3c83d87c39b133c34d5a4614a815bcda873b7..08fa4d98a93a955bd17f37776e332b8e9bca9a84 100644
--- a/src/kernel_services/abstract_interp/offsetmap.ml
+++ b/src/kernel_services/abstract_interp/offsetmap.ml
@@ -1144,7 +1144,7 @@ module Make (V : Offsetmap_lattice_with_isotropy.S) = struct
           pretty_int abs_min pretty_int abs_max pretty_int rem1 pretty_int
           modu1 V.pretty v1 pretty_int rem2 pretty_int modu2 V.pretty v2 ; *)
     else
-      let topify = Origin.K_Merge in
+      let topify = Origin.Merge in
       let offset = abs_min in
       let size = Integer.length abs_min abs_max in
       let v1_fit = modu1 =~ size && Rel.is_zero rem1
@@ -1174,7 +1174,7 @@ module Make (V : Offsetmap_lattice_with_isotropy.S) = struct
   (* similar to [f_aux_merge_generic], but we perform a reinterpretation in
      all cases. This is to ensure that [V.narrow] can be applied soundly. *)
   let f_aux_merge_narrow merge_v abs_min abs_max rem1 modu1 v1 rem2 modu2 v2 =
-    let topify = Origin.K_Merge in
+    let topify = Origin.Merge in
     let offset = abs_min in
     let size = Integer.length abs_min abs_max in
     let v1' =
@@ -1380,7 +1380,7 @@ module Make (V : Offsetmap_lattice_with_isotropy.S) = struct
           if V.is_isotropic v
           then v
           else
-            let origin = Origin.(current K_Misalign_read) in
+            let origin = Origin.(current Misalign_read) in
             V.topify_with_origin origin v
         in
         V.join subl_value (V.join subr_value current_node_value)
@@ -1523,7 +1523,7 @@ module Make (V : Offsetmap_lattice_with_isotropy.S) = struct
   (*  Finds the value associated to some offsets represented as an ival. *)
   let find ~validity ?(conflate_bottom=true) ~offsets ~size tree =
     let offsets = Tr_offset.trim_by_validity offsets size validity in
-    let topify = Origin.K_Misalign_read in
+    let topify = Origin.Misalign_read in
     let read_one_node ~offset node ~start ~size acc =
       extract_bits_and_stitch ~topify ~conflate_bottom
         ~offset:start ~size
@@ -1666,7 +1666,7 @@ module Make (V : Offsetmap_lattice_with_isotropy.S) = struct
               else if V.is_isotropic v_node
               then rem, size, V.anisotropic_cast ~size joined_value
               else
-                let origin = Origin.(current K_Merge) in
+                let origin = Origin.(current Merge) in
                 let new_value = V.topify_with_origin origin joined_value in
                 let new_rem = Rel.zero and new_modu = Integer.one in
                 new_rem, new_modu, new_value
@@ -1846,9 +1846,10 @@ module Make (V : Offsetmap_lattice_with_isotropy.S) = struct
   let update_aux_tr_offsets ~exact ~offsets ~size v curr_off t =
     match offsets with
     | Tr_offset.Overlap (mn, mx, origin) ->
-      let origin = if origin = Origin.Unknown
-        then Origin.(current K_Misalign_read)
-        else origin
+      let origin =
+        match origin with
+        | Some origin -> origin
+        | None -> Origin.(current Misalign_write)
       in
       let v = V.topify_with_origin origin v in
       (* TODO: check *)
@@ -1871,7 +1872,7 @@ module Make (V : Offsetmap_lattice_with_isotropy.S) = struct
         let v =
           if Int.is_zero (period %~ size) then v
           else
-            let origin = Origin.(current K_Misalign_read) in
+            let origin = Origin.(current Misalign_write) in
             let v' = V.topify_with_origin origin v in
             if not (V.equal v v') then
               Lattice_messages.emit_approximation msg_emitter
@@ -2802,14 +2803,14 @@ module Make_bitwise(V: sig
         in
         `Value (Int_Intervals.fold aux_itv itvs m)
     with Error_Top ->
-      update_imprecise_everywhere ~validity Origin.top v m
+      update_imprecise_everywhere ~validity Origin.(current Misalign_write) v m
 
   let add_binding_ival ~validity ~exact offsets ~size v m =
     match size with
     | Int_Base.Value size ->
       update ~validity ~exact ~offsets ~size v m
     | Int_Base.Top ->
-      update_imprecise_everywhere ~validity Origin.top v m
+      update_imprecise_everywhere ~validity Origin.(current Misalign_write) v m
 
   let fold_itv ?direction ~entire f itv m acc =
     let f' itv (v, _, _) acc = f itv v acc in
diff --git a/src/kernel_services/abstract_interp/origin.ml b/src/kernel_services/abstract_interp/origin.ml
index b804d1db97f5c4d417e95faeb2a0359694006b5f..357ebfd681a2f55cc8dd3ab93b61e9545dac4988 100644
--- a/src/kernel_services/abstract_interp/origin.ml
+++ b/src/kernel_services/abstract_interp/origin.ml
@@ -21,249 +21,181 @@
 (**************************************************************************)
 
 type kind =
-  | K_Misalign_read
-  | K_Leaf
-  | K_Merge
-  | K_Arith
-
-module Location = Cil_datatype.Location
-
-module LocationLattice = struct
-
-  type t = Top | Bottom | Value of Location.t
-
-  module Datatype_Input = struct
-    include Datatype.Serializable_undefined
-
-    type nonrec t = t
-    let name = "Origin.LocationLattice"
-    let reprs = [ Top ]
-    let structural_descr =
-      Structural_descr.t_sum [| [| Location.packed_descr |] |]
-
-    let compare l1 l2 =
-      match l1, l2 with
-      | Top, Top | Bottom, Bottom -> 0
-      | Value loc1, Value loc2 -> Location.compare loc1 loc2
-      | Top, _ -> 1
-      | _, Top -> -1
-      | Bottom, _ -> -1
-      | _, Bottom -> 1
-
-    let equal l1 l2 =
-      match l1, l2 with
-      | Top, Top | Bottom, Bottom -> true
-      | Value loc1, Value loc2 -> Location.equal loc1 loc2
-      | _ -> false
-
-    let hash = function
-      | Top -> 3
-      | Bottom -> 5
-      | Value loc -> Location.hash loc * 7
-
-    let pretty fmt = function
-      | Top -> Format.fprintf fmt "Top"
-      | Bottom ->  Format.fprintf fmt "Bottom"
-      | Value loc -> Format.fprintf fmt "{%a}" Location.pretty loc
-  end
-
-  include (Datatype.Make (Datatype_Input) : Datatype.S with type t := t)
-
-  let current_loc () = Value (Cil.CurrentLoc.get ())
-
-  let join l1 l2 =
-    if l1 == l2 then l1 else
-      match l1, l2 with
-      | Top, _ | _, Top -> Top
-      | Bottom , l | l, Bottom -> l
-      | Value loc1, Value loc2 ->
-        if Location.equal loc1 loc2 then l1 else Top
-
-  let narrow l1 l2 =
-    if l1 == l2 then l1 else
-      match l1, l2 with
-      | Bottom, _ | _, Bottom -> Bottom
-      | Top , l | l, Top -> l
-      | Value loc1, Value loc2 ->
-        if Location.equal loc1 loc2 then l1 else Bottom
-
-  let meet = narrow
-end
-
-type origin =
-  | Misalign_read of LocationLattice.t
-  | Leaf of LocationLattice.t
-  | Merge of LocationLattice.t
-  | Arith of LocationLattice.t
+  | Misalign_read
+  | Misalign_write
+  | Leaf
+  | Merge
+  | Arith
+
+let kind_rank = function
+  | Misalign_read -> 0
+  | Misalign_write -> 1
+  | Leaf -> 2
+  | Merge -> 3
+  | Arith -> 4
+
+let kind_label = function
+  | Misalign_read -> "Misaligned read"
+  | Misalign_write -> "Misaligned write"
+  | Leaf -> "Library function"
+  | Merge -> "Merge"
+  | Arith -> "Arithmetic"
+
+type location = Cil_datatype.Location.t
+
+type tt =
+  | Origin of { kind: kind; loc: location; id: int; }
   | Well
   | Unknown
 
+(* Unique id for each origin. Used to keep the oldest origin when a garbled
+   mix may have several origins. *)
+module Id = State_builder.Counter (struct let name = "Origin.Id" end)
+
+let current kind =
+  let id = Id.next () in
+  let loc = Cil.CurrentLoc.get () in
+  Origin { kind; loc; id; }
+
+let well = Well
+let unknown = Unknown
+let is_unknown t = t = Unknown
+
+module Prototype = struct
+  include Datatype.Serializable_undefined
+  type t = tt
+  let name = "Origin"
+  let reprs = [ Unknown ]
+
+  let compare t1 t2 =
+    match t1, t2 with
+    | Origin o1, Origin o2 ->
+      if o1.kind = o2.kind
+      then Cil_datatype.Location.compare o1.loc o2.loc
+      else kind_rank o2.kind - kind_rank o1.kind
+    | Well, Well | Unknown, Unknown -> 0
+    | Origin _, _ | Well, Unknown -> 1
+    | _, Origin _ | Unknown, Well -> -1
+
+  let equal = Datatype.from_compare
+
+  let hash = function
+    | Well -> 0
+    | Unknown -> 1
+    | Origin { kind; loc; } ->
+      Hashtbl.hash (kind_rank kind, Cil_datatype.Location.hash loc) + 2
+
+  let pretty fmt = function
+    | Well -> Format.fprintf fmt "Well"
+    | Unknown -> Format.fprintf fmt "Unknown"
+    | Origin { kind; loc; } ->
+      let pretty_loc = Cil_datatype.Location.pretty in
+      Format.fprintf fmt "%s@ {%a}" (kind_label kind) pretty_loc loc
+end
 
-let current = function
-  | K_Misalign_read -> Misalign_read (LocationLattice.current_loc ())
-  | K_Leaf -> Leaf (LocationLattice.current_loc ())
-  | K_Merge -> Merge (LocationLattice.current_loc ())
-  | K_Arith -> Arith (LocationLattice.current_loc ())
-
-let equal o1 o2 = match o1, o2 with
-  | Well, Well | Unknown, Unknown -> true
-  | Leaf o1, Leaf o2 | Arith o1, Arith o2 | Merge o1, Merge o2
-  | Misalign_read o1, Misalign_read o2  ->
-    LocationLattice.equal o1 o2
-  | Misalign_read _, _ -> false
-  | _, Misalign_read _ -> false
-  |  Leaf _, _ -> false
-  |  _, Leaf _ -> false
-  | Merge _, _ -> false
-  | _, Merge _ -> false
-  | Arith _, _ -> false
-  | _, Arith _ -> false
-  | _, Well | Well, _ -> false
-
-let compare o1 o2 = match o1, o2 with
-  | Misalign_read s1, Misalign_read s2
-  | Leaf s1, Leaf s2
-  | Merge s1, Merge s2
-  | Arith s1, Arith s2 ->
-    LocationLattice.compare s1 s2
-
-  | Well, Well | Unknown, Unknown -> 0
-
-  | Misalign_read _, (Leaf _ | Merge _ | Arith _ | Well | Unknown)
-  | Leaf _, (Merge _ | Arith _ | Well | Unknown)
-  | Merge _, (Arith _ | Well | Unknown)
-  | Arith _, (Well | Unknown)
-  | Well, Unknown ->
-    -1
-
-  | Unknown, (Well | Arith _ | Merge _ | Leaf _ | Misalign_read _)
-  | Well, (Arith _ | Merge _ | Leaf _ | Misalign_read _)
-  | Arith _, (Merge _ | Leaf _ | Misalign_read _)
-  | Merge _, (Leaf _ | Misalign_read _)
-  | Leaf _, Misalign_read _
-    -> 1
-
-let top = Unknown
-let is_top x = equal top x
-
-
-let pretty_source fmt = function
-  | LocationLattice.Top -> () (* Hide unhelpful 'TopSet' *)
-  | LocationLattice.Value _ | LocationLattice.Bottom as s ->
-    Format.fprintf fmt "@ %a" LocationLattice.pretty s
-
-let pretty fmt o = match o with
-  | Unknown ->
-    Format.fprintf fmt "Unknown"
-  | Misalign_read o ->
-    Format.fprintf fmt "Misaligned%a" pretty_source o
-  | Leaf o ->
-    Format.fprintf fmt "Library function%a" pretty_source o
-  | Merge o ->
-    Format.fprintf fmt "Merge%a" pretty_source o
-  | Arith o ->
-    Format.fprintf fmt "Arithmetic%a" pretty_source o
-  | Well ->       Format.fprintf fmt "Well"
+include Datatype.Make_with_collections (Prototype)
 
 let pretty_as_reason fmt org =
-  if not (is_top org) then
-    Format.fprintf fmt " because of %a" pretty org
-
-
-let hash o = match o with
-  | Misalign_read o ->
-    2001 +  (LocationLattice.hash o)
-  | Leaf o ->
-    2501 + (LocationLattice.hash o)
-  | Merge o ->
-    3001 + (LocationLattice.hash o)
-  | Arith o ->
-    3557 + (LocationLattice.hash o)
-  | Well -> 17
-  | Unknown -> 97
-
-include Datatype.Make
-    (struct
-      type t = origin
-      let name = "Origin"
-      let structural_descr = Structural_descr.t_unknown
-      let reprs = [ Well; Unknown ]
-      let compare = compare
-      let equal = equal
-      let hash = hash
-      let rehash = Datatype.undefined
-      let copy = Datatype.undefined
-      let pretty = pretty
-      let mem_project = Datatype.never_any_project
-    end)
-
-let bottom = Arith LocationLattice.Bottom
+  if not (is_unknown org)
+  then Format.fprintf fmt " because of %a" pretty org
+
+let descr = function
+  | Unknown -> "unknown origin"
+  | Well -> "well in initial state"
+  | Origin { kind } ->
+    match kind with
+    | Misalign_read -> "misaligned read of addresses"
+    | Misalign_write -> "misaligned write of addresses"
+    | Leaf -> "assigns clause on addresses"
+    | Merge -> "imprecise merge of addresses"
+    | Arith -> "arithmetic operation on addresses"
+
+(* Keep the oldest known origin: it is probably the most relevant origin, as
+   subsequent ones may have been created because of the first. *)
+let join t1 t2 =
+  if t1 == t2 then t1 else
+    match t1, t2 with
+    | Unknown, x | x, Unknown -> x
+    | Well, _ | _, Well -> Well
+    | Origin o1, Origin o2 -> if o1.id <= o2.id then t1 else t2
+
+
+(* For each garbled mix origin, keep track of:
+   - the number of writes (according to [register_write] below), i.e. the number
+     of times a garbled mix with this origin has been written in a state during
+     the analysis.
+   - the number of reads (according to [register_read] below), i.e. the number
+     of times a garbled mix with this origin is used by the analysis.
+     Only reads at a different location than that of the origin are counted:
+     if a garbled mix is only used where it has been created, it has no more
+     impact on the analysis precision than any other imprecise value.
+   - the set of bases related to garbled mix with this origin.
+
+   These info are printed at the end of an Eva analysis. *)
+
+module History_Info = struct
+  let name = "Origin.History"
+  let dependencies = []
+  let size = 32
+end
 
-let join o1 o2 =
-  let result =
-    if o1 == o2
-    then o1
-    else
-      match o1, o2 with
-      | Unknown,_ | _, Unknown -> Unknown
-      | Well,_ | _ , Well   -> Well
-      | Misalign_read o1, Misalign_read o2 ->
-        Misalign_read(LocationLattice.join o1 o2)
-      | _, (Misalign_read _ as m) | (Misalign_read _ as m), _ -> m
-      | Leaf o1, Leaf o2 ->
-        Leaf(LocationLattice.join o1 o2)
-      | (Leaf _ as m), _ | _, (Leaf _ as m) -> m
-      | Merge o1, Merge o2 ->
-        Merge(LocationLattice.join o1 o2)
-      | (Merge _ as m), _ | _, (Merge _ as m) -> m
-      | Arith o1, Arith o2 ->
-        Arith(LocationLattice.join o1 o2)
-        (* | (Arith _ as m), _ | _, (Arith _ as m) -> m *)
+(* Number of writes, number of reads, related bases. *)
+module History_Data =
+  Datatype.Triple (Datatype.Int) (Datatype.Int) (Base.SetLattice)
+module History = State_builder.Hashtbl (Hashtbl) (History_Data) (History_Info)
+
+let clear () = Id.reset (); History.clear ()
+
+let is_current = function
+  | Unknown | Well -> false
+  | Origin { loc } -> Cil_datatype.Location.equal loc (Cil.CurrentLoc.get ())
+
+(* Returns true if the origin has never been registered and is related to the
+   current location. *)
+let register_write bases t =
+  if is_unknown t then false else
+    let change (w, r, b) = w+1, r, Base.SetLattice.join b bases in
+    let count, _, _ = History.memo ~change (fun _ -> 1, 0, bases) t in
+    count < 2 && is_current t
+
+(* Registers a read only if the current location is not that of the origin. *)
+let register_read bases t =
+  if not (is_unknown t || is_current t) then
+    let change (w, r, b) = w, r+1, Base.SetLattice.join b bases in
+    ignore (History.memo ~change (fun _ -> 0, 1, bases) t)
+
+(* Returns the list of recorded origins, sorted by number of reads.
+   Origins with no reads are filtered. *)
+let get_history () =
+  let list = List.of_seq (History.to_seq ()) in
+  let list = List.filter (fun (_origin, (_, r, _)) -> r > 0) list in
+  let cmp (origin1, (_, r1, _)) (origin2, (_, r2, _)) =
+    let r = r2 - r1 in
+    if r <> 0 then r else compare origin1 origin2
   in
-  (*  Format.printf "Origin.join %a %a -> %a@." pretty o1 pretty o2 pretty result;
-  *)
-  result
-
-let link = join
-
-let meet o1 o2 =
-  if o1 == o2
-  then o1
-  else
-    match o1, o2 with
-    | Arith o1, Arith o2 ->
-      Arith(LocationLattice.meet o1 o2)
-    | (Arith _ as m), _ | _, (Arith _ as m) -> m
-    | Merge o1, Merge o2 ->
-      Merge(LocationLattice.meet o1 o2)
-    | (Merge _ as m), _ | _, (Merge _ as m) -> m
-    | Leaf o1, Leaf o2 ->
-      Leaf(LocationLattice.meet o1 o2)
-    | (Leaf _ as m), _ | _, (Leaf _ as m) -> m
-    | Misalign_read o1, Misalign_read o2 ->
-      Misalign_read(LocationLattice.meet o1 o2)
-    | _, (Misalign_read _ as m) | (Misalign_read _ as m), _ -> m
-    | Well, Well -> Well
-    | Well,m | m, Well -> m
-    | Unknown, Unknown -> Unknown
-
-let narrow o1 o2 =
-  if o1 == o2
-  then o1
-  else
-    match o1, o2 with
-    | Arith o1, Arith o2 -> Arith (LocationLattice.narrow o1 o2)
-    | Merge o1, Merge o2 -> Merge (LocationLattice.narrow o1 o2)
-    | Leaf o1, Leaf o2 -> Leaf (LocationLattice.narrow o1 o2)
-    | Misalign_read o1, Misalign_read o2 ->
-      Misalign_read (LocationLattice.narrow o1 o2)
-    | Well, Well -> Well
-    | Unknown, m | m, Unknown -> m
-    | _, _ -> Unknown
-
-let is_included o1 o2 =
-  (equal o1 (meet o1 o2))
-
+  List.sort cmp list
+
+let pretty_origin fmt origin =
+  match origin with
+  | Unknown -> Format.fprintf fmt "Unknown origin"
+  | Well -> Format.fprintf fmt "Initial state"
+  | Origin { loc } ->
+    Format.fprintf fmt "%a: %s"
+      Cil_datatype.Location.pretty loc (descr origin)
+
+let pretty_history fmt =
+  let list = get_history () in
+  let pp_origin fmt (origin, (w, r, bases)) =
+    let bases = Base.SetLattice.filter (fun b -> not (Base.is_null b)) bases in
+    Format.fprintf fmt
+      "@[<hov 2>%a@ (read %i times, propagated %i times)@ \
+       garbled mix of &%a@]"
+      pretty_origin origin r w Base.SetLattice.pretty bases
+  in
+  if list <> [] then
+    Format.fprintf fmt
+      "@[<v 2>Origins of garbled mix generated during analysis:@,%a@]"
+      (Pretty_utils.pp_list ~sep:"@," pp_origin) list
 
 (*
 Local Variables:
diff --git a/src/kernel_services/abstract_interp/origin.mli b/src/kernel_services/abstract_interp/origin.mli
index 4f6b0a4fa8f30e7216564041337bdc71afaf5303..bb8cdc57192bd5ebf3e2932f41bbb66f10f855ad 100644
--- a/src/kernel_services/abstract_interp/origin.mli
+++ b/src/kernel_services/abstract_interp/origin.mli
@@ -20,57 +20,58 @@
 (*                                                                        *)
 (**************************************************************************)
 
-(** The datastructures of this module can be used to track the origin
-    of a major imprecision in the values of an abstract domain. *)
+(** This module is used to track the origin of very imprecise values
+    (namely "garbled mix", created on imprecise or unsupported operations on
+    addresses) propagated by an Eva analysis. *)
 
-(** This module is generic, although currently used only by the plugin Value.
-    Within Value, values that have an imprecision origin are "garbled mix",
-    ie. a numeric value that contains bits extracted from at least one
-    pointer, and that are not the result of a translation *)
+include Datatype.S
 
+type kind =
+  | Misalign_read (* Misaligned read of addresses *)
+  | Misalign_write (* Misaligned write of addresses *)
+  | Leaf  (* Interpretation of assigns clause *)
+  | Merge (* Imprecise merge of addresses *)
+  | Arith (* Arithmetic operation on addresses *)
 
-(** Lattice of source locations. *)
-module LocationLattice : Datatype.S
-
-(** List of possible origins. Most of them also include the set of
-    source locations where the operation took place. *)
-type origin =
-  | Misalign_read of LocationLattice.t (** Read of not all the bits of a
-                                           pointer, typically through a pointer cast *)
-  | Leaf of LocationLattice.t (** Result of a function without a body *)
-  | Merge of LocationLattice.t (** Join between two control-flows *)
-  | Arith of LocationLattice.t (** Arithmetic operation that cannot be
-                                      represented, eg. ['&x * 2'] *)
-  | Well (** Imprecise variables of the initial state *)
-  | Unknown
+(** Creates an origin of the given kind, associated with the current source
+    location extracted from [Cil.CurrentLoc]. *)
+val current: kind -> t
 
-include Datatype.S with type t = origin
+(** Origin for garbled mix created in the initial state of the analysis
+    (not associated to a source location). *)
+val well: t
 
+(** Unknown origin. *)
+val unknown: t
+val is_unknown: t -> bool
 
-type kind =
-  | K_Misalign_read
-  | K_Leaf
-  | K_Merge
-  | K_Arith
+(** Pretty-print [because of <origin>] if the origin is not {!Unknown}, or
+    nothing otherwise. *)
+val pretty_as_reason: Format.formatter -> t -> unit
 
-val current: kind -> origin
-(** This is automatically extracted from [Cil.CurrentLoc] *)
+(** Short description of an origin. *)
+val descr: t -> string
 
-val pretty_as_reason: Format.formatter -> t -> unit
-(** Pretty-print [because of <origin>] if the origin is not {!Unknown}, or
-    nothing otherwise *)
+val join: t -> t -> t
 
-val top: t
-val is_top: t -> bool
+(** Records the write of an imprecise value of the given bases,
+    with the given origin.
+    Returns [true] if the given origin has never been written before,
+    and if it is related to the current location — in which case a warning
+    should probably be emitted. *)
+val register_write: Base.SetLattice.t -> t -> bool
 
-val bottom: t
+(** Records the read of an imprecise value of the given bases,
+    with the given origin. *)
+val register_read: Base.SetLattice.t -> t -> unit
 
-val join: t -> t -> t
-val link: t -> t -> t
-val meet: t -> t -> t
-val narrow: t -> t -> t
+(** Pretty-print a summary of the origins of imprecise values recorded
+    by [register_write] and [register_read] above. *)
+val pretty_history: Format.formatter -> unit
 
-val is_included: t -> t -> bool
+(** Clears the history of origins saved by [register_write] and
+    [register_read] above. *)
+val clear: unit -> unit
 
 (*
 Local Variables:
diff --git a/src/kernel_services/abstract_interp/tr_offset.ml b/src/kernel_services/abstract_interp/tr_offset.ml
index 7df602f5d22549ba73b6b201ca00e887e9de23f9..4f4093907f48e38c81700e6a897d8803693f8b0c 100644
--- a/src/kernel_services/abstract_interp/tr_offset.ml
+++ b/src/kernel_services/abstract_interp/tr_offset.ml
@@ -26,7 +26,7 @@ type t =
   | Invalid
   | Set of Int.t list
   | Interval of Int.t * Int.t * Int.t
-  | Overlap of Int.t * Int.t * Origin.t
+  | Overlap of Int.t * Int.t * Origin.t option
 
 let pretty fmt = function
   | Invalid -> Format.fprintf fmt "Invalid"
@@ -35,7 +35,8 @@ let pretty fmt = function
   | Interval (mn, mx, modu) -> Format.fprintf fmt "Interval (%a,%a,%a)"
                                  Int.pretty mn Int.pretty mx Int.pretty modu
   | Overlap (mn, mx, o) -> Format.fprintf fmt "Overlap (%a,%a,%a)"
-                             Int.pretty mn Int.pretty mx Origin.pretty o
+                             Int.pretty mn Int.pretty mx
+                             (Pretty_utils.pp_opt Origin.pretty) o
 
 (* Reduces [ival] for an access according to [validity]. *)
 let reduce_offset_by_validity origin ival size validity =
@@ -64,7 +65,7 @@ let reduce_offset_by_validity origin ival size validity =
   | Base.Unknown (min, _, max) -> reduce_for_bounds min max
   | Base.Variable v -> reduce_for_bounds Int.zero v.Base.max_alloc
 
-let trim_by_validity ?(origin=Origin.Unknown) ival size validity =
+let trim_by_validity ?origin ival size validity =
   reduce_offset_by_validity origin ival size validity
 
 (*
diff --git a/src/kernel_services/abstract_interp/tr_offset.mli b/src/kernel_services/abstract_interp/tr_offset.mli
index 7f72dff4878d09edeb5d9247d8bcb0c00ca7e652..8b16d56ebda0da7ba18a0b9a989766ce3741a419 100644
--- a/src/kernel_services/abstract_interp/tr_offset.mli
+++ b/src/kernel_services/abstract_interp/tr_offset.mli
@@ -29,10 +29,10 @@ type t = private
   | Set of Integer.t list (** Limited number of locations *)
   | Interval of Integer.t * Integer.t * Integer.t
   (** [Interval(min, max, modulo)]*)
-  | Overlap of Integer.t * Integer.t * Origin.t
-  (**[Overlap(min, max, origin)]
-     - [origin]: the location covers the entire range [min..max],
-                 but consecutive offsets overlap *)
+  | Overlap of Integer.t * Integer.t * Origin.t option
+  (** [Overlap(min, max, origin)]
+      - [origin]: the location covers the entire range [min..max],
+                  but consecutive offsets overlap *)
 
 val pretty: t Pretty_utils.formatter
 
diff --git a/src/kernel_services/ast_data/alarms.ml b/src/kernel_services/ast_data/alarms.ml
index 16ab1a0a5cb8b889b7df6868556313aaa273af74..1fbd95cf54409731a14b92c32289277fb255c55b 100644
--- a/src/kernel_services/ast_data/alarms.ml
+++ b/src/kernel_services/ast_data/alarms.ml
@@ -519,7 +519,7 @@ let create_predicate ?(loc=Location.unknown) alarm =
               | _ -> Cil.voidPtrType
             in
             let zero = Cil.lzero () in
-            Logic_const.term (TCastE (typ, zero)) (Ctype typ)
+            Logic_const.term (TCast (false, Ctype typ, zero)) (Ctype typ)
           end
         | Some e -> Logic_utils.expr_to_term e
       in
diff --git a/src/kernel_services/ast_data/cil_types.ml b/src/kernel_services/ast_data/cil_types.ml
index 55ea832112543d096e2c2d08246197b5091f8729..9fb991e9eccd6b53dff7da97314be358c63f6f54 100644
--- a/src/kernel_services/ast_data/cil_types.ml
+++ b/src/kernel_services/ast_data/cil_types.ml
@@ -1362,7 +1362,13 @@ and term_node =
   | TAlignOfE of term (** alignment of the type of an expression. *)
   | TUnOp of unop * term (** unary operator. *)
   | TBinOp of binop * term * term (** binary operators. *)
-  | TCastE of typ * term (** cast to a C type. *)
+  | TCast of bool * logic_type * term
+  (** cast to a C type (if bool is false)
+      or an implicit conversion from C type to a logic type (if bool is true).
+      In the second case:
+      The logic type must not be a Ctype.
+      In particular, used to denote lifting to Linteger and Lreal.
+  *)
   | TAddrOf of term_lval (** address of a term. *)
   | TStartOf of term_lval (** beginning of an array. *)
 
@@ -1380,11 +1386,7 @@ and term_node =
   | Toffset of logic_label * term (** offset from the base address of a pointer. *)
   | Tblock_length of logic_label * term (** length of the block pointed to by the term. *)
   | Tnull (** the null pointer. *)
-  | TLogic_coerce of logic_type * term
-  (** implicit conversion from a C type to a logic type.
-      The logic type must not be a Ctype. In particular, used to denote
-      lifting to Linteger and Lreal.
-  *)
+
   | TUpdate of term * term_offset * term
   (** functional update of a field. *)
   | Ttypeof of term (** type tag for a term. *)
diff --git a/src/kernel_services/ast_printing/cil_printer.ml b/src/kernel_services/ast_printing/cil_printer.ml
index b8d83736750983e051905470103a7e9e89f744c9..a9d7c98103737e6c3f99048062c7ff2a5af3647a 100644
--- a/src/kernel_services/ast_printing/cil_printer.ml
+++ b/src/kernel_services/ast_printing/cil_printer.ml
@@ -360,7 +360,7 @@ module Precedence = struct
     | Tapp({ l_var_info },[],[_;_])
       when l_var_info.lv_name = "\\repeat" -> bitwiseLevel
     (* Unary *)
-    | TCastE(_,_)
+    | TCast(false,_,_)
     | TAddrOf(_)
     | TStartOf(_)
     | TUnOp((Neg|BNot|LNot),_) -> unaryLevel
@@ -382,7 +382,7 @@ module Precedence = struct
     | TConst _
     | Tnull | TLval (TResult _,TNoOffset) | Tcomprehension _  | Tempty_set -> 0
     | Tif (_, _, _)  -> questionLevel
-    | TLogic_coerce(_,e) -> (getParenthLevelLogic e.term_node) + 1
+    | TCast (true,_,e) -> (getParenthLevelLogic e.term_node) + 1
 
   (* Create an expression of the same shape, and use {!getParenthLevel} *)
   let getParenthLevelAttrParam = function
@@ -468,12 +468,12 @@ let is_same_direction_rel dir op =
 
 let remove_no_op_coerce t =
   match t.term_node with
-  | TLogic_coerce (ty,t) when Cil.no_op_coerce ty t -> t
+  | TCast (true, ty,t) when Cil.no_op_coerce ty t -> t
   | _ -> t
 
 let rec is_singleton t =
   match t.term_node with
-  | TLogic_coerce(Ltype ({ lt_name = "set"},_), t') -> is_singleton t'
+  | TCast (true, Ltype ({ lt_name = "set"},_), t') -> is_singleton t'
   | _ -> not (Logic_const.is_set_type t.term_type)
 
 (* when pretty-printing relation chains, a < b && b' < c, it can happen that
@@ -2547,7 +2547,7 @@ class cil_printer () = object (self)
       fprintf fmt "@[%a@]" self#tand_list (get_tand_list l [r])
     | TBinOp (op,l,r) ->
       fprintf fmt "@[%a@ %a@ %a@]" term l self#term_binop op term r
-    | TCastE (ty,t) ->
+    | TCast (false, Ctype ty,t) ->
       begin match ty, t.term_node with
         | TFloat(fk,_) , TConst(LReal r as cst) when
             not Kernel.(is_debug_key_enabled dkey_print_logic_coercions) &&
@@ -2556,6 +2556,8 @@ class cil_printer () = object (self)
         | _ ->
           fprintf fmt "(%a)%a" (self#typ None) ty term t
       end
+    | TCast(false,_,_) ->
+      Kernel.fatal "Found a TCast to ctype without a Ctype associated"
     | TAddrOf lv ->
       fprintf fmt "&%a" (self#term_lval_prec Precedence.addrOfLevel) lv
     | TStartOf lv ->
@@ -2659,7 +2661,7 @@ class cil_printer () = object (self)
               self#quantifiers args)
         pp_defn
         term body
-    | TLogic_coerce(ty,t) ->
+    | TCast (true, ty,t) ->
       if (not (Cil.no_op_coerce ty t)) ||
          Kernel.is_debug_key_enabled Kernel.dkey_print_logic_coercions
       then
diff --git a/src/kernel_services/ast_printing/cil_types_debug.ml b/src/kernel_services/ast_printing/cil_types_debug.ml
index 97cbc21081fba3d4763edac53f4ed9bf1f68c882..bdd64597f8619aa9e107a96a7c81671aebfdff2c 100644
--- a/src/kernel_services/ast_printing/cil_types_debug.ml
+++ b/src/kernel_services/ast_printing/cil_types_debug.ml
@@ -660,7 +660,7 @@ and pp_term_node fmt = function
   | TUnOp(unop,term) -> Format.fprintf fmt "TUnOp(%a,%a)"  pp_unop unop  pp_term term
   | TBinOp(binop,term1,term2) ->
     Format.fprintf fmt "TBinOp(%a,%a,%a)"  pp_binop binop  pp_term term1  pp_term term2
-  | TCastE(typ,term) -> Format.fprintf fmt "TCastE(%a,%a)"  pp_typ typ  pp_term term
+  | TCast(logic,typ,term) -> Format.fprintf fmt "TCast(%a,%a,%a)" pp_bool logic pp_logic_type typ  pp_term term
   | TAddrOf(term_lval) -> Format.fprintf fmt "TAddrOf(%a)"  pp_term_lval  term_lval
   | TStartOf(term_lval) -> Format.fprintf fmt "TStartOf(%a)"  pp_term_lval term_lval
   | Tapp(logic_info,logic_label_list,term_list) ->
@@ -681,8 +681,6 @@ and pp_term_node fmt = function
   | Tblock_length(logic_label,term) ->
     Format.fprintf fmt "Tblock_length(%a,%a)"  pp_logic_label logic_label  pp_term term
   | Tnull -> Format.fprintf fmt "Tnull"
-  | TLogic_coerce(logic_type,term) ->
-    Format.fprintf fmt "TLogic_coerce(%a,%a)"  pp_logic_type logic_type  pp_term term
   | TUpdate(term1,term_offset,term2) ->
     Format.fprintf fmt "TUpdate(%a,%a,%a)"  pp_term term1  pp_term_offset term_offset  pp_term term2
   | Ttypeof(term) -> Format.fprintf fmt "Ttypeof(%a)"  pp_term term
diff --git a/src/kernel_services/ast_queries/ast_diff.ml b/src/kernel_services/ast_queries/ast_diff.ml
index 222d4c77a26e2b10ba247b08b698d63ff7a6b886..3b73ea2acc6ee7008575ff226599c2d6a29fb22e 100644
--- a/src/kernel_services/ast_queries/ast_diff.ml
+++ b/src/kernel_services/ast_queries/ast_diff.ml
@@ -582,8 +582,8 @@ and is_same_term_node t t' env =
   | TUnOp(op,t), TUnOp(op',t') -> Unop.equal op op' && is_same_term t t' env
   | TBinOp(op,t1,t2), TBinOp(op',t1',t2') ->
     Binop.equal op op' && is_same_term t1 t1' env && is_same_term t2 t2' env
-  | TCastE(typ,term), TCastE(typ',term') ->
-    is_same_type typ typ' env && is_same_term term term' env
+  | TCast(is_logic, typ, term), TCast(is_logic', typ', term') ->
+    is_logic = is_logic' && is_same_logic_type typ typ' env && is_same_term term term' env
   | TAddrOf lv, TAddrOf lv'
   | TStartOf lv, TStartOf lv' -> is_same_term_lval lv lv' env
   | Tapp(f,labs,args), Tapp(f',labs',args') ->
@@ -609,8 +609,6 @@ and is_same_term_node t t' env =
   | Tblock_length(l,t), Tblock_length(l',t') ->
     is_same_logic_label l l' env && is_same_term t t' env
   | Tnull, Tnull -> true
-  | TLogic_coerce(typ,t), TLogic_coerce(typ',t') ->
-    is_same_logic_type typ typ' env && is_same_term t t' env
   | TUpdate(a,o,v), TUpdate(a',o',v') ->
     is_same_term a a' env &&
     is_same_term_offset o o' env &&
@@ -634,9 +632,9 @@ and is_same_term_node t t' env =
       is_same_term t t' env
     end else false
   | (TConst _ | TLval _ | TSizeOf _ | TSizeOfE _ | TSizeOfStr _ | TAlignOf _
-    | TAlignOfE _ |  TUnOp _ | TBinOp _ | TCastE _ | TAddrOf _ | TStartOf _
+    | TAlignOfE _ |  TUnOp _ | TBinOp _ | TCast _ | TAddrOf _ | TStartOf _
     | Tapp _ | Tlambda _ | TDataCons _ | Tif _ | Tat _ | Tbase_addr _
-    | Toffset _ | Tblock_length _ | Tnull | TLogic_coerce _ | TUpdate _
+    | Toffset _ | Tblock_length _ | Tnull | TUpdate _
     | Ttypeof _ | Ttype _ | Tempty_set | Tunion _ | Tinter _ | Tcomprehension _
     | Tlet _ | Trange _), _ -> false
 
diff --git a/src/kernel_services/ast_queries/ast_info.ml b/src/kernel_services/ast_queries/ast_info.ml
index e1c019546c4378a8da490dfa0968ba58283c4565..b9da577467a961ca1a8e3b2c7ebbaf1cd577df51 100644
--- a/src/kernel_services/ast_queries/ast_info.ml
+++ b/src/kernel_services/ast_queries/ast_info.ml
@@ -307,7 +307,7 @@ let constant_term loc i =
 let rec is_null_term t = match t.term_node with
   | TConst c when is_integral_logic_const c ->
     Integer.equal (value_of_integral_logic_const c) Integer.zero
-  | TCastE(_,t) -> is_null_term t
+  | TCast(false, _,t) -> is_null_term t
   | _ -> false
 
 (* ************************************************************************** *)
@@ -465,33 +465,37 @@ let pointed_type ty =
 (** {2 Predefined} *)
 (* ************************************************************************** *)
 
-let can_be_cea_function name =
-  String.starts_with ~prefix:"Frama_" name
+let start_with_frama_c name =
+  String.starts_with ~prefix:"Frama_C_" name
 
-let is_cea_function name =
+let is_show_each_builtin name =
   String.starts_with ~prefix:"Frama_C_show_each" name
 
-let is_cea_domain_function name =
+let is_domain_show_each_builtin name =
   String.starts_with ~prefix:"Frama_C_domain_show_each" name
 
-let is_cea_dump_function name =
+let is_dump_each_builtin name =
   String.starts_with ~prefix:"Frama_C_dump_each" name
 
-let is_cea_dump_file_function name =
+let is_dump_file_builtin name =
   String.starts_with ~prefix:"Frama_C_dump_each_file" name
 
-let is_cea_builtin name =
-  String.starts_with ~prefix:"Frama_C_builtin" name
+let is_split_builtin name =
+  String.starts_with ~prefix:"Frama_C_builtin_split" name
 
-let is_frama_c_builtin n =
-  can_be_cea_function n &&
-  (is_cea_dump_function n ||
-   is_cea_function n ||
-   is_cea_builtin n ||
-   is_cea_domain_function n ||
-   is_cea_dump_file_function n)
+let start_with_frama_c_builtin n =
+  start_with_frama_c n &&
+  (is_dump_each_builtin n ||
+   is_show_each_builtin n ||
+   is_split_builtin n ||
+   is_domain_show_each_builtin n ||
+   is_dump_file_builtin n)
+
+let () = Cil_builtins.add_special_builtin_family start_with_frama_c_builtin
+
+let is_frama_c_builtin v =
+  Cil_builtins.has_fc_builtin_attr v || start_with_frama_c_builtin v.vname
 
-let () = Cil_builtins.add_special_builtin_family is_frama_c_builtin
 
 (*
 Local Variables:
diff --git a/src/kernel_services/ast_queries/ast_info.mli b/src/kernel_services/ast_queries/ast_info.mli
index b068cb7fac8bb92949e2f65de23804d936f63c43..771f071232a5cf47d5b2d2feb75f59bb744021a2 100644
--- a/src/kernel_services/ast_queries/ast_info.mli
+++ b/src/kernel_services/ast_queries/ast_info.mli
@@ -240,12 +240,46 @@ end
 (** {2 Predefined} *)
 (* ************************************************************************** *)
 
-val can_be_cea_function : string -> bool
-val is_cea_function : string -> bool
-val is_cea_domain_function : string -> bool
-val is_cea_dump_function : string -> bool
-val is_cea_dump_file_function : string -> bool
-val is_frama_c_builtin : string -> bool
+val start_with_frama_c: string -> bool
+(** @return true if the given string starts with ["Frama_C_"].
+    @since Frama-C+dev
+*)
+
+val is_show_each_builtin: string -> bool
+(** @return true if the given string starts with ["Frama_C_show_each"].
+    @since Frama-C+dev
+*)
+
+val is_domain_show_each_builtin: string -> bool
+(** @return true if the given string starts with ["Frama_C_domain_show_each"].
+    @since Frama-C+dev
+*)
+
+val is_dump_each_builtin: string -> bool
+(** @return true if the given string starts with ["Frama_C_dump_each"].
+    @since Frama-C+dev
+*)
+
+val is_dump_file_builtin: string -> bool
+(** @return true if the given string starts with ["Frama_C_dump_each_file"].
+    @since Frama-C+dev
+*)
+
+val is_split_builtin: string -> bool
+(** @return true if the given string starts with ["Frama_C_builtin_split"].
+    @since Frama-C+dev
+*)
+
+val start_with_frama_c_builtin: string -> bool
+(** @return true if the given string starts with ["Frama_C_"].
+    @since Frama-C+dev
+*)
+
+val is_frama_c_builtin: varinfo -> bool
+(** @return true if {!start_with_frama_c_builtin} or
+    {!Cil_builtins.has_fc_builtin_attr} are true.
+    @before Frama-C+dev Behave like {!start_with_frama_c_builtin}.
+*)
 
 (*
 Local Variables:
diff --git a/src/kernel_services/ast_queries/cil.ml b/src/kernel_services/ast_queries/cil.ml
index 6a38cc02b3662b0a9b5381992257f57b284e3153..6bfd4b301b5030ac589ec72bea962aa88381dffd 100644
--- a/src/kernel_services/ast_queries/cil.ml
+++ b/src/kernel_services/ast_queries/cil.ml
@@ -401,6 +401,8 @@ let qualifier_attributes = [ "const"; "restrict"; "volatile"; "ghost" ]
 
 let fc_internal_attributes = ["declspec"; "arraylen"; "fc_stdlib"]
 
+let cast_irrelevant_attributes = ["visibility"]
+
 let filter_qualifier_attributes al =
   List.filter
     (fun a -> List.mem (attributeName a) qualifier_attributes) al
@@ -1467,10 +1469,15 @@ and childrenTermNode vis tn =
     let t1' = vTerm t1 in
     let t2' = vTerm t2 in
     if t1' != t1 || t2' != t2 then TBinOp(op,t1',t2') else tn
-  | TCastE(ty,te) ->
+  | TCast(false, Ctype ty,te) ->
     let ty' = vTyp ty in
     let te' = vTerm te in
-    if ty' != ty || te' != te then TCastE(ty',te') else tn
+    if ty' != ty || te' != te then TCast(false, Ctype ty',te') else tn
+  | TCast (true, ty,t) ->
+    let ty' = visitCilLogicType vis ty in
+    let t' = visitCilTerm vis t in
+    if ty' != ty || t' != t then TCast (true, ty',t') else tn
+  | TCast(false,_,_) -> Kernel.fatal "TCast to ctype without Ctype"
   | TAddrOf tl ->
     let tl' = vTermLval tl in
     if tl' != tl then TAddrOf tl' else tn
@@ -1552,10 +1559,6 @@ and childrenTermNode vis tn =
     let def'= visitCilLogicInfo vis def in
     let body' = visitCilTerm vis body in
     if def != def' || body != body' then Tlet(def',body') else tn
-  | TLogic_coerce(ty,t) ->
-    let ty' = visitCilLogicType vis ty in
-    let t' = visitCilTerm vis t in
-    if ty' != ty || t' != t then TLogic_coerce(ty',t') else tn
 
 and visitCilLogicLabel vis l =
   doVisitCil vis
@@ -3186,14 +3189,14 @@ let isZero (e: exp) : bool =
 let rec isLogicZero t = match t.term_node with
   | TConst (Integer (n,_)) -> Integer.equal n Integer.zero
   | TConst (LChr c) -> Char.code c = 0
-  | TCastE(_, t) -> isLogicZero t
+  | TCast(_, _, t) -> isLogicZero t
   | _ -> false
 
 let isLogicNull t =
   isLogicZero t ||
   (let rec aux t = match t.term_node with
       | Tnull -> true
-      | TCastE(_, t) -> aux t
+      | TCast(_,_, t) -> aux t
       | _ -> false
    in aux t)
 
@@ -3461,7 +3464,7 @@ let rec stripCasts (e: exp) =
   match e.enode with CastE(_, e') -> stripCasts e' | _ -> e
 
 let rec stripTermCasts (t: term) =
-  match t.term_node with TCastE(_, t') -> stripTermCasts t' | _ -> t
+  match t.term_node with TCast(_,_, t') -> stripTermCasts t' | _ -> t
 
 (* Separate out the storage-modifier name attributes *)
 let separateStorageModifiers (al: attribute list) =
@@ -4509,7 +4512,7 @@ and bytesSizeOf t = (bitsSizeOf t) lsr 3
 
 and sizeOf ~loc t =
   try
-    integer ~loc ((bitsSizeOf t) lsr 3)
+    integer ~loc (bytesSizeOf t)
   with SizeOfError _ -> new_exp ~loc (SizeOf(t))
 
 and fieldBitsOffset (f : fieldinfo) : int * int =
@@ -4610,14 +4613,13 @@ and constFold (machdep: bool) (e: exp) : exp =
   | Const(CChr c) -> new_exp ~loc (Const(charConstToIntConstant c))
   | Const(CEnum {eival = v}) -> constFold machdep v
   | Const (CReal _ | CWStr _ | CStr _ | CInt64 _) -> e (* a constant *)
-  | SizeOf t when machdep -> begin
-      try
-        let bs = bitsSizeOf t in
-        kinteger ~loc theMachine.kindOfSizeOf (bs / 8)
+  | SizeOf t when machdep ->
+    begin
+      try kinteger ~loc theMachine.kindOfSizeOf (bytesSizeOf t)
       with SizeOfError _ -> e
     end
-  | SizeOfE e when machdep -> constFold machdep
-                                (new_exp ~loc:e.eloc (SizeOf (typeOf e)))
+  | SizeOfE e when machdep ->
+    constFold machdep (new_exp ~loc:e.eloc (SizeOf (typeOf e)))
   | SizeOfStr s when machdep ->
     kinteger ~loc theMachine.kindOfSizeOf (1 + String.length s)
   | AlignOf t when machdep ->
@@ -5020,14 +5022,20 @@ let spare_attributes_for_c_cast =
   fc_internal_attributes @ qualifier_attributes
 
 let type_remove_attributes_for_c_cast t =
-  let t = typeRemoveAttributesDeep fc_internal_attributes t in
+  let attributes_to_remove =
+    fc_internal_attributes @ cast_irrelevant_attributes
+  in
+  let t = typeRemoveAttributesDeep attributes_to_remove t in
   typeRemoveAttributes spare_attributes_for_c_cast t
 
 let spare_attributes_for_logic_cast =
   spare_attributes_for_c_cast
 
 let type_remove_attributes_for_logic_type t =
-  let t = typeRemoveAttributesDeep fc_internal_attributes t in
+  let attributes_to_remove =
+    fc_internal_attributes @ cast_irrelevant_attributes
+  in
+  let t = typeRemoveAttributesDeep attributes_to_remove t in
   typeRemoveAttributes spare_attributes_for_logic_cast t
 
 let () = Cil_datatype.drop_non_logic_attributes :=
@@ -6205,9 +6213,9 @@ let combineTypesGen ?emitwith (combF : combineFunction)
       raise (Cannot_combine "different vararg specifiers");
     (* If one does not have arguments, believe the one with the
      * arguments *)
-    let newargs, olda' =
-      if oldargs = None then args, olda
-      else if args = None then oldargs, olda
+    let newargs =
+      if oldargs = None then args
+      else if args = None then oldargs
       else
         let (oldargslist, oldghostargslist) = argsToPairOfLists oldargs in
         let (argslist, ghostargslist) = argsToPairOfLists args in
@@ -6239,21 +6247,20 @@ let combineTypesGen ?emitwith (combF : combineFunction)
                   in
                   let a = addAttributes oa aa in
                   (n, t, a))
-               oldargslist argslist),
-          olda
+               oldargslist argslist)
     in
     (* Drop missingproto as soon as one of the type is a properly declared one*)
-    let olda =
+    let olda' =
       if not (hasAttribute "missingproto" a) then
-        dropAttribute "missingproto" olda'
-      else olda'
+        dropAttribute "missingproto" olda
+      else olda
     in
-    let a =
-      if not (hasAttribute "missingproto" olda') then
+    let a' =
+      if not (hasAttribute "missingproto" olda) then
         dropAttribute "missingproto" a
       else a
     in
-    TFun (newrt, newargs, oldva, combineAttributes what olda a)
+    TFun (newrt, newargs, oldva, combineAttributes what olda' a')
 
   | TBuiltin_va_list olda, TBuiltin_va_list a ->
     TBuiltin_va_list (combineAttributes what olda a)
@@ -7356,7 +7363,7 @@ let rec free_vars_term bound_vars t = match t.term_node with
   | TSizeOfE t
   | TAlignOfE t
   | TUnOp (_,t)
-  | TCastE (_,t)
+  | TCast (_,_,t)
   | Tat (t,_)
   | Toffset (_,t)
   | Tbase_addr (_,t)
@@ -7429,7 +7436,6 @@ let rec free_vars_term bound_vars t = match t.term_node with
       free_vars_term (Logic_var.Set.add d.l_var_info bound_vars) b
     in
     Logic_var.Set.union fvd fvb
-  | TLogic_coerce(_,t) -> free_vars_term bound_vars t
 
 and free_vars_lval bv (h,o) =
   Logic_var.Set.union
diff --git a/src/kernel_services/ast_queries/cil_builtins.ml b/src/kernel_services/ast_queries/cil_builtins.ml
index a2cdec06341601b2e2f0602b099678f4e06a3532..c80b32e7484b1a703e85d748253a8919524fe330 100644
--- a/src/kernel_services/ast_queries/cil_builtins.ml
+++ b/src/kernel_services/ast_queries/cil_builtins.ml
@@ -56,9 +56,9 @@ module Frama_c_builtins =
       let size = 3
     end)
 
-let is_builtin v = Cil.hasAttribute "FC_BUILTIN" v.vattr
+let has_fc_builtin_attr v = Cil.hasAttribute "FC_BUILTIN" v.vattr
 
-let is_unused_builtin v = is_builtin v && not v.vreferenced
+let is_unused_builtin v = has_fc_builtin_attr v && not v.vreferenced
 
 
 (* [VP] Should we projectify this ?*)
@@ -68,6 +68,9 @@ let special_builtins = Queue.create ()
 let is_special_builtin s =
   Queue.fold (fun res f -> res || f s) false special_builtins
 
+let is_builtin v =
+  has_fc_builtin_attr v || is_special_builtin v.vname
+
 let add_special_builtin_family f = Queue.add f special_builtins
 
 let add_special_builtin s =
diff --git a/src/kernel_services/ast_queries/cil_builtins.mli b/src/kernel_services/ast_queries/cil_builtins.mli
index 76902c6d59284cabc83ad806c5063dbe5fae9265..45b02173c47744a19146fab35cc6eff13c84dbf8 100644
--- a/src/kernel_services/ast_queries/cil_builtins.mli
+++ b/src/kernel_services/ast_queries/cil_builtins.mli
@@ -57,9 +57,14 @@ module Frama_c_builtins:
   State_builder.Hashtbl with type key = string and type data = varinfo
 
 val is_builtin: varinfo -> bool
-(** @return true if the given variable refers to a Frama-C builtin.
+(** @return true if {!has_fc_builtin_attr} or {!is_special_builtin} are true.
+    @before Frama-C+dev Only check for {!has_fc_builtin_attr}.
     @since Fluorine-20130401 *)
 
+val has_fc_builtin_attr: varinfo -> bool
+(** @return true if the given variable has a FC_BUILTIN attribute
+    @since Frama-C+dev *)
+
 val is_unused_builtin: varinfo -> bool
 (** @return true if the given variable refers to a Frama-C builtin that
     is not used in the current program. Plugins may (and in fact should)
diff --git a/src/kernel_services/ast_queries/cil_datatype.ml b/src/kernel_services/ast_queries/cil_datatype.ml
index 0e02f014f613b5d8ee32410a1782e1f38d46961c..ef018a9add1a0848aaf6eea98dc9df7ce04e4563 100644
--- a/src/kernel_services/ast_queries/cil_datatype.ml
+++ b/src/kernel_services/ast_queries/cil_datatype.ml
@@ -93,7 +93,7 @@ let rank_term = function
   | TAlignOfE _ -> 6
   | TUnOp _ -> 7
   | TBinOp _ -> 8
-  | TCastE _ -> 9
+  | TCast (false,_,_) -> 9
   | TAddrOf _ -> 10
   | TStartOf _ -> 11
   | Tapp _ -> 12
@@ -114,7 +114,7 @@ let rank_term = function
   | Tlet _ -> 29
   | Tcomprehension _ -> 30
   | Toffset _ -> 31
-  | TLogic_coerce _ -> 32
+  | TCast (true, _,_) -> 32
 
 let rank_predicate = function
   | Pfalse -> 0
@@ -1638,9 +1638,11 @@ let rec compare_term t1 t2 =
       if c <> 0 then c else
         let cx = compare_term x1 x2 in
         if cx <> 0 then cx else compare_term y1 y2
-    | TCastE(ty1,t1) , TCastE(ty2,t2) ->
-      let c = Typ.compare ty1 ty2 in
-      if c <> 0 then c else compare_term t1 t2
+    | TCast (false, ty1,e1), TCast (false, ty2,e2)
+    | TCast (true, ty1,e1) , TCast (true, ty2,e2) ->
+      let ct = Logic_type.compare ty1 ty2 in
+      if ct <> 0 then ct
+      else compare_term e1 e2
     | Tapp(f1,labs1,ts1) , Tapp(f2,labs2,ts2) ->
       let cf = Logic_info.compare f1 f2 in
       if cf <> 0 then cf else
@@ -1683,18 +1685,13 @@ let rec compare_term t1 t2 =
       else
         let cq = compare_list Logic_var.compare q1 q2 in
         if cq <> 0 then cq else Option.compare compare_predicate p1 p2
-    | TLogic_coerce(ty1,e1), TLogic_coerce(ty2,e2) ->
-      let ct = Logic_type.compare ty1 ty2 in
-      if ct <> 0 then ct
-      else compare_term e1 e2
     | (TConst _ | TLval _ | TSizeOf _ | TSizeOfE _ | TSizeOfStr _ | TAlignOf _
-      | TAlignOfE _ | TUnOp _ | TBinOp _ | TCastE _ | TAddrOf _ | TStartOf _
+      | TAlignOfE _ | TUnOp _ | TBinOp _ | TCast _ | TAddrOf _ | TStartOf _
       | Tapp _ | Tlambda _ | TDataCons _ | Tif _ | Tat _
       | Tbase_addr _ | Tblock_length _ | Toffset _
       | Tnull | TUpdate _ | Ttypeof _
       | Ttype _ | Tempty_set | Tunion _ | Tinter _  | Tcomprehension _
-      | Trange _ | Tlet _
-      | TLogic_coerce _), _ -> assert false
+      | Trange _ | Tlet _ ), _ -> assert false
 
 and compare_tlval (h1,off1) (h2,off2) =
   let ch = compare_tlhost h1 h2 in
@@ -1854,9 +1851,12 @@ let rec hash_term (acc,depth,tot) t =
         hash_term (acc+19+Hashtbl.hash bop,depth-1,tot-2) t1
       in
       hash_term (hash1,depth-1,tot1) t2
-    | TCastE(ty,t) ->
+    | TCast(false, Ctype ty,t) ->
       let hash1 = Typ.hash ty in
       hash_term (acc+23+hash1,depth-1,tot-2) t
+    | TCast(true,_,e) -> hash_term (acc + 113, depth - 1, tot - 1) e
+    (* TODO (NB) : Check the magic values here (see if it can't be merged) *)
+    | TCast(false,_,_) -> assert false
     | TAddrOf lv -> hash_tlval (acc+29,depth-1,tot-1) lv
     | TStartOf lv -> hash_tlval (acc+31,depth-1,tot-1) lv
     | Tapp (li,labs,apps) ->
@@ -1935,7 +1935,6 @@ let rec hash_term (acc,depth,tot) t =
       hash_term
         (acc + 109 + Hashtbl.hash li.l_var_info.lv_name, depth-1, tot-1)
         t
-    | TLogic_coerce(_,e) -> hash_term (acc + 113, depth - 1, tot - 1) e
   end
 
 and hash_tlval (acc,depth,tot) (h,o) =
diff --git a/src/kernel_services/ast_queries/filecheck.ml b/src/kernel_services/ast_queries/filecheck.ml
index 262a40268e873206e5d593f5b673c4280092ad51..891a2394b1970e1e017adeed3274f822dcfcaea6 100644
--- a/src/kernel_services/ast_queries/filecheck.ml
+++ b/src/kernel_services/ast_queries/filecheck.ml
@@ -177,7 +177,7 @@ module Base_checker = struct
         let unknown () =
           check_abort "variable %s(%d) is not declared" v.vname v.vid
         in
-        if not v.vglob || not (Ast_info.is_frama_c_builtin v.vname) then
+        if not v.vglob || not (Ast_info.start_with_frama_c_builtin v.vname) then
           (try
              if Varinfo.Hashtbl.find known_vars v != v then not_shared ()
            with Not_found -> unknown ()
diff --git a/src/kernel_services/ast_queries/logic_const.ml b/src/kernel_services/ast_queries/logic_const.ml
index ccea4480273eff0b6ad8cfde1eafbe699978a233..34d0e0a7f32341891ae1e395b6cf66aa4bb235cf 100644
--- a/src/kernel_services/ast_queries/logic_const.ml
+++ b/src/kernel_services/ast_queries/logic_const.ml
@@ -309,10 +309,10 @@ let tat ?(loc=Cil_datatype.Location.unknown) (t,label) =
 let told ?(loc=Cil_datatype.Location.unknown) t = tat ~loc (t,old_label)
 
 let tcast ?(loc=Cil_datatype.Location.unknown) t ct =
-  term ~loc (TCastE (ct, t)) (Ctype ct)
+  term ~loc (TCast(false, Ctype ct, t)) (Ctype ct)
 
 let tlogic_coerce ?(loc=Cil_datatype.Location.unknown) t lt =
-  term ~loc (TLogic_coerce (lt, t)) lt
+  term ~loc (TCast (true, lt, t)) lt
 
 let tvar ?(loc=Cil_datatype.Location.unknown) lv =
   term ~loc (TLval(TVar lv,TNoOffset)) lv.lv_type
diff --git a/src/kernel_services/ast_queries/logic_to_c.ml b/src/kernel_services/ast_queries/logic_to_c.ml
index 2b0ab82e02493b5f081dc5d98dbc1e7e31e3aff0..971013e57574174953aa5bd169e8adc7d5857dd6 100644
--- a/src/kernel_services/ast_queries/logic_to_c.ml
+++ b/src/kernel_services/ast_queries/logic_to_c.ml
@@ -115,7 +115,7 @@ and loc_to_exp ?result {term_node = lnode ; term_type = ltype; term_loc = loc} =
     (* TODO: Very likely to fail on large integer and incorrect on reals not
        representable as floats *)
     [new_exp ~loc (Const (Logic_utils.lconstant_to_constant constant))]
-  | TCastE (typ, lexp) ->
+  | TCast (false, Ctype typ, lexp) ->
     List.map
       (fun x -> new_exp ~loc (CastE (typ, x))) (loc_to_exp ?result lexp)
   | TAlignOf typ -> [new_exp ~loc (AlignOf typ)]
@@ -129,15 +129,15 @@ and loc_to_exp ?result {term_node = lnode ; term_type = ltype; term_loc = loc} =
   | Tinter _ | Tcomprehension _ -> error_lval()
   | Tat ({term_node = TAddrOf (TVar _, TNoOffset)} as taddroflval, _) ->
     loc_to_exp ?result taddroflval
-  | TLogic_coerce(Linteger, t) when Logic_typing.is_integral_type t.term_type ->
+  | TCast (true, Linteger, t) when Logic_typing.is_integral_type t.term_type ->
     loc_to_exp ?result t
-  | TLogic_coerce(Lreal, t) when Logic_typing.is_integral_type t.term_type ->
+  | TCast (true, Lreal, t) when Logic_typing.is_integral_type t.term_type ->
     List.map
       (fun x -> new_exp ~loc (CastE (logic_type_to_typ Lreal, x)))
       (loc_to_exp ?result t)
-  | TLogic_coerce(Lreal, t) when Logic_typing.is_arithmetic_type t.term_type ->
+  | TCast (true, Lreal, t) when Logic_typing.is_arithmetic_type t.term_type ->
     loc_to_exp ?result t
-  | TLogic_coerce (set, t)
+  | TCast (true, set, t)
     when
       Logic_const.is_set_type set &&
       Logic_utils.is_same_type
@@ -154,7 +154,7 @@ and loc_to_exp ?result {term_node = lnode ; term_type = ltype; term_loc = loc} =
   | Toffset _
   | Tblock_length _
   | TUpdate _ | Ttypeof _ | Ttype _
-  | TLogic_coerce _
+  | TCast _
     -> error_lval ()
 
 let rec loc_to_lval ?result t =
@@ -167,7 +167,7 @@ let rec loc_to_lval ?result t =
   (* coercions to arithmetic types cannot be lval. We only have to consider
      a coercion to set here.
   *)
-  | TLogic_coerce(set, t) when
+  | TCast (true, set, t) when
       Logic_typing.is_set_type set &&
       Logic_utils.is_same_type
         (Logic_typing.type_of_set_elem set) t.term_type ->
@@ -175,10 +175,10 @@ let rec loc_to_lval ?result t =
   | Tinter _ -> error_lval() (* TODO *)
   | Tcomprehension _ -> error_lval()
   | TSizeOfE _ | TAlignOfE _ | TUnOp _ | TBinOp _ | TSizeOfStr _
-  | TConst _ | TCastE _ | TAlignOf _ | TSizeOf _ | Tapp _ | Tif _
+  | TConst _ | TCast _ | TAlignOf _ | TSizeOf _ | Tapp _ | Tif _
   | Tat _ | Toffset _ | Tbase_addr _ | Tblock_length _ | Tnull | Trange _
   | TDataCons _ | TUpdate _ | Tlambda _
-  | Ttypeof _ | Ttype _ | Tlet _ | TLogic_coerce _ ->
+  | Ttypeof _ | Ttype _ | Tlet _ ->
     error_lval ()
 
 let loc_to_offset ?result loc =
@@ -198,11 +198,10 @@ let loc_to_offset ?result loc =
     | Tempty_set -> h,[]
     | Trange _ | TAddrOf _ | Tat _
     | TSizeOfE _ | TAlignOfE _ | TUnOp _ | TBinOp _ | TSizeOfStr _
-    | TConst _ | TCastE _ | TAlignOf _ | TSizeOf _ | Tapp _ | Tif _
+    | TConst _ | TCast _ | TAlignOf _ | TSizeOf _ | Tapp _ | Tif _
     | Toffset _ | Tbase_addr _ | Tblock_length _ | Tnull
     | TDataCons _ | TUpdate _ | Tlambda _
     | Ttypeof _ | Ttype _ | Tcomprehension _ | Tinter _ | Tlet _
-    | TLogic_coerce _
       -> error_lval ()
   in snd (aux None loc.term_node)
 
diff --git a/src/kernel_services/ast_queries/logic_typing.ml b/src/kernel_services/ast_queries/logic_typing.ml
index 4cfddc62f891ddba3b715a74d7d4d96e67a2cd96..1eac2474cd76980f80c8a23c14fb9abb5533fc10 100644
--- a/src/kernel_services/ast_queries/logic_typing.ml
+++ b/src/kernel_services/ast_queries/logic_typing.ml
@@ -192,10 +192,10 @@ let optimize_comprehension term =
            let lv = Logic_const.addTermOffsetLval o lv in
            let ty = Cil.typeOfTermLval lv in
            Logic_utils.mk_logic_StartOf (Logic_const.term ~loc (TLval lv) ty))
-    | TLogic_coerce(lt,{ term_node = TLval(TVar y,TNoOffset)}) when is_x y ->
+    | TCast (true, lt,{ term_node = TLval(TVar y,TNoOffset)}) when is_x y ->
       (* { (lt)x | \subset(x, set) } -> (lt set)set *)
       { t with
-        term_node = TLogic_coerce(Logic_const.make_set_type lt,set);
+        term_node = TCast (true, Logic_const.make_set_type lt,set);
         term_type = Logic_const.make_set_type lt }
     | _ -> term
   in
@@ -206,8 +206,8 @@ let optimize_comprehension term =
          { pred_content =
              Papp({l_var_info = {lv_name="\\subset"}},[],[elt;set]) }) ->
     (match elt.term_node with
-     | TLogic_coerce
-         (_,
+     | TCast
+         (true,_,
           { term_node =
               TLval(TVar y, TNoOffset) })
        when Cil_datatype.Logic_var.equal x y ->
@@ -228,22 +228,22 @@ let lift_set f loc =
     | Tempty_set -> loc
     (* coercion from a set to another set: keep the current coercion
        over the result of the transformation. *)
-    | TLogic_coerce(set,t1)
+    | TCast (true, set,t1)
       when is_set_type set && is_set_type t1.term_type ->
       let res = aux t1 in
-      { loc with term_node = TLogic_coerce(set, res) }
+      { loc with term_node = TCast (true, set, res) }
     (* coercion from a singleton to a set: performs the transformation.
     *)
-    | TLogic_coerce(oset, t1) when is_set_type oset ->
+    | TCast (true, oset, t1) when is_set_type oset ->
       let t = f t1 in
       let nset = make_set_type t.term_type in
       (* performs the coercion into a set. *)
       let singleton_coerce =
-        { t with term_node = TLogic_coerce(nset, t); term_type = nset }
+        { t with term_node = TCast (true, nset, t); term_type = nset }
       in
       (* see whether we have to coerce the set type itself. *)
       if is_same_type oset nset then singleton_coerce
-      else { loc with term_node = TLogic_coerce(oset, singleton_coerce) }
+      else { loc with term_node = TCast (true, oset, singleton_coerce) }
     (* if we a term of type set, try to apply f to each
        element of x by using a comprehension, and see whether we can get
        rid of said comprehension afterwards. *)
@@ -257,7 +257,7 @@ let lift_set f loc =
       let t2 = Logic_const.tvar ~loc:loc.term_loc x in
       let t2 =
         Logic_const.term
-          ~loc:loc.term_loc (TLogic_coerce (loc.term_type,t2)) loc.term_type
+          ~loc:loc.term_loc (TCast (true, loc.term_type,t2)) loc.term_type
       in
       let p = Logic_const.papp ~loc:loc.term_loc (sub, [], [t2;loc]) in
       let c = { loc with term_node = Tcomprehension(t,[x],Some p) } in
@@ -1057,7 +1057,7 @@ struct
       | TLval _ -> true
       | TUnOp(_,t) -> needs_at t
       | TBinOp(_,t1,t2) -> needs_at t1 || needs_at t2
-      | TCastE(_,t) -> needs_at t
+      | TCast(_,_,t) -> needs_at t
       | TAddrOf (_,o) -> needs_at_offset o
       | TStartOf (_,o) -> needs_at_offset o
       | Tapp(_,_,l) | TDataCons(_,l) -> List.exists needs_at l
@@ -1071,7 +1071,6 @@ struct
       | Trange (Some t1, Some t2) -> needs_at t1 || needs_at t2
       | Tlet(_,t) -> needs_at t
       | Tif(t1,t2,t3) -> needs_at t1 || needs_at t2 || needs_at t3
-      | TLogic_coerce(_,t) -> needs_at t
     and needs_at_offset = function
       | TNoOffset -> false
       | TIndex (t,o) -> needs_at t || needs_at_offset o
@@ -1124,7 +1123,7 @@ struct
       if isPointerType newt && isLogicNull e && not (isLogicZero e) then
         (* \null can have any pointer type, see ACSL manual. *)
         (if force then
-           Logic_const.term ~loc (TCastE (newt, e)) (Ctype newt)
+           Logic_const.term ~loc (TCast (false, Ctype newt, e)) (Ctype newt)
          else
            { e with term_type = Ctype newt })
       else if isPointerType newt && isArrayType oldt then begin
@@ -1225,13 +1224,13 @@ struct
       | Tinter l ->
         { e with term_type = real_type; term_node = Tinter (List.map aux l) }
       | Tempty_set -> { e with term_type = real_type }
-      | TLogic_coerce(t2,e) when Cil.no_op_coerce t2 e ->
+      | TCast (true,t2,e) when Cil.no_op_coerce t2 e ->
         let e = aux e in
-        { e with term_type = real_type; term_node = TLogic_coerce(real_type,e) }
+        { e with term_type = real_type; term_node = TCast (true, real_type,e) }
       | _ when Cil.isLogicArithmeticType real_type ->
         Logic_utils.numeric_coerce real_type e
       | _ ->
-        { e with term_type = real_type; term_node = TLogic_coerce(real_type,e) }
+        { e with term_type = real_type; term_node = TCast (true, real_type,e) }
     in
     if is_same_type e.term_type t then e else aux e
 
@@ -1248,7 +1247,7 @@ struct
         let range = trange ~loc (Some (lzero ~loc ()), Some sizeof) in
         let converted_type = set_conversion (Ctype Cil.charPtrType) t.term_type
         in
-        let cast = term ~loc (TCastE(Cil.charPtrType, t)) converted_type in
+        let cast = term ~loc (TCast(false, Ctype Cil.charPtrType, t)) converted_type in
         term ~loc (TBinOp(PlusPI,cast,range)) (make_set_type converted_type)
     in
     lift_set convert_one_location t
@@ -1263,7 +1262,7 @@ struct
       if explicit then begin
         match Logic_const.unroll_ltdef newt with
         | Ctype cnewt ->
-          { e with term_node = TCastE(cnewt,e); term_type = newt }
+          { e with term_node = TCast(false, Ctype cnewt,e); term_type = newt }
         | _ -> e
       end else e
     end else if is_enum_cst e newt then { e with term_type = newt }
@@ -1284,7 +1283,7 @@ struct
         logic_coerce Linteger e
       | t1, Ctype t2 when Logic_const.is_boolean_type t1
                        && is_integral_type newt && explicit ->
-        Logic_const.term ~loc (TCastE (t2,e)) newt
+        Logic_const.term ~loc (TCast (false, Ctype t2,e)) newt
       | ty1, Ltype({lt_name="set"},[ty2])
         when is_pointer_type ty1 &&
              is_plain_pointer_type ty2 &&
@@ -1429,7 +1428,7 @@ struct
     (* Integer 0 is also a valid pointer. *)
     | Linteger, Ctype ty when Cil.isPointerType ty && isLogicNull oterm ->
       nt, { oterm with
-            term_node = TCastE(ty,oterm);
+            term_node = TCast(false, Ctype ty,oterm);
             term_type = nt }
     | Linteger, Ctype ty when Cil.isIntegralType ty ->
       (try
@@ -2058,7 +2057,7 @@ struct
         known_vars, kont (eta_expand term.term_loc term.term_name env v)
       | TConst _ | TLval _ | TSizeOf _ | TSizeOfE _
       | TSizeOfStr _ | TAlignOf _ | TAlignOfE _
-      | TUnOp _ | TBinOp _ | TCastE _ | TAddrOf _ | TStartOf _
+      | TUnOp _ | TBinOp _ | TCast _ | TAddrOf _ | TStartOf _
       | Tapp _  | TDataCons _ | Tbase_addr _ | Toffset _
       | Tblock_length _ | Tnull
       | TUpdate _ | Ttypeof _ | Ttype _ | Tempty_set
@@ -2068,7 +2067,7 @@ struct
          idea that you can always replace a term by a set of terms
       *)
       | Tunion _ | Tinter _ | Tcomprehension _
-      | Trange _ | TLogic_coerce _
+      | Trange _
 
         -> known_vars, kont term
       | Tlambda (quants,term) ->
@@ -2366,11 +2365,11 @@ struct
 
       | Tunion l | Tinter l -> List.for_all aux l
 
-      | TLogic_coerce (_,t) | Tat (t, _) | Tcomprehension (t,_,_) | Tlet (_, t)
+      | TCast (true,_,t) | Tat (t, _) | Tcomprehension (t,_,_) | Tlet (_, t)
         -> aux t
 
       | Trange _ | TConst _ | TSizeOf _ | TSizeOfE _ | TSizeOfStr _ | TAlignOf _
-      | TAlignOfE _ | TUnOp (_,_) | TBinOp (_,_,_) | TCastE (_,_)
+      | TAlignOfE _ | TUnOp (_,_) | TBinOp (_,_,_) | TCast (false,_,_)
       | Tlambda (_,_) | TDataCons (_,_) | Tbase_addr (_,_)
       | Toffset (_,_) | Tblock_length (_,_) | Tnull | Tapp _
       | TUpdate (_,_,_) | Ttypeof _ | Ttype _ ->
@@ -3159,7 +3158,7 @@ struct
     let check_lval t =
       match t.term_node with
         TLval lv
-      | TLogic_coerce(_,{term_node = TLval lv })
+      | TCast (true, _,{term_node = TLval lv })
       | Tat({term_node = TLval lv},_) -> f lv t
       | TStartOf lv
       | Tat ({term_node = TStartOf lv}, _) ->
@@ -3183,7 +3182,7 @@ struct
             term_type = type_of_pointed t.term_type;
             term_node = TLval lv }
       | TLval lv
-      | TLogic_coerce(_,{term_node = TLval lv })
+      | TCast (true, _,{term_node = TLval lv })
       | Tat({term_node = TLval lv},_) -> f lv t
       | TStartOf lv
       | Tat ({term_node = TStartOf lv}, _)
diff --git a/src/kernel_services/ast_queries/logic_utils.ml b/src/kernel_services/ast_queries/logic_utils.ml
index 7a2b471b5d840b3a1c71ae62cce6d9bedc149f85..5a8bd35caa31c3a9c990ecd4b123eab7163f4183 100644
--- a/src/kernel_services/ast_queries/logic_utils.ml
+++ b/src/kernel_services/ast_queries/logic_utils.ml
@@ -236,16 +236,16 @@ let mk_cast ?loc ?(force=false) newt t =
   let newt' = Cil.type_remove_attributes_for_logic_type newt in
   if equal_ltype (Ctype newt') t.term_type then t else
     let rec unroll_cast e = match e.term_node with
-      | TCastE(oldt,e)
+      | TCast(false, Ctype oldt,e)
         when (Cil.isPointerType newt' && Cil.isPointerType oldt)
           || equal_ltype
                (Ctype (Cil.type_remove_attributes_for_logic_type oldt))
                (Ctype newt')
         -> unroll_cast e
-      | TLogic_coerce(Linteger,e)
+      | TCast(true,Linteger,e)
         when Cil.isArithmeticOrPointerType newt'
         -> unroll_cast e
-      | TLogic_coerce(Lreal,e)
+      | TCast(true,Lreal,e)
         when Cil.isFloatingType newt'
         -> unroll_cast e
       | _ -> e
@@ -254,7 +254,7 @@ let mk_cast ?loc ?(force=false) newt t =
     let loc = match loc with None -> t.term_loc | Some loc -> loc in
     (* we keep newt as the cast target, as newt' might have unrolled typedefs
        in order to remove attributes, resulting in a less user-friendly type *)
-    Logic_const.term ~loc (TCastE (newt, tres)) (Ctype newt')
+    Logic_const.term ~loc (TCast (false, Ctype newt, tres)) (Ctype newt')
 
 
 (* -------------------------------------------------------------------------- *)
@@ -319,23 +319,23 @@ let parse_float ?loc literal =
   let vreal = Logic_const.term ?loc (TConst(LReal creal)) Lreal in
   if is_flt then
     let ty = TFloat(fk,[]) in
-    Logic_const.term ?loc (TCastE(ty,vreal)) (Ctype ty)
+    Logic_const.term ?loc (TCast(false, Ctype ty,vreal)) (Ctype ty)
   else vreal
 
 let mk_coerce ltyp t =
-  Logic_const.term ~loc:t.term_loc (TLogic_coerce(ltyp, t)) ltyp
+  Logic_const.term ~loc:t.term_loc (TCast (true, ltyp, t)) ltyp
 
 let rec numeric_coerce ltyp t =
   let oldt = unroll_type t.term_type in
   match t.term_node with
-  | TLogic_coerce(lt,e) when Cil.no_op_coerce lt e ->
+  | TCast (true, lt,e) when Cil.no_op_coerce lt e ->
     (* coercion hidden by the printer, but still present *)
     numeric_coerce ltyp e
   | TConst(LEnum _) | TConst(Integer _) when ltyp = Linteger
     -> { t with term_type = Linteger }
   | TConst(LReal _ ) when ltyp = Lreal ->
     { t with term_type = Lreal }
-  | TCastE(ty,e) ->
+  | TCast (false, Ctype ty,e) ->
     begin match ltyp, Cil.unrollType ty, e.term_node with
       | Linteger, TInt(ik,_), TConst(Integer(v,_))
         when Cil.fitsInInt ik v -> { e with term_type = Linteger }
@@ -658,7 +658,7 @@ let array_with_range arr size =
 
 let remove_logic_coerce t =
   match t.term_node with
-  | TLogic_coerce(_,t) -> t
+  | TCast (true, _,t) -> t
   | _ -> t
 
 let rec remove_term_offset o =
@@ -954,8 +954,8 @@ let rec is_same_term t1 t2 =
   | TUnOp (o1,t1), TUnOp(o2,t2) -> o1 = o2 && is_same_term t1 t2
   | TBinOp(o1,l1,r1), TBinOp(o2,l2,r2) ->
     is_same_binop o1 o2 && is_same_term l1 l2 && is_same_term r1 r2
-  | TCastE(typ1,t1), TCastE(typ2,t2) ->
-    Cil_datatype.TypByName.equal typ1 typ2 && is_same_term t1 t2
+  | TCast (b1, ty1,t1), TCast (b2, ty2,t2) ->
+    b1 = b2 && is_same_type ty1 ty2 && is_same_term t1 t2
   | TAddrOf l1, TAddrOf l2 -> is_same_tlval l1 l2
   | TStartOf l1, TStartOf l2 -> is_same_tlval l1 l2
   | Tapp(f1,labels1, args1), Tapp(f2, labels2, args2) ->
@@ -993,15 +993,13 @@ let rec is_same_term t1 t2 =
     is_same_opt is_same_term l1 l2 && is_same_opt is_same_term h1 h2
   | Tlet(d1,b1), Tlet(d2,b2) ->
     is_same_logic_info d1 d2 && is_same_term b1 b2
-  | TLogic_coerce(ty1,t1), TLogic_coerce(ty2,t2) ->
-    is_same_type ty1 ty2 && is_same_term t1 t2
   | (TConst _ | TLval _ | TSizeOf _ | TSizeOfE _ | TSizeOfStr _
-    | TAlignOf _ | TAlignOfE _ | TUnOp _ | TBinOp _ | TCastE _
+    | TAlignOf _ | TAlignOfE _ | TUnOp _ | TBinOp _ | TCast _
     | TAddrOf _ | TStartOf _ | Tapp _ | Tlambda _ | TDataCons _
     | Tif _ | Tat _ | Tbase_addr _ | Tblock_length _ | Toffset _ | Tnull
     | TUpdate _ | Ttypeof _ | Ttype _
     | Tcomprehension _ | Tempty_set | Tunion _ | Tinter _ | Trange _
-    | Tlet _ | TLogic_coerce _
+    | Tlet _
     ),_ -> false
 
 and is_same_logic_info l1 l2 =
@@ -1508,9 +1506,14 @@ let rec hash_term (acc,depth,tot) t =
         hash_term (acc+152+Hashtbl.hash bop,depth-1,tot-2) t1
       in
       hash_term (hash1,depth-1,tot1) t2
-    | TCastE(ty,t) ->
+    | TCast (false, Ctype ty,t) ->
       let hash1 = Cil_datatype.TypByName.hash ty in
       hash_term (acc+171+hash1,depth-1,tot-2) t
+    | TCast (true, _,t) ->
+      hash_term (acc + 587, depth - 1, tot - 1) t
+    | TCast (false, _,_) -> assert false
+    (* TODO (NB) : Should check the magic values here to see if we can merge
+       them *)
     | TAddrOf lv -> hash_term_lval (acc+190,depth-1,tot-1) lv
     | TStartOf lv -> hash_term_lval (acc+209,depth-1,tot-1) lv
     | Tapp (li,labs,apps) -> hash_app (acc,depth,tot) li labs apps
@@ -1583,8 +1586,6 @@ let rec hash_term (acc,depth,tot) t =
       hash_term
         (acc + 570 + Hashtbl.hash li.l_var_info.lv_name, depth-1, tot-1)
         t
-    | TLogic_coerce(_,t) ->
-      hash_term (acc + 587, depth - 1, tot - 1) t
   end
 
 and hash_app (acc,depth,tot) li labs apps =
@@ -1740,11 +1741,14 @@ let rec compare_term t1 t2 =
     else res
   | TBinOp _, _ -> 1
   | _, TBinOp _ -> -1
-  | TCastE(typ1,t1), TCastE(typ2,t2) ->
-    let res = Cil_datatype.TypByName.compare typ1 typ2 in
+  | TCast (false, ty1,t1), TCast (false, ty2,t2)
+  | TCast (true, ty1,t1), TCast (true, ty2,t2) ->
+    let res = Cil_datatype.Logic_type_ByName.compare ty1 ty2 in
     if res = 0 then compare_term t1 t2 else res
-  | TCastE _, _ -> 1
-  | _, TCastE _ -> -1
+  | TCast (false,_,_), _ -> 1
+  | _, TCast (false,_,_) -> -1
+  | TCast(true,_,_), _ -> 1
+  | _, TCast(true,_,_) -> -1
   | TAddrOf l1, TAddrOf l2 -> compare_tlval l1 l2
   | TAddrOf _, _ -> 1
   | _, TAddrOf _ -> -1
@@ -1833,11 +1837,6 @@ let rec compare_term t1 t2 =
   | Tlet(d1,b1), Tlet(d2,b2) ->
     let res = compare_logic_info d1 d2 in
     if res = 0 then compare_term b1 b2 else res
-  | Tlet _, _ -> 1
-  | _, Tlet _ -> -1
-  | TLogic_coerce(ty1,t1), TLogic_coerce(ty2,t2) ->
-    let res = Cil_datatype.Logic_type_ByName.compare ty1 ty2 in
-    if res = 0 then compare_term t1 t2 else res
 
 and compare_logic_info l1 l2 =
   let res = compare_logic_signature l1 l2 in
@@ -2446,30 +2445,28 @@ let rec constFoldTermToInt ?(machdep=true) (e: term) : Integer.t option =
       with Cil.SizeOfError _ -> None
     end
   | TAlignOfE _ -> None (* exp case is very complex, and possibly incorrect *)
-  | TCastE (typ, e) -> constFoldCastToInt ~machdep typ e
+  | TCast (false, Ctype typ, e) -> constFoldCastToInt ~machdep typ e
+  | TCast (true, Linteger, e) -> constFoldTermToInt ~machdep e
   | Toffset (_, t) -> if machdep then constFoldToffset t else None
   | Tif (c, e1, e2) -> begin
-      match constFoldTermToInt ~machdep c with
-      | None -> None
-      | Some i ->
-        constFoldTermToInt ~machdep (if Integer.is_zero i then e2 else e1)
+      Option.bind (constFoldTermToInt ~machdep c)
+        (fun i -> constFoldTermToInt ~machdep (if Integer.is_zero i then e2 else e1))
     end
-  | TLogic_coerce (lt, e) ->
-    if lt = Linteger then constFoldTermToInt ~machdep e else None
   | Tnull -> Some Integer.zero
   | Tapp (li, _, [{term_node = (Tunion args |
-                                TLogic_coerce (_, {term_node = Tunion args}))}])
+                                TCast (true, _, {term_node = Tunion args}))}])
     when is_max_function li ->
     constFoldMinMax ~machdep Integer.max args
   | Tapp (li, _, [{term_node = (Tunion args |
-                                TLogic_coerce (_, {term_node = Tunion args}))}])
+                                TCast (true, _, {term_node = Tunion args}))}])
     when is_min_function li ->
     constFoldMinMax ~machdep Integer.min args
 
   | TLval _ | TAddrOf _ | TStartOf _ | Tapp _ | Tlambda _ | TDataCons _
   | Tat _ | Tbase_addr _ | Tblock_length _
   | TUpdate _ | Ttypeof _ | Ttype _ | Tempty_set | Tunion _ | Tinter _
-  | Tcomprehension _ | Trange _ | Tlet _ ->
+  | Tcomprehension _ | Trange _ | Tlet _
+  | TCast _ ->
     None
 
 and constFoldCastToInt ~machdep typ e =
diff --git a/src/kernel_services/cmdline_parameters/parameter_builder.ml b/src/kernel_services/cmdline_parameters/parameter_builder.ml
index 6997606429cfe4cfcbede1bf6b57a8e80259ef8f..95f2a78c7d5a62aad8be4912184283de3dd30ac8 100644
--- a/src/kernel_services/cmdline_parameters/parameter_builder.ml
+++ b/src/kernel_services/cmdline_parameters/parameter_builder.ml
@@ -353,10 +353,13 @@ struct
         end)
 
     let add_option name =
+      let help =
+        Format.asprintf "%s (preferably use %s=\"%s\")" X.help name X.arg_name
+      in
       Cmdline.add_option
         name
         ~argname:X.arg_name
-        ~help:X.help
+        ~help
         ~visible:is_visible
         ~ext_help:!Parameter_customize.optional_help_ref
         ~plugin:P.shortname
diff --git a/src/kernel_services/plugin_entry_points/dynamic.ml b/src/kernel_services/plugin_entry_points/dynamic.ml
index 9524edda4888b72a0e631cef9dddcf5890d1bc57..fe20f1848549c440da0d6a57421e2dd2ac1639f3 100644
--- a/src/kernel_services/plugin_entry_points/dynamic.ml
+++ b/src/kernel_services/plugin_entry_points/dynamic.ml
@@ -145,6 +145,14 @@ let load_module m =
             load_plugin m
     end
 
+let () = Printexc.register_printer (function
+    | Dynlink.Error err -> Some (Dynlink.error_message err)
+    | _ -> None
+  )
+
+let () = Dynlink.allow_unsafe_modules true
+
+
 (* ************************************************************************* *)
 (** {2 Registering and accessing dynamic values} *)
 (* ************************************************************************* *)
diff --git a/src/kernel_services/plugin_entry_points/kernel.ml b/src/kernel_services/plugin_entry_points/kernel.ml
index 5b11f4352b8c6e6a627218fb2afcb033c5cb2283..2cb8ce7036c7ed6070986cfa77a41c82064e7e7e 100644
--- a/src/kernel_services/plugin_entry_points/kernel.ml
+++ b/src/kernel_services/plugin_entry_points/kernel.ml
@@ -212,6 +212,8 @@ let () = set_warn_status wkey_audit Log.Werror
 
 let wkey_parser_unsupported = register_warn_category "parser:unsupported"
 
+let wkey_parser_unsupported_attributes = register_warn_category "parser:unsupported:attributes"
+
 let wkey_asm = register_warn_category "asm:clobber"
 
 let wkey_unnamed_typedef = register_warn_category "parser:unnamed-typedef"
diff --git a/src/kernel_services/plugin_entry_points/kernel.mli b/src/kernel_services/plugin_entry_points/kernel.mli
index d9142b7318f091c656957404f1f90ad56b0ecedd..21bc5342c779a0b5452235e65f16ec4ec46cadfa 100644
--- a/src/kernel_services/plugin_entry_points/kernel.mli
+++ b/src/kernel_services/plugin_entry_points/kernel.mli
@@ -205,6 +205,9 @@ val wkey_audit: warn_category
 val wkey_parser_unsupported: warn_category
 (** Warning related to unsupported parsing-related features. *)
 
+val wkey_parser_unsupported_attributes: warn_category
+(** Warning related to unsupported attributes during parsing. *)
+
 val wkey_asm: warn_category
 (** Warnings related to assembly code. *)
 
diff --git a/src/libraries/project/state_builder.ml b/src/libraries/project/state_builder.ml
index 519505130bd580bf084dd7da1794cb95d391c33a..231dae0d4a6f80b181125d185a98c0fdcafb40be 100644
--- a/src/libraries/project/state_builder.ml
+++ b/src/libraries/project/state_builder.ml
@@ -814,6 +814,7 @@ module Hashconsing_tbl =
 module type Counter = sig
   val next : unit -> int
   val get: unit -> int
+  val reset: unit -> unit
   val self: State.t
 end
 
@@ -849,6 +850,7 @@ module SharedCounter(Info : sig val name : string end) = struct
 
   let next () = incr cpt ; !cpt
   let get () = !cpt
+  let reset () = cpt := 0
   let self = Cpt.self
 
 end
@@ -886,6 +888,7 @@ module Counter(Info : sig val name : string end) = struct
 
   let next () = incr !cpt ; !(!cpt)
   let get () = !(!cpt)
+  let reset () = !cpt := 0
   let self = Cpt.self
 
 end
diff --git a/src/libraries/project/state_builder.mli b/src/libraries/project/state_builder.mli
index f4770180a8efd00c05ccd310951dc0f511cde48d..10bbb9e968622ebbe64792f4f2c0d4ad083688c9 100644
--- a/src/libraries/project/state_builder.mli
+++ b/src/libraries/project/state_builder.mli
@@ -507,6 +507,10 @@ module type Counter = sig
   (** @return the current value of the counter, without incrementing it.
       @since Fluorine-20130401 *)
 
+  (** Resets the counter to 0.
+      @since Frama-C+dev *)
+  val reset: unit -> unit
+
   val self: State.t
   (** @since Oxygen-20120901 *)
 
diff --git a/src/libraries/qed/pool.ml b/src/libraries/qed/pool.ml
index b431def8e772b24c11eaaf7f09c59a47790dc005..b817c26909c861036e92fa30512b6e5b679c8063 100644
--- a/src/libraries/qed/pool.ml
+++ b/src/libraries/qed/pool.ml
@@ -29,6 +29,7 @@ sig
   type t
   val dummy : t
   val equal : t -> t -> bool
+  val compare : t -> t -> int
 end
 
 module Make(T : Type) =
@@ -79,7 +80,7 @@ struct
     if cmp <> 0 then cmp else
       let cmp = Stdlib.compare x.vrank y.vrank in
       if cmp <> 0 then cmp else
-        Stdlib.compare x.vid y.vid
+        T.compare x.vtau y.vtau
 
   (* POOL *)
 
diff --git a/src/libraries/qed/pool.mli b/src/libraries/qed/pool.mli
index e6b236fc74cf904beb65eab0c0300824dae13f81..ea3845fb60ee44f09d687be9e4eca020e46200d9 100644
--- a/src/libraries/qed/pool.mli
+++ b/src/libraries/qed/pool.mli
@@ -29,6 +29,7 @@ sig
   type t
   val dummy : t
   val equal : t -> t -> bool
+  val compare : t -> t -> int
 end
 
 module Make(T : Type) :
diff --git a/src/libraries/qed/term.ml b/src/libraries/qed/term.ml
index be5a1a97ea5a010eb5cdf358354a0cb7597db42a..bd6a98bf5ee9380f48ad4f4ccf5296a367764f63 100644
--- a/src/libraries/qed/term.ml
+++ b/src/libraries/qed/term.ml
@@ -45,6 +45,7 @@ struct
         type t = tau
         let dummy = Prop
         let equal = Kind.eq_tau Field.equal ADT.equal
+        let compare = Kind.compare_tau Field.compare ADT.compare
       end)
 
   open POOL
diff --git a/src/plugins/alias/API.mli b/src/plugins/alias/API.mli
deleted file mode 100644
index 6af32089c3600570ac10c4a84ceb986eee791a76..0000000000000000000000000000000000000000
--- a/src/plugins/alias/API.mli
+++ /dev/null
@@ -1,171 +0,0 @@
-(**************************************************************************)
-(*                                                                        *)
-(*  This file is part of Frama-C.                                         *)
-(*                                                                        *)
-(*  Copyright (C) 2007-2023                                               *)
-(*    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).            *)
-(*                                                                        *)
-(**************************************************************************)
-
-(** External API of the plugin Alias *)
-
-open Cil_types
-
-module LSet = Cil_datatype.LvalStructEq.Set
-module G : Graph.Sig.G
-
-val vid : G.V.t -> int
-
-(** NB : do the analysis BEFORE using any of those functions *)
-
-(** [points_to_set_stmt kf s lv] returns the points-to set of lval [lv] before
-    [stmt] in function [kf]. *)
-val points_to_set_stmt : kernel_function -> stmt -> lval -> LSet.t
-
-(** [points_to_set kf s lv] returns the points-to set of lval [lv] at the end
-    of function [kf]. *)
-val points_to_set_kf : kernel_function -> lval -> LSet.t
-
-(** [aliases_stmt kf s lv] return the alias set of lval [lv] before [stmt] in
-    function [kf]. *)
-val aliases_stmt : kernel_function -> stmt -> lval -> LSet.t
-
-(** [aliases_kf kf lv] return the alias set of lval [lv] at the end of function
-    [kf]. *)
-val aliases_kf : kernel_function -> lval -> LSet.t
-
-(** list of pairs [s, e] where [e] is the set of lval aliased to [v] after
-    statement [s] in function [kf]. *)
-val fundec_stmts : kernel_function -> lval -> (stmt * LSet.t) list
-
-
-(** [fold_points_to_set f acc kf s lv] folds [f acc] over all the lvals in the
-    points-to set of the given lval [lv] right before stmt [s] in function
-    [kf]. *)
-val fold_points_to_set:
-  ('a -> lval -> 'a) -> 'a -> kernel_function -> stmt -> lval -> 'a
-
-(** [fold_aliases_stmt f acc kf s lv] folds [f acc] over all the aliases of the
-    given lval [lv] right before stmt [s] in function [kf]. *)
-val fold_aliases_stmt:
-  ('a -> lval -> 'a) -> 'a -> kernel_function -> stmt -> lval -> 'a
-
-(** [fold_new_aliases_stmt f acc kf s lv] folds [f acc] over all the aliases of
-    the given lval [lv] created by stmt [s] in function [kf]. *)
-val fold_new_aliases_stmt:
-  ('a -> lval -> 'a) -> 'a -> kernel_function -> stmt -> lval -> 'a
-
-(** [fold_points_to_set_kf f acc kf lv] folds [f acc] over the points-to set of lval
-    [lv] at the end of function [kf]. *)
-val fold_points_to_set_kf :
-  ('a -> lval -> 'a) -> 'a -> kernel_function -> lval -> 'a
-
-(** [fold_aliases_kf f acc kf lv] folds [f acc] over all the aliases of lval
-    [lv] at the end of function [kf]. *)
-val fold_aliases_kf:
-  ('a -> lval -> 'a) -> 'a -> kernel_function -> lval -> 'a
-
-(** [fold_fundec_stmts f acc kf v] folds [f acc s e] on the list of
-    pairs [s, e] where [e] is the set of lval aliased to [v] after statement [s]
-    in function [kf]. *)
-val fold_fundec_stmts:
-  ('a -> stmt -> lval -> 'a) -> 'a -> kernel_function -> lval -> 'a
-
-(** [are_aliased kf s lv1 lv2] returns true if and only if the two
-    lvals [lv1] and [lv2] are aliased before stmt [s] in function
-    [kf]. *)
-val are_aliased: kernel_function -> stmt -> lval -> lval -> bool
-
-(** [fold_vertex f acc kf s v] folds [f acc i lv] to all [lv] in [i], where [i] is
-    the vertex that represents the equivalence class of [v] before statement [s] in function [kf]. *)
-val fold_vertex:
-  ('a -> G.V.t -> lval -> 'a) -> 'a  -> kernel_function -> stmt -> lval  -> 'a
-
-(** [fold_vertex_closure f acc kf s v] is the transitive closure of function
-    [fold_vertex]. *)
-val fold_vertex_closure:
-  ('a -> G.V.t -> lval -> 'a) -> 'a  -> kernel_function -> stmt -> lval  -> 'a
-
-
-(** direct access to the abstract state. See Abstract_state.mli *)
-
-module Abstract_state : sig
-  (** Type denothing an abstract state of the analysis. It is a graph containing
-      all aliases and points-to information. *)
-  type t
-
-  (** access to the points-to graph *)
-  val get_graph: t -> G.t
-
-  (** set of lvals stored in a vertex *)
-  val get_lval_set : G.V.t -> t -> LSet.t
-
-  (** pretty printer; debug=true prints the graph, debug = false only
-      prints aliased variables *)
-  val pretty : ?debug:bool -> Format.formatter -> t -> unit
-
-  (** dot printer; first argument is a file name *)
-  val print_dot : string -> t -> unit
-
-  (** finds the vertex corresponding to a lval.
-      @raise Not_found if such a vertex does not exist
-  *)
-  val find_vertex : lval -> t -> G.V.t
-
-  (** same as previous function, but return a set of lval. Cannot
-      raise an exception but may return an empty set if the lval is not
-      in the graph *)
-  val find_aliases : lval -> t -> LSet.t
-
-  (** similar to the previous functions, but does not only give the
-      equivalence class of lv, but also all lv that are aliases in
-      other vertex of the graph *)
-  val find_all_aliases : lval -> t -> LSet.t
-
-  (** the set of all lvars to which the given variable may point. *)
-  val points_to_set : lval -> t -> LSet.t
-
-  (** find_aliases, then recursively finds other sets of lvals. We
-      have the property (if lval [lv] is in abstract state [x]) :
-      List.hd (find_transitive_closure lv x) = (find_vertex lv x,
-      find_aliases lv x) *)
-  val find_transitive_closure : lval -> t -> (G.V.t * LSet.t) list
-
-  (** inclusion test; [is_included a1 a2] tests if, for any lvl
-      present in a1 (associated to a vertex v1), that it is also
-      present in a2 (associated to a vertex v2) and that
-      get_lval_set(succ(v1) is included in get_lval_set(succ(v2)) *)
-  val is_included : t -> t -> bool
-end
-
-(** [get_state_before_stmt f s] gets the abstract state computed after
-    statement [s] in function [f]. Returns [None] if
-    the abstract state is bottom or not computed. *)
-val get_state_before_stmt :  kernel_function -> stmt -> Abstract_state.t option
-
-
-(** [call_function a f Some(res) args] computes the abstract state
-    after the instruction res=f(args) where res is a lval. [a] is the
-    abstract state before the call. If function [f] returns no value,
-    use [call_function a f None args] instead. Returns [None] if
-    the abstract state [a] is bottom or not computed. *)
-val call_function: Abstract_state.t -> kernel_function -> lval option -> exp list -> Abstract_state.t option
-
-
-(** [simplify_lval lv] returns a lval where every index of an array is
-    replaced by 0, evey pointer arithmetic is simplified to an access
-    to an array *)
-val simplify_lval: lval -> lval
diff --git a/src/plugins/alias/README.md b/src/plugins/alias/README.md
index 8bf5f633dca549786a11c93c42913da563bf58f6..8877a24d83af1ce82e26663eecd2f135c362b997 100644
--- a/src/plugins/alias/README.md
+++ b/src/plugins/alias/README.md
@@ -43,7 +43,6 @@ Therefore the analysis is efficient, whereas the results are not very precise.
 - recursive functions
 - user-defined variadic functions
 - function declared and used without being defined (i.e., no function body)
-- function pointers
 - assembly code
 - instructions longjmp and setjmp
 - complex instruction goto that breaks the natural control-flow of the program
diff --git a/src/plugins/alias/abstract_state.ml b/src/plugins/alias/abstract_state.ml
deleted file mode 100644
index b0326f07c131cc77566a05beaa2018d61c404921..0000000000000000000000000000000000000000
--- a/src/plugins/alias/abstract_state.ml
+++ /dev/null
@@ -1,924 +0,0 @@
-(**************************************************************************)
-(*                                                                        *)
-(*  This file is part of Frama-C.                                         *)
-(*                                                                        *)
-(*  Copyright (C) 2007-2023                                               *)
-(*    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
-
-open Simplified
-
-module VSet = Datatype.Int.Set
-module VMap = Datatype.Int.Map
-
-module Lval = Simplified.Lval
-module LSet = Cil_datatype.LvalStructEq.Set
-module LMap = Cil_datatype.LvalStructEq.Map
-
-module G = Graph.Persistent.Digraph.ConcreteBidirectional(Datatype.Int)
-module V = G.V
-
-let vid (v : G.V.t) : int = v
-
-(* like LMap, but organized with offset and specialized functions *)
-module LLMap =
-struct
-  module OMap = Offset.Map
-  (* each t is a map (lhost,NoOffset) -> offset -> V.t *)
-  type t = (V.t OMap.t) LMap.t
-
-  let empty : t = LMap.empty
-
-  let mem (lv : lval) (m:t) =
-    let lv, off = Cil.removeOffsetLval lv in
-    try
-      OMap.mem off (LMap.find lv m)
-    with
-      Not_found -> false
-
-  let find (lv : lval) (m:t) : V.t =
-    let lv, off = Cil.removeOffsetLval lv in
-    OMap.find off (LMap.find lv m)
-
-  let add (lv : lval) (v:V.t) (m:t) :t  =
-    let lv, off = Cil.removeOffsetLval lv in
-    let mo = try LMap.find lv m with Not_found -> OMap.empty in
-    LMap.add lv (OMap.add off v mo) m
-
-  let iter f = LMap.iter @@ fun lv -> OMap.iter @@ fun o -> f @@ Cil.addOffsetLval o lv
-
-  let map f = LMap.map @@ OMap.map f
-
-  let pretty fmt =
-    let is_first = ref true in
-    LMap.iter (fun lv ->
-        OMap.iter
-          (fun o v -> let lv =  Cil.addOffsetLval o lv in
-            if !is_first then is_first := false else Format.fprintf fmt "@;<3>";
-            Format.fprintf fmt "@ @[%a:%d@]" Lval.pretty lv v))
-
-  (* left-biased *)
-  let union = LMap.union @@ fun _ l r -> Some (OMap.union (fun _ l _r -> Some l) l r)
-
-  let intersect =
-    let intersect_omap l r = match l, r with
-      | Some l, Some r -> Some (l,r)
-      | _ -> None
-    in
-    let intersect_lmap l r = match l, r with
-      | Some l, Some r ->
-        let omap = OMap.merge (fun _ -> intersect_omap) l r in
-        if OMap.is_empty omap then None else Some omap
-      | _ -> None
-    in
-    LMap.merge @@ fun _ -> intersect_lmap
-
-  let to_seq m = LMap.fold (fun lv omap -> OMap.fold (fun o v s -> Seq.cons (lv,o,v) s) omap) m Seq.empty
-
-  (* specialized functions *)
-  let rec is_sub_offset o1 o2 =
-    match (o1,o2) with
-      NoOffset, _ -> true
-    | Index (e1,o1), Index (e2,o2) when Cil_datatype.ExpStructEq.equal e1 e2 -> is_sub_offset o1 o2
-    | Field (f1,o1), Field (f2,o2) when Fieldinfo.equal f1 f2 ->  is_sub_offset o1 o2
-    | _ -> false
-
-  (* finds all the lval lv1 apearing in [m] such as there exists an offset o1 and lv1 + o1 = lv *)
-  let find_upper_offsets (lv : lval) (m:t) : V.t LMap.t =
-    let lv, off = Cil.removeOffsetLval lv in
-    let mo = try LMap.find lv m with Not_found -> OMap.empty in
-    let f_filter o _v = is_sub_offset o off in
-    let mo = OMap.filter f_filter mo in
-    OMap.fold
-      (fun o -> let lv = Cil.addOffsetLval o lv in LMap.add lv)
-      mo
-      LMap.empty
-
-end
-
-type t = {
-  graph : G.t;
-  lmap : LLMap.t ; (* lmap(lv) is a table [offset->v] where the vertex v corresponding to lval (lv+offset), in other words (lv+offset) is in label(v) *)
-  vmap : LSet.t VMap.t ;(* reverse of lmap *)
-}
-
-let node_counter = ref 0
-let fresh_node_id () =
-  let id = !node_counter in
-  node_counter := !node_counter + 1;
-  id
-
-(* find functions *)
-let find_lset (v:V.t) (x:t) : LSet.t =
-  try VMap.find v x.vmap
-  with Not_found -> LSet.empty
-
-let find_aliases (lv:lval) (x:t) =
-  let lv = Lval.simplify lv in
-  try
-    let v = LLMap.find lv x.lmap in
-    find_lset v x
-  with Not_found -> LSet.empty
-
-let rec get_points_to (v:V.t) (x:t) : LSet.t =
-  assert (G.mem_vertex x.graph v);
-  let set_predecessors =
-    List.fold_left
-      (fun acc v -> LSet.union acc (get_points_to v x))
-      LSet.empty
-      (G.pred x.graph v)
-  in
-  LSet.union
-    (find_lset v x)
-    (LSet.map Lval.points_to set_predecessors)
-
-let aliases_of_vertex (v:V.t) (x:t) : LSet.t =
-  assert (G.mem_vertex x.graph v);
-  let list_pred = G.pred x.graph v in
-  List.fold_left
-    (fun acc v -> LSet.union acc (get_points_to v x))
-    LSet.empty
-    list_pred
-
-let succ_of_lval (lv:lval) (x:t) : int option =
-  let lv = Lval.simplify lv in
-  try begin
-    let v = LLMap.find lv x.lmap in
-    match G.succ x.graph v with
-    | [] -> None
-    | [succ_v] -> Some succ_v
-    | _ -> Options.fatal "invariant violated (more than 1 successor)"
-  end with Not_found -> None
-
-let find_all_aliases (lv:lval) (x:t) : LSet.t =
-  match succ_of_lval lv x with
-  | None -> LSet.empty
-  | Some succ_v -> aliases_of_vertex succ_v x
-
-let points_to_set (lv:lval) (x:t) : LSet.t =
-  match succ_of_lval lv x with
-  | None -> LSet.empty
-  | Some succ_v -> find_lset succ_v x
-
-let get_graph (x:t) = x.graph
-
-(* renamed for the interface *)
-let get_lval_set = find_lset
-
-
-(* printing functions *)
-
-let print_debug fmt (x:t) =
-  Format.fprintf fmt "@[<v>";
-  Format.fprintf fmt "@[Edges:";
-  G.iter_edges (fun v1 v2 -> Format.fprintf fmt "@;<3 2>@[%d → %d@]" v1 v2) x.graph;
-  Format.fprintf fmt "@]@;<6>";
-  Format.fprintf fmt "@[LMap:@;<3 2>";
-  LLMap.pretty fmt x.lmap;
-  Format.fprintf fmt "@]@;<6>";
-  Format.fprintf fmt "@[VMap:@;<2>";
-  VMap.iter (fun v ls -> Format.fprintf fmt "@;<2 2>@[%d:%a@]" v LSet.pretty ls) x.vmap;
-  Format.fprintf fmt "@]";
-  Format.fprintf fmt "@]"
-
-let print_graph fmt (x:t) =
-  let is_first = ref true in
-  let print_edge v1 v2 =
-    if !is_first then is_first := false else Format.fprintf fmt "@;<3>";
-    let print_node v fmt lset = Format.fprintf fmt "%d:%a" v LSet.pretty lset in
-    Format.fprintf fmt "@[%a@] → @[%a@]"
-      (print_node v1) (VMap.find v1 x.vmap)
-      (print_node v2) (VMap.find v2 x.vmap)
-  in
-  if G.nb_edges x.graph = 0
-  then Format.fprintf fmt "<empty>"
-  else G.iter_edges print_edge x.graph
-
-let print_aliases fmt (x:t) =
-  let is_first = ref true in
-  let print_alias_set _ set_lv =
-    if !is_first then is_first := false else Format.fprintf fmt "@;<2>";
-    LSet.pretty fmt set_lv
-  in
-  let alias_set_of_vertex i _ =
-    let aliases = aliases_of_vertex i x in
-    if LSet.cardinal aliases >= 2 then Some aliases else None
-  in
-  let alias_sets = VMap.filter_map alias_set_of_vertex x.vmap in
-  if VMap.is_empty alias_sets
-  then Format.fprintf fmt "<none>"
-  else VMap.iter print_alias_set alias_sets
-
-(** invariants of type t must be true before and after each functon call *)
-let assert_invariants (x:t) : unit =
-  (* check that all vertex of the graph have entries in vmap,
-     and are integer between 0 and node_counter, and have at most 1 successor *)
-  assert (!node_counter >= 0);
-  let assert_vertex (v:V.t) =
-    assert (v >= 0);
-    assert (v < !node_counter);
-    assert (VMap.mem v x.vmap);
-    assert (List.length (G.succ x.graph v) <= 1)
-  in
-  G.iter_vertex assert_vertex x.graph;
-  let assert_edge v1 v2 =
-    assert (v1 <> v2);
-    assert (G.mem_vertex x.graph v1);
-    assert (G.mem_vertex x.graph v2)
-  in
-  G.iter_edges assert_edge x.graph;
-  let assert_lmap (lv : lval) (v:V.t) =
-    assert (G.mem_vertex x.graph v);
-    assert (LSet.mem lv (VMap.find v x.vmap))
-  in
-  LLMap.iter assert_lmap x.lmap;
-  let assert_vmap (v:V.t) (ls:LSet.t) =
-    assert (G.mem_vertex x.graph v);
-    (* TODO: we removed the invariant because of OSCS*)
-    (* if not (LSet.is_empty ls)
-     * then
-     *   begin
-     *     let lv = LSet.choose ls in
-     *     let is_ptr_lv = Lval.is_pointer lv in
-     *     assert (LSet.for_all (fun x -> Lval.is_pointer x = is_ptr_lv) ls)
-     *   end; *)
-    assert (LSet.fold (fun lv acc -> acc && V.equal (LLMap.find lv x.lmap) v) ls true)
-  in
-  VMap.iter assert_vmap x.vmap
-
-(* Ensure that assert_invariants is not executed if the -noassert flag is supplied. *)
-let assert_invariants x = assert (assert_invariants x; true)
-
-let pretty ?(debug = false) fmt (x:t) =
-  if debug then
-    try
-      assert_invariants x;
-      print_graph fmt x
-    with Assert_failure _ -> print_debug fmt x
-  else
-    print_aliases fmt x
-
-(** .dot printing functions*)
-let find_vertex_name_ref = Extlib.mk_fun "find_vertex_name"
-
-module Dot = Graph.Graphviz.Dot (struct
-    include G
-    let edge_attributes _ = []
-    let default_edge_attributes _ = []
-    let get_subgraph _ = None
-    let vertex_attributes _ = [`Shape `Box]
-    let vertex_name (v:V.t) =
-      let lset = !find_vertex_name_ref v in
-      let fmt = Format.str_formatter in
-      Format.fprintf fmt "\"%a\"" LSet.pretty lset;
-      Format.flush_str_formatter ()
-    let default_vertex_attributes _ = []
-    let graph_attributes _ = []
-  end)
-
-let print_dot filename (a:t) =
-  let file = open_out filename in
-  find_vertex_name_ref :=
-    (fun v -> find_lset v a
-    );
-  Dot.output_graph file a.graph;
-  close_out file
-
-(* find functions, part 2 *)
-let rec closure_find_lset (v:V.t) (x:t) : (V.t * LSet.t) list =
-  match G.succ x.graph v with
-    [] -> [v, find_lset v x]
-  | [v_next] -> (v, find_lset v x)::(closure_find_lset v_next x)
-  | _ -> Options.fatal ("this shall not happen (invariant broken)")
-
-let find_transitive_closure  (lv:lval) (x:t) : (G.V.t * LSet.t) list =
-  let lv = Lval.simplify lv in
-  assert_invariants x;
-  try closure_find_lset (LLMap.find lv x.lmap) x with Not_found -> []
-(* TODO : what about offsets ? *)
-
-(* NOTE on "constant vertex": a constant vertex represents an unamed
-   scalar value (type bottom in steensgaard's paper), or the address
-   of a variable. It means that in [vmap], its associated LSet is
-   empty.  By definition, constant vertex cannot be associated to a
-   lval in [lmap] *)
-let create_cst_vertex (x:t) : V.t * t =
-  let new_v = fresh_node_id () in
-  new_v,
-  {
-    graph = G.add_vertex x.graph new_v;
-    lmap = x.lmap ;
-    vmap = VMap.add new_v LSet.empty x.vmap
-  }
-
-(* find all the aliases of lv1 in x, for create_vertex *)
-let find_all_aliases_of_offset (lv1 : lval) (x: t) : LSet.t =
-  let lvals_to_be_searched = decompose_lval lv1 in
-  (* for each lval, find the set of aliases *)
-  let f_map (lv,o) =
-    try VMap.find (LLMap.find lv x.lmap) x.vmap, o
-    with Not_found -> LSet.empty, o
-  in
-  Options.debug ~level:9 "decompose_lval %a : [@[<hov 2>" Lval.pretty lv1;
-  List.iter (fun (x, o) -> Options.debug ~level:9 " (%a,%a) " Lval.pretty x Offset.pretty o) lvals_to_be_searched;
-  Options.debug ~level:9 "@]]";
-  let aliases = List.map f_map lvals_to_be_searched in
-  (*  for each lval of the Lset, add the offset and add it to the resulting set *)
-  let f_fold_left (acc : LSet.t) (ls,o) =
-    LSet.fold (fun lv -> LSet.add @@ Cil.addOffsetLval o lv) ls acc
-  in
-  List.fold_left f_fold_left (LSet.singleton lv1) aliases
-
-(* returns the new vertex and the new graph *)
-(* only for function find_or_create vertex *)
-let create_vertex_simple (lv:lval) (x:t) : V.t * t =
-  let new_v = fresh_node_id () in
-  let new_g = G.add_vertex x.graph new_v in
-  (* find all the alias of lv (because of offset) *)
-  let set_of_aliases : LSet.t = find_all_aliases_of_offset lv x in
-  (* add all these aliases *)
-  Options.debug ~level:9 "all_aliases of %a : %a " Lval.pretty lv LSet.pretty set_of_aliases;
-  let new_lmap =
-    LSet.fold
-      (fun lv acc -> assert (not (LLMap.mem lv x.lmap)); LLMap.add lv new_v acc)
-      set_of_aliases
-      x.lmap
-  in
-  let new_vmap = VMap.add new_v set_of_aliases x.vmap in
-
-  let new_x =
-    {
-      graph = new_g ;
-      lmap = new_lmap ;
-      vmap = new_vmap ;
-    }
-  in
-  assert_invariants new_x;
-  match lv with
-  | Var v, NoOffset ->
-    begin
-      match v.vtype with
-        TPtr _ ->
-        (* then add a constant vertex *)
-        let another_v, new_x = create_cst_vertex new_x in
-        let new_g = G.add_edge new_x.graph new_v another_v in
-        new_v, {new_x with graph = new_g}
-      | _ -> new_v, new_x
-    end
-  | _ -> new_v , new_x
-
-let diff_offset (lv1 : lval) (lv2 : lval) =
-  let rec f_diff_offset o1 o2 =
-    match o1, o2 with
-      NoOffset, _ -> o2
-    | Field (_,o1), Field (_,o2) -> f_diff_offset o1 o2
-    | Index (_,o1), Index (_,o2) -> f_diff_offset o1 o2
-    | _ -> Options.fatal "%s: unexpected case" __LOC__
-  in
-  let _, o1 = Cil.removeOffsetLval lv1
-  and _, o2 = Cil.removeOffsetLval lv2
-  in
-  assert (LLMap.is_sub_offset o1 o2);
-  f_diff_offset o1 o2
-
-let rec create_vertex lv x =
-  Options.debug ~level:9 "creating a vertex for %a" Lval.pretty lv;
-  assert (not (LLMap.mem lv x.lmap));
-  begin
-    match lv with
-      (Mem e, NoOffset) ->
-      (* special case, when we also add another vertex and a points-to edge *)
-      begin
-        (* first find the vertex corresponding to e *)
-        match LvalOrRef.from_exp e with
-        | None -> Options.fatal "unexpected result: Lval.from (%a) = None" Exp.pretty e
-        | Some (LvalOrRef.Ref lv1) ->
-          find_or_create_vertex (LvalOrRef.Lval lv1) x
-        | Some (LvalOrRef.Lval lv1) ->
-          (* find the vertex *)
-          let v1, x = find_or_create_vertex (LvalOrRef.Lval lv1) x in
-          (* then creates a vertex for bvl ONLY IF there is no successor *)
-          begin
-            match G.succ x.graph v1 with
-              [] ->
-              let v2, x = create_vertex_simple lv x in
-              (* finally add a points-to edge between v1 and v2 *)
-              let new_graph = G.add_edge x.graph v1 v2 in
-              v2, {x with graph = new_graph }
-            | [succ_v1] ->
-              (* if there is a successor, update lmap and vmap to add blv to that successor's set *)
-              let new_lmap = LLMap.add lv succ_v1 x.lmap in
-              let new_vmap = VMap.add succ_v1 (LSet.add lv (VMap.find succ_v1 x.vmap)) x.vmap in
-              succ_v1, {x with lmap = new_lmap ; vmap = new_vmap }
-            | _ -> Options.fatal " Invariant violated : more than 1 successor"
-          end
-      end
-    | _ -> create_vertex_simple lv x
-  end
-
-and find_or_create_lval_vertex (lv:lval) (x:t) : V.t * t =
-  try LLMap.find lv x.lmap, x
-  with Not_found ->
-    (* try to find if an alias already exists in x *)
-    let map_predecessors : V.t LMap.t =
-      LLMap.find_upper_offsets lv x.lmap
-    in
-    (* for any predecessor, find all its aliases and then look for potential existing vertex *)
-    let f_fold_lmap lvx vx acc =
-      let set_aliases = VMap.find vx x.vmap in
-      Options.debug ~level:9 "looking for aliases of %a in set %a" Lval.pretty lv LSet.pretty set_aliases;
-      if LSet.cardinal set_aliases <= 1 then acc else
-        let off = diff_offset lvx lv in
-        let f_fold_lset lvs acc =
-          try
-            let lvs = Cil.addOffsetLval off lvs in
-            VSet.add (LLMap.find lvs x.lmap) acc
-          with
-            Not_found -> acc
-        in
-        LSet.fold f_fold_lset set_aliases acc
-    in
-    (* set of all existing aliases *)
-    let vset_res = LMap.fold f_fold_lmap map_predecessors VSet.empty in
-    Options.debug ~level:9 "found aliases of %a : %a" Lval.pretty lv VSet.pretty vset_res;
-    if VSet.is_empty vset_res
-    then create_vertex lv x
-    else
-      let () = assert (VSet.cardinal vset_res = 1) in
-      let v_res = VSet.choose vset_res in
-      (* vertex found, update the tables *)
-      let new_lmap = LLMap.add lv v_res x.lmap in
-      let new_vmap = VMap.add v_res (LSet.add lv (VMap.find v_res x.vmap)) x.vmap in
-      v_res, {x with lmap = new_lmap; vmap = new_vmap}
-
-(* find the vertex of an lval *)
-and find_or_create_vertex (lv : LvalOrRef.t) (x:t) : V.t * t =
-  match lv with
-  | LvalOrRef.Lval lv -> find_or_create_lval_vertex lv x
-  | LvalOrRef.Ref lv ->
-    Options.debug ~level:9 "creating a vertex for %a" LvalOrRef.pretty (LvalOrRef.Ref lv);
-    let v1, x = find_or_create_lval_vertex lv x in
-    let va, x = create_cst_vertex x in
-    va, {x with graph = G.add_edge x.graph va v1}
-
-(* TODO is there a better way to do it ? *)
-let find_vertex lv x =
-  let lv = Lval.simplify lv in
-  let v,x1 = find_or_create_lval_vertex lv x in
-  if x == x1
-  (* if x has not been modified, then the vertex was found, not created *)
-  then v
-  else raise Not_found
-
-(* merge of two vertices; the first vertex carries both sets, the second is removed from the graph and from lmap and vmap *)
-let merge x v1 v2 =
-  if (V.equal v1 v2) || not (G.mem_vertex x.graph v1) || not (G.mem_vertex x.graph v2)
-  then x
-  else
-    let set1 = find_lset v1 x in
-    let set2 = find_lset v2 x in
-
-    let new_set = LSet.union set1 set2 in
-    (* update lmap : every lval in v2 must now be associated with v1*)
-    let new_lmap = LSet.fold (fun lv2 m -> LLMap.add lv2 v1 m) set2 x.lmap in
-
-    (* update vmap *)
-    let new_vmap = VMap.add v1 new_set (VMap.remove v2 x.vmap) in
-    (* update the graph *)
-    let f_fold_succ v_succ (g:G.t) : G.t =
-      G.add_edge g v1 v_succ
-    and f_fold_pred v_pred (g:G.t) : G.t =
-      G.add_edge g v_pred v1
-    in
-    let g = x.graph in
-    (* adds all new edges *)
-    let g = G.fold_succ f_fold_succ g v2 g in
-    let g = G.fold_pred f_fold_pred g v2 g in
-    (* remove v2 *)
-    let g =  G.remove_vertex g v2 in
-    {graph = g; lmap = new_lmap; vmap = new_vmap}
-
-(* functions join and unify-pointer of steensgaard's paper *)
-let rec join_without_check (x:t) (v1:V.t) (v2:V.t) : t =
-  if (V.equal v1 v2) || not (G.mem_vertex x.graph v1 && G.mem_vertex x.graph v2)
-  then
-    x
-  else
-    let pt1 = G.succ x.graph v1 in (* TODO ask frama-c type instead of looking in the graph *)
-    let pt2 = G.succ x.graph v2 in
-    let x = merge x v1 v2 in
-    assert (not (G.mem_vertex x.graph v2));
-    match (pt1, pt2) with
-    | [], _ -> x
-    | _, [] -> x
-    | [succ_v1],[succ_v2] ->
-      assert (succ_v1 <> v2);
-      assert (succ_v2 <> v1);
-      join_without_check x succ_v1 succ_v2
-    | _, _ ->
-      Options.fatal "invariant broken"
-
-(* since the recursive version of join, unify, unify2 and merge may break the invariants *)
-let join (x:t) (v1:V.t) (v2:V.t) : t =
-  Options.debug ~level:7 "graph before join(%d,%d):@;<2>@[%a@]" v1 v2 print_debug x;
-  assert_invariants x;
-  let res = join_without_check x v1 v2 in
-  Options.debug ~level:7 "graph after join(%d,%d):@;<2>@[%a@]" v1 v2 print_debug res;
-  begin
-    try assert_invariants res
-    with Assert_failure _ ->
-      Options.debug "join(%d,%d) failed" v1 v2;
-      Options.debug "graph before join(%d,%d):@;<2>@[%a@]" v1 v2 print_debug x;
-      Options.debug "graph after join(%d,%d):@;<2>@[ %a@]" v1 v2 print_debug res;
-      assert_invariants res
-  end;
-  res
-
-let merge_set (x:t) (vs:VSet.t) : V.t * t =
-  let v0 = VSet.choose vs in
-  if VSet.cardinal vs < 2 then v0, x else begin
-    Options.debug ~level:7 "graph before merge_set %a:@;<2>@[%a@]" VSet.pretty vs print_debug x;
-    assert (G.mem_vertex x.graph v0);
-    let result = VSet.fold (fun v acc -> merge acc v0 v) vs x in
-    Options.debug ~level:7 "graph after merge_set %a:@;<2>@[%a@]" VSet.pretty vs print_debug result;
-    v0, result
-  end
-
-let rec join_succs (x:t) v =
-  Options.debug ~level:8 "joining successors of %d" v;
-  if not @@ G.mem_vertex x.graph v then x else
-    match G.succ x.graph v with
-    | [] | [_] -> x
-    | succs ->
-      let v0, x = merge_set x @@ VSet.of_list succs in
-      join_succs x v0
-
-(* in Steensgard's paper, this is written settype(v1,ref(v2,bot)) *)
-let set_type (x:t) (v1:V.t) (v2:V.t) : t =
-  assert_invariants x;
-  (* if v1 points to another node, suppress current outgoing edge (and the node if it is a constant node) *)
-  let g, new_vmap =
-    match G.succ x.graph v1 with
-      [] -> x.graph, x.vmap
-    | [v2] ->
-      (* if v2 is a constant node supress it directly *)
-      if LSet.is_empty (VMap.find v2 x.vmap)
-      then (G.remove_vertex x.graph v2, VMap.remove v2 x.vmap)
-      else (G.remove_edge x.graph v1 v2, x.vmap)
-    | _ -> Options.fatal "too many outgoing edges in set_type"
-  in
-  let new_g = G.add_edge g v1 v2 in
-  let new_x = {x with graph = new_g ; vmap = new_vmap} in
-  assert_invariants new_x ; new_x
-
-let assignment (a:t) (lv:lval) (e:exp) : t =
-  assert_invariants a;
-  if not @@ Cil.isPointerType (Cil.typeOf e) then a else
-    let x = Lval.simplify lv in
-    match LvalOrRef.from_exp e with
-    | None -> a
-    | Some y ->
-      let (v1,a) = find_or_create_lval_vertex x a in
-      let (v2,a) = find_or_create_vertex y a in
-      if List.mem v2 (G.succ a.graph v1) || List.mem v1 (G.succ a.graph v2)
-      then
-        let () =
-          Options.warning ~source:(fst e.eloc)
-            "ignoring assignment of the form: %a = %a"
-            Printer.pp_lval lv Printer.pp_exp e;
-        in a
-      else
-        let a = join a v1 v2 in
-        let () = assert_invariants a in
-        a
-
-(* assignment x = allocate(y) *)
-let assignment_x_allocate_y (a:t) (lv:lval) : t =
-  assert_invariants a;
-  let x = Lval.simplify lv in
-  let (v1,a) = find_or_create_lval_vertex x a in
-  match G.succ a.graph v1 with
-  | [] ->
-    let (v2,a) = create_cst_vertex a in
-    let new_a : t = set_type a v1 v2 in
-    let () = assert_invariants new_a in new_a
-  | [_v2] -> a
-  | _ -> Options.fatal "this should not hapen (invariant broken)"
-
-let is_included (a1:t) (a2:t) =
-  (* tests if a1 is included in a2, at least as the nodes with lval *)
-  assert_invariants a1;
-  assert_invariants a2;
-  Options.debug ~level:8 "testing equal %a AND à.%a" (pretty ~debug:true) a1 (pretty ~debug:true) a2;
-  let exception Not_included in
-  try
-    let iter_lmap (lv : lval) (v1:V.t): unit =
-      let v2 : V.t = try LLMap.find lv a2.lmap with Not_found -> raise Not_included in
-      match G.succ a1.graph v1, G.succ a2.graph v2 with
-        [], _ -> ()
-      | [_], [] -> raise Not_included
-      | [v1p], [v2p] ->
-        if LSet.subset (VMap.find v1p a1.vmap) (VMap.find v2p a2.vmap)
-        then
-          ()
-        else
-          raise Not_included
-      | _ -> Options.fatal "this should not hapen (invariant broken)"
-    in
-    LLMap.iter iter_lmap a1.lmap; true
-  with
-    Not_included -> false
-
-let empty :t =
-  {graph = G.empty; lmap = LLMap.empty; vmap = VMap.empty}
-
-let is_empty s =
-  compare s empty = 0
-
-(* add an int to all vertex values *)
-let shift (a : t) : t =
-  assert_invariants a;
-  if is_empty a then a else
-    let () = Options.debug ~level:8 "before shift: node_counter=%d@.%a" !node_counter print_debug a in
-    let max_idx = G.fold_vertex max a.graph 0 in
-    let min_idx = G.fold_vertex min a.graph max_idx in
-    let offset = !node_counter - min_idx in
-    let shift x = x + offset in
-    let shift_vmap shift_elem vmap =
-      VMap.of_seq @@ Stdlib.Seq.map shift_elem @@ VMap.to_seq vmap
-    in
-    let {graph; lmap; vmap} = a in
-    node_counter := max_idx + offset + 1;
-    let result =
-      {graph = G.map_vertex shift graph;
-       lmap = LLMap.map shift lmap;
-       vmap = shift_vmap (fun (key, l) -> (shift key, l)) vmap}
-    in
-    let () = Options.debug ~level:8 "after shift: node_counter=%d@.%a" !node_counter print_debug result in
-    assert_invariants result;
-    result
-
-let union_find vmap intersections =
-  let module Store : UnionFind.STORE = UnionFind.StoreMap.Make (VMap) in
-  let module UF = UnionFind.Make (Store) in
-  let uf = UF.new_store () in
-  let refs = VMap.mapi (fun i _ -> UF.make uf i) vmap in
-  let put_into_uf (v1,v2) =
-    let r1 = VMap.find v1 refs in
-    let r2 = VMap.find v2 refs in
-    ignore @@ UF.union uf r1 r2
-  in
-  let _vs = Seq.iter put_into_uf intersections in
-  let sets_to_be_joined =
-    let add_to_map i r sets =
-      let repr = UF.find uf r in
-      let add_to_set = function
-        | None -> Some (VSet.singleton i)
-        | Some set -> Some (VSet.add i set)
-      in
-      VMap.update (UF.get uf repr) add_to_set sets
-    in
-    VMap.fold add_to_map refs VMap.empty in
-  sets_to_be_joined
-
-let union (a1:t) (a2:t) :t =
-  (* naive algorithm :
-     1 merge the graph and the vmap (by doing union of sets)
-     2 for any node present in both a1.graph and a2.graph, merge/join them
-     3 for any lval [lv] that are has an entry in both a1.lmap and a2.lmap, merge the two vertex a1.lmap[lv]
-       and a2.lmap[lv]
-
-     I am not confident about this function, there are too many potential bugs and inefficiencies
-  *)
-  assert_invariants a1;
-  assert_invariants a2;
-
-  Options.debug ~level:4 "Union: First graph:%a" print_graph a1;
-  Options.debug ~level:5 "Union: First graph:%a" print_debug a1;
-  Options.debug ~level:4 "Union: Second graph:%a" print_graph a2;
-  Options.debug ~level:5 "Union: Second graph:%a" print_debug a2;
-  let new_graph =
-    G.fold_vertex
-      (fun v2 g -> G.add_vertex g v2)
-      a2.graph
-      a1.graph
-  in
-  let new_graph =
-    G.fold_edges
-      (fun v2a v2b g -> G.add_edge g v2a v2b)
-      a2.graph
-      new_graph
-  in
-  let new_vmap =
-    VMap.union (fun _ lset1 lset2 -> Option.some @@ LSet.union lset1 lset2)
-      a2.vmap
-      a1.vmap
-  in
-  let sets_to_be_joined =
-    let intersections = LLMap.to_seq @@ LLMap.intersect a1.lmap a2.lmap in
-    union_find new_vmap @@ Seq.map (fun (_,_,x) -> x) intersections
-  in
-  let new_lmap = LLMap.union a1.lmap a2.lmap in
-  Options.debug ~level:7 "Union: sets to be joined:@[";
-  VMap.iter (fun _ set -> Options.debug ~level:7 "%a" VSet.pretty set) sets_to_be_joined;
-  Options.debug ~level:7 "@]";
-  let new_a = {graph = new_graph; lmap = new_lmap; vmap = new_vmap} in
-  let merged_nodes, new_a =
-    VMap.fold
-      (fun _ set (merged_nodes, x) -> let v0, x = merge_set x set in (v0 :: merged_nodes), x)
-      sets_to_be_joined
-      ([], new_a)
-  in
-  let new_a = List.fold_left join_succs new_a merged_nodes in
-  Options.debug ~level:4 "Union: Result graph:%a" print_graph new_a;
-  Options.debug ~level:5 "Union: Result graph:%a" print_debug new_a;
-  begin
-    try assert_invariants new_a
-    with Assert_failure _ ->
-      Options.debug "union failed";
-      Options.debug "Union: First graph:%a" print_graph a1;
-      Options.debug "Union: First graph:%a" print_debug a1;
-      Options.debug "Union: Second graph:%a" print_graph a2;
-      Options.debug "Union: Second graph:%a" print_debug a2;
-      Options.debug "Union: Result graph:%a" print_graph new_a;
-      Options.debug "Union: Result graph:%a" print_debug new_a;
-      assert_invariants new_a
-  end;
-  new_a
-
-(** a type for summaries of functions *)
-type summary =
-  {
-    state : t option;
-    formals: lval list;
-    locals: lval list;
-    return : exp option
-  }
-
-let make_summary (s : t) (kf : kernel_function) =
-  let exp_return : exp option =
-    if Kernel_function.has_definition kf then
-      let return_stmt = Kernel_function.find_return kf in
-      match return_stmt.skind with
-        Return (e, _) -> e
-      | _ -> Options.fatal "this should not happen"
-    else
-      None
-  in
-  let s =
-    match exp_return with
-      None -> s
-    | Some e ->
-      begin
-        match s, LvalOrRef.from_exp e with
-          _, None -> s
-        | s, Some lv ->
-          let _, new_s = find_or_create_vertex lv s in
-          new_s
-      end
-  in
-  {
-    state = Some s;
-    formals = List.map (fun v -> (Var v,NoOffset)) (Kernel_function.get_formals kf);
-    locals = List.map (fun v -> (Var v,NoOffset))  (Kernel_function.get_locals kf);
-    return = exp_return
-  }
-
-let pretty_summary ?(debug=false) fmt s =
-  let print_list_lval ~state fmt (l: lval list) =
-    let is_first = ref true in
-    let print_elem x =
-      if !is_first then is_first := false else Format.fprintf fmt "@  ";
-      Format.fprintf fmt "@[%a" Cil_datatype.Lval.pretty x;
-      let pointees = points_to_set x state in
-      if not @@ LSet.is_empty pointees then
-        Format.fprintf fmt "→%a" LSet.pretty pointees;
-      Format.fprintf fmt "@]";
-    in
-    List.iter print_elem l
-  in
-  let print_option pp fmt x =
-    match x with
-    | Some x -> pp fmt x
-    | None -> Format.fprintf fmt "<none>"
-  in
-  match s.state with
-  | None -> if debug then Format.fprintf fmt "not found"
-  | Some s when is_empty s -> if debug then Format.fprintf fmt "empty"
-  | Some state ->
-    begin
-      Format.fprintf fmt "@[formals: @[%a@]@;<4>locals: @[%a@]@;<4>returns: @[%a@]@;<4>state: @[%a@] "
-        (print_list_lval ~state) s.formals
-        (print_list_lval ~state) s.locals
-        (print_option Exp.pretty) s.return
-        (print_option @@ pretty ~debug) s.state;
-    end
-
-(* the algorithm:
-   - unify the two graphs dropping all the variables from the summary
-   - pair arguments with formals assigning the formal's successor as the argument's successor
-*)
-let call (state:t) (res:lval option) (args:exp list) (summary:summary) :t =
-  assert_invariants state;
-  let formals = summary.formals in
-  assert (List.length args = List.length formals);
-  let sum_state = shift @@ Option.get summary.state in
-
-  (* pair up formals and their corresponding arguments,
-     as well as the bound result with the returned value *)
-  let arg_formal_pairs =
-    let res_ret = match res, summary.return with
-      | None, None -> []
-      | Some res, Some ret ->
-        let simplify_ret x = match LvalOrRef.from_exp x with
-          | Some (LvalOrRef.Lval lval) -> lval
-          | _ -> Options.fatal "unexpected form of return statement"
-        in
-        [LvalOrRef.Lval (Lval.simplify res), simplify_ret ret]
-      | None, Some _ -> []
-      | Some _, None -> (* Shouldn't happen: Frama-C adds missing returns *)
-        Options.fatal "unexpected case: result without return"
-    in
-    let simplify_both (arg, formal) =
-      try
-        match LvalOrRef.from_exp arg with
-        | None -> None
-        | Some lv -> Some (lv, Lval.simplify formal)
-      with Explicit_pointer_address loc ->
-        Options.warning ~source:(fst loc) ~wkey:Options.Warn.unsupported_address
-          "unsupported feature: explicit pointer address: %a; analysis may be unsound"
-          Printer.pp_exp arg;
-        None
-    in
-    res_ret @ List.filter_map simplify_both @@ List.combine args formals
-  in
-
-  (* for each pair (lv1,lv2) find (or create) the corresponding vertices *)
-  let state, vertex_pairs =
-    let state = ref state in
-    let find_vertex (lv1, lv2) =
-      try
-        let v2 = LLMap.find lv2 sum_state.lmap in
-        let v1, new_state = find_or_create_vertex lv1 !state in
-        state := new_state;
-        Some (v1, v2)
-      with Not_found -> None
-    in
-    !state, List.filter_map find_vertex arg_formal_pairs
-  in
-
-  (* merge the function graph;
-     for every arg/formal vertex pair (v1,v2) and every edge v2→v create edge v1→v. *)
-  let g =
-    let transfer_succs (g : G.t) (v1,v2) =
-      let v2_succs = G.succ sum_state.graph v2 in
-      assert (List.length v2_succs < 2);
-      List.fold_left (fun g succ -> G.add_edge g v1 succ) g v2_succs
-    in
-    let g = state.graph in
-    let g = G.fold_vertex (fun i g -> G.add_vertex g i) sum_state.graph g in
-    let g = G.fold_edges (fun i j g -> G.add_edge g i j) sum_state.graph g in
-    List.fold_left transfer_succs g vertex_pairs
-  in
-
-  (* garbage collect: remove leaf vertices from g that originate from sum_state *)
-  let vertices_to_add_to_g, g =
-    let g = ref g in
-    let remove_if_leaf v _ =
-      if G.in_degree sum_state.graph v = 0
-      then let () = g := G.remove_vertex !g v in None
-      else Some LSet.empty
-    in
-    let remaining_vertices = VMap.filter_map remove_if_leaf sum_state.vmap in
-    remaining_vertices, !g
-  in
-
-  let state = {
-    graph = g;
-    lmap = state.lmap;
-    vmap =
-      let left_bias _ l _ = Some l in
-      VMap.union left_bias state.vmap vertices_to_add_to_g}
-  in
-
-  let state = List.fold_left join_succs state (List.map fst vertex_pairs) in
-
-  assert_invariants state;
-  state
diff --git a/src/plugins/alias/API.ml b/src/plugins/alias/src/API.ml
similarity index 57%
rename from src/plugins/alias/API.ml
rename to src/plugins/alias/src/API.ml
index 66e9f86bd0801c600e172220ad10956c7c6d32f4..53ae066ea24aafd942d7d7a861fb10668723d4de 100644
--- a/src/plugins/alias/API.ml
+++ b/src/plugins/alias/src/API.ml
@@ -22,12 +22,17 @@
 
 open Cil_types
 
+module EdgeLabel = Abstract_state.EdgeLabel
+
 (** Points-to graphs datastructure. *)
 module G = Abstract_state.G
 
+type v = G.V.t
+
 let vid = Abstract_state.vid
 
 module LSet = Abstract_state.LSet
+module VarSet = Abstract_state.VarSet
 
 module Abstract_state = Abstract_state
 
@@ -37,60 +42,67 @@ let check_computed () =
     Options.abort "Static analysis must be called before any function of the API can be called"
 
 
-let lset
-    (get_set : Abstract_state.t -> LSet.t)
-    (kf : kernel_function) (s : stmt) =
+let lset ~stmt (get_set : Abstract_state.t -> LSet.t) =
   check_computed ();
-  match Analysis.get_state_before_stmt kf s with
+  match Analysis.get_state_before_stmt stmt with
   | None -> LSet.empty
   | Some state -> get_set state
 
-let points_to_set_stmt kf s lv = lset (Abstract_state.points_to_set lv) kf s
+let vars ~stmt (get_set : Abstract_state.t -> VarSet.t) =
+  check_computed ();
+  match Analysis.get_state_before_stmt stmt with
+  | None -> VarSet.empty
+  | Some state -> get_set state
 
-let new_points_to_set_stmt kf s lv =
-  let get_set state =
-    let new_state = Analysis.do_stmt state s in
-    Abstract_state.points_to_set lv new_state
-  in
-  lset get_set kf s
+module Statement = struct
+  let points_to_vars ~stmt lv = vars ~stmt (Abstract_state.points_to_vars lv)
+  let points_to_lvals ~stmt lv = lset ~stmt (Abstract_state.points_to_lvals lv)
+  let alias_vars ~stmt lv = vars ~stmt (Abstract_state.alias_vars lv)
+  let aliases ~stmt lv = lset ~stmt (Abstract_state.find_all_aliases lv)
+
+  let are_aliased ~stmt (lv1: lval) (lv2:lval) : bool =
+    (* TODO: more efficient algorithm: do they share a successor? *)
+    LSet.mem lv2 @@ aliases ~stmt lv1
+end
 
-let aliases_stmt kf s lv =
-  lset (Abstract_state.find_all_aliases lv) kf s
+let points_to_set_stmt _kf stmt = Statement.points_to_lvals ~stmt
 
-let new_aliases_stmt kf s lv =
+let aliases_stmt _kf stmt = Statement.aliases ~stmt
+
+let new_aliases_stmt s lv =
   let get_set state =
     let new_state = Analysis.do_stmt state s in
     Abstract_state.find_all_aliases lv new_state
   in
-  lset get_set kf s
+  lset ~stmt:s get_set
 
-let points_to_set_kf (kf : kernel_function) (lv : lval) =
-  check_computed ();
-  if Kernel_function.has_definition kf
-  then
-    let s = Kernel_function.find_return kf in
-    new_points_to_set_stmt kf s lv
-  else
-    Options.abort "points_to_set_kf: function %a has no definition" Kernel_function.pretty kf
+module Function = struct
+  let return_stmt kf =
+    if Kernel_function.has_definition kf
+    then Kernel_function.find_return kf
+    else Options.abort "function %a has no definition" Kernel_function.pretty kf
 
-let aliases_kf (kf : kernel_function) (lv : lval) =
-  check_computed ();
-  if Kernel_function.has_definition kf
-  then
-    let s = Kernel_function.find_return kf in
-    new_aliases_stmt kf s lv
-  else
-    Options.abort "aliases_kf: function %a has no definition" Kernel_function.pretty kf
+  let points_to_vars ~kf = Statement.points_to_vars ~stmt:(return_stmt kf)
+  let points_to_lvals ~kf = Statement.points_to_lvals ~stmt:(return_stmt kf)
+  let alias_vars ~kf = Statement.alias_vars ~stmt:(return_stmt kf)
+  let aliases ~kf = Statement.aliases ~stmt:(return_stmt kf)
+  let are_aliased ~kf = Statement.are_aliased ~stmt:(return_stmt kf)
 
-let fundec_stmts (kf : kernel_function) (lv : lval) =
-  check_computed ();
-  if Kernel_function.has_definition kf
-  then
-    List.map
-      (fun s -> s, new_aliases_stmt kf s lv)
-      (Kernel_function.get_definition kf).sallstmts
-  else
-    Options.abort "fundec_stmts: function %a has no definition" Kernel_function.pretty kf
+  let fundec_stmts ~kf lv =
+    if Kernel_function.has_definition kf
+    then
+      List.map
+        (fun s -> s, new_aliases_stmt s lv)
+        (Kernel_function.get_definition kf).sallstmts
+    else
+      Options.abort "fundec_stmts: function %a has no definition" Kernel_function.pretty kf
+end
+
+let points_to_set_kf kf = Function.points_to_lvals ~kf
+
+let aliases_kf kf = Function.aliases ~kf
+
+let fundec_stmts kf = Function.fundec_stmts ~kf
 
 
 let fold_points_to_set f_fold acc kf s lv =
@@ -99,13 +111,13 @@ let fold_points_to_set f_fold acc kf s lv =
 let fold_aliases_stmt f_fold acc kf s lv =
   LSet.fold (fun e a -> f_fold a e) (aliases_stmt kf s lv) acc
 
-let fold_new_aliases_stmt f_fold acc kf s lv =
-  LSet.fold (fun e a -> f_fold a e) (new_aliases_stmt kf s lv) acc
+let fold_new_aliases_stmt f_fold acc _kf s lv =
+  LSet.fold (fun e a -> f_fold a e) (new_aliases_stmt s lv) acc
 
 let fold_points_to_set_kf (f_fold: 'a -> lval -> 'a) (acc: 'a) (kf:kernel_function) (lv:lval) : 'a =
   LSet.fold (fun e a -> f_fold a e) (points_to_set_kf kf lv) acc
 
-let fold_aliases_kf (f_fold : 'a -> lval -> 'a) (acc : 'a) (kf : kernel_function) (lv : lval) : 'a =
+let fold_aliases_kf (f_fold : 'a -> lval -> 'a) (acc : 'a) kf lv : 'a =
   LSet.fold (fun e a -> f_fold a e) (aliases_kf kf lv) acc
 
 let fold_fundec_stmts (f_fold: 'a -> stmt -> lval -> 'a) (acc: 'a) (kf:kernel_function) (lv:lval) : 'a =
@@ -116,26 +128,20 @@ let fold_fundec_stmts (f_fold: 'a -> stmt -> lval -> 'a) (acc: 'a) (kf:kernel_fu
     acc
     (fundec_stmts kf lv)
 
-let are_aliased (kf: kernel_function) (s:stmt) (lv1: lval) (lv2:lval) : bool =
-  check_computed ();
-  match Analysis.get_state_before_stmt kf s with
-    None -> false
-  | Some state ->
-    let setv1 = Abstract_state.find_all_aliases lv1 state in
-    LSet.mem lv2 setv1
+let are_aliased (_kf: kernel_function) stmt = Statement.are_aliased ~stmt
 
-let fold_vertex (f_fold : 'a -> G.V.t -> lval -> 'a) (acc: 'a) (kf: kernel_function) (s:stmt) (lv: lval) : 'a =
+let fold_vertex (f_fold : 'a -> G.V.t -> lval -> 'a) (acc: 'a) (_kf: kernel_function) (s:stmt) (lv: lval) : 'a =
   check_computed ();
-  match Analysis.get_state_before_stmt kf s with
+  match Analysis.get_state_before_stmt s with
     None -> acc
   | Some state ->
     let v : G.V.t = Abstract_state.find_vertex lv state in
-    let set_aliases = Abstract_state.find_aliases lv state in
-    LSet.fold (fun lv a-> f_fold a v lv) set_aliases acc
+    let set_aliases = Abstract_state.find_synonyms lv state in
+    LSet.fold (fun lv a -> f_fold a v lv) set_aliases acc
 
-let fold_vertex_closure  (f_fold : 'a -> G.V.t -> lval -> 'a) (acc: 'a) (kf: kernel_function)  (s:stmt) (lv: lval) : 'a =
+let fold_vertex_closure  (f_fold : 'a -> G.V.t -> lval -> 'a) (acc: 'a) (_kf: kernel_function)  (s:stmt) (lv: lval) : 'a =
   check_computed ();
-  match Analysis.get_state_before_stmt kf s with
+  match Analysis.get_state_before_stmt s with
     None -> acc
   | Some state ->
     let list_closure : (G.V.t * LSet.t) list = Abstract_state.find_transitive_closure lv state in
@@ -144,7 +150,7 @@ let fold_vertex_closure  (f_fold : 'a -> G.V.t -> lval -> 'a) (acc: 'a) (kf: ker
       acc
       list_closure
 
-let get_state_before_stmt =
+let get_state_before_stmt _kf =
   Analysis.get_state_before_stmt
 
 let call_function a f res args =
diff --git a/src/plugins/alias/src/API.mli b/src/plugins/alias/src/API.mli
new file mode 100644
index 0000000000000000000000000000000000000000..d415b1699ac41171fa7e8ba17b2437bbd6c9fd5b
--- /dev/null
+++ b/src/plugins/alias/src/API.mli
@@ -0,0 +1,266 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of Frama-C.                                         *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2023                                               *)
+(*    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).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+(** External API of the plugin Alias *)
+
+open Cil_types
+
+module LSet = Cil_datatype.LvalStructEq.Set
+module VarSet = Cil_datatype.Varinfo.Set
+
+module EdgeLabel : sig
+  type t = Pointer | Field of fieldinfo
+
+  val compare : t -> t -> int
+  val default : t
+  val is_pointer : t -> bool
+  val is_field : t -> bool
+  val pretty : Format.formatter -> t -> unit
+end
+
+module G : Graph.Sig.G with type V.t = int and type E.t = int * EdgeLabel.t * int
+
+type v = G.V.t
+
+val vid : v -> int
+
+(** analyses at the granularity of a statement, i.e. the results are w.r.t. to
+    the state just before the given statement [stmt] *)
+module Statement : sig
+  (** see [Abstract_state.points_to_vars] *)
+  val points_to_vars : stmt:stmt -> lval -> VarSet.t
+
+  (** see [Abstract_state.points_to_lvals] *)
+  val points_to_lvals : stmt:stmt -> lval -> LSet.t
+
+  (** see [Abstract_state.alias_vars] *)
+  val alias_vars : stmt:stmt -> lval -> VarSet.t
+
+  (** see [Abstract_state.find_all_aliases] *)
+  val aliases : stmt:stmt -> lval -> LSet.t
+
+  val are_aliased: stmt:stmt -> lval -> lval -> bool
+end
+
+(** analyses at the level of a [kernel_function], i.e. the results are w.r.t.
+    to the end of the given function *)
+module Function : sig
+  (** see [Abstract_state.points_to_vars] *)
+  val points_to_vars : kf:kernel_function -> lval -> VarSet.t
+
+  (** see [Abstract_state.points_to_lvals] *)
+  val points_to_lvals : kf:kernel_function -> lval -> LSet.t
+
+  (** see [Abstract_state.alias_vars] *)
+  val alias_vars : kf:kernel_function -> lval -> VarSet.t
+
+  (** see [Abstract_state.find_all_aliases] *)
+  val aliases : kf:kernel_function -> lval -> LSet.t
+
+  val are_aliased: kf:kernel_function -> lval -> lval -> bool
+
+  (** list of pairs [s, e] where [e] is the set of lvals aliased to [v] after
+      each statement [s] in function [kf]. *)
+  val fundec_stmts : kf:kernel_function -> lval -> (stmt * LSet.t) list
+end
+
+val points_to_set_stmt : kernel_function -> stmt -> lval -> LSet.t
+[@@alert deprecated "Use Statement.points_to_vars or Statement.points_to_lvals instead!"]
+
+val points_to_set_kf : kernel_function -> lval -> LSet.t
+[@@alert deprecated "Use Function.points_to_vars or Function.points_to_lvals instead!"]
+
+val aliases_stmt : kernel_function -> stmt -> lval -> LSet.t
+[@@alert deprecated "Use Statement.aliases instead!"]
+
+val aliases_kf : kernel_function -> lval -> LSet.t
+[@@alert deprecated "Use Function.aliases instead!"]
+
+val fundec_stmts : kernel_function -> lval -> (stmt * LSet.t) list
+[@@alert deprecated "Use Function.fundec_stmts instead!"]
+
+
+val fold_points_to_set:
+  ('a -> lval -> 'a) -> 'a -> kernel_function -> stmt -> lval -> 'a
+[@@alert deprecated "Use LSet.fold/Statement.points_to_lvals or VarSet.fold/Statement.points_to_vars instead!"]
+
+val fold_aliases_stmt:
+  ('a -> lval -> 'a) -> 'a -> kernel_function -> stmt -> lval -> 'a
+[@@alert deprecated "Use LSet.fold and Statement.aliases instead!"]
+
+(** [fold_new_aliases_stmt f acc kf s lv] folds [f acc] over all the aliases of
+    the given lval [lv] created by stmt [s] in function [kf]. *)
+val fold_new_aliases_stmt:
+  ('a -> lval -> 'a) -> 'a -> kernel_function -> stmt -> lval -> 'a
+
+val fold_points_to_set_kf :
+  ('a -> lval -> 'a) -> 'a -> kernel_function -> lval -> 'a
+[@@alert deprecated "Use LSet.fold/Function.points_to_lvals VarSet.fold/Function.points_to_vars instead!"]
+
+(** [fold_aliases_kf f acc kf lv] folds [f acc] over all the aliases of lval
+    [lv] at the end of function [kf]. *)
+val fold_aliases_kf:
+  ('a -> lval -> 'a) -> 'a -> kernel_function -> lval -> 'a
+[@@alert deprecated "Use LSet.fold/Function.aliases VarSet.fold/alias_vars instead!"]
+
+(** [fold_fundec_stmts f acc kf v] folds [f acc s e] on the list of
+    pairs [s, e] where [e] is the set of lval aliased to [v] after statement [s]
+    in function [kf]. *)
+val fold_fundec_stmts:
+  ('a -> stmt -> lval -> 'a) -> 'a -> kernel_function -> lval -> 'a
+
+val are_aliased: kernel_function -> stmt -> lval -> lval -> bool
+[@@alert deprecated "Use Statement.are_aliased instead!"]
+
+(** [fold_vertex f acc kf s v] folds [f acc i lv] to all [lv] in [i], where [i] is
+    the vertex that represents the equivalence class of [v] before statement [s] in function [kf]. *)
+val fold_vertex:
+  ('a -> v -> lval -> 'a) -> 'a  -> kernel_function -> stmt -> lval  -> 'a
+
+(** [fold_vertex_closure f acc kf s v] is the transitive closure of function
+    [fold_vertex]. *)
+val fold_vertex_closure:
+  ('a -> v -> lval -> 'a) -> 'a  -> kernel_function -> stmt -> lval  -> 'a
+
+
+(** direct access to the abstract state. See Abstract_state.mli *)
+
+module Abstract_state : sig
+  (** Type denothing an abstract state of the analysis. It is a graph containing
+      all aliases and points-to information. *)
+  type t
+
+  (** access to the points-to graph *)
+  val get_graph: t -> G.t
+
+  (** set of variables associated with given vertex *)
+  val get_vars : v -> t -> VarSet.t
+
+  (** set of lvals which can be used to refered to the given vertex
+      Example graph: {a} → {b} -t→ {c}
+      The lvals corresponding to the rightmost vertex are {c, b.t, a->t}:
+      - c:    simply refers to a variable associated with the vertex.
+      - b.t:  starting from the second vertex one can follow a field-edge
+              labelled "t" to come upon the rightmost vertex.
+      - a->t: Following a pointer edge from the leftmost vertex one obtains
+              "*a". Following the "t" field-edge one arrives at the rightmost
+              vertex, corresponding to "( *a ).t" or "a->t". *)
+  val get_lval_set : v -> t -> LSet.t
+
+  (** pretty printer; debug=true prints the graph, debug = false only
+      prints aliased variables *)
+  val pretty : ?debug:bool -> Format.formatter -> t -> unit
+
+  (** dot printer; first argument is a file name *)
+  val print_dot : string -> t -> unit
+
+  (** finds the vertex corresponding to a lval.
+      @raise Not_found if such a vertex does not exist
+  *)
+  val find_vertex : lval -> t -> v
+
+  (* Combining [find_vertex] and [get_vars] finds the varset associated with
+     the vertex of the given lval.
+     Does not raise an exception but returns an empty set for inexisting lval. *)
+  val find_vars : lval -> t -> VarSet.t
+
+  (** Note: You probably want to use [find_all_aliases] instead of this function.
+      Combining [find_vertex] with [get_lval_set], this function yields all the
+      different ways the vertex containing the given lval can be referred to.
+      Example: {a} → {b,c}
+      If "a" points to "b", then the vertex containing "b" can be referred to not
+      only by "b" but also by "c" or "*a".
+      Does not raise an exception but returns an empty set if the lval is not in
+      the graph. *)
+  val find_synonyms : lval -> t -> LSet.t
+
+  (** all the variables that are aliases of the given lval:
+      - variables sharing an equivalence class (or: vertex) with [lv]
+      - variables from a neighbouring vertex, i.e. a vertex that shares a
+        successor with the vertex of [lv].
+
+      Example: {a,b} → {c} ← {d} ← {e}
+      The aliases of "a" are {a,b,d}:
+      - "b" shares a vertex with "a"
+      - "d" is in a neighbouring vertex, pointing to "c" as does {a,b} *)
+  val alias_vars : lval -> t -> VarSet.t
+
+  val find_aliases : lval -> t -> LSet.t
+  [@@alert deprecated "Use find_synonyms, alias_vars, or find_all_aliases instead!"]
+
+  (** Yields all lvals that are alias of a given lval [lv]. This includes:
+      - variables sharing an equivalence class (or: vertex) with [lv]
+      - variables from a neighbouring vertex, i.e. a vertex that shares a
+        successor with the vertex of [lv].
+      - lvals reconstructed from the variables from the two previous sets.
+
+      Example: {a,b} → {c} ← {d} ← {e}
+      The aliases of "a" are {a,b,d,*e}:
+      - "b" shares a vertex with "a"
+      - "d" is in a neighbouring vertex, pointing to "c" as does {a,b}
+      - *e is obtained by following backwards the pointer edge from {d} to {e}. *)
+  val find_all_aliases : lval -> t -> LSet.t
+
+  (** the set of all lvars to which the given variable may point. *)
+  val points_to_vars : lval -> t -> VarSet.t
+
+  (** the set of all lvals to which the given variable may point including
+      reconstructed lvals such as *p, a.t, c->s.
+      For some pointer p it will always include *p. *)
+  val points_to_lvals : lval -> t -> LSet.t
+
+  val points_to_set : lval -> t -> LSet.t
+  [@@alert deprecated "Use points_to_vars or points_to_lvals instead!"]
+
+  (** find_aliases, then recursively finds other sets of lvals. We
+      have the property (if lval [lv] is in abstract state [x]) :
+      List.hd (find_transitive_closure lv x) = (find_vertex lv x,
+      find_aliases lv x).
+      Only follows pointer edges, not field edges.
+  *)
+  val find_transitive_closure : lval -> t -> (v * LSet.t) list
+
+  (** inclusion test; [is_included a1 a2] tests if, for any lvl
+      present in a1 (associated to a vertex v1), that it is also
+      present in a2 (associated to a vertex v2) and that
+      get_lval_set(succ(v1) is included in get_lval_set(succ(v2)) *)
+  val is_included : t -> t -> bool
+end
+
+(** [get_state_before_stmt f s] gets the abstract state computed after
+    statement [s] in function [f]. Returns [None] if
+    the abstract state is bottom or not computed. *)
+val get_state_before_stmt :  kernel_function -> stmt -> Abstract_state.t option
+
+
+(** [call_function a f Some(res) args] computes the abstract state
+    after the instruction res=f(args) where res is a lval. [a] is the
+    abstract state before the call. If function [f] returns no value,
+    use [call_function a f None args] instead. Returns [None] if
+    the abstract state [a] is bottom or not computed. *)
+val call_function: Abstract_state.t -> kernel_function -> lval option -> exp list -> Abstract_state.t option
+
+
+(** [simplify_lval lv] returns a lval where every index of an array is
+    replaced by 0, evey pointer arithmetic is simplified to an access
+    to an array *)
+val simplify_lval: lval -> lval
diff --git a/src/plugins/alias/Alias.ml b/src/plugins/alias/src/Alias.ml
similarity index 100%
rename from src/plugins/alias/Alias.ml
rename to src/plugins/alias/src/Alias.ml
diff --git a/src/plugins/alias/Alias.mli b/src/plugins/alias/src/Alias.mli
similarity index 100%
rename from src/plugins/alias/Alias.mli
rename to src/plugins/alias/src/Alias.mli
diff --git a/src/plugins/alias/src/abstract_state.ml b/src/plugins/alias/src/abstract_state.ml
new file mode 100644
index 0000000000000000000000000000000000000000..2dbd0b81ec4a95ec60d34dfa9c67ff2cdd49aabb
--- /dev/null
+++ b/src/plugins/alias/src/abstract_state.ml
@@ -0,0 +1,942 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of Frama-C.                                         *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2023                                               *)
+(*    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
+
+open Simplified
+
+module EdgeLabel = struct
+  type t =
+    | Pointer (* represents dereferentiation of pointers as well as arrays *)
+    | Field of fieldinfo
+  let compare l r = match l, r with
+    | Pointer, Pointer -> 0
+    | Pointer, Field _ -> -1
+    | Field lv, Field rv -> Fieldinfo.compare lv rv
+    | Field _, Pointer -> 1
+  let default = Pointer
+  let is_pointer = function Pointer -> true | _ -> false
+  let is_field = function Field _ -> true | _ -> false
+  let pretty fmt = function
+    | Pointer -> ()
+    | Field f -> Format.fprintf fmt "-%s" f.fname
+end
+
+module G = struct
+  include Graph.Persistent.Digraph.ConcreteBidirectionalLabeled (Datatype.Int) (EdgeLabel)
+
+  let psucc g v =
+    let only_pointer_succ e =
+      if EdgeLabel.is_pointer (E.label e) then Some (E.dst e) else None
+    in
+    List.filter_map only_pointer_succ (succ_e g v)
+
+  let ppred g v =
+    let p e = match E.label e with Pointer -> Some (E.src e) | _ -> None in
+    List.filter_map p (pred_e g v)
+
+  let fsucc_opt g v f =
+    assert (List.for_all (fun e -> EdgeLabel.is_field @@ E.label e) @@ succ_e g v);
+    let is_field_f e = match E.label e with
+      | Field f' -> Fieldinfo.equal f f'
+      | _ -> false
+    in
+    let edges = succ_e g v in
+    assert (List.length (List.filter is_field_f edges) <= 1);
+    Option.map E.dst @@ List.find_opt is_field_f edges
+
+  let psucc_opt g v = match psucc g v with
+    | [] -> None
+    | [v] -> Some v
+    | _ -> Options.fatal "Invariant violated: more than one successor"
+end
+
+type v = G.V.t
+
+module V = G.V
+module E = struct
+  include G.E
+  include EdgeLabel
+  module Map = Stdlib.Map.Make (struct
+      type t = EdgeLabel.t
+      let compare = EdgeLabel.compare
+    end)
+end
+
+module VMap = Datatype.Int.Map
+module VSet = Datatype.Int.Set
+module LSet = Cil_datatype.LvalStructEq.Set
+module VarSet = Cil_datatype.Varinfo.Set
+
+module VarMap = struct
+  include Cil_datatype.Varinfo.Map
+
+  let intersect = merge @@ fun _ l r -> match l,r with
+    | Some l, Some r -> Some (l,r)
+    | _ -> None
+
+  let pretty = let module M = Make (Datatype.Int) in M.pretty
+end
+
+type state =
+  {graph : G.t;
+   vmap : VarSet.t VMap.t; (* associate with each node a set of variables *)
+   varmap : V.t VarMap.t (* reverse of varmap *)}
+
+let node_counter = ref 0
+let fresh_node_id () =
+  let id = !node_counter in
+  node_counter := !node_counter + 1;
+  id
+
+let get_vars v s : VarSet.t =
+  try VMap.find v s.vmap with Not_found -> VarSet.empty
+
+(* raises Not_found *)
+let rec find_lval_vertex ((lhost, offset) : lval) s : V.t =
+  let find_psucc v = match G.psucc_opt s.graph v with Some v -> v | _ -> raise Not_found in
+  let find_fsucc v fname = match G.fsucc_opt s.graph v fname with Some v -> v | _ -> raise Not_found in
+  let find_lhost = function
+    | Var var -> VarMap.find var s.varmap
+    | Mem e ->
+      match LvalOrRef.from_exp e with
+      | None -> Options.fatal "unexpected result: Lval.from (%a) = None" Exp.pretty e
+      | Some (LvalOrRef.Ref lv1) -> find_lval_vertex lv1 s
+      | Some (LvalOrRef.Lval lv1) ->
+        let v1 = find_lval_vertex lv1 s in
+        find_psucc v1
+  in
+  let rec find_offset v = function
+    | NoOffset -> v
+    | Index (_, o) ->
+      let v' = find_psucc v in
+      find_offset v' o
+    | Field (f, o) ->
+      let v' = find_fsucc v f in
+      find_offset v' o
+  in
+  let hv = find_lhost lhost in
+  find_offset hv offset
+
+
+module Readout = struct
+
+  (* Reconstruct all lvals that are represented by the given node.
+     Nodes only carry varinfos. In order to obtain lvals we recursively walk
+     backwards in the graph inductively constructing lvals from scratch.
+     - The lvals of the current node are the stored varinfos themselves.
+     - After gathering the lvals for the predecessor, the lvals are
+       modified according to the edge type used:
+       * Pointer: add a star (x → *x)
+       * Field f: add an offset (x -> x.f) *)
+  let get_lval_set v s : LSet.t =
+    assert (G.mem_vertex s.graph v);
+    (* cycles can occur with unsafe casts such as: x->f = (int* ) x; *)
+    let rec checking_for_cycles s visited v =
+      if VSet.mem v visited then
+        let () =
+          Options.warning ~once:true ~wkey:Options.Warn.incoherent
+            "cycle during readout of vertex %d, \
+             (following unsafe cast?); analysis may be unsound" v
+        in LSet.empty
+      else
+        let visited = VSet.add v visited in
+        let modified_predecessors = List.map
+            (fun e ->
+               let pred_lvals = checking_for_cycles s visited @@ E.src e in
+               let modify_lval lv = match E.label e with
+                 | Field f -> Cil.addOffsetLval (Field (f, NoOffset)) lv
+                 | Pointer ->
+                   (* TODO: This Cil.typeOfLval may crash with a fatal kernel
+                      error for certain reconstructed lvals involving a union
+                      type. See tests/known_bugs/union_readback.c *)
+                   let ty = Cil.typeOfLval lv in
+                   if Cil.isArrayType ty then
+                     Cil.addOffsetLval (Index (Simplified.nul_exp, NoOffset)) lv
+                   else
+                     let () = if not @@ Cil.isPointerType ty then
+                         Options.debug "unexpected type: %a" Printer.pp_typ ty
+                     in
+                     Mem (Cil.dummy_exp @@ Lval lv), NoOffset
+               in
+               LSet.map modify_lval pred_lvals
+            )
+            (G.pred_e s.graph v)
+        in
+        let lvals_of_v =
+          let mk_lval var = (Var var), NoOffset in
+          LSet.of_seq @@ Seq.map mk_lval @@ VarSet.to_seq @@ get_vars v s
+        in
+        List.fold_left LSet.union lvals_of_v modified_predecessors
+    in
+    checking_for_cycles s VSet.empty v
+
+  let lvals_pointing_to_vertex v s : LSet.t =
+    assert (G.mem_vertex s.graph v);
+    let list_pred = List.map (fun b -> get_lval_set b s) (G.ppred s.graph v) in
+    List.fold_left LSet.union LSet.empty list_pred
+
+  let find_vars lv s =
+    let lv = Lval.simplify lv in
+    try let v = find_lval_vertex lv s in get_vars v s
+    with Not_found -> VarSet.empty
+
+  let find_synonyms lv s =
+    let lv = Lval.simplify lv in
+    try let v = find_lval_vertex lv s in get_lval_set v s
+    with Not_found -> LSet.empty
+
+  let alias_vars lv s : VarSet.t =
+    try
+      let v = find_lval_vertex lv s in
+      let succs = G.psucc s.graph v in
+      let pred_succs = List.concat_map (G.ppred s.graph) succs in
+      let pred_vars = List.map (fun p -> get_vars p s) pred_succs in
+      List.fold_left VarSet.union VarSet.empty pred_vars
+    with Not_found -> VarSet.empty
+
+  let find_all_aliases lv s : LSet.t =
+    let v_opt = try Some (find_lval_vertex lv s) with Not_found -> None in
+    match Option.bind v_opt @@ G.psucc_opt s.graph with
+    | None -> LSet.empty
+    | Some succ -> lvals_pointing_to_vertex succ s
+
+  let points_to_vars lv s : VarSet.t =
+    let succ = try G.psucc_opt s.graph @@ find_lval_vertex lv s with Not_found -> None in
+    match succ with
+    | None -> VarSet.empty
+    | Some succ_v -> get_vars succ_v s
+
+  let points_to_lvals lv s : LSet.t =
+    let succ = try G.psucc_opt s.graph @@ find_lval_vertex lv s with Not_found -> None in
+    match succ with
+    | None -> LSet.empty
+    | Some succ_v -> get_lval_set succ_v s
+
+end
+
+
+module Pretty = struct
+
+  let pp_debug fmt s =
+    Format.fprintf fmt "@[<v>";
+    Format.fprintf fmt "@[Edges:";
+    G.iter_edges_e
+      (fun e ->
+         Format.fprintf fmt "@;<3 2>@[%d@ @[%a→@]@ %d@]"
+           (E.src e) E.pretty (E.label e) (E.dst e))
+      s.graph;
+    Format.fprintf fmt "@]@;<6>";
+    Format.fprintf fmt "@[VarMap:@;<3 2>";
+    VarMap.pretty fmt s.varmap;
+    Format.fprintf fmt "@]@;<6>";
+    Format.fprintf fmt "@[VMap:@;<2>";
+    VMap.iter (fun v ls -> Format.fprintf fmt "@;<2 2>@[%d:%a@]" v VarSet.pretty ls) s.vmap;
+    Format.fprintf fmt "@]";
+    Format.fprintf fmt "@]"
+
+  let pp_graph fmt s =
+    let is_first = ref true in
+    let pp_node v fmt lset = Format.fprintf fmt "%d:%a" v VarSet.pretty lset in
+    let pp_edge e =
+      let v1 = E.src e and v2 = E.dst e in
+      if !is_first then is_first := false else Format.fprintf fmt "@;<3>";
+      Format.fprintf fmt "@[%a@] %a→ @[%a@]"
+        (pp_node v1) (VMap.find v1 s.vmap)
+        E.pretty (E.label e)
+        (pp_node v2) (VMap.find v2 s.vmap)
+    in
+    let pp_unconnected_vertex v =
+      if G.in_degree s.graph v = 0 && G.out_degree s.graph v = 0 then begin
+        if !is_first then is_first := false else Format.fprintf fmt "@;<3>";
+        pp_node v fmt (VMap.find v s.vmap)
+      end
+    in
+    if G.nb_vertex s.graph = 0
+    then Format.fprintf fmt "<empty>"
+    else (G.iter_edges_e pp_edge s.graph;
+          G.iter_vertex pp_unconnected_vertex s.graph)
+
+  let pp_aliases fmt s =
+    let alias_set_of_vertex (i, _) =
+      let aliases = Readout.lvals_pointing_to_vertex i s in
+      if LSet.cardinal aliases >= 2 then Some aliases else None
+    in
+    let alias_sets = List.filter_map alias_set_of_vertex @@ VMap.bindings s.vmap in
+    Pretty_utils.pp_list ~empty:"<none>" ~sep:"@;<2>" LSet.pretty fmt alias_sets
+
+end
+
+(* invariants of type t must be true before and after each functon call *)
+let assert_invariants s : unit =
+  (* check that all vertex of the graph have entries in vmap,
+     and are integer between 0 and node_counter, and have at most 1 successor *)
+  assert (!node_counter >= 0);
+  let assert_vertex v =
+    Options.debug ~level:11 "checking coherence of vertex %d" v;
+    assert (v >= 0);
+    assert (v < !node_counter);
+    assert (VMap.mem v s.vmap);
+    let succ_e = G.succ_e s.graph v in
+    let is_pointer_vertex =
+      List.exists (fun e -> E.is_pointer @@ E.label e) succ_e
+    and is_struct_vertex =
+      List.exists (fun e -> E.is_field @@ E.label e) succ_e
+    in
+    assert (not (is_pointer_vertex && is_struct_vertex));
+    assert (not is_pointer_vertex || List.length (G.succ s.graph v) <= 1);
+  in
+  G.iter_vertex assert_vertex s.graph;
+  let assert_edge v1 v2 =
+    Options.debug ~level:11 "checking coherence of edge %d → %d" v1 v2;
+    if v1 = v2 then
+      Options.warning ~once:true ~wkey:Options.Warn.incoherent
+        "loop on vertex %d (following unsafe cast?); analysis may be unsound" v1;
+    assert (G.mem_vertex s.graph v1);
+    assert (G.mem_vertex s.graph v2)
+  in
+  G.iter_edges assert_edge s.graph;
+  let assert_varmap (var : varinfo) v =
+    assert (G.mem_vertex s.graph v);
+    assert (VarSet.mem var (VMap.find v s.vmap))
+  in
+  VarMap.iter assert_varmap s.varmap;
+  let assert_vmap v (ls:VarSet.t) =
+    assert (G.mem_vertex s.graph v);
+    (* TODO: we removed the invariant because of OSCS*)
+    (* if not (VarSet.is_empty ls)
+     * then
+     *   begin
+     *     let lv = VarSet.choose ls in
+     *     let is_ptr_lv = Lval.is_pointer lv in
+     *     assert (VarSet.for_all (fun x -> Lval.is_pointer x = is_ptr_lv) ls)
+     *   end; *)
+    assert (VarSet.fold (fun lv acc -> acc && V.equal (VarMap.find lv s.varmap) v) ls true)
+  in
+  VMap.iter assert_vmap s.vmap
+
+(* Ensure that assert_invariants is not executed if the -noassert flag is supplied. *)
+let assert_invariants s =
+  try assert (assert_invariants s; true)
+  with Assert_failure _ as exn ->
+    let bt = Printexc.get_raw_backtrace () in
+    Options.debug "incoherent graph:@ @[%a@]" Pretty.pp_debug s;
+    Options.debug "incoherent graph:@ @[%a@]" Pretty.pp_graph s;
+    Printexc.raise_with_backtrace exn bt
+
+let asserting_invariants s = assert_invariants s; s
+
+let pretty ?(debug = false) fmt s =
+  assert_invariants s;
+  if debug then Pretty.pp_graph fmt s
+  else Pretty.pp_aliases fmt s
+
+(* NOTE on "constant vertex": a constant vertex represents an unamed
+   scalar value (type bottom in steensgaard's paper), or the address
+   of a variable. It means that in [vmap], its associated VarSet is
+   empty.  By definition, constant vertex cannot be associated to a
+   lval in [varmap] *)
+let create_empty_vertex s : V.t * state =
+  let new_v = fresh_node_id () in
+  new_v, {graph = G.add_vertex s.graph new_v;
+          varmap = s.varmap;
+          vmap = VMap.add new_v VarSet.empty s.vmap}
+
+let create_var_vertex var s =
+  assert (not @@ VarMap.mem var s.varmap);
+  let v = fresh_node_id () in
+  let s = {graph = G.add_vertex s.graph v;
+           varmap = VarMap.add var v s.varmap;
+           vmap = VMap.add v (VarSet.singleton var) s.vmap} in
+  let rec create_typ_vertex s v ty = match ty with
+    | TArray (ty, _, _) | TPtr (ty, _) ->
+      (* create more vertices for each level of dereferentiation *)
+      let v', s = create_empty_vertex s in
+      let s = {s with graph = G.add_edge s.graph v v'} in
+      create_typ_vertex s v' ty
+    | _ -> s (* until the type becomes scalar *)
+  in
+  v, create_typ_vertex s v var.vtype
+
+let find_or_create_var_vertex (var : varinfo) s =
+  try VarMap.find var s.varmap, s
+  with Not_found -> create_var_vertex var s
+
+let rec find_or_create_lval_vertex ((lhost, offset) : lval) s : V.t * state =
+  let find_or_create_psucc v s =
+    match G.psucc_opt s.graph v with
+    | None ->
+      let v', s = create_empty_vertex s in
+      (* finally add a points-to edge between v and v' *)
+      let new_graph = G.add_edge s.graph v v' in
+      v', {s with graph = new_graph}
+    | Some v' -> v', s
+  in
+  let find_or_create_fsucc v s f =
+    match G.fsucc_opt s.graph v f with
+    | None ->
+      let v', s = create_empty_vertex s in
+      (* finally add a points-to edge between v and v' *)
+      let new_graph = G.add_edge_e s.graph @@ E.create v (Field f) v' in
+      v', {s with graph = new_graph}
+    | Some v' -> v', s
+  in
+  let find_or_create_lhost s = function
+    | Var var -> find_or_create_var_vertex var s
+    | Mem e ->
+      match LvalOrRef.from_exp e with
+      | None -> Options.fatal "unexpected result: Lval.from (%a) = None" Exp.pretty e
+      | Some (LvalOrRef.Ref lv1) -> find_or_create_lval_vertex lv1 s
+      | Some (LvalOrRef.Lval lv1) ->
+        let v1, s = find_or_create_lval_vertex lv1 s in
+        find_or_create_psucc v1 s
+  in
+  let rec find_or_create_offset v s = function
+    | NoOffset -> v, s
+    | Index (_, o) ->
+      let v', s = find_or_create_psucc v s in
+      find_or_create_offset v' s o
+    | Field (f, o) ->
+      let v', s = find_or_create_fsucc v s f in
+      find_or_create_offset v' s o
+  in
+  let hv, s = find_or_create_lhost s lhost in
+  let v, s = find_or_create_offset hv s offset in
+  Options.debug ~level:7 "graph after find_or_create_lval_vertex @[%a@] (%d):@ %a"
+    Printer.pp_lval (lhost, offset) v Pretty.pp_graph s;
+  v, s
+
+and find_or_create_ref_vertex lv s : V.t * state =
+  let v1, s = find_or_create_lval_vertex lv s in
+  let va, s = create_empty_vertex s in
+  let s = {s with graph = G.add_edge s.graph va v1} in
+  Options.debug ~level:7 "graph after find_or_create_ref_vertex @[%a@] (%d):@ %a"
+    LvalOrRef.pretty (LvalOrRef.Ref lv) va Pretty.pp_graph s;
+  va, s
+
+and find_or_create_lval_or_ref_vertex (lv : LvalOrRef.t) s : V.t * state =
+  match lv with
+  | LvalOrRef.Lval lv -> find_or_create_lval_vertex lv s
+  | LvalOrRef.Ref lv -> find_or_create_ref_vertex lv s
+
+(* TODO is there a better way to do it ? *)
+let find_vertex lv s =
+  let lv = Lval.simplify lv in
+  let v,x1 = find_or_create_lval_vertex lv s in
+  if s == x1
+  then v (* if s has not been modified, then the vertex was found, not created *)
+  else raise Not_found
+
+(* merge of two vertices; the first vertex carries both sets, the second is
+   removed from the graph and from varmap and vmap *)
+let merge s v1 v2 =
+  if V.equal v1 v2 || not (G.mem_vertex s.graph v1) || not (G.mem_vertex s.graph v2)
+  then s
+  else
+    (* update varmap : every lval in v2 must now be associated with v1 *)
+    let new_varmap = VarSet.fold (fun lv2 -> VarMap.add lv2 v1) (get_vars v2 s) s.varmap in
+    let new_vmap =
+      let new_set = VarSet.union (get_vars v1 s) (get_vars v2 s) in
+      VMap.add v1 new_set @@ VMap.remove v2 s.vmap
+    in
+    let new_graph = (* update the graph *)
+      let f_fold_succ e g : G.t =
+        G.add_edge_e g @@ E.create v1 (E.label e) (E.dst e)
+      and f_fold_pred e g : G.t =
+        G.add_edge_e g @@ E.create (E.src e) (E.label e) v1
+      in
+      let g = s.graph in
+      (* add all new edges *)
+      let g = G.fold_succ_e f_fold_succ g v2 g in
+      let g = G.fold_pred_e f_fold_pred g v2 g in
+      G.remove_vertex g v2 (* remove v2 *)
+    in
+    {graph = new_graph; varmap = new_varmap; vmap = new_vmap}
+
+(* functions join and unify-pointer of steensgaard's paper *)
+(* join_without_check may break the invariants *)
+let rec join_without_check s v1 v2 : state =
+  if V.equal v1 v2 || not (G.mem_vertex s.graph v1 && G.mem_vertex s.graph v2)
+  then s
+  else
+    let mk_edge_map succs =
+      let mk_succ e = E.label e, E.dst e in
+      E.Map.of_seq @@ Seq.map mk_succ @@ List.to_seq succs
+    in
+    let succs1 = mk_edge_map @@ G.succ_e s.graph v1 in
+    let succs2 = mk_edge_map @@ G.succ_e s.graph v2 in
+    let succ_pairs =
+      let mk_pair _ succ1 succ2 = match succ1, succ2 with
+        | Some s1, Some s2 -> Some (s1, s2)
+        | _ -> None
+      in
+      E.Map.merge mk_pair succs1 succs2
+    in
+    let s = merge s v1 v2 in
+    assert (not (G.mem_vertex s.graph v2));
+    let merge_succs _ (succ1, succ2) s =
+      assert (succ1 <> v2);
+      assert (succ2 <> v1);
+      join_without_check s succ1 succ2
+    in
+    E.Map.fold merge_succs succ_pairs s
+
+let join s v1 v2 : state =
+  Options.debug ~level:6 "graph before join(%d,%d):@;<2>@[%a@]" v1 v2 Pretty.pp_graph s;
+  assert_invariants s;
+  let res = join_without_check s v1 v2 in
+  Options.debug ~level:6 "graph after join(%d,%d):@;<2>@[%a@]" v1 v2 Pretty.pp_graph res;
+  begin try assert_invariants res
+    with Assert_failure _ ->
+      Options.debug "join(%d,%d) failed" v1 v2;
+      Options.debug "graph before join(%d,%d):@;<2>@[%a@]" v1 v2 Pretty.pp_debug s;
+      Options.debug "graph after join(%d,%d):@;<2>@[ %a@]" v1 v2 Pretty.pp_debug res;
+      assert_invariants res
+  end;
+  res
+
+let merge_set s (vs:VSet.t) : V.t * state =
+  let v0 = VSet.choose vs in
+  if VSet.cardinal vs < 2 then v0, s else begin
+    Options.debug ~level:6 "graph before merge_set %a:@;<2>@[%a@]"
+      VSet.pretty vs Pretty.pp_debug s;
+    assert (G.mem_vertex s.graph v0);
+    let result = VSet.fold (fun v acc -> merge acc v0 v) vs s in
+    Options.debug ~level:6 "graph after merge_set %a:@;<2>@[%a@]"
+      VSet.pretty vs Pretty.pp_debug result;
+    v0, result
+  end
+
+(* may operate on an unsound state, where nodes may have multiple successors
+   of the same edge type *)
+let rec join_succs s v =
+  Options.debug ~level:8 "joining successors of %d" v;
+  if not @@ G.mem_vertex s.graph v then s else
+    let edge_map =
+      List.fold_left (fun m e ->
+          let add_dst = function
+            | None -> Some (VSet.singleton @@ E.dst e)
+            | Some vs -> Some (VSet.add (E.dst e) vs)
+          in
+          E.Map.update (E.label e) add_dst m
+        )
+        E.Map.empty
+        (G.succ_e s.graph v)
+    in
+    let merge_vset _e vs s =
+      if VSet.cardinal vs < 2
+      then s
+      else let v0, s = merge_set s vs in join_succs s v0
+    in
+    E.Map.fold merge_vset edge_map s
+
+(* in Steensgard's paper, this is written settype(v1,ref(v2,bot)) *)
+let set_type s v1 v2 : state =
+  assert_invariants s;
+  (* if v1 points to another node, suppress current outgoing edge (and the node if it is a constant node) *)
+  let g, new_vmap =
+    match G.psucc_opt s.graph v1 with
+    | None -> s.graph, s.vmap
+    | Some v2 ->
+      (* if v2 is a constant node supress it directly *)
+      if VarSet.is_empty (VMap.find v2 s.vmap)
+      then G.remove_vertex s.graph v2, VMap.remove v2 s.vmap
+      else G.remove_edge s.graph v1 v2, s.vmap
+  in
+  let new_g = G.add_edge g v1 v2 in
+  asserting_invariants {s with graph = new_g; vmap = new_vmap}
+
+let assignment s lv (e:exp) : state =
+  assert_invariants s;
+  match Cil.isPointerType (Cil.typeOf e), LvalOrRef.from_exp e with
+  | false, _ | _, None -> s
+  | true, Some y ->
+    let v1, s = find_or_create_lval_vertex (Lval.simplify lv) s in
+    let v2, s = find_or_create_lval_or_ref_vertex y s in
+    if List.mem v2 (G.psucc s.graph v1) || List.mem v1 (G.psucc s.graph v2)
+    then
+      let () =
+        Options.warning ~source:(fst e.eloc)
+          "ignoring assignment of the form: %a = %a"
+          Printer.pp_lval lv Printer.pp_exp e;
+      in s
+    else asserting_invariants @@ join s v1 v2
+
+(* assignment x = allocate(y) *)
+let assignment_x_allocate_y s lv : state =
+  assert_invariants s;
+  let v1, s = find_or_create_lval_vertex (Lval.simplify lv) s in
+  match G.psucc_opt s.graph v1 with
+  | None ->
+    let v2, s = create_empty_vertex s in
+    set_type s v1 v2
+  | Some _ -> s
+
+let is_included s s' =
+  (* tests if s is included in s', at least as the nodes with lval *)
+  assert_invariants s;
+  assert_invariants s';
+  Options.debug ~level:8 "testing equal %a AND à.%a"
+    Pretty.pp_graph s (pretty ~debug:true) s';
+  let exception Not_included in
+  try
+    let iter_varmap (var : varinfo) v : unit =
+      let v' = try VarMap.find var s'.varmap with Not_found -> raise Not_included in
+      (* TODO: render correct for structs *)
+      let succs =
+        E.Map.of_seq @@ Seq.map (fun e -> E.label e, E.dst e) @@ List.to_seq @@ G.succ_e s.graph v
+      and succs' =
+        E.Map.of_seq @@ Seq.map (fun e -> E.label e, E.dst e) @@ List.to_seq @@ G.succ_e s'.graph v'
+      in
+      let check_succs _ succ1 succ2 = match succ1, succ2 with
+        | None, _ -> None
+        | Some _, None -> raise Not_included
+        | Some v1p, Some v2p ->
+          if VarSet.subset (VMap.find v1p s.vmap) (VMap.find v2p s'.vmap)
+          then None
+          else raise Not_included
+      in
+      ignore @@ E.Map.merge check_succs succs succs'
+    in
+    VarMap.iter iter_varmap s.varmap; true
+  with Not_included -> false
+
+let empty : state = {graph = G.empty; varmap = VarMap.empty; vmap = VMap.empty}
+
+let is_empty s = compare s empty = 0
+
+(* add an int to all vertex values *)
+let shift s : state =
+  assert_invariants s;
+  if is_empty s then s else begin
+    Options.debug ~level:8 "before shift: node_counter=%d@.%a"
+      !node_counter Pretty.pp_debug s;
+    let max_idx = G.fold_vertex max s.graph 0 in
+    let min_idx = G.fold_vertex min s.graph max_idx in
+    let offset = !node_counter - min_idx in
+    let shift x = x + offset in
+    let shift_vmap shift_elem vmap =
+      VMap.of_seq @@ Stdlib.Seq.map shift_elem @@ VMap.to_seq vmap
+    in
+    let {graph; varmap; vmap} = s in
+    node_counter := max_idx + offset + 1;
+    let result =
+      {graph = G.map_vertex shift graph;
+       varmap = VarMap.map shift varmap;
+       vmap = shift_vmap (fun (key, l) -> shift key, l) vmap}
+    in
+    Options.debug ~level:8 "after shift: node_counter=%d@.%a"
+      !node_counter Pretty.pp_debug result;
+    asserting_invariants result
+  end
+
+let union_find vmap intersections =
+  let module Store : UnionFind.STORE = UnionFind.StoreMap.Make (VMap) in
+  let module UF = UnionFind.Make (Store) in
+  let uf = UF.new_store () in
+  let refs = VMap.mapi (fun i _ -> UF.make uf i) vmap in
+  let put_into_uf (v1,v2) =
+    let r1 = VMap.find v1 refs in
+    let r2 = VMap.find v2 refs in
+    ignore @@ UF.union uf r1 r2
+  in
+  let _vs = Seq.iter put_into_uf intersections in
+  let sets_to_be_joined =
+    let add_to_map i r sets =
+      let repr = UF.find uf r in
+      let add_to_set = function
+        | None -> Some (VSet.singleton i)
+        | Some set -> Some (VSet.add i set)
+      in
+      VMap.update (UF.get uf repr) add_to_set sets
+    in
+    VMap.fold add_to_map refs VMap.empty in
+  sets_to_be_joined
+
+let union s1 s2 : state =
+  assert_invariants s1;
+  assert_invariants s2;
+
+  Options.debug ~level:4 "Union: First graph:%a" Pretty.pp_graph s1;
+  Options.debug ~level:5 "Union: First graph:%a" Pretty.pp_debug s1;
+  Options.debug ~level:4 "Union: Second graph:%a" Pretty.pp_graph s2;
+  Options.debug ~level:5 "Union: Second graph:%a" Pretty.pp_debug s2;
+  let new_graph =
+    G.fold_vertex
+      (fun v2 g -> G.add_vertex g v2)
+      s2.graph
+      s1.graph
+  in
+  let new_graph =
+    G.fold_edges_e (fun e g -> G.add_edge_e g e) s2.graph new_graph
+  in
+  let new_vmap =
+    VMap.union (fun _ lset1 lset2 -> Option.some @@ VarSet.union lset1 lset2)
+      s2.vmap
+      s1.vmap
+  in
+  let sets_to_be_joined =
+    let intersections = VarMap.to_seq @@ VarMap.intersect s1.varmap s2.varmap in
+    union_find new_vmap @@ Seq.map snd intersections
+  in
+  let new_varmap = VarMap.union (fun _ l _r -> Some l) s1.varmap s2.varmap in
+  Options.debug ~level:7 "Union: sets to be joined:@[";
+  VMap.iter (fun _ set -> Options.debug ~level:7 "%a" VSet.pretty set) sets_to_be_joined;
+  Options.debug ~level:7 "@]";
+  let s = {graph = new_graph; varmap = new_varmap; vmap = new_vmap} in
+  let merged_nodes, s =
+    VMap.fold
+      (fun _ set (merged_nodes, s) -> let v0, s = merge_set s set in (v0 :: merged_nodes), s)
+      sets_to_be_joined
+      ([], s)
+  in
+  let s = List.fold_left join_succs s merged_nodes in
+  Options.debug ~level:4 "Union: Result graph:%a" Pretty.pp_graph s;
+  Options.debug ~level:5 "Union: Result graph:%a" Pretty.pp_debug s;
+  begin try assert_invariants s
+    with Assert_failure _ ->
+      Options.debug "union failed";
+      Options.debug "Union: First graph:%a" Pretty.pp_graph s1;
+      Options.debug "Union: First graph:%a" Pretty.pp_debug s1;
+      Options.debug "Union: Second graph:%a" Pretty.pp_graph s2;
+      Options.debug "Union: Second graph:%a" Pretty.pp_debug s2;
+      Options.debug "Union: Result graph:%a" Pretty.pp_graph s;
+      Options.debug "Union: Result graph:%a" Pretty.pp_debug s;
+      assert_invariants s
+  end;
+  s
+
+
+module Summary = struct
+  (* a type for summaries of functions *)
+  type t = {state   : state option;
+            formals : lval list;
+            return  : exp option}
+
+  let make s (kf : kernel_function) =
+    let exp_return : exp option =
+      if Kernel_function.has_definition kf then
+        let return_stmt = Kernel_function.find_return kf in
+        match return_stmt.skind with
+        | Return (e, _) -> e
+        | _ -> Options.fatal "this should not happen"
+      else None
+    in
+    let s =
+      match exp_return with
+      | None -> s
+      | Some e ->
+        begin match s, LvalOrRef.from_exp e with
+          | _, None -> s
+          | s, Some lv ->
+            let _, new_s = find_or_create_lval_or_ref_vertex lv s in
+            new_s
+        end
+    in
+    {state = Some s;
+     formals = List.map (fun v -> (Var v,NoOffset)) (Kernel_function.get_formals kf);
+     return = exp_return}
+
+  let pretty ?(debug=false) fmt summary =
+    let pp_list_lval s fmt (l: lval list) =
+      let is_first = ref true in
+      let pp_elem lv =
+        if !is_first then is_first := false else Format.fprintf fmt "@  ";
+        Format.fprintf fmt "@[%a" Cil_datatype.Lval.pretty lv;
+        let pointees = Readout.points_to_vars lv s in
+        if not @@ VarSet.is_empty pointees then
+          Format.fprintf fmt "→%a" VarSet.pretty pointees;
+        Format.fprintf fmt "@]";
+      in
+      List.iter pp_elem l
+    in
+    let pp_option pp fmt = function
+      | Some x -> pp fmt x
+      | None -> Format.fprintf fmt "<none>"
+    in
+    match summary.state with
+    | None -> if debug then Format.fprintf fmt "not found"
+    | Some s when is_empty s -> if debug then Format.fprintf fmt "empty"
+    | Some s ->
+      Format.fprintf fmt "@[formals: @[%a@]@;<4>returns: @[%a@]@;<4>state: @[%a@] "
+        (pp_list_lval s) summary.formals
+        (pp_option Exp.pretty) summary.return
+        (pp_option @@ pretty ~debug) summary.state
+
+end
+
+(* the algorithm:
+   - unify the two graphs dropping all the variables from the summary
+   - pair arguments with formals assigning the formal's successor as the argument's successor
+*)
+let call s (res : lval option) (args : exp list) (summary : Summary.t) : state =
+  assert_invariants s;
+  let formals = summary.Summary.formals in
+  assert (List.length args = List.length formals);
+  let sum_state = shift @@ Option.get summary.state in
+
+  (* pair up formals and their corresponding arguments,
+     as well as the bound result with the returned value *)
+  let arg_formal_pairs =
+    let res_ret = match res, summary.return with
+      | None, None -> []
+      | Some res, Some ret ->
+        let simplify_ret x = match LvalOrRef.from_exp x with
+          | Some (LvalOrRef.Lval lval) -> lval
+          | _ -> Options.fatal "unexpected form of return statement"
+        in
+        [LvalOrRef.Lval (Lval.simplify res), simplify_ret ret]
+      | None, Some _ -> []
+      | Some _, None -> (* Shouldn't happen: Frama-C adds missing returns *)
+        Options.fatal "unexpected case: result without return"
+    in
+    let simplify_both (arg, formal) =
+      try
+        match LvalOrRef.from_exp arg with
+        | None -> None
+        | Some lv -> Some (lv, Lval.simplify formal)
+      with Explicit_pointer_address loc ->
+        Options.warning ~source:(fst loc) ~wkey:Options.Warn.unsupported_address
+          "unsupported feature: explicit pointer address: %a; analysis may be unsound"
+          Printer.pp_exp arg;
+        None
+    in
+    res_ret @ List.filter_map simplify_both @@ List.combine args formals
+  in
+
+  (* for each pair (lv1,lv2) find (or create) the corresponding vertices *)
+  let s, vertex_pairs =
+    let s = ref s in
+    let find_vertex (lv1, lv2) =
+      try
+        let v2 = find_lval_vertex lv2 sum_state in
+        let v1, new_state = find_or_create_lval_or_ref_vertex lv1 !s in
+        s := new_state;
+        Some (v1, v2)
+      with Not_found -> None
+    in
+    !s, List.filter_map find_vertex arg_formal_pairs
+  in
+
+  (* merge the function graph;
+     for every arg/formal vertex pair (v1,v2) and every edge v2→v create edge v1→v. *)
+  let g =
+    let transfer_succs g (v1,v2) =
+      List.fold_left
+        (fun g e -> G.add_edge_e g @@ E.create v1 (E.label e) (E.dst e))
+        g
+        (G.succ_e sum_state.graph v2)
+    in
+    let g = s.graph in
+    let g = G.fold_vertex (fun i g -> G.add_vertex g i) sum_state.graph g in
+    let g = G.fold_edges_e (fun e g -> G.add_edge_e g e) sum_state.graph g in
+    List.fold_left transfer_succs g vertex_pairs
+  in
+
+  (* garbage collect: remove leaf vertices from g that originate from sum_state *)
+  let vertices_to_add_to_g, g =
+    let g = ref g in
+    let remove_if_leaf v _ =
+      if G.in_degree !g v = 0
+      then let () = g := G.remove_vertex !g v in None
+      else Some VarSet.empty
+    in
+    let remaining_vertices = VMap.filter_map remove_if_leaf sum_state.vmap in
+    remaining_vertices, !g
+  in
+
+  let s = {
+    graph = g;
+    varmap = s.varmap;
+    vmap =
+      let left_bias _ l _ = Some l in
+      VMap.union left_bias s.vmap vertices_to_add_to_g}
+  in
+
+  asserting_invariants
+    (List.fold_left join_succs s @@ List.map fst vertex_pairs)
+
+module Dot = struct
+  let find_vars_ref = Extlib.mk_fun "find_vars"
+
+  include Graph.Graphviz.Dot (struct
+      include G
+      let edge_attributes _ = []
+      let default_edge_attributes _ = []
+      let get_subgraph _ = None
+      let vertex_attributes v =
+        let lset = !find_vars_ref v in
+        let label =
+          VarSet.pretty Format.str_formatter lset;
+          Format.flush_str_formatter ()
+        in
+        [`Label label]
+
+      let vertex_name v = string_of_int v
+      let default_vertex_attributes _ = [`Shape `Box]
+      let graph_attributes _ = []
+    end)
+end
+
+module API = struct
+  type t = state
+
+  type summary = Summary.t
+
+  let pretty_summary = Summary.pretty
+
+  let make_summary = Summary.make
+
+  let vid v : int = v
+
+  let rec closure_find_lset v s : (V.t * LSet.t) list =
+    match G.psucc_opt s.graph v with
+    | None -> [v, Readout.get_lval_set v s]
+    | Some v_next -> (v, Readout.get_lval_set v s) :: closure_find_lset v_next s
+
+  let find_transitive_closure lv s : (V.t * LSet.t) list =
+    let lv = Lval.simplify lv in
+    assert_invariants s;
+    try closure_find_lset (find_lval_vertex lv s) s with Not_found -> []
+  (* TODO : what about offsets ? *)
+
+  let get_lval_set = Readout.get_lval_set
+  let find_vars = Readout.find_vars
+  let find_synonyms = Readout.find_synonyms
+  let find_aliases = Readout.find_synonyms
+  let alias_vars = Readout.alias_vars
+  let find_all_aliases = Readout.find_all_aliases
+  let points_to_vars = Readout.points_to_vars
+  let points_to_set = Readout.points_to_lvals
+  let points_to_lvals = Readout.points_to_lvals
+
+  let get_graph s = s.graph
+
+  let print_dot filename s =
+    let file = open_out filename in
+    Dot.find_vars_ref := (fun v -> get_vars v s);
+    Dot.output_graph file s.graph;
+    close_out file
+end
+
+include API
diff --git a/src/plugins/alias/abstract_state.mli b/src/plugins/alias/src/abstract_state.mli
similarity index 63%
rename from src/plugins/alias/abstract_state.mli
rename to src/plugins/alias/src/abstract_state.mli
index cf4e8fe939f894e20e09be52da7555f00d219299..69f194b08d12d2f779f4e5b61bd81d32440b0a92 100644
--- a/src/plugins/alias/abstract_state.mli
+++ b/src/plugins/alias/src/abstract_state.mli
@@ -20,71 +20,60 @@
 (*                                                                        *)
 (**************************************************************************)
 
-(** Module abstract_state *)
+(** Module Abstract_state *)
+
+(** see API.Abstract_state for documentation *)
 
 open Cil_types
 
-(** Points-to graphs datastructure. *)
-module G: Graph.Sig.G with type V.t = int
+module EdgeLabel : sig
+  type t = Pointer | Field of fieldinfo
+
+  val compare : t -> t -> int
+  val default : t
+  val is_pointer : t -> bool
+  val is_field : t -> bool
+  val pretty : Format.formatter -> t -> unit
+end
+
+module G: Graph.Sig.G with type V.t = int and type E.t = int * EdgeLabel.t * int
 
 module LSet = Cil_datatype.LvalStructEq.Set
-module LMap = Cil_datatype.LvalStructEq.Map
+module VarSet = Cil_datatype.Varinfo.Set
 
-(** Type denothing an abstract state of the analysis. It is a graph containing
-    all aliases and points-to information. *)
 type t
+type v = G.V.t
 
-val vid : G.V.t -> int
-
-(** access to the points-to graph *)
+val vid : v -> int
 val get_graph: t -> G.t
-
-(** set of lvals stored in a vertex *)
-val get_lval_set : G.V.t -> t -> LSet.t
-
-(** pretty printer; debug=true prints the graph, debug = false only
-    prints aliased variables *)
+val get_vars : v -> t -> VarSet.t
+val get_lval_set : v -> t -> LSet.t
 val pretty : ?debug:bool -> Format.formatter -> t -> unit
-
-(** dot printer; first argument is a file name *)
 val print_dot : string -> t -> unit
+val find_vertex : lval -> t -> v
+val find_vars : lval -> t -> VarSet.t
+val find_synonyms : lval -> t -> LSet.t
 
-(** finds the vertex corresponding to a lval.
-    @raise Not_found if such a vertex does not exist
-*)
-val find_vertex : lval -> t -> G.V.t
-
-(** same as previous function, but return a set of lval. Cannot
-    raise an exception but may return an empty set if the lval is not
-    in the graph *)
 val find_aliases : lval -> t -> LSet.t
+[@@alert deprecated "Use find_synonyms or find_all_aliases instead!"]
 
-(** similar to the previous functions, but does not only give the
-    equivalence class of lv, but also all lv that are aliases in
-    other vertex of the graph *)
+val alias_vars : lval -> t -> VarSet.t
 val find_all_aliases : lval -> t -> LSet.t
+val points_to_vars : lval -> t -> VarSet.t
+val points_to_lvals : lval -> t -> LSet.t
 
-(** the set of all lvars to which the given variable may point. *)
 val points_to_set : lval -> t -> LSet.t
+[@@alert deprecated "Use points_to_vars or points_to_lvals instead!"]
 
-(** find_aliases, then recursively finds other sets of lvals. We
-    have the property (if lval [lv] is in abstract state [x]) :
-    List.hd (find_transitive_closure lv x) = (find_vertex lv x,
-    find_aliases lv x) *)
-val find_transitive_closure : lval -> t -> (G.V.t * LSet.t) list
-
-(** inclusion test; [is_included a1 a2] tests if, for any lvl
-    present in a1 (associated to a vertex v1), that it is also
-    present in a2 (associated to a vertex v2) and that
-    get_lval_set(succ(v1) is included in get_lval_set(succ(v2)) *)
+val find_transitive_closure : lval -> t -> (v * LSet.t) list
 val is_included : t -> t -> bool
 
 (** check all the invariants that must be true on an abstract value
-      before and after each function call or transformation of the graph)  *)
+    before and after each function call or transformation of the graph) *)
 val assert_invariants : t -> unit
 
 (** Functions for Steensgaard's algorithm, see the paper *)
-val join : t -> G.V.t -> G.V.t -> t
+val join : t -> v -> v -> t
 
 (** transfert functions for different kinds of assignments *)
 val assignment : t -> lval -> exp -> t
diff --git a/src/plugins/alias/analysis.ml b/src/plugins/alias/src/analysis.ml
similarity index 71%
rename from src/plugins/alias/analysis.ml
rename to src/plugins/alias/src/analysis.ml
index 148dabcd63c02521a4a2059b661b4b21af6b5c60..39dd741625663e0b3e659e708d3bdc470c314a18 100644
--- a/src/plugins/alias/analysis.ml
+++ b/src/plugins/alias/src/analysis.ml
@@ -90,10 +90,9 @@ let do_function_call (stmt:stmt) state (res : lval option) (ef : exp) (args: exp
   in
   match ef with
   | {enode=Lval (Var v, _);_}  when is_malloc v.vname ->
-    begin
-      (* special case for malloc *)
-      match (state,res) with
-        (None, _) -> None
+    (* special case for malloc *)
+    begin match (state, res) with
+      | (None, _) -> None
       | (Some a, None) -> (Options.warning "Memory allocation not stored (ignored)"; Some a)
       | (Some a, Some lv) ->
         try Some (Abstract_state.assignment_x_allocate_y a lv)
@@ -101,43 +100,50 @@ let do_function_call (stmt:stmt) state (res : lval option) (ef : exp) (args: exp
           warn_unsupported_explicit_pointer Printer.pp_stmt stmt loc;
           Some a
     end
-  | _ ->
-    begin
-      (* general case *)
-      let summary =
-        match Kernel_function.get_called ef with
-        | Some kf when Kernel_function.is_main kf -> None
-        | Some kf -> begin
-            try Function_table.find kf
-            with Not_found -> doFunction kf
-          end
-        | None ->
-          Options.warning ~wkey:Options.Warn.unsupported_function ~source:(fst loc)
-            "unsupported feature: call to function pointer: %a" Exp.pretty ef;
-          None
-      in
+  | _ -> (* general case *)
+    let get_function kf = try Function_table.find kf with Not_found -> doFunction kf in
+    let summaries =
+      match Kernel_function.get_called ef with
+      | Some kf when Kernel_function.is_main kf -> []
+      | Some kf -> [get_function kf]
+      | None -> (* dereference function pointer using the results of the points-to analysis *)
+        begin match ef, Stmt_table.find stmt with
+          | {enode = Lval lv; _}, Some state ->
+            let targets = Abstract_state.find_vars lv state in
+            Options.feedback ~level:3 "%a is an indirect function call to one of %a"
+              Printer.pp_stmt stmt
+              Abstract_state.VarSet.pretty targets;
+            let kf_of_var {vname; _} =
+              try Some (Globals.Functions.find_def_by_name vname) with Not_found -> None
+            in
+            let kfs = Seq.filter_map kf_of_var @@ Abstract_state.VarSet.to_seq targets in
+            List.of_seq @@ Seq.map get_function kfs
+          | _ ->
+            Options.fatal "unsupported call to function pointer: %a" Exp.pretty ef
+        end
+    in
+    let apply_summary state summary =
       match (state, summary) with
-        (None, _) -> None
-      | (Some a, Some summary) ->
-        Some (Abstract_state.call a res args summary)
+      | (None, _) -> None
+      | (Some a, Some summary) -> Some (Abstract_state.call a res args summary)
       | (Some a, None) ->
         Options.warning ~wkey:Options.Warn.undefined_function ~once:true ~source:(fst loc)
           "function %a has no definition" Exp.pretty ef;
         Some a
-    end
+    in
+    List.fold_left apply_summary state summaries
 
 let do_cons_init (s:stmt) (v:varinfo) f arg t loc state =
   Cil.treat_constructor_as_func (do_function_call s state) v f arg t loc
 
-let analyse_instr (s:stmt)  (i:instr) (a:Abstract_state.t option) : Abstract_state.t option =
+let analyse_instr (s:stmt) (i:instr) (a:Abstract_state.t option) : Abstract_state.t option =
   match i with
-    Set (lv,exp,_) -> Option.map (do_assignment lv exp) a
+  | Set (lv,exp,_) -> Option.map (do_assignment lv exp) a
   | Local_init (v,AssignInit i,_) -> do_init (Var v, NoOffset) i a
   | Local_init (v,ConsInit (f,arg,t),loc) -> do_cons_init s v f arg t loc a
   | Code_annot _ -> a
   | Skip _ -> a
-  | Call (res,ef,es,loc) -> (* !function_compute_ref ef *)
-    do_function_call s a res ef es loc
+  | Call (res,ef,es,loc) -> do_function_call s a res ef es loc
   | Asm (_,_,_,loc) ->
     Options.warning
       ~source:(fst loc) ~wkey:Options.Warn.unsupported_asm
@@ -149,7 +155,7 @@ let pp_abstract_state_opt ?(debug=false) fmt v =
   | None -> Format.fprintf fmt "⊥"
   | Some a -> Abstract_state.pretty ~debug fmt a
 
-let do_instr (s:stmt)  (i:instr) (a:Abstract_state.t option) : Abstract_state.t option =
+let do_instr (s:stmt) (i:instr) (a:Abstract_state.t option) : Abstract_state.t option =
   Options.feedback ~level:3 "@[analysing instruction:@ %a@]" Printer.pp_stmt s;
   let result = analyse_instr s i a in
   Options.feedback ~level:3 "@[May-aliases after instruction@;<2>@[%a@]@;<2>are@;<2>@[%a@]@]"
@@ -171,7 +177,7 @@ module T = struct
 
   let pretty fmt a =
     match a with
-      None -> Format.fprintf fmt "<No abstract state>"
+    | None -> Format.fprintf fmt "<No abstract state>"
     | Some a -> Abstract_state.pretty fmt a
 
   let computeFirstPredecessor _ a = a
@@ -188,8 +194,7 @@ module T = struct
 
   let doInstr = do_instr
 
-  let doGuard _ _ a =
-    Dataflow.GUse a, Dataflow.GUse a
+  let doGuard _ _ a = Dataflow.GUse a, Dataflow.GUse a
 
   let doStmt _ _ = Dataflow.SDefault
 
@@ -200,51 +205,47 @@ module F = Dataflow.Forwards (T)
 
 let do_stmt (a: Abstract_state.t) (s:stmt) :  Abstract_state.t =
   match s.skind with
-    Instr i ->
-    begin
-      match do_instr s i (Some a) with
-        None -> Options.fatal "problem here"
+  | Instr i ->
+    begin match do_instr s i (Some a) with
+      | None -> Options.fatal "problem here"
       | Some a -> a
     end
   | _ -> a
 
 let analyse_function (kf:kernel_function) =
-  Options.feedback ~level:2 "analysing function: %a" Kernel_function.pretty kf;
-  if Kernel_function.has_definition kf then
-    begin
-      let first_stmt =
-        try Kernel_function.find_first_stmt kf
-        with Kernel_function.No_Statement -> assert false
-      in
-      T.StmtStartData.add first_stmt (Some Abstract_state.empty);
-      F.compute [first_stmt];
-      let return_stmt = Kernel_function.find_return kf in
-      try Stmt_table.find return_stmt
-      with Not_found ->
-        begin
-          let source, _ = Kernel_function.get_location kf in
-          Options.warning ~source ~wkey:Options.Warn.no_return_stmt
-            "function %a does not return; analysis may be unsound"
-            Kernel_function.pretty kf;
-          Some Abstract_state.empty
-        end
-    end
-  else
-    None
+  if not @@ Kernel_function.has_definition kf then None else begin
+    Options.feedback ~level:2 "analysing function: %a" Kernel_function.pretty kf;
+    let first_stmt =
+      try Kernel_function.find_first_stmt kf
+      with Kernel_function.No_Statement -> assert false
+    in
+    T.StmtStartData.add first_stmt (Some Abstract_state.empty);
+    F.compute [first_stmt];
+    let return_stmt = Kernel_function.find_return kf in
+    try Stmt_table.find return_stmt
+    with Not_found ->
+      let source, _ = Kernel_function.get_location kf in
+      Options.warning ~source ~wkey:Options.Warn.no_return_stmt
+        "function %a does not return; analysis may be unsound"
+        Kernel_function.pretty kf;
+      Some Abstract_state.empty
+  end
 
 let doFunction (kf:kernel_function) =
   let final_state = analyse_function kf in
   let level = if Kernel_function.is_main kf then 1 else 2 in
-  Options.feedback ~level "@[May-aliases at the end of function %a:@ @[%a@]"
-    Kernel_function.pretty kf
-    (pp_abstract_state_opt ~debug:false) final_state;
-  Options.debug ~level "May-alias graph at the end of function %a:@;<4>@[%a@]"
-    Kernel_function.pretty kf
-    (pp_abstract_state_opt ~debug:true) final_state;
+  final_state |> Option.iter (fun s ->
+      Options.feedback ~level "@[May-aliases at the end of function %a:@ @[%a@]"
+        Kernel_function.pretty kf
+        (Abstract_state.pretty ~debug:false) s;
+      Options.debug ~level "May-alias graph at the end of function %a:@;<4>@[%a@]"
+        Kernel_function.pretty kf
+        (Abstract_state.pretty ~debug:true)s;
+    );
   let result =
     match final_state with
     (* final state is None if kf has no definition *)
-      None -> None
+    | None -> None
     | Some fs ->
       let summary = Abstract_state.make_summary fs kf in
       Options.debug ~level:2 "Summary of function %a:@ @[%a@]"
@@ -264,17 +265,13 @@ let doFunction (kf:kernel_function) =
 let () = function_compute_ref := doFunction
 
 let make_summary (state:Abstract_state.t) (kf:kernel_function) =
-  try
-    begin
-      match Function_table.find kf with
-        Some s -> (state, s)
-      | None -> Options.fatal "not implemented"
-    end
-  with
-    Not_found ->
-    begin
-      match doFunction kf with
-        Some s -> (state, s)
+  try begin match Function_table.find kf with
+    | Some s -> (state, s)
+    | None -> Options.fatal "not implemented"
+  end
+  with Not_found ->
+    begin match doFunction kf with
+      | Some s -> (state, s)
       | None -> Options.fatal "not implemented"
     end
 
@@ -313,18 +310,12 @@ let clear () =
   computed_flag := false;
   Stmt_table.clear ()
 
-let get_state_before_stmt _kf stmt =
+let get_state_before_stmt stmt =
   if is_computed ()
-  then
-    try Stmt_table.find stmt with
-      Not_found -> None
-  else
-    None
+  then try Stmt_table.find stmt with Not_found -> None
+  else None
 
 let get_summary kf =
   if is_computed ()
-  then
-    try Function_table.find kf with
-      Not_found -> None
-  else
-    None
+  then try Function_table.find kf with Not_found -> None
+  else None
diff --git a/src/plugins/alias/analysis.mli b/src/plugins/alias/src/analysis.mli
similarity index 97%
rename from src/plugins/alias/analysis.mli
rename to src/plugins/alias/src/analysis.mli
index f1bb2652e88fdb27f7c590589b3dcfb6a252438b..2b8353181ca9d43edb8ff1c3a8e65413fabd9ee3 100644
--- a/src/plugins/alias/analysis.mli
+++ b/src/plugins/alias/src/analysis.mli
@@ -62,7 +62,7 @@ val is_computed : unit -> bool
 val clear : unit -> unit
 
 (** see API.mli *)
-val get_state_before_stmt :  kernel_function -> stmt -> Abstract_state.t option
+val get_state_before_stmt : stmt -> Abstract_state.t option
 
 (** see API.mli *)
 val get_summary : kernel_function -> Abstract_state.summary option
diff --git a/src/plugins/alias/dune b/src/plugins/alias/src/dune
similarity index 98%
rename from src/plugins/alias/dune
rename to src/plugins/alias/src/dune
index 480ffb1277133e4926f5ed26129715b08d444246..a80c5018589cb73e8d1bd3b80181cbcf540b5d55 100644
--- a/src/plugins/alias/dune
+++ b/src/plugins/alias/src/dune
@@ -30,6 +30,8 @@
   )
 )
 
+(env (release (flags -noassert)))
+
 ( library
   (name Alias)
   (public_name frama-c-alias.core)
diff --git a/src/plugins/alias/options.ml b/src/plugins/alias/src/options.ml
similarity index 98%
rename from src/plugins/alias/options.ml
rename to src/plugins/alias/src/options.ml
index 7c57801673f809e66add699feacd0ff7595c1bc4..ef9f63fa9464a7ed8aa9d50a17319cacc3723665 100644
--- a/src/plugins/alias/options.ml
+++ b/src/plugins/alias/src/options.ml
@@ -72,6 +72,7 @@ module Warn = struct
   let unsupported_asm = register_warn_category "unsupported:asm"
   let unsupported_function = register_warn_category "unsupported:fn"
   let unsafe_cast = register_warn_category "unsafe-cast"
+  let incoherent = register_warn_category "incoherent"
 end
 
 module DebugKeys = struct
diff --git a/src/plugins/alias/options.mli b/src/plugins/alias/src/options.mli
similarity index 98%
rename from src/plugins/alias/options.mli
rename to src/plugins/alias/src/options.mli
index bfe5800b537c1a318d743ab9f19ba389a1031700..603c67bcb21e5ee8e0be6001c2b7e4179fb6a9c6 100644
--- a/src/plugins/alias/options.mli
+++ b/src/plugins/alias/src/options.mli
@@ -48,6 +48,7 @@ module Warn : sig
   val unsupported_asm : warn_category
   val unsupported_function : warn_category
   val unsafe_cast : warn_category
+  val incoherent : warn_category
 end
 
 module DebugKeys : sig
diff --git a/src/plugins/alias/simplified.ml b/src/plugins/alias/src/simplified.ml
similarity index 74%
rename from src/plugins/alias/simplified.ml
rename to src/plugins/alias/src/simplified.ml
index 95d0f57925464ef1d49de7e43776e03b9690c4b6..f9722a3a84153361f7f8a6cb10121d50feabef65 100644
--- a/src/plugins/alias/simplified.ml
+++ b/src/plugins/alias/src/simplified.ml
@@ -23,7 +23,7 @@
 open Cil_types
 open Cil_datatype
 
-let nul_exp= Cil.kinteger64 ~loc:Location.unknown ~repr:"0.." ~kind:IInt Integer.zero
+let nul_exp = Cil.kinteger64 ~loc:Location.unknown ~repr:"0.." ~kind:IInt Integer.zero
 let is_nul_exp = Cil_datatype.ExpStructEq.equal nul_exp
 
 module HL = Lval.Hashtbl
@@ -46,7 +46,7 @@ let check_cast_compatibility e typ =
       ~once:true
       ~source:(fst @@ e.eloc)
       ~wkey:Options.Warn.unsafe_cast
-      "unsafe cast from %a to %a"
+      "unsafe cast from %a to %a; analysis may be unsound"
       Printer.pp_typ type_of_e Printer.pp_typ typ
 
 let rec simplify_offset o =
@@ -81,7 +81,8 @@ and simplify_exp e =
         check_cast_compatibility e typ;
         simplify_exp e
       | Lval lv -> {e with enode = Lval (simplify_lval lv)}
-      | AddrOf lv | StartOf lv -> {e with enode = AddrOf (simplify_lval lv)}
+      | StartOf lv -> {e with enode = Lval (simplify_lval lv)}
+      | AddrOf lv -> {e with enode = AddrOf (simplify_lval lv)}
       | BinOp(PlusPI, e1, _, _) | BinOp(MinusPI, e1, _, _) ->
         begin
           match (simplify_exp e1).enode with
@@ -91,6 +92,8 @@ and simplify_exp e =
       | _ -> e
     in
     HE.add cached_exp e res;
+    Options.debug ~level:9 "simplify_exp %a = %a"
+      Printer.pp_exp e Printer.pp_exp res;
     res
 
 module LvalOrRef = struct
@@ -112,52 +115,8 @@ module LvalOrRef = struct
       Lval lv -> Some (Lval lv)
     | AddrOf lv -> Some (Ref lv)
     | _ -> None
-
-  let is_pointer x =
-    match x with
-    | Ref _ -> true
-    | Lval lv ->
-      let t = Cil.typeOfLval lv in
-      match Cil.unrollType t with
-        TPtr _ | TArray _ -> true
-      | _ -> false
 end
 
 module Lval = struct
-  type t = lval
-
-  let simplify x = simplify_lval x
-
-  let compare = Cil_datatype.LvalStructEq.compare
-
-  let pretty l =
-    if Options.is_debug_key_enabled Options.DebugKeys.lvals
-    then Cil_types_debug.pp_lval l
-    else Printer.pp_lval l
-
-  let points_to lv = Mem (Cil.dummy_exp (Lval lv)), NoOffset
+  let simplify = simplify_lval
 end
-
-let decompose_lval lv1 : (lval * offset) list =
-  let rec list_of_offset (o: offset) : (offset*offset) list =
-    match o with
-      NoOffset -> [NoOffset,o]
-    | Index(e,ofs) ->
-      let li =
-        List.map
-          (fun (o1,o2) -> (Index(e,o1),o2))
-          (list_of_offset ofs)
-      in
-      (NoOffset,o)::li
-    | Field(f, ofs) ->
-      let li =
-        List.map
-          (fun (o1,o2) -> (Field(f,o1),o2))
-          (list_of_offset ofs)
-      in
-      (NoOffset,o)::li
-  in
-  let lv, off = Cil.removeOffsetLval lv1 in
-  List.map
-    (fun (o1,o2) -> Cil.addOffsetLval o1 lv, o2)
-    (list_of_offset off)
diff --git a/src/plugins/alias/simplified.mli b/src/plugins/alias/src/simplified.mli
similarity index 83%
rename from src/plugins/alias/simplified.mli
rename to src/plugins/alias/src/simplified.mli
index 08f5e21c9e8d1785115db6de5160d856c54b7360..b0fc8070450982487cbe5eefabdbac43047993f4 100644
--- a/src/plugins/alias/simplified.mli
+++ b/src/plugins/alias/src/simplified.mli
@@ -22,37 +22,24 @@
 
 open Cil_types
 
+
+val nul_exp : exp
+
+(* exception raised when the program tries to access a memory location directly. *)
+exception Explicit_pointer_address of location
+
 module LvalOrRef : sig
   type t = Lval of lval | Ref of lval
   val pretty : Format.formatter -> t -> unit
 
   (* result stored in cache. May raise Explicit_pointer_address *)
   val from_exp : exp -> t option
-
-  (* true if x is assimilable to a pointer type (explicit pointer or
-     memory adress or array *)
-  val is_pointer : t -> bool
 end
 
-(* exception raised when the program tries to access a memory location directly. *)
-exception Explicit_pointer_address of location
-
 module Lval : sig
-  type t = lval
-
-  val compare: t -> t -> int
-
   (* result stored in cache. May raise Explicit_pointer_address *)
   val simplify : lval -> lval
-
-  val pretty: Format.formatter -> t -> unit
-
-  (* (points_to x) = *x and (points_to &x) = x. Raise
-     Explicit_pointer_address when applied to BNone *)
-  val points_to : lval -> lval
 end
 
-val decompose_lval : lval -> (lval * offset) list
-
 (** clear the two caches *)
 val clear_cache : unit -> unit
diff --git a/src/plugins/alias/tests/basic/oracle/addrof.res.oracle b/src/plugins/alias/tests/basic/oracle/addrof.res.oracle
index c721b21001c6ad2f68ca327d72df4754aa3fb229..9d99ee3ec0c2d5a71ba546e083b70347465634d6 100644
--- a/src/plugins/alias/tests/basic/oracle/addrof.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/addrof.res.oracle
@@ -2,16 +2,38 @@
 [alias] analysing function: main
 [alias] analysing instruction: a = & x;
 [alias] May-aliases after instruction  a = & x;  are  { *a; x }
+[alias] May-alias graph after instruction  a = & x;  is
+  0:{ a } → 1:{ x }   1:{ x } → 2:{  }
 [alias] analysing instruction: b = & y;
-[alias] May-aliases after instruction  b = & y;  are  { *a; x }  { *b; y }
+[alias] May-aliases after instruction  b = & y;  are
+  { *a; x }  { *b; y }  { *(*b); *y }
+[alias] May-alias graph after instruction  b = & y;  is
+  0:{ a } → 1:{ x }   1:{ x } → 2:{  }   6:{ b } → 7:{ y }
+  7:{ y } → 8:{  }   8:{  } → 9:{  }
 [alias] analysing instruction: y = & z;
 [alias] May-aliases after instruction  y = & z;  are
   { *a; x }  { *b; y }  { *(*b); *y; z }
+[alias] May-alias graph after instruction  y = & z;  is
+  0:{ a } → 1:{ x }   1:{ x } → 2:{  }   6:{ b } → 7:{ y }
+  7:{ y } → 8:{ z }   8:{ z } → 9:{  }
 [alias] analysing instruction: *y = x;
 [alias] May-aliases after instruction  *y = x;  are
-  { *(*b); *a; *y; x }  { *b; a; y }
+  { *b; a; y }  { *(*b); *a; *y; x }
+[alias] May-alias graph after instruction  *y = x;  is
+  0:{ a } → 8:{ x }   6:{ b } → 7:{ y }   7:{ y } → 8:{ x }
+  8:{ x } → 9:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are
   { *b; a; y }  { *(*b); *a; *y; x; z }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ a } → 1:{ x; z }   1:{ x; z } → 2:{  }   6:{ b } → 7:{ y }
+  7:{ y } → 1:{ x; z }
 [alias] May-aliases at the end of function main:
   { *b; a; y }  { *(*b); *a; *y; x; z }
+[alias] May-alias graph at the end of function main:
+  0:{ a } → 1:{ x; z }   1:{ x; z } → 2:{  }   6:{ b } → 7:{ y }
+  7:{ y } → 1:{ x; z }
+[alias] Summary of function main:
+  formals:     returns: __retres
+  state: { *b; a; y }  { *(*b); *a; *y; x; z }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/assignment1.res.oracle b/src/plugins/alias/tests/basic/oracle/assignment1.res.oracle
index 0a62f46e5b140cf0ff68ba9f7cf44fc14c9c5491..b1e3f774ca69aa751f6a63e87cc3fff79b83fca9 100644
--- a/src/plugins/alias/tests/basic/oracle/assignment1.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/assignment1.res.oracle
@@ -2,18 +2,32 @@
 [alias] analysing function: main
 [alias] analysing instruction: int *a = (int *)0;
 [alias] May-aliases after instruction  int *a = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *a = (int *)0;  is    <empty>
 [alias] analysing instruction: int *b = (int *)0;
 [alias] May-aliases after instruction  int *b = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *b = (int *)0;  is    <empty>
 [alias] analysing instruction: int *c = (int *)0;
 [alias] May-aliases after instruction  int *c = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *c = (int *)0;  is    <empty>
 [alias] analysing instruction: int *d = (int *)0;
 [alias] May-aliases after instruction  int *d = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *d = (int *)0;  is    <empty>
 [alias] analysing instruction: a = b;
 [alias] May-aliases after instruction  a = b;  are  { a; b }
+[alias] May-alias graph after instruction  a = b;  is    0:{ a; b } → 1:{  }
 [alias] analysing instruction: b = c;
 [alias] May-aliases after instruction  b = c;  are  { a; b; c }
+[alias] May-alias graph after instruction  b = c;  is    0:{ a; b; c } → 1:{  }
 [alias] analysing instruction: a = d;
 [alias] May-aliases after instruction  a = d;  are  { a; b; c; d }
+[alias] May-alias graph after instruction  a = d;  is    0:{ a; b; c; d } → 1:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  { a; b; c; d }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ a; b; c; d } → 1:{  }
 [alias] May-aliases at the end of function main: { a; b; c; d }
+[alias] May-alias graph at the end of function main:
+  0:{ a; b; c; d } → 1:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { a; b; c; d }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/assignment2.res.oracle b/src/plugins/alias/tests/basic/oracle/assignment2.res.oracle
index 02b7661040b329de9fcce9bcca780a7896a5a53a..a584e695cb3bf290518c41e0c4313c5d36906880 100644
--- a/src/plugins/alias/tests/basic/oracle/assignment2.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/assignment2.res.oracle
@@ -2,18 +2,36 @@
 [alias] analysing function: main
 [alias] analysing instruction: int **a = (int **)0;
 [alias] May-aliases after instruction  int **a = (int **)0;  are  <none>
+[alias] May-alias graph after instruction  int **a = (int **)0;  is    <empty>
 [alias] analysing instruction: int *b = (int *)0;
 [alias] May-aliases after instruction  int *b = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *b = (int *)0;  is    <empty>
 [alias] analysing instruction: int **c = (int **)0;
 [alias] May-aliases after instruction  int **c = (int **)0;  are  <none>
+[alias] May-alias graph after instruction  int **c = (int **)0;  is    <empty>
 [alias] analysing instruction: int *d = (int *)0;
 [alias] May-aliases after instruction  int *d = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *d = (int *)0;  is    <empty>
 [alias] analysing instruction: *a = b;
 [alias] May-aliases after instruction  *a = b;  are  { *a; b }
+[alias] May-alias graph after instruction  *a = b;  is
+  0:{ a } → 1:{ b }   1:{ b } → 2:{  }
 [alias] analysing instruction: *c = d;
 [alias] May-aliases after instruction  *c = d;  are  { *a; b }  { *c; d }
+[alias] May-alias graph after instruction  *c = d;  is
+  0:{ a } → 1:{ b }   1:{ b } → 2:{  }   5:{ c } → 6:{ d }
+  6:{ d } → 7:{  }
 [alias] analysing instruction: a = c;
 [alias] May-aliases after instruction  a = c;  are  { a; c }  { *a; *c; b; d }
+[alias] May-alias graph after instruction  a = c;  is
+  0:{ a; c } → 1:{ b; d }   1:{ b; d } → 2:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  { a; c }  { *a; *c; b; d }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ a; c } → 1:{ b; d }   1:{ b; d } → 2:{  }
 [alias] May-aliases at the end of function main: { a; c }  { *a; *c; b; d }
+[alias] May-alias graph at the end of function main:
+  0:{ a; c } → 1:{ b; d }   1:{ b; d } → 2:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { a; c }  { *a; *c; b; d }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/assignment3.res.oracle b/src/plugins/alias/tests/basic/oracle/assignment3.res.oracle
index 38afe15b98597c2d9d4d2753d68fc53c242b2a59..22605c19af07f9a50a3b547c507b389718b4adec 100644
--- a/src/plugins/alias/tests/basic/oracle/assignment3.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/assignment3.res.oracle
@@ -2,14 +2,27 @@
 [alias] analysing function: main
 [alias] analysing instruction: int *a = (int *)0;
 [alias] May-aliases after instruction  int *a = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *a = (int *)0;  is    <empty>
 [alias] analysing instruction: int b = 0;
 [alias] May-aliases after instruction  int b = 0;  are  <none>
+[alias] May-alias graph after instruction  int b = 0;  is    <empty>
 [alias] analysing instruction: int *c = (int *)0;
 [alias] May-aliases after instruction  int *c = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *c = (int *)0;  is    <empty>
 [alias] analysing instruction: a = & b;
 [alias] May-aliases after instruction  a = & b;  are  <none>
+[alias] May-alias graph after instruction  a = & b;  is    0:{ a } → 1:{ b }
 [alias] analysing instruction: c = & b;
 [alias] May-aliases after instruction  c = & b;  are  { a; c }
+[alias] May-alias graph after instruction  c = & b;  is
+  0:{ a } → 5:{ b }   4:{ c } → 5:{ b }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  { a; c }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ a } → 5:{ b }   4:{ c } → 5:{ b }
 [alias] May-aliases at the end of function main: { a; c }
+[alias] May-alias graph at the end of function main:
+  0:{ a } → 5:{ b }   4:{ c } → 5:{ b }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { a; c }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/assignment4.res.oracle b/src/plugins/alias/tests/basic/oracle/assignment4.res.oracle
index 8d9d355619779d4622cfb830c25bcebf079d70a2..69175d2e930b735b530c6482d78dd2d410e4382b 100644
--- a/src/plugins/alias/tests/basic/oracle/assignment4.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/assignment4.res.oracle
@@ -2,18 +2,36 @@
 [alias] analysing function: main
 [alias] analysing instruction: int **a = (int **)0;
 [alias] May-aliases after instruction  int **a = (int **)0;  are  <none>
+[alias] May-alias graph after instruction  int **a = (int **)0;  is    <empty>
 [alias] analysing instruction: int *b = (int *)0;
 [alias] May-aliases after instruction  int *b = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *b = (int *)0;  is    <empty>
 [alias] analysing instruction: int **c = (int **)0;
 [alias] May-aliases after instruction  int **c = (int **)0;  are  <none>
+[alias] May-alias graph after instruction  int **c = (int **)0;  is    <empty>
 [alias] analysing instruction: int *d = (int *)0;
 [alias] May-aliases after instruction  int *d = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *d = (int *)0;  is    <empty>
 [alias] analysing instruction: *a = b;
 [alias] May-aliases after instruction  *a = b;  are  { *a; b }
+[alias] May-alias graph after instruction  *a = b;  is
+  0:{ a } → 1:{ b }   1:{ b } → 2:{  }
 [alias] analysing instruction: *c = d;
 [alias] May-aliases after instruction  *c = d;  are  { *a; b }  { *c; d }
+[alias] May-alias graph after instruction  *c = d;  is
+  0:{ a } → 1:{ b }   1:{ b } → 2:{  }   5:{ c } → 6:{ d }
+  6:{ d } → 7:{  }
 [alias] analysing instruction: b = d;
 [alias] May-aliases after instruction  b = d;  are  { a; c }  { *a; *c; b; d }
+[alias] May-alias graph after instruction  b = d;  is
+  0:{ a } → 1:{ b; d }   1:{ b; d } → 2:{  }   5:{ c } → 1:{ b; d }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  { a; c }  { *a; *c; b; d }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ a } → 1:{ b; d }   1:{ b; d } → 2:{  }   5:{ c } → 1:{ b; d }
 [alias] May-aliases at the end of function main: { a; c }  { *a; *c; b; d }
+[alias] May-alias graph at the end of function main:
+  0:{ a } → 1:{ b; d }   1:{ b; d } → 2:{  }   5:{ c } → 1:{ b; d }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { a; c }  { *a; *c; b; d }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/assignment5.res.oracle b/src/plugins/alias/tests/basic/oracle/assignment5.res.oracle
index 023e852d0398703b8760d45770f1286d46c1c250..64a9a7de39abd3aa7876c5a87a0dec4d273b1edc 100644
--- a/src/plugins/alias/tests/basic/oracle/assignment5.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/assignment5.res.oracle
@@ -2,20 +2,37 @@
 [alias] analysing function: main
 [alias] analysing instruction: int ***a = (int ***)0;
 [alias] May-aliases after instruction  int ***a = (int ***)0;  are  <none>
+[alias] May-alias graph after instruction  int ***a = (int ***)0;  is    <empty>
 [alias] analysing instruction: int **b = (int **)0;
 [alias] May-aliases after instruction  int **b = (int **)0;  are  <none>
+[alias] May-alias graph after instruction  int **b = (int **)0;  is    <empty>
 [alias] analysing instruction: int *c = (int *)0;
 [alias] May-aliases after instruction  int *c = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *c = (int *)0;  is    <empty>
 [alias] analysing instruction: int *d = (int *)0;
 [alias] May-aliases after instruction  int *d = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *d = (int *)0;  is    <empty>
 [alias] analysing instruction: *a = b;
-[alias] May-aliases after instruction  *a = b;  are  { *a; b }
+[alias] May-aliases after instruction  *a = b;  are  { *a; b }  { *(*a); *b }
+[alias] May-alias graph after instruction  *a = b;  is
+  0:{ a } → 1:{ b }   1:{ b } → 2:{  }   2:{  } → 3:{  }
 [alias] analysing instruction: *b = c;
 [alias] May-aliases after instruction  *b = c;  are  { *a; b }  { *(*a); *b; c }
+[alias] May-alias graph after instruction  *b = c;  is
+  0:{ a } → 1:{ b }   1:{ b } → 2:{ c }   2:{ c } → 3:{  }
 [alias] analysing instruction: d = *(*a);
 [alias] May-aliases after instruction  d = *(*a);  are
   { *a; b }  { *(*a); *b; c; d }
+[alias] May-alias graph after instruction  d = *(*a);  is
+  0:{ a } → 1:{ b }   1:{ b } → 9:{ c; d }   9:{ c; d } → 10:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are
   { *a; b }  { *(*a); *b; c; d }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ a } → 1:{ b }   1:{ b } → 9:{ c; d }   9:{ c; d } → 10:{  }
 [alias] May-aliases at the end of function main: { *a; b }  { *(*a); *b; c; d }
+[alias] May-alias graph at the end of function main:
+  0:{ a } → 1:{ b }   1:{ b } → 9:{ c; d }   9:{ c; d } → 10:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { *a; b }  { *(*a); *b; c; d }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/cast1.res.oracle b/src/plugins/alias/tests/basic/oracle/cast1.res.oracle
index 8a1dd1b9c580fa8fb3d77e3b216cbad020db570d..176c4f381f9259dffabbb0b7f4de5fa873fbf492 100644
--- a/src/plugins/alias/tests/basic/oracle/cast1.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/cast1.res.oracle
@@ -2,18 +2,34 @@
 [alias] analysing function: main
 [alias] analysing instruction: int *a = (int *)0;
 [alias] May-aliases after instruction  int *a = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *a = (int *)0;  is    <empty>
 [alias] analysing instruction: int *b = (int *)0;
 [alias] May-aliases after instruction  int *b = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *b = (int *)0;  is    <empty>
 [alias] analysing instruction: float *c = (float *)0;
 [alias] May-aliases after instruction  float *c = (float *)0;  are  <none>
+[alias] May-alias graph after instruction  float *c = (float *)0;  is    <empty>
 [alias] analysing instruction: float *d = (float *)0;
 [alias] May-aliases after instruction  float *d = (float *)0;  are  <none>
+[alias] May-alias graph after instruction  float *d = (float *)0;  is    <empty>
 [alias] analysing instruction: a = (int *)c;
-[alias:unsafe-cast] cast1.c:10: Warning: unsafe cast from float * to int *
+[alias:unsafe-cast] cast1.c:10: Warning: 
+  unsafe cast from float * to int *; analysis may be unsound
 [alias] May-aliases after instruction  a = (int *)c;  are  { a; c }
+[alias] May-alias graph after instruction  a = (int *)c;  is    0:{ a; c } → 1:{  }
 [alias] analysing instruction: d = (float *)b;
-[alias:unsafe-cast] cast1.c:11: Warning: unsafe cast from int * to float *
+[alias:unsafe-cast] cast1.c:11: Warning: 
+  unsafe cast from int * to float *; analysis may be unsound
 [alias] May-aliases after instruction  d = (float *)b;  are  { a; c }  { b; d }
+[alias] May-alias graph after instruction  d = (float *)b;  is
+  0:{ a; c } → 1:{  }   4:{ b; d } → 5:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  { a; c }  { b; d }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ a; c } → 1:{  }   4:{ b; d } → 5:{  }
 [alias] May-aliases at the end of function main: { a; c }  { b; d }
+[alias] May-alias graph at the end of function main:
+  0:{ a; c } → 1:{  }   4:{ b; d } → 5:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { a; c }  { b; d }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/conditional1.res.oracle b/src/plugins/alias/tests/basic/oracle/conditional1.res.oracle
index 878ffd6070b299f54c2888bf492b61e71983e5ec..0fa0dba3a4307b4ee494e725810288cdb9323883 100644
--- a/src/plugins/alias/tests/basic/oracle/conditional1.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/conditional1.res.oracle
@@ -2,16 +2,29 @@
 [alias] analysing function: main
 [alias] analysing instruction: int *a = (int *)0;
 [alias] May-aliases after instruction  int *a = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *a = (int *)0;  is    <empty>
 [alias] analysing instruction: int *b = (int *)0;
 [alias] May-aliases after instruction  int *b = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *b = (int *)0;  is    <empty>
 [alias] analysing instruction: int *c = (int *)0;
 [alias] May-aliases after instruction  int *c = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *c = (int *)0;  is    <empty>
 [alias] analysing instruction: a = b;
 [alias] May-aliases after instruction  a = b;  are  { a; b }
+[alias] May-alias graph after instruction  a = b;  is    0:{ a; b } → 1:{  }
 [alias] analysing instruction: a = c;
 [alias] May-aliases after instruction  a = c;  are  { a; c }
+[alias] May-alias graph after instruction  a = c;  is    4:{ a; c } → 5:{  }
 [alias] analysing instruction: *a = 4;
 [alias] May-aliases after instruction  *a = 4;  are  { a; b; c }
+[alias] May-alias graph after instruction  *a = 4;  is    0:{ a; b; c } → 1:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  { a; b; c }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ a; b; c } → 1:{  }
 [alias] May-aliases at the end of function main: { a; b; c }
+[alias] May-alias graph at the end of function main:
+  0:{ a; b; c } → 1:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { a; b; c }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/conditional2.res.oracle b/src/plugins/alias/tests/basic/oracle/conditional2.res.oracle
index 74a6ebea0fc5c1ad01eeee8567b555029abb9cf8..7fc2d29a8e6e828cba54c70a7b1935c428af995b 100644
--- a/src/plugins/alias/tests/basic/oracle/conditional2.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/conditional2.res.oracle
@@ -1,19 +1,38 @@
 [kernel] Parsing conditional2.c (with preprocessing)
 [alias] analysing function: main
 [alias] analysing instruction: b = & c;
-[alias] May-aliases after instruction  b = & c;  are  { *b; c }
+[alias] May-aliases after instruction  b = & c;  are  { *b; c }  { *(*b); *c }
+[alias] May-alias graph after instruction  b = & c;  is
+  0:{ b } → 1:{ c }   1:{ c } → 2:{  }   2:{  } → 3:{  }
 [alias] analysing instruction: c = & d;
 [alias] May-aliases after instruction  c = & d;  are  { *b; c }  { *(*b); *c; d }
+[alias] May-alias graph after instruction  c = & d;  is
+  0:{ b } → 1:{ c }   1:{ c } → 2:{ d }   2:{ d } → 3:{  }
 [alias] analysing instruction: d = & e;
 [alias] May-aliases after instruction  d = & e;  are  { *b; c }  { *(*b); *c; d }
+[alias] May-alias graph after instruction  d = & e;  is
+  0:{ b } → 1:{ c }   1:{ c } → 2:{ d }   2:{ d } → 3:{ e }
 [alias] analysing instruction: a = b;
 [alias] May-aliases after instruction  a = b;  are
-  { *a; *b; c }  { *(*a); *(*b); *c; d }  { a; b }
+  { a; b }  { *a; *b; c }  { *(*a); *(*b); *c; d }
+[alias] May-alias graph after instruction  a = b;  is
+  13:{ a; b } → 14:{ c }   14:{ c } → 15:{ d }   15:{ d } → 16:{ e }
 [alias] analysing instruction: a = & c;
 [alias] May-aliases after instruction  a = & c;  are
-  { *a; *b; c }  { *(*a); *(*b); *c; d }  { a; b }
+  { a; b }  { *a; *b; c }  { *(*a); *(*b); *c; d }
+[alias] May-alias graph after instruction  a = & c;  is
+  0:{ b } → 18:{ c }   17:{ a } → 18:{ c }   18:{ c } → 19:{ d }
+  19:{ d } → 20:{ e }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are
-  { *a; *b; c }  { *(*a); *(*b); *c; d }  { a; b }
+  { a; b }  { *a; *b; c }  { *(*a); *(*b); *c; d }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  13:{ a; b } → 14:{ c }   14:{ c } → 15:{ d }   15:{ d } → 16:{ e }
 [alias] May-aliases at the end of function main:
-  { *a; *b; c }  { *(*a); *(*b); *c; d }  { a; b }
+  { a; b }  { *a; *b; c }  { *(*a); *(*b); *c; d }
+[alias] May-alias graph at the end of function main:
+  13:{ a; b } → 14:{ c }   14:{ c } → 15:{ d }   15:{ d } → 16:{ e }
+[alias] Summary of function main:
+  formals:     returns: __retres
+  state: { a; b }  { *a; *b; c }  { *(*a); *(*b); *c; d }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/conditional3.res.oracle b/src/plugins/alias/tests/basic/oracle/conditional3.res.oracle
index d91937c0431836ffc5d198eab44303805d5c6c48..c6dbb35184a35298494d14ee90341a2c5ad7be89 100644
--- a/src/plugins/alias/tests/basic/oracle/conditional3.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/conditional3.res.oracle
@@ -1,35 +1,80 @@
 [kernel] Parsing conditional3.c (with preprocessing)
 [alias] analysing function: main
 [alias] analysing instruction: a = b;
-[alias] May-aliases after instruction  a = b;  are  { a; b }
+[alias] May-aliases after instruction  a = b;  are
+  { a; b }  { *a; *b }  { *(*a); *(*b) }  { *(*(*a)); *(*(*b)) }
+[alias] May-alias graph after instruction  a = b;  is
+  0:{ a; b } → 1:{  }   1:{  } → 2:{  }   2:{  } → 3:{  }
+  3:{  } → 4:{  }
 [alias] analysing instruction: b = & i;
-[alias] May-aliases after instruction  b = & i;  are  { a; b }  { *a; *b; i }
+[alias] May-aliases after instruction  b = & i;  are
+  { a; b }  { *a; *b; i }  { *(*a); *(*b); *i }  { *(*(*a)); *(*(*b)); *(*i) }
+[alias] May-alias graph after instruction  b = & i;  is
+  0:{ a; b } → 1:{ i }   1:{ i } → 2:{  }   2:{  } → 3:{  }
+  3:{  } → 4:{  }
 [alias] analysing instruction: i = & x;
 [alias] May-aliases after instruction  i = & x;  are
   { a; b }  { *a; *b; i }  { *(*a); *(*b); *i; x }
+  { *(*(*a)); *(*(*b)); *(*i); *x }
+[alias] May-alias graph after instruction  i = & x;  is
+  0:{ a; b } → 1:{ i }   1:{ i } → 2:{ x }   2:{ x } → 3:{  }
+  3:{  } → 4:{  }
 [alias] analysing instruction: x = & t;
 [alias] May-aliases after instruction  x = & t;  are
   { a; b }  { *a; *b; i }  { *(*a); *(*b); *i; x }
   { *(*(*a)); *(*(*b)); *(*i); *x; t }
+[alias] May-alias graph after instruction  x = & t;  is
+  0:{ a; b } → 1:{ i }   1:{ i } → 2:{ x }   2:{ x } → 3:{ t }
+  3:{ t } → 4:{  }
 [alias] analysing instruction: a = c;
-[alias] May-aliases after instruction  a = c;  are  { a; c }
+[alias] May-aliases after instruction  a = c;  are
+  { a; c }  { *a; *c }  { *(*a); *(*c) }  { *(*(*a)); *(*(*c)) }
+[alias] May-alias graph after instruction  a = c;  is
+  22:{ a; c } → 23:{  }   23:{  } → 24:{  }   24:{  } → 25:{  }
+  25:{  } → 26:{  }
 [alias] analysing instruction: c = & j;
-[alias] May-aliases after instruction  c = & j;  are  { a; c }  { *a; *c; j }
+[alias] May-aliases after instruction  c = & j;  are
+  { a; c }  { *a; *c; j }  { *(*a); *(*c); *j }  { *(*(*a)); *(*(*c)); *(*j) }
+[alias] May-alias graph after instruction  c = & j;  is
+  22:{ a; c } → 23:{ j }   23:{ j } → 24:{  }   24:{  } → 25:{  }
+  25:{  } → 26:{  }
 [alias] analysing instruction: j = & y;
 [alias] May-aliases after instruction  j = & y;  are
   { a; c }  { *a; *c; j }  { *(*a); *(*c); *j; y }
+  { *(*(*a)); *(*(*c)); *(*j); *y }
+[alias] May-alias graph after instruction  j = & y;  is
+  22:{ a; c } → 23:{ j }   23:{ j } → 24:{ y }   24:{ y } → 25:{  }
+  25:{  } → 26:{  }
 [alias] analysing instruction: y = & u;
 [alias] May-aliases after instruction  y = & u;  are
   { a; c }  { *a; *c; j }  { *(*a); *(*c); *j; y }
   { *(*(*a)); *(*(*c)); *(*j); *y; u }
+[alias] May-alias graph after instruction  y = & u;  is
+  22:{ a; c } → 23:{ j }   23:{ j } → 24:{ y }   24:{ y } → 25:{ u }
+  25:{ u } → 26:{  }
 [alias] analysing instruction: p = 0;
 [alias] May-aliases after instruction  p = 0;  are
   { a; b; c }  { *a; *b; *c; i; j }  { *(*a); *(*b); *(*c); *i; *j; x; y }
   { *(*(*a)); *(*(*b)); *(*(*c)); *(*i); *(*j); *x; *y; t; u }
+[alias] May-alias graph after instruction  p = 0;  is
+  0:{ a; b; c } → 1:{ i; j }   1:{ i; j } → 2:{ x; y }
+  2:{ x; y } → 3:{ t; u }   3:{ t; u } → 4:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are
   { a; b; c }  { *a; *b; *c; i; j }  { *(*a); *(*b); *(*c); *i; *j; x; y }
   { *(*(*a)); *(*(*b)); *(*(*c)); *(*i); *(*j); *x; *y; t; u }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ a; b; c } → 1:{ i; j }   1:{ i; j } → 2:{ x; y }
+  2:{ x; y } → 3:{ t; u }   3:{ t; u } → 4:{  }
 [alias] May-aliases at the end of function main:
   { a; b; c }  { *a; *b; *c; i; j }  { *(*a); *(*b); *(*c); *i; *j; x; y }
   { *(*(*a)); *(*(*b)); *(*(*c)); *(*i); *(*j); *x; *y; t; u }
+[alias] May-alias graph at the end of function main:
+  0:{ a; b; c } → 1:{ i; j }   1:{ i; j } → 2:{ x; y }
+  2:{ x; y } → 3:{ t; u }   3:{ t; u } → 4:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres
+  state: { a; b; c }  { *a; *b; *c; i; j }
+         { *(*a); *(*b); *(*c); *i; *j; x; y }
+         { *(*(*a)); *(*(*b)); *(*(*c)); *(*i); *(*j); *x; *y; t; u }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/function1.res.oracle b/src/plugins/alias/tests/basic/oracle/function1.res.oracle
index d97b433f7171289d3ffd85343bae5e419ea8ab15..2d3bdc6d06a4081fe504be989c432580a7dc79fb 100644
--- a/src/plugins/alias/tests/basic/oracle/function1.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/function1.res.oracle
@@ -2,30 +2,61 @@
 [alias] analysing function: main
 [alias] analysing instruction: int *a = (int *)0;
 [alias] May-aliases after instruction  int *a = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *a = (int *)0;  is    <empty>
 [alias] analysing instruction: int *b = (int *)0;
 [alias] May-aliases after instruction  int *b = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *b = (int *)0;  is    <empty>
 [alias] analysing instruction: int *c = (int *)0;
 [alias] May-aliases after instruction  int *c = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *c = (int *)0;  is    <empty>
 [alias] analysing instruction: int *d = (int *)0;
 [alias] May-aliases after instruction  int *d = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *d = (int *)0;  is    <empty>
 [alias] analysing instruction: swap(a,b);
 [alias] analysing function: swap
 [alias] analysing instruction: int *z = (int *)0;
 [alias] May-aliases after instruction  int *z = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *z = (int *)0;  is    <empty>
 [alias] analysing instruction: z = x;
 [alias] May-aliases after instruction  z = x;  are  { x; z }
+[alias] May-alias graph after instruction  z = x;  is    0:{ x; z } → 1:{  }
 [alias] analysing instruction: x = y;
 [alias] May-aliases after instruction  x = y;  are  { x; y; z }
+[alias] May-alias graph after instruction  x = y;  is    0:{ x; y; z } → 1:{  }
 [alias] analysing instruction: y = z;
 [alias] May-aliases after instruction  y = z;  are  { x; y; z }
+[alias] May-alias graph after instruction  y = z;  is    0:{ x; y; z } → 1:{  }
 [alias] May-aliases at the end of function swap: { x; y; z }
+[alias] May-alias graph at the end of function swap:
+  0:{ x; y; z } → 1:{  }
+[alias] Summary of function swap:
+  formals: x  y    returns: <none>    state: { x; y; z }
 [alias] May-aliases after instruction  swap(a,b);  are  { a; b }
+[alias] May-alias graph after instruction  swap(a,b);  is
+  8:{ a } → 7:{  }   10:{ b } → 7:{  }
 [alias] analysing instruction: swap(c,d);
 [alias] May-aliases after instruction  swap(c,d);  are  { a; b }  { c; d }
+[alias] May-alias graph after instruction  swap(c,d);  is
+  8:{ a } → 7:{  }   10:{ b } → 7:{  }   14:{ c } → 13:{  }
+  16:{ d } → 13:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  { a; b }  { c; d }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  8:{ a } → 7:{  }   10:{ b } → 7:{  }   14:{ c } → 13:{  }
+  16:{ d } → 13:{  }
 [alias] May-aliases at the end of function main: { a; b }  { c; d }
+[alias] May-alias graph at the end of function main:
+  8:{ a } → 7:{  }   10:{ b } → 7:{  }   14:{ c } → 13:{  }
+  16:{ d } → 13:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { a; b }  { c; d }
 [alias] analysing function: swap
 [alias] analysing instruction: int *z = (int *)0;
 [alias] May-aliases after instruction  int *z = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *z = (int *)0;  is    <empty>
 [alias] May-aliases at the end of function swap: { x; y; z }
+[alias] May-alias graph at the end of function swap:
+  0:{ x; y; z } → 1:{  }
+[alias] Summary of function swap:
+  formals: x  y    returns: <none>    state: { x; y; z }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/function2.res.oracle b/src/plugins/alias/tests/basic/oracle/function2.res.oracle
index 1e4decb3e431ddaeca4ca82775f8bc469b5f9756..d7e607ebde164861b5db116e4a2157a97f9e278b 100644
--- a/src/plugins/alias/tests/basic/oracle/function2.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/function2.res.oracle
@@ -1,136 +1,49 @@
 [kernel] Parsing function2.c (with preprocessing)
-[alias] analysing function: _Exit
-[alias] May-aliases at the end of function _Exit: ⊥
-[alias] analysing function: abort
-[alias] May-aliases at the end of function abort: ⊥
-[alias] analysing function: abs
-[alias] May-aliases at the end of function abs: ⊥
-[alias] analysing function: at_quick_exit
-[alias] May-aliases at the end of function at_quick_exit: ⊥
-[alias] analysing function: atexit
-[alias] May-aliases at the end of function atexit: ⊥
-[alias] analysing function: atof
-[alias] May-aliases at the end of function atof: ⊥
-[alias] analysing function: atoi
-[alias] May-aliases at the end of function atoi: ⊥
-[alias] analysing function: atol
-[alias] May-aliases at the end of function atol: ⊥
-[alias] analysing function: atoll
-[alias] May-aliases at the end of function atoll: ⊥
-[alias] analysing function: bsearch
-[alias] May-aliases at the end of function bsearch: ⊥
-[alias] analysing function: calloc
-[alias] May-aliases at the end of function calloc: ⊥
-[alias] analysing function: div
-[alias] May-aliases at the end of function div: ⊥
-[alias] analysing function: drand48
-[alias] May-aliases at the end of function drand48: ⊥
-[alias] analysing function: erand48
-[alias] May-aliases at the end of function erand48: ⊥
-[alias] analysing function: exit
-[alias] May-aliases at the end of function exit: ⊥
-[alias] analysing function: free
-[alias] May-aliases at the end of function free: ⊥
-[alias] analysing function: getenv
-[alias] May-aliases at the end of function getenv: ⊥
-[alias] analysing function: jrand48
-[alias] May-aliases at the end of function jrand48: ⊥
-[alias] analysing function: labs
-[alias] May-aliases at the end of function labs: ⊥
-[alias] analysing function: lcong48
-[alias] May-aliases at the end of function lcong48: ⊥
-[alias] analysing function: ldiv
-[alias] May-aliases at the end of function ldiv: ⊥
-[alias] analysing function: llabs
-[alias] May-aliases at the end of function llabs: ⊥
-[alias] analysing function: lldiv
-[alias] May-aliases at the end of function lldiv: ⊥
-[alias] analysing function: lrand48
-[alias] May-aliases at the end of function lrand48: ⊥
 [alias] analysing function: main
 [alias] analysing instruction: int *a = (int *)0;
 [alias] May-aliases after instruction  int *a = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *a = (int *)0;  is    <empty>
 [alias] analysing instruction: int *b = (int *)0;
 [alias] May-aliases after instruction  int *b = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *b = (int *)0;  is    <empty>
 [alias] analysing instruction: a = my_malloc(2);
 [alias] analysing function: my_malloc
 [alias] analysing instruction: int *res = (int *)0;
 [alias] May-aliases after instruction  int *res = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *res = (int *)0;  is    <empty>
 [alias] analysing instruction: res = (int *)malloc((size_t)size);
 [alias] May-aliases after instruction  res = (int *)malloc((size_t)size);  are
   <none>
+[alias] May-alias graph after instruction  res = (int *)malloc((size_t)size);  is
+  0:{ res } → 1:{  }
 [alias] May-aliases at the end of function my_malloc: <none>
+[alias] May-alias graph at the end of function my_malloc:
+  0:{ res } → 1:{  }
+[alias] Summary of function my_malloc:
+  formals: size    returns: res    state: <none>
 [alias] May-aliases after instruction  a = my_malloc(2);  are  <none>
+[alias] May-alias graph after instruction  a = my_malloc(2);  is
+  4:{ a } → 3:{  }
 [alias] analysing instruction: b = my_malloc(3);
 [alias] May-aliases after instruction  b = my_malloc(3);  are  <none>
+[alias] May-alias graph after instruction  b = my_malloc(3);  is
+  4:{ a } → 3:{  }   8:{ b } → 7:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  <none>
+[alias] May-alias graph after instruction  __retres = 0;  is
+  4:{ a } → 3:{  }   8:{ b } → 7:{  }
 [alias] May-aliases at the end of function main: <none>
-[alias] analysing function: malloc
-[alias] May-aliases at the end of function malloc: ⊥
-[alias] analysing function: mblen
-[alias] May-aliases at the end of function mblen: ⊥
-[alias] analysing function: mbstowcs
-[alias] May-aliases at the end of function mbstowcs: ⊥
-[alias] analysing function: mbtowc
-[alias] May-aliases at the end of function mbtowc: ⊥
-[alias] analysing function: mkstemp
-[alias] May-aliases at the end of function mkstemp: ⊥
-[alias] analysing function: mkstemps
-[alias] May-aliases at the end of function mkstemps: ⊥
-[alias] analysing function: mrand48
-[alias] May-aliases at the end of function mrand48: ⊥
+[alias] May-alias graph at the end of function main:
+  4:{ a } → 3:{  }   8:{ b } → 7:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: <none>
 [alias] analysing function: my_malloc
 [alias] analysing instruction: int *res = (int *)0;
 [alias] May-aliases after instruction  int *res = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *res = (int *)0;  is    <empty>
 [alias] May-aliases at the end of function my_malloc: <none>
-[alias] analysing function: nrand48
-[alias] May-aliases at the end of function nrand48: ⊥
-[alias] analysing function: posix_memalign
-[alias] May-aliases at the end of function posix_memalign: ⊥
-[alias] analysing function: putenv
-[alias] May-aliases at the end of function putenv: ⊥
-[alias] analysing function: qsort
-[alias] May-aliases at the end of function qsort: ⊥
-[alias] analysing function: quick_exit
-[alias] May-aliases at the end of function quick_exit: ⊥
-[alias] analysing function: rand
-[alias] May-aliases at the end of function rand: ⊥
-[alias] analysing function: random
-[alias] May-aliases at the end of function random: ⊥
-[alias] analysing function: realloc
-[alias] May-aliases at the end of function realloc: ⊥
-[alias] analysing function: reallocarray
-[alias] May-aliases at the end of function reallocarray: ⊥
-[alias] analysing function: seed48
-[alias] May-aliases at the end of function seed48: ⊥
-[alias] analysing function: setenv
-[alias] May-aliases at the end of function setenv: ⊥
-[alias] analysing function: srand
-[alias] May-aliases at the end of function srand: ⊥
-[alias] analysing function: srand48
-[alias] May-aliases at the end of function srand48: ⊥
-[alias] analysing function: srandom
-[alias] May-aliases at the end of function srandom: ⊥
-[alias] analysing function: strtod
-[alias] May-aliases at the end of function strtod: ⊥
-[alias] analysing function: strtof
-[alias] May-aliases at the end of function strtof: ⊥
-[alias] analysing function: strtol
-[alias] May-aliases at the end of function strtol: ⊥
-[alias] analysing function: strtold
-[alias] May-aliases at the end of function strtold: ⊥
-[alias] analysing function: strtoll
-[alias] May-aliases at the end of function strtoll: ⊥
-[alias] analysing function: strtoul
-[alias] May-aliases at the end of function strtoul: ⊥
-[alias] analysing function: strtoull
-[alias] May-aliases at the end of function strtoull: ⊥
-[alias] analysing function: system
-[alias] May-aliases at the end of function system: ⊥
-[alias] analysing function: unsetenv
-[alias] May-aliases at the end of function unsetenv: ⊥
-[alias] analysing function: wcstombs
-[alias] May-aliases at the end of function wcstombs: ⊥
-[alias] analysing function: wctomb
-[alias] May-aliases at the end of function wctomb: ⊥
+[alias] May-alias graph at the end of function my_malloc:
+  0:{ res } → 1:{  }
+[alias] Summary of function my_malloc:
+  formals: size    returns: res    state: <none>
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/function3.res.oracle b/src/plugins/alias/tests/basic/oracle/function3.res.oracle
index b45284aa949832888557c32e03d34fee1e6f1b6f..1642757d0b1a51127c2c1ab0880e0d9ec81ce20a 100644
--- a/src/plugins/alias/tests/basic/oracle/function3.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/function3.res.oracle
@@ -2,26 +2,54 @@
 [alias] analysing function: f1
 [alias] analysing instruction: int *tmp = x;
 [alias] May-aliases after instruction  int *tmp = x;  are  { x; tmp }
+[alias] May-alias graph after instruction  int *tmp = x;  is
+  0:{ x; tmp } → 1:{  }
 [alias] analysing instruction: x = y;
 [alias] May-aliases after instruction  x = y;  are  { x; y; tmp }
+[alias] May-alias graph after instruction  x = y;  is    0:{ x; y; tmp } → 1:{  }
 [alias] analysing instruction: y = tmp;
 [alias] May-aliases after instruction  y = tmp;  are  { x; y; tmp }
+[alias] May-alias graph after instruction  y = tmp;  is    0:{ x; y; tmp } → 1:{  }
 [alias] analysing instruction: __retres = (void *)0;
 [alias] May-aliases after instruction  __retres = (void *)0;  are  { x; y; tmp }
+[alias] May-alias graph after instruction  __retres = (void *)0;  is
+  0:{ x; y; tmp } → 1:{  }
 [alias] May-aliases at the end of function f1: { x; y; tmp }
+[alias] May-alias graph at the end of function f1:
+  0:{ x; y; tmp } → 1:{  }
+[alias] Summary of function f1:
+  formals: x  y    returns: __retres    state: { x; y; tmp }
 [alias] analysing function: main
 [alias] analysing instruction: int *a = (int *)0;
 [alias] May-aliases after instruction  int *a = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *a = (int *)0;  is    <empty>
 [alias] analysing instruction: int *b = (int *)0;
 [alias] May-aliases after instruction  int *b = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *b = (int *)0;  is    <empty>
 [alias] analysing instruction: int *c = (int *)0;
 [alias] May-aliases after instruction  int *c = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *c = (int *)0;  is    <empty>
 [alias] analysing instruction: int *d = (int *)0;
 [alias] May-aliases after instruction  int *d = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *d = (int *)0;  is    <empty>
 [alias] analysing instruction: f1(a,b);
 [alias] May-aliases after instruction  f1(a,b);  are  { a; b }
+[alias] May-alias graph after instruction  f1(a,b);  is
+  16:{ a } → 9:{  }   18:{ b } → 9:{  }
 [alias] analysing instruction: f1(c,d);
 [alias] May-aliases after instruction  f1(c,d);  are  { a; b }  { c; d }
+[alias] May-alias graph after instruction  f1(c,d);  is
+  16:{ a } → 9:{  }   18:{ b } → 9:{  }   28:{ c } → 21:{  }
+  30:{ d } → 21:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  { a; b }  { c; d }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  16:{ a } → 9:{  }   18:{ b } → 9:{  }   28:{ c } → 21:{  }
+  30:{ d } → 21:{  }
 [alias] May-aliases at the end of function main: { a; b }  { c; d }
+[alias] May-alias graph at the end of function main:
+  16:{ a } → 9:{  }   18:{ b } → 9:{  }   28:{ c } → 21:{  }
+  30:{ d } → 21:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { a; b }  { c; d }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/function4.res.oracle b/src/plugins/alias/tests/basic/oracle/function4.res.oracle
index fb629f9683ca15d9fadde9031640b8070fa25eb5..2b8bbf2b4c64cabaa547f565ac191b6a07fa733d 100644
--- a/src/plugins/alias/tests/basic/oracle/function4.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/function4.res.oracle
@@ -1,17 +1,35 @@
 [kernel] Parsing function4.c (with preprocessing)
 [alias] analysing function: addr
 [alias] May-aliases at the end of function addr: <none>
+[alias] May-alias graph at the end of function addr:
+  <empty>
+[alias] Summary of function addr:
+  formals: x    returns: x    state: <none>
 [alias] analysing function: main
 [alias] analysing instruction: int *a = (int *)0;
 [alias] May-aliases after instruction  int *a = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *a = (int *)0;  is    <empty>
 [alias] analysing instruction: int *b = (int *)0;
 [alias] May-aliases after instruction  int *b = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *b = (int *)0;  is    <empty>
 [alias] analysing instruction: int c = 0;
 [alias] May-aliases after instruction  int c = 0;  are  <none>
+[alias] May-alias graph after instruction  int c = 0;  is    <empty>
 [alias] analysing instruction: a = addr(& c);
 [alias] May-aliases after instruction  a = addr(& c);  are  <none>
+[alias] May-alias graph after instruction  a = addr(& c);  is
+  4:{ a } → 3:{ c }   7:{  } → 3:{ c }
 [alias] analysing instruction: b = & c;
 [alias] May-aliases after instruction  b = & c;  are  { a; b }
+[alias] May-alias graph after instruction  b = & c;  is
+  4:{ a } → 9:{ c }   7:{  } → 9:{ c }   8:{ b } → 9:{ c }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  { a; b }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  4:{ a } → 9:{ c }   7:{  } → 9:{ c }   8:{ b } → 9:{ c }
 [alias] May-aliases at the end of function main: { a; b }
+[alias] May-alias graph at the end of function main:
+  4:{ a } → 9:{ c }   7:{  } → 9:{ c }   8:{ b } → 9:{ c }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { a; b }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/function5.res.oracle b/src/plugins/alias/tests/basic/oracle/function5.res.oracle
index 53362c373d1c8f03d0e2ad4e06b1c2e4a30faea6..cce128cc40eb99959377e03b5b26de0b7e7bbba3 100644
--- a/src/plugins/alias/tests/basic/oracle/function5.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/function5.res.oracle
@@ -2,20 +2,41 @@
 [alias] analysing function: choice
 [alias] analysing instruction: int c = 0;
 [alias] May-aliases after instruction  int c = 0;  are  <none>
+[alias] May-alias graph after instruction  int c = 0;  is    <empty>
 [alias] analysing instruction: __retres = x;
 [alias] May-aliases after instruction  __retres = x;  are  { x; __retres }
+[alias] May-alias graph after instruction  __retres = x;  is
+  0:{ x; __retres } → 1:{  }
 [alias] analysing instruction: __retres = y;
 [alias] May-aliases after instruction  __retres = y;  are  { y; __retres }
+[alias] May-alias graph after instruction  __retres = y;  is
+  4:{ y; __retres } → 5:{  }
 [alias] May-aliases at the end of function choice: { x; y; __retres }
+[alias] May-alias graph at the end of function choice:
+  0:{ x; y; __retres } → 1:{  }
+[alias] Summary of function choice:
+  formals: x  y    returns: __retres    state: { x; y; __retres }
 [alias] analysing function: main
 [alias] analysing instruction: int *a = (int *)0;
 [alias] May-aliases after instruction  int *a = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *a = (int *)0;  is    <empty>
 [alias] analysing instruction: int *b = (int *)0;
 [alias] May-aliases after instruction  int *b = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *b = (int *)0;  is    <empty>
 [alias] analysing instruction: int *c = (int *)0;
 [alias] May-aliases after instruction  int *c = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *c = (int *)0;  is    <empty>
 [alias] analysing instruction: c = choice(a,b);
 [alias] May-aliases after instruction  c = choice(a,b);  are  { a; b; c }
+[alias] May-alias graph after instruction  c = choice(a,b);  is
+  10:{ c } → 9:{  }   12:{ a } → 9:{  }   14:{ b } → 9:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  { a; b; c }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  10:{ c } → 9:{  }   12:{ a } → 9:{  }   14:{ b } → 9:{  }
 [alias] May-aliases at the end of function main: { a; b; c }
+[alias] May-alias graph at the end of function main:
+  10:{ c } → 9:{  }   12:{ a } → 9:{  }   14:{ b } → 9:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { a; b; c }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/function6.res.oracle b/src/plugins/alias/tests/basic/oracle/function6.res.oracle
index 4d8f8fa4a01fce5e95e6b5afdc4c4f24aec1c045..e60a5f1225ecfdd72138228934f4c11fa3df73aa 100644
--- a/src/plugins/alias/tests/basic/oracle/function6.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/function6.res.oracle
@@ -2,30 +2,53 @@
 [alias] analysing function: main
 [alias] analysing instruction: int *a = (int *)0;
 [alias] May-aliases after instruction  int *a = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *a = (int *)0;  is    <empty>
 [alias] analysing instruction: int *b = (int *)0;
 [alias] May-aliases after instruction  int *b = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *b = (int *)0;  is    <empty>
 [alias] analysing instruction: int *c = (int *)0;
 [alias] May-aliases after instruction  int *c = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *c = (int *)0;  is    <empty>
 [alias] analysing instruction: int *d = (int *)0;
 [alias] May-aliases after instruction  int *d = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *d = (int *)0;  is    <empty>
 [alias] analysing instruction: swap(a,b);
 [alias] analysing function: swap
 [alias] analysing instruction: int z = 0;
 [alias] May-aliases after instruction  int z = 0;  are  <none>
+[alias] May-alias graph after instruction  int z = 0;  is    <empty>
 [alias] analysing instruction: z = *x;
 [alias] May-aliases after instruction  z = *x;  are  <none>
+[alias] May-alias graph after instruction  z = *x;  is    <empty>
 [alias] analysing instruction: *x = *y;
 [alias] May-aliases after instruction  *x = *y;  are  <none>
+[alias] May-alias graph after instruction  *x = *y;  is    <empty>
 [alias] analysing instruction: *y = z;
 [alias] May-aliases after instruction  *y = z;  are  <none>
+[alias] May-alias graph after instruction  *y = z;  is    <empty>
 [alias] May-aliases at the end of function swap: <none>
+[alias] May-alias graph at the end of function swap:
+  <empty>
+[alias] Summary of function swap:
 [alias] May-aliases after instruction  swap(a,b);  are  <none>
+[alias] May-alias graph after instruction  swap(a,b);  is    <empty>
 [alias] analysing instruction: swap(c,d);
 [alias] May-aliases after instruction  swap(c,d);  are  <none>
+[alias] May-alias graph after instruction  swap(c,d);  is    <empty>
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  <none>
+[alias] May-alias graph after instruction  __retres = 0;  is    <empty>
 [alias] May-aliases at the end of function main: <none>
+[alias] May-alias graph at the end of function main:
+  <empty>
+[alias] Summary of function main:
+  formals:     returns: __retres    state: <none>
 [alias] analysing function: swap
 [alias] analysing instruction: int z = 0;
 [alias] May-aliases after instruction  int z = 0;  are  <none>
+[alias] May-alias graph after instruction  int z = 0;  is    <empty>
 [alias] May-aliases at the end of function swap: <none>
+[alias] May-alias graph at the end of function swap:
+  <empty>
+[alias] Summary of function swap:
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/globctr.res.oracle b/src/plugins/alias/tests/basic/oracle/globctr.res.oracle
index 64f2826db29bf339219770a5cf558ec4f579b092..3b942fd3aae5a0f0e099016b82bdfa3fb35bb975 100644
--- a/src/plugins/alias/tests/basic/oracle/globctr.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/globctr.res.oracle
@@ -2,18 +2,33 @@
 [alias] analysing function: f
 [alias] analysing instruction: int y = 0;
 [alias] May-aliases after instruction  int y = 0;  are  <none>
+[alias] May-alias graph after instruction  int y = 0;  is    <empty>
 [alias] analysing instruction: *x = y;
 [alias] May-aliases after instruction  *x = y;  are  <none>
+[alias] May-alias graph after instruction  *x = y;  is    <empty>
 [alias] May-aliases at the end of function f: <none>
+[alias] May-alias graph at the end of function f:
+  <empty>
+[alias] Summary of function f:
 [alias] analysing function: main
 [alias] analysing instruction: int *a = (int *)0;
 [alias] May-aliases after instruction  int *a = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *a = (int *)0;  is    <empty>
 [alias] analysing instruction: int *b = (int *)0;
 [alias] May-aliases after instruction  int *b = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *b = (int *)0;  is    <empty>
 [alias] analysing instruction: f(a);
 [alias] May-aliases after instruction  f(a);  are  <none>
+[alias] May-alias graph after instruction  f(a);  is    <empty>
 [alias] analysing instruction: f(b);
 [alias] May-aliases after instruction  f(b);  are  <none>
+[alias] May-alias graph after instruction  f(b);  is    <empty>
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  <none>
+[alias] May-alias graph after instruction  __retres = 0;  is    <empty>
 [alias] May-aliases at the end of function main: <none>
+[alias] May-alias graph at the end of function main:
+  <empty>
+[alias] Summary of function main:
+  formals:     returns: __retres    state: <none>
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/loop.res.oracle b/src/plugins/alias/tests/basic/oracle/loop.res.oracle
index 9ef827f6daf8c1920926e31460dc19ab04c72bac..e0dd21c5c92e01e09c9cd42556593d79cfec0077 100644
--- a/src/plugins/alias/tests/basic/oracle/loop.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/loop.res.oracle
@@ -2,18 +2,36 @@
 [alias] analysing function: main
 [alias] analysing instruction: int l[1] = {0};
 [alias] May-aliases after instruction  int l[1] = {0};  are  <none>
+[alias] May-alias graph after instruction  int l[1] = {0};  is    <empty>
 [alias] analysing instruction: int *n_0 = & l[1];
-[alias] May-aliases after instruction  int *n_0 = & l[1];  are  <none>
+[alias] May-aliases after instruction  int *n_0 = & l[1];  are  { l; n_0 }
+[alias] May-alias graph after instruction  int *n_0 = & l[1];  is
+  0:{ n_0 } → 1:{  }   2:{ l } → 1:{  }
 [alias] analysing instruction: n_0 = & l[1] + 0;
-[alias] May-aliases after instruction  n_0 = & l[1] + 0;  are  <none>
+[alias] May-aliases after instruction  n_0 = & l[1] + 0;  are  { l; n_0 }
+[alias] May-alias graph after instruction  n_0 = & l[1] + 0;  is
+  0:{ n_0 } → 1:{  }   2:{ l } → 1:{  }
 [alias] analysing instruction: int w = 0;
-[alias] May-aliases after instruction  int w = 0;  are  <none>
+[alias] May-aliases after instruction  int w = 0;  are  { l; n_0 }
+[alias] May-alias graph after instruction  int w = 0;  is
+  0:{ n_0 } → 1:{  }   2:{ l } → 1:{  }
 [alias] analysing instruction: l[0] = *(& l[1] + 0);
-[alias] May-aliases after instruction  l[0] = *(& l[1] + 0);  are  <none>
+[alias] May-aliases after instruction  l[0] = *(& l[1] + 0);  are  { l; n_0 }
+[alias] May-alias graph after instruction  l[0] = *(& l[1] + 0);  is
+  0:{ n_0 } → 1:{  }   2:{ l } → 1:{  }
 [alias] analysing instruction: int l[1] = {0};
-[alias] May-aliases after instruction  int l[1] = {0};  are  <none>
+[alias] May-aliases after instruction  int l[1] = {0};  are  { l; n_0 }
+[alias] May-alias graph after instruction  int l[1] = {0};  is
+  0:{ n_0 } → 1:{  }   2:{ l } → 1:{  }
 [alias] analysing instruction: int *n_0 = & l[1];
-[alias] May-aliases after instruction  int *n_0 = & l[1];  are  <none>
+[alias] May-aliases after instruction  int *n_0 = & l[1];  are  { l; n_0 }
+[alias] May-alias graph after instruction  int *n_0 = & l[1];  is
+  0:{ n_0 } → 1:{  }   2:{ l } → 1:{  }
 [alias:no-return] loop.c:4: Warning: 
   function main does not return; analysis may be unsound
 [alias] May-aliases at the end of function main: <none>
+[alias] May-alias graph at the end of function main:
+  <empty>
+[alias] Summary of function main:
+  formals:     returns: __retres    state: <none>
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/pointer_call.res.oracle b/src/plugins/alias/tests/basic/oracle/pointer_call.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..33e7e0abd98799b45a4a0bb5bf65aa3460482bfb
--- /dev/null
+++ b/src/plugins/alias/tests/basic/oracle/pointer_call.res.oracle
@@ -0,0 +1,55 @@
+[kernel] Parsing pointer_call.c (with preprocessing)
+[alias] analysing function: alias_xy
+[alias] analysing instruction: x = y;
+[alias] May-aliases after instruction  x = y;  are  { x; y }
+[alias] May-alias graph after instruction  x = y;  is    0:{ x; y } → 1:{  }
+[alias] May-aliases at the end of function alias_xy: { x; y }
+[alias] May-alias graph at the end of function alias_xy:
+  0:{ x; y } → 1:{  }
+[alias] Summary of function alias_xy:
+  formals: x  y  z    returns: <none>    state: { x; y }
+[alias] analysing function: alias_yz
+[alias] analysing instruction: y = z;
+[alias] May-aliases after instruction  y = z;  are  { y; z }
+[alias] May-alias graph after instruction  y = z;  is    4:{ y; z } → 5:{  }
+[alias] May-aliases at the end of function alias_yz: { y; z }
+[alias] May-alias graph at the end of function alias_yz:
+  4:{ y; z } → 5:{  }
+[alias] Summary of function alias_yz:
+  formals: x  y  z    returns: <none>    state: { y; z }
+[alias] analysing function: main
+[alias] analysing instruction: int *a = (int *)0;
+[alias] May-aliases after instruction  int *a = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *a = (int *)0;  is    <empty>
+[alias] analysing instruction: int *b = (int *)0;
+[alias] May-aliases after instruction  int *b = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *b = (int *)0;  is    <empty>
+[alias] analysing instruction: int *c = (int *)0;
+[alias] May-aliases after instruction  int *c = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *c = (int *)0;  is    <empty>
+[alias] analysing instruction: p = & alias_xy;
+[alias] May-aliases after instruction  p = & alias_xy;  are  <none>
+[alias] May-alias graph after instruction  p = & alias_xy;  is
+  8:{ p } → 9:{ alias_xy }
+[alias] analysing instruction: p = & alias_yz;
+[alias] May-aliases after instruction  p = & alias_yz;  are  <none>
+[alias] May-alias graph after instruction  p = & alias_yz;  is
+  8:{ p } → 9:{ alias_xy; alias_yz }
+[alias] analysing instruction: (*p)(a,b,c);
+[alias] (*p)(a,b,c); is an indirect function call to one of { alias_xy; alias_yz }
+[alias] May-aliases after instruction  (*p)(a,b,c);  are  { a; b; c }
+[alias] May-alias graph after instruction  (*p)(a,b,c);  is
+  8:{ p } → 9:{ alias_xy; alias_yz }   16:{ a } → 15:{  }
+  18:{ b } → 15:{  }   22:{ c } → 15:{  }
+[alias] analysing instruction: __retres = 0;
+[alias] May-aliases after instruction  __retres = 0;  are  { a; b; c }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  8:{ p } → 9:{ alias_xy; alias_yz }   16:{ a } → 15:{  }
+  18:{ b } → 15:{  }   22:{ c } → 15:{  }
+[alias] May-aliases at the end of function main: { a; b; c }
+[alias] May-alias graph at the end of function main:
+  8:{ p } → 9:{ alias_xy; alias_yz }   16:{ a } → 15:{  }
+  18:{ b } → 15:{  }   22:{ c } → 15:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { a; b; c }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/steensgaard.res.oracle b/src/plugins/alias/tests/basic/oracle/steensgaard.res.oracle
index fdb1f8f1ce3b2bbb12c678edf124ed7295c1e1ff..45caffcae31e7ad8603f290150252e74e1fbe165 100644
--- a/src/plugins/alias/tests/basic/oracle/steensgaard.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/steensgaard.res.oracle
@@ -2,16 +2,38 @@
 [alias] analysing function: main
 [alias] analysing instruction: a = & x;
 [alias] May-aliases after instruction  a = & x;  are  <none>
+[alias] May-alias graph after instruction  a = & x;  is    0:{ a } → 1:{ x }
 [alias] analysing instruction: b = & y;
 [alias] May-aliases after instruction  b = & y;  are  { *b; y }
+[alias] May-alias graph after instruction  b = & y;  is
+  0:{ a } → 1:{ x }   4:{ b } → 5:{ y }   5:{ y } → 6:{  }
 [alias] analysing instruction: y = & z;
 [alias] May-aliases after instruction  y = & z;  are  { *b; y }
+[alias] May-alias graph after instruction  y = & z;  is
+  0:{ a } → 1:{ x }   4:{ b } → 5:{ y }   5:{ y } → 6:{ z }
 [alias] analysing instruction: y = & x;
 [alias] May-aliases after instruction  y = & x;  are  { *b; a; y }
+[alias] May-alias graph after instruction  y = & x;  is
+  0:{ a } → 6:{ x }   4:{ b } → 5:{ y }   5:{ y } → 6:{ x }
 [alias] analysing instruction: c = & y;
-[alias] May-aliases after instruction  c = & y;  are  { *b; *c; a; y }  { b; c }
+[alias] May-aliases after instruction  c = & y;  are  { b; c }  { *b; *c; a; y }
+[alias] May-alias graph after instruction  c = & y;  is
+  0:{ a } → 15:{ x; z }   4:{ b } → 14:{ y }   13:{ c } → 14:{ y }
+  14:{ y } → 15:{ x; z }
 [alias] analysing instruction: *y = 4;
-[alias] May-aliases after instruction  *y = 4;  are  { *b; *c; a; y }  { b; c }
+[alias] May-aliases after instruction  *y = 4;  are  { b; c }  { *b; *c; a; y }
+[alias] May-alias graph after instruction  *y = 4;  is
+  0:{ a } → 15:{ x; z }   4:{ b } → 14:{ y }   13:{ c } → 14:{ y }
+  14:{ y } → 15:{ x; z }
 [alias] analysing instruction: __retres = 0;
-[alias] May-aliases after instruction  __retres = 0;  are  { *b; *c; a; y }  { b; c }
-[alias] May-aliases at the end of function main: { *b; *c; a; y }  { b; c }
+[alias] May-aliases after instruction  __retres = 0;  are  { b; c }  { *b; *c; a; y }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ a } → 15:{ x; z }   4:{ b } → 14:{ y }   13:{ c } → 14:{ y }
+  14:{ y } → 15:{ x; z }
+[alias] May-aliases at the end of function main: { b; c }  { *b; *c; a; y }
+[alias] May-alias graph at the end of function main:
+  0:{ a } → 15:{ x; z }   4:{ b } → 14:{ y }   13:{ c } → 14:{ y }
+  14:{ y } → 15:{ x; z }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { b; c }  { *b; *c; a; y }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/switch1.res.oracle b/src/plugins/alias/tests/basic/oracle/switch1.res.oracle
index 1d3c1881fa95b04f44b10729f9dbd1c1c045342c..05300247fce1f838844c67fa0680d5118c4002df 100644
--- a/src/plugins/alias/tests/basic/oracle/switch1.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/switch1.res.oracle
@@ -2,18 +2,34 @@
 [alias] analysing function: main
 [alias] analysing instruction: int *a = (int *)0;
 [alias] May-aliases after instruction  int *a = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *a = (int *)0;  is    <empty>
 [alias] analysing instruction: int *b = (int *)0;
 [alias] May-aliases after instruction  int *b = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *b = (int *)0;  is    <empty>
 [alias] analysing instruction: int *c = (int *)0;
 [alias] May-aliases after instruction  int *c = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *c = (int *)0;  is    <empty>
 [alias] analysing instruction: int *d = (int *)0;
 [alias] May-aliases after instruction  int *d = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *d = (int *)0;  is    <empty>
 [alias] analysing instruction: int e = 0;
 [alias] May-aliases after instruction  int e = 0;  are  <none>
+[alias] May-alias graph after instruction  int e = 0;  is    <empty>
 [alias] analysing instruction: case 1: a = d;
 [alias] May-aliases after instruction  case 1: a = d;  are  { a; d }
+[alias] May-alias graph after instruction  case 1: a = d;  is
+  0:{ a; d } → 1:{  }
 [alias] analysing instruction: case 2: b = d;
 [alias] May-aliases after instruction  case 2: b = d;  are  { b; d }
+[alias] May-alias graph after instruction  case 2: b = d;  is
+  4:{ b; d } → 5:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  { a; b; d }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ a; b; d } → 1:{  }
 [alias] May-aliases at the end of function main: { a; b; d }
+[alias] May-alias graph at the end of function main:
+  0:{ a; b; d } → 1:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { a; b; d }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/switch2.res.oracle b/src/plugins/alias/tests/basic/oracle/switch2.res.oracle
index 8097b1a0db56aa0691de2531dcee7786e04b44f2..ddad760995837ebb16e0f1661422a71e091c0bbe 100644
--- a/src/plugins/alias/tests/basic/oracle/switch2.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/switch2.res.oracle
@@ -2,20 +2,38 @@
 [alias] analysing function: main
 [alias] analysing instruction: int *a = (int *)0;
 [alias] May-aliases after instruction  int *a = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *a = (int *)0;  is    <empty>
 [alias] analysing instruction: int *b = (int *)0;
 [alias] May-aliases after instruction  int *b = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *b = (int *)0;  is    <empty>
 [alias] analysing instruction: int *c = (int *)0;
 [alias] May-aliases after instruction  int *c = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *c = (int *)0;  is    <empty>
 [alias] analysing instruction: int *d = (int *)0;
 [alias] May-aliases after instruction  int *d = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *d = (int *)0;  is    <empty>
 [alias] analysing instruction: int e = 0;
 [alias] May-aliases after instruction  int e = 0;  are  <none>
+[alias] May-alias graph after instruction  int e = 0;  is    <empty>
 [alias] analysing instruction: case 1: a = d;
 [alias] May-aliases after instruction  case 1: a = d;  are  { a; d }
+[alias] May-alias graph after instruction  case 1: a = d;  is
+  0:{ a; d } → 1:{  }
 [alias] analysing instruction: case 2: b = d;
 [alias] May-aliases after instruction  case 2: b = d;  are  { b; d }
+[alias] May-alias graph after instruction  case 2: b = d;  is
+  4:{ b; d } → 5:{  }
 [alias] analysing instruction: default: c = d;
 [alias] May-aliases after instruction  default: c = d;  are  { c; d }
+[alias] May-alias graph after instruction  default: c = d;  is
+  8:{ c; d } → 9:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  { a; b; c; d }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ a; b; c; d } → 1:{  }
 [alias] May-aliases at the end of function main: { a; b; c; d }
+[alias] May-alias graph at the end of function main:
+  0:{ a; b; c; d } → 1:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { a; b; c; d }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/while_for1.res.oracle b/src/plugins/alias/tests/basic/oracle/while_for1.res.oracle
index 228274eef6fbd1b252d69ecb7bf0cf0c763c528e..0db95fcf8a6756a1d61297dbfbf3436e506730e7 100644
--- a/src/plugins/alias/tests/basic/oracle/while_for1.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/while_for1.res.oracle
@@ -1,127 +1,28 @@
 [kernel] Parsing while_for1.c (with preprocessing)
-[alias] analysing function: _Exit
-[alias] May-aliases at the end of function _Exit: ⊥
-[alias] analysing function: abort
-[alias] May-aliases at the end of function abort: ⊥
-[alias] analysing function: abs
-[alias] May-aliases at the end of function abs: ⊥
-[alias] analysing function: at_quick_exit
-[alias] May-aliases at the end of function at_quick_exit: ⊥
-[alias] analysing function: atexit
-[alias] May-aliases at the end of function atexit: ⊥
-[alias] analysing function: atof
-[alias] May-aliases at the end of function atof: ⊥
-[alias] analysing function: atoi
-[alias] May-aliases at the end of function atoi: ⊥
-[alias] analysing function: atol
-[alias] May-aliases at the end of function atol: ⊥
-[alias] analysing function: atoll
-[alias] May-aliases at the end of function atoll: ⊥
-[alias] analysing function: bsearch
-[alias] May-aliases at the end of function bsearch: ⊥
-[alias] analysing function: calloc
-[alias] May-aliases at the end of function calloc: ⊥
-[alias] analysing function: div
-[alias] May-aliases at the end of function div: ⊥
-[alias] analysing function: drand48
-[alias] May-aliases at the end of function drand48: ⊥
-[alias] analysing function: erand48
-[alias] May-aliases at the end of function erand48: ⊥
-[alias] analysing function: exit
-[alias] May-aliases at the end of function exit: ⊥
-[alias] analysing function: free
-[alias] May-aliases at the end of function free: ⊥
-[alias] analysing function: getenv
-[alias] May-aliases at the end of function getenv: ⊥
-[alias] analysing function: jrand48
-[alias] May-aliases at the end of function jrand48: ⊥
-[alias] analysing function: labs
-[alias] May-aliases at the end of function labs: ⊥
-[alias] analysing function: lcong48
-[alias] May-aliases at the end of function lcong48: ⊥
-[alias] analysing function: ldiv
-[alias] May-aliases at the end of function ldiv: ⊥
-[alias] analysing function: llabs
-[alias] May-aliases at the end of function llabs: ⊥
-[alias] analysing function: lldiv
-[alias] May-aliases at the end of function lldiv: ⊥
-[alias] analysing function: lrand48
-[alias] May-aliases at the end of function lrand48: ⊥
 [alias] analysing function: main
 [alias] analysing instruction: int *s = (int *)0;
 [alias] May-aliases after instruction  int *s = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *s = (int *)0;  is    <empty>
 [alias] analysing instruction: int idx = 0;
 [alias] May-aliases after instruction  int idx = 0;  are  <none>
+[alias] May-alias graph after instruction  int idx = 0;  is    <empty>
 [alias] analysing instruction: s = (int *)malloc((size_t)idx);
 [alias] May-aliases after instruction  s = (int *)malloc((size_t)idx);  are  <none>
+[alias] May-alias graph after instruction  s = (int *)malloc((size_t)idx);  is
+  0:{ s } → 1:{  }
 [alias] analysing instruction: idx ++;
 [alias] May-aliases after instruction  idx ++;  are  <none>
+[alias] May-alias graph after instruction  idx ++;  is    0:{ s } → 1:{  }
 [alias] analysing instruction: s = (int *)malloc((size_t)idx);
 [alias] May-aliases after instruction  s = (int *)malloc((size_t)idx);  are  <none>
+[alias] May-alias graph after instruction  s = (int *)malloc((size_t)idx);  is
+  0:{ s } → 1:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  <none>
+[alias] May-alias graph after instruction  __retres = 0;  is    0:{ s } → 1:{  }
 [alias] May-aliases at the end of function main: <none>
-[alias] analysing function: malloc
-[alias] May-aliases at the end of function malloc: ⊥
-[alias] analysing function: mblen
-[alias] May-aliases at the end of function mblen: ⊥
-[alias] analysing function: mbstowcs
-[alias] May-aliases at the end of function mbstowcs: ⊥
-[alias] analysing function: mbtowc
-[alias] May-aliases at the end of function mbtowc: ⊥
-[alias] analysing function: mkstemp
-[alias] May-aliases at the end of function mkstemp: ⊥
-[alias] analysing function: mkstemps
-[alias] May-aliases at the end of function mkstemps: ⊥
-[alias] analysing function: mrand48
-[alias] May-aliases at the end of function mrand48: ⊥
-[alias] analysing function: nrand48
-[alias] May-aliases at the end of function nrand48: ⊥
-[alias] analysing function: posix_memalign
-[alias] May-aliases at the end of function posix_memalign: ⊥
-[alias] analysing function: putenv
-[alias] May-aliases at the end of function putenv: ⊥
-[alias] analysing function: qsort
-[alias] May-aliases at the end of function qsort: ⊥
-[alias] analysing function: quick_exit
-[alias] May-aliases at the end of function quick_exit: ⊥
-[alias] analysing function: rand
-[alias] May-aliases at the end of function rand: ⊥
-[alias] analysing function: random
-[alias] May-aliases at the end of function random: ⊥
-[alias] analysing function: realloc
-[alias] May-aliases at the end of function realloc: ⊥
-[alias] analysing function: reallocarray
-[alias] May-aliases at the end of function reallocarray: ⊥
-[alias] analysing function: seed48
-[alias] May-aliases at the end of function seed48: ⊥
-[alias] analysing function: setenv
-[alias] May-aliases at the end of function setenv: ⊥
-[alias] analysing function: srand
-[alias] May-aliases at the end of function srand: ⊥
-[alias] analysing function: srand48
-[alias] May-aliases at the end of function srand48: ⊥
-[alias] analysing function: srandom
-[alias] May-aliases at the end of function srandom: ⊥
-[alias] analysing function: strtod
-[alias] May-aliases at the end of function strtod: ⊥
-[alias] analysing function: strtof
-[alias] May-aliases at the end of function strtof: ⊥
-[alias] analysing function: strtol
-[alias] May-aliases at the end of function strtol: ⊥
-[alias] analysing function: strtold
-[alias] May-aliases at the end of function strtold: ⊥
-[alias] analysing function: strtoll
-[alias] May-aliases at the end of function strtoll: ⊥
-[alias] analysing function: strtoul
-[alias] May-aliases at the end of function strtoul: ⊥
-[alias] analysing function: strtoull
-[alias] May-aliases at the end of function strtoull: ⊥
-[alias] analysing function: system
-[alias] May-aliases at the end of function system: ⊥
-[alias] analysing function: unsetenv
-[alias] May-aliases at the end of function unsetenv: ⊥
-[alias] analysing function: wcstombs
-[alias] May-aliases at the end of function wcstombs: ⊥
-[alias] analysing function: wctomb
-[alias] May-aliases at the end of function wctomb: ⊥
+[alias] May-alias graph at the end of function main:
+  0:{ s } → 1:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: <none>
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/while_for2.res.oracle b/src/plugins/alias/tests/basic/oracle/while_for2.res.oracle
index c7c4c865fea086d4385379cddaac3da2c9c5315d..14fd60cfa99f24b91c7c48b1bf3aa5a79e5a5f3e 100644
--- a/src/plugins/alias/tests/basic/oracle/while_for2.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/while_for2.res.oracle
@@ -2,12 +2,22 @@
 [alias] analysing function: main
 [alias] analysing instruction: int *a = (int *)0;
 [alias] May-aliases after instruction  int *a = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *a = (int *)0;  is    <empty>
 [alias] analysing instruction: int *b = (int *)0;
 [alias] May-aliases after instruction  int *b = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *b = (int *)0;  is    <empty>
 [alias] analysing instruction: int *c = (int *)0;
 [alias] May-aliases after instruction  int *c = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *c = (int *)0;  is    <empty>
 [alias] analysing instruction: a = b;
 [alias] May-aliases after instruction  a = b;  are  { a; b }
+[alias] May-alias graph after instruction  a = b;  is    0:{ a; b } → 1:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  { a; b }
+[alias] May-alias graph after instruction  __retres = 0;  is    0:{ a; b } → 1:{  }
 [alias] May-aliases at the end of function main: { a; b }
+[alias] May-alias graph at the end of function main:
+  0:{ a; b } → 1:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { a; b }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/oracle/while_for3.res.oracle b/src/plugins/alias/tests/basic/oracle/while_for3.res.oracle
index 40720eb3def4099a57c1c04e687c0d37e2a6f84e..fa8a4fc601abfa5883e6c3e788ec3a13e63cc916 100644
--- a/src/plugins/alias/tests/basic/oracle/while_for3.res.oracle
+++ b/src/plugins/alias/tests/basic/oracle/while_for3.res.oracle
@@ -2,18 +2,31 @@
 [alias] analysing function: main
 [alias] analysing instruction: int *a = (int *)0;
 [alias] May-aliases after instruction  int *a = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *a = (int *)0;  is    <empty>
 [alias] analysing instruction: int *b = (int *)0;
 [alias] May-aliases after instruction  int *b = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *b = (int *)0;  is    <empty>
 [alias] analysing instruction: int *c = (int *)0;
 [alias] May-aliases after instruction  int *c = (int *)0;  are  <none>
+[alias] May-alias graph after instruction  int *c = (int *)0;  is    <empty>
 [alias] analysing instruction: int i = 0;
 [alias] May-aliases after instruction  int i = 0;  are  <none>
+[alias] May-alias graph after instruction  int i = 0;  is    <empty>
 [alias] analysing instruction: a = b;
 [alias] May-aliases after instruction  a = b;  are  { a; b }
+[alias] May-alias graph after instruction  a = b;  is    0:{ a; b } → 1:{  }
 [alias] analysing instruction: __Cont: i ++;
 [alias] May-aliases after instruction  __Cont: i ++;  are  { a; b }
+[alias] May-alias graph after instruction  __Cont: i ++;  is    0:{ a; b } → 1:{  }
 [alias] analysing instruction: a = b;
 [alias] May-aliases after instruction  a = b;  are  { a; b }
+[alias] May-alias graph after instruction  a = b;  is    0:{ a; b } → 1:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  { a; b }
+[alias] May-alias graph after instruction  __retres = 0;  is    0:{ a; b } → 1:{  }
 [alias] May-aliases at the end of function main: { a; b }
+[alias] May-alias graph at the end of function main:
+  0:{ a; b } → 1:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { a; b }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/basic/pointer_call.c b/src/plugins/alias/tests/basic/pointer_call.c
new file mode 100644
index 0000000000000000000000000000000000000000..24d6059e5029a31a67afa2161bd898f63bf34fa7
--- /dev/null
+++ b/src/plugins/alias/tests/basic/pointer_call.c
@@ -0,0 +1,17 @@
+void alias_xy(int *x, int* y, int* z) {
+  x=y;
+}
+
+void alias_yz(int *x, int* y, int* z) {
+  y=z;
+}
+
+int main(void)
+{
+  int *a=0, *b=0, *c=0;
+  void (*p)(int* x, int* y, int* z);
+	p = &alias_xy;
+  p = &alias_yz;
+  (*p)(a,b,c);
+  return 0;
+}
diff --git a/src/plugins/alias/tests/fixed_bugs/arrays.c b/src/plugins/alias/tests/fixed_bugs/arrays.c
new file mode 100644
index 0000000000000000000000000000000000000000..c4a6e0fce936c115921e7652d6f02b940522e734
--- /dev/null
+++ b/src/plugins/alias/tests/fixed_bugs/arrays.c
@@ -0,0 +1,19 @@
+#include <stdio.h>
+
+int *a;
+int *b;
+int *n;
+int *(*z)[2];
+int *(*q)[2];
+int *t[2];
+
+int main(void)
+{
+  t[0] = a;
+  z = &t;
+  q = z;
+  b = *z[0];
+  n = *q[0];
+  printf("%d\n%d\n", a == b, a == n);
+  return 0;
+}
diff --git a/src/plugins/alias/tests/fixed_bugs/ex_jfla.c b/src/plugins/alias/tests/fixed_bugs/ex_jfla.c
new file mode 100644
index 0000000000000000000000000000000000000000..4e1f86660e8aff14c391fbbbdcc2f20bba28bcc8
--- /dev/null
+++ b/src/plugins/alias/tests/fixed_bugs/ex_jfla.c
@@ -0,0 +1,51 @@
+// https://git.frama-c.com/frama-c/frama-c/-/issues/1309
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+typedef struct {int *a; int *b;} str_t;
+
+str_t* create_str_t (int va, int *b) {
+  str_t *res = malloc(sizeof(str_t));
+  if (res) {
+    res->a = malloc(sizeof(int));
+    res->b = malloc(sizeof(int));
+    if (res->a)
+      *res->a = va;
+    if (res->b)
+      res->b = b;
+  }
+  return res;
+}
+
+void jfla (str_t *s, int* i1, int* i2, int b) {
+  *s->b = *s->a;
+  if (b)
+    s->a = i1;
+  else
+    s->a = i2;
+}
+
+
+int main(void)
+{
+  int u = 11 ;
+  int v = 12 ;
+  int t[3] = {0,1,2} ;
+  int *a = t+1;
+  int *b = &u ;
+  int *c = &v ;
+  int **w= &a ;
+  str_t *s1 = create_str_t(-1,b);
+  if (s1) {
+    printf("a=%d\n",*s1->a) ;
+    printf("b=%d\n",*s1->b) ;
+    jfla(s1, a, t+2, 1) ;
+    printf("a=%d\n",*s1->a) ;
+    printf("b=%d\n",*s1->b) ;
+    jfla(s1, t, c, 0) ;
+    printf("a=%d\n",*s1->a) ;
+    printf("b=%d\n",*s1->b) ;
+  }
+}
diff --git a/src/plugins/alias/tests/fixed_bugs/ex_jfla_2.c b/src/plugins/alias/tests/fixed_bugs/ex_jfla_2.c
new file mode 100644
index 0000000000000000000000000000000000000000..bbbf129d65a6843e0ea4adef58d881b30035d3cf
--- /dev/null
+++ b/src/plugins/alias/tests/fixed_bugs/ex_jfla_2.c
@@ -0,0 +1,51 @@
+// https://git.frama-c.com/frama-c/frama-c/-/issues/1309
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+typedef struct {int *fst; int *snd;} str_t;
+
+str_t* create_str_t (int va, int *b) {
+  str_t *res = malloc(sizeof(str_t));
+  if (res) {
+    res->fst = malloc(sizeof(int));
+    res->snd = malloc(sizeof(int));
+    if (res->fst)
+      *res->fst = va;
+    if (res->snd)
+      res->snd = b;
+  }
+  return res;
+}
+
+void jfla (str_t *s, int* i1, int* i2, int b) {
+  *s->snd = *s->fst;
+  if (b)
+    s->fst = i1;
+  else
+    s->fst = i2;
+}
+
+int main(void)
+{
+  int u = 11 ;
+  int v = 12 ;
+  int t[3] = {0,1,2} ;
+  int *a = t+1;
+  int *b = &u ;
+  int *c = &v ;
+  int **x = &a ;
+  int **y = &b ;
+  int **z = &c ;
+  str_t *s1 = create_str_t(-1,b) ;
+  str_t *s2 = create_str_t(-2,c) ;
+  printf("a=%d\n",*s1->fst) ;
+  printf("b=%d\n",*s1->snd) ;
+  jfla(s1, a, t+2, 1) ;
+  printf("a=%d\n",*s1->fst) ;
+  printf("b=%d\n",*s1->snd) ;
+  jfla(s1, t, s2->snd, 0) ;
+  printf("a=%d\n",*s1->fst) ;
+  printf("b=%d\n",*s1->snd) ;
+}
diff --git a/src/plugins/alias/tests/fixed_bugs/ex_jfla_3.c b/src/plugins/alias/tests/fixed_bugs/ex_jfla_3.c
new file mode 100644
index 0000000000000000000000000000000000000000..59a728cdfa057f6450a3516cef1a896922f0ed0f
--- /dev/null
+++ b/src/plugins/alias/tests/fixed_bugs/ex_jfla_3.c
@@ -0,0 +1,41 @@
+// https://git.frama-c.com/frama-c/frama-c/-/issues/1309
+
+#include <stdio.h>
+
+int* jfla (int *fst, int *snd, int **i1, int **i2, int bo) {
+  *snd = *fst;
+  if (bo) {
+    fst = *i1;
+    return *i2;
+  }
+  else {
+    fst = *i2;
+    return *i1;
+  }
+}
+
+int main(void)
+{
+  int u = 11 ;
+  int v = 12 ;
+  int t[3] = {0,1,2} ;
+  int *a = &t[1];
+  int *b = &u ;
+  int *c = &v ;
+  int **x = &a ;
+  int **y = &b ;
+  int **z = &c ;
+  struct str_t {int *fst; int *snd; } ;
+  struct str_t  s = { c , t } ;
+  struct str_t *s1 = &s;
+  struct str_t *s2 = &s;
+  printf("a=%d\n",*s1->fst) ;
+  printf("b=%d\n",*s1->snd) ;
+  c =  jfla(s1->fst, s1->snd, x, y, 0) ;
+  printf("a=%d\n",*s1->fst) ;
+  printf("b=%d\n",*s1->snd) ;
+  a = jfla(s2->fst, s2->snd, y, z, 1) ;
+  printf("a=%d\n",*s1->fst) ;
+  printf("b=%d\n",*s1->snd) ;
+}
+
diff --git a/src/plugins/alias/tests/fixed_bugs/oracle/arrays.res.oracle b/src/plugins/alias/tests/fixed_bugs/oracle/arrays.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..dc03371929486375affbc2fdcb1da5e66a3b1e85
--- /dev/null
+++ b/src/plugins/alias/tests/fixed_bugs/oracle/arrays.res.oracle
@@ -0,0 +1,49 @@
+[kernel] Parsing arrays.c (with preprocessing)
+[alias] analysing function: main
+[alias] analysing instruction: t[0] = a;
+[alias] May-aliases after instruction  t[0] = a;  are  { a; t[0..] }
+[alias] May-alias graph after instruction  t[0] = a;  is
+  0:{ t } → 1:{ a }   1:{ a } → 2:{  }
+[alias] analysing instruction: z = & t;
+[alias] May-aliases after instruction  z = & t;  are
+  { *z; t }  { (*z)[0..]; a; t[0..] }
+[alias] May-alias graph after instruction  z = & t;  is
+  5:{ z } → 6:{ t }   6:{ t } → 7:{ a }   7:{ a } → 8:{  }
+[alias] analysing instruction: q = z;
+[alias] May-aliases after instruction  q = z;  are
+  { z; q }  { *z; *q; t }  { (*z)[0..]; (*q)[0..]; a; t[0..] }
+[alias] May-alias graph after instruction  q = z;  is
+  10:{ z; q } → 11:{ t }   11:{ t } → 12:{ a }   12:{ a } → 13:{  }
+[alias] analysing instruction: b = (*(z + 0))[0];
+[alias] May-aliases after instruction  b = (*(z + 0))[0];  are
+  { z; q }  { *z; *q; t }  { (*z)[0..]; (*q)[0..]; a; b; t[0..] }
+[alias] May-alias graph after instruction  b = (*(z + 0))[0];  is
+  10:{ z; q } → 11:{ t }   11:{ t } → 14:{ a; b }   14:{ a; b } → 15:{  }
+[alias] analysing instruction: n = (*(q + 0))[0];
+[alias] May-aliases after instruction  n = (*(q + 0))[0];  are
+  { z; q }  { *z; *q; t }  { (*z)[0..]; (*q)[0..]; a; b; n; t[0..] }
+[alias] May-alias graph after instruction  n = (*(q + 0))[0];  is
+  10:{ z; q } → 11:{ t }   11:{ t } → 16:{ a; b; n }
+  16:{ a; b; n } → 17:{  }
+[alias] analysing instruction: printf("%d\n%d\n",a == b,a == n);
+[alias:undefined:fn] arrays.c:17: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("%d\n%d\n",a == b,a == n);  are
+  { z; q }  { *z; *q; t }  { (*z)[0..]; (*q)[0..]; a; b; n; t[0..] }
+[alias] May-alias graph after instruction  printf("%d\n%d\n",a == b,a == n);  is
+  10:{ z; q } → 11:{ t }   11:{ t } → 16:{ a; b; n }
+  16:{ a; b; n } → 17:{  }
+[alias] analysing instruction: __retres = 0;
+[alias] May-aliases after instruction  __retres = 0;  are
+  { z; q }  { *z; *q; t }  { (*z)[0..]; (*q)[0..]; a; b; n; t[0..] }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  10:{ z; q } → 11:{ t }   11:{ t } → 16:{ a; b; n }
+  16:{ a; b; n } → 17:{  }
+[alias] May-aliases at the end of function main:
+  { z; q }  { *z; *q; t }  { (*z)[0..]; (*q)[0..]; a; b; n; t[0..] }
+[alias] May-alias graph at the end of function main:
+  10:{ z; q } → 11:{ t }   11:{ t } → 16:{ a; b; n }
+  16:{ a; b; n } → 17:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres
+  state: { z; q }  { *z; *q; t }  { (*z)[0..]; (*q)[0..]; a; b; n; t[0..] }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/fixed_bugs/oracle/empty_nodes.res.oracle b/src/plugins/alias/tests/fixed_bugs/oracle/empty_nodes.res.oracle
index 3f911591f73e9f1c9f616f3a128b0651af18d00c..7141f4e9d659ca156e505174535b95c67b82ef6c 100644
--- a/src/plugins/alias/tests/fixed_bugs/oracle/empty_nodes.res.oracle
+++ b/src/plugins/alias/tests/fixed_bugs/oracle/empty_nodes.res.oracle
@@ -2,13 +2,33 @@
 [alias] analysing function: f
 [alias] analysing instruction: *y = t + (*y - *x);
 [alias] May-aliases after instruction  *y = t + (*y - *x);  are  { *y; t }
+[alias] May-alias graph after instruction  *y = t + (*y - *x);  is
+  0:{ y } → 1:{ t }   1:{ t } → 2:{  }
 [alias] analysing instruction: *z = t + (*z - *x);
 [alias] May-aliases after instruction  *z = t + (*z - *x);  are
-  { *y; *z; t }  { y; z }
+  { y; z }  { *y; *z; t }
+[alias] May-alias graph after instruction  *z = t + (*z - *x);  is
+  0:{ y } → 6:{ t }   5:{ z } → 6:{ t }   6:{ t } → 7:{  }
 [alias] analysing instruction: *x = t;
-[alias] May-aliases after instruction  *x = t;  are  { *x; *y; *z; t }  { x; y; z }
-[alias] May-aliases at the end of function f: { *x; *y; *z; t }  { x; y; z }
+[alias] May-aliases after instruction  *x = t;  are  { x; y; z }  { *x; *y; *z; t }
+[alias] May-alias graph after instruction  *x = t;  is
+  0:{ y } → 9:{ t }   5:{ z } → 9:{ t }   8:{ x } → 9:{ t }
+  9:{ t } → 10:{  }
+[alias] May-aliases at the end of function f: { x; y; z }  { *x; *y; *z; t }
+[alias] May-alias graph at the end of function f:
+  0:{ y } → 9:{ t }   5:{ z } → 9:{ t }   8:{ x } → 9:{ t }
+  9:{ t } → 10:{  }
+[alias] Summary of function f:
+  formals: x→{ t }  y→{ t }  z→{ t }    returns: <none>
+  state: { x; y; z }  { *x; *y; *z; t }
 [alias] analysing function: g
 [alias] analysing instruction: f(a,a,a);
 [alias] May-aliases after instruction  f(a,a,a);  are  <none>
+[alias] May-alias graph after instruction  f(a,a,a);  is
+  20:{  } → 21:{  }   22:{ a } → 20:{  }
 [alias] May-aliases at the end of function g: <none>
+[alias] May-alias graph at the end of function g:
+  20:{  } → 21:{  }   22:{ a } → 20:{  }
+[alias] Summary of function g:
+  formals: a    returns: <none>    state: <none>
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/fixed_bugs/oracle/ex_jfla.res.oracle b/src/plugins/alias/tests/fixed_bugs/oracle/ex_jfla.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..96084ba3ad058fd772be8579c58ca1c1df4e0175
--- /dev/null
+++ b/src/plugins/alias/tests/fixed_bugs/oracle/ex_jfla.res.oracle
@@ -0,0 +1,176 @@
+[kernel] Parsing ex_jfla.c (with preprocessing)
+[alias] analysing function: create_str_t
+[alias] analysing instruction: str_t *res = malloc(sizeof(str_t));
+[alias] May-aliases after instruction  str_t *res = malloc(sizeof(str_t));  are
+  <none>
+[alias] May-alias graph after instruction  str_t *res = malloc(sizeof(str_t));  is
+  0:{ res } → 1:{  }
+[alias] analysing instruction: res->a = (int *)malloc(sizeof(int));
+[alias] May-aliases after instruction  res->a = (int *)malloc(sizeof(int));  are
+  <none>
+[alias] May-alias graph after instruction  res->a = (int *)malloc(sizeof(int));
+  is    0:{ res } → 1:{  }   1:{  } -a→ 2:{  }   2:{  } → 3:{  }
+[alias] analysing instruction: res->b = (int *)malloc(sizeof(int));
+[alias] May-aliases after instruction  res->b = (int *)malloc(sizeof(int));  are
+  <none>
+[alias] May-alias graph after instruction  res->b = (int *)malloc(sizeof(int));
+  is
+  0:{ res } → 1:{  }   1:{  } -a→ 2:{  }   1:{  } -b→ 4:{  }
+  2:{  } → 3:{  }   4:{  } → 5:{  }
+[alias] analysing instruction: *(res->a) = va;
+[alias] May-aliases after instruction  *(res->a) = va;  are  <none>
+[alias] May-alias graph after instruction  *(res->a) = va;  is
+  0:{ res } → 1:{  }   1:{  } -a→ 2:{  }   1:{  } -b→ 4:{  }
+  2:{  } → 3:{  }   4:{  } → 5:{  }
+[alias] analysing instruction: res->b = b;
+[alias] May-aliases after instruction  res->b = b;  are  { res->b; b }
+[alias] May-alias graph after instruction  res->b = b;  is
+  0:{ res } → 1:{  }   1:{  } -a→ 2:{  }   1:{  } -b→ 4:{ b }
+  2:{  } → 3:{  }   4:{ b } → 5:{  }
+[alias] May-aliases at the end of function create_str_t: { res->b; b }
+[alias] May-alias graph at the end of function create_str_t:
+  0:{ res } → 1:{  }   1:{  } -a→ 2:{  }   1:{  } -b→ 4:{ b }
+  2:{  } → 3:{  }   4:{ b } → 5:{  }
+[alias] Summary of function create_str_t:
+  formals: va  b    returns: res    state: { res->b; b }
+[alias] analysing function: jfla
+[alias] analysing instruction: *(s->b) = *(s->a);
+[alias] May-aliases after instruction  *(s->b) = *(s->a);  are  <none>
+[alias] May-alias graph after instruction  *(s->b) = *(s->a);  is    <empty>
+[alias] analysing instruction: s->a = i1;
+[alias] May-aliases after instruction  s->a = i1;  are  { s->a; i1 }
+[alias] May-alias graph after instruction  s->a = i1;  is
+  8:{ s } → 9:{  }   9:{  } -a→ 10:{ i1 }   10:{ i1 } → 12:{  }
+[alias] analysing instruction: s->a = i2;
+[alias] May-aliases after instruction  s->a = i2;  are  { s->a; i2 }
+[alias] May-alias graph after instruction  s->a = i2;  is
+  13:{ s } → 14:{  }   14:{  } -a→ 15:{ i2 }   15:{ i2 } → 17:{  }
+[alias] May-aliases at the end of function jfla: { s->a; i1; i2 }
+[alias] May-alias graph at the end of function jfla:
+  8:{ s } → 9:{  }   9:{  } -a→ 10:{ i1; i2 }   10:{ i1; i2 } → 12:{  }
+[alias] Summary of function jfla:
+  formals: s  i1  i2  b    returns: <none>    state: { s->a; i1; i2 }
+[alias] analysing function: main
+[alias] analysing instruction: int u = 11;
+[alias] May-aliases after instruction  int u = 11;  are  <none>
+[alias] May-alias graph after instruction  int u = 11;  is    <empty>
+[alias] analysing instruction: int v = 12;
+[alias] May-aliases after instruction  int v = 12;  are  <none>
+[alias] May-alias graph after instruction  int v = 12;  is    <empty>
+[alias] analysing instruction: int t[3] = {0, 1, 2};
+[alias] May-aliases after instruction  int t[3] = {0, 1, 2};  are  <none>
+[alias] May-alias graph after instruction  int t[3] = {0, 1, 2};  is    <empty>
+[alias] analysing instruction: int *a = & t[1];
+[alias] May-aliases after instruction  int *a = & t[1];  are  { t; a }
+[alias] May-alias graph after instruction  int *a = & t[1];  is
+  18:{ a } → 19:{  }   20:{ t } → 19:{  }
+[alias] analysing instruction: int *b = & u;
+[alias] May-aliases after instruction  int *b = & u;  are  { t; a }
+[alias] May-alias graph after instruction  int *b = & u;  is
+  18:{ a } → 19:{  }   20:{ t } → 19:{  }   23:{ b } → 24:{ u }
+[alias] analysing instruction: int *c = & v;
+[alias] May-aliases after instruction  int *c = & v;  are  { t; a }
+[alias] May-alias graph after instruction  int *c = & v;  is
+  18:{ a } → 19:{  }   20:{ t } → 19:{  }   23:{ b } → 24:{ u }
+  27:{ c } → 28:{ v }
+[alias] analysing instruction: int **w = & a;
+[alias] May-aliases after instruction  int **w = & a;  are  { *w; t; a }
+[alias] May-alias graph after instruction  int **w = & a;  is
+  20:{ t } → 33:{  }   23:{ b } → 24:{ u }   27:{ c } → 28:{ v }
+  31:{ w } → 32:{ a }   32:{ a } → 33:{  }
+[alias] analysing instruction: str_t *s1 = create_str_t(-1,b);
+[alias] May-aliases after instruction  str_t *s1 = create_str_t(-1,b);  are
+  { s1->b; b }  { *w; t; a }
+[alias] May-alias graph after instruction  str_t *s1 = create_str_t(-1,b);  is
+  20:{ t } → 33:{  }   23:{ b } → 24:{ u }   27:{ c } → 28:{ v }
+  31:{ w } → 32:{ a }   32:{ a } → 33:{  }   36:{  } -a→ 37:{  }
+  36:{  } -b→ 39:{  }   37:{  } → 38:{  }   39:{  } → 24:{ u }
+  41:{ s1 } → 36:{  }
+[alias] analysing instruction: printf("a=%d\n",*(s1->a));
+[alias:undefined:fn] ex_jfla.c:42: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("a=%d\n",*(s1->a));  are
+  { s1->b; b }  { *w; t; a }
+[alias] May-alias graph after instruction  printf("a=%d\n",*(s1->a));  is
+  20:{ t } → 33:{  }   23:{ b } → 24:{ u }   27:{ c } → 28:{ v }
+  31:{ w } → 32:{ a }   32:{ a } → 33:{  }   36:{  } -a→ 37:{  }
+  36:{  } -b→ 39:{  }   37:{  } → 38:{  }   39:{  } → 24:{ u }
+  41:{ s1 } → 36:{  }
+[alias] analysing instruction: printf("b=%d\n",*(s1->b));
+[alias:undefined:fn] ex_jfla.c:43: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("b=%d\n",*(s1->b));  are
+  { s1->b; b }  { *w; t; a }
+[alias] May-alias graph after instruction  printf("b=%d\n",*(s1->b));  is
+  20:{ t } → 33:{  }   23:{ b } → 24:{ u }   27:{ c } → 28:{ v }
+  31:{ w } → 32:{ a }   32:{ a } → 33:{  }   36:{  } -a→ 37:{  }
+  36:{  } -b→ 39:{  }   37:{  } → 38:{  }   39:{  } → 24:{ u }
+  41:{ s1 } → 36:{  }
+[alias] analysing instruction: jfla(s1,a,& t[2],1);
+[alias] May-aliases after instruction  jfla(s1,a,& t[2],1);  are
+  { s1->b; b }  { *w; s1->a; t; a }
+[alias] May-alias graph after instruction  jfla(s1,a,& t[2],1);  is
+  20:{ t } → 33:{  }   23:{ b } → 24:{ u }   27:{ c } → 28:{ v }
+  31:{ w } → 32:{ a }   32:{ a } → 33:{  }   36:{  } -a→ 37:{  }
+  36:{  } -b→ 39:{  }   37:{  } → 33:{  }   39:{  } → 24:{ u }
+  41:{ s1 } → 36:{  }   48:{  } → 33:{  }
+[alias] analysing instruction: printf("a=%d\n",*(s1->a));
+[alias:undefined:fn] ex_jfla.c:45: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("a=%d\n",*(s1->a));  are
+  { s1->b; b }  { *w; s1->a; t; a }
+[alias] May-alias graph after instruction  printf("a=%d\n",*(s1->a));  is
+  20:{ t } → 33:{  }   23:{ b } → 24:{ u }   27:{ c } → 28:{ v }
+  31:{ w } → 32:{ a }   32:{ a } → 33:{  }   36:{  } -a→ 37:{  }
+  36:{  } -b→ 39:{  }   37:{  } → 33:{  }   39:{  } → 24:{ u }
+  41:{ s1 } → 36:{  }   48:{  } → 33:{  }
+[alias] analysing instruction: printf("b=%d\n",*(s1->b));
+[alias:undefined:fn] ex_jfla.c:46: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("b=%d\n",*(s1->b));  are
+  { s1->b; b }  { *w; s1->a; t; a }
+[alias] May-alias graph after instruction  printf("b=%d\n",*(s1->b));  is
+  20:{ t } → 33:{  }   23:{ b } → 24:{ u }   27:{ c } → 28:{ v }
+  31:{ w } → 32:{ a }   32:{ a } → 33:{  }   36:{  } -a→ 37:{  }
+  36:{  } -b→ 39:{  }   37:{  } → 33:{  }   39:{  } → 24:{ u }
+  41:{ s1 } → 36:{  }   48:{  } → 33:{  }
+[alias] analysing instruction: jfla(s1,t,c,0);
+[alias] May-aliases after instruction  jfla(s1,t,c,0);  are
+  { s1->b; b }  { *w; s1->a; t; a; c }
+[alias] May-alias graph after instruction  jfla(s1,t,c,0);  is
+  20:{ t } → 28:{ v }   23:{ b } → 24:{ u }   27:{ c } → 28:{ v }
+  31:{ w } → 32:{ a }   32:{ a } → 28:{ v }   36:{  } -a→ 37:{  }
+  36:{  } -b→ 39:{  }   37:{  } → 28:{ v }   39:{  } → 24:{ u }
+  41:{ s1 } → 36:{  }   48:{  } → 28:{ v }
+[alias] analysing instruction: printf("a=%d\n",*(s1->a));
+[alias:undefined:fn] ex_jfla.c:48: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("a=%d\n",*(s1->a));  are
+  { s1->b; b }  { *w; s1->a; t; a; c }
+[alias] May-alias graph after instruction  printf("a=%d\n",*(s1->a));  is
+  20:{ t } → 28:{ v }   23:{ b } → 24:{ u }   27:{ c } → 28:{ v }
+  31:{ w } → 32:{ a }   32:{ a } → 28:{ v }   36:{  } -a→ 37:{  }
+  36:{  } -b→ 39:{  }   37:{  } → 28:{ v }   39:{  } → 24:{ u }
+  41:{ s1 } → 36:{  }   48:{  } → 28:{ v }
+[alias] analysing instruction: printf("b=%d\n",*(s1->b));
+[alias:undefined:fn] ex_jfla.c:49: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("b=%d\n",*(s1->b));  are
+  { s1->b; b }  { *w; s1->a; t; a; c }
+[alias] May-alias graph after instruction  printf("b=%d\n",*(s1->b));  is
+  20:{ t } → 28:{ v }   23:{ b } → 24:{ u }   27:{ c } → 28:{ v }
+  31:{ w } → 32:{ a }   32:{ a } → 28:{ v }   36:{  } -a→ 37:{  }
+  36:{  } -b→ 39:{  }   37:{  } → 28:{ v }   39:{  } → 24:{ u }
+  41:{ s1 } → 36:{  }   48:{  } → 28:{ v }
+[alias] analysing instruction: __retres = 0;
+[alias] May-aliases after instruction  __retres = 0;  are
+  { s1->b; b }  { *w; s1->a; t; a; c }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  20:{ t } → 28:{ v }   23:{ b } → 24:{ u }   27:{ c } → 28:{ v }
+  31:{ w } → 32:{ a }   32:{ a } → 28:{ v }   36:{  } -a→ 37:{  }
+  36:{  } -b→ 39:{  }   37:{  } → 28:{ v }   39:{  } → 24:{ u }
+  41:{ s1 } → 36:{  }   48:{  } → 28:{ v }
+[alias] May-aliases at the end of function main: { s1->b; b }  { *w; s1->a; t; a; c }
+[alias] May-alias graph at the end of function main:
+  20:{ t } → 28:{ v }   23:{ b } → 24:{ u }   27:{ c } → 28:{ v }
+  31:{ w } → 32:{ a }   32:{ a } → 28:{ v }   36:{  } -a→ 37:{  }
+  36:{  } -b→ 39:{  }   37:{  } → 28:{ v }   39:{  } → 24:{ u }
+  41:{ s1 } → 36:{  }   48:{  } → 28:{ v }
+[alias] Summary of function main:
+  formals:     returns: __retres
+  state: { s1->b; b }  { *w; s1->a; t; a; c }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/fixed_bugs/oracle/ex_jfla_2.res.oracle b/src/plugins/alias/tests/fixed_bugs/oracle/ex_jfla_2.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..769efeed723c2b2da1f61d3ca187a1aa52535647
--- /dev/null
+++ b/src/plugins/alias/tests/fixed_bugs/oracle/ex_jfla_2.res.oracle
@@ -0,0 +1,219 @@
+[kernel] Parsing ex_jfla_2.c (with preprocessing)
+[alias] analysing function: create_str_t
+[alias] analysing instruction: str_t *res = malloc(sizeof(str_t));
+[alias] May-aliases after instruction  str_t *res = malloc(sizeof(str_t));  are
+  <none>
+[alias] May-alias graph after instruction  str_t *res = malloc(sizeof(str_t));  is
+  0:{ res } → 1:{  }
+[alias] analysing instruction: res->fst = (int *)malloc(sizeof(int));
+[alias] May-aliases after instruction  res->fst = (int *)malloc(sizeof(int));  are
+  <none>
+[alias] May-alias graph after instruction  res->fst = (int *)malloc(sizeof(int));
+  is    0:{ res } → 1:{  }   1:{  } -fst→ 2:{  }   2:{  } → 3:{  }
+[alias] analysing instruction: res->snd = (int *)malloc(sizeof(int));
+[alias] May-aliases after instruction  res->snd = (int *)malloc(sizeof(int));  are
+  <none>
+[alias] May-alias graph after instruction  res->snd = (int *)malloc(sizeof(int));
+  is
+  0:{ res } → 1:{  }   1:{  } -fst→ 2:{  }   1:{  } -snd→ 4:{  }
+  2:{  } → 3:{  }   4:{  } → 5:{  }
+[alias] analysing instruction: *(res->fst) = va;
+[alias] May-aliases after instruction  *(res->fst) = va;  are  <none>
+[alias] May-alias graph after instruction  *(res->fst) = va;  is
+  0:{ res } → 1:{  }   1:{  } -fst→ 2:{  }   1:{  } -snd→ 4:{  }
+  2:{  } → 3:{  }   4:{  } → 5:{  }
+[alias] analysing instruction: res->snd = b;
+[alias] May-aliases after instruction  res->snd = b;  are  { res->snd; b }
+[alias] May-alias graph after instruction  res->snd = b;  is
+  0:{ res } → 1:{  }   1:{  } -fst→ 2:{  }   1:{  } -snd→ 4:{ b }
+  2:{  } → 3:{  }   4:{ b } → 5:{  }
+[alias] May-aliases at the end of function create_str_t: { res->snd; b }
+[alias] May-alias graph at the end of function create_str_t:
+  0:{ res } → 1:{  }   1:{  } -fst→ 2:{  }   1:{  } -snd→ 4:{ b }
+  2:{  } → 3:{  }   4:{ b } → 5:{  }
+[alias] Summary of function create_str_t:
+  formals: va  b    returns: res    state: { res->snd; b }
+[alias] analysing function: jfla
+[alias] analysing instruction: *(s->snd) = *(s->fst);
+[alias] May-aliases after instruction  *(s->snd) = *(s->fst);  are  <none>
+[alias] May-alias graph after instruction  *(s->snd) = *(s->fst);  is    <empty>
+[alias] analysing instruction: s->fst = i1;
+[alias] May-aliases after instruction  s->fst = i1;  are  { s->fst; i1 }
+[alias] May-alias graph after instruction  s->fst = i1;  is
+  8:{ s } → 9:{  }   9:{  } -fst→ 10:{ i1 }   10:{ i1 } → 12:{  }
+[alias] analysing instruction: s->fst = i2;
+[alias] May-aliases after instruction  s->fst = i2;  are  { s->fst; i2 }
+[alias] May-alias graph after instruction  s->fst = i2;  is
+  13:{ s } → 14:{  }   14:{  } -fst→ 15:{ i2 }   15:{ i2 } → 17:{  }
+[alias] May-aliases at the end of function jfla: { s->fst; i1; i2 }
+[alias] May-alias graph at the end of function jfla:
+  8:{ s } → 9:{  }   9:{  } -fst→ 10:{ i1; i2 }   10:{ i1; i2 } → 12:{  }
+[alias] Summary of function jfla:
+  formals: s  i1  i2  b    returns: <none>    state: { s->fst; i1; i2 }
+[alias] analysing function: main
+[alias] analysing instruction: int u = 11;
+[alias] May-aliases after instruction  int u = 11;  are  <none>
+[alias] May-alias graph after instruction  int u = 11;  is    <empty>
+[alias] analysing instruction: int v = 12;
+[alias] May-aliases after instruction  int v = 12;  are  <none>
+[alias] May-alias graph after instruction  int v = 12;  is    <empty>
+[alias] analysing instruction: int t[3] = {0, 1, 2};
+[alias] May-aliases after instruction  int t[3] = {0, 1, 2};  are  <none>
+[alias] May-alias graph after instruction  int t[3] = {0, 1, 2};  is    <empty>
+[alias] analysing instruction: int *a = & t[1];
+[alias] May-aliases after instruction  int *a = & t[1];  are  { t; a }
+[alias] May-alias graph after instruction  int *a = & t[1];  is
+  18:{ a } → 19:{  }   20:{ t } → 19:{  }
+[alias] analysing instruction: int *b = & u;
+[alias] May-aliases after instruction  int *b = & u;  are  { t; a }
+[alias] May-alias graph after instruction  int *b = & u;  is
+  18:{ a } → 19:{  }   20:{ t } → 19:{  }   23:{ b } → 24:{ u }
+[alias] analysing instruction: int *c = & v;
+[alias] May-aliases after instruction  int *c = & v;  are  { t; a }
+[alias] May-alias graph after instruction  int *c = & v;  is
+  18:{ a } → 19:{  }   20:{ t } → 19:{  }   23:{ b } → 24:{ u }
+  27:{ c } → 28:{ v }
+[alias] analysing instruction: int **x = & a;
+[alias] May-aliases after instruction  int **x = & a;  are  { *x; t; a }
+[alias] May-alias graph after instruction  int **x = & a;  is
+  20:{ t } → 33:{  }   23:{ b } → 24:{ u }   27:{ c } → 28:{ v }
+  31:{ x } → 32:{ a }   32:{ a } → 33:{  }
+[alias] analysing instruction: int **y = & b;
+[alias] May-aliases after instruction  int **y = & b;  are  { *x; t; a }  { *y; b }
+[alias] May-alias graph after instruction  int **y = & b;  is
+  20:{ t } → 33:{  }   27:{ c } → 28:{ v }   31:{ x } → 32:{ a }
+  32:{ a } → 33:{  }   35:{ y } → 36:{ b }   36:{ b } → 37:{ u }
+[alias] analysing instruction: int **z = & c;
+[alias] May-aliases after instruction  int **z = & c;  are
+  { *x; t; a }  { *y; b }  { *z; c }
+[alias] May-alias graph after instruction  int **z = & c;  is
+  20:{ t } → 33:{  }   31:{ x } → 32:{ a }   32:{ a } → 33:{  }
+  35:{ y } → 36:{ b }   36:{ b } → 37:{ u }   39:{ z } → 40:{ c }
+  40:{ c } → 41:{ v }
+[alias] analysing instruction: str_t *s1 = create_str_t(-1,b);
+[alias] May-aliases after instruction  str_t *s1 = create_str_t(-1,b);  are
+  { *x; t; a }  { *y; s1->snd; b }  { *z; c }
+[alias] May-alias graph after instruction  str_t *s1 = create_str_t(-1,b);  is
+  20:{ t } → 33:{  }   31:{ x } → 32:{ a }   32:{ a } → 33:{  }
+  35:{ y } → 36:{ b }   36:{ b } → 37:{ u }   39:{ z } → 40:{ c }
+  40:{ c } → 41:{ v }   44:{  } -fst→ 45:{  }   44:{  } -snd→ 47:{  }
+  45:{  } → 46:{  }   47:{  } → 37:{ u }   49:{ s1 } → 44:{  }
+[alias] analysing instruction: str_t *s2 = create_str_t(-2,c);
+[alias] May-aliases after instruction  str_t *s2 = create_str_t(-2,c);  are
+  { *x; t; a }  { *y; s1->snd; b }  { *z; s2->snd; c }
+[alias] May-alias graph after instruction  str_t *s2 = create_str_t(-2,c);  is
+  20:{ t } → 33:{  }   31:{ x } → 32:{ a }   32:{ a } → 33:{  }
+  35:{ y } → 36:{ b }   36:{ b } → 37:{ u }   39:{ z } → 40:{ c }
+  40:{ c } → 41:{ v }   44:{  } -fst→ 45:{  }   44:{  } -snd→ 47:{  }
+  45:{  } → 46:{  }   47:{  } → 37:{ u }   49:{ s1 } → 44:{  }
+  52:{  } -fst→ 53:{  }   52:{  } -snd→ 55:{  }   53:{  } → 54:{  }
+  55:{  } → 41:{ v }   57:{ s2 } → 52:{  }
+[alias] analysing instruction: printf("a=%d\n",*(s1->fst));
+[alias:undefined:fn] ex_jfla_2.c:43: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("a=%d\n",*(s1->fst));  are
+  { *x; t; a }  { *y; s1->snd; b }  { *z; s2->snd; c }
+[alias] May-alias graph after instruction  printf("a=%d\n",*(s1->fst));  is
+  20:{ t } → 33:{  }   31:{ x } → 32:{ a }   32:{ a } → 33:{  }
+  35:{ y } → 36:{ b }   36:{ b } → 37:{ u }   39:{ z } → 40:{ c }
+  40:{ c } → 41:{ v }   44:{  } -fst→ 45:{  }   44:{  } -snd→ 47:{  }
+  45:{  } → 46:{  }   47:{  } → 37:{ u }   49:{ s1 } → 44:{  }
+  52:{  } -fst→ 53:{  }   52:{  } -snd→ 55:{  }   53:{  } → 54:{  }
+  55:{  } → 41:{ v }   57:{ s2 } → 52:{  }
+[alias] analysing instruction: printf("b=%d\n",*(s1->snd));
+[alias:undefined:fn] ex_jfla_2.c:44: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("b=%d\n",*(s1->snd));  are
+  { *x; t; a }  { *y; s1->snd; b }  { *z; s2->snd; c }
+[alias] May-alias graph after instruction  printf("b=%d\n",*(s1->snd));  is
+  20:{ t } → 33:{  }   31:{ x } → 32:{ a }   32:{ a } → 33:{  }
+  35:{ y } → 36:{ b }   36:{ b } → 37:{ u }   39:{ z } → 40:{ c }
+  40:{ c } → 41:{ v }   44:{  } -fst→ 45:{  }   44:{  } -snd→ 47:{  }
+  45:{  } → 46:{  }   47:{  } → 37:{ u }   49:{ s1 } → 44:{  }
+  52:{  } -fst→ 53:{  }   52:{  } -snd→ 55:{  }   53:{  } → 54:{  }
+  55:{  } → 41:{ v }   57:{ s2 } → 52:{  }
+[alias] analysing instruction: jfla(s1,a,& t[2],1);
+[alias] May-aliases after instruction  jfla(s1,a,& t[2],1);  are
+  { *x; s1->fst; t; a }  { *y; s1->snd; b }  { *z; s2->snd; c }
+[alias] May-alias graph after instruction  jfla(s1,a,& t[2],1);  is
+  20:{ t } → 33:{  }   31:{ x } → 32:{ a }   32:{ a } → 33:{  }
+  35:{ y } → 36:{ b }   36:{ b } → 37:{ u }   39:{ z } → 40:{ c }
+  40:{ c } → 41:{ v }   44:{  } -fst→ 45:{  }   44:{  } -snd→ 47:{  }
+  45:{  } → 33:{  }   47:{  } → 37:{ u }   49:{ s1 } → 44:{  }
+  52:{  } -fst→ 53:{  }   52:{  } -snd→ 55:{  }   53:{  } → 54:{  }
+  55:{  } → 41:{ v }   57:{ s2 } → 52:{  }   64:{  } → 33:{  }
+[alias] analysing instruction: printf("a=%d\n",*(s1->fst));
+[alias:undefined:fn] ex_jfla_2.c:46: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("a=%d\n",*(s1->fst));  are
+  { *x; s1->fst; t; a }  { *y; s1->snd; b }  { *z; s2->snd; c }
+[alias] May-alias graph after instruction  printf("a=%d\n",*(s1->fst));  is
+  20:{ t } → 33:{  }   31:{ x } → 32:{ a }   32:{ a } → 33:{  }
+  35:{ y } → 36:{ b }   36:{ b } → 37:{ u }   39:{ z } → 40:{ c }
+  40:{ c } → 41:{ v }   44:{  } -fst→ 45:{  }   44:{  } -snd→ 47:{  }
+  45:{  } → 33:{  }   47:{  } → 37:{ u }   49:{ s1 } → 44:{  }
+  52:{  } -fst→ 53:{  }   52:{  } -snd→ 55:{  }   53:{  } → 54:{  }
+  55:{  } → 41:{ v }   57:{ s2 } → 52:{  }   64:{  } → 33:{  }
+[alias] analysing instruction: printf("b=%d\n",*(s1->snd));
+[alias:undefined:fn] ex_jfla_2.c:47: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("b=%d\n",*(s1->snd));  are
+  { *x; s1->fst; t; a }  { *y; s1->snd; b }  { *z; s2->snd; c }
+[alias] May-alias graph after instruction  printf("b=%d\n",*(s1->snd));  is
+  20:{ t } → 33:{  }   31:{ x } → 32:{ a }   32:{ a } → 33:{  }
+  35:{ y } → 36:{ b }   36:{ b } → 37:{ u }   39:{ z } → 40:{ c }
+  40:{ c } → 41:{ v }   44:{  } -fst→ 45:{  }   44:{  } -snd→ 47:{  }
+  45:{  } → 33:{  }   47:{  } → 37:{ u }   49:{ s1 } → 44:{  }
+  52:{  } -fst→ 53:{  }   52:{  } -snd→ 55:{  }   53:{  } → 54:{  }
+  55:{  } → 41:{ v }   57:{ s2 } → 52:{  }   64:{  } → 33:{  }
+[alias] analysing instruction: jfla(s1,t,s2->snd,0);
+[alias] May-aliases after instruction  jfla(s1,t,s2->snd,0);  are
+  { *x; *z; s1->fst; s2->snd; t; a; c }  { *y; s1->snd; b }
+[alias] May-alias graph after instruction  jfla(s1,t,s2->snd,0);  is
+  20:{ t } → 33:{ v }   31:{ x } → 32:{ a }   32:{ a } → 33:{ v }
+  35:{ y } → 36:{ b }   36:{ b } → 37:{ u }   39:{ z } → 40:{ c }
+  40:{ c } → 33:{ v }   44:{  } -fst→ 45:{  }   44:{  } -snd→ 47:{  }
+  45:{  } → 33:{ v }   47:{  } → 37:{ u }   49:{ s1 } → 44:{  }
+  52:{  } -fst→ 53:{  }   52:{  } -snd→ 55:{  }   53:{  } → 54:{  }
+  55:{  } → 33:{ v }   57:{ s2 } → 52:{  }   64:{  } → 33:{ v }
+[alias] analysing instruction: printf("a=%d\n",*(s1->fst));
+[alias:undefined:fn] ex_jfla_2.c:49: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("a=%d\n",*(s1->fst));  are
+  { *x; *z; s1->fst; s2->snd; t; a; c }  { *y; s1->snd; b }
+[alias] May-alias graph after instruction  printf("a=%d\n",*(s1->fst));  is
+  20:{ t } → 33:{ v }   31:{ x } → 32:{ a }   32:{ a } → 33:{ v }
+  35:{ y } → 36:{ b }   36:{ b } → 37:{ u }   39:{ z } → 40:{ c }
+  40:{ c } → 33:{ v }   44:{  } -fst→ 45:{  }   44:{  } -snd→ 47:{  }
+  45:{  } → 33:{ v }   47:{  } → 37:{ u }   49:{ s1 } → 44:{  }
+  52:{  } -fst→ 53:{  }   52:{  } -snd→ 55:{  }   53:{  } → 54:{  }
+  55:{  } → 33:{ v }   57:{ s2 } → 52:{  }   64:{  } → 33:{ v }
+[alias] analysing instruction: printf("b=%d\n",*(s1->snd));
+[alias:undefined:fn] ex_jfla_2.c:50: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("b=%d\n",*(s1->snd));  are
+  { *x; *z; s1->fst; s2->snd; t; a; c }  { *y; s1->snd; b }
+[alias] May-alias graph after instruction  printf("b=%d\n",*(s1->snd));  is
+  20:{ t } → 33:{ v }   31:{ x } → 32:{ a }   32:{ a } → 33:{ v }
+  35:{ y } → 36:{ b }   36:{ b } → 37:{ u }   39:{ z } → 40:{ c }
+  40:{ c } → 33:{ v }   44:{  } -fst→ 45:{  }   44:{  } -snd→ 47:{  }
+  45:{  } → 33:{ v }   47:{  } → 37:{ u }   49:{ s1 } → 44:{  }
+  52:{  } -fst→ 53:{  }   52:{  } -snd→ 55:{  }   53:{  } → 54:{  }
+  55:{  } → 33:{ v }   57:{ s2 } → 52:{  }   64:{  } → 33:{ v }
+[alias] analysing instruction: __retres = 0;
+[alias] May-aliases after instruction  __retres = 0;  are
+  { *x; *z; s1->fst; s2->snd; t; a; c }  { *y; s1->snd; b }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  20:{ t } → 33:{ v }   31:{ x } → 32:{ a }   32:{ a } → 33:{ v }
+  35:{ y } → 36:{ b }   36:{ b } → 37:{ u }   39:{ z } → 40:{ c }
+  40:{ c } → 33:{ v }   44:{  } -fst→ 45:{  }   44:{  } -snd→ 47:{  }
+  45:{  } → 33:{ v }   47:{  } → 37:{ u }   49:{ s1 } → 44:{  }
+  52:{  } -fst→ 53:{  }   52:{  } -snd→ 55:{  }   53:{  } → 54:{  }
+  55:{  } → 33:{ v }   57:{ s2 } → 52:{  }   64:{  } → 33:{ v }
+[alias] May-aliases at the end of function main:
+  { *x; *z; s1->fst; s2->snd; t; a; c }  { *y; s1->snd; b }
+[alias] May-alias graph at the end of function main:
+  20:{ t } → 33:{ v }   31:{ x } → 32:{ a }   32:{ a } → 33:{ v }
+  35:{ y } → 36:{ b }   36:{ b } → 37:{ u }   39:{ z } → 40:{ c }
+  40:{ c } → 33:{ v }   44:{  } -fst→ 45:{  }   44:{  } -snd→ 47:{  }
+  45:{  } → 33:{ v }   47:{  } → 37:{ u }   49:{ s1 } → 44:{  }
+  52:{  } -fst→ 53:{  }   52:{  } -snd→ 55:{  }   53:{  } → 54:{  }
+  55:{  } → 33:{ v }   57:{ s2 } → 52:{  }   64:{  } → 33:{ v }
+[alias] Summary of function main:
+  formals:     returns: __retres
+  state: { *x; *z; s1->fst; s2->snd; t; a; c }  { *y; s1->snd; b }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/fixed_bugs/oracle/ex_jfla_3.res.oracle b/src/plugins/alias/tests/fixed_bugs/oracle/ex_jfla_3.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..5237ddd1cfe5950a50994b9475242ff8931d059f
--- /dev/null
+++ b/src/plugins/alias/tests/fixed_bugs/oracle/ex_jfla_3.res.oracle
@@ -0,0 +1,208 @@
+[kernel] Parsing ex_jfla_3.c (with preprocessing)
+[alias] analysing function: jfla
+[alias] analysing instruction: *snd = *fst;
+[alias] May-aliases after instruction  *snd = *fst;  are  <none>
+[alias] May-alias graph after instruction  *snd = *fst;  is    <empty>
+[alias] analysing instruction: fst = *i1;
+[alias] May-aliases after instruction  fst = *i1;  are  { *i1; fst }
+[alias] May-alias graph after instruction  fst = *i1;  is
+  0:{ fst } → 1:{  }   2:{ i1 } → 0:{ fst }
+[alias] analysing instruction: __retres = *i2;
+[alias] May-aliases after instruction  __retres = *i2;  are
+  { *i1; fst }  { *i2; __retres }
+[alias] May-alias graph after instruction  __retres = *i2;  is
+  0:{ fst } → 1:{  }   2:{ i1 } → 0:{ fst }   5:{ __retres } → 6:{  }
+  7:{ i2 } → 5:{ __retres }
+[alias] analysing instruction: fst = *i2;
+[alias] May-aliases after instruction  fst = *i2;  are  { *i2; fst }
+[alias] May-alias graph after instruction  fst = *i2;  is
+  10:{ fst } → 11:{  }   12:{ i2 } → 10:{ fst }
+[alias] analysing instruction: __retres = *i1;
+[alias] May-aliases after instruction  __retres = *i1;  are
+  { *i2; fst }  { *i1; __retres }
+[alias] May-alias graph after instruction  __retres = *i1;  is
+  10:{ fst } → 11:{  }   12:{ i2 } → 10:{ fst }
+  15:{ __retres } → 16:{  }   17:{ i1 } → 15:{ __retres }
+[alias] May-aliases at the end of function jfla:
+  { i1; i2 }  { *i1; *i2; fst; __retres }
+[alias] May-alias graph at the end of function jfla:
+  0:{ fst; __retres } → 1:{  }   2:{ i1 } → 0:{ fst; __retres }
+  7:{ i2 } → 0:{ fst; __retres }
+[alias] Summary of function jfla:
+  formals: fst  snd  i1→{ fst; __retres }  i2→{ fst; __retres }  bo
+  returns: __retres    state: { i1; i2 }  { *i1; *i2; fst; __retres }
+[alias] analysing function: main
+[alias] analysing instruction: int u = 11;
+[alias] May-aliases after instruction  int u = 11;  are  <none>
+[alias] May-alias graph after instruction  int u = 11;  is    <empty>
+[alias] analysing instruction: int v = 12;
+[alias] May-aliases after instruction  int v = 12;  are  <none>
+[alias] May-alias graph after instruction  int v = 12;  is    <empty>
+[alias] analysing instruction: int t[3] = {0, 1, 2};
+[alias] May-aliases after instruction  int t[3] = {0, 1, 2};  are  <none>
+[alias] May-alias graph after instruction  int t[3] = {0, 1, 2};  is    <empty>
+[alias] analysing instruction: int *a = & t[1];
+[alias] May-aliases after instruction  int *a = & t[1];  are  { t; a }
+[alias] May-alias graph after instruction  int *a = & t[1];  is
+  20:{ a } → 21:{  }   22:{ t } → 21:{  }
+[alias] analysing instruction: int *b = & u;
+[alias] May-aliases after instruction  int *b = & u;  are  { t; a }
+[alias] May-alias graph after instruction  int *b = & u;  is
+  20:{ a } → 21:{  }   22:{ t } → 21:{  }   25:{ b } → 26:{ u }
+[alias] analysing instruction: int *c = & v;
+[alias] May-aliases after instruction  int *c = & v;  are  { t; a }
+[alias] May-alias graph after instruction  int *c = & v;  is
+  20:{ a } → 21:{  }   22:{ t } → 21:{  }   25:{ b } → 26:{ u }
+  29:{ c } → 30:{ v }
+[alias] analysing instruction: int **x = & a;
+[alias] May-aliases after instruction  int **x = & a;  are  { *x; t; a }
+[alias] May-alias graph after instruction  int **x = & a;  is
+  22:{ t } → 35:{  }   25:{ b } → 26:{ u }   29:{ c } → 30:{ v }
+  33:{ x } → 34:{ a }   34:{ a } → 35:{  }
+[alias] analysing instruction: int **y = & b;
+[alias] May-aliases after instruction  int **y = & b;  are  { *x; t; a }  { *y; b }
+[alias] May-alias graph after instruction  int **y = & b;  is
+  22:{ t } → 35:{  }   29:{ c } → 30:{ v }   33:{ x } → 34:{ a }
+  34:{ a } → 35:{  }   37:{ y } → 38:{ b }   38:{ b } → 39:{ u }
+[alias] analysing instruction: int **z = & c;
+[alias] May-aliases after instruction  int **z = & c;  are
+  { *x; t; a }  { *y; b }  { *z; c }
+[alias] May-alias graph after instruction  int **z = & c;  is
+  22:{ t } → 35:{  }   33:{ x } → 34:{ a }   34:{ a } → 35:{  }
+  37:{ y } → 38:{ b }   38:{ b } → 39:{ u }   41:{ z } → 42:{ c }
+  42:{ c } → 43:{ v }
+[alias] analysing instruction: struct str_t s = {.fst = c, .snd = t};
+[alias] May-aliases after instruction  struct str_t s = {.fst = c, .snd = t};  are
+  { *x; t; a; s.snd }  { *y; b }  { *z; c; s.fst }
+[alias] May-alias graph after instruction  struct str_t s = {.fst = c, .snd = t};
+  is
+  33:{ x } → 34:{ a }   34:{ a } → 35:{  }   37:{ y } → 38:{ b }
+  38:{ b } → 39:{ u }   41:{ z } → 46:{ c }   45:{ s } -fst→ 46:{ c }
+  45:{ s } -snd→ 47:{ t }   46:{ c } → 43:{ v }   47:{ t } → 35:{  }
+[alias] analysing instruction: struct str_t *s1 = & s;
+[alias] May-aliases after instruction  struct str_t *s1 = & s;  are
+  { *x; s1->snd; t; a; s.snd }  { *y; b }  { *z; s1->fst; c; s.fst }
+[alias] May-alias graph after instruction  struct str_t *s1 = & s;  is
+  33:{ x } → 34:{ a }   34:{ a } → 35:{  }   37:{ y } → 38:{ b }
+  38:{ b } → 39:{ u }   41:{ z } → 46:{ c }   46:{ c } → 43:{ v }
+  47:{ t } → 35:{  }   48:{ s1 } → 49:{ s }   49:{ s } -fst→ 46:{ c }
+  49:{ s } -snd→ 47:{ t }
+[alias] analysing instruction: struct str_t *s2 = & s;
+[alias] May-aliases after instruction  struct str_t *s2 = & s;  are
+  { *x; s1->snd; s2->snd; t; a; s.snd }  { *y; b }
+  { *z; s1->fst; s2->fst; c; s.fst }  { s1; s2 }
+[alias] May-alias graph after instruction  struct str_t *s2 = & s;  is
+  33:{ x } → 34:{ a }   34:{ a } → 35:{  }   37:{ y } → 38:{ b }
+  38:{ b } → 39:{ u }   41:{ z } → 46:{ c }   46:{ c } → 43:{ v }
+  47:{ t } → 35:{  }   48:{ s1 } → 52:{ s }   51:{ s2 } → 52:{ s }
+  52:{ s } -fst→ 46:{ c }   52:{ s } -snd→ 47:{ t }
+[alias] analysing instruction: printf("a=%d\n",*(s1->fst));
+[alias:undefined:fn] ex_jfla_3.c:32: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("a=%d\n",*(s1->fst));  are
+  { *x; s1->snd; s2->snd; t; a; s.snd }  { *y; b }
+  { *z; s1->fst; s2->fst; c; s.fst }  { s1; s2 }
+[alias] May-alias graph after instruction  printf("a=%d\n",*(s1->fst));  is
+  33:{ x } → 34:{ a }   34:{ a } → 35:{  }   37:{ y } → 38:{ b }
+  38:{ b } → 39:{ u }   41:{ z } → 46:{ c }   46:{ c } → 43:{ v }
+  47:{ t } → 35:{  }   48:{ s1 } → 52:{ s }   51:{ s2 } → 52:{ s }
+  52:{ s } -fst→ 46:{ c }   52:{ s } -snd→ 47:{ t }
+[alias] analysing instruction: printf("b=%d\n",*(s1->snd));
+[alias:undefined:fn] ex_jfla_3.c:33: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("b=%d\n",*(s1->snd));  are
+  { *x; s1->snd; s2->snd; t; a; s.snd }  { *y; b }
+  { *z; s1->fst; s2->fst; c; s.fst }  { s1; s2 }
+[alias] May-alias graph after instruction  printf("b=%d\n",*(s1->snd));  is
+  33:{ x } → 34:{ a }   34:{ a } → 35:{  }   37:{ y } → 38:{ b }
+  38:{ b } → 39:{ u }   41:{ z } → 46:{ c }   46:{ c } → 43:{ v }
+  47:{ t } → 35:{  }   48:{ s1 } → 52:{ s }   51:{ s2 } → 52:{ s }
+  52:{ s } -fst→ 46:{ c }   52:{ s } -snd→ 47:{ t }
+[alias] analysing instruction: c = jfla(s1->fst,s1->snd,x,y,0);
+[alias] May-aliases after instruction  c = jfla(s1->fst,s1->snd,x,y,0);  are
+  { x; y }
+  { *x; *y; *z; s1->fst; s1->snd; s2->fst; s2->snd; t; a; b; c; s.fst; s.snd }
+  { s1; s2 }
+[alias] May-alias graph after instruction  c = jfla(s1->fst,s1->snd,x,y,0);  is
+  33:{ x } → 34:{ a; b }   34:{ a; b } → 35:{ u; v }
+  37:{ y } → 34:{ a; b }   41:{ z } → 46:{ c }   46:{ c } → 35:{ u; v }
+  47:{ t } → 35:{ u; v }   48:{ s1 } → 52:{ s }   51:{ s2 } → 52:{ s }
+  52:{ s } -fst→ 46:{ c }   52:{ s } -snd→ 47:{ t }
+[alias] analysing instruction: printf("a=%d\n",*(s1->fst));
+[alias:undefined:fn] ex_jfla_3.c:35: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("a=%d\n",*(s1->fst));  are
+  { x; y }
+  { *x; *y; *z; s1->fst; s1->snd; s2->fst; s2->snd; t; a; b; c; s.fst; s.snd }
+  { s1; s2 }
+[alias] May-alias graph after instruction  printf("a=%d\n",*(s1->fst));  is
+  33:{ x } → 34:{ a; b }   34:{ a; b } → 35:{ u; v }
+  37:{ y } → 34:{ a; b }   41:{ z } → 46:{ c }   46:{ c } → 35:{ u; v }
+  47:{ t } → 35:{ u; v }   48:{ s1 } → 52:{ s }   51:{ s2 } → 52:{ s }
+  52:{ s } -fst→ 46:{ c }   52:{ s } -snd→ 47:{ t }
+[alias] analysing instruction: printf("b=%d\n",*(s1->snd));
+[alias:undefined:fn] ex_jfla_3.c:36: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("b=%d\n",*(s1->snd));  are
+  { x; y }
+  { *x; *y; *z; s1->fst; s1->snd; s2->fst; s2->snd; t; a; b; c; s.fst; s.snd }
+  { s1; s2 }
+[alias] May-alias graph after instruction  printf("b=%d\n",*(s1->snd));  is
+  33:{ x } → 34:{ a; b }   34:{ a; b } → 35:{ u; v }
+  37:{ y } → 34:{ a; b }   41:{ z } → 46:{ c }   46:{ c } → 35:{ u; v }
+  47:{ t } → 35:{ u; v }   48:{ s1 } → 52:{ s }   51:{ s2 } → 52:{ s }
+  52:{ s } -fst→ 46:{ c }   52:{ s } -snd→ 47:{ t }
+[alias] analysing instruction: a = jfla(s2->fst,s2->snd,y,z,1);
+[alias] May-aliases after instruction  a = jfla(s2->fst,s2->snd,y,z,1);  are
+  { x; y; z }
+  { *x; *y; *z; s1->fst; s1->snd; s2->fst; s2->snd; t; a; b; c; s.fst; s.snd }
+  { s1; s2 }
+[alias] May-alias graph after instruction  a = jfla(s2->fst,s2->snd,y,z,1);  is
+  33:{ x } → 34:{ a; b; c }   34:{ a; b; c } → 35:{ u; v }
+  37:{ y } → 34:{ a; b; c }   41:{ z } → 34:{ a; b; c }
+  47:{ t } → 35:{ u; v }   48:{ s1 } → 52:{ s }   51:{ s2 } → 52:{ s }
+  52:{ s } -fst→ 34:{ a; b; c }   52:{ s } -snd→ 47:{ t }
+[alias] analysing instruction: printf("a=%d\n",*(s1->fst));
+[alias:undefined:fn] ex_jfla_3.c:38: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("a=%d\n",*(s1->fst));  are
+  { x; y; z }
+  { *x; *y; *z; s1->fst; s1->snd; s2->fst; s2->snd; t; a; b; c; s.fst; s.snd }
+  { s1; s2 }
+[alias] May-alias graph after instruction  printf("a=%d\n",*(s1->fst));  is
+  33:{ x } → 34:{ a; b; c }   34:{ a; b; c } → 35:{ u; v }
+  37:{ y } → 34:{ a; b; c }   41:{ z } → 34:{ a; b; c }
+  47:{ t } → 35:{ u; v }   48:{ s1 } → 52:{ s }   51:{ s2 } → 52:{ s }
+  52:{ s } -fst→ 34:{ a; b; c }   52:{ s } -snd→ 47:{ t }
+[alias] analysing instruction: printf("b=%d\n",*(s1->snd));
+[alias:undefined:fn] ex_jfla_3.c:39: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("b=%d\n",*(s1->snd));  are
+  { x; y; z }
+  { *x; *y; *z; s1->fst; s1->snd; s2->fst; s2->snd; t; a; b; c; s.fst; s.snd }
+  { s1; s2 }
+[alias] May-alias graph after instruction  printf("b=%d\n",*(s1->snd));  is
+  33:{ x } → 34:{ a; b; c }   34:{ a; b; c } → 35:{ u; v }
+  37:{ y } → 34:{ a; b; c }   41:{ z } → 34:{ a; b; c }
+  47:{ t } → 35:{ u; v }   48:{ s1 } → 52:{ s }   51:{ s2 } → 52:{ s }
+  52:{ s } -fst→ 34:{ a; b; c }   52:{ s } -snd→ 47:{ t }
+[alias] analysing instruction: __retres = 0;
+[alias] May-aliases after instruction  __retres = 0;  are
+  { x; y; z }
+  { *x; *y; *z; s1->fst; s1->snd; s2->fst; s2->snd; t; a; b; c; s.fst; s.snd }
+  { s1; s2 }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  33:{ x } → 34:{ a; b; c }   34:{ a; b; c } → 35:{ u; v }
+  37:{ y } → 34:{ a; b; c }   41:{ z } → 34:{ a; b; c }
+  47:{ t } → 35:{ u; v }   48:{ s1 } → 52:{ s }   51:{ s2 } → 52:{ s }
+  52:{ s } -fst→ 34:{ a; b; c }   52:{ s } -snd→ 47:{ t }
+[alias] May-aliases at the end of function main:
+  { x; y; z }
+  { *x; *y; *z; s1->fst; s1->snd; s2->fst; s2->snd; t; a; b; c; s.fst; s.snd }
+  { s1; s2 }
+[alias] May-alias graph at the end of function main:
+  33:{ x } → 34:{ a; b; c }   34:{ a; b; c } → 35:{ u; v }
+  37:{ y } → 34:{ a; b; c }   41:{ z } → 34:{ a; b; c }
+  47:{ t } → 35:{ u; v }   48:{ s1 } → 52:{ s }   51:{ s2 } → 52:{ s }
+  52:{ s } -fst→ 34:{ a; b; c }   52:{ s } -snd→ 47:{ t }
+[alias] Summary of function main:
+  formals:     returns: __retres
+  state: { x; y; z }
+         { *x; *y; *z; s1->fst; s1->snd; s2->fst; s2->snd; t; a; b; c; 
+           s.fst; s.snd }
+         { s1; s2 }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/fixed_bugs/oracle/gzip124.res.oracle b/src/plugins/alias/tests/fixed_bugs/oracle/gzip124.res.oracle
index fd9878fef65bf1ea35de5b51eef9ccfe7b40d5a0..2b5f051f79fac140c48681375ab0b95ae221d013 100644
--- a/src/plugins/alias/tests/fixed_bugs/oracle/gzip124.res.oracle
+++ b/src/plugins/alias/tests/fixed_bugs/oracle/gzip124.res.oracle
@@ -2,14 +2,28 @@
 [alias] analysing function: main
 [alias] analysing instruction: short tmp_0 = (short)0;
 [alias] May-aliases after instruction  short tmp_0 = (short)0;  are  <none>
+[alias] May-alias graph after instruction  short tmp_0 = (short)0;  is    <empty>
 [alias] analysing instruction: *(& prev[1] + 0) = tmp_0;
 [alias] May-aliases after instruction  *(& prev[1] + 0) = tmp_0;  are  <none>
+[alias] May-alias graph after instruction  *(& prev[1] + 0) = tmp_0;  is    <empty>
 [alias] analysing instruction: prev[0] = (short)0;
 [alias] May-aliases after instruction  prev[0] = (short)0;  are  <none>
+[alias] May-alias graph after instruction  prev[0] = (short)0;  is    <empty>
 [alias] analysing instruction: p = & prev[1] + (int)*p;
-[alias] May-aliases after instruction  p = & prev[1] + (int)*p;  are  <none>
+[alias] May-aliases after instruction  p = & prev[1] + (int)*p;  are  { prev; p }
+[alias] May-alias graph after instruction  p = & prev[1] + (int)*p;  is
+  0:{ p } → 1:{  }   2:{ prev } → 1:{  }
 [alias] analysing instruction: p = & prev[*p];
-[alias] May-aliases after instruction  p = & prev[*p];  are  <none>
+[alias] May-aliases after instruction  p = & prev[*p];  are  { prev; p }
+[alias] May-alias graph after instruction  p = & prev[*p];  is
+  5:{ p } → 6:{  }   7:{ prev } → 6:{  }
 [alias] analysing instruction: __retres = 0;
-[alias] May-aliases after instruction  __retres = 0;  are  <none>
-[alias] May-aliases at the end of function main: <none>
+[alias] May-aliases after instruction  __retres = 0;  are  { prev; p }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ p } → 1:{  }   2:{ prev } → 1:{  }
+[alias] May-aliases at the end of function main: { prev; p }
+[alias] May-alias graph at the end of function main:
+  0:{ p } → 1:{  }   2:{ prev } → 1:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { prev; p }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/fixed_bugs/oracle/origin.res.oracle b/src/plugins/alias/tests/fixed_bugs/oracle/origin.res.oracle
index 5804eca90b42b52e9398c876abd3db981aa95c13..32f600115b8584bdd15261cae93e8887982b4f0f 100644
--- a/src/plugins/alias/tests/fixed_bugs/oracle/origin.res.oracle
+++ b/src/plugins/alias/tests/fixed_bugs/oracle/origin.res.oracle
@@ -4,11 +4,25 @@
 [alias] analysing function: f
 [alias] analysing instruction: tmp = & f;
 [alias] May-aliases after instruction  tmp = & f;  are  <none>
+[alias] May-alias graph after instruction  tmp = & f;  is    0:{ tmp } → 1:{ f }
 [alias] analysing instruction: tmp = (void (*)(void))*((char *)(v.t));
-[alias:unsafe-cast] origin.c:8: Warning: unsafe cast from char to void (*)(void)
-[alias:unsafe-cast] origin.c:8: Warning: unsafe cast from int * to char *
+[alias:unsafe-cast] origin.c:8: Warning: 
+  unsafe cast from char to void (*)(void); analysis may be unsound
+[alias:unsafe-cast] origin.c:8: Warning: 
+  unsafe cast from int * to char *; analysis may be unsound
 [alias] May-aliases after instruction  tmp = (void (*)(void))*((char *)(v.t));  are
-  { v.t; tmp }
+  { v.t[0..]; tmp }
+[alias] May-alias graph after instruction  tmp = (void (*)(void))*((char *)(v.t));
+  is    0:{ tmp } → 1:{ f }   4:{ v } -t→ 5:{  }   5:{  } → 0:{ tmp }
 [alias] analysing instruction: int g = (int)tmp;
-[alias] May-aliases after instruction  int g = (int)tmp;  are  { v.t; tmp }
-[alias] May-aliases at the end of function f: { v.t; tmp }
+[alias:unsafe-cast] origin.c:8: Warning: 
+  unsafe cast from void (*)(void) to int; analysis may be unsound
+[alias] May-aliases after instruction  int g = (int)tmp;  are  { v.t[0..]; tmp }
+[alias] May-alias graph after instruction  int g = (int)tmp;  is
+  0:{ tmp } → 1:{ f }   4:{ v } -t→ 5:{  }   5:{  } → 0:{ tmp }
+[alias] May-aliases at the end of function f: { v.t[0..]; tmp }
+[alias] May-alias graph at the end of function f:
+  0:{ tmp } → 1:{ f }   4:{ v } -t→ 5:{  }   5:{  } → 0:{ tmp }
+[alias] Summary of function f:
+  formals:     returns: <none>    state: { v.t[0..]; tmp }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/fixed_bugs/oracle/origin_simpl.res.oracle b/src/plugins/alias/tests/fixed_bugs/oracle/origin_simpl.res.oracle
index e0e7350e8bb270bc2ab56b5fba3c3e9f0c191f38..c2c8ab976e07eaa3512215cc56e5a9eeba759cae 100644
--- a/src/plugins/alias/tests/fixed_bugs/oracle/origin_simpl.res.oracle
+++ b/src/plugins/alias/tests/fixed_bugs/oracle/origin_simpl.res.oracle
@@ -1,7 +1,17 @@
 [kernel] Parsing origin_simpl.c (with preprocessing)
 [alias] analysing function: f
 [alias] analysing instruction: tmp = (void *)*((int *)(t));
-[alias:unsafe-cast] origin_simpl.c:9: Warning: unsafe cast from int to void *
-[alias:unsafe-cast] origin_simpl.c:9: Warning: unsafe cast from char * to int *
-[alias] May-aliases after instruction  tmp = (void *)*((int *)(t));  are  { t; tmp }
-[alias] May-aliases at the end of function f: { t; tmp }
+[alias:unsafe-cast] origin_simpl.c:9: Warning: 
+  unsafe cast from int to void *; analysis may be unsound
+[alias:unsafe-cast] origin_simpl.c:9: Warning: 
+  unsafe cast from char * to int *; analysis may be unsound
+[alias] May-aliases after instruction  tmp = (void *)*((int *)(t));  are
+  { t[0..]; tmp }
+[alias] May-alias graph after instruction  tmp = (void *)*((int *)(t));  is
+  0:{ tmp } → 1:{  }   2:{ t } → 0:{ tmp }
+[alias] May-aliases at the end of function f: { t[0..]; tmp }
+[alias] May-alias graph at the end of function f:
+  0:{ tmp } → 1:{  }   2:{ t } → 0:{ tmp }
+[alias] Summary of function f:
+  formals:     returns: <none>    state: { t[0..]; tmp }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/fixed_bugs/oracle/records.res.oracle b/src/plugins/alias/tests/fixed_bugs/oracle/records.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..af00a8c8d9577a3453f8fa8e8d6e22ba8b0a37bb
--- /dev/null
+++ b/src/plugins/alias/tests/fixed_bugs/oracle/records.res.oracle
@@ -0,0 +1,52 @@
+[kernel] Parsing records.c (with preprocessing)
+[alias] analysing function: main
+[alias] analysing instruction: a = & x;
+[alias] May-aliases after instruction  a = & x;  are  <none>
+[alias] May-alias graph after instruction  a = & x;  is    0:{ a } → 1:{ x }
+[alias] analysing instruction: t.field = a;
+[alias] May-aliases after instruction  t.field = a;  are  { a; t.field }
+[alias] May-alias graph after instruction  t.field = a;  is
+  4:{ t } -field→ 5:{ a }   5:{ a } → 1:{ x }
+[alias] analysing instruction: z = & t;
+[alias] May-aliases after instruction  z = & t;  are  { z->field; a; t.field }
+[alias] May-alias graph after instruction  z = & t;  is
+  5:{ a } → 1:{ x }   6:{ z } → 7:{ t }   7:{ t } -field→ 5:{ a }
+[alias] analysing instruction: q = z;
+[alias] May-aliases after instruction  q = z;  are
+  { z->field; q->field; a; t.field }  { z; q }
+[alias] May-alias graph after instruction  q = z;  is
+  5:{ a } → 1:{ x }   9:{ z; q } → 10:{ t }   10:{ t } -field→ 5:{ a }
+[alias] analysing instruction: b = z->field;
+[alias] May-aliases after instruction  b = z->field;  are
+  { z; q }  { z->field; q->field; a; b; t.field }
+[alias] May-alias graph after instruction  b = z->field;  is
+  9:{ z; q } → 10:{ t }   10:{ t } -field→ 11:{ a; b }
+  11:{ a; b } → 12:{ x }
+[alias] analysing instruction: n = q->field;
+[alias] May-aliases after instruction  n = q->field;  are
+  { z; q }  { z->field; q->field; a; b; n; t.field }
+[alias] May-alias graph after instruction  n = q->field;  is
+  9:{ z; q } → 10:{ t }   10:{ t } -field→ 13:{ a; b; n }
+  13:{ a; b; n } → 14:{ x }
+[alias] analysing instruction: printf("%d\n%d\n",a == b,a == n);
+[alias:undefined:fn] records.c:21: Warning: function printf has no definition
+[alias] May-aliases after instruction  printf("%d\n%d\n",a == b,a == n);  are
+  { z; q }  { z->field; q->field; a; b; n; t.field }
+[alias] May-alias graph after instruction  printf("%d\n%d\n",a == b,a == n);  is
+  9:{ z; q } → 10:{ t }   10:{ t } -field→ 13:{ a; b; n }
+  13:{ a; b; n } → 14:{ x }
+[alias] analysing instruction: __retres = 0;
+[alias] May-aliases after instruction  __retres = 0;  are
+  { z; q }  { z->field; q->field; a; b; n; t.field }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  9:{ z; q } → 10:{ t }   10:{ t } -field→ 13:{ a; b; n }
+  13:{ a; b; n } → 14:{ x }
+[alias] May-aliases at the end of function main:
+  { z; q }  { z->field; q->field; a; b; n; t.field }
+[alias] May-alias graph at the end of function main:
+  9:{ z; q } → 10:{ t }   10:{ t } -field→ 13:{ a; b; n }
+  13:{ a; b; n } → 14:{ x }
+[alias] Summary of function main:
+  formals:     returns: __retres
+  state: { z; q }  { z->field; q->field; a; b; n; t.field }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/fixed_bugs/oracle/reduce_by_valid.res.oracle b/src/plugins/alias/tests/fixed_bugs/oracle/reduce_by_valid.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..df25a14949b787d251929bde47d8b0b3e01912f3
--- /dev/null
+++ b/src/plugins/alias/tests/fixed_bugs/oracle/reduce_by_valid.res.oracle
@@ -0,0 +1,34 @@
+[kernel] Parsing reduce_by_valid.c (with preprocessing)
+[kernel:typing:incompatible-pointer-types] reduce_by_valid.c:5: Warning: 
+  casting function to int *
+[kernel:typing:incompatible-pointer-types] reduce_by_valid.c:5: Warning: 
+  casting function to int *
+[alias] analysing function: f
+[alias] analysing instruction: int *q = (int *)(& f);
+[alias:unsafe-cast] reduce_by_valid.c:5: Warning: 
+  unsafe cast from void (*)(void) to int *; analysis may be unsound
+[alias] May-aliases after instruction  int *q = (int *)(& f);  are  <none>
+[alias] May-alias graph after instruction  int *q = (int *)(& f);  is
+  0:{ q } → 1:{ f }
+[alias] analysing instruction: int *p = (int *)(& f);
+[alias:unsafe-cast] reduce_by_valid.c:5: Warning: 
+  unsafe cast from void (*)(void) to int *; analysis may be unsound
+[alias] May-aliases after instruction  int *p = (int *)(& f);  are  { q; p }
+[alias] May-alias graph after instruction  int *p = (int *)(& f);  is
+  0:{ q } → 5:{ f }   4:{ p } → 5:{ f }
+[alias] analysing instruction: p = (int *)(& q);
+[alias:unsafe-cast] reduce_by_valid.c:6: Warning: 
+  unsafe cast from int ** to int *; analysis may be unsound
+[alias:incoherent] Warning: 
+  loop on vertex 5 (following unsafe cast?); analysis may be unsound
+[alias:incoherent] Warning: 
+  cycle during readout of vertex 5, (following unsafe cast?); analysis may be unsound
+[alias] May-aliases after instruction  p = (int *)(& q);  are  { *p; f; q; p }
+[alias] May-alias graph after instruction  p = (int *)(& q);  is
+  4:{ p } → 5:{ f; q }   5:{ f; q } → 5:{ f; q }
+[alias] May-aliases at the end of function f: { *p; f; q; p }
+[alias] May-alias graph at the end of function f:
+  4:{ p } → 5:{ f; q }   5:{ f; q } → 5:{ f; q }
+[alias] Summary of function f:
+  formals:     returns: <none>    state: { *p; f; q; p }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/fixed_bugs/oracle/semver.res.oracle b/src/plugins/alias/tests/fixed_bugs/oracle/semver.res.oracle
index bdc3f9de65441a71704fe3c6c2faf4b5d51f684b..7bf7a22a6e989a9581fa2b070758dab947eacdb9 100644
--- a/src/plugins/alias/tests/fixed_bugs/oracle/semver.res.oracle
+++ b/src/plugins/alias/tests/fixed_bugs/oracle/semver.res.oracle
@@ -1,12 +1,23 @@
 [kernel] Parsing semver.c (with preprocessing)
 [alias] analysing function: f
 [alias] May-aliases at the end of function f: <none>
+[alias] May-alias graph at the end of function f:
+  <empty>
+[alias] Summary of function f:
 [alias] analysing function: main
 [alias] analysing instruction: f((int *)*("1" + 2));
-[alias:unsafe-cast] semver.c:6: Warning: unsafe cast from char to int *
+[alias:unsafe-cast] semver.c:6: Warning: 
+  unsafe cast from char to int *; analysis may be unsound
 [alias:unsupported:addr] semver.c:6: Warning: 
   unsupported feature: explicit pointer address: (int *)*("1" + 2); analysis may be unsound
 [alias] May-aliases after instruction  f((int *)*("1" + 2));  are  <none>
+[alias] May-alias graph after instruction  f((int *)*("1" + 2));  is    <empty>
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  <none>
+[alias] May-alias graph after instruction  __retres = 0;  is    <empty>
 [alias] May-aliases at the end of function main: <none>
+[alias] May-alias graph at the end of function main:
+  <empty>
+[alias] Summary of function main:
+  formals:     returns: __retres    state: <none>
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/fixed_bugs/oracle/tkn-2.res.oracle b/src/plugins/alias/tests/fixed_bugs/oracle/tkn-2.res.oracle
index 7843cab155742b5e87b1d4e3c6fd67107fca9412..de858332e91e2b3c1c536ed852507fc8d0320fc6 100644
--- a/src/plugins/alias/tests/fixed_bugs/oracle/tkn-2.res.oracle
+++ b/src/plugins/alias/tests/fixed_bugs/oracle/tkn-2.res.oracle
@@ -1,9 +1,19 @@
 [kernel] Parsing tkn-2.c (with preprocessing)
 [alias] analysing function: main
 [alias] analysing instruction: a = (int *)(& a);
-[alias:unsafe-cast] tkn-2.c:6: Warning: unsafe cast from int ** to int *
+[alias:unsafe-cast] tkn-2.c:6: Warning: 
+  unsafe cast from int ** to int *; analysis may be unsound
 [alias] tkn-2.c:6: Warning: ignoring assignment of the form: a = (int *)(& a)
 [alias] May-aliases after instruction  a = (int *)(& a);  are  <none>
+[alias] May-alias graph after instruction  a = (int *)(& a);  is
+  0:{ a } → 1:{  }   2:{  } → 0:{ a }
 [alias] analysing instruction: __retres = *a;
 [alias] May-aliases after instruction  __retres = *a;  are  <none>
+[alias] May-alias graph after instruction  __retres = *a;  is
+  0:{ a } → 1:{  }   2:{  } → 0:{ a }
 [alias] May-aliases at the end of function main: <none>
+[alias] May-alias graph at the end of function main:
+  0:{ a } → 1:{  }   2:{  } → 0:{ a }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: <none>
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/fixed_bugs/oracle/union_readback.res.oracle b/src/plugins/alias/tests/fixed_bugs/oracle/union_readback.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..d22df63bf32b5fbf441192ad58bde54b468fab61
--- /dev/null
+++ b/src/plugins/alias/tests/fixed_bugs/oracle/union_readback.res.oracle
@@ -0,0 +1,15 @@
+[kernel] Parsing union_readback.c (with preprocessing)
+[alias] analysing function: f
+[alias] analysing instruction: flag.r.v = o;
+[alias] May-aliases after instruction  flag.r.v = o;  are
+  { o; flag.r.v }  { *o; *(flag.r.v) }
+[alias] May-alias graph after instruction  flag.r.v = o;  is
+  0:{ flag } -r→ 1:{  }   1:{  } -v→ 2:{ o }   2:{ o } → 4:{  }
+  4:{  } → 5:{  }
+[alias] May-aliases at the end of function f: { o; flag.r.v }  { *o; *(flag.r.v) }
+[alias] May-alias graph at the end of function f:
+  0:{ flag } -r→ 1:{  }   1:{  } -v→ 2:{ o }   2:{ o } → 4:{  }
+  4:{  } → 5:{  }
+[alias] Summary of function f:
+  formals: o    returns: <none>    state: { o; flag.r.v }  { *o; *(flag.r.v) }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/fixed_bugs/oracle/union_vmap.res.oracle b/src/plugins/alias/tests/fixed_bugs/oracle/union_vmap.res.oracle
index 7ea35d5b5b006eaa354b2f151d11e281fceaf470..ad021ebd893df1e93035660331c2ecabcfbdd3d9 100644
--- a/src/plugins/alias/tests/fixed_bugs/oracle/union_vmap.res.oracle
+++ b/src/plugins/alias/tests/fixed_bugs/oracle/union_vmap.res.oracle
@@ -3,19 +3,40 @@
 [alias] analysing instruction: char *s2 = CPS_SplitWord((char *)"a");
 [alias] analysing function: CPS_SplitWord
 [alias] May-aliases at the end of function CPS_SplitWord: <none>
+[alias] May-alias graph at the end of function CPS_SplitWord:
+  <empty>
+[alias] Summary of function CPS_SplitWord:
+  formals: line    returns: line    state: <none>
 [alias:unsafe-cast] union_vmap.c:11: Warning: 
-  unsafe cast from char const * to char *
+  unsafe cast from char const * to char *; analysis may be unsound
 [alias] May-aliases after instruction  char *s2 = CPS_SplitWord((char *)"a");  are
   <none>
+[alias] May-alias graph after instruction  char *s2 = CPS_SplitWord((char *)"a");
+  is    4:{ s2 } → 3:{  }
 [alias] analysing instruction: char *s3 = CPS_SplitWord((char *)"b");
 [alias:unsafe-cast] union_vmap.c:12: Warning: 
-  unsafe cast from char const * to char *
+  unsafe cast from char const * to char *; analysis may be unsound
 [alias] May-aliases after instruction  char *s3 = CPS_SplitWord((char *)"b");  are
   <none>
+[alias] May-alias graph after instruction  char *s3 = CPS_SplitWord((char *)"b");
+  is    4:{ s2 } → 3:{  }   8:{ s3 } → 7:{  }
 [alias] analysing instruction: *key = s3;
 [alias] May-aliases after instruction  *key = s3;  are  { *key; s3 }
+[alias] May-alias graph after instruction  *key = s3;  is
+  4:{ s2 } → 3:{  }   10:{ key } → 11:{ s3 }   11:{ s3 } → 12:{  }
 [alias] analysing instruction: *key = s2;
 [alias] May-aliases after instruction  *key = s2;  are  { *key; s2 }
+[alias] May-alias graph after instruction  *key = s2;  is
+  8:{ s3 } → 7:{  }   13:{ key } → 14:{ s2 }   14:{ s2 } → 15:{  }
 [alias] May-aliases at the end of function CPS_ParseKey: { *key; s2; s3 }
+[alias] May-alias graph at the end of function CPS_ParseKey:
+  4:{ s2; s3 } → 3:{  }   10:{ key } → 4:{ s2; s3 }
+[alias] Summary of function CPS_ParseKey:
+  formals:     returns: <none>    state: { *key; s2; s3 }
 [alias] analysing function: CPS_SplitWord
 [alias] May-aliases at the end of function CPS_SplitWord: <none>
+[alias] May-alias graph at the end of function CPS_SplitWord:
+  <empty>
+[alias] Summary of function CPS_SplitWord:
+  formals: line    returns: line    state: <none>
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/fixed_bugs/records.c b/src/plugins/alias/tests/fixed_bugs/records.c
new file mode 100644
index 0000000000000000000000000000000000000000..c3830f741937716d56989d718e83c74846347203
--- /dev/null
+++ b/src/plugins/alias/tests/fixed_bugs/records.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+
+typedef struct { int *field; } ty;
+
+int x;
+int *a;
+int *b;
+int *n;
+ty *z;
+ty *q;
+ty t;
+
+int main(void)
+{
+  a = &x;
+  t.field = a;
+  z = &t;
+  q = z;
+  b = z->field;
+  n = q->field;
+  printf("%d\n%d\n", a == b, a == n);
+  return 0;
+}
diff --git a/src/plugins/alias/tests/fixed_bugs/reduce_by_valid.c b/src/plugins/alias/tests/fixed_bugs/reduce_by_valid.c
new file mode 100644
index 0000000000000000000000000000000000000000..96b12149fa7d776e5ae9e23e8608f86a71ba39f6
--- /dev/null
+++ b/src/plugins/alias/tests/fixed_bugs/reduce_by_valid.c
@@ -0,0 +1,7 @@
+// https://git.frama-c.com/frama-c/frama-c/-/issues/1299
+// crashes due to an incoherent graph
+
+void f() {
+  int *q = (int*)f, *p = (int*)f;
+  p = (int*)&q;
+}
diff --git a/src/plugins/alias/tests/fixed_bugs/union_readback.c b/src/plugins/alias/tests/fixed_bugs/union_readback.c
new file mode 100644
index 0000000000000000000000000000000000000000..893f065aa76fded518256696d02e0d076b94efd6
--- /dev/null
+++ b/src/plugins/alias/tests/fixed_bugs/union_readback.c
@@ -0,0 +1,19 @@
+// REPRODUCE: frama-c -alias -alias-verbose 2 union_readback.c
+// BEHAVIOUR: fatal kernel error [kernel] test.c:10: Failure: 
+//   typeOffset: Field r on a non-compound type 'char const **'
+// EXPECTED: no error
+// EXPLANATION:
+//   This happens during the readback phase while reconstructing lvals.
+//   The call [Cil.typeOfLval lv] on the reconstructed lval [lv] fails.
+// FIX: take into account typing information during reconstruction.
+
+typedef struct s {
+    union {
+        const char **v;
+    } r;
+} s;
+
+void f(const char** o) {
+    s flag;
+    flag.r.v = o;
+}
diff --git a/src/plugins/alias/tests/offsets/jfla_running_ex.c b/src/plugins/alias/tests/offsets/jfla_running_ex.c
new file mode 100644
index 0000000000000000000000000000000000000000..4a71092687cf317b3083c9a2af676146abe35f45
--- /dev/null
+++ b/src/plugins/alias/tests/offsets/jfla_running_ex.c
@@ -0,0 +1,14 @@
+int* jfla (int *fst, int *snd, int **i1, int **i2, int bo) {
+  *snd = *fst;
+  if (bo) { fst = *i1; return *i2; }
+  else    { fst = *i2; return *i1; }
+}
+
+void main(void) {
+  int u = 11, v = 12, t[3] = {0,1,2};
+  int *a = &t[1], *b = &u, *c = &v;
+  int **x = &a, **y = &b, **z = &c;
+  struct str_t {int *fst; int *snd; } s = { c , t }, *s1 = &s, *s2 = &s;
+  c = jfla(s1->fst, s1->snd, x, y, 0);
+  a = jfla(s2->fst, s2->snd, y, z, 1);
+}
diff --git a/src/plugins/alias/tests/offsets/oracle/array1.res.oracle b/src/plugins/alias/tests/offsets/oracle/array1.res.oracle
index d49ca85c658d42bd0df259842d7cb3df03f4aa41..feef21de948540d1a6480d1ac2757742ee430c41 100644
--- a/src/plugins/alias/tests/offsets/oracle/array1.res.oracle
+++ b/src/plugins/alias/tests/offsets/oracle/array1.res.oracle
@@ -2,16 +2,32 @@
 [alias] analysing function: main
 [alias] analysing instruction: tab[0] = 0;
 [alias] May-aliases after instruction  tab[0] = 0;  are  <none>
+[alias] May-alias graph after instruction  tab[0] = 0;  is    <empty>
 [alias] analysing instruction: tab[1] = 1;
 [alias] May-aliases after instruction  tab[1] = 1;  are  <none>
+[alias] May-alias graph after instruction  tab[1] = 1;  is    <empty>
 [alias] analysing instruction: tab[2] = tab[1] + 1;
 [alias] May-aliases after instruction  tab[2] = tab[1] + 1;  are  <none>
+[alias] May-alias graph after instruction  tab[2] = tab[1] + 1;  is    <empty>
 [alias] analysing instruction: int *x = & tab[1];
-[alias] May-aliases after instruction  int *x = & tab[1];  are  <none>
+[alias] May-aliases after instruction  int *x = & tab[1];  are  { tab; x }
+[alias] May-alias graph after instruction  int *x = & tab[1];  is
+  0:{ x } → 1:{  }   2:{ tab } → 1:{  }
 [alias] analysing instruction: int *y = & tab[2];
-[alias] May-aliases after instruction  int *y = & tab[2];  are  { x; y }
+[alias] May-aliases after instruction  int *y = & tab[2];  are  { tab; x; y }
+[alias] May-alias graph after instruction  int *y = & tab[2];  is
+  0:{ x } → 6:{  }   2:{ tab } → 6:{  }   5:{ y } → 6:{  }
 [alias] analysing instruction: tab[3] = *x + *y;
-[alias] May-aliases after instruction  tab[3] = *x + *y;  are  { x; y }
+[alias] May-aliases after instruction  tab[3] = *x + *y;  are  { tab; x; y }
+[alias] May-alias graph after instruction  tab[3] = *x + *y;  is
+  0:{ x } → 6:{  }   2:{ tab } → 6:{  }   5:{ y } → 6:{  }
 [alias] analysing instruction: __retres = 0;
-[alias] May-aliases after instruction  __retres = 0;  are  { x; y }
-[alias] May-aliases at the end of function main: { x; y }
+[alias] May-aliases after instruction  __retres = 0;  are  { tab; x; y }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ x } → 6:{  }   2:{ tab } → 6:{  }   5:{ y } → 6:{  }
+[alias] May-aliases at the end of function main: { tab; x; y }
+[alias] May-alias graph at the end of function main:
+  0:{ x } → 6:{  }   2:{ tab } → 6:{  }   5:{ y } → 6:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { tab; x; y }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/offsets/oracle/array2.res.oracle b/src/plugins/alias/tests/offsets/oracle/array2.res.oracle
index 69f16a022f8b05688a9a9eb66a4180354fdcf323..175b930c1c3150571ccb15d3c06a0f88d8c7456b 100644
--- a/src/plugins/alias/tests/offsets/oracle/array2.res.oracle
+++ b/src/plugins/alias/tests/offsets/oracle/array2.res.oracle
@@ -2,12 +2,28 @@
 [alias] analysing function: main
 [alias] analysing instruction: mat[0][0] = 0;
 [alias] May-aliases after instruction  mat[0][0] = 0;  are  <none>
+[alias] May-alias graph after instruction  mat[0][0] = 0;  is    <empty>
 [alias] analysing instruction: mat[0][1] = 1;
 [alias] May-aliases after instruction  mat[0][1] = 1;  are  <none>
+[alias] May-alias graph after instruction  mat[0][1] = 1;  is    <empty>
 [alias] analysing instruction: *x = mat[1];
-[alias] May-aliases after instruction  *x = mat[1];  are  <none>
+[alias] May-aliases after instruction  *x = mat[1];  are
+  { mat; x }  { *x; mat[0..] }
+[alias] May-alias graph after instruction  *x = mat[1];  is
+  0:{ x } → 1:{  }   1:{  } → 2:{  }   3:{ mat } → 1:{  }
 [alias] analysing instruction: *y = *(*(x + 0));
-[alias] May-aliases after instruction  *y = *(*(x + 0));  are  <none>
+[alias] May-aliases after instruction  *y = *(*(x + 0));  are
+  { mat; x }  { *x; mat[0..] }
+[alias] May-alias graph after instruction  *y = *(*(x + 0));  is
+  0:{ x } → 1:{  }   1:{  } → 2:{  }   3:{ mat } → 1:{  }
 [alias] analysing instruction: __retres = 0;
-[alias] May-aliases after instruction  __retres = 0;  are  <none>
-[alias] May-aliases at the end of function main: <none>
+[alias] May-aliases after instruction  __retres = 0;  are
+  { mat; x }  { *x; mat[0..] }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ x } → 1:{  }   1:{  } → 2:{  }   3:{ mat } → 1:{  }
+[alias] May-aliases at the end of function main: { mat; x }  { *x; mat[0..] }
+[alias] May-alias graph at the end of function main:
+  0:{ x } → 1:{  }   1:{  } → 2:{  }   3:{ mat } → 1:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { mat; x }  { *x; mat[0..] }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/offsets/oracle/array3.res.oracle b/src/plugins/alias/tests/offsets/oracle/array3.res.oracle
index 30544c8240af350ca34a0debbf1321339786cff7..6a9db912e09ad8e8ccbb8adc25f7b7adbd51f77b 100644
--- a/src/plugins/alias/tests/offsets/oracle/array3.res.oracle
+++ b/src/plugins/alias/tests/offsets/oracle/array3.res.oracle
@@ -1,127 +1,31 @@
 [kernel] Parsing array3.c (with preprocessing)
-[alias] analysing function: _Exit
-[alias] May-aliases at the end of function _Exit: ⊥
-[alias] analysing function: abort
-[alias] May-aliases at the end of function abort: ⊥
-[alias] analysing function: abs
-[alias] May-aliases at the end of function abs: ⊥
-[alias] analysing function: at_quick_exit
-[alias] May-aliases at the end of function at_quick_exit: ⊥
-[alias] analysing function: atexit
-[alias] May-aliases at the end of function atexit: ⊥
-[alias] analysing function: atof
-[alias] May-aliases at the end of function atof: ⊥
-[alias] analysing function: atoi
-[alias] May-aliases at the end of function atoi: ⊥
-[alias] analysing function: atol
-[alias] May-aliases at the end of function atol: ⊥
-[alias] analysing function: atoll
-[alias] May-aliases at the end of function atoll: ⊥
-[alias] analysing function: bsearch
-[alias] May-aliases at the end of function bsearch: ⊥
-[alias] analysing function: calloc
-[alias] May-aliases at the end of function calloc: ⊥
-[alias] analysing function: div
-[alias] May-aliases at the end of function div: ⊥
-[alias] analysing function: drand48
-[alias] May-aliases at the end of function drand48: ⊥
-[alias] analysing function: erand48
-[alias] May-aliases at the end of function erand48: ⊥
-[alias] analysing function: exit
-[alias] May-aliases at the end of function exit: ⊥
-[alias] analysing function: free
-[alias] May-aliases at the end of function free: ⊥
-[alias] analysing function: getenv
-[alias] May-aliases at the end of function getenv: ⊥
-[alias] analysing function: jrand48
-[alias] May-aliases at the end of function jrand48: ⊥
-[alias] analysing function: labs
-[alias] May-aliases at the end of function labs: ⊥
-[alias] analysing function: lcong48
-[alias] May-aliases at the end of function lcong48: ⊥
-[alias] analysing function: ldiv
-[alias] May-aliases at the end of function ldiv: ⊥
-[alias] analysing function: llabs
-[alias] May-aliases at the end of function llabs: ⊥
-[alias] analysing function: lldiv
-[alias] May-aliases at the end of function lldiv: ⊥
-[alias] analysing function: lrand48
-[alias] May-aliases at the end of function lrand48: ⊥
 [alias] analysing function: main
 [alias] analysing instruction: int *x = malloc((unsigned long)4 * sizeof(int));
 [alias] May-aliases after instruction
   int *x = malloc((unsigned long)4 * sizeof(int));  are  <none>
+[alias] May-alias graph after instruction
+  int *x = malloc((unsigned long)4 * sizeof(int));  is    0:{ x } → 1:{  }
 [alias] analysing instruction: int *y = malloc((unsigned long)4 * sizeof(int));
 [alias] May-aliases after instruction
   int *y = malloc((unsigned long)4 * sizeof(int));  are  <none>
+[alias] May-alias graph after instruction
+  int *y = malloc((unsigned long)4 * sizeof(int));  is
+  0:{ x } → 1:{  }   2:{ y } → 3:{  }
 [alias] analysing instruction: x = mat[0];
-[alias] May-aliases after instruction  x = mat[0];  are  <none>
+[alias] May-aliases after instruction  x = mat[0];  are  { mat[0..]; x }
+[alias] May-alias graph after instruction  x = mat[0];  is
+  0:{ x } → 1:{  }   2:{ y } → 3:{  }   4:{ mat } → 0:{ x }
 [alias] analysing instruction: y = mat[1];
-[alias] May-aliases after instruction  y = mat[1];  are  { x; y }
+[alias] May-aliases after instruction  y = mat[1];  are  { mat[0..]; x; y }
+[alias] May-alias graph after instruction  y = mat[1];  is
+  2:{ x; y } → 3:{  }   4:{ mat } → 2:{ x; y }
 [alias] analysing instruction: __retres = 0;
-[alias] May-aliases after instruction  __retres = 0;  are  { x; y }
-[alias] May-aliases at the end of function main: { x; y }
-[alias] analysing function: malloc
-[alias] May-aliases at the end of function malloc: ⊥
-[alias] analysing function: mblen
-[alias] May-aliases at the end of function mblen: ⊥
-[alias] analysing function: mbstowcs
-[alias] May-aliases at the end of function mbstowcs: ⊥
-[alias] analysing function: mbtowc
-[alias] May-aliases at the end of function mbtowc: ⊥
-[alias] analysing function: mkstemp
-[alias] May-aliases at the end of function mkstemp: ⊥
-[alias] analysing function: mkstemps
-[alias] May-aliases at the end of function mkstemps: ⊥
-[alias] analysing function: mrand48
-[alias] May-aliases at the end of function mrand48: ⊥
-[alias] analysing function: nrand48
-[alias] May-aliases at the end of function nrand48: ⊥
-[alias] analysing function: posix_memalign
-[alias] May-aliases at the end of function posix_memalign: ⊥
-[alias] analysing function: putenv
-[alias] May-aliases at the end of function putenv: ⊥
-[alias] analysing function: qsort
-[alias] May-aliases at the end of function qsort: ⊥
-[alias] analysing function: quick_exit
-[alias] May-aliases at the end of function quick_exit: ⊥
-[alias] analysing function: rand
-[alias] May-aliases at the end of function rand: ⊥
-[alias] analysing function: random
-[alias] May-aliases at the end of function random: ⊥
-[alias] analysing function: realloc
-[alias] May-aliases at the end of function realloc: ⊥
-[alias] analysing function: reallocarray
-[alias] May-aliases at the end of function reallocarray: ⊥
-[alias] analysing function: seed48
-[alias] May-aliases at the end of function seed48: ⊥
-[alias] analysing function: setenv
-[alias] May-aliases at the end of function setenv: ⊥
-[alias] analysing function: srand
-[alias] May-aliases at the end of function srand: ⊥
-[alias] analysing function: srand48
-[alias] May-aliases at the end of function srand48: ⊥
-[alias] analysing function: srandom
-[alias] May-aliases at the end of function srandom: ⊥
-[alias] analysing function: strtod
-[alias] May-aliases at the end of function strtod: ⊥
-[alias] analysing function: strtof
-[alias] May-aliases at the end of function strtof: ⊥
-[alias] analysing function: strtol
-[alias] May-aliases at the end of function strtol: ⊥
-[alias] analysing function: strtold
-[alias] May-aliases at the end of function strtold: ⊥
-[alias] analysing function: strtoll
-[alias] May-aliases at the end of function strtoll: ⊥
-[alias] analysing function: strtoul
-[alias] May-aliases at the end of function strtoul: ⊥
-[alias] analysing function: strtoull
-[alias] May-aliases at the end of function strtoull: ⊥
-[alias] analysing function: system
-[alias] May-aliases at the end of function system: ⊥
-[alias] analysing function: unsetenv
-[alias] May-aliases at the end of function unsetenv: ⊥
-[alias] analysing function: wcstombs
-[alias] May-aliases at the end of function wcstombs: ⊥
-[alias] analysing function: wctomb
-[alias] May-aliases at the end of function wctomb: ⊥
+[alias] May-aliases after instruction  __retres = 0;  are  { mat[0..]; x; y }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  2:{ x; y } → 3:{  }   4:{ mat } → 2:{ x; y }
+[alias] May-aliases at the end of function main: { mat[0..]; x; y }
+[alias] May-alias graph at the end of function main:
+  2:{ x; y } → 3:{  }   4:{ mat } → 2:{ x; y }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { mat[0..]; x; y }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/offsets/oracle/collapse1.res.oracle b/src/plugins/alias/tests/offsets/oracle/collapse1.res.oracle
index 9b588f2f8f2484f894680dae6ca6129528811125..eb369e1766727fac32f06d465c96237522042a18 100644
--- a/src/plugins/alias/tests/offsets/oracle/collapse1.res.oracle
+++ b/src/plugins/alias/tests/offsets/oracle/collapse1.res.oracle
@@ -2,18 +2,31 @@
 [alias] analysing function: main
 [alias] analysing instruction: tab[0] = 0;
 [alias] May-aliases after instruction  tab[0] = 0;  are  <none>
+[alias] May-alias graph after instruction  tab[0] = 0;  is    <empty>
 [alias] analysing instruction: tab[1] = 1;
 [alias] May-aliases after instruction  tab[1] = 1;  are  <none>
+[alias] May-alias graph after instruction  tab[1] = 1;  is    <empty>
 [alias] analysing instruction: tab[2] = tab[1] + 1;
 [alias] May-aliases after instruction  tab[2] = tab[1] + 1;  are  <none>
+[alias] May-alias graph after instruction  tab[2] = tab[1] + 1;  is    <empty>
 [alias] analysing instruction: int x = 0;
 [alias] May-aliases after instruction  int x = 0;  are  <none>
+[alias] May-alias graph after instruction  int x = 0;  is    <empty>
 [alias] analysing instruction: int i = 0;
 [alias] May-aliases after instruction  int i = 0;  are  <none>
+[alias] May-alias graph after instruction  int i = 0;  is    <empty>
 [alias] analysing instruction: x = tab[i];
 [alias] May-aliases after instruction  x = tab[i];  are  <none>
+[alias] May-alias graph after instruction  x = tab[i];  is    <empty>
 [alias] analysing instruction: i ++;
 [alias] May-aliases after instruction  i ++;  are  <none>
+[alias] May-alias graph after instruction  i ++;  is    <empty>
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  <none>
+[alias] May-alias graph after instruction  __retres = 0;  is    <empty>
 [alias] May-aliases at the end of function main: <none>
+[alias] May-alias graph at the end of function main:
+  <empty>
+[alias] Summary of function main:
+  formals:     returns: __retres    state: <none>
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/offsets/oracle/collapse2.res.oracle b/src/plugins/alias/tests/offsets/oracle/collapse2.res.oracle
index 34b8bd11975081e1acc6cd63c7d0011d1f3b57e3..4cfb490989c591e340e2339761fb7814e3fc6887 100644
--- a/src/plugins/alias/tests/offsets/oracle/collapse2.res.oracle
+++ b/src/plugins/alias/tests/offsets/oracle/collapse2.res.oracle
@@ -2,16 +2,28 @@
 [alias] analysing function: main
 [alias] analysing instruction: mat[0][0] = 0;
 [alias] May-aliases after instruction  mat[0][0] = 0;  are  <none>
+[alias] May-alias graph after instruction  mat[0][0] = 0;  is    <empty>
 [alias] analysing instruction: mat[0][1] = 1;
 [alias] May-aliases after instruction  mat[0][1] = 1;  are  <none>
+[alias] May-alias graph after instruction  mat[0][1] = 1;  is    <empty>
 [alias] analysing instruction: int i = 2;
 [alias] May-aliases after instruction  int i = 2;  are  <none>
+[alias] May-alias graph after instruction  int i = 2;  is    <empty>
 [alias] analysing instruction: mat[1][i] = i;
 [alias] May-aliases after instruction  mat[1][i] = i;  are  <none>
+[alias] May-alias graph after instruction  mat[1][i] = i;  is    <empty>
 [alias] analysing instruction: i ++;
 [alias] May-aliases after instruction  i ++;  are  <none>
+[alias] May-alias graph after instruction  i ++;  is    <empty>
 [alias] analysing instruction: mat[1][i] = 2;
 [alias] May-aliases after instruction  mat[1][i] = 2;  are  <none>
+[alias] May-alias graph after instruction  mat[1][i] = 2;  is    <empty>
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  <none>
+[alias] May-alias graph after instruction  __retres = 0;  is    <empty>
 [alias] May-aliases at the end of function main: <none>
+[alias] May-alias graph at the end of function main:
+  <empty>
+[alias] Summary of function main:
+  formals:     returns: __retres    state: <none>
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/offsets/oracle/collapse3.res.oracle b/src/plugins/alias/tests/offsets/oracle/collapse3.res.oracle
index 4193c3f90a212238b3a6f1452d58e097c1ae1bd1..eefdb1052d6d022860ce659f51a5f69d94dea793 100644
--- a/src/plugins/alias/tests/offsets/oracle/collapse3.res.oracle
+++ b/src/plugins/alias/tests/offsets/oracle/collapse3.res.oracle
@@ -2,16 +2,28 @@
 [alias] analysing function: main
 [alias] analysing instruction: mat[0][0] = 0;
 [alias] May-aliases after instruction  mat[0][0] = 0;  are  <none>
+[alias] May-alias graph after instruction  mat[0][0] = 0;  is    <empty>
 [alias] analysing instruction: mat[0][1] = 1;
 [alias] May-aliases after instruction  mat[0][1] = 1;  are  <none>
+[alias] May-alias graph after instruction  mat[0][1] = 1;  is    <empty>
 [alias] analysing instruction: int i = 2;
 [alias] May-aliases after instruction  int i = 2;  are  <none>
+[alias] May-alias graph after instruction  int i = 2;  is    <empty>
 [alias] analysing instruction: mat[i][1] = i;
 [alias] May-aliases after instruction  mat[i][1] = i;  are  <none>
+[alias] May-alias graph after instruction  mat[i][1] = i;  is    <empty>
 [alias] analysing instruction: i ++;
 [alias] May-aliases after instruction  i ++;  are  <none>
+[alias] May-alias graph after instruction  i ++;  is    <empty>
 [alias] analysing instruction: mat[i][1] = 2;
 [alias] May-aliases after instruction  mat[i][1] = 2;  are  <none>
+[alias] May-alias graph after instruction  mat[i][1] = 2;  is    <empty>
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  <none>
+[alias] May-alias graph after instruction  __retres = 0;  is    <empty>
 [alias] May-aliases at the end of function main: <none>
+[alias] May-alias graph at the end of function main:
+  <empty>
+[alias] Summary of function main:
+  formals:     returns: __retres    state: <none>
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/offsets/oracle/jfla_running_ex.res.oracle b/src/plugins/alias/tests/offsets/oracle/jfla_running_ex.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..f7a7e1c869d4df4f2acff0b693a447f12f8c295a
--- /dev/null
+++ b/src/plugins/alias/tests/offsets/oracle/jfla_running_ex.res.oracle
@@ -0,0 +1,134 @@
+[kernel] Parsing jfla_running_ex.c (with preprocessing)
+[alias] analysing function: jfla
+[alias] analysing instruction: *snd = *fst;
+[alias] May-aliases after instruction  *snd = *fst;  are  <none>
+[alias] May-alias graph after instruction  *snd = *fst;  is    <empty>
+[alias] analysing instruction: fst = *i1;
+[alias] May-aliases after instruction  fst = *i1;  are  { *i1; fst }
+[alias] May-alias graph after instruction  fst = *i1;  is
+  0:{ fst } → 1:{  }   2:{ i1 } → 0:{ fst }
+[alias] analysing instruction: __retres = *i2;
+[alias] May-aliases after instruction  __retres = *i2;  are
+  { *i1; fst }  { *i2; __retres }
+[alias] May-alias graph after instruction  __retres = *i2;  is
+  0:{ fst } → 1:{  }   2:{ i1 } → 0:{ fst }   5:{ __retres } → 6:{  }
+  7:{ i2 } → 5:{ __retres }
+[alias] analysing instruction: fst = *i2;
+[alias] May-aliases after instruction  fst = *i2;  are  { *i2; fst }
+[alias] May-alias graph after instruction  fst = *i2;  is
+  10:{ fst } → 11:{  }   12:{ i2 } → 10:{ fst }
+[alias] analysing instruction: __retres = *i1;
+[alias] May-aliases after instruction  __retres = *i1;  are
+  { *i2; fst }  { *i1; __retres }
+[alias] May-alias graph after instruction  __retres = *i1;  is
+  10:{ fst } → 11:{  }   12:{ i2 } → 10:{ fst }
+  15:{ __retres } → 16:{  }   17:{ i1 } → 15:{ __retres }
+[alias] May-aliases at the end of function jfla:
+  { i1; i2 }  { *i1; *i2; fst; __retres }
+[alias] May-alias graph at the end of function jfla:
+  0:{ fst; __retres } → 1:{  }   2:{ i1 } → 0:{ fst; __retres }
+  7:{ i2 } → 0:{ fst; __retres }
+[alias] Summary of function jfla:
+  formals: fst  snd  i1→{ fst; __retres }  i2→{ fst; __retres }  bo
+  returns: __retres    state: { i1; i2 }  { *i1; *i2; fst; __retres }
+[alias] analysing function: main
+[alias] analysing instruction: int u = 11;
+[alias] May-aliases after instruction  int u = 11;  are  <none>
+[alias] May-alias graph after instruction  int u = 11;  is    <empty>
+[alias] analysing instruction: int v = 12;
+[alias] May-aliases after instruction  int v = 12;  are  <none>
+[alias] May-alias graph after instruction  int v = 12;  is    <empty>
+[alias] analysing instruction: int t[3] = {0, 1, 2};
+[alias] May-aliases after instruction  int t[3] = {0, 1, 2};  are  <none>
+[alias] May-alias graph after instruction  int t[3] = {0, 1, 2};  is    <empty>
+[alias] analysing instruction: int *a = & t[1];
+[alias] May-aliases after instruction  int *a = & t[1];  are  { t; a }
+[alias] May-alias graph after instruction  int *a = & t[1];  is
+  20:{ a } → 21:{  }   22:{ t } → 21:{  }
+[alias] analysing instruction: int *b = & u;
+[alias] May-aliases after instruction  int *b = & u;  are  { t; a }
+[alias] May-alias graph after instruction  int *b = & u;  is
+  20:{ a } → 21:{  }   22:{ t } → 21:{  }   25:{ b } → 26:{ u }
+[alias] analysing instruction: int *c = & v;
+[alias] May-aliases after instruction  int *c = & v;  are  { t; a }
+[alias] May-alias graph after instruction  int *c = & v;  is
+  20:{ a } → 21:{  }   22:{ t } → 21:{  }   25:{ b } → 26:{ u }
+  29:{ c } → 30:{ v }
+[alias] analysing instruction: int **x = & a;
+[alias] May-aliases after instruction  int **x = & a;  are  { *x; t; a }
+[alias] May-alias graph after instruction  int **x = & a;  is
+  22:{ t } → 35:{  }   25:{ b } → 26:{ u }   29:{ c } → 30:{ v }
+  33:{ x } → 34:{ a }   34:{ a } → 35:{  }
+[alias] analysing instruction: int **y = & b;
+[alias] May-aliases after instruction  int **y = & b;  are  { *x; t; a }  { *y; b }
+[alias] May-alias graph after instruction  int **y = & b;  is
+  22:{ t } → 35:{  }   29:{ c } → 30:{ v }   33:{ x } → 34:{ a }
+  34:{ a } → 35:{  }   37:{ y } → 38:{ b }   38:{ b } → 39:{ u }
+[alias] analysing instruction: int **z = & c;
+[alias] May-aliases after instruction  int **z = & c;  are
+  { *x; t; a }  { *y; b }  { *z; c }
+[alias] May-alias graph after instruction  int **z = & c;  is
+  22:{ t } → 35:{  }   33:{ x } → 34:{ a }   34:{ a } → 35:{  }
+  37:{ y } → 38:{ b }   38:{ b } → 39:{ u }   41:{ z } → 42:{ c }
+  42:{ c } → 43:{ v }
+[alias] analysing instruction: struct str_t s = {.fst = c, .snd = t};
+[alias] May-aliases after instruction  struct str_t s = {.fst = c, .snd = t};  are
+  { *x; t; a; s.snd }  { *y; b }  { *z; c; s.fst }
+[alias] May-alias graph after instruction  struct str_t s = {.fst = c, .snd = t};
+  is
+  33:{ x } → 34:{ a }   34:{ a } → 35:{  }   37:{ y } → 38:{ b }
+  38:{ b } → 39:{ u }   41:{ z } → 46:{ c }   45:{ s } -fst→ 46:{ c }
+  45:{ s } -snd→ 47:{ t }   46:{ c } → 43:{ v }   47:{ t } → 35:{  }
+[alias] analysing instruction: struct str_t *s1 = & s;
+[alias] May-aliases after instruction  struct str_t *s1 = & s;  are
+  { *x; s1->snd; t; a; s.snd }  { *y; b }  { *z; s1->fst; c; s.fst }
+[alias] May-alias graph after instruction  struct str_t *s1 = & s;  is
+  33:{ x } → 34:{ a }   34:{ a } → 35:{  }   37:{ y } → 38:{ b }
+  38:{ b } → 39:{ u }   41:{ z } → 46:{ c }   46:{ c } → 43:{ v }
+  47:{ t } → 35:{  }   48:{ s1 } → 49:{ s }   49:{ s } -fst→ 46:{ c }
+  49:{ s } -snd→ 47:{ t }
+[alias] analysing instruction: struct str_t *s2 = & s;
+[alias] May-aliases after instruction  struct str_t *s2 = & s;  are
+  { *x; s1->snd; s2->snd; t; a; s.snd }  { *y; b }
+  { *z; s1->fst; s2->fst; c; s.fst }  { s1; s2 }
+[alias] May-alias graph after instruction  struct str_t *s2 = & s;  is
+  33:{ x } → 34:{ a }   34:{ a } → 35:{  }   37:{ y } → 38:{ b }
+  38:{ b } → 39:{ u }   41:{ z } → 46:{ c }   46:{ c } → 43:{ v }
+  47:{ t } → 35:{  }   48:{ s1 } → 52:{ s }   51:{ s2 } → 52:{ s }
+  52:{ s } -fst→ 46:{ c }   52:{ s } -snd→ 47:{ t }
+[alias] analysing instruction: c = jfla(s1->fst,s1->snd,x,y,0);
+[alias] May-aliases after instruction  c = jfla(s1->fst,s1->snd,x,y,0);  are
+  { x; y }
+  { *x; *y; *z; s1->fst; s1->snd; s2->fst; s2->snd; t; a; b; c; s.fst; s.snd }
+  { s1; s2 }
+[alias] May-alias graph after instruction  c = jfla(s1->fst,s1->snd,x,y,0);  is
+  33:{ x } → 34:{ a; b }   34:{ a; b } → 35:{ u; v }
+  37:{ y } → 34:{ a; b }   41:{ z } → 46:{ c }   46:{ c } → 35:{ u; v }
+  47:{ t } → 35:{ u; v }   48:{ s1 } → 52:{ s }   51:{ s2 } → 52:{ s }
+  52:{ s } -fst→ 46:{ c }   52:{ s } -snd→ 47:{ t }
+[alias] analysing instruction: a = jfla(s2->fst,s2->snd,y,z,1);
+[alias] May-aliases after instruction  a = jfla(s2->fst,s2->snd,y,z,1);  are
+  { x; y; z }
+  { *x; *y; *z; s1->fst; s1->snd; s2->fst; s2->snd; t; a; b; c; s.fst; s.snd }
+  { s1; s2 }
+[alias] May-alias graph after instruction  a = jfla(s2->fst,s2->snd,y,z,1);  is
+  33:{ x } → 34:{ a; b; c }   34:{ a; b; c } → 35:{ u; v }
+  37:{ y } → 34:{ a; b; c }   41:{ z } → 34:{ a; b; c }
+  47:{ t } → 35:{ u; v }   48:{ s1 } → 52:{ s }   51:{ s2 } → 52:{ s }
+  52:{ s } -fst→ 34:{ a; b; c }   52:{ s } -snd→ 47:{ t }
+[alias] May-aliases at the end of function main:
+  { x; y; z }
+  { *x; *y; *z; s1->fst; s1->snd; s2->fst; s2->snd; t; a; b; c; s.fst; s.snd }
+  { s1; s2 }
+[alias] May-alias graph at the end of function main:
+  33:{ x } → 34:{ a; b; c }   34:{ a; b; c } → 35:{ u; v }
+  37:{ y } → 34:{ a; b; c }   41:{ z } → 34:{ a; b; c }
+  47:{ t } → 35:{ u; v }   48:{ s1 } → 52:{ s }   51:{ s2 } → 52:{ s }
+  52:{ s } -fst→ 34:{ a; b; c }   52:{ s } -snd→ 47:{ t }
+[alias] Summary of function main:
+  formals:     returns: <none>
+  state: { x; y; z }
+         { *x; *y; *z; s1->fst; s1->snd; s2->fst; s2->snd; t; a; b; c; 
+           s.fst; s.snd }
+         { s1; s2 }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/offsets/oracle/nested1.res.oracle b/src/plugins/alias/tests/offsets/oracle/nested1.res.oracle
index a5a58748f913ad57827319f33d80698f0cd9f96a..f9bd813190c345c46dd5df0a24f27e1ae9707ec1 100644
--- a/src/plugins/alias/tests/offsets/oracle/nested1.res.oracle
+++ b/src/plugins/alias/tests/offsets/oracle/nested1.res.oracle
@@ -1,168 +1,140 @@
 [kernel] Parsing nested1.c (with preprocessing)
-[alias] analysing function: _Exit
-[alias] May-aliases at the end of function _Exit: ⊥
-[alias] analysing function: abort
-[alias] May-aliases at the end of function abort: ⊥
-[alias] analysing function: abs
-[alias] May-aliases at the end of function abs: ⊥
-[alias] analysing function: at_quick_exit
-[alias] May-aliases at the end of function at_quick_exit: ⊥
-[alias] analysing function: atexit
-[alias] May-aliases at the end of function atexit: ⊥
-[alias] analysing function: atof
-[alias] May-aliases at the end of function atof: ⊥
-[alias] analysing function: atoi
-[alias] May-aliases at the end of function atoi: ⊥
-[alias] analysing function: atol
-[alias] May-aliases at the end of function atol: ⊥
-[alias] analysing function: atoll
-[alias] May-aliases at the end of function atoll: ⊥
-[alias] analysing function: bsearch
-[alias] May-aliases at the end of function bsearch: ⊥
-[alias] analysing function: calloc
-[alias] May-aliases at the end of function calloc: ⊥
-[alias] analysing function: div
-[alias] May-aliases at the end of function div: ⊥
-[alias] analysing function: drand48
-[alias] May-aliases at the end of function drand48: ⊥
-[alias] analysing function: erand48
-[alias] May-aliases at the end of function erand48: ⊥
-[alias] analysing function: exit
-[alias] May-aliases at the end of function exit: ⊥
-[alias] analysing function: free
-[alias] May-aliases at the end of function free: ⊥
-[alias] analysing function: getenv
-[alias] May-aliases at the end of function getenv: ⊥
-[alias] analysing function: jrand48
-[alias] May-aliases at the end of function jrand48: ⊥
-[alias] analysing function: labs
-[alias] May-aliases at the end of function labs: ⊥
-[alias] analysing function: lcong48
-[alias] May-aliases at the end of function lcong48: ⊥
-[alias] analysing function: ldiv
-[alias] May-aliases at the end of function ldiv: ⊥
-[alias] analysing function: llabs
-[alias] May-aliases at the end of function llabs: ⊥
-[alias] analysing function: lldiv
-[alias] May-aliases at the end of function lldiv: ⊥
-[alias] analysing function: lrand48
-[alias] May-aliases at the end of function lrand48: ⊥
 [alias] analysing function: main
 [alias] analysing instruction: st_1_t x1 = {.a = 0, .b = 1};
 [alias] May-aliases after instruction  st_1_t x1 = {.a = 0, .b = 1};  are  <none>
+[alias] May-alias graph after instruction  st_1_t x1 = {.a = 0, .b = 1};  is
+  <empty>
 [alias] analysing instruction: st_1_t x2 = {.a = 1, .b = 2};
 [alias] May-aliases after instruction  st_1_t x2 = {.a = 1, .b = 2};  are  <none>
+[alias] May-alias graph after instruction  st_1_t x2 = {.a = 1, .b = 2};  is
+  <empty>
 [alias] analysing instruction: tab_y[0] = & x1;
 [alias] May-aliases after instruction  tab_y[0] = & x1;  are  <none>
+[alias] May-alias graph after instruction  tab_y[0] = & x1;  is
+  0:{ tab_y } → 1:{  }   1:{  } → 2:{ x1 }
 [alias] analysing instruction: tab_y[1] = & x2;
 [alias] May-aliases after instruction  tab_y[1] = & x2;  are  <none>
+[alias] May-alias graph after instruction  tab_y[1] = & x2;  is
+  0:{ tab_y } → 1:{  }   1:{  } → 2:{ x1; x2 }
 [alias] analysing instruction: st_2_t *z1 = malloc(sizeof(st_2_t));
 [alias] May-aliases after instruction  st_2_t *z1 = malloc(sizeof(st_2_t));  are
   <none>
+[alias] May-alias graph after instruction  st_2_t *z1 = malloc(sizeof(st_2_t));
+  is    0:{ tab_y } → 1:{  }   1:{  } → 2:{ x1; x2 }   7:{ z1 } → 8:{  }
 [alias] analysing instruction: st_2_t *z2 = malloc(sizeof(st_2_t));
 [alias] May-aliases after instruction  st_2_t *z2 = malloc(sizeof(st_2_t));  are
   <none>
+[alias] May-alias graph after instruction  st_2_t *z2 = malloc(sizeof(st_2_t));
+  is
+  0:{ tab_y } → 1:{  }   1:{  } → 2:{ x1; x2 }   7:{ z1 } → 8:{  }
+  9:{ z2 } → 10:{  }
 [alias] analysing instruction: st_3_t *t = malloc(sizeof(st_3_t));
 [alias] May-aliases after instruction  st_3_t *t = malloc(sizeof(st_3_t));  are
   <none>
+[alias] May-alias graph after instruction  st_3_t *t = malloc(sizeof(st_3_t));  is
+  0:{ tab_y } → 1:{  }   1:{  } → 2:{ x1; x2 }   7:{ z1 } → 8:{  }
+  9:{ z2 } → 10:{  }   11:{ t } → 12:{  }
 [alias] analysing instruction: int *a = malloc(sizeof(int));
 [alias] May-aliases after instruction  int *a = malloc(sizeof(int));  are  <none>
+[alias] May-alias graph after instruction  int *a = malloc(sizeof(int));  is
+  0:{ tab_y } → 1:{  }   1:{  } → 2:{ x1; x2 }   7:{ z1 } → 8:{  }
+  9:{ z2 } → 10:{  }   11:{ t } → 12:{  }   13:{ a } → 14:{  }
 [alias] analysing instruction: int *b = malloc(sizeof(int));
 [alias] May-aliases after instruction  int *b = malloc(sizeof(int));  are  <none>
+[alias] May-alias graph after instruction  int *b = malloc(sizeof(int));  is
+  0:{ tab_y } → 1:{  }   1:{  } → 2:{ x1; x2 }   7:{ z1 } → 8:{  }
+  9:{ z2 } → 10:{  }   11:{ t } → 12:{  }   13:{ a } → 14:{  }
+  15:{ b } → 16:{  }
 [alias] analysing instruction: *a = 0;
 [alias] May-aliases after instruction  *a = 0;  are  <none>
+[alias] May-alias graph after instruction  *a = 0;  is
+  0:{ tab_y } → 1:{  }   1:{  } → 2:{ x1; x2 }   7:{ z1 } → 8:{  }
+  9:{ z2 } → 10:{  }   11:{ t } → 12:{  }   13:{ a } → 14:{  }
+  15:{ b } → 16:{  }
 [alias] analysing instruction: *b = 5;
 [alias] May-aliases after instruction  *b = 5;  are  <none>
+[alias] May-alias graph after instruction  *b = 5;  is
+  0:{ tab_y } → 1:{  }   1:{  } → 2:{ x1; x2 }   7:{ z1 } → 8:{  }
+  9:{ z2 } → 10:{  }   11:{ t } → 12:{  }   13:{ a } → 14:{  }
+  15:{ b } → 16:{  }
 [alias] analysing instruction: z1->s = (struct struct_1_t *)tab_y[0];
 [alias:unsafe-cast] nested1.c:47: Warning: 
-  unsafe cast from st_1_t * to struct struct_1_t *
+  unsafe cast from st_1_t * to struct struct_1_t *; analysis may be unsound
 [alias] May-aliases after instruction  z1->s = (struct struct_1_t *)tab_y[0];  are
   { z1->s; tab_y[0..] }
+[alias] May-alias graph after instruction  z1->s = (struct struct_1_t *)tab_y[0];
+  is
+  0:{ tab_y } → 17:{  }   7:{ z1 } → 8:{  }   8:{  } -s→ 17:{  }
+  9:{ z2 } → 10:{  }   11:{ t } → 12:{  }   13:{ a } → 14:{  }
+  15:{ b } → 16:{  }   17:{  } → 2:{ x1; x2 }
 [alias] analysing instruction: z2->s = (struct struct_1_t *)tab_y[1];
 [alias:unsafe-cast] nested1.c:48: Warning: 
-  unsafe cast from st_1_t * to struct struct_1_t *
+  unsafe cast from st_1_t * to struct struct_1_t *; analysis may be unsound
 [alias] May-aliases after instruction  z2->s = (struct struct_1_t *)tab_y[1];  are
   { z1->s; z2->s; tab_y[0..] }
+[alias] May-alias graph after instruction  z2->s = (struct struct_1_t *)tab_y[1];
+  is
+  0:{ tab_y } → 18:{  }   7:{ z1 } → 8:{  }   8:{  } -s→ 18:{  }
+  9:{ z2 } → 10:{  }   10:{  } -s→ 18:{  }   11:{ t } → 12:{  }
+  13:{ a } → 14:{  }   15:{ b } → 16:{  }   18:{  } → 2:{ x1; x2 }
 [alias] analysing instruction: z1->c = a;
 [alias] May-aliases after instruction  z1->c = a;  are
   { z1->s; z2->s; tab_y[0..] }  { z1->c; a }
+[alias] May-alias graph after instruction  z1->c = a;  is
+  0:{ tab_y } → 18:{  }   7:{ z1 } → 8:{  }   8:{  } -s→ 18:{  }
+  8:{  } -c→ 19:{ a }   9:{ z2 } → 10:{  }   10:{  } -s→ 18:{  }
+  11:{ t } → 12:{  }   15:{ b } → 16:{  }   18:{  } → 2:{ x1; x2 }
+  19:{ a } → 14:{  }
 [alias] analysing instruction: z2->c = b;
 [alias] May-aliases after instruction  z2->c = b;  are
   { z1->s; z2->s; tab_y[0..] }  { z1->c; a }  { z2->c; b }
+[alias] May-alias graph after instruction  z2->c = b;  is
+  0:{ tab_y } → 18:{  }   7:{ z1 } → 8:{  }   8:{  } -s→ 18:{  }
+  8:{  } -c→ 19:{ a }   9:{ z2 } → 10:{  }   10:{  } -s→ 18:{  }
+  10:{  } -c→ 20:{ b }   11:{ t } → 12:{  }   18:{  } → 2:{ x1; x2 }
+  19:{ a } → 14:{  }   20:{ b } → 16:{  }
 [alias] analysing instruction: t->t = (struct struct_2_t *)z1;
 [alias:unsafe-cast] nested1.c:51: Warning: 
-  unsafe cast from st_2_t * to struct struct_2_t *
+  unsafe cast from st_2_t * to struct struct_2_t *; analysis may be unsound
 [alias] May-aliases after instruction  t->t = (struct struct_2_t *)z1;  are
-  { z1->s; z2->s; tab_y[0..] }  { t->t; z1 }  { z1->c; a }  { z2->c; b }
+  { (t->t)->s; z1->s; z2->s; tab_y[0..] }  { t->t; z1 }
+  { (t->t)->c; z1->c; a }  { z2->c; b }
+[alias] May-alias graph after instruction  t->t = (struct struct_2_t *)z1;  is
+  0:{ tab_y } → 18:{  }   8:{  } -s→ 18:{  }   8:{  } -c→ 19:{ a }
+  9:{ z2 } → 10:{  }   10:{  } -s→ 18:{  }   10:{  } -c→ 20:{ b }
+  11:{ t } → 12:{  }   12:{  } -t→ 21:{ z1 }   18:{  } → 2:{ x1; x2 }
+  19:{ a } → 14:{  }   20:{ b } → 16:{  }   21:{ z1 } → 8:{  }
 [alias] analysing instruction: t->d = a;
 [alias] May-aliases after instruction  t->d = a;  are
-  { z1->s; z2->s; tab_y[0..] }  { t->t; z1 }  { z1->c; t->d; a }  { z2->c; b }
+  { (t->t)->s; z1->s; z2->s; tab_y[0..] }  { t->t; z1 }
+  { (t->t)->c; z1->c; t->d; a }  { z2->c; b }
+[alias] May-alias graph after instruction  t->d = a;  is
+  0:{ tab_y } → 18:{  }   8:{  } -s→ 18:{  }   8:{  } -c→ 22:{ a }
+  9:{ z2 } → 10:{  }   10:{  } -s→ 18:{  }   10:{  } -c→ 20:{ b }
+  11:{ t } → 12:{  }   12:{  } -t→ 21:{ z1 }   12:{  } -d→ 22:{ a }
+  18:{  } → 2:{ x1; x2 }   20:{ b } → 16:{  }   21:{ z1 } → 8:{  }
+  22:{ a } → 14:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are
-  { z1->s; z2->s; tab_y[0..] }  { t->t; z1 }  { z1->c; t->d; a }  { z2->c; b }
+  { (t->t)->s; z1->s; z2->s; tab_y[0..] }  { t->t; z1 }
+  { (t->t)->c; z1->c; t->d; a }  { z2->c; b }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ tab_y } → 18:{  }   8:{  } -s→ 18:{  }   8:{  } -c→ 22:{ a }
+  9:{ z2 } → 10:{  }   10:{  } -s→ 18:{  }   10:{  } -c→ 20:{ b }
+  11:{ t } → 12:{  }   12:{  } -t→ 21:{ z1 }   12:{  } -d→ 22:{ a }
+  18:{  } → 2:{ x1; x2 }   20:{ b } → 16:{  }   21:{ z1 } → 8:{  }
+  22:{ a } → 14:{  }
 [alias] May-aliases at the end of function main:
-  { z1->s; z2->s; tab_y[0..] }  { t->t; z1 }  { z1->c; t->d; a }  { z2->c; b }
-[alias] analysing function: malloc
-[alias] May-aliases at the end of function malloc: ⊥
-[alias] analysing function: mblen
-[alias] May-aliases at the end of function mblen: ⊥
-[alias] analysing function: mbstowcs
-[alias] May-aliases at the end of function mbstowcs: ⊥
-[alias] analysing function: mbtowc
-[alias] May-aliases at the end of function mbtowc: ⊥
-[alias] analysing function: mkstemp
-[alias] May-aliases at the end of function mkstemp: ⊥
-[alias] analysing function: mkstemps
-[alias] May-aliases at the end of function mkstemps: ⊥
-[alias] analysing function: mrand48
-[alias] May-aliases at the end of function mrand48: ⊥
-[alias] analysing function: nrand48
-[alias] May-aliases at the end of function nrand48: ⊥
-[alias] analysing function: posix_memalign
-[alias] May-aliases at the end of function posix_memalign: ⊥
-[alias] analysing function: putenv
-[alias] May-aliases at the end of function putenv: ⊥
-[alias] analysing function: qsort
-[alias] May-aliases at the end of function qsort: ⊥
-[alias] analysing function: quick_exit
-[alias] May-aliases at the end of function quick_exit: ⊥
-[alias] analysing function: rand
-[alias] May-aliases at the end of function rand: ⊥
-[alias] analysing function: random
-[alias] May-aliases at the end of function random: ⊥
-[alias] analysing function: realloc
-[alias] May-aliases at the end of function realloc: ⊥
-[alias] analysing function: reallocarray
-[alias] May-aliases at the end of function reallocarray: ⊥
-[alias] analysing function: seed48
-[alias] May-aliases at the end of function seed48: ⊥
-[alias] analysing function: setenv
-[alias] May-aliases at the end of function setenv: ⊥
-[alias] analysing function: srand
-[alias] May-aliases at the end of function srand: ⊥
-[alias] analysing function: srand48
-[alias] May-aliases at the end of function srand48: ⊥
-[alias] analysing function: srandom
-[alias] May-aliases at the end of function srandom: ⊥
-[alias] analysing function: strtod
-[alias] May-aliases at the end of function strtod: ⊥
-[alias] analysing function: strtof
-[alias] May-aliases at the end of function strtof: ⊥
-[alias] analysing function: strtol
-[alias] May-aliases at the end of function strtol: ⊥
-[alias] analysing function: strtold
-[alias] May-aliases at the end of function strtold: ⊥
-[alias] analysing function: strtoll
-[alias] May-aliases at the end of function strtoll: ⊥
-[alias] analysing function: strtoul
-[alias] May-aliases at the end of function strtoul: ⊥
-[alias] analysing function: strtoull
-[alias] May-aliases at the end of function strtoull: ⊥
-[alias] analysing function: system
-[alias] May-aliases at the end of function system: ⊥
-[alias] analysing function: unsetenv
-[alias] May-aliases at the end of function unsetenv: ⊥
-[alias] analysing function: wcstombs
-[alias] May-aliases at the end of function wcstombs: ⊥
-[alias] analysing function: wctomb
-[alias] May-aliases at the end of function wctomb: ⊥
+  { (t->t)->s; z1->s; z2->s; tab_y[0..] }  { t->t; z1 }
+  { (t->t)->c; z1->c; t->d; a }  { z2->c; b }
+[alias] May-alias graph at the end of function main:
+  0:{ tab_y } → 18:{  }   8:{  } -s→ 18:{  }   8:{  } -c→ 22:{ a }
+  9:{ z2 } → 10:{  }   10:{  } -s→ 18:{  }   10:{  } -c→ 20:{ b }
+  11:{ t } → 12:{  }   12:{  } -t→ 21:{ z1 }   12:{  } -d→ 22:{ a }
+  18:{  } → 2:{ x1; x2 }   20:{ b } → 16:{  }   21:{ z1 } → 8:{  }
+  22:{ a } → 14:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres
+  state: { (t->t)->s; z1->s; z2->s; tab_y[0..] }  { t->t; z1 }
+         { (t->t)->c; z1->c; t->d; a }  { z2->c; b }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/offsets/oracle/nested2.res.oracle b/src/plugins/alias/tests/offsets/oracle/nested2.res.oracle
index 3ec5a96f69efd55ea069b46b315fce29e468141b..85015cf9c50e50606ab4352c4a8c0b61ea586f17 100644
--- a/src/plugins/alias/tests/offsets/oracle/nested2.res.oracle
+++ b/src/plugins/alias/tests/offsets/oracle/nested2.res.oracle
@@ -1,152 +1,90 @@
 [kernel] Parsing nested2.c (with preprocessing)
-[alias] analysing function: _Exit
-[alias] May-aliases at the end of function _Exit: ⊥
-[alias] analysing function: abort
-[alias] May-aliases at the end of function abort: ⊥
-[alias] analysing function: abs
-[alias] May-aliases at the end of function abs: ⊥
-[alias] analysing function: at_quick_exit
-[alias] May-aliases at the end of function at_quick_exit: ⊥
-[alias] analysing function: atexit
-[alias] May-aliases at the end of function atexit: ⊥
-[alias] analysing function: atof
-[alias] May-aliases at the end of function atof: ⊥
-[alias] analysing function: atoi
-[alias] May-aliases at the end of function atoi: ⊥
-[alias] analysing function: atol
-[alias] May-aliases at the end of function atol: ⊥
-[alias] analysing function: atoll
-[alias] May-aliases at the end of function atoll: ⊥
-[alias] analysing function: bsearch
-[alias] May-aliases at the end of function bsearch: ⊥
-[alias] analysing function: calloc
-[alias] May-aliases at the end of function calloc: ⊥
-[alias] analysing function: div
-[alias] May-aliases at the end of function div: ⊥
-[alias] analysing function: drand48
-[alias] May-aliases at the end of function drand48: ⊥
-[alias] analysing function: erand48
-[alias] May-aliases at the end of function erand48: ⊥
-[alias] analysing function: exit
-[alias] May-aliases at the end of function exit: ⊥
-[alias] analysing function: free
-[alias] May-aliases at the end of function free: ⊥
-[alias] analysing function: getenv
-[alias] May-aliases at the end of function getenv: ⊥
-[alias] analysing function: jrand48
-[alias] May-aliases at the end of function jrand48: ⊥
-[alias] analysing function: labs
-[alias] May-aliases at the end of function labs: ⊥
-[alias] analysing function: lcong48
-[alias] May-aliases at the end of function lcong48: ⊥
-[alias] analysing function: ldiv
-[alias] May-aliases at the end of function ldiv: ⊥
-[alias] analysing function: llabs
-[alias] May-aliases at the end of function llabs: ⊥
-[alias] analysing function: lldiv
-[alias] May-aliases at the end of function lldiv: ⊥
-[alias] analysing function: lrand48
-[alias] May-aliases at the end of function lrand48: ⊥
 [alias] analysing function: main
 [alias] analysing instruction: st_1_t x1 = {.a = 0, .b = 1};
 [alias] May-aliases after instruction  st_1_t x1 = {.a = 0, .b = 1};  are  <none>
+[alias] May-alias graph after instruction  st_1_t x1 = {.a = 0, .b = 1};  is
+  <empty>
 [alias] analysing instruction: st_1_t x2 = {.a = 2, .b = 3};
 [alias] May-aliases after instruction  st_1_t x2 = {.a = 2, .b = 3};  are  <none>
+[alias] May-alias graph after instruction  st_1_t x2 = {.a = 2, .b = 3};  is
+  <empty>
 [alias] analysing instruction: st_2_t *z1 = malloc(sizeof(st_2_t));
 [alias] May-aliases after instruction  st_2_t *z1 = malloc(sizeof(st_2_t));  are
   <none>
+[alias] May-alias graph after instruction  st_2_t *z1 = malloc(sizeof(st_2_t));
+  is    0:{ z1 } → 1:{  }
 [alias] analysing instruction: st_3_t *t = malloc(sizeof(st_3_t));
 [alias] May-aliases after instruction  st_3_t *t = malloc(sizeof(st_3_t));  are
   <none>
+[alias] May-alias graph after instruction  st_3_t *t = malloc(sizeof(st_3_t));  is
+  0:{ z1 } → 1:{  }   2:{ t } → 3:{  }
 [alias] analysing instruction: int *a = malloc(sizeof(int));
 [alias] May-aliases after instruction  int *a = malloc(sizeof(int));  are  <none>
+[alias] May-alias graph after instruction  int *a = malloc(sizeof(int));  is
+  0:{ z1 } → 1:{  }   2:{ t } → 3:{  }   4:{ a } → 5:{  }
 [alias] analysing instruction: *a = 0;
 [alias] May-aliases after instruction  *a = 0;  are  <none>
+[alias] May-alias graph after instruction  *a = 0;  is
+  0:{ z1 } → 1:{  }   2:{ t } → 3:{  }   4:{ a } → 5:{  }
 [alias] analysing instruction: z1->s[0] = (struct struct_1_t *)(& x1);
 [alias:unsafe-cast] nested2.c:42: Warning: 
-  unsafe cast from st_1_t * to struct struct_1_t *
+  unsafe cast from st_1_t * to struct struct_1_t *; analysis may be unsound
 [alias] May-aliases after instruction  z1->s[0] = (struct struct_1_t *)(& x1);  are
   <none>
+[alias] May-alias graph after instruction  z1->s[0] = (struct struct_1_t *)(& x1);
+  is
+  0:{ z1 } → 1:{  }   1:{  } -s→ 6:{  }   2:{ t } → 3:{  }
+  4:{ a } → 5:{  }   6:{  } → 7:{  }   7:{  } → 8:{ x1 }
 [alias] analysing instruction: z1->s[1] = (struct struct_1_t *)(& x2);
 [alias:unsafe-cast] nested2.c:43: Warning: 
-  unsafe cast from st_1_t * to struct struct_1_t *
+  unsafe cast from st_1_t * to struct struct_1_t *; analysis may be unsound
 [alias] May-aliases after instruction  z1->s[1] = (struct struct_1_t *)(& x2);  are
   <none>
+[alias] May-alias graph after instruction  z1->s[1] = (struct struct_1_t *)(& x2);
+  is
+  0:{ z1 } → 1:{  }   1:{  } -s→ 6:{  }   2:{ t } → 3:{  }
+  4:{ a } → 5:{  }   6:{  } → 7:{  }   7:{  } → 8:{ x1; x2 }
 [alias] analysing instruction: z1->c = a;
 [alias] May-aliases after instruction  z1->c = a;  are  { z1->c; a }
+[alias] May-alias graph after instruction  z1->c = a;  is
+  0:{ z1 } → 1:{  }   1:{  } -s→ 6:{  }   1:{  } -c→ 12:{ a }
+  2:{ t } → 3:{  }   6:{  } → 7:{  }   7:{  } → 8:{ x1; x2 }
+  12:{ a } → 5:{  }
 [alias] analysing instruction: t->t = (struct struct_2_t *)z1;
 [alias:unsafe-cast] nested2.c:45: Warning: 
-  unsafe cast from st_2_t * to struct struct_2_t *
+  unsafe cast from st_2_t * to struct struct_2_t *; analysis may be unsound
 [alias] May-aliases after instruction  t->t = (struct struct_2_t *)z1;  are
-  { t->t; z1 }  { z1->c; a }
+  { t->t; z1 }  { (t->t)->c; z1->c; a }  { (t->t)->s; z1->s }
+  { (t->t)->s[0..]; z1->s[0..] }
+[alias] May-alias graph after instruction  t->t = (struct struct_2_t *)z1;  is
+  1:{  } -s→ 6:{  }   1:{  } -c→ 12:{ a }   2:{ t } → 3:{  }
+  3:{  } -t→ 13:{ z1 }   6:{  } → 7:{  }   7:{  } → 8:{ x1; x2 }
+  12:{ a } → 5:{  }   13:{ z1 } → 1:{  }
 [alias] analysing instruction: t->d = a;
 [alias] May-aliases after instruction  t->d = a;  are
-  { t->t; z1 }  { z1->c; t->d; a }
+  { t->t; z1 }  { (t->t)->c; z1->c; t->d; a }  { (t->t)->s; z1->s }
+  { (t->t)->s[0..]; z1->s[0..] }
+[alias] May-alias graph after instruction  t->d = a;  is
+  1:{  } -s→ 6:{  }   1:{  } -c→ 14:{ a }   2:{ t } → 3:{  }
+  3:{  } -t→ 13:{ z1 }   3:{  } -d→ 14:{ a }   6:{  } → 7:{  }
+  7:{  } → 8:{ x1; x2 }   13:{ z1 } → 1:{  }   14:{ a } → 5:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are
-  { t->t; z1 }  { z1->c; t->d; a }
-[alias] May-aliases at the end of function main: { t->t; z1 }  { z1->c; t->d; a }
-[alias] analysing function: malloc
-[alias] May-aliases at the end of function malloc: ⊥
-[alias] analysing function: mblen
-[alias] May-aliases at the end of function mblen: ⊥
-[alias] analysing function: mbstowcs
-[alias] May-aliases at the end of function mbstowcs: ⊥
-[alias] analysing function: mbtowc
-[alias] May-aliases at the end of function mbtowc: ⊥
-[alias] analysing function: mkstemp
-[alias] May-aliases at the end of function mkstemp: ⊥
-[alias] analysing function: mkstemps
-[alias] May-aliases at the end of function mkstemps: ⊥
-[alias] analysing function: mrand48
-[alias] May-aliases at the end of function mrand48: ⊥
-[alias] analysing function: nrand48
-[alias] May-aliases at the end of function nrand48: ⊥
-[alias] analysing function: posix_memalign
-[alias] May-aliases at the end of function posix_memalign: ⊥
-[alias] analysing function: putenv
-[alias] May-aliases at the end of function putenv: ⊥
-[alias] analysing function: qsort
-[alias] May-aliases at the end of function qsort: ⊥
-[alias] analysing function: quick_exit
-[alias] May-aliases at the end of function quick_exit: ⊥
-[alias] analysing function: rand
-[alias] May-aliases at the end of function rand: ⊥
-[alias] analysing function: random
-[alias] May-aliases at the end of function random: ⊥
-[alias] analysing function: realloc
-[alias] May-aliases at the end of function realloc: ⊥
-[alias] analysing function: reallocarray
-[alias] May-aliases at the end of function reallocarray: ⊥
-[alias] analysing function: seed48
-[alias] May-aliases at the end of function seed48: ⊥
-[alias] analysing function: setenv
-[alias] May-aliases at the end of function setenv: ⊥
-[alias] analysing function: srand
-[alias] May-aliases at the end of function srand: ⊥
-[alias] analysing function: srand48
-[alias] May-aliases at the end of function srand48: ⊥
-[alias] analysing function: srandom
-[alias] May-aliases at the end of function srandom: ⊥
-[alias] analysing function: strtod
-[alias] May-aliases at the end of function strtod: ⊥
-[alias] analysing function: strtof
-[alias] May-aliases at the end of function strtof: ⊥
-[alias] analysing function: strtol
-[alias] May-aliases at the end of function strtol: ⊥
-[alias] analysing function: strtold
-[alias] May-aliases at the end of function strtold: ⊥
-[alias] analysing function: strtoll
-[alias] May-aliases at the end of function strtoll: ⊥
-[alias] analysing function: strtoul
-[alias] May-aliases at the end of function strtoul: ⊥
-[alias] analysing function: strtoull
-[alias] May-aliases at the end of function strtoull: ⊥
-[alias] analysing function: system
-[alias] May-aliases at the end of function system: ⊥
-[alias] analysing function: unsetenv
-[alias] May-aliases at the end of function unsetenv: ⊥
-[alias] analysing function: wcstombs
-[alias] May-aliases at the end of function wcstombs: ⊥
-[alias] analysing function: wctomb
-[alias] May-aliases at the end of function wctomb: ⊥
+  { t->t; z1 }  { (t->t)->c; z1->c; t->d; a }  { (t->t)->s; z1->s }
+  { (t->t)->s[0..]; z1->s[0..] }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  1:{  } -s→ 6:{  }   1:{  } -c→ 14:{ a }   2:{ t } → 3:{  }
+  3:{  } -t→ 13:{ z1 }   3:{  } -d→ 14:{ a }   6:{  } → 7:{  }
+  7:{  } → 8:{ x1; x2 }   13:{ z1 } → 1:{  }   14:{ a } → 5:{  }
+[alias] May-aliases at the end of function main:
+  { t->t; z1 }  { (t->t)->c; z1->c; t->d; a }  { (t->t)->s; z1->s }
+  { (t->t)->s[0..]; z1->s[0..] }
+[alias] May-alias graph at the end of function main:
+  1:{  } -s→ 6:{  }   1:{  } -c→ 14:{ a }   2:{ t } → 3:{  }
+  3:{  } -t→ 13:{ z1 }   3:{  } -d→ 14:{ a }   6:{  } → 7:{  }
+  7:{  } → 8:{ x1; x2 }   13:{ z1 } → 1:{  }   14:{ a } → 5:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres
+  state: { t->t; z1 }  { (t->t)->c; z1->c; t->d; a }  { (t->t)->s; z1->s }
+         { (t->t)->s[0..]; z1->s[0..] }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/offsets/oracle/structure1.res.oracle b/src/plugins/alias/tests/offsets/oracle/structure1.res.oracle
index b325558af323d355e913457f624f99202dc3c3bb..e637a626f9b16410fe49a58e18203b19e122598e 100644
--- a/src/plugins/alias/tests/offsets/oracle/structure1.res.oracle
+++ b/src/plugins/alias/tests/offsets/oracle/structure1.res.oracle
@@ -2,18 +2,37 @@
 [alias] analysing function: main
 [alias] analysing instruction: st_1_t x = {.a = 0, .b = 1};
 [alias] May-aliases after instruction  st_1_t x = {.a = 0, .b = 1};  are  <none>
+[alias] May-alias graph after instruction  st_1_t x = {.a = 0, .b = 1};  is
+  <empty>
 [alias] analysing instruction: st_2_t y = {.a = 3, .c = 4};
 [alias] May-aliases after instruction  st_2_t y = {.a = 3, .c = 4};  are  <none>
+[alias] May-alias graph after instruction  st_2_t y = {.a = 3, .c = 4};  is
+  <empty>
 [alias] analysing instruction: st_1_t *p_x = & x;
 [alias] May-aliases after instruction  st_1_t *p_x = & x;  are  <none>
+[alias] May-alias graph after instruction  st_1_t *p_x = & x;  is
+  0:{ p_x } → 1:{ x }
 [alias] analysing instruction: st_2_t *p_y = & y;
 [alias] May-aliases after instruction  st_2_t *p_y = & y;  are  <none>
+[alias] May-alias graph after instruction  st_2_t *p_y = & y;  is
+  0:{ p_x } → 1:{ x }   4:{ p_y } → 5:{ y }
 [alias] analysing instruction: p_x->a = 3;
 [alias] May-aliases after instruction  p_x->a = 3;  are  <none>
+[alias] May-alias graph after instruction  p_x->a = 3;  is
+  0:{ p_x } → 1:{ x }   4:{ p_y } → 5:{ y }
 [alias] analysing instruction: p_x = (st_1_t *)p_y;
 [alias:unsafe-cast] structure1.c:28: Warning: 
-  unsafe cast from st_2_t * to st_1_t *
+  unsafe cast from st_2_t * to st_1_t *; analysis may be unsound
 [alias] May-aliases after instruction  p_x = (st_1_t *)p_y;  are  { p_x; p_y }
+[alias] May-alias graph after instruction  p_x = (st_1_t *)p_y;  is
+  0:{ p_x; p_y } → 1:{ x; y }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  { p_x; p_y }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ p_x; p_y } → 1:{ x; y }
 [alias] May-aliases at the end of function main: { p_x; p_y }
+[alias] May-alias graph at the end of function main:
+  0:{ p_x; p_y } → 1:{ x; y }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { p_x; p_y }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/offsets/oracle/structure2.res.oracle b/src/plugins/alias/tests/offsets/oracle/structure2.res.oracle
index 2b2f7ecd4e531f1ec02f3d115396b6b6f0de27d0..b278d558f710585ab6b6063d25fe40f7be6335b2 100644
--- a/src/plugins/alias/tests/offsets/oracle/structure2.res.oracle
+++ b/src/plugins/alias/tests/offsets/oracle/structure2.res.oracle
@@ -2,18 +2,34 @@
 [alias] analysing function: main
 [alias] analysing instruction: st_1_t x1 = {.a = 0, .b = 1};
 [alias] May-aliases after instruction  st_1_t x1 = {.a = 0, .b = 1};  are  <none>
+[alias] May-alias graph after instruction  st_1_t x1 = {.a = 0, .b = 1};  is
+  <empty>
 [alias] analysing instruction: st_1_t x2 = {.a = 1, .b = 2};
 [alias] May-aliases after instruction  st_1_t x2 = {.a = 1, .b = 2};  are  <none>
+[alias] May-alias graph after instruction  st_1_t x2 = {.a = 1, .b = 2};  is
+  <empty>
 [alias] analysing instruction: st_2_t y = {.s = (struct struct_1_t *)(& x1), .c = 4};
 [alias:unsafe-cast] structure2.c:21: Warning: 
-  unsafe cast from st_1_t * to struct struct_1_t *
+  unsafe cast from st_1_t * to struct struct_1_t *; analysis may be unsound
 [alias] May-aliases after instruction
   st_2_t y = {.s = (struct struct_1_t *)(& x1), .c = 4};  are  <none>
+[alias] May-alias graph after instruction
+  st_2_t y = {.s = (struct struct_1_t *)(& x1), .c = 4};  is
+  0:{ y } -s→ 1:{  }   1:{  } → 2:{ x1 }
 [alias] analysing instruction: y.s = (struct struct_1_t *)(& x2);
 [alias:unsafe-cast] structure2.c:23: Warning: 
-  unsafe cast from st_1_t * to struct struct_1_t *
+  unsafe cast from st_1_t * to struct struct_1_t *; analysis may be unsound
 [alias] May-aliases after instruction  y.s = (struct struct_1_t *)(& x2);  are
   <none>
+[alias] May-alias graph after instruction  y.s = (struct struct_1_t *)(& x2);  is
+  0:{ y } -s→ 1:{  }   1:{  } → 2:{ x1; x2 }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  <none>
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ y } -s→ 1:{  }   1:{  } → 2:{ x1; x2 }
 [alias] May-aliases at the end of function main: <none>
+[alias] May-alias graph at the end of function main:
+  0:{ y } -s→ 1:{  }   1:{  } → 2:{ x1; x2 }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: <none>
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/offsets/oracle/structure3.res.oracle b/src/plugins/alias/tests/offsets/oracle/structure3.res.oracle
index 7ec86d402cb6980ff01296b3901039b234b94464..2b7b2eb6949cf5f3dfd5dedffd72c02d3da00860 100644
--- a/src/plugins/alias/tests/offsets/oracle/structure3.res.oracle
+++ b/src/plugins/alias/tests/offsets/oracle/structure3.res.oracle
@@ -2,32 +2,46 @@
 [alias] analysing function: main
 [alias] analysing instruction: st_1_t x1 = {.a = 0, .b = 1};
 [alias] May-aliases after instruction  st_1_t x1 = {.a = 0, .b = 1};  are  <none>
+[alias] May-alias graph after instruction  st_1_t x1 = {.a = 0, .b = 1};  is
+  <empty>
 [alias] analysing instruction: st_1_t x2 = {.a = 1, .b = 2};
 [alias] May-aliases after instruction  st_1_t x2 = {.a = 1, .b = 2};  are  <none>
-[alias] analysing instruction:
-  st_2_t y1 = {.s = (struct struct_1_t *)(& x1), .c = 3};
-[alias:unsafe-cast] structure3.c:31: Warning: 
-  unsafe cast from st_1_t * to struct struct_1_t *
-[alias] May-aliases after instruction
-  st_2_t y1 = {.s = (struct struct_1_t *)(& x1), .c = 3};  are  <none>
-[alias] analysing instruction:
-  st_2_t y2 = {.s = (struct struct_1_t *)(& x2), .c = 4};
-[alias:unsafe-cast] structure3.c:32: Warning: 
-  unsafe cast from st_1_t * to struct struct_1_t *
-[alias] May-aliases after instruction
-  st_2_t y2 = {.s = (struct struct_1_t *)(& x2), .c = 4};  are  <none>
-[alias] analysing instruction: st_3_t z = {.t = (struct struct_2_t *)(& y1), .d = 5};
-[alias:unsafe-cast] structure3.c:33: Warning: 
-  unsafe cast from st_2_t * to struct struct_2_t *
-[alias] May-aliases after instruction
-  st_3_t z = {.t = (struct struct_2_t *)(& y1), .d = 5};  are  <none>
-[alias] analysing instruction: z.t = (struct struct_2_t *)(& y2);
-[alias:unsafe-cast] structure3.c:35: Warning: 
-  unsafe cast from st_2_t * to struct struct_2_t *
-[alias] May-aliases after instruction  z.t = (struct struct_2_t *)(& y2);  are
-  <none>
+[alias] May-alias graph after instruction  st_1_t x2 = {.a = 1, .b = 2};  is
+  <empty>
+[alias] analysing instruction: st_2_t y1 = {.s = & x1, .c = 3};
+[alias] May-aliases after instruction  st_2_t y1 = {.s = & x1, .c = 3};  are  <none>
+[alias] May-alias graph after instruction  st_2_t y1 = {.s = & x1, .c = 3};  is
+  0:{ y1 } -s→ 1:{  }   1:{  } → 2:{ x1 }
+[alias] analysing instruction: st_2_t y2 = {.s = & x2, .c = 4};
+[alias] May-aliases after instruction  st_2_t y2 = {.s = & x2, .c = 4};  are  <none>
+[alias] May-alias graph after instruction  st_2_t y2 = {.s = & x2, .c = 4};  is
+  0:{ y1 } -s→ 1:{  }   1:{  } → 2:{ x1 }   4:{ y2 } -s→ 5:{  }
+  5:{  } → 6:{ x2 }
+[alias] analysing instruction: st_3_t z = {.t = & y1, .d = 5};
+[alias] May-aliases after instruction  st_3_t z = {.t = & y1, .d = 5};  are
+  { (z.t)->s; y1.s }
+[alias] May-alias graph after instruction  st_3_t z = {.t = & y1, .d = 5};  is
+  0:{ y1 } -s→ 1:{  }   1:{  } → 2:{ x1 }   4:{ y2 } -s→ 5:{  }
+  5:{  } → 6:{ x2 }   8:{ z } -t→ 9:{  }   9:{  } → 0:{ y1 }
+[alias] analysing instruction: z.t = & y2;
+[alias] May-aliases after instruction  z.t = & y2;  are  { (z.t)->s; y1.s; y2.s }
+[alias] May-alias graph after instruction  z.t = & y2;  is
+  0:{ y1; y2 } -s→ 1:{  }   1:{  } → 2:{ x1; x2 }   8:{ z } -t→ 9:{  }
+  9:{  } → 0:{ y1; y2 }
 [alias] analysing instruction: y1.c = z.d;
-[alias] May-aliases after instruction  y1.c = z.d;  are  <none>
+[alias] May-aliases after instruction  y1.c = z.d;  are  { (z.t)->s; y1.s; y2.s }
+[alias] May-alias graph after instruction  y1.c = z.d;  is
+  0:{ y1; y2 } -s→ 1:{  }   1:{  } → 2:{ x1; x2 }   8:{ z } -t→ 9:{  }
+  9:{  } → 0:{ y1; y2 }
 [alias] analysing instruction: __retres = 0;
-[alias] May-aliases after instruction  __retres = 0;  are  <none>
-[alias] May-aliases at the end of function main: <none>
+[alias] May-aliases after instruction  __retres = 0;  are  { (z.t)->s; y1.s; y2.s }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  0:{ y1; y2 } -s→ 1:{  }   1:{  } → 2:{ x1; x2 }   8:{ z } -t→ 9:{  }
+  9:{  } → 0:{ y1; y2 }
+[alias] May-aliases at the end of function main: { (z.t)->s; y1.s; y2.s }
+[alias] May-alias graph at the end of function main:
+  0:{ y1; y2 } -s→ 1:{  }   1:{  } → 2:{ x1; x2 }   8:{ z } -t→ 9:{  }
+  9:{  } → 0:{ y1; y2 }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { (z.t)->s; y1.s; y2.s }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/offsets/oracle/structure4.res.oracle b/src/plugins/alias/tests/offsets/oracle/structure4.res.oracle
index f3c036ea172ce04fcd52afed729c4131ae330555..6a11ec706edc4f080c198122381ea9542094cf2e 100644
--- a/src/plugins/alias/tests/offsets/oracle/structure4.res.oracle
+++ b/src/plugins/alias/tests/offsets/oracle/structure4.res.oracle
@@ -1,136 +1,45 @@
 [kernel] Parsing structure4.c (with preprocessing)
-[alias] analysing function: _Exit
-[alias] May-aliases at the end of function _Exit: ⊥
-[alias] analysing function: abort
-[alias] May-aliases at the end of function abort: ⊥
-[alias] analysing function: abs
-[alias] May-aliases at the end of function abs: ⊥
-[alias] analysing function: at_quick_exit
-[alias] May-aliases at the end of function at_quick_exit: ⊥
-[alias] analysing function: atexit
-[alias] May-aliases at the end of function atexit: ⊥
-[alias] analysing function: atof
-[alias] May-aliases at the end of function atof: ⊥
-[alias] analysing function: atoi
-[alias] May-aliases at the end of function atoi: ⊥
-[alias] analysing function: atol
-[alias] May-aliases at the end of function atol: ⊥
-[alias] analysing function: atoll
-[alias] May-aliases at the end of function atoll: ⊥
-[alias] analysing function: bsearch
-[alias] May-aliases at the end of function bsearch: ⊥
-[alias] analysing function: calloc
-[alias] May-aliases at the end of function calloc: ⊥
-[alias] analysing function: div
-[alias] May-aliases at the end of function div: ⊥
-[alias] analysing function: drand48
-[alias] May-aliases at the end of function drand48: ⊥
-[alias] analysing function: erand48
-[alias] May-aliases at the end of function erand48: ⊥
-[alias] analysing function: exit
-[alias] May-aliases at the end of function exit: ⊥
-[alias] analysing function: free
-[alias] May-aliases at the end of function free: ⊥
-[alias] analysing function: getenv
-[alias] May-aliases at the end of function getenv: ⊥
-[alias] analysing function: jrand48
-[alias] May-aliases at the end of function jrand48: ⊥
-[alias] analysing function: labs
-[alias] May-aliases at the end of function labs: ⊥
-[alias] analysing function: lcong48
-[alias] May-aliases at the end of function lcong48: ⊥
-[alias] analysing function: ldiv
-[alias] May-aliases at the end of function ldiv: ⊥
-[alias] analysing function: llabs
-[alias] May-aliases at the end of function llabs: ⊥
-[alias] analysing function: lldiv
-[alias] May-aliases at the end of function lldiv: ⊥
-[alias] analysing function: lrand48
-[alias] May-aliases at the end of function lrand48: ⊥
 [alias] analysing function: main
 [alias] analysing instruction: st_1_t x1 = {.a = 0, .b = 1};
 [alias] May-aliases after instruction  st_1_t x1 = {.a = 0, .b = 1};  are  <none>
+[alias] May-alias graph after instruction  st_1_t x1 = {.a = 0, .b = 1};  is
+  <empty>
 [alias] analysing instruction: st_1_t x2 = {.a = 1, .b = 2};
 [alias] May-aliases after instruction  st_1_t x2 = {.a = 1, .b = 2};  are  <none>
+[alias] May-alias graph after instruction  st_1_t x2 = {.a = 1, .b = 2};  is
+  <empty>
 [alias] analysing instruction: st_1_t *y1 = malloc(sizeof(st_1_t));
 [alias] May-aliases after instruction  st_1_t *y1 = malloc(sizeof(st_1_t));  are
   <none>
+[alias] May-alias graph after instruction  st_1_t *y1 = malloc(sizeof(st_1_t));
+  is    0:{ y1 } → 1:{  }
 [alias] analysing instruction: st_2_t *z = malloc(sizeof(st_2_t));
 [alias] May-aliases after instruction  st_2_t *z = malloc(sizeof(st_2_t));  are
   <none>
+[alias] May-alias graph after instruction  st_2_t *z = malloc(sizeof(st_2_t));  is
+  0:{ y1 } → 1:{  }   2:{ z } → 3:{  }
 [alias] analysing instruction: y1 = & x1;
 [alias] May-aliases after instruction  y1 = & x1;  are  <none>
+[alias] May-alias graph after instruction  y1 = & x1;  is
+  0:{ y1 } → 1:{ x1 }   2:{ z } → 3:{  }
 [alias] analysing instruction: z->s = (struct struct_1_t *)y1;
 [alias:unsafe-cast] structure4.c:37: Warning: 
-  unsafe cast from st_1_t * to struct struct_1_t *
+  unsafe cast from st_1_t * to struct struct_1_t *; analysis may be unsound
 [alias] May-aliases after instruction  z->s = (struct struct_1_t *)y1;  are
   { z->s; y1 }
+[alias] May-alias graph after instruction  z->s = (struct struct_1_t *)y1;  is
+  2:{ z } → 3:{  }   3:{  } -s→ 6:{ y1 }   6:{ y1 } → 1:{ x1 }
 [alias] analysing instruction: z->c = 6;
 [alias] May-aliases after instruction  z->c = 6;  are  { z->s; y1 }
+[alias] May-alias graph after instruction  z->c = 6;  is
+  2:{ z } → 3:{  }   3:{  } -s→ 6:{ y1 }   6:{ y1 } → 1:{ x1 }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  { z->s; y1 }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  2:{ z } → 3:{  }   3:{  } -s→ 6:{ y1 }   6:{ y1 } → 1:{ x1 }
 [alias] May-aliases at the end of function main: { z->s; y1 }
-[alias] analysing function: malloc
-[alias] May-aliases at the end of function malloc: ⊥
-[alias] analysing function: mblen
-[alias] May-aliases at the end of function mblen: ⊥
-[alias] analysing function: mbstowcs
-[alias] May-aliases at the end of function mbstowcs: ⊥
-[alias] analysing function: mbtowc
-[alias] May-aliases at the end of function mbtowc: ⊥
-[alias] analysing function: mkstemp
-[alias] May-aliases at the end of function mkstemp: ⊥
-[alias] analysing function: mkstemps
-[alias] May-aliases at the end of function mkstemps: ⊥
-[alias] analysing function: mrand48
-[alias] May-aliases at the end of function mrand48: ⊥
-[alias] analysing function: nrand48
-[alias] May-aliases at the end of function nrand48: ⊥
-[alias] analysing function: posix_memalign
-[alias] May-aliases at the end of function posix_memalign: ⊥
-[alias] analysing function: putenv
-[alias] May-aliases at the end of function putenv: ⊥
-[alias] analysing function: qsort
-[alias] May-aliases at the end of function qsort: ⊥
-[alias] analysing function: quick_exit
-[alias] May-aliases at the end of function quick_exit: ⊥
-[alias] analysing function: rand
-[alias] May-aliases at the end of function rand: ⊥
-[alias] analysing function: random
-[alias] May-aliases at the end of function random: ⊥
-[alias] analysing function: realloc
-[alias] May-aliases at the end of function realloc: ⊥
-[alias] analysing function: reallocarray
-[alias] May-aliases at the end of function reallocarray: ⊥
-[alias] analysing function: seed48
-[alias] May-aliases at the end of function seed48: ⊥
-[alias] analysing function: setenv
-[alias] May-aliases at the end of function setenv: ⊥
-[alias] analysing function: srand
-[alias] May-aliases at the end of function srand: ⊥
-[alias] analysing function: srand48
-[alias] May-aliases at the end of function srand48: ⊥
-[alias] analysing function: srandom
-[alias] May-aliases at the end of function srandom: ⊥
-[alias] analysing function: strtod
-[alias] May-aliases at the end of function strtod: ⊥
-[alias] analysing function: strtof
-[alias] May-aliases at the end of function strtof: ⊥
-[alias] analysing function: strtol
-[alias] May-aliases at the end of function strtol: ⊥
-[alias] analysing function: strtold
-[alias] May-aliases at the end of function strtold: ⊥
-[alias] analysing function: strtoll
-[alias] May-aliases at the end of function strtoll: ⊥
-[alias] analysing function: strtoul
-[alias] May-aliases at the end of function strtoul: ⊥
-[alias] analysing function: strtoull
-[alias] May-aliases at the end of function strtoull: ⊥
-[alias] analysing function: system
-[alias] May-aliases at the end of function system: ⊥
-[alias] analysing function: unsetenv
-[alias] May-aliases at the end of function unsetenv: ⊥
-[alias] analysing function: wcstombs
-[alias] May-aliases at the end of function wcstombs: ⊥
-[alias] analysing function: wctomb
-[alias] May-aliases at the end of function wctomb: ⊥
+[alias] May-alias graph at the end of function main:
+  2:{ z } → 3:{  }   3:{  } -s→ 6:{ y1 }   6:{ y1 } → 1:{ x1 }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { z->s; y1 }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/offsets/oracle/structure5.res.oracle b/src/plugins/alias/tests/offsets/oracle/structure5.res.oracle
index bd0be91325e062c118eefd7b690d7ee96b248860..efd088f070c7ee0d048c76e31d7ffa1e665d8c84 100644
--- a/src/plugins/alias/tests/offsets/oracle/structure5.res.oracle
+++ b/src/plugins/alias/tests/offsets/oracle/structure5.res.oracle
@@ -1,153 +1,86 @@
 [kernel] Parsing structure5.c (with preprocessing)
-[alias] analysing function: _Exit
-[alias] May-aliases at the end of function _Exit: ⊥
-[alias] analysing function: abort
-[alias] May-aliases at the end of function abort: ⊥
-[alias] analysing function: abs
-[alias] May-aliases at the end of function abs: ⊥
-[alias] analysing function: at_quick_exit
-[alias] May-aliases at the end of function at_quick_exit: ⊥
-[alias] analysing function: atexit
-[alias] May-aliases at the end of function atexit: ⊥
-[alias] analysing function: atof
-[alias] May-aliases at the end of function atof: ⊥
-[alias] analysing function: atoi
-[alias] May-aliases at the end of function atoi: ⊥
-[alias] analysing function: atol
-[alias] May-aliases at the end of function atol: ⊥
-[alias] analysing function: atoll
-[alias] May-aliases at the end of function atoll: ⊥
-[alias] analysing function: bsearch
-[alias] May-aliases at the end of function bsearch: ⊥
-[alias] analysing function: calloc
-[alias] May-aliases at the end of function calloc: ⊥
-[alias] analysing function: div
-[alias] May-aliases at the end of function div: ⊥
-[alias] analysing function: drand48
-[alias] May-aliases at the end of function drand48: ⊥
-[alias] analysing function: erand48
-[alias] May-aliases at the end of function erand48: ⊥
-[alias] analysing function: exit
-[alias] May-aliases at the end of function exit: ⊥
-[alias] analysing function: free
-[alias] May-aliases at the end of function free: ⊥
-[alias] analysing function: getenv
-[alias] May-aliases at the end of function getenv: ⊥
-[alias] analysing function: jrand48
-[alias] May-aliases at the end of function jrand48: ⊥
-[alias] analysing function: labs
-[alias] May-aliases at the end of function labs: ⊥
-[alias] analysing function: lcong48
-[alias] May-aliases at the end of function lcong48: ⊥
-[alias] analysing function: ldiv
-[alias] May-aliases at the end of function ldiv: ⊥
-[alias] analysing function: llabs
-[alias] May-aliases at the end of function llabs: ⊥
-[alias] analysing function: lldiv
-[alias] May-aliases at the end of function lldiv: ⊥
-[alias] analysing function: lrand48
-[alias] May-aliases at the end of function lrand48: ⊥
 [alias] analysing function: main
 [alias] analysing instruction: st_1_t x1 = {.a = 0, .b = 1};
 [alias] May-aliases after instruction  st_1_t x1 = {.a = 0, .b = 1};  are  <none>
+[alias] May-alias graph after instruction  st_1_t x1 = {.a = 0, .b = 1};  is
+  <empty>
 [alias] analysing instruction: st_1_t x2 = {.a = 1, .b = 2};
 [alias] May-aliases after instruction  st_1_t x2 = {.a = 1, .b = 2};  are  <none>
+[alias] May-alias graph after instruction  st_1_t x2 = {.a = 1, .b = 2};  is
+  <empty>
 [alias] analysing instruction: st_1_t *y1 = malloc(sizeof(st_1_t));
 [alias] May-aliases after instruction  st_1_t *y1 = malloc(sizeof(st_1_t));  are
   <none>
+[alias] May-alias graph after instruction  st_1_t *y1 = malloc(sizeof(st_1_t));
+  is    0:{ y1 } → 1:{  }
 [alias] analysing instruction: st_2_t *z = malloc(sizeof(st_2_t));
 [alias] May-aliases after instruction  st_2_t *z = malloc(sizeof(st_2_t));  are
   <none>
+[alias] May-alias graph after instruction  st_2_t *z = malloc(sizeof(st_2_t));  is
+  0:{ y1 } → 1:{  }   2:{ z } → 3:{  }
 [alias] analysing instruction: st_3_t *t = malloc(sizeof(st_3_t));
 [alias] May-aliases after instruction  st_3_t *t = malloc(sizeof(st_3_t));  are
   <none>
+[alias] May-alias graph after instruction  st_3_t *t = malloc(sizeof(st_3_t));  is
+  0:{ y1 } → 1:{  }   2:{ z } → 3:{  }   4:{ t } → 5:{  }
 [alias] analysing instruction: int *a = malloc(sizeof(int));
 [alias] May-aliases after instruction  int *a = malloc(sizeof(int));  are  <none>
+[alias] May-alias graph after instruction  int *a = malloc(sizeof(int));  is
+  0:{ y1 } → 1:{  }   2:{ z } → 3:{  }   4:{ t } → 5:{  }
+  6:{ a } → 7:{  }
 [alias] analysing instruction: *a = 0;
 [alias] May-aliases after instruction  *a = 0;  are  <none>
+[alias] May-alias graph after instruction  *a = 0;  is
+  0:{ y1 } → 1:{  }   2:{ z } → 3:{  }   4:{ t } → 5:{  }
+  6:{ a } → 7:{  }
 [alias] analysing instruction: y1 = & x1;
 [alias] May-aliases after instruction  y1 = & x1;  are  <none>
+[alias] May-alias graph after instruction  y1 = & x1;  is
+  0:{ y1 } → 1:{ x1 }   2:{ z } → 3:{  }   4:{ t } → 5:{  }
+  6:{ a } → 7:{  }
 [alias] analysing instruction: z->s = (struct struct_1_t *)y1;
 [alias:unsafe-cast] structure5.c:41: Warning: 
-  unsafe cast from st_1_t * to struct struct_1_t *
+  unsafe cast from st_1_t * to struct struct_1_t *; analysis may be unsound
 [alias] May-aliases after instruction  z->s = (struct struct_1_t *)y1;  are
   { z->s; y1 }
+[alias] May-alias graph after instruction  z->s = (struct struct_1_t *)y1;  is
+  2:{ z } → 3:{  }   3:{  } -s→ 10:{ y1 }   4:{ t } → 5:{  }
+  6:{ a } → 7:{  }   10:{ y1 } → 1:{ x1 }
 [alias] analysing instruction: z->c = a;
 [alias] May-aliases after instruction  z->c = a;  are  { z->s; y1 }  { z->c; a }
+[alias] May-alias graph after instruction  z->c = a;  is
+  2:{ z } → 3:{  }   3:{  } -s→ 10:{ y1 }   3:{  } -c→ 11:{ a }
+  4:{ t } → 5:{  }   10:{ y1 } → 1:{ x1 }   11:{ a } → 7:{  }
 [alias] analysing instruction: t->t = (struct struct_2_t *)z;
 [alias:unsafe-cast] structure5.c:43: Warning: 
-  unsafe cast from st_2_t * to struct struct_2_t *
+  unsafe cast from st_2_t * to struct struct_2_t *; analysis may be unsound
 [alias] May-aliases after instruction  t->t = (struct struct_2_t *)z;  are
-  { z->s; y1 }  { t->t; z }  { z->c; a }
+  { (t->t)->s; z->s; y1 }  { t->t; z }  { (t->t)->c; z->c; a }
+[alias] May-alias graph after instruction  t->t = (struct struct_2_t *)z;  is
+  3:{  } -s→ 10:{ y1 }   3:{  } -c→ 11:{ a }   4:{ t } → 5:{  }
+  5:{  } -t→ 12:{ z }   10:{ y1 } → 1:{ x1 }   11:{ a } → 7:{  }
+  12:{ z } → 3:{  }
 [alias] analysing instruction: t->d = a;
 [alias] May-aliases after instruction  t->d = a;  are
-  { z->s; y1 }  { t->t; z }  { z->c; t->d; a }
+  { (t->t)->s; z->s; y1 }  { t->t; z }  { (t->t)->c; z->c; t->d; a }
+[alias] May-alias graph after instruction  t->d = a;  is
+  3:{  } -s→ 10:{ y1 }   3:{  } -c→ 13:{ a }   4:{ t } → 5:{  }
+  5:{  } -t→ 12:{ z }   5:{  } -d→ 13:{ a }   10:{ y1 } → 1:{ x1 }
+  12:{ z } → 3:{  }   13:{ a } → 7:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are
-  { z->s; y1 }  { t->t; z }  { z->c; t->d; a }
+  { (t->t)->s; z->s; y1 }  { t->t; z }  { (t->t)->c; z->c; t->d; a }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  3:{  } -s→ 10:{ y1 }   3:{  } -c→ 13:{ a }   4:{ t } → 5:{  }
+  5:{  } -t→ 12:{ z }   5:{  } -d→ 13:{ a }   10:{ y1 } → 1:{ x1 }
+  12:{ z } → 3:{  }   13:{ a } → 7:{  }
 [alias] May-aliases at the end of function main:
-  { z->s; y1 }  { t->t; z }  { z->c; t->d; a }
-[alias] analysing function: malloc
-[alias] May-aliases at the end of function malloc: ⊥
-[alias] analysing function: mblen
-[alias] May-aliases at the end of function mblen: ⊥
-[alias] analysing function: mbstowcs
-[alias] May-aliases at the end of function mbstowcs: ⊥
-[alias] analysing function: mbtowc
-[alias] May-aliases at the end of function mbtowc: ⊥
-[alias] analysing function: mkstemp
-[alias] May-aliases at the end of function mkstemp: ⊥
-[alias] analysing function: mkstemps
-[alias] May-aliases at the end of function mkstemps: ⊥
-[alias] analysing function: mrand48
-[alias] May-aliases at the end of function mrand48: ⊥
-[alias] analysing function: nrand48
-[alias] May-aliases at the end of function nrand48: ⊥
-[alias] analysing function: posix_memalign
-[alias] May-aliases at the end of function posix_memalign: ⊥
-[alias] analysing function: putenv
-[alias] May-aliases at the end of function putenv: ⊥
-[alias] analysing function: qsort
-[alias] May-aliases at the end of function qsort: ⊥
-[alias] analysing function: quick_exit
-[alias] May-aliases at the end of function quick_exit: ⊥
-[alias] analysing function: rand
-[alias] May-aliases at the end of function rand: ⊥
-[alias] analysing function: random
-[alias] May-aliases at the end of function random: ⊥
-[alias] analysing function: realloc
-[alias] May-aliases at the end of function realloc: ⊥
-[alias] analysing function: reallocarray
-[alias] May-aliases at the end of function reallocarray: ⊥
-[alias] analysing function: seed48
-[alias] May-aliases at the end of function seed48: ⊥
-[alias] analysing function: setenv
-[alias] May-aliases at the end of function setenv: ⊥
-[alias] analysing function: srand
-[alias] May-aliases at the end of function srand: ⊥
-[alias] analysing function: srand48
-[alias] May-aliases at the end of function srand48: ⊥
-[alias] analysing function: srandom
-[alias] May-aliases at the end of function srandom: ⊥
-[alias] analysing function: strtod
-[alias] May-aliases at the end of function strtod: ⊥
-[alias] analysing function: strtof
-[alias] May-aliases at the end of function strtof: ⊥
-[alias] analysing function: strtol
-[alias] May-aliases at the end of function strtol: ⊥
-[alias] analysing function: strtold
-[alias] May-aliases at the end of function strtold: ⊥
-[alias] analysing function: strtoll
-[alias] May-aliases at the end of function strtoll: ⊥
-[alias] analysing function: strtoul
-[alias] May-aliases at the end of function strtoul: ⊥
-[alias] analysing function: strtoull
-[alias] May-aliases at the end of function strtoull: ⊥
-[alias] analysing function: system
-[alias] May-aliases at the end of function system: ⊥
-[alias] analysing function: unsetenv
-[alias] May-aliases at the end of function unsetenv: ⊥
-[alias] analysing function: wcstombs
-[alias] May-aliases at the end of function wcstombs: ⊥
-[alias] analysing function: wctomb
-[alias] May-aliases at the end of function wctomb: ⊥
+  { (t->t)->s; z->s; y1 }  { t->t; z }  { (t->t)->c; z->c; t->d; a }
+[alias] May-alias graph at the end of function main:
+  3:{  } -s→ 10:{ y1 }   3:{  } -c→ 13:{ a }   4:{ t } → 5:{  }
+  5:{  } -t→ 12:{ z }   5:{  } -d→ 13:{ a }   10:{ y1 } → 1:{ x1 }
+  12:{ z } → 3:{  }   13:{ a } → 7:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres
+  state: { (t->t)->s; z->s; y1 }  { t->t; z }  { (t->t)->c; z->c; t->d; a }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/offsets/structure3.c b/src/plugins/alias/tests/offsets/structure3.c
index 9582ccd3f86dfe6b9b186213836c29aee37a600f..e800d76cd1a74966dc9f3dee99185aed30ff50da 100644
--- a/src/plugins/alias/tests/offsets/structure3.c
+++ b/src/plugins/alias/tests/offsets/structure3.c
@@ -1,38 +1,32 @@
 // double structure with initialisation and pointer
-//  no alias
 
-typedef struct
-{       
+// There are no real aliases at the end of the function,
+// but some aliases are created along the way,
+// so at the end we obtain { (z.t)->s; y1.s; y2.s }
+
+typedef struct st_1_t {
     int   a;
     int   b;
 } st_1_t;
 
-typedef struct
-{       
-    struct struct_1_t*  s;
+typedef struct st_2_t {
+    struct st_1_t*  s;
     int   c;
 } st_2_t;
 
-
-typedef struct
-{       
-    struct struct_2_t*  t;
+typedef struct st_3_t {
+    struct st_2_t*  t;
     int   d;
 } st_3_t;
 
-
-
-
-
 int main () {
-
   st_1_t x1 = {0,1};
   st_1_t x2 = {1,2};
   st_2_t y1 = {&x1,3};
   st_2_t y2 = {&x2,4};
-  st_3_t z = {&y1,5};
-  
-  z.t = &y2;
+  st_3_t z = {&y1,5}; // creates alias { (z.t)->s; y1.s }
+
+  z.t = &y2; // creates alias { (z.t)->s; y2.s }
   y1.c = z.d;
 
   return 0;
diff --git a/src/plugins/alias/tests/real_world/oracle/example1.res.oracle b/src/plugins/alias/tests/real_world/oracle/example1.res.oracle
index ec0365c4343944aca7257f2288fbd23f26dd5d1c..3adc34389ba645190b0b6bedee1fe44d73c660a3 100644
--- a/src/plugins/alias/tests/real_world/oracle/example1.res.oracle
+++ b/src/plugins/alias/tests/real_world/oracle/example1.res.oracle
@@ -1,419 +1,324 @@
 [kernel] Parsing example1.c (with preprocessing)
-[alias] analysing function: _Exit
-[alias] May-aliases at the end of function _Exit: ⊥
-[alias] analysing function: __fc_fpclassify
-[alias] May-aliases at the end of function __fc_fpclassify: ⊥
-[alias] analysing function: __fc_fpclassifyf
-[alias] May-aliases at the end of function __fc_fpclassifyf: ⊥
-[alias] analysing function: __fc_infinity
-[alias] May-aliases at the end of function __fc_infinity: ⊥
-[alias] analysing function: __fc_nan
-[alias] May-aliases at the end of function __fc_nan: ⊥
-[alias] analysing function: __finite
-[alias] May-aliases at the end of function __finite: ⊥
-[alias] analysing function: __finitef
-[alias] May-aliases at the end of function __finitef: ⊥
-[alias] analysing function: abort
-[alias] May-aliases at the end of function abort: ⊥
-[alias] analysing function: abs
-[alias] May-aliases at the end of function abs: ⊥
-[alias] analysing function: acos
-[alias] May-aliases at the end of function acos: ⊥
-[alias] analysing function: acosf
-[alias] May-aliases at the end of function acosf: ⊥
-[alias] analysing function: acosh
-[alias] May-aliases at the end of function acosh: ⊥
-[alias] analysing function: acoshf
-[alias] May-aliases at the end of function acoshf: ⊥
-[alias] analysing function: acoshl
-[alias] May-aliases at the end of function acoshl: ⊥
-[alias] analysing function: acosl
-[alias] May-aliases at the end of function acosl: ⊥
-[alias] analysing function: asin
-[alias] May-aliases at the end of function asin: ⊥
-[alias] analysing function: asinf
-[alias] May-aliases at the end of function asinf: ⊥
-[alias] analysing function: asinl
-[alias] May-aliases at the end of function asinl: ⊥
-[alias] analysing function: at_quick_exit
-[alias] May-aliases at the end of function at_quick_exit: ⊥
-[alias] analysing function: atan
-[alias] May-aliases at the end of function atan: ⊥
-[alias] analysing function: atan2
-[alias] May-aliases at the end of function atan2: ⊥
-[alias] analysing function: atan2f
-[alias] May-aliases at the end of function atan2f: ⊥
-[alias] analysing function: atan2l
-[alias] May-aliases at the end of function atan2l: ⊥
-[alias] analysing function: atanf
-[alias] May-aliases at the end of function atanf: ⊥
-[alias] analysing function: atanl
-[alias] May-aliases at the end of function atanl: ⊥
-[alias] analysing function: atexit
-[alias] May-aliases at the end of function atexit: ⊥
-[alias] analysing function: atof
-[alias] May-aliases at the end of function atof: ⊥
-[alias] analysing function: atoi
-[alias] May-aliases at the end of function atoi: ⊥
-[alias] analysing function: atol
-[alias] May-aliases at the end of function atol: ⊥
-[alias] analysing function: atoll
-[alias] May-aliases at the end of function atoll: ⊥
-[alias] analysing function: bsearch
-[alias] May-aliases at the end of function bsearch: ⊥
-[alias] analysing function: calloc
-[alias] May-aliases at the end of function calloc: ⊥
-[alias] analysing function: ceil
-[alias] May-aliases at the end of function ceil: ⊥
-[alias] analysing function: ceilf
-[alias] May-aliases at the end of function ceilf: ⊥
-[alias] analysing function: ceill
-[alias] May-aliases at the end of function ceill: ⊥
-[alias] analysing function: cos
-[alias] May-aliases at the end of function cos: ⊥
-[alias] analysing function: cosf
-[alias] May-aliases at the end of function cosf: ⊥
-[alias] analysing function: cosl
-[alias] May-aliases at the end of function cosl: ⊥
-[alias] analysing function: div
-[alias] May-aliases at the end of function div: ⊥
-[alias] analysing function: drand48
-[alias] May-aliases at the end of function drand48: ⊥
-[alias] analysing function: erand48
-[alias] May-aliases at the end of function erand48: ⊥
-[alias] analysing function: exit
-[alias] May-aliases at the end of function exit: ⊥
-[alias] analysing function: exp
-[alias] May-aliases at the end of function exp: ⊥
-[alias] analysing function: expf
-[alias] May-aliases at the end of function expf: ⊥
 [alias] analysing function: f1
 [alias] analysing instruction: ty *tmp = x;
 [alias] May-aliases after instruction  ty *tmp = x;  are  { x; tmp }
+[alias] May-alias graph after instruction  ty *tmp = x;  is
+  0:{ x; tmp } → 1:{  }
 [alias] analysing instruction:
   idata = (double *)malloc((unsigned long)10 * sizeof(double));
 [alias] May-aliases after instruction
   idata = (double *)malloc((unsigned long)10 * sizeof(double));  are
   { x; tmp }
+[alias] May-alias graph after instruction
+  idata = (double *)malloc((unsigned long)10 * sizeof(double));  is
+  0:{ x; tmp } → 1:{  }   4:{ idata } → 5:{  }
 [alias] analysing instruction: idata = tmp->t2[*(tmp->n2)];
 [alias] May-aliases after instruction  idata = tmp->t2[*(tmp->n2)];  are
-  { x; tmp }  { tmp->t2[0..]; idata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+[alias] May-alias graph after instruction  idata = tmp->t2[*(tmp->n2)];  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   4:{ idata } → 5:{  }
+  6:{  } → 4:{ idata }
 [alias] analysing instruction: odata = tmp->t1[*(tmp->n1)];
 [alias] May-aliases after instruction  odata = tmp->t1[*(tmp->n1)];  are
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph after instruction  odata = tmp->t1[*(tmp->n1)];  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
 [alias] analysing instruction: idx = 0;
 [alias] May-aliases after instruction  idx = 0;  are
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph after instruction  idx = 0;  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
 [alias] analysing instruction: tmp_1 = sin(*(idata + idx));
-[alias] analysing function: sin
-[alias] May-aliases at the end of function sin: ⊥
 [alias:undefined:fn] example1.c:45: Warning: function sin has no definition
 [alias] May-aliases after instruction  tmp_1 = sin(*(idata + idx));  are
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph after instruction  tmp_1 = sin(*(idata + idx));  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
 [alias] analysing instruction: *(odata + idx) = 0.5 * tmp_1;
 [alias] May-aliases after instruction  *(odata + idx) = 0.5 * tmp_1;  are
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph after instruction  *(odata + idx) = 0.5 * tmp_1;  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
 [alias] analysing instruction: idx ++;
 [alias] May-aliases after instruction  idx ++;  are
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph after instruction  idx ++;  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
 [alias] analysing instruction: swap(tmp->n1);
 [alias] analysing function: swap
 [alias] analysing instruction: *n = 0;
 [alias] May-aliases after instruction  *n = 0;  are  <none>
+[alias] May-alias graph after instruction  *n = 0;  is    <empty>
 [alias] analysing instruction: (*n) ++;
 [alias] May-aliases after instruction  (*n) ++;  are  <none>
+[alias] May-alias graph after instruction  (*n) ++;  is    <empty>
 [alias] May-aliases at the end of function swap: <none>
+[alias] May-alias graph at the end of function swap:
+  <empty>
+[alias] Summary of function swap:
 [alias] May-aliases after instruction  swap(tmp->n1);  are
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph after instruction  swap(tmp->n1);  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
 [alias] analysing instruction: idata = tmp->t2[*(tmp->n2)];
 [alias] May-aliases after instruction  idata = tmp->t2[*(tmp->n2)];  are
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph after instruction  idata = tmp->t2[*(tmp->n2)];  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
 [alias] analysing instruction: odata = tmp->t1[*(tmp->n1)];
 [alias] May-aliases after instruction  odata = tmp->t1[*(tmp->n1)];  are
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph after instruction  odata = tmp->t1[*(tmp->n1)];  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
 [alias:no-return] example1.c:29: Warning: 
   function f1 does not return; analysis may be unsound
 [alias] May-aliases at the end of function f1: <none>
+[alias] May-alias graph at the end of function f1:
+  <empty>
+[alias] Summary of function f1:
+  formals: x    returns: __retres    state: <none>
 [alias] analysing function: f2
 [alias] analysing instruction: ty *tmp = x;
 [alias] May-aliases after instruction  ty *tmp = x;  are  { x; tmp }
+[alias] May-alias graph after instruction  ty *tmp = x;  is
+  14:{ x; tmp } → 15:{  }
 [alias] analysing instruction:
   idata = (double *)malloc((unsigned long)10 * sizeof(double));
 [alias] May-aliases after instruction
   idata = (double *)malloc((unsigned long)10 * sizeof(double));  are
   { x; tmp }
+[alias] May-alias graph after instruction
+  idata = (double *)malloc((unsigned long)10 * sizeof(double));  is
+  14:{ x; tmp } → 15:{  }   18:{ idata } → 19:{  }
 [alias] analysing instruction: idata = tmp->t1[*(tmp->n1)];
 [alias] May-aliases after instruction  idata = tmp->t1[*(tmp->n1)];  are
-  { x; tmp }  { tmp->t1[0..]; idata }
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+[alias] May-alias graph after instruction  idata = tmp->t1[*(tmp->n1)];  is
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
 [alias] analysing instruction: odata = tmp->t2[*(tmp->n2)];
 [alias] May-aliases after instruction  odata = tmp->t2[*(tmp->n2)];  are
-  { x; tmp }  { tmp->t1[0..]; idata }  { tmp->t2[0..]; odata }
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; odata }
+[alias] May-alias graph after instruction  odata = tmp->t2[*(tmp->n2)];  is
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }   15:{  } -t2→ 24:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
+  22:{ odata } → 23:{  }   24:{  } → 22:{ odata }
 [alias] analysing instruction: idx = 0;
 [alias] May-aliases after instruction  idx = 0;  are
-  { x; tmp }  { tmp->t1[0..]; idata }  { tmp->t2[0..]; odata }
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; odata }
+[alias] May-alias graph after instruction  idx = 0;  is
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }   15:{  } -t2→ 24:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
+  22:{ odata } → 23:{  }   24:{  } → 22:{ odata }
 [alias] analysing instruction:
   *(odata + idx) = (double)3 * *(idata + idx) + (double)1;
 [alias] May-aliases after instruction
   *(odata + idx) = (double)3 * *(idata + idx) + (double)1;  are
-  { x; tmp }  { tmp->t1[0..]; idata }  { tmp->t2[0..]; odata }
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; odata }
+[alias] May-alias graph after instruction
+  *(odata + idx) = (double)3 * *(idata + idx) + (double)1;  is
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }   15:{  } -t2→ 24:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
+  22:{ odata } → 23:{  }   24:{  } → 22:{ odata }
 [alias] analysing instruction: idx ++;
 [alias] May-aliases after instruction  idx ++;  are
-  { x; tmp }  { tmp->t1[0..]; idata }  { tmp->t2[0..]; odata }
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; odata }
+[alias] May-alias graph after instruction  idx ++;  is
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }   15:{  } -t2→ 24:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
+  22:{ odata } → 23:{  }   24:{  } → 22:{ odata }
 [alias] analysing instruction: swap(tmp->n2);
 [alias] May-aliases after instruction  swap(tmp->n2);  are
-  { x; tmp }  { tmp->t1[0..]; idata }  { tmp->t2[0..]; odata }
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; odata }
+[alias] May-alias graph after instruction  swap(tmp->n2);  is
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }   15:{  } -t2→ 24:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
+  22:{ odata } → 23:{  }   24:{  } → 22:{ odata }
 [alias] analysing instruction: idata = tmp->t1[*(tmp->n1)];
 [alias] May-aliases after instruction  idata = tmp->t1[*(tmp->n1)];  are
-  { x; tmp }  { tmp->t1[0..]; idata }  { tmp->t2[0..]; odata }
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; odata }
+[alias] May-alias graph after instruction  idata = tmp->t1[*(tmp->n1)];  is
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }   15:{  } -t2→ 24:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
+  22:{ odata } → 23:{  }   24:{  } → 22:{ odata }
 [alias] analysing instruction: odata = tmp->t2[*(tmp->n2)];
 [alias] May-aliases after instruction  odata = tmp->t2[*(tmp->n2)];  are
-  { x; tmp }  { tmp->t1[0..]; idata }  { tmp->t2[0..]; odata }
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; odata }
+[alias] May-alias graph after instruction  odata = tmp->t2[*(tmp->n2)];  is
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }   15:{  } -t2→ 24:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
+  22:{ odata } → 23:{  }   24:{  } → 22:{ odata }
 [alias:no-return] example1.c:53: Warning: 
   function f2 does not return; analysis may be unsound
 [alias] May-aliases at the end of function f2: <none>
-[alias] analysing function: fabs
-[alias] May-aliases at the end of function fabs: ⊥
-[alias] analysing function: fabsf
-[alias] May-aliases at the end of function fabsf: ⊥
-[alias] analysing function: fabsl
-[alias] May-aliases at the end of function fabsl: ⊥
-[alias] analysing function: floor
-[alias] May-aliases at the end of function floor: ⊥
-[alias] analysing function: floorf
-[alias] May-aliases at the end of function floorf: ⊥
-[alias] analysing function: floorl
-[alias] May-aliases at the end of function floorl: ⊥
-[alias] analysing function: fmod
-[alias] May-aliases at the end of function fmod: ⊥
-[alias] analysing function: fmodf
-[alias] May-aliases at the end of function fmodf: ⊥
-[alias] analysing function: free
-[alias] May-aliases at the end of function free: ⊥
-[alias] analysing function: frexp
-[alias] May-aliases at the end of function frexp: ⊥
-[alias] analysing function: frexpf
-[alias] May-aliases at the end of function frexpf: ⊥
-[alias] analysing function: frexpl
-[alias] May-aliases at the end of function frexpl: ⊥
-[alias] analysing function: getenv
-[alias] May-aliases at the end of function getenv: ⊥
-[alias] analysing function: jrand48
-[alias] May-aliases at the end of function jrand48: ⊥
-[alias] analysing function: labs
-[alias] May-aliases at the end of function labs: ⊥
-[alias] analysing function: lcong48
-[alias] May-aliases at the end of function lcong48: ⊥
-[alias] analysing function: ldexp
-[alias] May-aliases at the end of function ldexp: ⊥
-[alias] analysing function: ldexpf
-[alias] May-aliases at the end of function ldexpf: ⊥
-[alias] analysing function: ldiv
-[alias] May-aliases at the end of function ldiv: ⊥
-[alias] analysing function: llabs
-[alias] May-aliases at the end of function llabs: ⊥
-[alias] analysing function: lldiv
-[alias] May-aliases at the end of function lldiv: ⊥
-[alias] analysing function: log
-[alias] May-aliases at the end of function log: ⊥
-[alias] analysing function: log10
-[alias] May-aliases at the end of function log10: ⊥
-[alias] analysing function: log10f
-[alias] May-aliases at the end of function log10f: ⊥
-[alias] analysing function: log10l
-[alias] May-aliases at the end of function log10l: ⊥
-[alias] analysing function: log2
-[alias] May-aliases at the end of function log2: ⊥
-[alias] analysing function: log2f
-[alias] May-aliases at the end of function log2f: ⊥
-[alias] analysing function: log2l
-[alias] May-aliases at the end of function log2l: ⊥
-[alias] analysing function: logf
-[alias] May-aliases at the end of function logf: ⊥
-[alias] analysing function: logl
-[alias] May-aliases at the end of function logl: ⊥
-[alias] analysing function: lrand48
-[alias] May-aliases at the end of function lrand48: ⊥
+[alias] May-alias graph at the end of function f2:
+  <empty>
+[alias] Summary of function f2:
+  formals: x    returns: __retres    state: <none>
 [alias] analysing function: main
 [alias] analysing instruction: a = (ty *)malloc(sizeof(ty));
 [alias] May-aliases after instruction  a = (ty *)malloc(sizeof(ty));  are  <none>
+[alias] May-alias graph after instruction  a = (ty *)malloc(sizeof(ty));  is
+  28:{ a } → 29:{  }
 [alias] analysing instruction: b = (ty *)malloc(sizeof(ty));
 [alias] May-aliases after instruction  b = (ty *)malloc(sizeof(ty));  are  <none>
+[alias] May-alias graph after instruction  b = (ty *)malloc(sizeof(ty));  is
+  28:{ a } → 29:{  }   30:{ b } → 31:{  }
 [alias] analysing instruction: i = 0;
 [alias] May-aliases after instruction  i = 0;  are  <none>
+[alias] May-alias graph after instruction  i = 0;  is
+  28:{ a } → 29:{  }   30:{ b } → 31:{  }
 [alias] analysing instruction:
   a->t1[i] = (double *)malloc((unsigned long)10 * sizeof(double));
 [alias] May-aliases after instruction
   a->t1[i] = (double *)malloc((unsigned long)10 * sizeof(double));  are  
   <none>
+[alias] May-alias graph after instruction
+  a->t1[i] = (double *)malloc((unsigned long)10 * sizeof(double));  is
+  28:{ a } → 29:{  }   29:{  } -t1→ 32:{  }   30:{ b } → 31:{  }
+  32:{  } → 33:{  }   33:{  } → 34:{  }
 [alias] analysing instruction:
   a->t2[i] = (double *)malloc((unsigned long)10 * sizeof(double));
 [alias] May-aliases after instruction
   a->t2[i] = (double *)malloc((unsigned long)10 * sizeof(double));  are  
   <none>
+[alias] May-alias graph after instruction
+  a->t2[i] = (double *)malloc((unsigned long)10 * sizeof(double));  is
+  28:{ a } → 29:{  }   29:{  } -t1→ 32:{  }   29:{  } -t2→ 35:{  }
+  30:{ b } → 31:{  }   32:{  } → 33:{  }   33:{  } → 34:{  }
+  35:{  } → 36:{  }   36:{  } → 37:{  }
 [alias] analysing instruction: i ++;
 [alias] May-aliases after instruction  i ++;  are  <none>
-[alias] analysing instruction:
-  a->t1[i] = (double *)malloc((unsigned long)10 * sizeof(double));
-[alias] May-aliases after instruction
-  a->t1[i] = (double *)malloc((unsigned long)10 * sizeof(double));  are  
-  <none>
-[alias] analysing instruction:
-  a->t2[i] = (double *)malloc((unsigned long)10 * sizeof(double));
-[alias] May-aliases after instruction
-  a->t2[i] = (double *)malloc((unsigned long)10 * sizeof(double));  are  
-  <none>
+[alias] May-alias graph after instruction  i ++;  is
+  28:{ a } → 29:{  }   29:{  } -t1→ 32:{  }   29:{  } -t2→ 35:{  }
+  30:{ b } → 31:{  }   32:{  } → 33:{  }   33:{  } → 34:{  }
+  35:{  } → 36:{  }   36:{  } → 37:{  }
 [alias] analysing instruction: a->n1 = (int *)malloc(sizeof(int));
 [alias] May-aliases after instruction  a->n1 = (int *)malloc(sizeof(int));  are
   <none>
+[alias] May-alias graph after instruction  a->n1 = (int *)malloc(sizeof(int));  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 38:{  }   30:{ b } → 31:{  }
+  38:{  } → 39:{  }
 [alias] analysing instruction: a->n2 = (int *)malloc(sizeof(int));
 [alias] May-aliases after instruction  a->n2 = (int *)malloc(sizeof(int));  are
   <none>
+[alias] May-alias graph after instruction  a->n2 = (int *)malloc(sizeof(int));  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 38:{  }   29:{  } -n2→ 40:{  }
+  30:{ b } → 31:{  }   38:{  } → 39:{  }   40:{  } → 41:{  }
 [alias] analysing instruction: *(a->n1) = 1;
 [alias] May-aliases after instruction  *(a->n1) = 1;  are  <none>
+[alias] May-alias graph after instruction  *(a->n1) = 1;  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 38:{  }   29:{  } -n2→ 40:{  }
+  30:{ b } → 31:{  }   38:{  } → 39:{  }   40:{  } → 41:{  }
 [alias] analysing instruction: *(a->n2) = 1;
 [alias] May-aliases after instruction  *(a->n2) = 1;  are  <none>
+[alias] May-alias graph after instruction  *(a->n2) = 1;  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 38:{  }   29:{  } -n2→ 40:{  }
+  30:{ b } → 31:{  }   38:{  } → 39:{  }   40:{  } → 41:{  }
 [alias] analysing instruction: i = 0;
 [alias] May-aliases after instruction  i = 0;  are  <none>
+[alias] May-alias graph after instruction  i = 0;  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 38:{  }   29:{  } -n2→ 40:{  }
+  30:{ b } → 31:{  }   38:{  } → 39:{  }   40:{  } → 41:{  }
 [alias] analysing instruction: b->t1[i] = a->t1[i];
-[alias] May-aliases after instruction  b->t1[i] = a->t1[i];  are
-  { a->t1[0..]; b->t1[0..] }
+[alias] May-aliases after instruction  b->t1[i] = a->t1[i];  are  { a->t1; b->t1 }
+[alias] May-alias graph after instruction  b->t1[i] = a->t1[i];  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 38:{  }   29:{  } -n2→ 40:{  }
+  29:{  } -t1→ 44:{  }   30:{ b } → 31:{  }   31:{  } -t1→ 42:{  }
+  38:{  } → 39:{  }   40:{  } → 41:{  }   42:{  } → 43:{  }
+  44:{  } → 43:{  }
 [alias] analysing instruction: b->t2[i] = a->t2[i];
 [alias] May-aliases after instruction  b->t2[i] = a->t2[i];  are
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }
+  { a->t1; b->t1 }  { a->t2; b->t2 }
+[alias] May-alias graph after instruction  b->t2[i] = a->t2[i];  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 38:{  }   29:{  } -n2→ 40:{  }
+  29:{  } -t1→ 44:{  }   29:{  } -t2→ 48:{  }   30:{ b } → 31:{  }
+  31:{  } -t1→ 42:{  }   31:{  } -t2→ 46:{  }   38:{  } → 39:{  }
+  40:{  } → 41:{  }   42:{  } → 43:{  }   44:{  } → 43:{  }
+  46:{  } → 47:{  }   48:{  } → 47:{  }
 [alias] analysing instruction: i ++;
-[alias] May-aliases after instruction  i ++;  are
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }
-[alias] analysing instruction: b->t1[i] = a->t1[i];
-[alias] May-aliases after instruction  b->t1[i] = a->t1[i];  are
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }
-[alias] analysing instruction: b->t2[i] = a->t2[i];
-[alias] May-aliases after instruction  b->t2[i] = a->t2[i];  are
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }
+[alias] May-aliases after instruction  i ++;  are  { a->t1; b->t1 }  { a->t2; b->t2 }
+[alias] May-alias graph after instruction  i ++;  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 38:{  }   29:{  } -n2→ 40:{  }
+  29:{  } -t1→ 44:{  }   29:{  } -t2→ 48:{  }   30:{ b } → 31:{  }
+  31:{  } -t1→ 42:{  }   31:{  } -t2→ 46:{  }   38:{  } → 39:{  }
+  40:{  } → 41:{  }   42:{  } → 43:{  }   44:{  } → 43:{  }
+  46:{  } → 47:{  }   48:{  } → 47:{  }
 [alias] analysing instruction: b->n1 = a->n1;
-[alias] May-aliases after instruction  b->n1 = a->n1;  are
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }  { a->n1; b->n1 }
+[alias] May-aliases after instruction  b->n1 = a->n1;  are  { a->n1; b->n1 }
+[alias] May-alias graph after instruction  b->n1 = a->n1;  is
+  28:{ a } → 29:{  }   29:{  } -n2→ 40:{  }   29:{  } -n1→ 50:{  }
+  30:{ b } → 31:{  }   31:{  } -n1→ 50:{  }   40:{  } → 41:{  }
+  50:{  } → 39:{  }
 [alias] analysing instruction: b->n2 = a->n2;
 [alias] May-aliases after instruction  b->n2 = a->n2;  are
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }  { a->n1; b->n1 }
-  { a->n2; b->n2 }
+  { a->n1; b->n1 }  { a->n2; b->n2 }
+[alias] May-alias graph after instruction  b->n2 = a->n2;  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 50:{  }   29:{  } -n2→ 51:{  }
+  30:{ b } → 31:{  }   31:{  } -n1→ 50:{  }   31:{  } -n2→ 51:{  }
+  50:{  } → 39:{  }   51:{  } → 41:{  }
 [alias] analysing instruction: f1(a);
 [alias] May-aliases after instruction  f1(a);  are
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }  { a->n1; b->n1 }
-  { a->n2; b->n2 }
+  { a->n1; b->n1 }  { a->n2; b->n2 }
+[alias] May-alias graph after instruction  f1(a);  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 50:{  }   29:{  } -n2→ 51:{  }
+  30:{ b } → 31:{  }   31:{  } -n1→ 50:{  }   31:{  } -n2→ 51:{  }
+  50:{  } → 39:{  }   51:{  } → 41:{  }
 [alias] analysing instruction: f2(b);
 [alias] May-aliases after instruction  f2(b);  are
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }  { a->n1; b->n1 }
-  { a->n2; b->n2 }
+  { a->n1; b->n1 }  { a->n2; b->n2 }
+[alias] May-alias graph after instruction  f2(b);  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 50:{  }   29:{  } -n2→ 51:{  }
+  30:{ b } → 31:{  }   31:{  } -n1→ 50:{  }   31:{  } -n2→ 51:{  }
+  50:{  } → 39:{  }   51:{  } → 41:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }  { a->n1; b->n1 }
-  { a->n2; b->n2 }
-[alias] May-aliases at the end of function main:
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }  { a->n1; b->n1 }
-  { a->n2; b->n2 }
-[alias] analysing function: malloc
-[alias] May-aliases at the end of function malloc: ⊥
-[alias] analysing function: mblen
-[alias] May-aliases at the end of function mblen: ⊥
-[alias] analysing function: mbstowcs
-[alias] May-aliases at the end of function mbstowcs: ⊥
-[alias] analysing function: mbtowc
-[alias] May-aliases at the end of function mbtowc: ⊥
-[alias] analysing function: mkstemp
-[alias] May-aliases at the end of function mkstemp: ⊥
-[alias] analysing function: mkstemps
-[alias] May-aliases at the end of function mkstemps: ⊥
-[alias] analysing function: mrand48
-[alias] May-aliases at the end of function mrand48: ⊥
-[alias] analysing function: nan
-[alias] May-aliases at the end of function nan: ⊥
-[alias] analysing function: nanf
-[alias] May-aliases at the end of function nanf: ⊥
-[alias] analysing function: nanl
-[alias] May-aliases at the end of function nanl: ⊥
-[alias] analysing function: nrand48
-[alias] May-aliases at the end of function nrand48: ⊥
-[alias] analysing function: posix_memalign
-[alias] May-aliases at the end of function posix_memalign: ⊥
-[alias] analysing function: pow
-[alias] May-aliases at the end of function pow: ⊥
-[alias] analysing function: powf
-[alias] May-aliases at the end of function powf: ⊥
-[alias] analysing function: putenv
-[alias] May-aliases at the end of function putenv: ⊥
-[alias] analysing function: qsort
-[alias] May-aliases at the end of function qsort: ⊥
-[alias] analysing function: quick_exit
-[alias] May-aliases at the end of function quick_exit: ⊥
-[alias] analysing function: rand
-[alias] May-aliases at the end of function rand: ⊥
-[alias] analysing function: random
-[alias] May-aliases at the end of function random: ⊥
-[alias] analysing function: realloc
-[alias] May-aliases at the end of function realloc: ⊥
-[alias] analysing function: reallocarray
-[alias] May-aliases at the end of function reallocarray: ⊥
-[alias] analysing function: round
-[alias] May-aliases at the end of function round: ⊥
-[alias] analysing function: roundf
-[alias] May-aliases at the end of function roundf: ⊥
-[alias] analysing function: roundl
-[alias] May-aliases at the end of function roundl: ⊥
-[alias] analysing function: seed48
-[alias] May-aliases at the end of function seed48: ⊥
-[alias] analysing function: setenv
-[alias] May-aliases at the end of function setenv: ⊥
-[alias] analysing function: sin
-[alias] May-aliases at the end of function sin: ⊥
-[alias] analysing function: sinf
-[alias] May-aliases at the end of function sinf: ⊥
-[alias] analysing function: sinl
-[alias] May-aliases at the end of function sinl: ⊥
-[alias] analysing function: sqrt
-[alias] May-aliases at the end of function sqrt: ⊥
-[alias] analysing function: sqrtf
-[alias] May-aliases at the end of function sqrtf: ⊥
-[alias] analysing function: sqrtl
-[alias] May-aliases at the end of function sqrtl: ⊥
-[alias] analysing function: srand
-[alias] May-aliases at the end of function srand: ⊥
-[alias] analysing function: srand48
-[alias] May-aliases at the end of function srand48: ⊥
-[alias] analysing function: srandom
-[alias] May-aliases at the end of function srandom: ⊥
-[alias] analysing function: strtod
-[alias] May-aliases at the end of function strtod: ⊥
-[alias] analysing function: strtof
-[alias] May-aliases at the end of function strtof: ⊥
-[alias] analysing function: strtol
-[alias] May-aliases at the end of function strtol: ⊥
-[alias] analysing function: strtold
-[alias] May-aliases at the end of function strtold: ⊥
-[alias] analysing function: strtoll
-[alias] May-aliases at the end of function strtoll: ⊥
-[alias] analysing function: strtoul
-[alias] May-aliases at the end of function strtoul: ⊥
-[alias] analysing function: strtoull
-[alias] May-aliases at the end of function strtoull: ⊥
+  { a->n1; b->n1 }  { a->n2; b->n2 }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 50:{  }   29:{  } -n2→ 51:{  }
+  30:{ b } → 31:{  }   31:{  } -n1→ 50:{  }   31:{  } -n2→ 51:{  }
+  50:{  } → 39:{  }   51:{  } → 41:{  }
+[alias] May-aliases at the end of function main: { a->n1; b->n1 }  { a->n2; b->n2 }
+[alias] May-alias graph at the end of function main:
+  28:{ a } → 29:{  }   29:{  } -n1→ 50:{  }   29:{  } -n2→ 51:{  }
+  30:{ b } → 31:{  }   31:{  } -n1→ 50:{  }   31:{  } -n2→ 51:{  }
+  50:{  } → 39:{  }   51:{  } → 41:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { a->n1; b->n1 }  { a->n2; b->n2 }
 [alias] analysing function: swap
 [alias] May-aliases at the end of function swap: <none>
-[alias] analysing function: system
-[alias] May-aliases at the end of function system: ⊥
-[alias] analysing function: tan
-[alias] May-aliases at the end of function tan: ⊥
-[alias] analysing function: tanf
-[alias] May-aliases at the end of function tanf: ⊥
-[alias] analysing function: tanl
-[alias] May-aliases at the end of function tanl: ⊥
-[alias] analysing function: trunc
-[alias] May-aliases at the end of function trunc: ⊥
-[alias] analysing function: truncf
-[alias] May-aliases at the end of function truncf: ⊥
-[alias] analysing function: truncl
-[alias] May-aliases at the end of function truncl: ⊥
-[alias] analysing function: unsetenv
-[alias] May-aliases at the end of function unsetenv: ⊥
-[alias] analysing function: wcstombs
-[alias] May-aliases at the end of function wcstombs: ⊥
-[alias] analysing function: wctomb
-[alias] May-aliases at the end of function wctomb: ⊥
+[alias] May-alias graph at the end of function swap:
+  <empty>
+[alias] Summary of function swap:
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/real_world/oracle/example2.res.oracle b/src/plugins/alias/tests/real_world/oracle/example2.res.oracle
index 9194ea04e6668bcb37cb9735c58a8ff129e50f15..0ef06bd90acc8ce5bb80ae121d8bc442f832ab25 100644
--- a/src/plugins/alias/tests/real_world/oracle/example2.res.oracle
+++ b/src/plugins/alias/tests/real_world/oracle/example2.res.oracle
@@ -1,433 +1,386 @@
 [kernel] Parsing example2.c (with preprocessing)
-[alias] analysing function: _Exit
-[alias] May-aliases at the end of function _Exit: ⊥
-[alias] analysing function: __fc_fpclassify
-[alias] May-aliases at the end of function __fc_fpclassify: ⊥
-[alias] analysing function: __fc_fpclassifyf
-[alias] May-aliases at the end of function __fc_fpclassifyf: ⊥
-[alias] analysing function: __fc_infinity
-[alias] May-aliases at the end of function __fc_infinity: ⊥
-[alias] analysing function: __fc_nan
-[alias] May-aliases at the end of function __fc_nan: ⊥
-[alias] analysing function: __finite
-[alias] May-aliases at the end of function __finite: ⊥
-[alias] analysing function: __finitef
-[alias] May-aliases at the end of function __finitef: ⊥
-[alias] analysing function: abort
-[alias] May-aliases at the end of function abort: ⊥
-[alias] analysing function: abs
-[alias] May-aliases at the end of function abs: ⊥
-[alias] analysing function: acos
-[alias] May-aliases at the end of function acos: ⊥
-[alias] analysing function: acosf
-[alias] May-aliases at the end of function acosf: ⊥
-[alias] analysing function: acosh
-[alias] May-aliases at the end of function acosh: ⊥
-[alias] analysing function: acoshf
-[alias] May-aliases at the end of function acoshf: ⊥
-[alias] analysing function: acoshl
-[alias] May-aliases at the end of function acoshl: ⊥
-[alias] analysing function: acosl
-[alias] May-aliases at the end of function acosl: ⊥
-[alias] analysing function: asin
-[alias] May-aliases at the end of function asin: ⊥
-[alias] analysing function: asinf
-[alias] May-aliases at the end of function asinf: ⊥
-[alias] analysing function: asinl
-[alias] May-aliases at the end of function asinl: ⊥
-[alias] analysing function: at_quick_exit
-[alias] May-aliases at the end of function at_quick_exit: ⊥
-[alias] analysing function: atan
-[alias] May-aliases at the end of function atan: ⊥
-[alias] analysing function: atan2
-[alias] May-aliases at the end of function atan2: ⊥
-[alias] analysing function: atan2f
-[alias] May-aliases at the end of function atan2f: ⊥
-[alias] analysing function: atan2l
-[alias] May-aliases at the end of function atan2l: ⊥
-[alias] analysing function: atanf
-[alias] May-aliases at the end of function atanf: ⊥
-[alias] analysing function: atanl
-[alias] May-aliases at the end of function atanl: ⊥
-[alias] analysing function: atexit
-[alias] May-aliases at the end of function atexit: ⊥
-[alias] analysing function: atof
-[alias] May-aliases at the end of function atof: ⊥
-[alias] analysing function: atoi
-[alias] May-aliases at the end of function atoi: ⊥
-[alias] analysing function: atol
-[alias] May-aliases at the end of function atol: ⊥
-[alias] analysing function: atoll
-[alias] May-aliases at the end of function atoll: ⊥
-[alias] analysing function: bsearch
-[alias] May-aliases at the end of function bsearch: ⊥
-[alias] analysing function: calloc
-[alias] May-aliases at the end of function calloc: ⊥
-[alias] analysing function: ceil
-[alias] May-aliases at the end of function ceil: ⊥
-[alias] analysing function: ceilf
-[alias] May-aliases at the end of function ceilf: ⊥
-[alias] analysing function: ceill
-[alias] May-aliases at the end of function ceill: ⊥
-[alias] analysing function: cos
-[alias] May-aliases at the end of function cos: ⊥
-[alias] analysing function: cosf
-[alias] May-aliases at the end of function cosf: ⊥
-[alias] analysing function: cosl
-[alias] May-aliases at the end of function cosl: ⊥
-[alias] analysing function: div
-[alias] May-aliases at the end of function div: ⊥
-[alias] analysing function: drand48
-[alias] May-aliases at the end of function drand48: ⊥
-[alias] analysing function: erand48
-[alias] May-aliases at the end of function erand48: ⊥
-[alias] analysing function: exit
-[alias] May-aliases at the end of function exit: ⊥
-[alias] analysing function: exp
-[alias] May-aliases at the end of function exp: ⊥
-[alias] analysing function: expf
-[alias] May-aliases at the end of function expf: ⊥
 [alias] analysing function: f1
 [alias] analysing instruction: ty *tmp = x;
 [alias] May-aliases after instruction  ty *tmp = x;  are  { x; tmp }
+[alias] May-alias graph after instruction  ty *tmp = x;  is
+  0:{ x; tmp } → 1:{  }
 [alias] analysing instruction:
   idata = (double *)malloc((unsigned long)10 * sizeof(double));
 [alias] May-aliases after instruction
   idata = (double *)malloc((unsigned long)10 * sizeof(double));  are
   { x; tmp }
+[alias] May-alias graph after instruction
+  idata = (double *)malloc((unsigned long)10 * sizeof(double));  is
+  0:{ x; tmp } → 1:{  }   4:{ idata } → 5:{  }
 [alias] analysing instruction: int i = 0;
 [alias] May-aliases after instruction  int i = 0;  are  { x; tmp }
+[alias] May-alias graph after instruction  int i = 0;  is
+  0:{ x; tmp } → 1:{  }   4:{ idata } → 5:{  }
 [alias] analysing instruction: idata = tmp->t2[*(tmp->n2)];
 [alias] May-aliases after instruction  idata = tmp->t2[*(tmp->n2)];  are
-  { x; tmp }  { tmp->t2[0..]; idata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+[alias] May-alias graph after instruction  idata = tmp->t2[*(tmp->n2)];  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   4:{ idata } → 5:{  }
+  6:{  } → 4:{ idata }
 [alias] analysing instruction: odata = tmp->t1[*(tmp->n1)];
 [alias] May-aliases after instruction  odata = tmp->t1[*(tmp->n1)];  are
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph after instruction  odata = tmp->t1[*(tmp->n1)];  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
 [alias] analysing instruction: idx = 0;
 [alias] May-aliases after instruction  idx = 0;  are
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph after instruction  idx = 0;  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
 [alias] analysing instruction: tmp_1 = sin(*(idata + idx));
-[alias] analysing function: sin
-[alias] May-aliases at the end of function sin: ⊥
 [alias:undefined:fn] example2.c:45: Warning: function sin has no definition
 [alias] May-aliases after instruction  tmp_1 = sin(*(idata + idx));  are
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph after instruction  tmp_1 = sin(*(idata + idx));  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
 [alias] analysing instruction: *(odata + idx) = 0.5 * tmp_1;
 [alias] May-aliases after instruction  *(odata + idx) = 0.5 * tmp_1;  are
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph after instruction  *(odata + idx) = 0.5 * tmp_1;  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
 [alias] analysing instruction: idx ++;
 [alias] May-aliases after instruction  idx ++;  are
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph after instruction  idx ++;  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
 [alias] analysing instruction: swap(tmp->n1);
 [alias] analysing function: swap
 [alias] analysing instruction: *n = 0;
 [alias] May-aliases after instruction  *n = 0;  are  <none>
+[alias] May-alias graph after instruction  *n = 0;  is    <empty>
 [alias] analysing instruction: (*n) ++;
 [alias] May-aliases after instruction  (*n) ++;  are  <none>
+[alias] May-alias graph after instruction  (*n) ++;  is    <empty>
 [alias] May-aliases at the end of function swap: <none>
+[alias] May-alias graph at the end of function swap:
+  <empty>
+[alias] Summary of function swap:
 [alias] May-aliases after instruction  swap(tmp->n1);  are
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph after instruction  swap(tmp->n1);  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
 [alias] analysing instruction: i ++;
 [alias] May-aliases after instruction  i ++;  are
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph after instruction  i ++;  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
 [alias] analysing instruction: idata = tmp->t2[*(tmp->n2)];
 [alias] May-aliases after instruction  idata = tmp->t2[*(tmp->n2)];  are
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph after instruction  idata = tmp->t2[*(tmp->n2)];  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
 [alias] analysing instruction: odata = tmp->t1[*(tmp->n1)];
 [alias] May-aliases after instruction  odata = tmp->t1[*(tmp->n1)];  are
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph after instruction  odata = tmp->t1[*(tmp->n1)];  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
 [alias] analysing instruction: __retres = (void *)0;
 [alias] May-aliases after instruction  __retres = (void *)0;  are
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph after instruction  __retres = (void *)0;  is
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
 [alias] May-aliases at the end of function f1:
-  { x; tmp }  { tmp->t2[0..]; idata }  { tmp->t1[0..]; odata }
+  { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
+[alias] May-alias graph at the end of function f1:
+  0:{ x; tmp } → 1:{  }   1:{  } -t2→ 6:{  }   1:{  } -t1→ 10:{  }
+  4:{ idata } → 5:{  }   6:{  } → 4:{ idata }   8:{ odata } → 9:{  }
+  10:{  } → 8:{ odata }
+[alias] Summary of function f1:
+  formals: x    returns: __retres
+  state: { x; tmp }  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; idata }
+         { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; odata }
 [alias] analysing function: f2
 [alias] analysing instruction: ty *tmp = x;
 [alias] May-aliases after instruction  ty *tmp = x;  are  { x; tmp }
+[alias] May-alias graph after instruction  ty *tmp = x;  is
+  14:{ x; tmp } → 15:{  }
 [alias] analysing instruction:
   idata = (double *)malloc((unsigned long)10 * sizeof(double));
 [alias] May-aliases after instruction
   idata = (double *)malloc((unsigned long)10 * sizeof(double));  are
   { x; tmp }
+[alias] May-alias graph after instruction
+  idata = (double *)malloc((unsigned long)10 * sizeof(double));  is
+  14:{ x; tmp } → 15:{  }   18:{ idata } → 19:{  }
 [alias] analysing instruction: int i = 0;
 [alias] May-aliases after instruction  int i = 0;  are  { x; tmp }
+[alias] May-alias graph after instruction  int i = 0;  is
+  14:{ x; tmp } → 15:{  }   18:{ idata } → 19:{  }
 [alias] analysing instruction: idata = tmp->t1[*(tmp->n1)];
 [alias] May-aliases after instruction  idata = tmp->t1[*(tmp->n1)];  are
-  { x; tmp }  { tmp->t1[0..]; idata }
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+[alias] May-alias graph after instruction  idata = tmp->t1[*(tmp->n1)];  is
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
 [alias] analysing instruction: odata = tmp->t2[*(tmp->n2)];
 [alias] May-aliases after instruction  odata = tmp->t2[*(tmp->n2)];  are
-  { x; tmp }  { tmp->t1[0..]; idata }  { tmp->t2[0..]; odata }
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; odata }
+[alias] May-alias graph after instruction  odata = tmp->t2[*(tmp->n2)];  is
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }   15:{  } -t2→ 24:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
+  22:{ odata } → 23:{  }   24:{  } → 22:{ odata }
 [alias] analysing instruction: idx = 0;
 [alias] May-aliases after instruction  idx = 0;  are
-  { x; tmp }  { tmp->t1[0..]; idata }  { tmp->t2[0..]; odata }
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; odata }
+[alias] May-alias graph after instruction  idx = 0;  is
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }   15:{  } -t2→ 24:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
+  22:{ odata } → 23:{  }   24:{  } → 22:{ odata }
 [alias] analysing instruction:
   *(odata + idx) = (double)3 * *(idata + idx) + (double)1;
 [alias] May-aliases after instruction
   *(odata + idx) = (double)3 * *(idata + idx) + (double)1;  are
-  { x; tmp }  { tmp->t1[0..]; idata }  { tmp->t2[0..]; odata }
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; odata }
+[alias] May-alias graph after instruction
+  *(odata + idx) = (double)3 * *(idata + idx) + (double)1;  is
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }   15:{  } -t2→ 24:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
+  22:{ odata } → 23:{  }   24:{  } → 22:{ odata }
 [alias] analysing instruction: idx ++;
 [alias] May-aliases after instruction  idx ++;  are
-  { x; tmp }  { tmp->t1[0..]; idata }  { tmp->t2[0..]; odata }
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; odata }
+[alias] May-alias graph after instruction  idx ++;  is
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }   15:{  } -t2→ 24:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
+  22:{ odata } → 23:{  }   24:{  } → 22:{ odata }
 [alias] analysing instruction: swap(tmp->n2);
 [alias] May-aliases after instruction  swap(tmp->n2);  are
-  { x; tmp }  { tmp->t1[0..]; idata }  { tmp->t2[0..]; odata }
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; odata }
+[alias] May-alias graph after instruction  swap(tmp->n2);  is
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }   15:{  } -t2→ 24:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
+  22:{ odata } → 23:{  }   24:{  } → 22:{ odata }
 [alias] analysing instruction: i ++;
 [alias] May-aliases after instruction  i ++;  are
-  { x; tmp }  { tmp->t1[0..]; idata }  { tmp->t2[0..]; odata }
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; odata }
+[alias] May-alias graph after instruction  i ++;  is
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }   15:{  } -t2→ 24:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
+  22:{ odata } → 23:{  }   24:{  } → 22:{ odata }
 [alias] analysing instruction: idata = tmp->t1[*(tmp->n1)];
 [alias] May-aliases after instruction  idata = tmp->t1[*(tmp->n1)];  are
-  { x; tmp }  { tmp->t1[0..]; idata }  { tmp->t2[0..]; odata }
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; odata }
+[alias] May-alias graph after instruction  idata = tmp->t1[*(tmp->n1)];  is
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }   15:{  } -t2→ 24:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
+  22:{ odata } → 23:{  }   24:{  } → 22:{ odata }
 [alias] analysing instruction: odata = tmp->t2[*(tmp->n2)];
 [alias] May-aliases after instruction  odata = tmp->t2[*(tmp->n2)];  are
-  { x; tmp }  { tmp->t1[0..]; idata }  { tmp->t2[0..]; odata }
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; odata }
+[alias] May-alias graph after instruction  odata = tmp->t2[*(tmp->n2)];  is
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }   15:{  } -t2→ 24:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
+  22:{ odata } → 23:{  }   24:{  } → 22:{ odata }
 [alias] analysing instruction: __retres = (void *)0;
 [alias] May-aliases after instruction  __retres = (void *)0;  are
-  { x; tmp }  { tmp->t1[0..]; idata }  { tmp->t2[0..]; odata }
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; odata }
+[alias] May-alias graph after instruction  __retres = (void *)0;  is
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }   15:{  } -t2→ 24:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
+  22:{ odata } → 23:{  }   24:{  } → 22:{ odata }
 [alias] May-aliases at the end of function f2:
-  { x; tmp }  { tmp->t1[0..]; idata }  { tmp->t2[0..]; odata }
-[alias] analysing function: fabs
-[alias] May-aliases at the end of function fabs: ⊥
-[alias] analysing function: fabsf
-[alias] May-aliases at the end of function fabsf: ⊥
-[alias] analysing function: fabsl
-[alias] May-aliases at the end of function fabsl: ⊥
-[alias] analysing function: floor
-[alias] May-aliases at the end of function floor: ⊥
-[alias] analysing function: floorf
-[alias] May-aliases at the end of function floorf: ⊥
-[alias] analysing function: floorl
-[alias] May-aliases at the end of function floorl: ⊥
-[alias] analysing function: fmod
-[alias] May-aliases at the end of function fmod: ⊥
-[alias] analysing function: fmodf
-[alias] May-aliases at the end of function fmodf: ⊥
-[alias] analysing function: free
-[alias] May-aliases at the end of function free: ⊥
-[alias] analysing function: frexp
-[alias] May-aliases at the end of function frexp: ⊥
-[alias] analysing function: frexpf
-[alias] May-aliases at the end of function frexpf: ⊥
-[alias] analysing function: frexpl
-[alias] May-aliases at the end of function frexpl: ⊥
-[alias] analysing function: getenv
-[alias] May-aliases at the end of function getenv: ⊥
-[alias] analysing function: jrand48
-[alias] May-aliases at the end of function jrand48: ⊥
-[alias] analysing function: labs
-[alias] May-aliases at the end of function labs: ⊥
-[alias] analysing function: lcong48
-[alias] May-aliases at the end of function lcong48: ⊥
-[alias] analysing function: ldexp
-[alias] May-aliases at the end of function ldexp: ⊥
-[alias] analysing function: ldexpf
-[alias] May-aliases at the end of function ldexpf: ⊥
-[alias] analysing function: ldiv
-[alias] May-aliases at the end of function ldiv: ⊥
-[alias] analysing function: llabs
-[alias] May-aliases at the end of function llabs: ⊥
-[alias] analysing function: lldiv
-[alias] May-aliases at the end of function lldiv: ⊥
-[alias] analysing function: log
-[alias] May-aliases at the end of function log: ⊥
-[alias] analysing function: log10
-[alias] May-aliases at the end of function log10: ⊥
-[alias] analysing function: log10f
-[alias] May-aliases at the end of function log10f: ⊥
-[alias] analysing function: log10l
-[alias] May-aliases at the end of function log10l: ⊥
-[alias] analysing function: log2
-[alias] May-aliases at the end of function log2: ⊥
-[alias] analysing function: log2f
-[alias] May-aliases at the end of function log2f: ⊥
-[alias] analysing function: log2l
-[alias] May-aliases at the end of function log2l: ⊥
-[alias] analysing function: logf
-[alias] May-aliases at the end of function logf: ⊥
-[alias] analysing function: logl
-[alias] May-aliases at the end of function logl: ⊥
-[alias] analysing function: lrand48
-[alias] May-aliases at the end of function lrand48: ⊥
+  { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+  { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; odata }
+[alias] May-alias graph at the end of function f2:
+  14:{ x; tmp } → 15:{  }   15:{  } -t1→ 20:{  }   15:{  } -t2→ 24:{  }
+  18:{ idata } → 19:{  }   20:{  } → 18:{ idata }
+  22:{ odata } → 23:{  }   24:{  } → 22:{ odata }
+[alias] Summary of function f2:
+  formals: x    returns: __retres
+  state: { x; tmp }  { x->t1; tmp->t1 }  { x->t1[0..]; tmp->t1[0..]; idata }
+         { x->t2; tmp->t2 }  { x->t2[0..]; tmp->t2[0..]; odata }
 [alias] analysing function: main
 [alias] analysing instruction: a = (ty *)malloc(sizeof(ty));
 [alias] May-aliases after instruction  a = (ty *)malloc(sizeof(ty));  are  <none>
+[alias] May-alias graph after instruction  a = (ty *)malloc(sizeof(ty));  is
+  28:{ a } → 29:{  }
 [alias] analysing instruction: b = (ty *)malloc(sizeof(ty));
 [alias] May-aliases after instruction  b = (ty *)malloc(sizeof(ty));  are  <none>
+[alias] May-alias graph after instruction  b = (ty *)malloc(sizeof(ty));  is
+  28:{ a } → 29:{  }   30:{ b } → 31:{  }
 [alias] analysing instruction: i = 0;
 [alias] May-aliases after instruction  i = 0;  are  <none>
+[alias] May-alias graph after instruction  i = 0;  is
+  28:{ a } → 29:{  }   30:{ b } → 31:{  }
 [alias] analysing instruction:
   a->t1[i] = (double *)malloc((unsigned long)10 * sizeof(double));
 [alias] May-aliases after instruction
   a->t1[i] = (double *)malloc((unsigned long)10 * sizeof(double));  are  
   <none>
+[alias] May-alias graph after instruction
+  a->t1[i] = (double *)malloc((unsigned long)10 * sizeof(double));  is
+  28:{ a } → 29:{  }   29:{  } -t1→ 32:{  }   30:{ b } → 31:{  }
+  32:{  } → 33:{  }   33:{  } → 34:{  }
 [alias] analysing instruction:
   a->t2[i] = (double *)malloc((unsigned long)10 * sizeof(double));
 [alias] May-aliases after instruction
   a->t2[i] = (double *)malloc((unsigned long)10 * sizeof(double));  are  
   <none>
+[alias] May-alias graph after instruction
+  a->t2[i] = (double *)malloc((unsigned long)10 * sizeof(double));  is
+  28:{ a } → 29:{  }   29:{  } -t1→ 32:{  }   29:{  } -t2→ 35:{  }
+  30:{ b } → 31:{  }   32:{  } → 33:{  }   33:{  } → 34:{  }
+  35:{  } → 36:{  }   36:{  } → 37:{  }
 [alias] analysing instruction: i ++;
 [alias] May-aliases after instruction  i ++;  are  <none>
-[alias] analysing instruction:
-  a->t1[i] = (double *)malloc((unsigned long)10 * sizeof(double));
-[alias] May-aliases after instruction
-  a->t1[i] = (double *)malloc((unsigned long)10 * sizeof(double));  are  
-  <none>
-[alias] analysing instruction:
-  a->t2[i] = (double *)malloc((unsigned long)10 * sizeof(double));
-[alias] May-aliases after instruction
-  a->t2[i] = (double *)malloc((unsigned long)10 * sizeof(double));  are  
-  <none>
+[alias] May-alias graph after instruction  i ++;  is
+  28:{ a } → 29:{  }   29:{  } -t1→ 32:{  }   29:{  } -t2→ 35:{  }
+  30:{ b } → 31:{  }   32:{  } → 33:{  }   33:{  } → 34:{  }
+  35:{  } → 36:{  }   36:{  } → 37:{  }
 [alias] analysing instruction: a->n1 = (int *)malloc(sizeof(int));
 [alias] May-aliases after instruction  a->n1 = (int *)malloc(sizeof(int));  are
   <none>
+[alias] May-alias graph after instruction  a->n1 = (int *)malloc(sizeof(int));  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 38:{  }   30:{ b } → 31:{  }
+  38:{  } → 39:{  }
 [alias] analysing instruction: a->n2 = (int *)malloc(sizeof(int));
 [alias] May-aliases after instruction  a->n2 = (int *)malloc(sizeof(int));  are
   <none>
+[alias] May-alias graph after instruction  a->n2 = (int *)malloc(sizeof(int));  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 38:{  }   29:{  } -n2→ 40:{  }
+  30:{ b } → 31:{  }   38:{  } → 39:{  }   40:{  } → 41:{  }
 [alias] analysing instruction: *(a->n1) = 1;
 [alias] May-aliases after instruction  *(a->n1) = 1;  are  <none>
+[alias] May-alias graph after instruction  *(a->n1) = 1;  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 38:{  }   29:{  } -n2→ 40:{  }
+  30:{ b } → 31:{  }   38:{  } → 39:{  }   40:{  } → 41:{  }
 [alias] analysing instruction: *(a->n2) = 1;
 [alias] May-aliases after instruction  *(a->n2) = 1;  are  <none>
+[alias] May-alias graph after instruction  *(a->n2) = 1;  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 38:{  }   29:{  } -n2→ 40:{  }
+  30:{ b } → 31:{  }   38:{  } → 39:{  }   40:{  } → 41:{  }
 [alias] analysing instruction: i = 0;
 [alias] May-aliases after instruction  i = 0;  are  <none>
+[alias] May-alias graph after instruction  i = 0;  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 38:{  }   29:{  } -n2→ 40:{  }
+  30:{ b } → 31:{  }   38:{  } → 39:{  }   40:{  } → 41:{  }
 [alias] analysing instruction: b->t1[i] = a->t1[i];
-[alias] May-aliases after instruction  b->t1[i] = a->t1[i];  are
-  { a->t1[0..]; b->t1[0..] }
+[alias] May-aliases after instruction  b->t1[i] = a->t1[i];  are  { a->t1; b->t1 }
+[alias] May-alias graph after instruction  b->t1[i] = a->t1[i];  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 38:{  }   29:{  } -n2→ 40:{  }
+  29:{  } -t1→ 44:{  }   30:{ b } → 31:{  }   31:{  } -t1→ 42:{  }
+  38:{  } → 39:{  }   40:{  } → 41:{  }   42:{  } → 43:{  }
+  44:{  } → 43:{  }
 [alias] analysing instruction: b->t2[i] = a->t2[i];
 [alias] May-aliases after instruction  b->t2[i] = a->t2[i];  are
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }
+  { a->t1; b->t1 }  { a->t2; b->t2 }
+[alias] May-alias graph after instruction  b->t2[i] = a->t2[i];  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 38:{  }   29:{  } -n2→ 40:{  }
+  29:{  } -t1→ 44:{  }   29:{  } -t2→ 48:{  }   30:{ b } → 31:{  }
+  31:{  } -t1→ 42:{  }   31:{  } -t2→ 46:{  }   38:{  } → 39:{  }
+  40:{  } → 41:{  }   42:{  } → 43:{  }   44:{  } → 43:{  }
+  46:{  } → 47:{  }   48:{  } → 47:{  }
 [alias] analysing instruction: i ++;
-[alias] May-aliases after instruction  i ++;  are
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }
-[alias] analysing instruction: b->t1[i] = a->t1[i];
-[alias] May-aliases after instruction  b->t1[i] = a->t1[i];  are
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }
-[alias] analysing instruction: b->t2[i] = a->t2[i];
-[alias] May-aliases after instruction  b->t2[i] = a->t2[i];  are
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }
+[alias] May-aliases after instruction  i ++;  are  { a->t1; b->t1 }  { a->t2; b->t2 }
+[alias] May-alias graph after instruction  i ++;  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 38:{  }   29:{  } -n2→ 40:{  }
+  29:{  } -t1→ 44:{  }   29:{  } -t2→ 48:{  }   30:{ b } → 31:{  }
+  31:{  } -t1→ 42:{  }   31:{  } -t2→ 46:{  }   38:{  } → 39:{  }
+  40:{  } → 41:{  }   42:{  } → 43:{  }   44:{  } → 43:{  }
+  46:{  } → 47:{  }   48:{  } → 47:{  }
 [alias] analysing instruction: b->n1 = a->n1;
-[alias] May-aliases after instruction  b->n1 = a->n1;  are
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }  { a->n1; b->n1 }
+[alias] May-aliases after instruction  b->n1 = a->n1;  are  { a->n1; b->n1 }
+[alias] May-alias graph after instruction  b->n1 = a->n1;  is
+  28:{ a } → 29:{  }   29:{  } -n2→ 40:{  }   29:{  } -n1→ 50:{  }
+  30:{ b } → 31:{  }   31:{  } -n1→ 50:{  }   40:{  } → 41:{  }
+  50:{  } → 39:{  }
 [alias] analysing instruction: b->n2 = a->n2;
 [alias] May-aliases after instruction  b->n2 = a->n2;  are
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }  { a->n1; b->n1 }
-  { a->n2; b->n2 }
+  { a->n1; b->n1 }  { a->n2; b->n2 }
+[alias] May-alias graph after instruction  b->n2 = a->n2;  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 50:{  }   29:{  } -n2→ 51:{  }
+  30:{ b } → 31:{  }   31:{  } -n1→ 50:{  }   31:{  } -n2→ 51:{  }
+  50:{  } → 39:{  }   51:{  } → 41:{  }
 [alias] analysing instruction: f1(a);
 [alias] May-aliases after instruction  f1(a);  are
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }  { a->n1; b->n1 }
-  { a->n2; b->n2 }
+  { a->n1; b->n1 }  { a->n2; b->n2 }
+[alias] May-alias graph after instruction  f1(a);  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 50:{  }   29:{  } -n2→ 51:{  }
+  29:{  } -t2→ 58:{  }   29:{  } -t1→ 62:{  }   30:{ b } → 31:{  }
+  31:{  } -n1→ 50:{  }   31:{  } -n2→ 51:{  }   50:{  } → 39:{  }
+  51:{  } → 41:{  }   56:{  } → 57:{  }   58:{  } → 56:{  }
+  60:{  } → 61:{  }   62:{  } → 60:{  }
 [alias] analysing instruction: f2(b);
 [alias] May-aliases after instruction  f2(b);  are
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }  { a->n1; b->n1 }
-  { a->n2; b->n2 }
+  { a->n1; b->n1 }  { a->n2; b->n2 }
+[alias] May-alias graph after instruction  f2(b);  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 50:{  }   29:{  } -n2→ 51:{  }
+  29:{  } -t2→ 58:{  }   29:{  } -t1→ 62:{  }   30:{ b } → 31:{  }
+  31:{  } -n1→ 50:{  }   31:{  } -n2→ 51:{  }   31:{  } -t1→ 72:{  }
+  31:{  } -t2→ 76:{  }   50:{  } → 39:{  }   51:{  } → 41:{  }
+  56:{  } → 57:{  }   58:{  } → 56:{  }   60:{  } → 61:{  }
+  62:{  } → 60:{  }   70:{  } → 71:{  }   72:{  } → 70:{  }
+  74:{  } → 75:{  }   76:{  } → 74:{  }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }  { a->n1; b->n1 }
-  { a->n2; b->n2 }
-[alias] May-aliases at the end of function main:
-  { a->t1[0..]; b->t1[0..] }  { a->t2[0..]; b->t2[0..] }  { a->n1; b->n1 }
-  { a->n2; b->n2 }
-[alias] analysing function: malloc
-[alias] May-aliases at the end of function malloc: ⊥
-[alias] analysing function: mblen
-[alias] May-aliases at the end of function mblen: ⊥
-[alias] analysing function: mbstowcs
-[alias] May-aliases at the end of function mbstowcs: ⊥
-[alias] analysing function: mbtowc
-[alias] May-aliases at the end of function mbtowc: ⊥
-[alias] analysing function: mkstemp
-[alias] May-aliases at the end of function mkstemp: ⊥
-[alias] analysing function: mkstemps
-[alias] May-aliases at the end of function mkstemps: ⊥
-[alias] analysing function: mrand48
-[alias] May-aliases at the end of function mrand48: ⊥
-[alias] analysing function: nan
-[alias] May-aliases at the end of function nan: ⊥
-[alias] analysing function: nanf
-[alias] May-aliases at the end of function nanf: ⊥
-[alias] analysing function: nanl
-[alias] May-aliases at the end of function nanl: ⊥
-[alias] analysing function: nrand48
-[alias] May-aliases at the end of function nrand48: ⊥
-[alias] analysing function: posix_memalign
-[alias] May-aliases at the end of function posix_memalign: ⊥
-[alias] analysing function: pow
-[alias] May-aliases at the end of function pow: ⊥
-[alias] analysing function: powf
-[alias] May-aliases at the end of function powf: ⊥
-[alias] analysing function: putenv
-[alias] May-aliases at the end of function putenv: ⊥
-[alias] analysing function: qsort
-[alias] May-aliases at the end of function qsort: ⊥
-[alias] analysing function: quick_exit
-[alias] May-aliases at the end of function quick_exit: ⊥
-[alias] analysing function: rand
-[alias] May-aliases at the end of function rand: ⊥
-[alias] analysing function: random
-[alias] May-aliases at the end of function random: ⊥
-[alias] analysing function: realloc
-[alias] May-aliases at the end of function realloc: ⊥
-[alias] analysing function: reallocarray
-[alias] May-aliases at the end of function reallocarray: ⊥
-[alias] analysing function: round
-[alias] May-aliases at the end of function round: ⊥
-[alias] analysing function: roundf
-[alias] May-aliases at the end of function roundf: ⊥
-[alias] analysing function: roundl
-[alias] May-aliases at the end of function roundl: ⊥
-[alias] analysing function: seed48
-[alias] May-aliases at the end of function seed48: ⊥
-[alias] analysing function: setenv
-[alias] May-aliases at the end of function setenv: ⊥
-[alias] analysing function: sin
-[alias] May-aliases at the end of function sin: ⊥
-[alias] analysing function: sinf
-[alias] May-aliases at the end of function sinf: ⊥
-[alias] analysing function: sinl
-[alias] May-aliases at the end of function sinl: ⊥
-[alias] analysing function: sqrt
-[alias] May-aliases at the end of function sqrt: ⊥
-[alias] analysing function: sqrtf
-[alias] May-aliases at the end of function sqrtf: ⊥
-[alias] analysing function: sqrtl
-[alias] May-aliases at the end of function sqrtl: ⊥
-[alias] analysing function: srand
-[alias] May-aliases at the end of function srand: ⊥
-[alias] analysing function: srand48
-[alias] May-aliases at the end of function srand48: ⊥
-[alias] analysing function: srandom
-[alias] May-aliases at the end of function srandom: ⊥
-[alias] analysing function: strtod
-[alias] May-aliases at the end of function strtod: ⊥
-[alias] analysing function: strtof
-[alias] May-aliases at the end of function strtof: ⊥
-[alias] analysing function: strtol
-[alias] May-aliases at the end of function strtol: ⊥
-[alias] analysing function: strtold
-[alias] May-aliases at the end of function strtold: ⊥
-[alias] analysing function: strtoll
-[alias] May-aliases at the end of function strtoll: ⊥
-[alias] analysing function: strtoul
-[alias] May-aliases at the end of function strtoul: ⊥
-[alias] analysing function: strtoull
-[alias] May-aliases at the end of function strtoull: ⊥
+  { a->n1; b->n1 }  { a->n2; b->n2 }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  28:{ a } → 29:{  }   29:{  } -n1→ 50:{  }   29:{  } -n2→ 51:{  }
+  29:{  } -t2→ 58:{  }   29:{  } -t1→ 62:{  }   30:{ b } → 31:{  }
+  31:{  } -n1→ 50:{  }   31:{  } -n2→ 51:{  }   31:{  } -t1→ 72:{  }
+  31:{  } -t2→ 76:{  }   50:{  } → 39:{  }   51:{  } → 41:{  }
+  56:{  } → 57:{  }   58:{  } → 56:{  }   60:{  } → 61:{  }
+  62:{  } → 60:{  }   70:{  } → 71:{  }   72:{  } → 70:{  }
+  74:{  } → 75:{  }   76:{  } → 74:{  }
+[alias] May-aliases at the end of function main: { a->n1; b->n1 }  { a->n2; b->n2 }
+[alias] May-alias graph at the end of function main:
+  28:{ a } → 29:{  }   29:{  } -n1→ 50:{  }   29:{  } -n2→ 51:{  }
+  29:{  } -t2→ 58:{  }   29:{  } -t1→ 62:{  }   30:{ b } → 31:{  }
+  31:{  } -n1→ 50:{  }   31:{  } -n2→ 51:{  }   31:{  } -t1→ 72:{  }
+  31:{  } -t2→ 76:{  }   50:{  } → 39:{  }   51:{  } → 41:{  }
+  56:{  } → 57:{  }   58:{  } → 56:{  }   60:{  } → 61:{  }
+  62:{  } → 60:{  }   70:{  } → 71:{  }   72:{  } → 70:{  }
+  74:{  } → 75:{  }   76:{  } → 74:{  }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { a->n1; b->n1 }  { a->n2; b->n2 }
 [alias] analysing function: swap
 [alias] May-aliases at the end of function swap: <none>
-[alias] analysing function: system
-[alias] May-aliases at the end of function system: ⊥
-[alias] analysing function: tan
-[alias] May-aliases at the end of function tan: ⊥
-[alias] analysing function: tanf
-[alias] May-aliases at the end of function tanf: ⊥
-[alias] analysing function: tanl
-[alias] May-aliases at the end of function tanl: ⊥
-[alias] analysing function: trunc
-[alias] May-aliases at the end of function trunc: ⊥
-[alias] analysing function: truncf
-[alias] May-aliases at the end of function truncf: ⊥
-[alias] analysing function: truncl
-[alias] May-aliases at the end of function truncl: ⊥
-[alias] analysing function: unsetenv
-[alias] May-aliases at the end of function unsetenv: ⊥
-[alias] analysing function: wcstombs
-[alias] May-aliases at the end of function wcstombs: ⊥
-[alias] analysing function: wctomb
-[alias] May-aliases at the end of function wctomb: ⊥
+[alias] May-alias graph at the end of function swap:
+  <empty>
+[alias] Summary of function swap:
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/real_world/oracle/function1_v2.res.oracle b/src/plugins/alias/tests/real_world/oracle/function1_v2.res.oracle
index 15cf879d31ba16210aae70e1265d1567aa8fa401..23d94fe8cb7ae6d16a7ca4ab9535253349a572cf 100644
--- a/src/plugins/alias/tests/real_world/oracle/function1_v2.res.oracle
+++ b/src/plugins/alias/tests/real_world/oracle/function1_v2.res.oracle
@@ -1,133 +1,45 @@
 [kernel] Parsing function1_v2.c (with preprocessing)
-[alias] analysing function: _Exit
-[alias] May-aliases at the end of function _Exit: ⊥
-[alias] analysing function: abort
-[alias] May-aliases at the end of function abort: ⊥
-[alias] analysing function: abs
-[alias] May-aliases at the end of function abs: ⊥
 [alias] analysing function: alias
 [alias] analysing instruction: *x = *y;
-[alias] May-aliases after instruction  *x = *y;  are  { x; y }
-[alias] May-aliases at the end of function alias: { x; y }
-[alias] analysing function: at_quick_exit
-[alias] May-aliases at the end of function at_quick_exit: ⊥
-[alias] analysing function: atexit
-[alias] May-aliases at the end of function atexit: ⊥
-[alias] analysing function: atof
-[alias] May-aliases at the end of function atof: ⊥
-[alias] analysing function: atoi
-[alias] May-aliases at the end of function atoi: ⊥
-[alias] analysing function: atol
-[alias] May-aliases at the end of function atol: ⊥
-[alias] analysing function: atoll
-[alias] May-aliases at the end of function atoll: ⊥
-[alias] analysing function: bsearch
-[alias] May-aliases at the end of function bsearch: ⊥
-[alias] analysing function: calloc
-[alias] May-aliases at the end of function calloc: ⊥
-[alias] analysing function: div
-[alias] May-aliases at the end of function div: ⊥
-[alias] analysing function: drand48
-[alias] May-aliases at the end of function drand48: ⊥
-[alias] analysing function: erand48
-[alias] May-aliases at the end of function erand48: ⊥
-[alias] analysing function: exit
-[alias] May-aliases at the end of function exit: ⊥
-[alias] analysing function: free
-[alias] May-aliases at the end of function free: ⊥
-[alias] analysing function: getenv
-[alias] May-aliases at the end of function getenv: ⊥
-[alias] analysing function: jrand48
-[alias] May-aliases at the end of function jrand48: ⊥
-[alias] analysing function: labs
-[alias] May-aliases at the end of function labs: ⊥
-[alias] analysing function: lcong48
-[alias] May-aliases at the end of function lcong48: ⊥
-[alias] analysing function: ldiv
-[alias] May-aliases at the end of function ldiv: ⊥
-[alias] analysing function: llabs
-[alias] May-aliases at the end of function llabs: ⊥
-[alias] analysing function: lldiv
-[alias] May-aliases at the end of function lldiv: ⊥
-[alias] analysing function: lrand48
-[alias] May-aliases at the end of function lrand48: ⊥
+[alias] May-aliases after instruction  *x = *y;  are  { x; y }  { *x; *y }
+[alias] May-alias graph after instruction  *x = *y;  is
+  0:{ x } → 1:{  }   1:{  } → 2:{  }   3:{ y } → 1:{  }
+[alias] May-aliases at the end of function alias: { x; y }  { *x; *y }
+[alias] May-alias graph at the end of function alias:
+  0:{ x } → 1:{  }   1:{  } → 2:{  }   3:{ y } → 1:{  }
+[alias] Summary of function alias:
+  formals: x  y    returns: <none>    state: { x; y }  { *x; *y }
 [alias] analysing function: main
 [alias] analysing instruction: int *a = malloc(sizeof(int));
 [alias] May-aliases after instruction  int *a = malloc(sizeof(int));  are  <none>
+[alias] May-alias graph after instruction  int *a = malloc(sizeof(int));  is
+  6:{ a } → 7:{  }
 [alias] analysing instruction: *a = 0;
 [alias] May-aliases after instruction  *a = 0;  are  <none>
+[alias] May-alias graph after instruction  *a = 0;  is    6:{ a } → 7:{  }
 [alias] analysing instruction: int *b = malloc(sizeof(int));
 [alias] May-aliases after instruction  int *b = malloc(sizeof(int));  are  <none>
+[alias] May-alias graph after instruction  int *b = malloc(sizeof(int));  is
+  6:{ a } → 7:{  }   8:{ b } → 9:{  }
 [alias] analysing instruction: *b = 42;
 [alias] May-aliases after instruction  *b = 42;  are  <none>
+[alias] May-alias graph after instruction  *b = 42;  is
+  6:{ a } → 7:{  }   8:{ b } → 9:{  }
 [alias] analysing instruction: alias(& a,& b);
 [alias] May-aliases after instruction  alias(& a,& b);  are  { a; b }
+[alias] May-alias graph after instruction  alias(& a,& b);  is
+  6:{ a; b } → 7:{  }   14:{  } → 6:{ a; b }   15:{  } → 6:{ a; b }
 [alias] analysing instruction: *a = 7;
 [alias] May-aliases after instruction  *a = 7;  are  { a; b }
+[alias] May-alias graph after instruction  *a = 7;  is
+  6:{ a; b } → 7:{  }   14:{  } → 6:{ a; b }   15:{  } → 6:{ a; b }
 [alias] analysing instruction: __retres = 0;
 [alias] May-aliases after instruction  __retres = 0;  are  { a; b }
+[alias] May-alias graph after instruction  __retres = 0;  is
+  6:{ a; b } → 7:{  }   14:{  } → 6:{ a; b }   15:{  } → 6:{ a; b }
 [alias] May-aliases at the end of function main: { a; b }
-[alias] analysing function: malloc
-[alias] May-aliases at the end of function malloc: ⊥
-[alias] analysing function: mblen
-[alias] May-aliases at the end of function mblen: ⊥
-[alias] analysing function: mbstowcs
-[alias] May-aliases at the end of function mbstowcs: ⊥
-[alias] analysing function: mbtowc
-[alias] May-aliases at the end of function mbtowc: ⊥
-[alias] analysing function: mkstemp
-[alias] May-aliases at the end of function mkstemp: ⊥
-[alias] analysing function: mkstemps
-[alias] May-aliases at the end of function mkstemps: ⊥
-[alias] analysing function: mrand48
-[alias] May-aliases at the end of function mrand48: ⊥
-[alias] analysing function: nrand48
-[alias] May-aliases at the end of function nrand48: ⊥
-[alias] analysing function: posix_memalign
-[alias] May-aliases at the end of function posix_memalign: ⊥
-[alias] analysing function: putenv
-[alias] May-aliases at the end of function putenv: ⊥
-[alias] analysing function: qsort
-[alias] May-aliases at the end of function qsort: ⊥
-[alias] analysing function: quick_exit
-[alias] May-aliases at the end of function quick_exit: ⊥
-[alias] analysing function: rand
-[alias] May-aliases at the end of function rand: ⊥
-[alias] analysing function: random
-[alias] May-aliases at the end of function random: ⊥
-[alias] analysing function: realloc
-[alias] May-aliases at the end of function realloc: ⊥
-[alias] analysing function: reallocarray
-[alias] May-aliases at the end of function reallocarray: ⊥
-[alias] analysing function: seed48
-[alias] May-aliases at the end of function seed48: ⊥
-[alias] analysing function: setenv
-[alias] May-aliases at the end of function setenv: ⊥
-[alias] analysing function: srand
-[alias] May-aliases at the end of function srand: ⊥
-[alias] analysing function: srand48
-[alias] May-aliases at the end of function srand48: ⊥
-[alias] analysing function: srandom
-[alias] May-aliases at the end of function srandom: ⊥
-[alias] analysing function: strtod
-[alias] May-aliases at the end of function strtod: ⊥
-[alias] analysing function: strtof
-[alias] May-aliases at the end of function strtof: ⊥
-[alias] analysing function: strtol
-[alias] May-aliases at the end of function strtol: ⊥
-[alias] analysing function: strtold
-[alias] May-aliases at the end of function strtold: ⊥
-[alias] analysing function: strtoll
-[alias] May-aliases at the end of function strtoll: ⊥
-[alias] analysing function: strtoul
-[alias] May-aliases at the end of function strtoul: ⊥
-[alias] analysing function: strtoull
-[alias] May-aliases at the end of function strtoull: ⊥
-[alias] analysing function: system
-[alias] May-aliases at the end of function system: ⊥
-[alias] analysing function: unsetenv
-[alias] May-aliases at the end of function unsetenv: ⊥
-[alias] analysing function: wcstombs
-[alias] May-aliases at the end of function wcstombs: ⊥
-[alias] analysing function: wctomb
-[alias] May-aliases at the end of function wctomb: ⊥
+[alias] May-alias graph at the end of function main:
+  6:{ a; b } → 7:{  }   14:{  } → 6:{ a; b }   15:{  } → 6:{ a; b }
+[alias] Summary of function main:
+  formals:     returns: __retres    state: { a; b }
+[alias] Analysis complete
diff --git a/src/plugins/alias/tests/test_config b/src/plugins/alias/tests/test_config
index e14c0a6d24720b60c9a29eb36a4bb4cd432e5b55..80976f50aac4719cd461142fbf18921cc32c3768 100644
--- a/src/plugins/alias/tests/test_config
+++ b/src/plugins/alias/tests/test_config
@@ -1,2 +1,2 @@
 PLUGIN: alias
-OPT: -alias -alias-verbose 3
+OPT: -alias -alias-verbose 3 -alias-debug 3
diff --git a/src/plugins/alias/tests/unsupported/pointer_call.c b/src/plugins/alias/tests/unsupported/pointer_call.c
deleted file mode 100644
index 448ec0f752f68628673aafccdb70969d51f5a381..0000000000000000000000000000000000000000
--- a/src/plugins/alias/tests/unsupported/pointer_call.c
+++ /dev/null
@@ -1,8 +0,0 @@
-int f () {
-  return 0;
-}
-
-int main () {
-  int (*p)() = &f;
-  return ((*p)());
-}
diff --git a/src/plugins/aorai/aorai_utils.ml b/src/plugins/aorai/aorai_utils.ml
index 23685c5dde7f246d2bc7d5a4e0e9a82308f19d3d..395295a390427ea1ae2f7abc419d173fab87871f 100644
--- a/src/plugins/aorai/aorai_utils.ml
+++ b/src/plugins/aorai/aorai_utils.ml
@@ -165,13 +165,12 @@ let isCrossableAtInit tr func =
               bool_res (comp (Char.compare c1 c2))
             | TConst(LReal r1), TConst (LReal r2) ->
               bool_res (comp (compare r1.r_nearest r2.r_nearest))
-            | TCastE(ty1,t1), TCastE(ty2,t2)
+            | TCast (false, Ctype ty1,t1), TCast (false, Ctype ty2,t2)
               when Cil_datatype.Typ.equal ty1 ty2 ->
               comparison comp t1 t2
             | _ -> t
           in
           (match op, t1.term_node, t2.term_node with
-
            | PlusA, TConst(Integer(i1,_)), TConst(Integer(i2,_)) ->
              { t with term_node =
                         TConst(Integer(Integer.add i1 i2,None))}
@@ -208,11 +207,11 @@ let isCrossableAtInit tr func =
            | LOr, t1, t2 ->
              bool3_res t (Bool3.bool3or (is_true t1) (is_true t2))
            | _ -> t)
-        | TCastE(ty,t1) ->
+        | TCast (false, Ctype ty,t1) ->
           let t1 = aux t1 in
           (match t1.term_type with
-             Ctype ty1 when Cil_datatype.Typ.equal ty ty1 -> t1
-           | _ -> { t with term_node = TCastE(ty,t1) })
+           | Ctype ty1 when Cil_datatype.Typ.equal ty ty1 -> t1
+           | _ -> { t with term_node = TCast (false, Ctype ty,t1) })
         | _ -> t
       and aux_lv (base,off) =
         match base with
@@ -283,7 +282,8 @@ let isCrossableAtInit tr func =
         Bool3.bool3_of_bool (comp (Char.compare c1 c2))
       | TConst(LReal r1), TConst (LReal r2) ->
         Bool3.bool3_of_bool (comp (compare r1.r_nearest r2.r_nearest))
-      | TCastE(ty1,t1), TCastE(ty2,t2) when Cil_datatype.Typ.equal ty1 ty2 ->
+      | TCast (false, Ctype ty1,t1), TCast (false, Ctype ty2,t2)
+        when Cil_datatype.Typ.equal ty1 ty2 ->
         comparison t1 t2
       | _ -> Bool3.Undefined
     in
@@ -419,7 +419,7 @@ let rec term_to_exp t res =
   | TBinOp (binop, t1, t2)->
     new_exp ~loc
       (BinOp(binop, term_to_exp t1 res, term_to_exp t2 res, Cil.intType))
-  | TCastE(ty, {term_node = TConst(LReal lreal)}) when Cil.isFloatingType ty ->
+  | TCast (false, Ctype ty, {term_node = TConst(LReal lreal)}) when Cil.isFloatingType ty ->
     (match Cil.unrollType ty with
      | TFloat(fk,_) ->
        new_exp ~loc
@@ -427,10 +427,10 @@ let rec term_to_exp t res =
      | _ ->
        Aorai_option.fatal
          "A floating-point type was expected, got %a." Printer.pp_typ ty)
-  | TCastE (ty, t) -> new_exp ~loc (CastE (ty, term_to_exp t res))
+  | TCast (false, Ctype ty, t) -> new_exp ~loc (CastE (ty, term_to_exp t res))
   | TAddrOf tlval -> new_exp ~loc (AddrOf (tlval_to_lval tlval res))
   | TStartOf tlval -> new_exp ~loc (StartOf (tlval_to_lval tlval res))
-  | TLogic_coerce (_,t) -> term_to_exp t res
+  | TCast (true, _,t) -> term_to_exp t res
   | _ ->
     Aorai_option.fatal
       "Term %a cannot be transformed into exp."
@@ -510,7 +510,7 @@ let get_bhv_aux_fct kf bhv =
       [Normal,
        Logic_const.(
          new_predicate
-           (prel (Req,tlogic_coerce (tresult ret_typ) Linteger,lone())))]
+           (prel (Req, tlogic_coerce (tresult ret_typ) Linteger,lone())))]
     in
     let bhv_in =
       Cil.mk_behavior ~name:bhv.b_name ~assumes ~assigns ~post_cond ()
diff --git a/src/plugins/dive/tests/dive/oracle/exceptional.res.oracle b/src/plugins/dive/tests/dive/oracle/exceptional.res.oracle
index 7cfe3e4ea5cf0dc4afe4fc3594f5fc056a737886..ae50bf359dc8ec7fdd730f6d2635af6d25ce7453 100644
--- a/src/plugins/dive/tests/dive/oracle/exceptional.res.oracle
+++ b/src/plugins/dive/tests/dive/oracle/exceptional.res.oracle
@@ -1,14 +1,8 @@
 [kernel] Parsing exceptional.i (no preprocessing)
 [eva] Analyzing a complete application starting at main
 [eva:garbled-mix:write] exceptional.i:5: 
-  Assigning imprecise value to __retres.
-  The imprecision originates from Arithmetic {exceptional.i:5}
-[eva:garbled-mix:write] exceptional.i:5: 
-  Assigning imprecise value to \result<gm>.
-  The imprecision originates from Arithmetic {exceptional.i:5}
-[eva:garbled-mix:write] exceptional.i:16: 
-  Assigning imprecise value to p.
-  The imprecision originates from Arithmetic {exceptional.i:5}
+  Assigning imprecise value to __retres
+  because of arithmetic operation on addresses.
 [eva:alarm] exceptional.i:17: Warning: 
   accessing uninitialized left-value. assert \initialized(p);
 [eva:alarm] exceptional.i:17: Warning: 
@@ -19,6 +13,10 @@
   signed overflow. assert a + x ≤ 2147483647;
 [eva:alarm] exceptional.i:23: Warning: 
   signed overflow. assert (int)(a + x) + (int)c ≤ 2147483647;
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    exceptional.i:5: arithmetic operation on addresses
+      (read 3 times, propagated 3 times) garbled mix of &{i}
 [eva:summary] ====== ANALYSIS SUMMARY ======
   ----------------------------------------------------------------------------
   2 functions analyzed (out of 2): 100% coverage.
diff --git a/src/plugins/e-acsl/doc/Changelog b/src/plugins/e-acsl/doc/Changelog
index 35c9005a454f37c39aa66292522f8df0b3f8a120..d8870d5d675330af434e4497703f6dcdb3ce0f41 100644
--- a/src/plugins/e-acsl/doc/Changelog
+++ b/src/plugins/e-acsl/doc/Changelog
@@ -25,6 +25,10 @@
 Plugin E-ACSL <next-release>
 ###############################################################################
 
+###############################################################################
+Plugin E-ACSL 28.1 (Nickel)
+###############################################################################
+
 ###############################################################################
 Plugin E-ACSL 28.0 (Nickel)
 ###############################################################################
diff --git a/src/plugins/e-acsl/src/analyses/bound_variables.ml b/src/plugins/e-acsl/src/analyses/bound_variables.ml
index 7764bd1d100ddfb9a262a99cc358a558c73d0368..7bf460e21c6454077bd009589977b7f54afdee22 100644
--- a/src/plugins/e-acsl/src/analyses/bound_variables.ml
+++ b/src/plugins/e-acsl/src/analyses/bound_variables.ml
@@ -247,7 +247,7 @@ end = struct
   let get_bounded_var t ctxt =
     let rec aux t =
       match t.term_node with
-      | TLogic_coerce(_, t) -> aux t
+      | TCast (true, _, t) -> aux t
       | TLval(TVar lv, TNoOffset) when Logic_var.Set.mem lv ctxt.bounded_vars ->
         Some lv
       | _ -> None
@@ -524,7 +524,7 @@ let extract_constraint ctxt t1 r t2 =
      is not a variable ([TLval(TVar _, TNoOffset)]). *)
   let rec _get_logic_var_opt t =
     match t.term_node with
-    | TLogic_coerce(_, t) -> _get_logic_var_opt t
+    | TCast (true, _, t) -> _get_logic_var_opt t
     | TLval(TVar x, TNoOffset) -> Some x
     | _ -> None
   in
diff --git a/src/plugins/e-acsl/src/analyses/interval.ml b/src/plugins/e-acsl/src/analyses/interval.ml
index 79f27b6ae314fad54e9a56d5231165ca91575271..679f8530323bf7ba8cad51946fb551f17e193e81 100644
--- a/src/plugins/e-acsl/src/analyses/interval.ml
+++ b/src/plugins/e-acsl/src/analyses/interval.ml
@@ -392,10 +392,12 @@ let rec infer ~force ~logic_env t =
       let i2 = infer ~force ~logic_env t2 in
       Error.map2 (lift_arith_binop (ival_arith_binop op)) i1 i2
 
-    | TCastE (ty, t) ->
+    | TCast (false, Ctype ty, t) ->
       let src = infer ~force ~logic_env t in
       let dst = interv_of_typ ty in
       Error.map (fun src -> cast ~src ~dst) src
+    | TCast (true, _, t) -> get_res (infer ~force ~logic_env t)
+    | TCast (false, _,_) -> assert false
     | Tif (t1, t2, t3) ->
       ignore (infer ~force ~logic_env t1);
       let logic_env_tbranch, logic_env_fbranch =
@@ -440,7 +442,6 @@ let rec infer ~force ~logic_env t =
        | TPtr _ -> Lazy.force interv_of_unknown_block
        | _ -> assert false)
     | Tnull  -> singleton_of_int 0
-    | TLogic_coerce (_, t) -> get_res (infer ~force ~logic_env t)
     | Tapp (li,_,args) ->
       (match li.l_body with
        | LBpred _ | LBterm _ ->
diff --git a/src/plugins/e-acsl/src/analyses/labels.ml b/src/plugins/e-acsl/src/analyses/labels.ml
index 36325279dedccb2ef82c6b2f9a034d804b5268c8..29fe58ee99045e56f539febd04361a71d5af15ae 100644
--- a/src/plugins/e-acsl/src/analyses/labels.ml
+++ b/src/plugins/e-acsl/src/analyses/labels.ml
@@ -324,8 +324,8 @@ end = struct
       do_term ?error env t
     | TLval lv | TAddrOf lv | TStartOf lv ->
       do_term_lval ?error env lv
-    | TSizeOfE t | TAlignOfE t | TUnOp (_, t) | TCastE (_, t) | Tlambda (_, t)
-    | TLogic_coerce (_, t) ->
+    | TSizeOfE t | TAlignOfE t | TUnOp (_, t)
+    | TCast (_, _, t) | Tlambda (_, t) ->
       do_term ?error env t
     | TBinOp (_, t1, t2) ->
       let error = do_term ?error env t1 in
diff --git a/src/plugins/e-acsl/src/analyses/memory_tracking.ml b/src/plugins/e-acsl/src/analyses/memory_tracking.ml
index e0aacb1c1fe979b7aedba67086228e38f89c2786..ccaa156f127213cbb15761efade516299d97c848 100644
--- a/src/plugins/e-acsl/src/analyses/memory_tracking.ml
+++ b/src/plugins/e-acsl/src/analyses/memory_tracking.ml
@@ -303,7 +303,7 @@ module rec Transfer
   and register_term kf varinfos term = match term.term_node with
     | TLval tlv | TAddrOf tlv | TStartOf tlv ->
       register_term_lval kf varinfos tlv
-    | TCastE(_, t) | Tat(t, _) ->
+    | TCast (_, _, t) | Tat(t, _) ->
       register_term kf varinfos t
     | Tlet(li, t) ->
       if may_alias li then Error.not_yet "let-binding on array or pointer"
@@ -339,7 +339,6 @@ module rec Transfer
     | Tbase_addr _ -> Error.not_yet "\\base_addr"
     | Toffset _ -> Error.not_yet "\\offset"
     | Tblock_length _ -> Error.not_yet "\\block_length"
-    | TLogic_coerce(_, t) -> register_term kf varinfos t
     | TUpdate _ -> Error.not_yet "functional update"
     | Ttypeof _ -> Error.not_yet "typeof"
     | Tempty_set -> Error.not_yet "empty set"
@@ -396,10 +395,10 @@ module rec Transfer
         (* no left-value inside inside: skip for efficiency *)
         Cil.SkipChildren
       | TUnOp _ | TBinOp _ | Ttypeof _ | TSizeOfE _
-      | TLval _ | TAlignOfE _ | TCastE _ | TAddrOf _
+      | TLval _ | TAlignOfE _ | TCast _ | TAddrOf _
       | TStartOf _ | Tapp _ | Tlambda _ | TDataCons _ | Tif _ | Tat _
       | TUpdate _ | Tunion _ | Tinter _
-      | Tcomprehension _ | Trange _ | TLogic_coerce _ ->
+      | Tcomprehension _ | Trange _  ->
         (* potential sub-term inside *)
         Cil.DoChildren
     method !vlogic_label _ = Cil.SkipChildren
diff --git a/src/plugins/e-acsl/src/analyses/typing.ml b/src/plugins/e-acsl/src/analyses/typing.ml
index 00650b57443b805c93c142af63cc2ab0415f8f82..3dbec883bfe28d2c7ae0cf87067016cef93b8dba 100644
--- a/src/plugins/e-acsl/src/analyses/typing.ml
+++ b/src/plugins/e-acsl/src/analyses/typing.ml
@@ -428,7 +428,7 @@ let rec type_term
          order to lower the number of explicit casts *)
       let rec cast_first t1 t2 = match t1.term_node with
         | TLval _ -> false
-        | TLogic_coerce(_, t) -> cast_first t t2
+        | TCast (true, _, t) -> cast_first t t2
         | _ -> true
       in
       let cast_first = cast_first t1 t2 in
@@ -457,7 +457,7 @@ let rec type_term
       ignore (type_term ~use_gmp_opt:true ~ctx:c_int ~profile t2);
       ty
 
-    | TCastE(_, t') ->
+    | TCast (false, Ctype _, t') ->
       (* compute the smallest interval from the whole term [t] *)
       let i = Interval.get_from_profile ~profile t in
       (* nothing more to do: [i] is already more precise than what we could
@@ -466,6 +466,14 @@ let rec type_term
       ignore (type_term ~use_gmp_opt:true ~ctx ~profile t');
       ctx
 
+    | TCast (true, _, t') ->
+      let i = Interval.get_from_profile ~profile t in
+      ignore (type_term ~use_gmp_opt ~arith_operand ?ctx ~profile t');
+      ty_of_interv ~use_gmp_opt i
+    (* TODO (NB) : Maybe can be merged ? *)
+
+    | TCast (false, _,_) -> assert false
+
     | Tif (t1, t2, t3) ->
       let ctx1 =
         mk_ctx ~use_gmp_opt:false c_int (* an int must be generated *)
@@ -479,11 +487,6 @@ let rec type_term
       ignore (type_term ~use_gmp_opt:true ~ctx ~profile t3);
       ctx
 
-    | TLogic_coerce (_, t') ->
-      let i = Interval.get_from_profile ~profile t in
-      ignore (type_term ~use_gmp_opt ~arith_operand ?ctx ~profile t');
-      ty_of_interv ~use_gmp_opt i
-
     | Tat (t, _) ->
       (type_term ~use_gmp_opt ~arith_operand ?ctx ~profile t).ty
 
@@ -534,7 +537,7 @@ let rec type_term
                       the kernel introduces a coercion to integer, so we will
                       always see integer here.*)
                    begin match x.term_node with
-                     |TLogic_coerce _ -> None
+                     | TCast (true,_,_) -> None
                      |_ -> if Options.Gmp_only.get() then Some Gmpz else None
                    end
                  | Lreal -> Some Real
@@ -567,7 +570,7 @@ let rec type_term
                       the kernel introduces a coercion to integer, so we will
                       always see integer here.*)
                    begin match x.term_node with
-                     | TLogic_coerce _ -> None
+                     | TCast (true,_,_) -> None
                      |_ -> if Options.Gmp_only.get() then Some Gmpz else None
                    end
                  | Lreal -> Some Real
diff --git a/src/plugins/e-acsl/src/code_generator/translate_terms.ml b/src/plugins/e-acsl/src/code_generator/translate_terms.ml
index c025a21d2518cdf93c425fb62598490a35fc7275..c8d95953029fac0ba8334315f02d790960fe82d6 100644
--- a/src/plugins/e-acsl/src/code_generator/translate_terms.ml
+++ b/src/plugins/e-acsl/src/code_generator/translate_terms.ml
@@ -473,8 +473,7 @@ and context_insensitive_term_to_exp ~adata ?(inplace=false) kf env t =
         match t.term_node with
         | TConst _ -> "cst_"
         | TLval (TVar { lv_name }, _) -> lv_name ^ "_"
-        | TCastE (_, t) -> term_to_name t
-        | TLogic_coerce (_, t) -> term_to_name t
+        | TCast (_,_, t) -> term_to_name t
         | _ -> ""
       in
       let ctx = Typing.get_number_ty ~logic_env t in
@@ -724,7 +723,7 @@ and context_insensitive_term_to_exp ~adata ?(inplace=false) kf env t =
       | C_float _ | Rational | Real | Nan ->
         assert false
     end
-  | TCastE(ty, t') ->
+  | TCast (false, Ctype ty, t') ->
     let e, adata, env = to_exp ~adata kf env t' in
     let e, env =
       Typed_number.add_cast
@@ -738,7 +737,8 @@ and context_insensitive_term_to_exp ~adata ?(inplace=false) kf env t =
         e
     in
     e, adata, env, Analyses_types.C_number, ""
-  | TLogic_coerce (_, t) -> context_insensitive_term_to_exp ~adata kf env t
+  | TCast (true, _, t) -> context_insensitive_term_to_exp ~adata kf env t
+  | TCast (false, _,_) -> assert false
   | TAddrOf lv ->
     let lv, env, _ = tlval_to_lval kf env lv in
     let e = Cil.mkAddrOf ~loc lv in
diff --git a/src/plugins/e-acsl/src/libraries/misc.ml b/src/plugins/e-acsl/src/libraries/misc.ml
index f7c2936976227b7b12cf90bf734420948c2cbd8a..7b03b13df7d378e548a91f90d82582817b14e24e 100644
--- a/src/plugins/e-acsl/src/libraries/misc.ml
+++ b/src/plugins/e-acsl/src/libraries/misc.ml
@@ -27,7 +27,7 @@ open Cil_types
 (* ************************************************************************** *)
 
 let is_fc_or_compiler_builtin vi =
-  Cil_builtins.is_builtin vi
+  Cil_builtins.has_fc_builtin_attr vi
   ||
   (let prefix_length = 10 (* number of characters in "__builtin_" *) in
    String.length vi.vname > prefix_length
diff --git a/src/plugins/e-acsl/tests/bts/oracle/issue-eacsl-145.res.oracle b/src/plugins/e-acsl/tests/bts/oracle/issue-eacsl-145.res.oracle
index 44a3cdfd58d00b48dd99a2a3a393754880497e23..201d2b2a599aa089c5debb92d71b0fd2e6d33d98 100644
--- a/src/plugins/e-acsl/tests/bts/oracle/issue-eacsl-145.res.oracle
+++ b/src/plugins/e-acsl/tests/bts/oracle/issue-eacsl-145.res.oracle
@@ -18,6 +18,9 @@
 [eva] using specification for function __e_acsl_full_init
 [eva] using specification for function __e_acsl_valid
 [eva] using specification for function __e_acsl_assert_register_ptr
+[eva:garbled-mix:assigns] issue-eacsl-145.c:9: 
+  The specification of function __e_acsl_assert_register_ptr
+  has generated a garbled mix of addresses for assigns clause data->values.
 [eva] using specification for function __e_acsl_assert_register_ulong
 [eva:alarm] issue-eacsl-145.c:9: Warning: 
   function __e_acsl_assert_register_ulong: precondition data->values == \null ||
diff --git a/src/plugins/eva/domains/cvalue/builtins.ml b/src/plugins/eva/domains/cvalue/builtins.ml
index 4dc7cb838a7542869c60076fb8ea28dc82287eb3..b128b35eed8387cf041c595f1438392a8f0bc3e9 100644
--- a/src/plugins/eva/domains/cvalue/builtins.ml
+++ b/src/plugins/eva/domains/cvalue/builtins.ml
@@ -252,6 +252,8 @@ let process_result call state call_result =
     | Some value, Some vi_ret ->
       let b_ret = Base.of_varinfo vi_ret in
       let offsm = Eval_op.offsetmap_of_v ~typ:vi_ret.vtype value in
+      let prefix = "Builtin " ^ Kernel_function.get_name call.kf in
+      Cvalue_transfer.warn_imprecise_offsm_write ~prefix (Cil.var vi_ret) offsm;
       Cvalue.Model.add_base b_ret offsm state, clob
     | _, _ -> state, clob (* TODO: error? *)
   in
diff --git a/src/plugins/eva/domains/cvalue/builtins_memory.ml b/src/plugins/eva/domains/cvalue/builtins_memory.ml
index 9cfa63a0dc9bdeb2a69c7f92614b36e039790f2f..073fc79acf09987e1fd82a7623e58bd1257f3e97 100644
--- a/src/plugins/eva/domains/cvalue/builtins_memory.ml
+++ b/src/plugins/eva/domains/cvalue/builtins_memory.ml
@@ -30,6 +30,12 @@ let register_builtin name ?replace builtin =
 
 let dkey = Self.register_category "imprecision"
 
+let rec lval_of_address exp =
+  match exp.enode with
+  | AddrOf lval -> lval
+  | CastE (_typ, exp) -> lval_of_address exp
+  | _ -> Cil.mkMem ~addr:exp ~off:Cil_types.NoOffset
+
 let frama_C_is_base_aligned _state = function
   | [_, x; _, y] ->
     let result =
@@ -99,8 +105,10 @@ let deps_nth_arg n =
   with Failure _ -> Kernel.fatal "%d arguments expected" n
 
 
-let frama_c_memcpy state actuals =
-  let compute (_exp_dst,dst_bytes) (_exp_src,src_bytes) (_exp_size,size) =
+let frama_c_memcpy name state actuals =
+  let prefix = "Builtin " ^ name in
+  let compute (exp_dst,dst_bytes) (_exp_src,src_bytes) (_exp_size,size) =
+    let dst_lval = lval_of_address exp_dst in
     let plevel = Parameters.ArrayPrecisionLevel.get() in
     let size =
       try Cvalue.V.project_ival size
@@ -132,6 +140,7 @@ let frama_c_memcpy state actuals =
           memcpy_check_indeterminate_offsetmap offsetmap;
           (* Read succeeded. We write the result *)
           let loc_src = make_loc src (Int_Base.inject size_min) in
+          Cvalue_transfer.warn_imprecise_offsm_write ~prefix dst_lval offsetmap;
           let new_state =
             Cvalue.Model.paste_offsetmap
               ~from:offsetmap ~dst_loc:dst_bits ~size:size_min ~exact:true state
@@ -212,6 +221,7 @@ let frama_c_memcpy state actuals =
               raise (Memcpy_result (state,c_from,sure_zone))
             | `Value offsetmap ->
               memcpy_check_indeterminate_offsetmap offsetmap;
+              Cvalue_transfer.warn_imprecise_offsm_write ~prefix dst_lval offsetmap;
               let new_state =
                 Cvalue.Model.paste_offsetmap
                   ~from:offsetmap ~dst_loc:dst ~size:diff ~exact:false state
@@ -247,6 +257,8 @@ let frama_c_memcpy state actuals =
                    "@[In memcpy@ builtin:@ imprecise@ copy of@ indeterminate@ values@]%t"
                    Eva_utils.pp_callstack
         end;
+        let value = Cvalue.V_Or_Uninitialized.get_v v in
+        Cvalue_transfer.warn_imprecise_write ~prefix dst_lval loc_dst value;
         let updated_state =
           Cvalue.Model.add_indeterminate_binding
             ~exact:false new_state loc_dst v
@@ -287,11 +299,13 @@ let frama_c_memcpy state actuals =
   | [dst; src; size] -> compute dst src size
   | _ -> raise (Builtins.Invalid_nb_of_args 3)
 
-let () = register_builtin ~replace:"memcpy" "Frama_C_memcpy" frama_c_memcpy
-let () = register_builtin ~replace:"memmove" "Frama_C_memmove" frama_c_memcpy
+let () =
+  register_builtin ~replace:"memcpy" "Frama_C_memcpy" (frama_c_memcpy "memcpy");
+  register_builtin ~replace:"memmove" "Frama_C_memmove" (frama_c_memcpy "memmove")
 
 (*  Implementation of [memset] that accepts imprecise arguments. *)
-let frama_c_memset_imprecise state dst v size =
+let frama_c_memset_imprecise state dst_lval dst v size =
+  let prefix = "Builtin memset" in
   let size_char = Bit_utils.sizeofchar () in
   let size_min, size_max_bytes =
     try
@@ -317,6 +331,7 @@ let frama_c_memset_imprecise state dst v size =
       let loc = Location_Bytes.shift shift dst in
       let loc = loc_bytes_to_loc_bits loc in
       let loc = make_loc loc (Int_Base.inject size_char) in
+      Cvalue_transfer.warn_imprecise_write ~prefix dst_lval loc v;
       let state = Cvalue.Model.add_binding ~exact:false state loc v in
       (state,enumerate_valid_bits Locations.Write loc)
     else (state,Zone.bottom)
@@ -335,6 +350,7 @@ let frama_c_memset_imprecise state dst v size =
         let left' = Location_Bits.inject base (Ival.inject_singleton maxb) in
         let vuninit = V_Or_Uninitialized.initialized v in
         let from = V_Offsetmap.create ~size:sure vuninit ~size_v:size_char in
+        Cvalue_transfer.warn_imprecise_offsm_write ~prefix dst_lval from;
         let state =
           Cvalue.Model.paste_offsetmap
             ~from ~dst_loc:left' ~size:sure ~exact:true new_state
@@ -521,7 +537,7 @@ let memset_typ_offsm typ v =
 
 (*  Precise memset builtin, that requires its arguments to be sufficiently
     precise abstract values. *)
-let frama_c_memset_precise state dst v (exp_size, size) =
+let frama_c_memset_precise state dst_lval dst v (exp_size, size) =
   try
     let size_char = Bit_utils.sizeofchar () in
     (* We want an exact size, Otherwise, we can use the imprecise memset as a
@@ -571,6 +587,8 @@ let frama_c_memset_precise state dst v (exp_size, size) =
       c_from,dst_zone
     in
     let _ = c_from in
+    let prefix = "Builtin memset" in
+    Cvalue_transfer.warn_imprecise_offsm_write ~prefix dst_lval offsm;
     let state' =
       Cvalue.Model.paste_offsetmap
         ~from:offsm ~dst_loc ~size:size_bits ~exact:true state
@@ -590,24 +608,25 @@ let frama_c_memset_precise state dst v (exp_size, size) =
 
 let frama_c_memset state actuals =
   match actuals with
-  | [(_exp_dst, dst); (_, v); (exp_size, size)] ->
+  | [(exp_dst, dst); (_, v); (exp_size, size)] ->
     begin
+      let dst_lval = lval_of_address exp_dst in
       (* Remove read-only destinations *)
       let dst = V.filter_base (fun b -> not (Base.is_read_only b)) dst in
       (* Keep only the first byte of the value argument *)
       let _, v = Cvalue.V.extract_bits
-          ~topify:Origin.K_Misalign_read
+          ~topify:Origin.Misalign_read
           ~start:Int.zero ~stop:(Int.pred (Bit_utils.sizeofchar ()))
           ~size:(Int.of_int (Cil.bitsSizeOfInt IInt))
           v
       in
-      try frama_c_memset_precise state dst v (exp_size, size)
+      try frama_c_memset_precise state dst_lval dst v (exp_size, size)
       with ImpreciseMemset reason ->
         Self.debug ~dkey ~current:true
           "Call to builtin precise_memset(%a) failed; %a%t"
           Eva_utils.pretty_actuals actuals pretty_imprecise_memset_reason reason
           Eva_utils.pp_callstack;
-        frama_c_memset_imprecise state dst v size
+        frama_c_memset_imprecise state dst_lval dst v size
     end
   | _ -> raise (Builtins.Invalid_nb_of_args 3)
 
diff --git a/src/plugins/eva/domains/cvalue/cvalue_domain.ml b/src/plugins/eva/domains/cvalue/cvalue_domain.ml
index 28d8274aa83aa006de84c4838b1a4092b345c800..43b19bd42586c0c09577be32dd4c1aefe5958e90 100644
--- a/src/plugins/eva/domains/cvalue/cvalue_domain.ml
+++ b/src/plugins/eva/domains/cvalue/cvalue_domain.ml
@@ -148,6 +148,15 @@ module State = struct
       finalize_recursive_call stmt call ~pre:(pre, clob) a post
     in
     let post = Option.fold ~some:finalize ~none:post recursion in
+    (* Deallocate memory allocated via alloca().
+       To minimize computations, only do it for function definitions. *)
+    let post =
+      if Kernel_function.is_definition call.kf then
+        let callstack = Eva_utils.current_call_stack () in
+        let callstack = Callstack.push call.kf stmt callstack in
+        Builtins_malloc.free_automatic_bases callstack post
+      else post
+    in
     Cvalue_transfer.finalize_call stmt call recursion ~pre ~post
     >>-: fun state ->
     state, clob
diff --git a/src/plugins/eva/domains/cvalue/cvalue_init.ml b/src/plugins/eva/domains/cvalue/cvalue_init.ml
index d6b5fc4dc83b90f048cd6dbc2be85148db3168b4..a606eac714e321bfa78df6709fd39685665b7439 100644
--- a/src/plugins/eva/domains/cvalue/cvalue_init.ml
+++ b/src/plugins/eva/domains/cvalue/cvalue_init.ml
@@ -33,7 +33,7 @@ let add_initialized state loc v =
 let make_well hidden_base state loc =
   let size = Bit_utils.max_bit_size () in
   let well =
-    Cvalue.V.inject_top_origin Origin.Well (Base.Hptset.singleton hidden_base)
+    Cvalue.V.inject_top_origin Origin.well (Base.Hptset.singleton hidden_base)
   in
   let well_loc =
     Locations.make_loc
diff --git a/src/plugins/eva/domains/cvalue/cvalue_offsetmap.ml b/src/plugins/eva/domains/cvalue/cvalue_offsetmap.ml
index b025905db610ec025920ff50613359a8e74d733d..b2d0019e28ae7a67b2e5a6e58ccda40dd182d66f 100644
--- a/src/plugins/eva/domains/cvalue/cvalue_offsetmap.ml
+++ b/src/plugins/eva/domains/cvalue/cvalue_offsetmap.ml
@@ -22,35 +22,6 @@
 
 open Eval
 
-exception Got_imprecise of Cvalue.V.t
-let offsetmap_contains_imprecision offs =
-  try
-    Cvalue.V_Offsetmap.iter_on_values
-      (fun v ->
-         match Cvalue.V_Or_Uninitialized.get_v v with
-         | Locations.Location_Bytes.Map _ -> ()
-         | Locations.Location_Bytes.Top _ as v -> raise (Got_imprecise v)
-      ) offs;
-    None
-  with Got_imprecise v -> Some v
-
-let warn_right_imprecision lval loc offsetmap =
-  match offsetmap_contains_imprecision offsetmap with
-  | Some v -> Warn.warn_right_exp_imprecision lval loc v
-  | None -> ()
-
-let warn_if_imprecise lval loc offsm =
-  match offsetmap_contains_imprecision offsm with
-  | Some v ->
-    let loc = Precise_locs.imprecise_location loc in
-    Warn.warn_imprecise_lval_read lval loc v
-  | None -> ()
-
-let offsetmap_of_lval state lval loc =
-  let offsm = Bottom.non_bottom (Eval_op.offsetmap_of_loc loc state) in
-  warn_if_imprecise lval loc offsm;
-  offsm
-
 let offsetmap_of_v ~typ v =
   let size = Integer.of_int (Cil.bitsSizeOf typ) in
   let v = Cvalue.V.anisotropic_cast ~size v in
@@ -58,5 +29,7 @@ let offsetmap_of_v ~typ v =
   Cvalue.V_Offsetmap.create ~size v ~size_v:size
 
 let offsetmap_of_assignment state expr = function
-  | Copy (lv, _value) -> offsetmap_of_lval state lv.lval lv.lloc
-  | Assign value -> offsetmap_of_v ~typ:(Cil.typeOf expr) value
+  | Copy (lv, _value) ->
+    Bottom.non_bottom (Eval_op.offsetmap_of_loc lv.lloc state)
+  | Assign value ->
+    offsetmap_of_v ~typ:(Cil.typeOf expr) value
diff --git a/src/plugins/eva/domains/cvalue/cvalue_offsetmap.mli b/src/plugins/eva/domains/cvalue/cvalue_offsetmap.mli
index 8d6903e821611855a4ff6831055b57186dda3434..8e0119621709ef78e080b02d5a3af3a896e8e94f 100644
--- a/src/plugins/eva/domains/cvalue/cvalue_offsetmap.mli
+++ b/src/plugins/eva/domains/cvalue/cvalue_offsetmap.mli
@@ -25,18 +25,6 @@
 open Cil_types
 open Cvalue
 
-(** [warn_right_imprecision lval loc offsm] is used for the assignment of the
-    lvalue [lval] pointing to the location [loc]; it warns if the offsetmap
-    [offsm] contains a garbled mix. *)
-val warn_right_imprecision:
-  lval -> Locations.location -> V_Offsetmap.t -> unit
-
-(** [offsetmap_of_lval state lval loc] extracts from state [state] the offsetmap
-    at location [loc], corresponding to the lvalue [lval]. Warns if this
-    offsetmap contains a garbled mix. *)
-val offsetmap_of_lval:
-  Model.t -> lval -> Precise_locs.precise_location -> V_Offsetmap.t
-
 (** Computes the offsetmap for an assignment:
     - in case of a copy, extracts the offsetmap from the state;
     - otherwise, translates the value assigned into an offsetmap. *)
diff --git a/src/plugins/eva/domains/cvalue/cvalue_queries.ml b/src/plugins/eva/domains/cvalue/cvalue_queries.ml
index ae31230b0e8ede332ce8a485e99431acb7c51d83..a39492a45942563e4e8cdaaa3368a8812ff5480f 100644
--- a/src/plugins/eva/domains/cvalue/cvalue_queries.ml
+++ b/src/plugins/eva/domains/cvalue/cvalue_queries.ml
@@ -76,6 +76,10 @@ module Queries = struct
   let is_float v =
     Cvalue.V.(is_included v top_float) && Cvalue.V.contains_non_zero v
 
+  let read_garbled_mix = function
+    | Cvalue.V.Top (bases, origin) -> Origin.register_read bases origin
+    | _ -> ()
+
   let extract_scalar_lval state lval typ loc =
     let process_one_loc = eval_one_loc state lval typ in
     let acc = Cvalue.V.bottom, None in
@@ -88,6 +92,7 @@ module Queries = struct
     let incompatible_type = is_float value <> Cil.isFloatingType typ in
     let origin = if incompatible_type then Some value else None in
     let value = Cvalue_forward.reinterpret typ value in
+    read_garbled_mix value;
     if Cvalue.V.is_bottom value
     then `Bottom, alarms
     else `Value (value, origin), alarms
@@ -106,6 +111,7 @@ module Queries = struct
         let value = Cvalue.V_Offsetmap.find_imprecise_everywhere offsm in
         let alarms = indeterminate_alarms lval value in
         let v = Cvalue.V_Or_Uninitialized.get_v value in
+        read_garbled_mix v;
         let v = if Cvalue.V.is_bottom v then `Bottom else `Value (v, None) in
         v, alarms
 
diff --git a/src/plugins/eva/domains/cvalue/cvalue_transfer.ml b/src/plugins/eva/domains/cvalue/cvalue_transfer.ml
index 007674371f657ba8bdca117a649689e86287b3be..bbe73b8013d315befd32c8bdf48195e8a6a8ce61 100644
--- a/src/plugins/eva/domains/cvalue/cvalue_transfer.ml
+++ b/src/plugins/eva/domains/cvalue/cvalue_transfer.ml
@@ -22,7 +22,6 @@
 
 open Cil_types
 open Eval
-open Cvalue.Model
 
 type value = Main_values.CVal.t
 type origin = value
@@ -32,6 +31,40 @@ let unbottomize = function
   | `Bottom -> Cvalue.V.bottom
   | `Value v -> v
 
+(* ---------------------------------------------------------------------- *)
+(*                        Garbled mix warnings                            *)
+(* ---------------------------------------------------------------------- *)
+
+let warn_imprecise_value ?prefix lval value =
+  match value with
+  | Locations.Location_Bytes.Top (bases, origin) ->
+    if Origin.register_write bases origin then
+      let prefix = Option.fold ~none:"A" ~some:(fun s -> s ^ ": a") prefix in
+      Self.warning ~wkey:Self.wkey_garbled_mix_write ~once:true ~current:true
+        "@[%sssigning imprecise value to %a@ because of %s.@]%t"
+        prefix Printer.pp_lval lval (Origin.descr origin)
+        Eva_utils.pp_callstack
+  | _ -> ()
+
+let warn_imprecise_location ?prefix loc =
+  match loc.Locations.loc with
+  | Locations.Location_Bits.Top (Base.SetLattice.Top, orig) ->
+    let prefix = Option.fold ~none:"" ~some:(fun s -> s ^ ": ") prefix in
+    Self.fatal ~current:true
+      "@[%swriting at a completely unknown address@ because of %s.@]@\nAborting."
+      prefix (Origin.descr orig)
+  | _ -> ()
+
+let warn_imprecise_write ?prefix lval loc value =
+  warn_imprecise_location ?prefix loc;
+  warn_imprecise_value ?prefix lval value
+
+let warn_imprecise_offsm_write ?prefix lval offsm =
+  let warn value =
+    warn_imprecise_value ?prefix lval (Cvalue.V_Or_Uninitialized.get_v value)
+  in
+  Cvalue.V_Offsetmap.iter_on_values warn offsm
+
 (* ---------------------------------------------------------------------- *)
 (*                               Assumptions                              *)
 (* ---------------------------------------------------------------------- *)
@@ -45,7 +78,7 @@ let reduce valuation lval value t =
     | `Value record ->
       let loc = Precise_locs.imprecise_location record.loc in
       if Locations.cardinal_zero_or_one loc
-      then reduce_indeterminate_binding t loc value
+      then Cvalue.Model.reduce_indeterminate_binding t loc value
       else t
     | `Top -> t (* Cannot reduce without the location of the lvalue. *)
 
@@ -90,38 +123,26 @@ let update valuation t =
 let write_abstract_value state (lval, loc, typ) assigned_value =
   let {v; initialized; escaping} = assigned_value in
   let value = unbottomize v in
-  Warn.warn_right_exp_imprecision lval loc value;
   let value =
     if Cil.typeHasQualifier "volatile" typ
     then Cvalue_forward.make_volatile value
     else value
   in
-  match loc.Locations.loc with
-  | Locations.Location_Bits.Top (Base.SetLattice.Top, orig) ->
-    Self.result
-      "State before degeneration:@\n======%a@\n======="
-      Cvalue.Model.pretty state;
-    Self.fatal ~current:true
-      "writing at a completely unknown address@[%a@].@\nAborting."
-      Origin.pretty_as_reason orig
-  | _ ->
-    let exact = Locations.cardinal_zero_or_one loc in
-    let value =
-      Cvalue.V_Or_Uninitialized.make ~initialized ~escaping value in
-    (* let value = Cvalue.V_Or_Uninitialized.initialized value in *)
-    add_indeterminate_binding ~exact state loc value
+  warn_imprecise_write lval loc value;
+  let exact = Locations.cardinal_zero_or_one loc in
+  let value = Cvalue.V_Or_Uninitialized.make ~initialized ~escaping value in
+  Cvalue.Model.add_indeterminate_binding ~exact state loc value;
 
 exception Do_assign_imprecise_copy
 
 let copy_one_loc state left_lv right_lv =
   let left_lval, left_loc, left_typ = left_lv
-  and right_lval, right_loc, right_typ = right_lv in
-  (* Warn if right_loc is imprecise *)
-  Warn.warn_imprecise_lval_read right_lval right_loc Cvalue.V.bottom;
+  and _right_lval, right_loc, right_typ = right_lv in
   (* top size is tested before this function is called, in which case
      the imprecise copy mode is used. *)
   let size = Int_Base.project right_loc.Locations.size in
-  let offsetmap = copy_offsetmap right_loc.Locations.loc size state in
+  let right_loc = right_loc.Locations.loc in
+  let offsetmap = Cvalue.Model.copy_offsetmap right_loc size state in
   let make_volatile =
     Cil.typeHasQualifier "volatile" left_typ ||
     Cil.typeHasQualifier "volatile" right_typ
@@ -139,9 +160,9 @@ let copy_one_loc state left_lv right_lv =
     in
     if not (Eval_typ.offsetmap_matches_type left_typ offsetmap) then
       raise Do_assign_imprecise_copy;
-    Cvalue_offsetmap.warn_right_imprecision left_lval left_loc offsetmap;
+    warn_imprecise_offsm_write left_lval offsetmap;
     `Value
-      (paste_offsetmap ~exact:true
+      (Cvalue.Model.paste_offsetmap ~exact:true
          ~from:offsetmap ~dst_loc:left_loc.Locations.loc ~size state)
 
 let make_determinate value =
@@ -164,9 +185,9 @@ let copy_right_lval state left_lv right_lv copied_value =
           and right_lv = right_lv.lval, right_loc, right_lv.ltyp in
           match copy_one_loc state left_lv right_lv with
           | `Bottom -> acc
-          | `Value state -> join acc state
+          | `Value state -> Cvalue.Model.join acc state
         in
-        Precise_locs.fold process right_lv.lloc bottom
+        Precise_locs.fold process right_lv.lloc Cvalue.Model.bottom
       with
         Do_assign_imprecise_copy ->
         write_abstract_value state (lval, loc, typ) copied_value
@@ -183,10 +204,10 @@ let assign _stmt { lval; ltyp; lloc } _expr assigned valuation state =
   in
   let aux_loc loc acc_state =
     let s = assign_one_loc loc in
-    join acc_state s
+    Cvalue.Model.join acc_state s
   in
-  let state = Precise_locs.fold aux_loc lloc bottom in
-  if not (is_reachable state)
+  let state = Precise_locs.fold aux_loc lloc Cvalue.Model.bottom in
+  if not (Cvalue.Model.is_reachable state)
   then `Bottom
   else `Value state
 
@@ -199,6 +220,7 @@ let actualize_formals state arguments =
     let offsm =
       Cvalue_offsetmap.offsetmap_of_assignment state arg.concrete arg.avalue
     in
+    warn_imprecise_offsm_write (Cil.var arg.formal) offsm;
     Cvalue.Model.add_base (Base.of_varinfo arg.formal) offsm state
   in
   List.fold_left treat_one_formal state arguments
@@ -206,26 +228,17 @@ let actualize_formals state arguments =
 let start_call _stmt call _recursion _valuation state =
   `Value (actualize_formals state call.arguments)
 
-let finalize_call stmt call _recursion ~pre:_ ~post:state =
-  (* Deallocate memory allocated via alloca().
-     To minimize computations, only do it for function definitions. *)
-  let state' =
-    if Kernel_function.is_definition call.kf then
-      let callstack = Eva_utils.current_call_stack () in
-      let callstack = Callstack.push call.kf stmt callstack in
-      Builtins_malloc.free_automatic_bases callstack state
-    else state
-  in
-  `Value state'
+let finalize_call _stmt _call _recursion ~pre:_ ~post:state =
+  `Value state
 
 let show_expr valuation state fmt expr =
   match expr.enode with
   | Lval lval | StartOf lval ->
-    let record = match valuation.Abstract_domain.find_loc lval with
-      | `Value record -> record
+    let loc = match valuation.Abstract_domain.find_loc lval with
+      | `Value record -> record.loc
       | `Top -> assert false
     in
-    let offsm = Cvalue_offsetmap.offsetmap_of_lval state lval record.loc in
+    let offsm = Bottom.non_bottom (Eval_op.offsetmap_of_loc loc state) in
     let typ = Cil.typeOfLval lval in
     Eval_op.pretty_offsetmap typ fmt offsm
   | _ -> Format.fprintf fmt "%s" (Unicode.top_string ())
diff --git a/src/plugins/eva/domains/cvalue/cvalue_transfer.mli b/src/plugins/eva/domains/cvalue/cvalue_transfer.mli
index 5b01daee42dfc4630b86ce8ba5fd76ca38c8b8e8..0b16f6a3034fcd4378805815ffe1644c711e8dde 100644
--- a/src/plugins/eva/domains/cvalue/cvalue_transfer.mli
+++ b/src/plugins/eva/domains/cvalue/cvalue_transfer.mli
@@ -32,6 +32,18 @@ include Abstract_domain.Transfer
    and type location := location
    and type origin := origin
 
+(** [warn_imprecise_write lval loc v] emits a warning about the assignment of
+    value [v] into location [loc] if one of them is overly imprecise. [lval] is
+    the assigned lvalue, and [prefix] is an optional prefix to the warning. *)
+val warn_imprecise_write:
+  ?prefix:string -> Cil_types.lval -> Locations.location -> Cvalue.V.t -> unit
+
+(** [warn_imprecise_offsm_write lval offsm] emits a warning about the assignment
+    of offsetmap [offsm] if it contains an overly imprecise value. [lval] is the
+    assigned lvalue, and [prefix] is an optional prefix to the warning. *)
+val warn_imprecise_offsm_write:
+  ?prefix:string -> Cil_types.lval -> Cvalue.V_Offsetmap.t -> unit
+
 (*
 Local Variables:
 compile-command: "make -C ../../../../.."
diff --git a/src/plugins/eva/domains/cvalue/locals_scoping.ml b/src/plugins/eva/domains/cvalue/locals_scoping.ml
index 2e263ae8d1f369514c6351153e9628b3e8b0bc62..afd70681b564287638238667bde0e910b012714f 100644
--- a/src/plugins/eva/domains/cvalue/locals_scoping.ml
+++ b/src/plugins/eva/domains/cvalue/locals_scoping.ml
@@ -54,6 +54,17 @@ let offsetmap_contains_local offm =
   with Exit -> true
 
 
+let warn_locals_escape is_block fundec k locals =
+  let pretty_base = Base.pretty in
+  let pretty_block fmt = Pretty_utils.pp_cond is_block fmt "a block of " in
+  let sv = fundec.svar in
+  Self.warning
+    ~wkey:Self.wkey_locals_escaping
+    ~current:true ~once:true
+    "locals %a escaping the scope of %t%a through %a"
+    Base.Hptset.pretty locals pretty_block Printer.pp_varinfo sv pretty_base k
+
+
 (* Rebuild [offsm] by applying [f] to the bindings that verify [test].
    Also call [warn] in this case. *)
 let rebuild_offsetmap f warn offsm =
@@ -123,7 +134,7 @@ let make_escaping_fundec fundec clob vars state =
         | Base.SetLattice.Top -> escaping
         | Base.SetLattice.Set bases -> Base.Hptset.inter bases escaping
       in
-      Warn.warn_locals_escape is_inner_block fundec b bases
+      warn_locals_escape is_inner_block fundec b bases
     in
     make_escaping ~exact:true ~escaping ~on_escaping ~within:clob.clob state
 
diff --git a/src/plugins/eva/domains/cvalue/warn.ml b/src/plugins/eva/domains/cvalue/warn.ml
deleted file mode 100644
index 3604d914973d55ba0cf412c4b6aee1436ec81f32..0000000000000000000000000000000000000000
--- a/src/plugins/eva/domains/cvalue/warn.ml
+++ /dev/null
@@ -1,125 +0,0 @@
-(**************************************************************************)
-(*                                                                        *)
-(*  This file is part of Frama-C.                                         *)
-(*                                                                        *)
-(*  Copyright (C) 2007-2023                                               *)
-(*    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 Locations
-
-let warn_locals_escape is_block fundec k locals =
-  let pretty_base = Base.pretty in
-  let pretty_block fmt = Pretty_utils.pp_cond is_block fmt "a block of " in
-  let sv = fundec.svar in
-  Self.warning
-    ~wkey:Self.wkey_locals_escaping
-    ~current:true ~once:true
-    "locals %a escaping the scope of %t%a through %a"
-    Base.Hptset.pretty locals pretty_block Printer.pp_varinfo sv pretty_base k
-
-let warn_imprecise_lval_read lv loc contents =
-  if Self.verbose_atleast 1 then
-    let pretty_gm fmt s =
-      let s = Base.SetLattice.(inject (O.remove Base.null s)) in
-      Base.SetLattice.pretty fmt s
-    in
-    let pretty_param fmt param =
-      match param with
-      | Base.SetLattice.Top -> Format.fprintf fmt "is imprecise"
-      | Base.SetLattice.Set s ->
-        Format.fprintf fmt "is a garbled mix of %a" pretty_gm s
-    in
-    let pretty_param_b fmt param =
-      match param with
-      | Base.SetLattice.Top ->
-        Format.fprintf fmt "The contents@ are imprecise"
-      | Base.SetLattice.Set s ->
-        Format.fprintf fmt "It contains@ a garbled@ mix@ of@ %a" pretty_gm s
-    in
-    let something_to_warn =
-      match loc.loc with
-      | Location_Bits.Top _ -> true
-      | Location_Bits.Map _ ->
-        match contents with
-        | Location_Bytes.Top _ -> true
-        | Location_Bytes.Map _ -> false
-    in
-    if something_to_warn
-    then
-      Self.warning ~wkey:Self.wkey_garbled_mix_read ~current:true ~once:true
-        "@[<v>@[Reading left-value %a.@]@ %t%t%t@]"
-        Printer.pp_lval lv
-        (fun fmt ->
-           match loc.loc with
-           | Location_Bits.Top (param,o) when Origin.equal o Origin.top  ->
-             Format.fprintf fmt "@[The location %a.@]@ "
-               pretty_param param
-           | Location_Bits.Top (param,orig) ->
-             Format.fprintf fmt "@[The location @[%a@]@ because of@ %a.@]@ "
-               pretty_param param
-               Origin.pretty orig
-           | Location_Bits.Map _ ->
-             match lv with
-             | Mem _, _ ->
-               Format.fprintf fmt "@[The location is @[%a@].@]@ "
-                 Location_Bits.pretty loc.loc
-             | Var _, _ -> ()
-        )
-        (fun fmt ->
-           match contents with
-           | Location_Bytes.Top (param,o) when Origin.equal o Origin.top ->
-             Format.fprintf fmt "@[%a.@]"
-               pretty_param_b param
-           | Location_Bytes.Top (param,orig) ->
-             Format.fprintf fmt "@[%a@ because of@ %a.@]"
-               pretty_param_b param
-               Origin.pretty orig
-           | Location_Bytes.Map _ -> ())
-        Eva_utils.pp_callstack
-
-(* Auxiliary function for [do_assign] below. When computing the
-   result of [lv = exp], warn if the evaluation of [exp] results in
-   an imprecision. [loc_lv] is the location pointed to by [lv].
-   [exp_val] is the part of the evaluation of [exp] that is imprecise. *)
-let warn_right_exp_imprecision lv loc_lv exp_val =
-  match exp_val with
-  | Location_Bytes.Top(_topparam,origin) ->
-    Self.warning ~wkey:Self.wkey_garbled_mix_write ~once:true ~current:true
-      "@[<v>@[Assigning imprecise value to %a%t.@]%a%t@]"
-      Printer.pp_lval lv
-      (fun fmt -> match lv with
-         | (Mem _, _) ->
-           Format.fprintf fmt "@ (pointing to %a)"
-             (Locations.pretty_english ~prefix:false) loc_lv
-         | (Var _, _) -> ())
-      (fun fmt org ->
-         if not (Origin.is_top origin) then
-           Format.fprintf fmt
-             "@ @[The imprecision@ originates@ from@ %a@]"
-             Origin.pretty org)
-      origin
-      Eva_utils.pp_callstack
-  | Location_Bytes.Map _ -> ()
-
-
-(*
-Local Variables:
-compile-command: "make -C ../../../.."
-End:
-*)
diff --git a/src/plugins/eva/domains/cvalue/warn.mli b/src/plugins/eva/domains/cvalue/warn.mli
deleted file mode 100644
index 2c9664ff6b7d31dbfdb591aed7230ff3788a8247..0000000000000000000000000000000000000000
--- a/src/plugins/eva/domains/cvalue/warn.mli
+++ /dev/null
@@ -1,30 +0,0 @@
-(**************************************************************************)
-(*                                                                        *)
-(*  This file is part of Frama-C.                                         *)
-(*                                                                        *)
-(*  Copyright (C) 2007-2023                                               *)
-(*    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).            *)
-(*                                                                        *)
-(**************************************************************************)
-
-(** Alarms and imprecision warnings emitted during the analysis. *)
-
-open Cil_types
-open Locations
-
-val warn_locals_escape: bool -> fundec -> Base.t -> Base.Hptset.t -> unit
-val warn_imprecise_lval_read: lval -> location -> Location_Bytes.t -> unit
-val warn_right_exp_imprecision: lval -> location -> Cvalue.V.t -> unit
diff --git a/src/plugins/eva/domains/equality/equality_domain.ml b/src/plugins/eva/domains/equality/equality_domain.ml
index 9c7407b2d0138c580d74b96b56252074168718ea..55affa63dc9a97b8759e9139264972c7e574d5c2 100644
--- a/src/plugins/eva/domains/equality/equality_domain.ml
+++ b/src/plugins/eva/domains/equality/equality_domain.ml
@@ -212,7 +212,7 @@ module Make
       fun v ->
         let c = get v in
         if Cvalue.V.is_imprecise c then
-          let c' = Cvalue.V.topify_with_origin Origin.top c in
+          let c' = Cvalue.V.topify_with_origin Origin.unknown c in
           Value.set Main_values.CVal.key c' v
         else v
 
diff --git a/src/plugins/eva/domains/multidim/multidim_domain.ml b/src/plugins/eva/domains/multidim/multidim_domain.ml
index d721e62e638a22343470bb3815108b0e92ad2ec0..c5606b0ebeb8571025778bb05ca5f1fb8434c374 100644
--- a/src/plugins/eva/domains/multidim/multidim_domain.ml
+++ b/src/plugins/eva/domains/multidim/multidim_domain.ml
@@ -75,12 +75,12 @@ struct
   let of_bit ~typ:_ = function
     | Abstract_memory.Uninitialized -> uninitialized
     | Zero i -> make i (V.inject_int Integer.zero)
-    | Any (Top, i) -> make i (V.top_with_origin Origin.top)
+    | Any (Top, i) -> make i (V.top_with_origin Origin.unknown)
     | Any (Set s, i) ->
       let v =
         if Base.Hptset.is_empty s
         then V.inject_ival Ival.top
-        else V.inject_top_origin Origin.top s
+        else V.inject_top_origin Origin.unknown s
       in
       make i v
 
diff --git a/src/plugins/eva/engine/compute_functions.ml b/src/plugins/eva/engine/compute_functions.ml
index 09a3b4d353b06d83d8a5a5c13396a4b28c90765f..88b6280b2e75a83b72bf2a90b23921754ba17269 100644
--- a/src/plugins/eva/engine/compute_functions.ml
+++ b/src/plugins/eva/engine/compute_functions.ml
@@ -101,7 +101,7 @@ let pre_analysis () =
   (* We may be resuming Value from a previously crashed analysis. Clear
      degeneration states *)
   Eva_utils.DegenerationPoints.clear ();
-  Cvalue.V.clear_garbled_mix ();
+  Origin.clear ();
   Eva_utils.clear_call_stack ()
 
 let post_analysis_cleanup ~aborted =
@@ -114,7 +114,7 @@ let post_analysis () =
   (* Garbled mix must be dumped here -- at least before the call to
      mark_green_and_red -- because fresh ones are created when re-evaluating
      all the alarms, and we get an unpleasant "ghost effect". *)
-  Eva_utils.dump_garbled_mix ();
+  Self.warning ~wkey:Self.wkey_garbled_mix_summary "%t" Origin.pretty_history;
   (* Mark unreachable and RTE statuses. Only do this there, not when the
      analysis was aborted (hence, not in post_cleanup), because the
      propagation is incomplete. Also do not mark unreachable statutes if
@@ -303,13 +303,9 @@ module Make (Abstract: Abstractions.S_with_evaluation) = struct
       Self.feedback ~current:true "Call to builtin %s%s"
         name (if kf_name = name then "" else " for function " ^ kf_name);
     apply_call_hooks call state `Builtin;
-    (* Do not track garbled mixes created when interpreting the specification,
-       as the result of the cvalue builtin will overwrite them. *)
-    Locations.Location_Bytes.do_track_garbled_mix false;
     let states =
       Spec.compute_using_specification ~warn:false kinstr call spec state
     in
-    Locations.Location_Bytes.do_track_garbled_mix true;
     let final_state = join_states states in
     match final_state with
     | `Bottom ->
diff --git a/src/plugins/eva/engine/function_calls.ml b/src/plugins/eva/engine/function_calls.ml
index ee88bbdc58569980f49e7cbca5c5c539ca06cdeb..5b8cd029a76e9302b0b46e434645ee209704b11d 100644
--- a/src/plugins/eva/engine/function_calls.ml
+++ b/src/plugins/eva/engine/function_calls.ml
@@ -146,7 +146,7 @@ let analysis_status kf =
 
 (* Must be consistent with the choice made by [analysis_target] below. *)
 let use_spec_instead_of_definition ?(recursion_depth = -1) kf =
-  Ast_info.is_frama_c_builtin (Kernel_function.get_name kf) ||
+  Ast_info.start_with_frama_c_builtin (Kernel_function.get_name kf) ||
   Builtins.is_builtin_overridden kf ||
   recursion_depth >= Parameters.RecursiveUnroll.get () ||
   not (Kernel_function.is_definition kf) ||
diff --git a/src/plugins/eva/engine/transfer_specification.ml b/src/plugins/eva/engine/transfer_specification.ml
index bd0b649c6bdaa5c7d80f0a64e713d08caf666c63..c0520b22fcdeefcc45e9882f89f38bb43780267b 100644
--- a/src/plugins/eva/engine/transfer_specification.ml
+++ b/src/plugins/eva/engine/transfer_specification.ml
@@ -306,21 +306,25 @@ module Make
     let env = make_env pre in
     let assigns = get_assigns_for_behavior spec behavior in
     let check_one_assign cvalue_state (assign, _) =
-      match evaluate_location env retres_loc Assign assign with
-      | None -> ()
-      | Some location ->
-        let loc = Precise_locs.imprecise_location (get_ploc location) in
-        let cvalue = Cvalue.Model.find cvalue_state loc in
-        if Cvalue.V.is_imprecise cvalue
-        then
-          begin
-            ignore (Locations.Location_Bytes.track_garbled_mix cvalue);
-            Self.warning ~current:true ~once:true
-              ~wkey:Self.wkey_garbled_mix_assigns
-              "The specification of function %a has generated a garbled mix \
-               for %a."
-              Kernel_function.pretty kf pp_assign_clause (Assign, assign)
-          end
+      let location = evaluate_location env retres_loc Assign assign in
+      let precise_loc = Option.map get_ploc location in
+      let loc = Option.map Precise_locs.imprecise_location precise_loc in
+      match loc with
+      | None | Some Locations.{ size = Top } -> ()
+      | Some Locations.{ loc; size = Value size } ->
+        let offsm = Cvalue.Model.copy_offsetmap loc size cvalue_state in
+        let warn v =
+          match Cvalue.V_Or_Uninitialized.get_v v with
+          | Top (bases, origin) ->
+            if Origin.register_write bases origin then
+              Self.warning ~current:true ~once:true
+                ~wkey:Self.wkey_garbled_mix_assigns
+                "@[The specification of function %a@ has generated \
+                 a garbled mix of addresses@ for %a.@]"
+                Kernel_function.pretty kf pp_assign_clause (Assign, assign)
+          | _ -> ()
+        in
+        Bottom.iter (Cvalue.V_Offsetmap.iter_on_values warn) offsm
     in
     let check_one_state state =
       let cvalue_state = get_cvalue_or_top state in
@@ -335,7 +339,6 @@ module Make
      and [status] the status of the behaviors. *)
   let compute_effects ~warn kf spec result behaviors status states =
     States.join states >>- fun pre_state ->
-    Locations.Location_Bytes.do_track_garbled_mix false;
     let behavior = List.hd behaviors in
     let retres_loc = Option.map Location.eval_varinfo result in
     let assigns = get_assigns_for_behavior spec behavior in
@@ -353,7 +356,6 @@ module Make
     (* Warn on garbled mixes created by specifications, except on builtins. *)
     if warn
     then check_post_assigns kf retres_loc spec behavior ~pre:pre_state states;
-    Locations.Location_Bytes.do_track_garbled_mix true;
     states
 
   (* Reduces the [states] by the assumes and requires clauses of the [behavior]
diff --git a/src/plugins/eva/engine/transfer_stmt.ml b/src/plugins/eva/engine/transfer_stmt.ml
index 13a12c2e3005871a3047ab6bcc774d8d3c1ae1a4..34a7b67ef1f8590dd7a6a5ea37dc447b8ca7104e 100644
--- a/src/plugins/eva/engine/transfer_stmt.ml
+++ b/src/plugins/eva/engine/transfer_stmt.ml
@@ -85,7 +85,7 @@ let do_copy_at = function
 let is_determinate kf =
   let name = Kernel_function.get_name kf in
   (warn_indeterminate kf || Function_calls.use_spec_instead_of_definition kf)
-  && not (Ast_info.is_frama_c_builtin name)
+  && not (Ast_info.start_with_frama_c_builtin name)
 
 let subdivide_stmt = Eva_utils.get_subdivision
 
@@ -189,13 +189,8 @@ module Make (Abstract: Abstractions.S_with_evaluation) = struct
 
   (* Assignment by copying the value of a right lvalue. *)
   let assign_by_copy ~subdivnb state valuation lval lloc ltyp =
-    (* This code about garbled mix is specific to the Cvalue domain.
-       Unfortunately, the current API for abstract_domain does not permit
-       distinguishing between an evaluation or a copy. *)
-    Locations.Location_Bytes.do_track_garbled_mix false;
-    let r = copy_lvalue_and_check ~valuation ~subdivnb state lval in
-    Locations.Location_Bytes.do_track_garbled_mix true;
-    r >>=: fun (valuation, value) ->
+    copy_lvalue_and_check ~valuation ~subdivnb state lval
+    >>=: fun (valuation, value) ->
     Copy ({lval; lloc; ltyp}, value), valuation
 
   (* For an initialization, use for_writing:false for the evaluation of
@@ -713,15 +708,15 @@ module Make (Abstract: Abstractions.S_with_evaluation) = struct
   (** Applies the show_each or dump_each directives. *)
   let apply_special_directives ~subdivnb kf arguments state =
     let name = Kernel_function.get_name kf in
-    if Ast_info.can_be_cea_function name
+    if Ast_info.start_with_frama_c name
     then
-      if Ast_info.is_cea_function name
+      if Ast_info.is_show_each_builtin name
       then (show_each ~subdivnb name arguments state; true)
-      else if Ast_info.is_cea_domain_function name
+      else if Ast_info.is_domain_show_each_builtin name
       then (domain_show_each ~subdivnb name arguments state; true)
-      else if Ast_info.is_cea_dump_file_function name
+      else if Ast_info.is_dump_file_builtin name
       then (dump_state_file ~subdivnb name arguments state; true)
-      else if Ast_info.is_cea_dump_function name
+      else if Ast_info.is_dump_each_builtin name
       then (dump_state name state; true)
       else false
     else false
diff --git a/src/plugins/eva/legacy/eval_terms.ml b/src/plugins/eva/legacy/eval_terms.ml
index 6f7b8fe7f10a96f00f209706d8e1a3bf1a47cc0a..709c0be21386ffd30db98ada627b86de4ffa5828 100644
--- a/src/plugins/eva/legacy/eval_terms.ml
+++ b/src/plugins/eva/legacy/eval_terms.ml
@@ -604,9 +604,9 @@ let pass_logic_cast exn typ trm =
 
 let is_same_term_coerce t1 t2 =
   match t1.term_node, t2.term_node with
-  | TLogic_coerce _, TLogic_coerce _ -> Logic_utils.is_same_term t1 t2
-  | TLogic_coerce (_,t1), _ -> Logic_utils.is_same_term t1 t2
-  | _, TLogic_coerce(_,t2) -> Logic_utils.is_same_term t1 t2
+  | TCast (true,_,_), TCast (true,_,_) -> Logic_utils.is_same_term t1 t2
+  | TCast (true, _,t1), _ -> Logic_utils.is_same_term t1 t2
+  | _, TCast (true, _,t2) -> Logic_utils.is_same_term t1 t2
   | _ -> Logic_utils.is_same_term t1 t2
 
 (* Constrain the ACSL range [idx] when it is used to access an array of
@@ -1142,7 +1142,7 @@ let rec eval_term ~alarm_mode env t =
       etype = Cil.intType;
       eunder; eover; empty; }
 
-  | TCastE (typ, t) ->
+  | TCast (false, Ctype typ, t) ->
     let r = eval_term ~alarm_mode env t in
     (* See if the cast does something. If not, we can keep eunder as is.*)
     if is_noop_cast ~src_typ:t.term_type ~dst_typ:typ
@@ -1153,6 +1153,36 @@ let rec eval_term ~alarm_mode env t =
       let eover = cast ~src_typ:r.etype ~dst_typ:typ r.eover in
       { etype = typ; ldeps = r.ldeps; eunder = under_from_over eover; eover;
         empty = r.empty; }
+  | TCast (false, _,_) -> assert false
+
+  | TCast (true, ltyp, t) ->
+    let r = eval_term ~alarm_mode env t in
+    (* we must handle coercion from singleton to set, for which there is
+       nothing to do, AND coercion from an integer type to a floating-point
+       type, that require a conversion. *)
+    (match Logic_const.plain_or_set Fun.id ltyp with
+     | Linteger when Logic_typing.is_integral_type t.term_type
+                  || Logic_const.is_boolean_type t.term_type -> r
+     | Ctype typ when Cil.isIntegralOrPointerType typ -> r
+     | Lreal ->
+       let eover =
+         if Logic_typing.is_integral_type t.term_type
+         then V.cast_int_to_float Fval.Real r.eover
+         else V.cast_float_to_float Fval.Real r.eover
+       in
+       { etype = Cil.longDoubleType; (* hack until logic type *)
+         ldeps = r.ldeps;
+         eover; eunder = under_from_over eover;
+         empty = r.empty }
+     | _ ->
+       if Logic_const.is_boolean_type ltyp
+       && Logic_typing.is_integral_type t.term_type
+       then cast_to_bool r
+       else
+         unsupported
+           (Format.asprintf "logic coercion %a -> %a@."
+              Printer.pp_logic_type t.term_type Printer.pp_logic_type ltyp)
+    )
 
   | Tif (tcond, ttrue, tfalse) ->
     eval_tif eval_term Cvalue.V.join Cvalue.V.meet ~alarm_mode env
@@ -1193,35 +1223,6 @@ let rec eval_term ~alarm_mode env t =
       eover = Cvalue.V.singleton_zero;
       empty = false; }
 
-  | TLogic_coerce(ltyp, t) ->
-    let r = eval_term ~alarm_mode env t in
-    (* we must handle coercion from singleton to set, for which there is
-       nothing to do, AND coercion from an integer type to a floating-point
-       type, that require a conversion. *)
-    (match Logic_const.plain_or_set Fun.id ltyp with
-     | Linteger when Logic_typing.is_integral_type t.term_type
-                  || Logic_const.is_boolean_type t.term_type -> r
-     | Ctype typ when Cil.isIntegralOrPointerType typ -> r
-     | Lreal ->
-       let eover =
-         if Logic_typing.is_integral_type t.term_type
-         then V.cast_int_to_float Fval.Real r.eover
-         else V.cast_float_to_float Fval.Real r.eover
-       in
-       { etype = Cil.longDoubleType; (* hack until logic type *)
-         ldeps = r.ldeps;
-         eover; eunder = under_from_over eover;
-         empty = r.empty }
-     | _ ->
-       if Logic_const.is_boolean_type ltyp
-       && Logic_typing.is_integral_type t.term_type
-       then cast_to_bool r
-       else
-         unsupported
-           (Format.asprintf "logic coercion %a -> %a@."
-              Printer.pp_logic_type t.term_type Printer.pp_logic_type ltyp)
-    )
-
   (* TODO: the meaning of the label in \offset and \base_addr is not obvious
      at all *)
   | Toffset (_lbl, t) ->
@@ -1781,7 +1782,7 @@ and eval_term_as_lval ~alarm_mode env t =
   | Tat (t, lab) ->
     ignore (env_state env lab);
     eval_term_as_lval ~alarm_mode { env with e_cur = lab } t
-  | TLogic_coerce (_lt, t) ->
+  | TCast (true, _lt, t) ->
     (* Logic coerce on locations (that are pointers) can only introduce
        sets, that do not change the abstract value. *)
     eval_term_as_lval ~alarm_mode env t
@@ -1816,7 +1817,7 @@ and eval_term_as_exact_locs ~alarm_mode env t =
     if Locations.is_bottom_loc loc then raise Not_an_exact_loc;
     Location (typ, loc)
 
-  | TLogic_coerce (Lreal, t) -> begin
+  | TCast (true, Lreal, t) -> begin
       match eval_term_as_exact_locs ~alarm_mode env t with
       | Logic_var _ as x -> x
       | Location (_, locs) as r ->
@@ -1841,13 +1842,13 @@ and eval_term_as_exact_locs ~alarm_mode env t =
         r
     end
 
-  | TLogic_coerce (_, t) ->
-    (* Otherwise it is always ok to pass through a TLogic_coerce, as the destination
+  | TCast (true, _, t) ->
+    (* Otherwise it is always ok to pass through a TCast (true,_,_), as the destination
        type is always a supertype *)
     eval_term_as_exact_locs ~alarm_mode env t
 
-  | TCastE (ctype, t') ->
-    pass_logic_cast Not_an_exact_loc (Ctype ctype) t';
+  | TCast (false, ctype, t') ->
+    pass_logic_cast Not_an_exact_loc ctype t';
     eval_term_as_exact_locs ~alarm_mode env t'
 
   | Tunion [t] ->
@@ -1947,7 +1948,7 @@ and reduce_by_valid env positive access (tset: term) =
 
     | TLval tlval -> aux_lval tlval env
 
-    | TCastE (typ, {term_node = TLval tlval}) -> aux_lval ~typ tlval env
+    | TCast (false, Ctype typ, {term_node = TLval tlval}) -> aux_lval ~typ tlval env
 
     | TAddrOf (TMem {term_node = TLval tlval}, offs) ->
       (try
diff --git a/src/plugins/eva/partitioning/auto_loop_unroll.ml b/src/plugins/eva/partitioning/auto_loop_unroll.ml
index 58b52807752271e0a9c58bb69d832deeb6f78844..fca0c44ebc07734543e871f4d45fa8be744cf173 100644
--- a/src/plugins/eva/partitioning/auto_loop_unroll.ml
+++ b/src/plugins/eva/partitioning/auto_loop_unroll.ml
@@ -177,7 +177,7 @@ let add_written_var vi effect =
 
 let is_frama_c_builtin exp =
   match exp.enode with
-  | Lval (Var vi, NoOffset) -> Ast_info.is_frama_c_builtin vi.vname
+  | Lval (Var vi, NoOffset) -> Ast_info.start_with_frama_c_builtin vi.vname
   | _ -> false
 
 let compute_instr_effect effect = function
diff --git a/src/plugins/eva/self.ml b/src/plugins/eva/self.ml
index cfe1067963566392dca48328322c3eda7545609a..d1c33a8a5ee375b35ac4c016138ba4181b58cfd3 100644
--- a/src/plugins/eva/self.ml
+++ b/src/plugins/eva/self.ml
@@ -93,14 +93,12 @@ let () =
 (* Warning categories. *)
 let wkey_alarm = register_warn_category "alarm"
 let wkey_locals_escaping = register_warn_category "locals-escaping"
-let wkey_garbled_mix_read = register_warn_category "garbled-mix:read"
-let () = set_warn_status wkey_garbled_mix_read Log.Wfeedback
 let wkey_garbled_mix_write = register_warn_category "garbled-mix:write"
 let () = set_warn_status wkey_garbled_mix_write Log.Wfeedback
 let wkey_garbled_mix_assigns = register_warn_category "garbled-mix:assigns"
-let () = set_warn_status wkey_garbled_mix_assigns Log.Winactive
+let () = set_warn_status wkey_garbled_mix_assigns Log.Wfeedback
 let wkey_garbled_mix_summary = register_warn_category "garbled-mix:summary"
-let () = set_warn_status wkey_garbled_mix_summary Log.Winactive
+let () = set_warn_status wkey_garbled_mix_summary Log.Wfeedback
 let wkey_builtins_missing_spec = register_warn_category "builtins:missing-spec"
 let wkey_builtins_override = register_warn_category "builtins:override"
 let wkey_libc_unsupported_spec = register_warn_category "libc:unsupported-spec"
diff --git a/src/plugins/eva/self.mli b/src/plugins/eva/self.mli
index 3ff073a5baab3e01b761681f798d13ddafd4d9ab..c5d22caedb189e077fdff74d9d18bd70de0b950f 100644
--- a/src/plugins/eva/self.mli
+++ b/src/plugins/eva/self.mli
@@ -56,7 +56,6 @@ val dkey_recursion : category
 
 val wkey_alarm: warn_category
 val wkey_locals_escaping: warn_category
-val wkey_garbled_mix_read: warn_category
 val wkey_garbled_mix_write: warn_category
 val wkey_garbled_mix_assigns: warn_category
 val wkey_garbled_mix_summary: warn_category
diff --git a/src/plugins/eva/utils/eva_utils.ml b/src/plugins/eva/utils/eva_utils.ml
index 73d1517b788b01dac7dfa5f7aeb7e0c589e5bb6c..e1a9d043fec882e18870b54ba124cdf87ce62943 100644
--- a/src/plugins/eva/utils/eva_utils.ml
+++ b/src/plugins/eva/utils/eva_utils.ml
@@ -285,16 +285,6 @@ let lval_to_exp =
   MemoLvalToExp.memo
     (fun lv -> Cil.new_exp ~loc:Cil_datatype.Location.unknown (Lval lv))
 
-let dump_garbled_mix () =
-  let l = Cvalue.V.get_garbled_mix () in
-  if l <> [] then
-    let pp_one fmt v = Format.fprintf fmt "@[<hov 2>%a@]" Cvalue.V.pretty v in
-    Self.warning ~wkey:Self.wkey_garbled_mix_summary
-      "Garbled mix generated during analysis:@.\
-       @[<v>%a@]"
-      (Pretty_utils.pp_list ~pre:"" ~suf:"" ~sep:"@ " pp_one) l
-
-
 type deps = Function_Froms.Deps.deps = {
   data: Locations.Zone.t;
   indirect: Locations.Zone.t;
diff --git a/src/plugins/eva/utils/eva_utils.mli b/src/plugins/eva/utils/eva_utils.mli
index 2e3ab131c5c85d921a2eecf7bc1d6fa42912b002..b7c7a84512a3e487546f175d94229b679fcb82b7 100644
--- a/src/plugins/eva/utils/eva_utils.mli
+++ b/src/plugins/eva/utils/eva_utils.mli
@@ -112,9 +112,6 @@ val is_value_zero: exp -> bool
 val lval_to_exp: lval -> exp
 (** This function is memoized to avoid creating too many expressions *)
 
-val dump_garbled_mix: unit -> unit
-(** print information on the garbled mix created during evaluation *)
-
 
 (** Dependences of expressions and lvalues. *)
 
diff --git a/src/plugins/eva/utils/summary.ml b/src/plugins/eva/utils/summary.ml
index b168b19625124b901ddcf2b86c184e9d0ee1c13f..6982ec1bfeef2b3ad812871677fbe05e8d79fc86 100644
--- a/src/plugins/eva/utils/summary.ml
+++ b/src/plugins/eva/utils/summary.ml
@@ -225,9 +225,7 @@ end
 
 let consider_function vi =
   vi.Cil_types.vdefined &&
-  not (Cil_builtins.is_builtin vi
-       || Cil_builtins.is_special_builtin vi.vname
-       || Cil.is_in_libc vi.vattr)
+  not (Cil_builtins.is_builtin vi || Cil.is_in_libc vi.vattr)
 
 let compute_events () =
   let eva = Events.make () and kernel = Events.make () in
diff --git a/src/plugins/from/from_compute.ml b/src/plugins/from/from_compute.ml
index 4060d0d518378c27d35ebfd9724579e3e3f6354a..4c662872580ba2732f0583f403dda70ffe646c7a 100644
--- a/src/plugins/from/from_compute.ml
+++ b/src/plugins/from/from_compute.ml
@@ -346,7 +346,7 @@ struct
       let states_with_formals = ref [] in
       let do_on kf =
         let called_vinfo = Kernel_function.get_vi kf in
-        if Ast_info.is_frama_c_builtin called_vinfo.vname then
+        if Ast_info.start_with_frama_c_builtin called_vinfo.vname then
           state
         else
           let froms_call = To_Use.get_from_call kf stmt in
diff --git a/src/plugins/gui/property_navigator.ml b/src/plugins/gui/property_navigator.ml
index 3f874465f59b47884281ad734ce6e00f19b98259..a873fdbf6f894e4b03faea6bdaded41d0c61d0da 100644
--- a/src/plugins/gui/property_navigator.ml
+++ b/src/plugins/gui/property_navigator.ml
@@ -43,7 +43,7 @@ let all_properties () =
        match Property.get_kf ip with
        | None -> globals := Property.Set.add ip !globals
        | Some kf ->
-         if not (Ast_info.is_frama_c_builtin (Kernel_function.get_name kf))
+         if not (Ast_info.start_with_frama_c_builtin (Kernel_function.get_name kf))
          then try
              let fips = Kernel_function.Map.find kf !functions in
              fips := Property.Set.add ip !fips
diff --git a/src/plugins/metrics/metrics_base.ml b/src/plugins/metrics/metrics_base.ml
index b20821d6b8dfc2fbdccfbd0c2ecfa44a9f66d9df..777bce0fd9b012002a2b9da61bb378a01dad7207 100644
--- a/src/plugins/metrics/metrics_base.ml
+++ b/src/plugins/metrics/metrics_base.ml
@@ -367,7 +367,7 @@ let get_filename fdef =
 
 let consider_function ~libc vinfo =
   not (Eva.Builtins.is_builtin vinfo.vname
-       || Ast_info.is_frama_c_builtin vinfo.vname
+       || Ast_info.start_with_frama_c_builtin vinfo.vname
        || Cil_builtins.is_unused_builtin vinfo
       ) && (libc || not (Cil.is_in_libc vinfo.vattr))
 
diff --git a/src/plugins/obfuscator/obfuscate.ml b/src/plugins/obfuscator/obfuscate.ml
index 777b2cfc05de6807ce65cbb9c2cf59d58de36fa2..fba8a49e215abae7019981c079bb1fca1763026a 100644
--- a/src/plugins/obfuscator/obfuscate.ml
+++ b/src/plugins/obfuscator/obfuscate.ml
@@ -102,7 +102,6 @@ class visitor = object
       if Cil.isFunctionType vi.vtype then begin
         if vi.vname <> "main"
         && not (Cil_builtins.is_builtin vi)
-        && not (Cil_builtins.is_special_builtin vi.vname)
         && not (Cil.is_in_libc vi.vattr) then
           vi.vname <- Dictionary.fresh Obfuscator_kind.Function vi.vname
       end
diff --git a/src/plugins/report/scan.ml b/src/plugins/report/scan.ml
index 522d3376dddb4c87dfd1fcf7be3625996a5b3c4c..e7c28026e6a13de377f8e617906f036c57b8399a 100644
--- a/src/plugins/report/scan.ml
+++ b/src/plugins/report/scan.ml
@@ -126,7 +126,7 @@ let iter (inspector:inspector) =
          match Property.get_kf ip with
          | None -> globals := Property.Set.add ip !globals
          | Some kf ->
-           if not (Ast_info.is_frama_c_builtin (Kernel_function.get_name kf))
+           if not (Ast_info.start_with_frama_c_builtin (Kernel_function.get_name kf))
            then try
                let fips = Kernel_function.Map.find kf !functions in
                fips := Property.Set.add ip !fips
diff --git a/src/plugins/rte/visit.ml b/src/plugins/rte/visit.ml
index 02f8d10d536283f588b0daca43e8f97a0aa45050..c92bf683b585155d67ef88c99292989ecde548e7 100644
--- a/src/plugins/rte/visit.ml
+++ b/src/plugins/rte/visit.ml
@@ -170,7 +170,7 @@ class annot_visitor kf flags on_alarm = object (self)
         match funcexp.enode with
         | Lval (Var vinfo, NoOffset) ->
           let kf = Globals.Functions.get vinfo in
-          let frama_b = Ast_info.is_frama_c_builtin (Kernel_function.get_name kf)
+          let frama_b = Ast_info.start_with_frama_c_builtin (Kernel_function.get_name kf)
           in
           let va_start = Kernel_function.get_name kf = "__builtin_va_start" in
           (frama_b, va_start)
diff --git a/src/plugins/server/kernel_ast.ml b/src/plugins/server/kernel_ast.ml
index 46a17d9e1422e7e5d1569cf3da7cf30b5291bd8f..5e9c740f8e09959a733ce577ef7665e949604caf 100644
--- a/src/plugins/server/kernel_ast.ml
+++ b/src/plugins/server/kernel_ast.ml
@@ -608,7 +608,7 @@ struct
       if not libc then Kernel.PrintLibc.set false ; raise err
 
   let is_builtin kf =
-    Cil_builtins.is_builtin (Kernel_function.get_vi kf)
+    Cil_builtins.has_fc_builtin_attr (Kernel_function.get_vi kf)
 
   let is_extern kf =
     let vi = Kernel_function.get_vi kf in
@@ -618,7 +618,7 @@ struct
     Globals.Functions.iter
       (fun kf ->
          let name = Kernel_function.get_name kf in
-         if not (Ast_info.is_frama_c_builtin name) then f kf)
+         if not (Ast_info.start_with_frama_c_builtin name) then f kf)
 
   let array : kernel_function States.array =
     begin
diff --git a/src/plugins/server/kernel_properties.ml b/src/plugins/server/kernel_properties.ml
index 57d3d0305f4bfaa0aaf686adb88ccdae1f3d18ba..b7e821e4906a83172ef293c0de6fd5a6b36723eb 100644
--- a/src/plugins/server/kernel_properties.ml
+++ b/src/plugins/server/kernel_properties.ml
@@ -308,7 +308,7 @@ let is_relevant ip =
   match Property.get_kf ip with
   | None -> true
   | Some kf ->
-    not (Ast_info.is_frama_c_builtin (Kernel_function.get_name kf)
+    not (Ast_info.start_with_frama_c_builtin (Kernel_function.get_name kf)
          || Cil_builtins.is_unused_builtin (Kernel_function.get_vi kf))
 
 let iter f =
diff --git a/src/plugins/variadic/classify.ml b/src/plugins/variadic/classify.ml
index 32d4c8c2c3690afd523cc768515874f2ba7813f3..7717ee908379ed0e830a06ec4b92ec6be8d108d2 100644
--- a/src/plugins/variadic/classify.ml
+++ b/src/plugins/variadic/classify.ml
@@ -111,7 +111,7 @@ let mk_format_fun vi f_kind f_buffer ~format_pos =
 (* ************************************************************************ *)
 
 let is_frama_c_builtin name =
-  Ast_info.is_frama_c_builtin name ||
+  Ast_info.start_with_frama_c_builtin name ||
   Cil_builtins.Builtin_functions.mem name ||
   String.starts_with ~prefix:"__FRAMAC_" name (* Mthread prefixes *)
 
diff --git a/src/plugins/variadic/environment.ml b/src/plugins/variadic/environment.ml
index 77cbd5aa164e25b86baa964fd344662d60f772d2..e561d19a840790e654362ed126dcde9c1018556b 100644
--- a/src/plugins/variadic/environment.ml
+++ b/src/plugins/variadic/environment.ml
@@ -90,6 +90,12 @@ let find_type (env : t) (namespace : Logic_typing.type_namespace)
   | Logic_typing.Enum ->
     TEnum (find_enum env tname, [])
 
+let mem_global (env : t) (vname : string) : bool =
+  Table.mem env.globals vname
+
+let mem_function (env : t) (vname : string) : bool =
+  Table.mem env.functions vname
+
 let from_file (file : file) : t =
   let env = empty () in
   let v = object inherit Cil.nopCilVisitor
diff --git a/src/plugins/variadic/environment.mli b/src/plugins/variadic/environment.mli
index 9163b7b16cd5b49637fd03b67f358667a0a92c28..d8e54a24f77c9bf0ff48d574824ef0823fa820d1 100644
--- a/src/plugins/variadic/environment.mli
+++ b/src/plugins/variadic/environment.mli
@@ -34,3 +34,6 @@ val find_struct : t -> string ->  Cil_types.compinfo
 val find_union : t -> string ->  Cil_types.compinfo
 val find_enum : t -> string ->  Cil_types.enuminfo
 val find_type : t -> Logic_typing.type_namespace -> string -> Cil_types.typ
+
+val mem_global : t -> string -> bool
+val mem_function : t -> string -> bool
diff --git a/src/plugins/variadic/format_typer.ml b/src/plugins/variadic/format_typer.ml
index 3a9fc3992f390b99b136003d8e2a044830ef2e9c..d5f60a7ee7853b0f8da0754a4bc6158f9fb59d49 100644
--- a/src/plugins/variadic/format_typer.ml
+++ b/src/plugins/variadic/format_typer.ml
@@ -65,7 +65,7 @@ let type_f_specifier ?find_typedef spec =
   | #float_specifier, Some `l -> Cil.doubleType
   | #float_specifier, Some `L -> Cil.longDoubleType
   | `c, None    -> Cil.intType
-  | `c, Some `l -> get_typedef ?find_typedef "intmax_t"
+  | `c, Some `l -> get_typedef ?find_typedef "wint_t"
   | `s, None    -> Cil.charPtrType
   | `s, Some `l -> ptr (get_typedef ?find_typedef "wchar_t")
   | `p, None    -> Cil.voidPtrType
diff --git a/src/plugins/variadic/standard.ml b/src/plugins/variadic/standard.ml
index 98eefe0444d8a2b8313c137f22f55668bff17537..366a587f94f596452fb982aca1898b06d3db61ba 100644
--- a/src/plugins/variadic/standard.ml
+++ b/src/plugins/variadic/standard.ml
@@ -173,23 +173,34 @@ let match_call ~builder new_callee new_tparams args =
   Build.(List.iter pure (of_exp_list unused_args));
   Build.(translated_call (var new_callee) (of_exp_list new_args))
 
+
+let check_available_name env name =
+  not @@ Environment.mem_global env name
+  && not @@ Environment.mem_function env name
+
+let get_next_name env id name =
+  let rec aux id =
+    let next_name = name ^ (string_of_int id) in
+    if check_available_name env next_name then
+      next_name, id
+    else
+      aux (id + 1)
+  in
+  aux id
+
 (* ************************************************************************ *)
 (* Fallback calls                                                           *)
 (* ************************************************************************ *)
 
-let fallback_fun_call ~builder ~callee vf args =
+let fallback_fun_call ~builder ~callee env vf args =
   let module Build = (val builder : Builder.S) in
 
   (* Choose function name *)
   let name = callee.vname in
   let vorig_name = callee.vorig_name in
-  let count =
-    try Fallback_counts.find name
-    with Not_found -> 0
-  in
-  let count = count + 1 in
-  Fallback_counts.replace name count;
-  let new_name = name ^ "_fallback_" ^ (string_of_int count) in
+  let count = try Fallback_counts.find name + 1 with Not_found -> 1 in
+  let new_name, new_count = get_next_name env count (name ^ "_fallback_") in
+  Fallback_counts.replace name new_count;
 
   (* Start building the function *)
   let loc = vf.vf_decl.vdecl in
@@ -431,15 +442,15 @@ let valid_read_nstring typ =
 let format_length typ =
   find_predicate_by_width typ "format_length" "wformat_length"
 
-
 let build_specialized_fun ~builder env vf format_fun tvparams =
   let open Format_types in
   let module Build = (val builder : Builder.S) in
 
   (* Choose function name *)
   let name = vf.vf_decl.vorig_name in
-  vf.vf_specialization_count <- vf.vf_specialization_count + 1;
-  let new_name = name ^ "_va_" ^ (string_of_int vf.vf_specialization_count) in
+  let id = vf.vf_specialization_count + 1 in
+  let new_name, new_count = get_next_name env id (name ^ "_va_") in
+  vf.vf_specialization_count <- new_count;
 
   (* Start building the function *)
   let loc = vf.vf_decl.vdecl in
@@ -731,13 +742,13 @@ let format_fun_call ~builder env format_fun vf args =
   let tvparams =
     try
       Format_typer.type_format ~find_typedef format
-    with Format_typer.Type_not_found type_name ->
+    with Format_typer.Type_not_found (type_name) ->
       Self.warning ~current:true
         "Unable to find type %s in the source code which should be used in \
          this call:@ no specification will be generated.@ \
          Note that due to cleanup, the type may have been defined in the \
-         original code but not used anywhere."
-        type_name;
+         original code but not used anywhere.@.\
+         Did you include <stdint.h> ?" type_name;
       raise (Translate_call_exn vf.vf_decl)
   in
 
diff --git a/src/plugins/variadic/standard.mli b/src/plugins/variadic/standard.mli
index d06853851d9238bfbf47d01bc44c6d52398957b8..f7350aa4a112e9a89ef42eb1ba96199b3d1cfbce 100644
--- a/src/plugins/variadic/standard.mli
+++ b/src/plugins/variadic/standard.mli
@@ -24,6 +24,7 @@ exception Translate_call_exn of Cil_types.varinfo
 
 val fallback_fun_call :
   builder:Builder.t -> callee:Cil_types.varinfo ->
+  Environment.t ->
   Va_types.variadic_function -> Cil_types.exp list -> unit
 
 val aggregator_call :
diff --git a/src/plugins/variadic/tests/defined/oracle/sum_with_unspecified_sequence.res.oracle b/src/plugins/variadic/tests/defined/oracle/sum_with_unspecified_sequence.res.oracle
index c46681a1dfb4df684a4d7739e3782d316a48a598..0597fca78db0c2d14ac7825ecfcc7ffbaa0c75f8 100644
--- a/src/plugins/variadic/tests/defined/oracle/sum_with_unspecified_sequence.res.oracle
+++ b/src/plugins/variadic/tests/defined/oracle/sum_with_unspecified_sequence.res.oracle
@@ -5,9 +5,6 @@
   out of bounds read. assert \valid_read(list);
 [eva:alarm] sum_with_unspecified_sequence.c:14: Warning: 
   out of bounds read. assert \valid_read((int *)*list);
-[eva:garbled-mix:write] sum_with_unspecified_sequence.c:14: 
-  Assigning imprecise value to tmp_unroll_5.
-  The imprecision originates from Well
 [eva:alarm] sum_with_unspecified_sequence.c:14: Warning: 
   signed overflow.
   assert -2147483648 ≤ ret + tmp_unroll_5;
@@ -16,25 +13,20 @@
   signed overflow.
   assert ret + tmp_unroll_5 ≤ 2147483647;
   (tmp_unroll_5 from vararg)
-[eva:garbled-mix:write] sum_with_unspecified_sequence.c:14: 
-  Assigning imprecise value to ret.
-  The imprecision originates from Well
 [eva:alarm] sum_with_unspecified_sequence.c:14: Warning: 
   out of bounds read. assert \valid_read(list);
 [eva:alarm] sum_with_unspecified_sequence.c:14: Warning: 
   out of bounds read. assert \valid_read((int *)*list);
-[eva:garbled-mix:write] sum_with_unspecified_sequence.c:14: 
-  Assigning imprecise value to tmp.
-  The imprecision originates from Well
 [eva:alarm] sum_with_unspecified_sequence.c:14: Warning: 
   signed overflow. assert -2147483648 ≤ ret + tmp;
                    (tmp from vararg)
 [eva:alarm] sum_with_unspecified_sequence.c:14: Warning: 
   signed overflow. assert ret + tmp ≤ 2147483647;
                    (tmp from vararg)
-[eva:garbled-mix:write] sum_with_unspecified_sequence.c:17: 
-  Assigning imprecise value to \result<sum>.
-  The imprecision originates from Well
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    Initial state (read 12 times, propagated 6 times)
+      garbled mix of &{S_0_S___va_params; S_1_S___va_params}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function sum:
   ret ∈
diff --git a/src/plugins/variadic/tests/known/oracle/exec.res.oracle b/src/plugins/variadic/tests/known/oracle/exec.res.oracle
index 74ea04f2c8f1a5bfd993c56fc4632ae881ab3cb7..335dfe32f04bc71a0f8347d6161575ecc33dbca2 100644
--- a/src/plugins/variadic/tests/known/oracle/exec.res.oracle
+++ b/src/plugins/variadic/tests/known/oracle/exec.res.oracle
@@ -20,8 +20,20 @@
   Fallback translation of call execlp to a call to the specialized version execlp_fallback_1.
 [eva] Analyzing a complete application starting at main
 [eva] using specification for function execve
+[eva:garbled-mix:assigns] exec.c:9: 
+  The specification of function execve has generated a garbled mix of addresses
+  for assigns clause \result.
 [eva] using specification for function execv
+[eva:garbled-mix:assigns] exec.c:11: 
+  The specification of function execv has generated a garbled mix of addresses
+  for assigns clause \result.
 [eva] using specification for function execvp
+[eva:garbled-mix:assigns] exec.c:12: 
+  The specification of function execvp has generated a garbled mix of addresses
+  for assigns clause \result.
+[eva:garbled-mix:assigns] exec.c:13: 
+  The specification of function execve has generated a garbled mix of addresses
+  for assigns clause \result.
 [kernel:annot:missing-spec] exec.c:15: Warning: 
   Neither code nor specification for function execlp_fallback_1,
    generating default assigns. See -generated-spec-* options for more info
diff --git a/src/plugins/variadic/tests/known/oracle/print_libc.pretty.c b/src/plugins/variadic/tests/known/oracle/print_libc.pretty.c
index 0cc4de0588c6eab6ff596070c679cf5526386811..c90642f461962fdde63bb01ed6d90757cddd1c7d 100644
--- a/src/plugins/variadic/tests/known/oracle/print_libc.pretty.c
+++ b/src/plugins/variadic/tests/known/oracle/print_libc.pretty.c
@@ -51,12 +51,12 @@ int printf_va_1(char const * restrict format);
       \from (indirect: __fc_stdout->__fc_FILE_id),
             __fc_stdout->__fc_FILE_data, (indirect: *(format + (0 ..)));
  */
-int printf_va_1(char const * restrict format);
+int printf_va_2(char const * restrict format);
 
 int main(void)
 {
   int __retres;
-  printf(""); /* printf_va_1 */
+  printf(""); /* printf_va_2 */
   __retres = 0;
   return __retres;
 }
diff --git a/src/plugins/variadic/tests/known/oracle/printf.res.oracle b/src/plugins/variadic/tests/known/oracle/printf.res.oracle
index 96c9680ea4b2dab373d1c3ef0f45d8451e8ee2f8..7b945647be0216ee15d342ea55494da9642fb01b 100644
--- a/src/plugins/variadic/tests/known/oracle/printf.res.oracle
+++ b/src/plugins/variadic/tests/known/oracle/printf.res.oracle
@@ -114,6 +114,10 @@
 [eva] using specification for function printf_va_23
 [eva] using specification for function printf_va_24
 [eva] using specification for function printf_va_25
+[eva:garbled-mix:assigns] printf.c:68: 
+  The specification of function printf_va_25
+  has generated a garbled mix of addresses
+  for assigns clause __fc_stdout->__fc_FILE_data.
 [eva] using specification for function printf_va_26
 [kernel:annot:missing-spec] printf.c:71: Warning: 
   Neither code nor specification for function printf_fallback_1,
@@ -129,7 +133,7 @@
   __fc_initial_stdout.__fc_FILE_id ∈ {1}
                      .__fc_FILE_data ∈
                      {{ garbled mix of &{"Hello world !\n"}
-                      (origin: Library function) }}
+                      (origin: Library function {printf.c:68}) }}
   string ∈ {{ "Hello world !\n" }}
   wstring ∈ {{ L"Hello world !\n" }}
   c ∈ {52}
diff --git a/src/plugins/variadic/tests/known/oracle/printf_garbled_mix.res.oracle b/src/plugins/variadic/tests/known/oracle/printf_garbled_mix.res.oracle
index 88fba0600f56111170990308fe5ce792df30e713..2db3d36303765a91e701f6147e9efaacfb3e789d 100644
--- a/src/plugins/variadic/tests/known/oracle/printf_garbled_mix.res.oracle
+++ b/src/plugins/variadic/tests/known/oracle/printf_garbled_mix.res.oracle
@@ -20,13 +20,16 @@
   Translating call to printf to a call to the specialized version printf_va_1.
 [eva] Analyzing a complete application starting at main
 [eva:garbled-mix:write] printf_garbled_mix.c:6: 
-  Assigning imprecise value to b.
-  The imprecision originates from Arithmetic {printf_garbled_mix.c:6}
+  Assigning imprecise value to b because of arithmetic operation on addresses.
 [eva:alarm] printf_garbled_mix.c:7: Warning: 
   pointer downcast. assert (unsigned long)b ≤ 2147483647;
 [eva] using specification for function printf_va_1
 [eva] printf_garbled_mix.c:8: 
   Frama_C_show_each_nb_printed: [-2147483648..2147483647]
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    printf_garbled_mix.c:6: arithmetic operation on addresses
+      (read 2 times, propagated 3 times) garbled mix of &{a}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main:
   a[0] ∈ {1}
@@ -36,7 +39,7 @@
   S___fc_stdout[0].__fc_FILE_id ∈ [--..--]
                [0].__fc_FILE_data ∈
                {{ garbled mix of &{a}
-                (origin: Library function {printf_garbled_mix.c:7}) }}
+                (origin: Arithmetic {printf_garbled_mix.c:6}) }}
                [1] ∈ [--..--]
 /* Generated by Frama-C */
 #include "errno.h"
diff --git a/src/plugins/variadic/tests/known/oracle/scanf.res.oracle b/src/plugins/variadic/tests/known/oracle/scanf.0.res.oracle
similarity index 63%
rename from src/plugins/variadic/tests/known/oracle/scanf.res.oracle
rename to src/plugins/variadic/tests/known/oracle/scanf.0.res.oracle
index f01080214554f1e753c64b2728a44b1a7cff5cd3..3b3929047d11a5d489a49ad7de293a5586bc3721 100644
--- a/src/plugins/variadic/tests/known/oracle/scanf.res.oracle
+++ b/src/plugins/variadic/tests/known/oracle/scanf.0.res.oracle
@@ -16,15 +16,26 @@
   Declaration of variadic function dprintf.
 [variadic] FRAMAC_SHARE/libc/stdio.h:610: 
   Declaration of variadic function asprintf.
-[variadic] scanf.c:7: 
+[variadic] scanf.c:12: 
   Translating call to scanf to a call to the specialized version scanf_va_1.
+[variadic] scanf.c:15: 
+  Translating call to scanf to a call to the specialized version scanf_va_2.
+[variadic] scanf.c:23: Warning: 
+  Unable to find type intmax_t in the source code which should be used in this call:
+  no specification will be generated.
+  Note that due to cleanup, the type may have been defined in the original code but not used anywhere.
+  Did you include <stdint.h> ?
+[variadic] scanf.c:23: 
+  Fallback translation of call scanf to a call to the specialized version scanf_fallback_1.
 [eva] Analyzing a complete application starting at main
 [eva] using specification for function scanf_va_1
+[eva] using specification for function scanf_va_2
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main:
   c[0] ∈ [--..--]
    [1..9] ∈ [--..--] or UNINITIALIZED
   i ∈ [--..--]
+  wc ∈ [--..--]
   __retres ∈ {0}
   S___fc_stdin[0..1] ∈ [--..--]
 /* Generated by Frama-C */
@@ -59,14 +70,42 @@
 int scanf_va_1(char const * restrict format, char *param0, char *param1,
                int *param2);
 
+/*@ requires \valid(param0);
+    requires valid_read_string(format);
+    ensures \initialized(param0);
+    assigns \result, __fc_stdin->__fc_FILE_data, *param0;
+    assigns \result
+      \from (indirect: __fc_stdin->__fc_FILE_id),
+            (indirect: __fc_stdin->__fc_FILE_data),
+            (indirect: *(format + (0 ..)));
+    assigns __fc_stdin->__fc_FILE_data
+      \from (indirect: __fc_stdin->__fc_FILE_id), __fc_stdin->__fc_FILE_data,
+            (indirect: *(format + (0 ..)));
+    assigns *param0
+      \from (indirect: __fc_stdin->__fc_FILE_id), __fc_stdin->__fc_FILE_data,
+            (indirect: *(format + (0 ..)));
+ */
+int scanf_va_2(char const * restrict format, wchar_t *param0);
+
 int main(void)
 {
   int __retres;
   char c[10];
   int i;
+  wchar_t wc;
   scanf("Hello %*10le %% %10s %[^]world] %d !",c,c,& i); /* scanf_va_1 */
+  scanf("%lc",& wc); /* scanf_va_2 */
   __retres = 0;
   return __retres;
 }
 
+int scanf_fallback_1(char const * restrict format, int *param0);
+
+void warn_about_intmax_t(void)
+{
+  int i;
+  scanf("%jd",& i); /* scanf_fallback_1 */
+  return;
+}
+
 
diff --git a/src/plugins/variadic/tests/known/oracle/scanf.1.res.oracle b/src/plugins/variadic/tests/known/oracle/scanf.1.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..44221e5bb220b87e06bf9640fb09e6404e660fd3
--- /dev/null
+++ b/src/plugins/variadic/tests/known/oracle/scanf.1.res.oracle
@@ -0,0 +1,122 @@
+[variadic] FRAMAC_SHARE/libc/stdio.h:207: 
+  Declaration of variadic function fprintf.
+[variadic] FRAMAC_SHARE/libc/stdio.h:209: 
+  Declaration of variadic function fscanf.
+[variadic] FRAMAC_SHARE/libc/stdio.h:211: 
+  Declaration of variadic function printf.
+[variadic] FRAMAC_SHARE/libc/stdio.h:212: 
+  Declaration of variadic function scanf.
+[variadic] FRAMAC_SHARE/libc/stdio.h:213: 
+  Declaration of variadic function snprintf.
+[variadic] FRAMAC_SHARE/libc/stdio.h:215: 
+  Declaration of variadic function sprintf.
+[variadic] FRAMAC_SHARE/libc/stdio.h:217: 
+  Declaration of variadic function sscanf.
+[variadic] FRAMAC_SHARE/libc/stdio.h:550: 
+  Declaration of variadic function dprintf.
+[variadic] FRAMAC_SHARE/libc/stdio.h:610: 
+  Declaration of variadic function asprintf.
+[variadic] scanf.c:12: 
+  Translating call to scanf to a call to the specialized version scanf_va_1.
+[variadic] scanf.c:15: 
+  Translating call to scanf to a call to the specialized version scanf_va_2.
+[variadic] scanf.c:23: 
+  Translating call to scanf to a call to the specialized version scanf_va_3.
+[eva] Analyzing a complete application starting at main
+[eva] using specification for function scanf_va_1
+[eva] using specification for function scanf_va_2
+[eva] ====== VALUES COMPUTED ======
+[eva:final-states] Values at end of function main:
+  c[0] ∈ [--..--]
+   [1..9] ∈ [--..--] or UNINITIALIZED
+  i ∈ [--..--]
+  wc ∈ [--..--]
+  __retres ∈ {0}
+  S___fc_stdin[0..1] ∈ [--..--]
+/* Generated by Frama-C */
+#include "errno.h"
+#include "stdarg.h"
+#include "stddef.h"
+#include "stdint.h"
+#include "stdio.h"
+/*@ requires \valid(param1);
+    requires \valid(param2);
+    requires valid_read_string(format);
+    ensures \initialized(param1);
+    ensures \initialized(param2);
+    assigns \result, __fc_stdin->__fc_FILE_data, *param2, *param1,
+            *(param0 + (0 ..));
+    assigns \result
+      \from (indirect: __fc_stdin->__fc_FILE_id),
+            (indirect: __fc_stdin->__fc_FILE_data),
+            (indirect: *(format + (0 ..)));
+    assigns __fc_stdin->__fc_FILE_data
+      \from (indirect: __fc_stdin->__fc_FILE_id), __fc_stdin->__fc_FILE_data,
+            (indirect: *(format + (0 ..)));
+    assigns *param2
+      \from (indirect: __fc_stdin->__fc_FILE_id), __fc_stdin->__fc_FILE_data,
+            (indirect: *(format + (0 ..)));
+    assigns *param1
+      \from (indirect: __fc_stdin->__fc_FILE_id), __fc_stdin->__fc_FILE_data,
+            (indirect: *(format + (0 ..)));
+    assigns *(param0 + (0 ..))
+      \from (indirect: __fc_stdin->__fc_FILE_id), __fc_stdin->__fc_FILE_data,
+            (indirect: *(format + (0 ..)));
+ */
+int scanf_va_1(char const * restrict format, char *param0, char *param1,
+               int *param2);
+
+/*@ requires \valid(param0);
+    requires valid_read_string(format);
+    ensures \initialized(param0);
+    assigns \result, __fc_stdin->__fc_FILE_data, *param0;
+    assigns \result
+      \from (indirect: __fc_stdin->__fc_FILE_id),
+            (indirect: __fc_stdin->__fc_FILE_data),
+            (indirect: *(format + (0 ..)));
+    assigns __fc_stdin->__fc_FILE_data
+      \from (indirect: __fc_stdin->__fc_FILE_id), __fc_stdin->__fc_FILE_data,
+            (indirect: *(format + (0 ..)));
+    assigns *param0
+      \from (indirect: __fc_stdin->__fc_FILE_id), __fc_stdin->__fc_FILE_data,
+            (indirect: *(format + (0 ..)));
+ */
+int scanf_va_2(char const * restrict format, wchar_t *param0);
+
+int main(void)
+{
+  int __retres;
+  char c[10];
+  int i;
+  wchar_t wc;
+  scanf("Hello %*10le %% %10s %[^]world] %d !",c,c,& i); /* scanf_va_1 */
+  scanf("%lc",& wc); /* scanf_va_2 */
+  __retres = 0;
+  return __retres;
+}
+
+/*@ requires \valid(param0);
+    requires valid_read_string(format);
+    ensures \initialized(param0);
+    assigns \result, __fc_stdin->__fc_FILE_data, *param0;
+    assigns \result
+      \from (indirect: __fc_stdin->__fc_FILE_id),
+            (indirect: __fc_stdin->__fc_FILE_data),
+            (indirect: *(format + (0 ..)));
+    assigns __fc_stdin->__fc_FILE_data
+      \from (indirect: __fc_stdin->__fc_FILE_id), __fc_stdin->__fc_FILE_data,
+            (indirect: *(format + (0 ..)));
+    assigns *param0
+      \from (indirect: __fc_stdin->__fc_FILE_id), __fc_stdin->__fc_FILE_data,
+            (indirect: *(format + (0 ..)));
+ */
+int scanf_va_3(char const * restrict format, intmax_t *param0);
+
+void warn_about_intmax_t(void)
+{
+  int i;
+  scanf("%jd",(intmax_t *)(& i)); /* scanf_va_3 */
+  return;
+}
+
+
diff --git a/src/plugins/variadic/tests/known/scanf.c b/src/plugins/variadic/tests/known/scanf.c
index f407ca56e68af2fa6548c739c586970a16302321..8943f82294f5e5a0788c4afae166afa62b3e5f13 100644
--- a/src/plugins/variadic/tests/known/scanf.c
+++ b/src/plugins/variadic/tests/known/scanf.c
@@ -1,3 +1,8 @@
+/* run.config
+   STDOPT:
+   STDOPT: #"-cpp-extra-args=-DINCLUDE_STDINT"
+*/
+
 #include <stdio.h>
 
 int main(){
@@ -5,4 +10,15 @@ int main(){
   int i;
 
   scanf("Hello %*10le %% %10s %[^]world] %d !", c, c, &i);
+
+  wchar_t wc;
+  scanf("%lc", &wc);
+}
+
+#ifdef INCLUDE_STDINT
+#include <stdint.h> // avoids warning due to missing intmax_t below
+#endif
+void warn_about_intmax_t(void) {
+  int i;
+  scanf("%jd", &i); // '%j' is for intmax_t
 }
diff --git a/src/plugins/variadic/translate.ml b/src/plugins/variadic/translate.ml
index 21489606b074ca1cb2089786424f090d02fd1457..95778a48f085fb1313b855c324d699fcbae8d43d 100644
--- a/src/plugins/variadic/translate.ml
+++ b/src/plugins/variadic/translate.ml
@@ -200,7 +200,7 @@ let translate_variadics (file : file) =
             try
               f ~builder args
             with Standard.Translate_call_exn callee ->
-              Standard.fallback_fun_call ~callee ~builder vf args
+              Standard.fallback_fun_call ~callee ~builder env vf args
         in
         match vf.vf_class with
         | Overload o -> cover_failure (Standard.overloaded_call o vf)
diff --git a/src/plugins/wp/Changelog b/src/plugins/wp/Changelog
index e3b12412e74b8dd0e5e849f4ae71308b5408d84d..bf3d94cc895d1703c781a69fb9e96ce45898c8b0 100644
--- a/src/plugins/wp/Changelog
+++ b/src/plugins/wp/Changelog
@@ -28,6 +28,12 @@ Plugin WP <next-release>
                            -wp-counter-examples. Also introduce an ACSL extension
                            to create probes on terms for counter examples.
 
+###############################################################################
+Plugin WP 28.1 (Nickel)
+###############################################################################
+
+-* WP         [2024-01-29] Fix interactive prover startup.
+
 ###############################################################################
 Plugin WP 28.0 (Nickel)
 ###############################################################################
diff --git a/src/plugins/wp/LogicSemantics.ml b/src/plugins/wp/LogicSemantics.ml
index 96baad2451d79132d57ae02a8a6182fc4bd6c0f4..cad0d5b3b9382e7bfaac02125ea1c4c4f06aefb9 100644
--- a/src/plugins/wp/LogicSemantics.ml
+++ b/src/plugins/wp/LogicSemantics.ml
@@ -672,8 +672,7 @@ struct
     | TUnOp(unop,t) -> term_unop unop (C.logic env t)
     | TBinOp(binop,a,b) -> term_binop env binop a b
 
-    | TCastE(ty,t) -> term_cast_to_ctype env ty t
-    | TLogic_coerce(typ,t) -> term_cast_to_ltype env typ t
+    | TCast (_, typ,t) -> term_cast_to_ltype env typ t
 
     | Tapp(f,ls,ts) ->
       let vs = List.map (val_of_term env) ts in
@@ -941,8 +940,7 @@ struct
       Warning.error "Complex let-binding not implemented yet (%a)"
         Printer.pp_term t
 
-    | TCastE (_,t)
-    | TLogic_coerce(_,t) -> C.region env t
+    | TCast (_,_,t) -> C.region env t
 
     | TBinOp _ | TUnOp _ | Trange _ | TUpdate _ | Tapp _ | Tif _
     | TConst _ | Tnull | TDataCons _ | Tlambda _
diff --git a/src/plugins/wp/MemAddr.ml b/src/plugins/wp/MemAddr.ml
new file mode 100644
index 0000000000000000000000000000000000000000..325ee2b04bfa2b52c0b896a7adaaf18b583c64cd
--- /dev/null
+++ b/src/plugins/wp/MemAddr.ml
@@ -0,0 +1,417 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of WP plug-in of Frama-C.                           *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2023                                               *)
+(*    CEA (Commissariat a l'energie atomique et aux energies              *)
+(*         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 Lang.F
+
+(* -------------------------------------------------------------------------- *)
+(* --- Symbols registration                                               --- *)
+(* -------------------------------------------------------------------------- *)
+
+let library = "memaddr"
+
+(* Warning: DO NOT register map types using this constructor: it hides types
+   needed by ProverWhy3 for typing terms of the form x[i].
+*)
+
+let t_addr = Qed.Logic.Data(Lang.datatype ~library "addr",[])
+let t_table = Qed.Logic.Data(Lang.datatype ~library "table",[])
+
+let f_base   = Lang.extern_f ~library ~result:Qed.Logic.Int
+    ~link:(Qed.Engine.F_subst ("base", "%1.base")) "base"
+
+let f_offset = Lang.extern_f ~library ~result:Qed.Logic.Int
+    ~link:(Qed.Engine.F_subst ("offset", "%1.offset")) "offset"
+
+let f_shift  = Lang.extern_f ~library ~result:t_addr "shift"
+let f_global = Lang.extern_f ~library ~result:t_addr ~category:Qed.Logic.Injection "global"
+let f_null   = Lang.extern_f ~library ~result:t_addr "null"
+
+let p_addr_lt = Lang.extern_p ~library ~bool:"addr_lt_bool" ~prop:"addr_lt" ()
+let p_addr_le = Lang.extern_p ~library ~bool:"addr_le_bool" ~prop:"addr_le" ()
+
+let f_addr_of_int = Lang.extern_f
+    ~category:Qed.Logic.Injection
+    ~library ~result:t_addr "addr_of_int"
+
+let f_int_of_addr = Lang.extern_f
+    ~category:Qed.Logic.Injection
+    ~library ~result:Qed.Logic.Int "int_of_addr"
+
+
+let f_table_of_base = Lang.extern_f ~library
+    ~category:Qed.Logic.Function ~result:t_table "table_of_base"
+
+let f_table_to_offset = Lang.extern_f ~library
+    ~category:Qed.Logic.Injection ~result:Qed.Logic.Int "table_to_offset"
+
+let p_valid_rd = Lang.extern_fp ~library "valid_rd"
+let p_valid_rw = Lang.extern_fp ~library "valid_rw"
+let p_valid_obj = Lang.extern_fp ~library "valid_obj"
+let p_invalid = Lang.extern_fp ~library "invalid"
+let p_separated = Lang.extern_fp ~library "separated"
+let p_included = Lang.extern_fp ~library "included"
+
+(* base -> region *)
+let f_region = Lang.extern_f ~coloring:true ~library ~result:Qed.Logic.Int "region"
+(* allocation-table -> prop *)
+let p_linked = Lang.extern_fp ~coloring:true ~library "linked"
+
+(* -------------------------------------------------------------------------- *)
+(* --- API                                                                --- *)
+(* -------------------------------------------------------------------------- *)
+
+let base addr = e_fun f_base [ addr ]
+let offset addr = e_fun f_offset [ addr ]
+let null = constant (e_fun f_null [])
+let global base = e_fun f_global [ base ]
+let shift addr offset = e_fun f_shift [ addr ; offset ]
+let mk_addr base offset = shift (global base) offset
+
+let addr_lt addr1 addr2 = p_call p_addr_lt [ addr1 ; addr2 ]
+let addr_le addr1 addr2 = p_call p_addr_le [ addr1 ; addr2 ]
+
+let addr_of_int i = e_fun f_addr_of_int [ i ]
+let int_of_addr addr = e_fun f_int_of_addr [ addr ]
+
+let base_offset base offset =
+  let offset_index = e_fun f_table_of_base [base] in
+  e_fun f_table_to_offset [offset_index ; offset]
+(** Returns the offset in {i bytes} from the {i logic} offset
+    (which is a memory cell index, actually) *)
+
+let valid_rd alloc addr size = p_call p_valid_rd [ alloc ; addr ; size ]
+let valid_rw alloc addr size = p_call p_valid_rw [ alloc ; addr ; size ]
+let valid_obj alloc addr size = p_call p_valid_obj [ alloc ; addr ; size ]
+let invalid alloc addr size = p_call p_invalid [ alloc ; addr ; size ]
+
+let region base = e_fun f_region [ base ]
+let linked memory = p_call p_linked [ memory ]
+
+(* -------------------------------------------------------------------------- *)
+(* --- Qed Simplifiers                                                    --- *)
+(* -------------------------------------------------------------------------- *)
+
+(*
+    Pointer arithmetic for structure access and array access could be
+    defined directly using the record [{ base = p.base; offset = p.offset
+    + c*i + c' }]. However that gives very bad triggers for the memory
+    model axiomatization, so `shift p (c*i+c')` was used instead. It is
+    not sufficient for user axiomatisation because memory access in
+    axioms require trigger with arithmetic operators which is badly
+    handled by provers. So for each c and c', ie for each kind of
+    structure access and array access a specific function is used
+    `shift_xxx`.
+
+    Moreover no simplification of `shift_xxx` is done for keeping the
+    same terms in axioms and the goal. `base` and `offset` function
+    simplify all the `shift_xxx` because it seems they don't appear
+    often in axioms and they are useful for simplifying `separated`,
+    `assigns` and pointer comparisons in goals.
+
+    To sum up memory access should match, but not `\base`, `\offset`,
+    `\separated`, ...
+*)
+
+type addr_builtin = {
+  base: term list -> term ;
+  offset: term list -> term ;
+}
+
+module ADDR_BUILTIN = WpContext.Static
+    (struct
+      type key = Lang.lfun
+      type data = addr_builtin
+      let name = "MemMemory.ADDR_BUILTIN"
+      include Lang.Fun
+    end)
+
+let phi_base l =
+  match repr l with
+  | Fun(f,[p;_]) when f==f_shift -> base p
+  | Fun(f,[b]) when f==f_global -> b
+  | Fun(f,[]) when f==f_null -> e_zero
+  | Fun(f,args) -> (ADDR_BUILTIN.find f).base args
+  | _ -> raise Not_found
+
+let phi_offset l = match repr l with
+  | Fun(f,[p;k]) when f==f_shift -> e_add (offset p) k
+  | Fun(f,_) when f==f_global || f==f_null -> e_zero
+  | Fun(f,args) -> (ADDR_BUILTIN.find f).offset args
+  | _ -> raise Not_found
+
+let phi_shift f p i =
+  match repr p with
+  | Fun(g,[q;j]) when f == g -> e_fun f [q;e_add i j]
+  | _ -> raise Not_found
+
+let eq_shift a b =
+  let p = base a in
+  let q = base b in
+  let i = offset a in
+  let j = offset b in
+  if i==j then p_equal p q else
+    match is_equal p q with
+    | No -> p_false
+    | Yes -> p_equal i j
+    | Maybe -> raise Not_found
+
+let eq_shift_gen phi a b =
+  try phi a b with Not_found -> eq_shift a b
+
+let nop _ = raise Not_found
+
+let register ?(base=nop) ?(offset=nop) ?equal ?(linear=false) lfun =
+  begin
+    if base != nop || offset != nop then
+      ADDR_BUILTIN.define lfun { base ; offset } ;
+    if linear then
+      set_builtin_2 lfun (phi_shift lfun) ;
+    let phi_equal = match equal with
+      | None -> eq_shift
+      | Some phi -> eq_shift_gen phi
+    in
+    set_builtin_eqp lfun phi_equal ;
+  end
+
+(* -------------------------------------------------------------------------- *)
+(* --- Simplifier for 'separated'                                         --- *)
+(* -------------------------------------------------------------------------- *)
+
+let r_separated = function
+  | [p;a;q;b] ->
+    if a == e_one && b == e_one then e_neq p q
+    else
+      begin
+        let a_negative = e_leq a e_zero in
+        let b_negative = e_leq b e_zero in
+        if a_negative == e_true || b_negative == e_true then e_true else
+          let bp = base p in
+          let bq = base q in
+          match is_true (e_eq bp bq) with
+          | No -> e_true (* Have S *)
+          | Yes when (a_negative == e_false && b_negative == e_false) ->
+            (* Reduced to S *)
+            let p_ofs = offset p in
+            let q_ofs = offset q in
+            let p_ofs' = e_add p_ofs a in
+            let q_ofs' = e_add q_ofs b in
+            e_or [ e_leq q_ofs' p_ofs ;
+                   e_leq p_ofs' q_ofs ]
+          | _ -> raise Not_found
+      end
+  | _ -> raise Not_found
+
+let is_separated args = is_true (r_separated args)
+
+(* -------------------------------------------------------------------------- *)
+(* --- Simplifier for 'included'                                          --- *)
+(* -------------------------------------------------------------------------- *)
+
+(* See: tests/why3/test_memory.why
+
+   logic a : int
+   logic b : int
+
+   predicate R = p.base = q.base
+              /\ (q.offset <= p.offset)
+              /\ (p.offset + a <= q.offset + b)
+
+   predicate included = 0 < a -> ( 0 <= b and R )
+   predicate a_empty = a <= 0
+   predicate b_negative = b < 0
+
+   lemma SAME_P: p=q -> (R <-> a<=b)
+   lemma SAME_A: a=b -> (R <-> p=q)
+
+   goal INC_P:  p=q -> (included <-> ( 0 < a -> a <= b )) (by SAME_P)
+   goal INC_A:  a=b -> 0 < a -> (included <-> R) (by SAME_A)
+   goal INC_1:  a_empty -> (included <-> true)
+   goal INC_2:  b_negative -> (included <-> a_empty)
+   goal INC_3:  not R -> (included <-> a_empty)
+   goal INC_4:  not a_empty -> not b_negative -> (included <-> R)
+*)
+
+let r_included = function
+  | [p;a;q;b] ->
+    if e_eq p q == e_true
+    then e_imply [e_lt e_zero a] (e_leq a b) (* INC_P *)
+    else
+    if (e_eq a b == e_true) && (e_lt e_zero a == e_true)
+    then e_eq p q (* INC_A *)
+    else
+      begin
+        let a_empty = e_leq a e_zero in
+        let b_negative = e_lt b e_zero in
+        if a_empty == e_true then e_true (* INC_1 *) else
+        if b_negative == e_true then a_empty (* INC_2 *) else
+          let bp = base p in
+          let bq = base q in
+          match is_true (e_eq bp bq) with
+          | No -> a_empty (* INC_3 *)
+          | Yes when (a_empty == e_false && b_negative == e_false) ->
+            (* INC_4 *)
+            let p_ofs = offset p in
+            let q_ofs = offset q in
+            if a == b then e_eq p_ofs q_ofs
+            else
+              let p_ofs' = e_add p_ofs a in
+              let q_ofs' = e_add q_ofs b in
+              e_and [ e_leq q_ofs p_ofs ; e_leq p_ofs' q_ofs' ]
+          | _ -> raise Not_found
+      end
+  | _ -> raise Not_found
+
+let is_included args = is_true (r_included args)
+
+(* -------------------------------------------------------------------------- *)
+(* --- Simplifier for int/addr conversion                                 --- *)
+(* -------------------------------------------------------------------------- *)
+
+let phi_int_of_addr p =
+  if p == null then e_zero else
+    match repr p with
+    | Fun(f,[a]) when f == f_addr_of_int -> a
+    | _ -> raise Not_found
+
+let phi_addr_of_int p =
+  if p == e_zero then null else
+    match repr p with
+    | Fun(f,[a]) when f == f_int_of_addr -> a
+    | _ -> raise Not_found
+
+(* -------------------------------------------------------------------------- *)
+(* --- Simplifier for (in)validity                                        --- *)
+(* -------------------------------------------------------------------------- *)
+
+let null_base p = e_eq (e_fun f_base [p]) e_zero
+
+(* See: tests/why3/test_memory.why *)
+
+(* - lemma valid_rd_null: forall m n p. p.base = 0 -> (n <= 0 <-> valid_rd m p n)
+   - lemma valid_rw_null: forall m n p. p.base = 0 -> (n <= 0 <-> valid_rw m p n)
+*)
+let r_valid_unref = function
+  | [_; p; n] when decide (null_base p) ->
+    e_leq n e_zero
+  | _ -> raise Not_found
+
+(* - lemma valid_obj_null: forall m n. valid_obj m null n *)
+let r_valid_obj = function
+  | [_; p; _] when decide (e_eq p null) -> e_true
+  | _ -> raise Not_found
+
+(* - lemma invalid_null: forall m n p. p.base = 0 -> invalid m p n *)
+let r_invalid = function
+  | [_; p; _] when decide (null_base p) -> e_true
+  | _ -> raise Not_found
+
+(* -------------------------------------------------------------------------- *)
+(* --- Simplifiers Registration                                           --- *)
+(* -------------------------------------------------------------------------- *)
+
+let () = Context.register
+    begin fun () ->
+      set_builtin_1   f_base   phi_base ;
+      set_builtin_1   f_offset phi_offset ;
+      set_builtin_2   f_shift  (phi_shift f_shift) ;
+      set_builtin_eqp f_shift  eq_shift ;
+      set_builtin_eqp f_global eq_shift ;
+      set_builtin p_separated r_separated ;
+      set_builtin p_included  r_included ;
+      set_builtin_1 f_addr_of_int phi_addr_of_int ;
+      set_builtin_1 f_int_of_addr phi_int_of_addr ;
+      set_builtin p_invalid r_invalid ;
+      set_builtin p_valid_rd r_valid_unref ;
+      set_builtin p_valid_rw r_valid_unref ;
+      set_builtin p_valid_obj r_valid_obj ;
+    end
+
+(* -------------------------------------------------------------------------- *)
+(* --- Identify lfun                                                      --- *)
+(* -------------------------------------------------------------------------- *)
+
+let is_p_valid_rd lf = lf == p_valid_rd
+let is_p_valid_rw lf = lf == p_valid_rw
+let is_p_valid_obj lf = lf == p_valid_obj
+let is_p_invalid lf = lf == p_invalid
+
+let is_f_global lf = lf == f_global
+
+(* -------------------------------------------------------------------------- *)
+(* --- Range Comparison                                                   --- *)
+(* -------------------------------------------------------------------------- *)
+
+type range =
+  | LOC of term * term (* loc - size *)
+  | RANGE of term * Vset.set (* base - range offset *)
+
+let range ~shift ~addrof ~sizeof = function
+  | Sigs.Rloc(obj,loc) ->
+    LOC( addrof loc , sizeof obj )
+  | Sigs.Rrange(loc,obj,Some a,Some b) ->
+    let s = sizeof obj in
+    let p = addrof (shift loc obj a) in
+    let n = e_mul s (e_range a b) in
+    LOC( p , n )
+  | Sigs.Rrange(loc,_obj,None,None) ->
+    RANGE( base (addrof loc) , Vset.range None None )
+  | Sigs.Rrange(loc,obj,Some a,None) ->
+    let s = sizeof obj in
+    RANGE( base (addrof loc) , Vset.range (Some (e_mul s a)) None )
+  | Sigs.Rrange(loc,obj,None,Some b) ->
+    let s = sizeof obj in
+    RANGE( base (addrof loc) , Vset.range None (Some (e_mul s b)) )
+
+let range_set = function
+  | LOC(l,n) ->
+    let a = offset l in
+    let b = e_add a n in
+    base l , Vset.range (Some a) (Some b)
+  | RANGE(base,set) -> base , set
+
+let r_included r1 r2 =
+  match r1 , r2 with
+  | LOC(l1,n1) , LOC(l2,n2) ->
+    p_call p_included [l1;n1;l2;n2]
+  | _ ->
+    let base1,set1 = range_set r1 in
+    let base2,set2 = range_set r2 in
+    p_if (p_equal base1 base2)
+      (Vset.subset set1 set2)
+      (Vset.is_empty set1)
+
+let r_disjoint r1 r2 =
+  match r1 , r2 with
+  | LOC(l1,n1) , LOC(l2,n2) ->
+    p_call p_separated [l1;n1;l2;n2]
+  | _ ->
+    let base1,set1 = range_set r1 in
+    let base2,set2 = range_set r2 in
+    p_imply (p_equal base1 base2) (Vset.disjoint set1 set2)
+
+let included ~shift ~addrof ~sizeof s1 s2  =
+  let range = range ~shift ~addrof ~sizeof in
+  r_included (range s1) (range s2)
+
+let separated ~shift ~addrof ~sizeof s1 s2 =
+  let range = range ~shift ~addrof ~sizeof in
+  r_disjoint (range s1) (range s2)
diff --git a/src/plugins/wp/MemAddr.mli b/src/plugins/wp/MemAddr.mli
new file mode 100644
index 0000000000000000000000000000000000000000..38f30863eaffcb38353aa83fddbd8afbeb0572f5
--- /dev/null
+++ b/src/plugins/wp/MemAddr.mli
@@ -0,0 +1,166 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of WP plug-in of Frama-C.                           *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2023                                               *)
+(*    CEA (Commissariat a l'energie atomique et aux energies              *)
+(*         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 Lang.F
+
+(** Smart-constructors for building Qed terms from the MemAddr Why3 module
+    symbols. Types indicates in the documentation are Why3 types, not OCaml
+    types.
+
+    @since Frama-C+dev
+*)
+
+val t_addr : Lang.tau
+(** Pointer type : addr *)
+
+(** {2 Basic constructors} *)
+
+val base : term -> term
+(** [base(a: addr) : int = a.base] *)
+
+val offset : term -> term
+(** [offset(a: addr) : int = a.offset] *)
+
+val null : term
+(** [null : addr = { base = 0 ; offset = 0 }] *)
+
+val mk_addr : term -> term -> term
+(** [mk_addr(base: int)(offset: int) : addr = { base ; offset }] *)
+
+val global : term -> term
+(** [global(base: int) : addr = { base ; offset = 0 }] *)
+
+val shift : term -> term -> term
+(** [shift (a: addr) (k: int) : addr = { a with offset = a.offset + k } ]*)
+
+val addr_lt : term -> term -> pred
+(** [addr_lt(a: addr) (b: addr) = a < b] *)
+
+val addr_le : term -> term -> pred
+(** [addr_le(a: addr) (b: addr) = a <= b] *)
+
+val addr_of_int : term -> term
+(** [addr_of_int(i: int) : addr]
+    Abstract: Conversion from integer to address
+*)
+
+val int_of_addr : term -> term
+(** [int_of_addr (a: addr) : int]
+    Abstract: Conversion from address to integer
+*)
+
+val base_offset : term -> term -> term
+(** [base_offset(base: int)(offset: int) : int]
+    Converts a {i logic} offset (which is actually the address of a memory cell
+    in a given memory model into an offset in {i bytes}.
+*)
+
+(** {2 Symbols related to the table of allocation (int -> int)} *)
+
+val valid_rd : term -> term -> term -> pred
+(** [valid_rd(m: malloc)(a: addr)(l: length)] *)
+
+val valid_rw : term -> term -> term -> pred
+(** [valid_rw(m: malloc)(a: addr)(l: length)] *)
+
+val valid_obj : term -> term -> term -> pred
+(** [valid_obj(m: malloc)(a: addr)(l: length)] *)
+
+val invalid : term -> term -> term -> pred
+(** [invalid(m: malloc)(a: addr)(l: length)]
+    Invalidity means that the {i entire} range of addresses is invalid.
+*)
+
+val region : term -> term
+(** [region(base: int) : int]
+    The memory region a base belongs to.
+*)
+
+val linked : term -> pred
+(** [linked(m: malloc)] *)
+
+val register :
+  ?base:(term list -> term) ->
+  ?offset:(term list -> term) ->
+  ?equal:(term -> term -> pred) ->
+  ?linear:bool -> Lang.lfun -> unit
+(** Register simplifiers for functions producing [addr] terms:
+    - [~base es] is the simplifier for [(f es).base]
+    - [~offset es] is the simplifier for [(f es).offset]
+    - [~linear:true] register simplifier [f(f(p,i),k)=f(p,i+j)] on [f]
+    - [~equal a b] is the [set_eq_builtin] for [f]
+
+    The equality builtin is wrapped inside a default builtin that
+    compares [f es] by computing [base] and [offset].
+*)
+
+(** {2 Memory model parameterized inclusion and separation} *)
+
+val included :
+  shift:('loc -> Ctypes.c_object -> term -> 'loc) ->
+  addrof:('loc -> term) ->
+  sizeof:(Ctypes.c_object -> term) ->
+  'loc Sigs.rloc -> 'loc Sigs.rloc -> pred
+(** [included ~shift ~addrof ~sizeof r1 r2] builds a predicate that checks
+    whether [r1] is included in [r2].
+    - [shift loc obj k]: [loc] shifted of [k] [obj] in the memory model,
+    - [addrof loc]: [loc] translated into a [term] in the memory model,
+    - [sizeof obj]: the length of [obj] in the memory model.
+*)
+
+val separated :
+  shift:('loc -> Ctypes.c_object -> term -> 'loc) ->
+  addrof:('loc -> term) ->
+  sizeof:(Ctypes.c_object -> term) ->
+  'loc Sigs.rloc -> 'loc Sigs.rloc -> pred
+(** [separated ~shift ~addrof ~sizeof r1 r2] builds a predicate that checks
+    whether [r1] and [r2] are separated.
+    - [shift loc obj k]: [loc] shifted of [k] [obj] in the memory model,
+    - [addrof loc]: [loc] translated into a [term] in the memory model,
+    - [sizeof obj]: the length of [obj] in the memory model.
+*)
+
+(** {2 Qed symbols identification} *)
+
+val is_p_valid_rd  : Lang.lfun -> bool
+val is_p_valid_rw  : Lang.lfun -> bool
+val is_p_valid_obj : Lang.lfun -> bool
+val is_p_invalid   : Lang.lfun -> bool
+val is_f_global    : Lang.lfun -> bool
+
+(** {2 Raw Qed symbols} *)
+(** Use them with care, for building terms, prefer above constructors *)
+
+val p_separated : Lang.lfun
+val p_included : Lang.lfun
+
+(** {2 Qed simplification procedures} *)
+
+val is_separated : term list -> Qed.Logic.maybe
+(** [is_separated [ a ; la ; b ; lb ]]
+    Try to solve with Qed that separated(a, la, b, lb)
+*)
+
+val is_included : term list -> Qed.Logic.maybe
+(** [is_included [ a ; la ; b ; lb ]]
+    Try to solve with Qed that included(a, la, b, lb)
+*)
diff --git a/src/plugins/wp/MemMemory.ml b/src/plugins/wp/MemMemory.ml
index 062e3f01e3ebd9ee90fcdb40141fbc3975d2f92d..8ad0a096b7583126cd52c328954968b306f2d9fe 100644
--- a/src/plugins/wp/MemMemory.ml
+++ b/src/plugins/wp/MemMemory.ml
@@ -31,25 +31,6 @@ module L = Qed.Logic
 
 let library = "memory"
 
-let a_addr = Lang.datatype ~library "addr"
-let t_addr = L.Data(a_addr,[])
-let f_base   = Lang.extern_f ~library ~result:L.Int
-    ~link:(Qed.Engine.F_subst ("base", "%1.base")) "base"
-let f_offset = Lang.extern_f ~library ~result:L.Int
-    ~link:(Qed.Engine.F_subst ("offset", "%1.offset")) "offset"
-let f_shift  = Lang.extern_f ~library ~result:t_addr "shift"
-let f_global = Lang.extern_f ~library ~result:t_addr ~category:L.Injection "global"
-let f_null   = Lang.extern_f ~library ~result:t_addr "null"
-
-let a_table = Lang.datatype ~library "table"
-let t_table = L.Data(a_table,[])
-
-let f_table_of_base = Lang.extern_f ~library
-    ~category:Qed.Logic.Function ~result:t_table "table_of_base"
-
-let f_table_to_offset = Lang.extern_f ~library
-    ~category:Qed.Logic.Injection ~result:L.Int "table_to_offset"
-
 let ty_fst_arg = function
   | Some l :: _ -> l
   | _ -> raise Not_found
@@ -57,227 +38,27 @@ let ty_fst_arg = function
 let l_havoc = Qed.Engine.F_call "havoc"
 let l_set_init = Qed.Engine.F_call "set_init"
 
-let p_valid_rd = Lang.extern_fp ~library "valid_rd"
-let p_valid_rw = Lang.extern_fp ~library "valid_rw"
-let p_valid_obj = Lang.extern_fp ~library "valid_obj"
-let p_invalid = Lang.extern_fp ~library "invalid"
-let p_separated = Lang.extern_fp ~library "separated"
-let p_included = Lang.extern_fp ~library "included"
 let p_eqmem = Lang.extern_fp ~library "eqmem"
 let f_havoc = Lang.extern_f ~library ~typecheck:ty_fst_arg ~link:l_havoc "havoc"
-let f_region = Lang.extern_f ~coloring:true ~library ~result:L.Int "region" (* base -> region *)
 let p_framed = Lang.extern_fp ~coloring:true ~library "framed" (* m-pointer -> prop *)
-let p_linked = Lang.extern_fp ~coloring:true ~library "linked" (* allocation-table -> prop *)
 let p_sconst = Lang.extern_fp ~coloring:true ~library "sconst" (* int-memory -> prop *)
-let p_addr_lt = Lang.extern_p ~library ~bool:"addr_lt_bool" ~prop:"addr_lt" ()
-let p_addr_le = Lang.extern_p ~library ~bool:"addr_le_bool" ~prop:"addr_le" ()
 let f_set_init =
   Lang.extern_f ~library ~typecheck:ty_fst_arg ~link:l_set_init "set_init"
 let p_cinits = Lang.extern_fp ~coloring:true ~library "cinits" (* initializaton-table -> prop *)
 let p_is_init_r = Lang.extern_fp ~library "is_init_range"
 let p_monotonic = Lang.extern_fp ~library "monotonic_init"
 
-let f_addr_of_int = Lang.extern_f
-    ~category:L.Injection
-    ~library ~result:t_addr "addr_of_int"
-
-let f_int_of_addr = Lang.extern_f
-    ~category:L.Injection
-    ~library ~result:L.Int "int_of_addr"
-
 (* -------------------------------------------------------------------------- *)
 (* --- Utilities                                                          --- *)
 (* -------------------------------------------------------------------------- *)
 
-let t_mem t = L.Array(t_addr,t)
+let t_mem t = L.Array(MemAddr.t_addr,t)
 let t_malloc = L.Array(L.Int,L.Int)
-let t_init = L.Array(t_addr,L.Bool)
-
-let a_null = F.constant (e_fun f_null [])
-let a_base p = e_fun f_base [p]
-let a_offset p = e_fun f_offset [p]
-let a_global b = e_fun f_global [b]
-let a_shift l k = e_fun f_shift [l;k]
-let a_addr b k = a_shift (a_global b) k
-let a_base_offset b k =
-  let offset_index = e_fun f_table_of_base [b] in
-  e_fun f_table_to_offset [offset_index ; k]
-
-(* -------------------------------------------------------------------------- *)
-(* --- Qed Simplifiers                                                    --- *)
-(* -------------------------------------------------------------------------- *)
-
-(*
-    Pointer arithmetic for structure access and array access could be
-    defined directly using the record [{ base = p.base; offset = p.offset
-    + c*i + c' }]. However that gives very bad triggers for the memory
-    model axiomatization, so `shift p (c*i+c')` was used instead. It is
-    not sufficient for user axiomatisation because memory access in
-    axioms require trigger with arithmetic operators which is badly
-    handled by provers. So for each c and c', ie for each kind of
-    structure access and array access a specific function is used
-    `shift_xxx`.
-
-    Moreover no simplification of `shift_xxx` is done for keeping the
-    same terms in axioms and the goal. `base` and `offset` function
-    simplify all the `shift_xxx` because it seems they don't appear
-    often in axioms and they are useful for simplifying `separated`,
-    `assigns` and pointer comparisons in goals.
-
-    To sum up memory access should match, but not `\base`, `\offset`,
-    `\separated`, ...
-*)
-
-type addr_builtin = {
-  base: term list -> term ;
-  offset: term list -> term ;
-}
-
-module ADDR_BUILTIN = WpContext.Static
-    (struct
-      type key = lfun
-      type data = addr_builtin
-      let name = "MemMemory.ADDR_BUILTIN"
-      include Lang.Fun
-    end)
-
-let phi_base l =
-  match F.repr l with
-  | L.Fun(f,[p;_]) when f==f_shift -> a_base p
-  | L.Fun(f,[b]) when f==f_global -> b
-  | L.Fun(f,[]) when f==f_null -> e_zero
-  | L.Fun(f,args) -> (ADDR_BUILTIN.find f).base args
-  | _ -> raise Not_found
-
-let phi_offset l = match F.repr l with
-  | L.Fun(f,[p;k]) when f==f_shift -> e_add (a_offset p) k
-  | L.Fun(f,_) when f==f_global || f==f_null -> F.e_zero
-  | L.Fun(f,args) -> (ADDR_BUILTIN.find f).offset args
-  | _ -> raise Not_found
-
-let phi_shift f p i =
-  match F.repr p with
-  | L.Fun(g,[q;j]) when f == g -> F.e_fun f [q;F.e_add i j]
-  | _ -> raise Not_found
-
-let eq_shift a b =
-  let p = a_base a in
-  let q = a_base b in
-  let i = a_offset a in
-  let j = a_offset b in
-  if i==j then F.p_equal p q else
-    match F.is_equal p q with
-    | L.No -> F.p_false
-    | L.Yes -> F.p_equal i j
-    | L.Maybe -> raise Not_found
-
-let eq_shift_gen phi a b =
-  try phi a b with Not_found -> eq_shift a b
-
-let nop _ = raise Not_found
-
-let register ?(base=nop) ?(offset=nop) ?equal ?(linear=false) lfun =
-  begin
-    if base != nop || offset != nop then
-      ADDR_BUILTIN.define lfun { base ; offset } ;
-    if linear then
-      F.set_builtin_2 lfun (phi_shift lfun) ;
-    let phi_equal = match equal with
-      | None -> eq_shift
-      | Some phi -> eq_shift_gen phi
-    in
-    F.set_builtin_eqp lfun phi_equal ;
-  end
-
-(* -------------------------------------------------------------------------- *)
-(* --- Simplifier for 'separated'                                         --- *)
-(* -------------------------------------------------------------------------- *)
-
-let r_separated = function
-  | [p;a;q;b] ->
-    if a == F.e_one && b == F.e_one then F.e_neq p q
-    else
-      begin
-        let a_negative = F.e_leq a F.e_zero in
-        let b_negative = F.e_leq b F.e_zero in
-        if a_negative == e_true || b_negative == e_true then e_true else
-          let bp = a_base p in
-          let bq = a_base q in
-          let open Qed.Logic in
-          match F.is_true (F.e_eq bp bq) with
-          | No -> e_true (* Have S *)
-          | Yes when (a_negative == e_false && b_negative == e_false) ->
-            (* Reduced to S *)
-            let p_ofs = a_offset p in
-            let q_ofs = a_offset q in
-            let p_ofs' = F.e_add p_ofs a in
-            let q_ofs' = F.e_add q_ofs b in
-            F.e_or [ F.e_leq q_ofs' p_ofs ;
-                     F.e_leq p_ofs' q_ofs ]
-          | _ -> raise Not_found
-      end
-  | _ -> raise Not_found
-
-let is_separated args = F.is_true (r_separated args)
-
-(* -------------------------------------------------------------------------- *)
-(* --- Simplifier for 'included'                                          --- *)
-(* -------------------------------------------------------------------------- *)
+let t_init = L.Array(MemAddr.t_addr,L.Bool)
 
-(* See: tests/why3/test_memory.why
-
-   logic a : int
-   logic b : int
-
-   predicate R = p.base = q.base
-              /\ (q.offset <= p.offset)
-              /\ (p.offset + a <= q.offset + b)
-
-   predicate included = 0 < a -> ( 0 <= b and R )
-   predicate a_empty = a <= 0
-   predicate b_negative = b < 0
-
-   lemma SAME_P: p=q -> (R <-> a<=b)
-   lemma SAME_A: a=b -> (R <-> p=q)
-
-   goal INC_P:  p=q -> (included <-> ( 0 < a -> a <= b )) (by SAME_P)
-   goal INC_A:  a=b -> 0 < a -> (included <-> R) (by SAME_A)
-   goal INC_1:  a_empty -> (included <-> true)
-   goal INC_2:  b_negative -> (included <-> a_empty)
-   goal INC_3:  not R -> (included <-> a_empty)
-   goal INC_4:  not a_empty -> not b_negative -> (included <-> R)
-*)
-
-let r_included = function
-  | [p;a;q;b] ->
-    if F.e_eq p q == F.e_true
-    then F.e_imply [F.e_lt F.e_zero a] (F.e_leq a b) (* INC_P *)
-    else
-    if (F.e_eq a b == F.e_true) && (F.e_lt F.e_zero a == F.e_true)
-    then F.e_eq p q (* INC_A *)
-    else
-      begin
-        let a_empty = F.e_leq a F.e_zero in
-        let b_negative = F.e_lt b F.e_zero in
-        if a_empty == F.e_true then F.e_true (* INC_1 *) else
-        if b_negative == F.e_true then a_empty (* INC_2 *) else
-          let bp = a_base p in
-          let bq = a_base q in
-          let open Qed.Logic in
-          match F.is_true (F.e_eq bp bq) with
-          | No -> a_empty (* INC_3 *)
-          | Yes when (a_empty == e_false && b_negative == e_false) ->
-            (* INC_4 *)
-            let p_ofs = a_offset p in
-            let q_ofs = a_offset q in
-            if a == b then F.e_eq p_ofs q_ofs
-            else
-              let p_ofs' = e_add p_ofs a in
-              let q_ofs' = e_add q_ofs b in
-              e_and [ F.e_leq q_ofs p_ofs ; F.e_leq p_ofs' q_ofs' ]
-          | _ -> raise Not_found
-      end
-  | _ -> raise Not_found
+let cinits memory = p_call p_cinits [ memory ]
+let sconst memory = p_call p_sconst [ memory ]
+let framed memory = p_call p_framed [ memory ]
 
 (* -------------------------------------------------------------------------- *)
 (* --- Simplifier for 'havoc'                                             --- *)
@@ -290,7 +71,7 @@ let r_havoc = function
       match F.repr m1 with
       | L.Fun( f , [_undef0;m0;p0;a0] ) when f == f_havoc -> begin
           let open Qed.Logic in
-          match F.is_true (r_included [p0;a0;p1;a1]) with
+          match MemAddr.is_included [p0;a0;p1;a1] with
           | Yes -> F.e_fun f_havoc [undef1;m0;p1;a1]
           | _ -> raise Not_found
         end
@@ -306,76 +87,21 @@ let r_get_havoc es ks =
   match es, ks with
   | [undef;m;p;a],[k] ->
     begin
-      match is_separated [p;a;k;e_one] with
+      match MemAddr.is_separated [p;a;k;e_one] with
       | L.Yes -> F.e_get m k
       | L.No  -> F.e_get undef k
       | _ -> raise Not_found
     end
   | _ -> raise Not_found
 
-(* -------------------------------------------------------------------------- *)
-(* --- Simplifier for int/addr conversion                                 --- *)
-(* -------------------------------------------------------------------------- *)
-
-let phi_int_of_addr p =
-  if p == a_null then F.e_zero else
-    match F.repr p with
-    | L.Fun(f,[a]) when f == f_addr_of_int -> a
-    | _ -> raise Not_found
-
-let phi_addr_of_int p =
-  if p == F.e_zero then a_null else
-    match F.repr p with
-    | L.Fun(f,[a]) when f == f_int_of_addr -> a
-    | _ -> raise Not_found
-
-(* -------------------------------------------------------------------------- *)
-(* --- Simplifier for (in)validity                                        --- *)
-(* -------------------------------------------------------------------------- *)
-
-let null_base p = e_eq (F.e_fun f_base [p]) F.e_zero
-
-(* See: tests/why3/test_memory.why *)
-
-(* - lemma valid_rd_null: forall m n p. p.base = 0 -> (n <= 0 <-> valid_rd m p n)
-   - lemma valid_rw_null: forall m n p. p.base = 0 -> (n <= 0 <-> valid_rw m p n)
-*)
-let r_valid_unref = function
-  | [_; p; n] when F.decide (null_base p) ->
-    e_leq n e_zero
-  | _ -> raise Not_found
-
-(* - lemma valid_obj_null: forall m n. valid_obj m null n *)
-let r_valid_obj = function
-  | [_; p; _] when F.decide (e_eq p a_null) -> e_true
-  | _ -> raise Not_found
-
-(* - lemma invalid_null: forall m n p. p.base = 0 -> invalid m p n *)
-let r_invalid = function
-  | [_; p; _] when F.decide (null_base p) -> e_true
-  | _ -> raise Not_found
-
 (* -------------------------------------------------------------------------- *)
 (* --- Simplifiers Registration                                           --- *)
 (* -------------------------------------------------------------------------- *)
 
 let () = Context.register
     begin fun () ->
-      F.set_builtin_1   f_base   phi_base ;
-      F.set_builtin_1   f_offset phi_offset ;
-      F.set_builtin_2   f_shift  (phi_shift f_shift) ;
-      F.set_builtin_eqp f_shift  eq_shift ;
-      F.set_builtin_eqp f_global eq_shift ;
-      F.set_builtin p_separated r_separated ;
-      F.set_builtin p_included  r_included ;
       F.set_builtin f_havoc r_havoc ;
       F.set_builtin_get f_havoc r_get_havoc ;
-      F.set_builtin_1 f_addr_of_int phi_addr_of_int ;
-      F.set_builtin_1 f_int_of_addr phi_int_of_addr ;
-      F.set_builtin p_invalid r_invalid ;
-      F.set_builtin p_valid_rd r_valid_unref ;
-      F.set_builtin p_valid_rw r_valid_unref ;
-      F.set_builtin p_valid_obj r_valid_obj ;
     end
 
 (* -------------------------------------------------------------------------- *)
@@ -385,17 +111,17 @@ let () = Context.register
 module T = Definitions.Trigger
 
 let frames ~addr:p ~offset:n ~sizeof:s ?(basename="mem") tau =
-  let t_mem = L.Array(t_addr,tau) in
+  let t_mem = L.Array(MemAddr.t_addr,tau) in
   let m  = F.e_var (Lang.freshvar ~basename t_mem) in
   let m' = F.e_var (Lang.freshvar ~basename t_mem) in
-  let p' = F.e_var (Lang.freshvar ~basename:"q" t_addr) in
+  let p' = F.e_var (Lang.freshvar ~basename:"q" MemAddr.t_addr) in
   let n' = F.e_var (Lang.freshvar ~basename:"n" L.Int) in
   let mh = F.e_fun f_havoc [m';m;p';n'] in
   let v' = F.e_var (Lang.freshvar ~basename:"v" tau) in
   let meq = F.p_call p_eqmem [m;m';p';n'] in
-  let diff = F.p_call p_separated [p;n;p';s] in
-  let sep = F.p_call p_separated [p;n;p';n'] in
-  let inc = F.p_call p_included [p;n;p';n'] in
+  let diff = F.p_call MemAddr.p_separated [p;n;p';s] in
+  let sep = F.p_call MemAddr.p_separated [p;n;p';n'] in
+  let inc = F.p_call MemAddr.p_included [p;n;p';n'] in
   let teq = T.of_pred meq in
   [
     "update" , [] , [diff] , m , e_set m p' v' ;
@@ -403,66 +129,6 @@ let frames ~addr:p ~offset:n ~sizeof:s ?(basename="mem") tau =
     "havoc" , [] , [sep] , m , mh ;
   ]
 
-(* -------------------------------------------------------------------------- *)
-(* --- Range Comparison                                                   --- *)
-(* -------------------------------------------------------------------------- *)
-
-type range =
-  | LOC of term * term (* loc - size *)
-  | RANGE of term * Vset.set (* base - range offset *)
-
-let range ~shift ~addrof ~sizeof = function
-  | Sigs.Rloc(obj,loc) ->
-    LOC( addrof loc , sizeof obj )
-  | Sigs.Rrange(loc,obj,Some a,Some b) ->
-    let s = sizeof obj in
-    let p = addrof (shift loc obj a) in
-    let n = e_mul s (e_range a b) in
-    LOC( p , n )
-  | Sigs.Rrange(loc,_obj,None,None) ->
-    RANGE( a_base (addrof loc) , Vset.range None None )
-  | Sigs.Rrange(loc,obj,Some a,None) ->
-    let s = sizeof obj in
-    RANGE( a_base (addrof loc) , Vset.range (Some (e_mul s a)) None )
-  | Sigs.Rrange(loc,obj,None,Some b) ->
-    let s = sizeof obj in
-    RANGE( a_base (addrof loc) , Vset.range None (Some (e_mul s b)) )
-
-let range_set = function
-  | LOC(l,n) ->
-    let a = a_offset l in
-    let b = e_add a n in
-    a_base l , Vset.range (Some a) (Some b)
-  | RANGE(base,set) -> base , set
-
-let r_included r1 r2 =
-  match r1 , r2 with
-  | LOC(l1,n1) , LOC(l2,n2) ->
-    F.p_call p_included [l1;n1;l2;n2]
-  | _ ->
-    let base1,set1 = range_set r1 in
-    let base2,set2 = range_set r2 in
-    F.p_if (F.p_equal base1 base2)
-      (Vset.subset set1 set2)
-      (Vset.is_empty set1)
-
-let r_disjoint r1 r2 =
-  match r1 , r2 with
-  | LOC(l1,n1) , LOC(l2,n2) ->
-    F.p_call p_separated [l1;n1;l2;n2]
-  | _ ->
-    let base1,set1 = range_set r1 in
-    let base2,set2 = range_set r2 in
-    F.p_imply (F.p_equal base1 base2) (Vset.disjoint set1 set2)
-
-let included ~shift ~addrof ~sizeof s1 s2  =
-  let range = range ~shift ~addrof ~sizeof in
-  r_included (range s1) (range s2)
-
-let separated ~shift ~addrof ~sizeof s1 s2 =
-  let range = range ~shift ~addrof ~sizeof in
-  r_disjoint (range s1) (range s2)
-
 (* -------------------------------------------------------------------------- *)
 (* --- Unsupported Unions                                                 --- *)
 (* -------------------------------------------------------------------------- *)
diff --git a/src/plugins/wp/MemMemory.mli b/src/plugins/wp/MemMemory.mli
index 094cbb0bdc479fa0e6ced313eafc9449dccf740d..220b4e82b881c14817dc2280ed79f5abd38d7b7e 100644
--- a/src/plugins/wp/MemMemory.mli
+++ b/src/plugins/wp/MemMemory.mli
@@ -29,82 +29,24 @@ open Lang.F
 
 (** {2 Theory} *)
 
-val t_addr : tau
 val t_malloc : tau (** allocation tables *)
 
 val t_init : tau (** initialization tables *)
 
 val t_mem : tau -> tau (** t_addr indexed array *)
 
-val a_null : term (** Null address. Same as [a_addr 0 0] *)
-
-val a_global : term -> term (** Zero-offset base. Same as [a_addr base 0] *)
-
-val a_addr : term -> term -> term (** Constructor for [{ base ; offset }] *)
-
-val a_shift : term -> term -> term
-(** Shift: [a_shift a k] adds [k] to [a.offset] *)
-
-val a_base : term -> term
-(** Returns the base *)
-
-val a_offset : term -> term
-(** Returns the offset *)
-
-val a_base_offset : term -> term -> term
-(** Returns the offset in {i bytes} from the {i logic} offset
-    (which is a memory cell index, actually) *)
-
-val f_null : lfun
-val f_base : lfun
-val f_global : lfun
-val f_shift : lfun
-val f_offset : lfun
 val f_havoc : lfun
 val f_set_init : lfun
-val f_region : lfun
-
-val f_addr_of_int : lfun (** Physical address *)
 
-val f_int_of_addr : lfun (** Physical address *)
-
-val p_addr_lt : lfun
-val p_addr_le : lfun
-val p_linked : lfun
-val p_framed : lfun
-val p_sconst : lfun
-val p_cinits : lfun
 val p_is_init_r : lfun
-val p_separated : lfun
-val p_included : lfun
-val p_valid_rd : lfun
-val p_valid_rw : lfun
-val p_valid_obj : lfun
-val p_invalid : lfun
 val p_eqmem : lfun
 val p_monotonic : lfun
 
-(* -------------------------------------------------------------------------- *)
-
-(** {2 Addr Producer Registration} *)
-
-(** Register simplifiers for functions producing [addr] terms:
-    - [~base es] is the simplifier for [(f es).base]
-    - [~offset es] is the simplifier for [(f es).offset]
-    - [~linear:true] register simplifier [f(f(p,i),k)=f(p,i+j)] on [f]
-    - [~equal a b] is the [set_eq_builtin] for [f]
-
-    The equality builtin is wrapped inside a default builtin that
-    compares [f es] by computing [base] and [offset].
-*)
-
-val register :
-  ?base:(term list -> term) ->
-  ?offset:(term list -> term) ->
-  ?equal:(term -> term -> pred) ->
-  ?linear:bool ->
-  lfun -> unit
+val cinits : term -> pred
+val sconst : term -> pred
+val framed : term -> pred
 
+(* -------------------------------------------------------------------------- *)
 
 (** {2 Frame Conditions}
 
@@ -120,20 +62,6 @@ val register :
 val frames : addr:term -> offset:term -> sizeof:term ->
   ?basename:string -> tau -> Sigs.frame list
 
-(** {2 Range of Address} *)
-
-val separated :
-  shift:('a -> Ctypes.c_object -> term -> 'a) ->
-  addrof:('a -> term) ->
-  sizeof:(Ctypes.c_object -> term) ->
-  'a Sigs.rloc -> 'a Sigs.rloc -> pred
-
-val included :
-  shift:('a -> Ctypes.c_object -> term -> 'a) ->
-  addrof:('a -> term) ->
-  sizeof:(Ctypes.c_object -> term) ->
-  'a Sigs.rloc -> 'a Sigs.rloc -> pred
-
 (** {2 Unsupported Union Fields} *)
 
 val unsupported_union : Cil_types.fieldinfo -> unit
diff --git a/src/plugins/wp/MemRegion.ml b/src/plugins/wp/MemRegion.ml
index c6498e3b539ea64a14698393fbdf91e8815d00a6..0c1f75690761fb479909a7b6a646b2a79dc2d8f2 100644
--- a/src/plugins/wp/MemRegion.ml
+++ b/src/plugins/wp/MemRegion.ml
@@ -45,7 +45,7 @@ let cluster_region () =
   Definitions.cluster ~id:"Region" ~title:"Region Index Constructors" ()
 
 (* Index *)
-let t_addr = MemMemory.t_addr
+let t_addr = MemAddr.t_addr
 let t_index = L.Data( Lang.datatype ~library "index" ,[] )
 let f_addrof = Lang.extern_f ~library ~result:t_addr "addrof"
 let f_consistent = Lang.extern_fp ~library "consistent"
@@ -59,12 +59,7 @@ let p_range k n ps = F.(p_leq e_zero k :: p_lt k n :: ps)
 (* Null *)
 let f_inull = Lang.extern_f ~library ~result:t_index "inull"
 let l_inull = F.e_fun f_inull []
-let a_null = MemMemory.a_null
-let p_inull l = F.p_equal a_null (a_addrof l)
-
-(* Address *)
-
-let p_separated p n q m = F.p_call MemMemory.p_separated [p;n;q;m]
+let p_inull l = F.p_equal MemAddr.null (a_addrof l)
 
 (* Constructors *)
 let region_ctor ~result =
@@ -86,7 +81,6 @@ let l_index_ref l = F.e_fun f_index_ref [l]
 
 (* Shifts *)
 
-let a_shift = MemMemory.a_shift
 let f_shift_index = Lang.extern_f ~library ~result:t_index "shift_index"
 let l_shift_index l p = F.e_fun f_shift_index [l;p]
 
@@ -120,10 +114,10 @@ let is_shiftable f =
 
 let phi_addrof index =
   match F.repr index with
-  | L.Fun(f,[]) when f == f_inull -> a_null
+  | L.Fun(f,[]) when f == f_inull -> MemAddr.null
   | L.Fun(f,[x]) when f == f_index_var -> a_addr_var x
   | L.Fun(f,[l]) when f == f_index_ref -> a_addr_ref (a_addrof l)
-  | L.Fun(f,l::p::_) when is_shiftable f -> a_shift (a_addrof l) p
+  | L.Fun(f,l::p::_) when is_shiftable f -> MemAddr.shift (a_addrof l) p
   | L.Fun(f,es) -> (IndexBuiltin.find f).addrof es
   | _ -> raise Not_found
 
@@ -160,9 +154,9 @@ let phi_consistent_range index sizeof =
 
 let () = Context.register
     begin fun () ->
-      MemMemory.register f_addr_var
+      MemAddr.register f_addr_var
         ~base:(F.e_fun f_base_var) ~offset:(fun _ -> F.e_zero) ;
-      MemMemory.register f_addr_ref
+      MemAddr.register f_addr_ref
         ~base:(F.e_fun f_base_ref) ;
       F.set_builtin_1 f_addrof phi_addrof ;
       F.set_builtin_1 f_consistent phi_consistent ;
@@ -252,7 +246,7 @@ struct
     | _ -> raise Not_found
 
   let builtin_addrof = function
-    | [l;p] -> a_shift (a_addrof l) p
+    | [l;p] -> MemAddr.shift (a_addrof l) p
     | _ -> raise Not_found
 
   let builtin_consistent fds = function
@@ -316,7 +310,7 @@ struct
   (* Address shift with coefficient c_i for each index k_i *)
   let rec shift a cs ks =
     match cs , ks with
-    | c::cs , k::ks -> shift (a_shift a (F.e_fact c k)) cs ks
+    | c::cs , k::ks -> shift (MemAddr.shift a (F.e_fact c k)) cs ks
     | _ -> a
 
   (* Address of an array index *)
@@ -785,7 +779,7 @@ struct
         let p = F.e_var xp in
         let a = to_addr loc in
         let n = F.e_int (Ctypes.bits_sizeof_object obj) in
-        let separated = p_separated p F.e_one a n in
+        let separated = F.p_call MemAddr.p_separated [ p ; F.e_one ; a ; n ] in
         let equal = F.p_equal (F.e_get m1 p) (F.e_get m2 p) in
         [xp],separated,equal
       else [],F.p_true,F.p_equal m1 m2
@@ -859,11 +853,11 @@ let sizeof = MODEL.sizeof
 
 let included s1 s2 =
   if disjoint_region s1 s2 then F.p_false else
-    MemMemory.included ~shift ~addrof ~sizeof s1 s2
+    MemAddr.included ~shift ~addrof ~sizeof s1 s2
 
 let separated s1 s2 =
   if disjoint_region s1 s2 then F.p_true else
-    MemMemory.separated ~shift ~addrof ~sizeof s1 s2
+    MemAddr.separated ~shift ~addrof ~sizeof s1 s2
 
 (* -------------------------------------------------------------------------- *)
 (* ---  TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO  --- *)
@@ -880,7 +874,7 @@ let apply _ _ = ()
 let literal ~eid _ = ignore eid ; GarbledMix
 
 let base_addr _l = GarbledMix
-let base_offset l = MemMemory.a_offset (addrof l)
+let base_offset l = MemAddr.offset (addrof l)
 let block_length _s _obj _l = F.e_zero
 
 let cast _ _l = GarbledMix
diff --git a/src/plugins/wp/MemTyped.ml b/src/plugins/wp/MemTyped.ml
index ad0596bfa8f081ac33f64782ef2fdbaa33143e12..24e7ddb49ea91e9ca78384e2b57770182557a1e0 100644
--- a/src/plugins/wp/MemTyped.ml
+++ b/src/plugins/wp/MemTyped.ml
@@ -45,8 +45,8 @@ let datatype = "MemTyped"
 let hypotheses p = p
 let configure () =
   begin
-    let orig_pointer = Context.push Lang.pointer t_addr in
-    let orig_null    = Context.push Cvalues.null (p_equal a_null) in
+    let orig_pointer = Context.push Lang.pointer MemAddr.t_addr in
+    let orig_null    = Context.push Cvalues.null (p_equal MemAddr.null) in
     let rollback () =
       Context.pop Lang.pointer orig_pointer ;
       Context.pop Cvalues.null orig_null ;
@@ -164,14 +164,14 @@ struct
     | M_int _ -> L.Int
     | M_f32 -> Cfloat.tau_of_float Ctypes.Float32
     | M_f64 -> Cfloat.tau_of_float Ctypes.Float64
-    | M_pointer -> t_addr
+    | M_pointer -> MemAddr.t_addr
     | T_alloc -> L.Int
     | T_init -> L.Bool
   let tau_of_chunk = function
-    | M_int _ -> L.Array(t_addr,L.Int)
-    | M_pointer -> L.Array(t_addr,t_addr)
-    | M_f32 -> L.Array(t_addr,Cfloat.tau_of_float Ctypes.Float32)
-    | M_f64 -> L.Array(t_addr,Cfloat.tau_of_float Ctypes.Float64)
+    | M_int _ -> L.Array(MemAddr.t_addr,L.Int)
+    | M_pointer -> L.Array(MemAddr.t_addr,MemAddr.t_addr)
+    | M_f32 -> L.Array(MemAddr.t_addr,Cfloat.tau_of_float Ctypes.Float32)
+    | M_f64 -> L.Array(MemAddr.t_addr,Cfloat.tau_of_float Ctypes.Float64)
     | T_alloc -> t_malloc
     | T_init -> t_init
   let basename_of_chunk = basename
@@ -302,15 +302,15 @@ type shift =
   | RS_Index of term  (* size of the shift *)
 
 let phi_base = function
-  | p::_ -> a_base p
+  | p::_ -> MemAddr.base p
   | _ -> raise Not_found
 
 let phi_field offset = function
-  | [p] -> e_add (a_offset p) offset
+  | [p] -> e_add (MemAddr.offset p) offset
   | _ -> raise Not_found
 
 let phi_index size = function
-  | [p;k] -> e_add (a_offset p) (F.e_mul size k)
+  | [p;k] -> e_add (MemAddr.offset p) (F.e_mul size k)
   | _ -> raise Not_found
 
 module RegisterShift = WpContext.Static
@@ -328,16 +328,16 @@ module ShiftFieldDef = WpContext.StaticGenerator(Cil_datatype.Fieldinfo)
       type data = dfun
 
       let generate f =
-        let result = t_addr in
+        let result = MemAddr.t_addr in
         let lfun = Lang.generated_f ~result "shiftfield_%s" (Lang.field_id f) in
         let position = position_of_field f in
         (* Since its a generated it is the unique name given *)
-        let xloc = Lang.freshvar ~basename:"p" t_addr in
+        let xloc = Lang.freshvar ~basename:"p" MemAddr.t_addr in
         let loc = e_var xloc in
-        let def = a_shift loc position in
+        let def = MemAddr.shift loc position in
         let dfun = Definitions.Function( result , Def , def) in
         RegisterShift.define lfun (RS_Field(f,position)) ;
-        MemMemory.register ~base:phi_base ~offset:(phi_field position) lfun ;
+        MemAddr.register ~base:phi_base ~offset:(phi_field position) lfun ;
         {
           d_lfun = lfun ; d_types = 0 ;
           d_params = [xloc] ;
@@ -389,18 +389,18 @@ module ShiftGen = WpContext.StaticGenerator(Cobj)
       let c_object_id c = Format.asprintf "%a@?" c_object_id c
 
       let generate obj =
-        let result = t_addr in
+        let result = MemAddr.t_addr in
         let shift = Lang.generated_f ~result "shift_%s" (c_object_id obj) in
         let size = length_of_object obj in
         (* Since its a generated it is the unique name given *)
-        let xloc = Lang.freshvar ~basename:"p" t_addr in
+        let xloc = Lang.freshvar ~basename:"p" MemAddr.t_addr in
         let loc = e_var xloc in
         let xk = Lang.freshvar ~basename:"k" Qed.Logic.Int in
         let k = e_var xk in
-        let def = a_shift loc (F.e_mul size k) in
+        let def = MemAddr.shift loc (F.e_mul size k) in
         let dfun = Definitions.Function( result , Def , def) in
         RegisterShift.define shift (RS_Index size) ;
-        MemMemory.register ~base:phi_base ~offset:(phi_index size)
+        MemAddr.register ~base:phi_base ~offset:(phi_index size)
           ~linear:true shift ;
         {
           d_lfun = shift ; d_types = 0 ;
@@ -455,7 +455,7 @@ module STRING = WpContext.Generator(LITERAL)
         let name = prefix ^ "_linked" in
         let a = Lang.freshvar ~basename:"alloc" (Chunk.tau_of_chunk T_alloc) in
         let m = e_var a in
-        let m_linked = p_call p_linked [m] in
+        let m_linked = MemAddr.linked m in
         let alloc = F.e_get m base in (* The size is alloc-1 *)
         let sized = Cstring.str_len cst (F.e_add alloc F.e_minus_one) in
         Definitions.define_lemma {
@@ -472,7 +472,7 @@ module STRING = WpContext.Generator(LITERAL)
         Definitions.define_lemma {
           l_kind = Admit ;
           l_name = name ; l_triggers = [] ; l_forall = [] ;
-          l_lemma = p_equal (e_fun f_region [base]) (e_int re) ;
+          l_lemma = p_equal (MemAddr.region base) (e_int re) ;
           l_cluster = Cstring.cluster () ;
         }
 
@@ -482,10 +482,10 @@ module STRING = WpContext.Generator(LITERAL)
         let i = Lang.freshvar ~basename:"i" L.Int in
         let c = Cstring.char_at cst (e_var i) in
         let ikind = Ctypes.c_char () in
-        let addr = shift (a_global base) (C_int ikind) (e_var i) in
+        let addr = shift (MemAddr.global base) (C_int ikind) (e_var i) in
         let m =
           Lang.freshvar ~basename:"mchar" (Chunk.tau_of_chunk (M_int ikind)) in
-        let m_sconst = F.p_call p_sconst [e_var m] in
+        let m_sconst = MemMemory.sconst (e_var m) in
         let v = F.e_get (e_var m) addr in
         let read = F.p_equal c v in
         Definitions.define_lemma {
@@ -549,7 +549,7 @@ module BASE = WpContext.Generator(Varinfo)
         Definitions.define_lemma {
           l_kind = Admit ;
           l_name = name ; l_triggers = [] ; l_forall = [] ;
-          l_lemma = p_equal (e_fun f_region [base]) (e_int re) ;
+          l_lemma = p_equal (MemAddr.region base) (e_int re) ;
           l_cluster = cluster_globals () ;
         }
 
@@ -568,7 +568,7 @@ module BASE = WpContext.Generator(Varinfo)
         | Some size ->
           let a = Lang.freshvar ~basename:"alloc" t_malloc in
           let m = e_var a in
-          let m_linked = p_call p_linked [m] in
+          let m_linked = MemAddr.linked m in
           let base_size = p_equal (F.e_get m base) size in
           Definitions.define_lemma {
             l_kind = Admit ;
@@ -585,11 +585,11 @@ module BASE = WpContext.Generator(Varinfo)
           let m = e_var a in
           let init_access =
             if size = e_one then
-              p_bool (F.e_get m (a_addr base e_zero))
+              p_bool (F.e_get m (MemAddr.mk_addr base e_zero))
             else
-              F.p_call p_is_init_r [ m ; a_addr base e_zero ; size ]
+              F.p_call p_is_init_r [ m ; MemAddr.mk_addr base e_zero ; size ]
           in
-          let m_init = p_call p_cinits [m] in
+          let m_init = MemMemory.cinits m in
           let init_prop = p_forall [a] (p_imply m_init init_access) in
           Definitions.define_lemma {
             l_kind = Admit ;
@@ -631,20 +631,20 @@ module BASE = WpContext.Generator(Varinfo)
 (* --- Locations                                                          --- *)
 (* -------------------------------------------------------------------------- *)
 
-let null = a_null (* as a loc *)
+let null = MemAddr.null (* as a loc *)
 
 let literal ~eid cst =
-  shift (a_global (STRING.get (eid,cst))) (C_int (Ctypes.c_char ())) e_zero
+  shift (MemAddr.global (STRING.get (eid,cst))) (C_int (Ctypes.c_char ())) e_zero
 
-let cvar x = a_global (BASE.get x)
+let cvar x = MemAddr.global (BASE.get x)
 
 let pointer_loc t = t
 let pointer_val t = t
 
-let allocated sigma l = F.e_get (Sigma.value sigma T_alloc) (a_base l)
+let allocated sigma l = F.e_get (Sigma.value sigma T_alloc) (MemAddr.base l)
 
-let base_addr l = a_addr (a_base l) e_zero
-let base_offset l = a_base_offset (a_base l) (a_offset l)
+let base_addr l = MemAddr.mk_addr (MemAddr.base l) e_zero
+let base_offset l = MemAddr.base_offset (MemAddr.base l) (MemAddr.offset l)
 let block_length sigma obj l =
   let n_cells = e_div (allocated sigma l) (length_of_object obj) in
   match obj with
@@ -954,8 +954,8 @@ let cast s l =
             "%a" pp_mismatch s ; l
     end
 
-let loc_of_int _ v = F.e_fun f_addr_of_int [v]
-let int_of_loc _ l = F.e_fun f_int_of_addr [l]
+let loc_of_int _ v = MemAddr.addr_of_int v
+let int_of_loc _ l = MemAddr.int_of_addr l
 
 (* -------------------------------------------------------------------------- *)
 (* --- Frames                                                             --- *)
@@ -1052,10 +1052,10 @@ struct
     F.p_call p_eqmem [m1;m2;loc;length_of_object obj]
 
   let eqmem_forall obj loc _chunk m1 m2 =
-    let xp = Lang.freshvar ~basename:"p" t_addr in
+    let xp = Lang.freshvar ~basename:"p" MemAddr.t_addr in
     let p = F.e_var xp in
     let n = length_of_object obj in
-    let separated = F.p_call p_separated [p;e_one;loc;n] in
+    let separated = F.p_call MemAddr.p_separated [p;e_one;loc;n] in
     let equal = p_equal (e_get m1 p) (e_get m2 p) in
     [xp],separated,equal
 
@@ -1096,7 +1096,7 @@ let domain = LOADER.domain
 
 let assigned seq obj loc =
   (* Maintain always initialized values initialized *)
-  Assert (p_call p_cinits [Sigma.value seq.post T_init]) ::
+  Assert (MemMemory.cinits (Sigma.value seq.post T_init)) ::
   LOADER.assigned seq obj loc
 
 (* -------------------------------------------------------------------------- *)
@@ -1104,17 +1104,17 @@ let assigned seq obj loc =
 (* -------------------------------------------------------------------------- *)
 
 let loc_compare f_cmp i_cmp p q =
-  match F.is_equal (a_base p) (a_base q) with
-  | L.Yes -> i_cmp (a_offset p) (a_offset q)
-  | L.Maybe | L.No -> p_call f_cmp [p;q]
+  match F.is_equal (MemAddr.base p) (MemAddr.base q) with
+  | L.Yes -> i_cmp (MemAddr.offset p) (MemAddr.offset q)
+  | L.Maybe | L.No -> f_cmp p q
 
 let is_null l = p_equal l null
 let loc_eq = p_equal
 let loc_neq = p_neq
-let loc_lt = loc_compare p_addr_lt p_lt
-let loc_leq = loc_compare p_addr_le p_leq
+let loc_lt = loc_compare MemAddr.addr_lt p_lt
+let loc_leq = loc_compare MemAddr.addr_le p_leq
 let loc_diff obj p q =
-  let delta = e_sub (a_offset p) (a_offset q) in
+  let delta = e_sub (MemAddr.offset p) (MemAddr.offset q) in
   let size = length_of_object obj in
   e_div delta size
 
@@ -1123,15 +1123,15 @@ let loc_diff obj p q =
 (* -------------------------------------------------------------------------- *)
 
 let s_valid sigma acs p n =
-  let p_valid = match acs with
-    | RW -> p_valid_rw
-    | RD -> p_valid_rd
-    | OBJ -> p_valid_obj
+  let valid = match acs with
+    | RW -> MemAddr.valid_rw
+    | RD -> MemAddr.valid_rd
+    | OBJ -> MemAddr.valid_obj
   in
-  p_call p_valid [Sigma.value sigma T_alloc;p;n]
+  valid (Sigma.value sigma T_alloc) p n
 
 let s_invalid sigma p n =
-  p_call p_invalid [Sigma.value sigma T_alloc;p;n]
+  MemAddr.invalid (Sigma.value sigma T_alloc) p n
 
 let segment phi = function
   | Rloc(obj,l) ->
@@ -1151,13 +1151,13 @@ let invalid sigma = segment (s_invalid sigma)
 let frame sigma =
   let wellformed_frame phi chunk =
     if Sigma.mem sigma chunk
-    then [ p_call phi [Sigma.value sigma chunk] ]
+    then [ phi (Sigma.value sigma chunk) ]
     else []
   in
-  wellformed_frame p_linked T_alloc @
-  wellformed_frame p_cinits T_init @
-  wellformed_frame p_sconst (M_int (Ctypes.c_char ())) @
-  wellformed_frame p_framed M_pointer
+  wellformed_frame MemAddr.linked T_alloc @
+  wellformed_frame MemMemory.cinits T_init @
+  wellformed_frame MemMemory.sconst (M_int (Ctypes.c_char ())) @
+  wellformed_frame MemMemory.framed M_pointer
 
 let alloc sigma xs =
   if xs = [] then sigma else Sigma.havoc_chunk sigma T_alloc
@@ -1174,7 +1174,7 @@ let scope seq scope xs =
         (Sigma.value seq.pre T_alloc) xs in
     [ p_equal (Sigma.value seq.post T_alloc) alloc ]
 
-let global _sigma p = p_leq (e_fun f_region [a_base p]) e_zero
+let global _sigma p = p_leq MemAddr.(region @@ base p) e_zero
 
 (* -------------------------------------------------------------------------- *)
 (* --- Segments                                                           --- *)
@@ -1183,12 +1183,12 @@ let global _sigma p = p_leq (e_fun f_region [a_base p]) e_zero
 let included =
   let addrof l = l in
   let sizeof = length_of_object in
-  MemMemory.included ~shift ~addrof ~sizeof
+  MemAddr.included ~shift ~addrof ~sizeof
 
 let separated =
   let addrof l = l in
   let sizeof = length_of_object in
-  MemMemory.separated ~shift ~addrof ~sizeof
+  MemAddr.separated ~shift ~addrof ~sizeof
 
 (* -------------------------------------------------------------------------- *)
 (* --- State Model                                                        --- *)
@@ -1198,7 +1198,7 @@ type state = chunk Tmap.t
 
 let rec lookup_a e =
   match F.repr e with
-  | L.Fun( f , [e] ) when f == f_global -> lookup_a e
+  | L.Fun( f , [e] ) when MemAddr.is_f_global f -> lookup_a e
   | L.Fun( f , es ) -> lookup_f f es
   | _ -> raise Not_found
 
diff --git a/src/plugins/wp/MemoryContext.ml b/src/plugins/wp/MemoryContext.ml
index 3412bfc6824d0b8394dfa0c5b95c6b4ebd11e60c..5840be85cb81f75e9c49e20e31f37197217ed3eb 100644
--- a/src/plugins/wp/MemoryContext.ml
+++ b/src/plugins/wp/MemoryContext.ml
@@ -122,7 +122,7 @@ let rec addr_of_lval ?loc term =
   match term.term_node with
   | TLval lv ->
     Logic_utils.mk_logic_AddrOf ?loc lv typ
-  | TCastE (_, t) | TLogic_coerce (_, t) ->
+  | TCast (_,_, t) ->
     addr_of_lval ?loc t
   | Tif(c, t, e) ->
     let t = addr_of_lval ?loc t in
@@ -320,7 +320,7 @@ let assigned_via_pointers kf =
     match t.term_node with
     | TLval (TMem _, _) ->
       true
-    | TCastE (_, t) | TLogic_coerce (_, t)
+    | TCast (_,_, t)
     | Tcomprehension(t, _, _) | Tat (t, _) ->
       assigned_via_pointer t
     | Tunion l | Tinter l ->
diff --git a/src/plugins/wp/Pattern.ml b/src/plugins/wp/Pattern.ml
index c0660c931eb529f218cdeb03ab8c3efdefd1d641..35022166319bd93bfcc7b71abb650a168c605315 100644
--- a/src/plugins/wp/Pattern.ml
+++ b/src/plugins/wp/Pattern.ml
@@ -423,11 +423,9 @@ and ptry env p e =
 and pany env op rs es =
   match rs , es with
   | [] , [] -> ()
-  | rs , [] ->
-    let e = op [] in
-    List.iter (fun r -> pmatch env r e) rs
+  | [] , _ | _ , [] -> raise Not_found
+  | [r] , _ -> pmatch env r (op es)
   | r::rs , e::es -> pmatch env r e ; pany env op rs es
-  | [] , _::_ -> raise Not_found
 
 (* Pairwise matching *)
 and pargs env ps trail es =
diff --git a/src/plugins/wp/RefUsage.ml b/src/plugins/wp/RefUsage.ml
index 958a36bfde7edcb1c54dda27b20b8cd1118248b0..b6956f0222f7088bb574c59cfee988e77121b4bd 100644
--- a/src/plugins/wp/RefUsage.ml
+++ b/src/plugins/wp/RefUsage.ml
@@ -419,8 +419,9 @@ and term (env:ctx) (t:term) : model = match t.term_node with
   | TBinOp((PlusPI|MinusPI),a,b) -> shift (term env a) (vterm env b)
 
   (* Casts *)
-  | TCastE(ty_tgt,t) -> cast (cast_ltyp ty_tgt t.term_type) (term env t)
-  | TLogic_coerce (_lt,t) -> term env t
+  | TCast (false, Ctype ty_tgt,t) -> cast (cast_ltyp ty_tgt t.term_type) (term env t)
+  | TCast (true, _lt,t) -> term env t
+  | TCast (false, _, _) -> assert false
 
 
   (* Term L-Values *)
@@ -680,8 +681,6 @@ let cfun_spec env kf =
 
 let cfun kf =
   let env = mk_ctx () in
-  (* Skipping frama-c builtins?
-     if not (Cil_builtins.is_builtin (Kernel_function.get_vi kf)) then *)
   begin
     if Kernel_function.is_definition kf then cfun_code env kf ;
     cfun_spec env kf
@@ -914,7 +913,7 @@ let dump () =
       in Format.fprintf fmt "@[<hv 0>Init:@ %a@]@." E.pretty a_init ;
       KFmap.iter (fun kf m ->
           (* Do not dump results for frama-c builtins *)
-          if not (Cil_builtins.is_builtin (Kernel_function.get_vi kf)) then
+          if not (Cil_builtins.has_fc_builtin_attr (Kernel_function.get_vi kf)) then
             Format.fprintf fmt "@[<hv 0>Function %a:@ %a@]@."
               Kernel_function.pretty kf E.pretty m ;
         ) a_usage;
diff --git a/src/plugins/wp/RegionAccess.ml b/src/plugins/wp/RegionAccess.ml
index f96af2972fd969a0f78d0caf693eda64695fbbdf..4d1da96295109b95685b7d602f52cf85cffb7d35 100644
--- a/src/plugins/wp/RegionAccess.ml
+++ b/src/plugins/wp/RegionAccess.ml
@@ -270,9 +270,9 @@ and cc_term_value (map:map) (term:term) =
 
   | Tat(t,_) -> cc_term_value map t
 
-  | TCastE(ty,t) -> cast ty @@ cc_term_value map t
-  | TLogic_coerce (Ctype ty,t) -> cast ty @@ cc_term_value map t
-  | TLogic_coerce (_,t) -> cc_term_value map t
+  | TCast (_, Ctype ty,t) -> cast ty @@ cc_term_value map t
+  | TCast (true, _,t) -> cc_term_value map t
+  | TCast (false, _,_) -> assert false
 
   | TConst _
   | TSizeOf _ | TSizeOfE _ | TSizeOfStr _
diff --git a/src/plugins/wp/TacHavoc.ml b/src/plugins/wp/TacHavoc.ml
index 412c49592ae8c9f2ff585d46d69f49c4f714c85f..87cb011e34ce10ee3f8ed8426f1382dfced06449 100644
--- a/src/plugins/wp/TacHavoc.ml
+++ b/src/plugins/wp/TacHavoc.ml
@@ -55,7 +55,7 @@ class havoc =
       | None -> Not_applicable
       | Some(mr,m0,a,n,p) ->
         let separated =
-          F.p_call MemMemory.p_separated
+          F.p_call MemAddr.p_separated
             [ p ; F.e_int 1 ; a ; n ] in
         let process = Tactical.rewrite ?at [
             "Unassigned" , separated , e , F.e_get m0 p ;
@@ -70,11 +70,11 @@ class havoc =
 
 let separated ?at property =
   match F.e_expr property with
-  | L.Fun( f , [p;n;q;m] ) when f == MemMemory.p_separated ->
-    let base_p = MemMemory.a_base p in
-    let ofs_p = MemMemory.a_offset p in
-    let base_q = MemMemory.a_base q in
-    let ofs_q = MemMemory.a_offset q in
+  | L.Fun( f , [p;n;q;m] ) when f == MemAddr.p_separated ->
+    let base_p = MemAddr.base p in
+    let ofs_p = MemAddr.offset p in
+    let base_q = MemAddr.base q in
+    let ofs_q = MemAddr.offset q in
     let eq_base = F.p_equal base_p base_q in
     let on_left = F.p_leq (F.e_add ofs_p n) ofs_q in
     let on_right = F.p_leq (F.e_add ofs_q m) ofs_p in
@@ -110,8 +110,8 @@ class separated =
 (* -------------------------------------------------------------------------- *)
 
 let invalid m p n =
-  let base = MemMemory.a_base p in
-  let offset = MemMemory.a_offset p in
+  let base = MemAddr.base p in
+  let offset = MemAddr.offset p in
   let malloc = F.e_get m base in
   "Invalid",
   F.p_imply
@@ -121,8 +121,8 @@ let invalid m p n =
        (F.p_leq (F.e_add offset n) F.e_zero))
 
 let valid_rd m p n =
-  let base = MemMemory.a_base p in
-  let offset = MemMemory.a_offset p in
+  let base = MemAddr.base p in
+  let offset = MemAddr.offset p in
   let malloc = F.e_get m base in
   "Valid (Read)",
   F.p_imply
@@ -132,8 +132,8 @@ let valid_rd m p n =
        (F.p_leq (F.e_add offset n) malloc))
 
 let valid_rw m p n =
-  let base = MemMemory.a_base p in
-  let offset = MemMemory.a_offset p in
+  let base = MemAddr.base p in
+  let offset = MemAddr.offset p in
   let malloc = F.e_get m base in
   "Valid (Read & Write)",
   F.p_imply
@@ -145,10 +145,10 @@ let valid_rw m p n =
       ])
 
 let included p a q b =
-  let p_base = MemMemory.a_base p in
-  let q_base = MemMemory.a_base q in
-  let p_offset = MemMemory.a_offset p in
-  let q_offset = MemMemory.a_offset q in
+  let p_base = MemAddr.base p in
+  let q_base = MemAddr.base q in
+  let p_offset = MemAddr.offset p in
+  let q_offset = MemAddr.offset q in
   "Included",
   F.p_imply
     (F.p_lt F.e_zero a)
@@ -161,10 +161,10 @@ let included p a q b =
          ]))
 
 let lookup f = function
-  | [p;a;q;b] when f == MemMemory.p_included -> included p a q b
-  | [m;p;n] when f == MemMemory.p_invalid -> invalid m p n
-  | [m;p;n] when f == MemMemory.p_valid_rd -> valid_rd m p n
-  | [m;p;n] when f == MemMemory.p_valid_rw -> valid_rw m p n
+  | [p;a;q;b] when f == MemAddr.p_included -> included p a q b
+  | [m;p;n] when MemAddr.is_p_invalid f -> invalid m p n
+  | [m;p;n] when MemAddr.is_p_valid_rd f -> valid_rd m p n
+  | [m;p;n] when MemAddr.is_p_valid_rw f -> valid_rw m p n
   | _ -> raise Not_found
 
 let unfold ?at e f es =
diff --git a/src/plugins/wp/TacSplit.ml b/src/plugins/wp/TacSplit.ml
index 023633e34a2f7711cf3948eb23075ead12106d20..ebd670aac56e078b5195631e583342a218d4fedc 100644
--- a/src/plugins/wp/TacSplit.ml
+++ b/src/plugins/wp/TacSplit.ml
@@ -29,7 +29,7 @@ module PartitionsQQ : sig
     Lang.F.Vars.t * Lang.F.QED.term
 
   val get : vars:Lang.F.Vars.t -> Lang.F.term list ->
-    int * Lang.F.Tset.t list
+    int * Lang.F.term list list
 end
 = struct
   let dkey = Wp_parameters.register_category "tac_split_quantifiers" (* debugging key *)
@@ -147,7 +147,11 @@ end
     r
 
   let get ~vars es =
-    extract (partitions ~vars es)
+    let nbparts, parts = extract (partitions ~vars es) in
+    let sorted_ts e = List.sort Lang.F.compare @@ Lang.F.Tset.elements e in
+    let sort_es = List.sort (Extlib.list_compare Lang.F.compare) in
+    let parts = sort_es @@ List.map sorted_ts parts in
+    nbparts, parts
 end
 
 open Lang.F
@@ -260,7 +264,7 @@ class split =
                   feedback#set_descr
                     "Decompose the quantifier into %d parts." nb_parts ;
                   let bind es =
-                    bind Exists ~vars (F.e_and (F.Tset.elements es)) in
+                    bind Exists ~vars (F.e_and es) in
                   let goal i n es =
                     Printf.sprintf "Goal %d/%d" i n , F.p_bool (bind es) in
                   Applicable (Tactical.split (Tactical.mapi goal parts))
@@ -352,7 +356,7 @@ class split =
                     else begin
                       feedback#set_title "Split (forall or)" ;
                       feedback#set_descr "Decompose the quantifier between %d parts of the disjunction." nb_parts ;
-                      let bind es = bind Forall ~vars (F.e_or (F.Tset.elements es)) in
+                      let bind es = bind Forall ~vars (F.e_or es) in
                       let goal i n es = Printf.sprintf "Goal %d/%d" i n , When (F.p_bool (bind es)) in
                       let cases = Tactical.mapi goal parts in
                       Applicable (Tactical.replace ~at:step.id cases)
diff --git a/src/plugins/wp/dune b/src/plugins/wp/dune
index ec906197b6dd444a081afebd27ca36de2600d6ab..1e53b4d17b0373062e0141cb5ca849d1d679a501 100644
--- a/src/plugins/wp/dune
+++ b/src/plugins/wp/dune
@@ -61,6 +61,7 @@
     (share/why3/frama_c_wp/cint.mlw as wp/why3/frama_c_wp/cint.mlw)
     (share/why3/frama_c_wp/qed.mlw as wp/why3/frama_c_wp/qed.mlw)
     (share/why3/frama_c_wp/vset.mlw as wp/why3/frama_c_wp/vset.mlw)
+    (share/why3/frama_c_wp/memaddr.mlw as wp/why3/frama_c_wp/memaddr.mlw)
     (share/why3/frama_c_wp/memory.mlw as wp/why3/frama_c_wp/memory.mlw)
     (share/why3/frama_c_wp/cmath.mlw as wp/why3/frama_c_wp/cmath.mlw)
     (share/why3/frama_c_wp/cfloat.mlw as wp/why3/frama_c_wp/cfloat.mlw)
diff --git a/src/plugins/wp/share/why3/frama_c_wp/memaddr.mlw b/src/plugins/wp/share/why3/frama_c_wp/memaddr.mlw
new file mode 100644
index 0000000000000000000000000000000000000000..3dda4f82d376a5cb1b77a644d0567910a8ee8daa
--- /dev/null
+++ b/src/plugins/wp/share/why3/frama_c_wp/memaddr.mlw
@@ -0,0 +1,162 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of WP plug-in of Frama-C.                           *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2023                                               *)
+(*    CEA (Commissariat a l'energie atomique et aux energies              *)
+(*         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).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+theory MemAddr
+
+  use bool.Bool
+  use int.Int
+  use map.Map
+
+  type addr = { base : int ; offset : int }
+  type malloc = map int int
+
+  (* Special addresses *)
+
+  constant null: addr = { base = 0 ; offset = 0 }
+  function global (b: int) : addr = { base = b ; offset = 0 }
+  meta "inline:no" function null
+  meta "inline:no" function global
+
+  (* Pointer arithmetic *)
+
+  predicate addr_le addr addr
+  predicate addr_lt addr addr
+  function addr_le_bool addr addr : bool
+  function addr_lt_bool addr addr : bool
+
+  axiom addr_le_def:
+    forall p q: addr [addr_le p q].
+      p.base = q.base -> (addr_le p q <-> p.offset <= q.offset)
+
+  axiom addr_lt_def:
+    forall p q: addr [addr_lt p q].
+      p.base = q.base -> (addr_lt p q <-> p.offset < q.offset)
+
+  axiom addr_le_bool_def:
+    forall p q: addr [ addr_le_bool p q].
+      addr_le p q <-> addr_le_bool p q = True
+
+  axiom addr_lt_bool_def:
+    forall p q: addr [ addr_lt_bool p q].
+      addr_lt p q <-> addr_lt_bool p q = True
+
+
+  function shift (p: addr) (k: int) : addr = { p with offset = p.offset + k }
+
+  (* Validity *)
+
+  predicate valid_rw (m: malloc) (p: addr) (n: int) =
+    n > 0 -> (  0 < p.base /\ 0 <= p.offset /\ p.offset + n <= m[p.base] )
+
+  predicate valid_rd (m: malloc) (p: addr) (n: int) =
+    n > 0 -> ( 0 <> p.base /\ 0 <= p.offset /\ p.offset + n <= m[p.base] )
+
+  predicate valid_obj (m: malloc) (p: addr) (n: int) =
+    n > 0 -> ( p = null \/
+             ( 0 <> p.base /\ 0 <= p.offset /\ p.offset + n <= 1 + m[p.base] ))
+
+  predicate invalid (m : malloc) (p:addr) (n:int) =
+    n <= 0 \/ p.base = 0 \/ m[p.base] <= p.offset \/ p.offset + n <= 0
+
+  lemma valid_rw_rd:
+    forall m: malloc. forall p: addr. forall n: int.
+      valid_rw m p n -> valid_rd m p n
+
+  lemma valid_string:
+    forall m: malloc. forall p: addr.
+      p.base < 0 -> 0 <= p.offset < m[p.base] ->
+        (valid_rd m p 1 /\ not (valid_rw m p 1))
+
+  (* Separation and inclusion *)
+
+  predicate included (p: addr) (lp: int) (q: addr) (lq: int) =
+    lp > 0 -> ( lq >= 0 /\ p.base = q.base
+                      /\ (q.offset <= p.offset)
+                      /\ (p.offset + lp <= q.offset + lq) )
+
+  predicate separated (p: addr) (lp: int) (q: addr) (lq: int) =
+       lp <= 0 \/ lq <= 0
+    \/ p.base <> q.base
+    \/ q.offset + lq <= p.offset
+    \/ p.offset + lp <= q.offset
+
+  lemma separated_1:
+    forall p q: addr. forall lp lq i j: int
+      [ separated p lp q lq , { base = p.base ; offset = i } ,
+                              { base = q.base ; offset = j } ].
+      separated p lp q lq ->
+      p.offset <= i < p.offset + lp ->
+      q.offset <= j < q.offset + lq ->
+        { base = p.base ; offset = i } <>
+        { base = q.base ; offset = j }
+
+  lemma separated_included:
+    forall p q: addr. forall lp lq: int
+      [ separated p lp q lq , included p lp q lq ].
+      lp > 0 -> lq > 0 -> separated p lp q lq -> included p lp q lq -> false
+
+  lemma included_trans:
+    forall p q r: addr. forall lp lq lr: int
+      [ included p lp q lq , included q lq r lr ].
+    included p lp q lq -> included q lq r lr -> included p lp r lr
+
+  lemma separated_trans:
+    forall p q r: addr. forall lp lq lr : int
+      [ included p lp q lq , separated q lq r lr ].
+    included p lp q lq -> separated q lq r lr -> separated p lp r lr
+
+  lemma separated_sym:
+    forall p q : addr. forall lp lq : int
+      [ separated p lp q lq ].
+      separated p lp q lq <-> separated q lq p lp
+
+  (* Regions *)
+
+  function region int: int
+  predicate linked (malloc)
+
+  (* Physical Address *)
+
+  function int_of_addr addr: int
+  function addr_of_int int: addr
+
+  type table (* abstract for now, but can be more elaborated later on *)
+  function table_of_base int: table
+  function table_to_offset table int: int
+
+  axiom table_to_offset_zero:
+    forall t: table. table_to_offset t 0 = 0
+
+  axiom table_to_offset_monotonic:
+    forall t: table. forall o1 o2: int.
+      o1 <= o2 <-> table_to_offset t o1 <= table_to_offset t o2
+
+  axiom int_of_addr_bijection :
+    forall a:int. int_of_addr (addr_of_int a) = a
+
+  axiom addr_of_int_bijection :
+    forall p:addr. addr_of_int (int_of_addr p) = p
+
+  axiom addr_of_null :
+    int_of_addr null = 0
+
+end
diff --git a/src/plugins/wp/share/why3/frama_c_wp/memory.mlw b/src/plugins/wp/share/why3/frama_c_wp/memory.mlw
index d153801e34018a2125080d254a25660d634b323a..df3bc8578965be946d9f1c941ac757c851df3412 100644
--- a/src/plugins/wp/share/why3/frama_c_wp/memory.mlw
+++ b/src/plugins/wp/share/why3/frama_c_wp/memory.mlw
@@ -25,119 +25,18 @@ theory Memory
   use bool.Bool
   use int.Int
   use map.Map
-
-  type addr = { base : int ; offset : int }
-
-  predicate addr_le addr addr
-  predicate addr_lt addr addr
-  function addr_le_bool addr addr : bool
-  function addr_lt_bool addr addr : bool
-
-  axiom addr_le_def: forall p q :addr [addr_le p q].
-    p.base = q.base -> (addr_le p q <-> p.offset <= q.offset)
-
-  axiom addr_lt_def: forall p q :addr [addr_lt p q].
-    p.base = q.base -> (addr_lt p q <-> p.offset < q.offset)
-
-  axiom addr_le_bool_def : forall p q : addr [ addr_le_bool p q].
-    addr_le p q <-> addr_le_bool p q = True
-
-  axiom addr_lt_bool_def : forall p q : addr [ addr_lt_bool p q].
-    addr_lt p q <-> addr_lt_bool p q = True
-
-  constant null : addr = { base = 0 ; offset = 0 }
-  function global (b:int) : addr = { base = b ; offset = 0 }
-  meta "inline:no" function null
-  meta "inline:no" function global
-
-  function shift (p:addr) (k:int) : addr = { p with offset = p.offset + k }
-  predicate included (p:addr) (a:int) (q:addr) (b:int) =
-    a > 0 -> ( b >= 0 /\ p.base = q.base
-                     /\ (q.offset <= p.offset)
-                     /\ (p.offset + a <= q.offset + b) )
-
-  predicate separated (p:addr) (a:int) (q:addr) (b:int) =
-       a <= 0 \/ b <= 0
-    \/ p.base <> q.base
-    \/ q.offset + b <= p.offset
-    \/ p.offset + a <= q.offset
+  use frama_c_wp.memaddr.MemAddr
 
   (* Memories *)
 
-  predicate eqmem (m1 m2 : map addr 'a) (p:addr) (a:int) =
-    forall q:addr [m1[p]|m2[q]]. included q 1 p a -> m1[q] = m2[q]
-
-  function havoc (m0 m1 : map addr 'a) (p:addr) (a:int) : map addr 'a
-
-  predicate valid_rw (m : map int int) (p:addr) (n:int) =
-    n > 0 -> (  0 < p.base /\ 0 <= p.offset /\ p.offset + n <= m[p.base] )
-
-  predicate valid_rd (m : map int int) (p:addr) (n:int) =
-    n > 0 -> ( 0 <> p.base /\ 0 <= p.offset /\ p.offset + n <= m[p.base] )
-
-  predicate valid_obj (m : map int int) (p:addr) (n:int) =
-    n > 0 -> ( p = null \/
-             ( 0 <> p.base /\ 0 <= p.offset /\ p.offset + n <= 1 + m[p.base] ))
-
-  predicate invalid (m : map int int) (p:addr) (n:int) =
-    n <= 0 \/ p.base = 0 \/ m[p.base] <= p.offset \/ p.offset + n <= 0
-
-  lemma valid_rw_rd :
-    forall m : map int int.
-    forall p : addr.
-    forall n : int.
-    valid_rw m p n -> valid_rd m p n
-
-  lemma valid_string :
-    forall m : map int int.
-    forall p : addr.
-    p.base < 0 ->
-    0 <= p.offset < m[p.base] ->
-    (valid_rd m p 1 /\ not (valid_rw m p 1))
-
-  lemma separated_1 : forall p q : addr. forall a b i j : int
-    [ separated p a q b , { base = p.base ; offset = i } ,
-                          { base = q.base ; offset = j } ].
-    separated p a q b ->
-    p.offset <= i < p.offset + a ->
-    q.offset <= j < q.offset + b ->
-    { base = p.base ; offset = i } <>
-    { base = q.base ; offset = j }
-
-  (* Regions *)
-
-  function region int : int
-
-  predicate linked (map int int)
   predicate sconst (map addr int)
   predicate framed (m : map addr addr) =
     forall p:addr [m[p]]. region(p.base) <= 0 -> region(m[p].base) <= 0
 
-  (* Properties *)
+  predicate eqmem (m1 m2 : map addr 'a) (p:addr) (a:int) =
+    forall q:addr [m1[p]|m2[q]]. included q 1 p a -> m1[q] = m2[q]
 
-  lemma separated_included :
-    forall p q : addr.
-    forall a b : int
-      [ separated p a q b , included p a q b ].
-    a > 0 -> b > 0 -> separated p a q b -> included p a q b -> false
-
-  lemma included_trans :
-    forall p q r : addr.
-    forall a b c : int
-      [ included p a q b , included q b r c ].
-    included p a q b -> included q b r c -> included p a r c
-
-  lemma separated_trans :
-    forall p q r : addr.
-    forall a b c : int
-      [ included p a q b , separated q b r c ].
-    included p a q b -> separated q b r c -> separated p a r c
-
-  lemma separated_sym :
-    forall p q : addr.
-    forall a b : int
-      [ separated p a q b ].
-    separated p a q b <-> separated q b p a
+  function havoc (m0 m1 : map addr 'a) (p:addr) (a:int) : map addr 'a
 
   lemma eqmem_included :
     forall m1 m2 : map addr 'a.
@@ -178,29 +77,4 @@ theory Memory
   predicate monotonic_init(m1 m2 : map addr bool) =
     forall p: addr. m1[p] -> m2[p]
 
-  (* Physical Address *)
-
-  function int_of_addr addr : int
-  function addr_of_int int : addr
-
-  type table (* abstract for now, but can be more elaborated later on *)
-  function table_of_base int : table
-  function table_to_offset table int : int
-
-  axiom table_to_offset_zero:
-    forall t: table. table_to_offset t 0 = 0
-
-  axiom table_to_offset_monotonic:
-    forall t: table. forall o1 o2: int.
-      o1 <= o2 <-> table_to_offset t o1 <= table_to_offset t o2
-
-  axiom int_of_addr_bijection :
-    forall a:int. int_of_addr (addr_of_int a) = a
-
-  axiom addr_of_int_bijection :
-    forall p:addr. addr_of_int (int_of_addr p) = p
-
-  axiom addr_of_null :
-    int_of_addr null = 0
-
 end
diff --git a/src/plugins/wp/share/wp.driver b/src/plugins/wp/share/wp.driver
index 7f473abbea88e3f73f84ac6b41db8fcdef5edb0c..52b3e021364caa844726656f22dcfb89ca2b5d6d 100644
--- a/src/plugins/wp/share/wp.driver
+++ b/src/plugins/wp/share/wp.driver
@@ -86,7 +86,10 @@ why3.import := "vset.Vset";
 library vlist:
 why3.import := "frama_c_wp.vlist.Vlist";
 
-library memory:
+library memaddr:
+why3.import := "frama_c_wp.memaddr.MemAddr";
+
+library memory: memaddr
 why3.import := "frama_c_wp.memory.Memory";
 
 library sqrt: cmath
diff --git a/src/plugins/wp/tests/why3/spec_memory.why b/src/plugins/wp/tests/why3/spec_memory.why
index 6c1f84a465e774c3f2ce7d0961d4a9e8a9968f0e..29d0887963627a29b9eb99bfac31337249e89fe4 100644
--- a/src/plugins/wp/tests/why3/spec_memory.why
+++ b/src/plugins/wp/tests/why3/spec_memory.why
@@ -3,7 +3,7 @@ module Spec_memory
   use int.Int
   use map.Map
 
-  use frama_c_wp.memory.Memory
+  use frama_c_wp.memaddr.MemAddr
 
   type malloc = map int int
 
diff --git a/src/plugins/wp/tests/wp/oracle/sharing.res.oracle b/src/plugins/wp/tests/wp/oracle/sharing.res.oracle
index bba94a31d5f562ce29b573eb64d0ee7dc5ffd21e..a415fcd4524da1e46c9fdb0aff4321a269627293 100644
--- a/src/plugins/wp/tests/wp/oracle/sharing.res.oracle
+++ b/src/plugins/wp/tests/wp/oracle/sharing.res.oracle
@@ -23,7 +23,7 @@ theory Compound
   
   (* use map.Map *)
   
-  (* use frama_c_wp.memory.Memory *)
+  (* use frama_c_wp.memaddr.MemAddr *)
   
   function shift_sint32 (p:addr) (k:int) : addr = shift p k
 end
@@ -43,7 +43,7 @@ end
     
     (* use map.Map *)
     
-    (* use frama_c_wp.memory.Memory *)
+    (* use frama_c_wp.memaddr.MemAddr *)
     
     (* use frama_c_wp.cint.Cint *)
     
diff --git a/src/plugins/wp/tests/wp_acsl/oracle/chunk_typing_usable.res.oracle b/src/plugins/wp/tests/wp_acsl/oracle/chunk_typing_usable.res.oracle
index 6514809aaf78a858612e4af77acd5b5a9c5e589f..a52cc11028400374f3a3ca8a9ecd1f8a43e6127f 100644
--- a/src/plugins/wp/tests/wp_acsl/oracle/chunk_typing_usable.res.oracle
+++ b/src/plugins/wp/tests/wp_acsl/oracle/chunk_typing_usable.res.oracle
@@ -26,7 +26,7 @@ theory Chunk
   
   (* use map.Map *)
   
-  (* use frama_c_wp.memory.Memory *)
+  (* use frama_c_wp.memaddr.MemAddr *)
   
   (* use frama_c_wp.cint.Cint *)
   
@@ -51,7 +51,7 @@ theory Compound
   
   (* use map.Map *)
   
-  (* use frama_c_wp.memory.Memory *)
+  (* use frama_c_wp.memaddr.MemAddr *)
   
   function shift_sint32 (p:addr) (k:int) : addr = shift p k
 end
@@ -73,7 +73,7 @@ theory A_Occ
   
   (* use map.Map *)
   
-  (* use frama_c_wp.memory.Memory *)
+  (* use frama_c_wp.memaddr.MemAddr *)
   
   function L_occ (addr -> int) int addr int int : int
   
@@ -122,7 +122,7 @@ theory Axiomatic1
   
   (* use map.Map *)
   
-  (* use frama_c_wp.memory.Memory *)
+  (* use frama_c_wp.memaddr.MemAddr *)
   
   (* use Chunk *)
   
@@ -184,7 +184,7 @@ theory Chunk1
   
   (* use map.Map1 *)
   
-  (* use frama_c_wp.memory.Memory1 *)
+  (* use frama_c_wp.memaddr.MemAddr1 *)
   
   (* use frama_c_wp.cint.Cint1 *)
   
@@ -209,7 +209,7 @@ theory Compound1
   
   (* use map.Map1 *)
   
-  (* use frama_c_wp.memory.Memory1 *)
+  (* use frama_c_wp.memaddr.MemAddr1 *)
   
   function shift_sint321 (p:addr1) (k:int) : addr1 = shift1 p k
 end
@@ -231,7 +231,7 @@ theory A_Occ1
   
   (* use map.Map1 *)
   
-  (* use frama_c_wp.memory.Memory1 *)
+  (* use frama_c_wp.memaddr.MemAddr1 *)
   
   function L_occ1 (addr1 -> int) int addr1 int int : int
   
@@ -282,7 +282,7 @@ theory Axiomatic11
   
   (* use map.Map1 *)
   
-  (* use frama_c_wp.memory.Memory1 *)
+  (* use frama_c_wp.memaddr.MemAddr1 *)
   
   (* use Chunk1 *)
   
@@ -343,7 +343,7 @@ theory Chunk2
   
   (* use map.Map2 *)
   
-  (* use frama_c_wp.memory.Memory2 *)
+  (* use frama_c_wp.memaddr.MemAddr2 *)
   
   (* use frama_c_wp.cint.Cint2 *)
   
@@ -368,7 +368,7 @@ theory Compound2
   
   (* use map.Map2 *)
   
-  (* use frama_c_wp.memory.Memory2 *)
+  (* use frama_c_wp.memaddr.MemAddr2 *)
   
   function shift_sint322 (p:addr2) (k:int) : addr2 = shift2 p k
 end
@@ -390,7 +390,7 @@ theory A_Occ2
   
   (* use map.Map2 *)
   
-  (* use frama_c_wp.memory.Memory2 *)
+  (* use frama_c_wp.memaddr.MemAddr2 *)
   
   function L_occ2 (addr2 -> int) int addr2 int int : int
   
@@ -439,7 +439,7 @@ end
     
     (* use map.Map2 *)
     
-    (* use frama_c_wp.memory.Memory2 *)
+    (* use frama_c_wp.memaddr.MemAddr2 *)
     
     (* use Chunk2 *)
     
diff --git a/src/plugins/wp/tests/wp_acsl/oracle/inductive.res.oracle b/src/plugins/wp/tests/wp_acsl/oracle/inductive.res.oracle
index 444fa41e01aa69044058c14920ddfa7f6441712c..fc53f6bcec0761474f5d95ba675a15b3c971e1f2 100644
--- a/src/plugins/wp/tests/wp_acsl/oracle/inductive.res.oracle
+++ b/src/plugins/wp/tests/wp_acsl/oracle/inductive.res.oracle
@@ -20,7 +20,7 @@ theory Compound
   
   (* use map.Map *)
   
-  (* use frama_c_wp.memory.Memory *)
+  (* use frama_c_wp.memaddr.MemAddr *)
   
   function shift_sint32 (p:addr) (k:int) : addr = shift p k
   
@@ -50,7 +50,7 @@ end
     lemma Q_test_no_label :
       forall a:int, b:int, d:int. P_is_gcd a b d -> not P_is_gcd b d a
     
-    (* use frama_c_wp.memory.Memory *)
+    (* use frama_c_wp.memaddr.MemAddr *)
     
     (* use Compound *)
     
@@ -109,7 +109,7 @@ end
     
     (* use map.Map *)
     
-    (* use frama_c_wp.memory.Memory *)
+    (* use frama_c_wp.memaddr.MemAddr *)
     
     (* use Compound *)
     
diff --git a/src/plugins/wp/tests/wp_acsl/oracle/struct_fields.res.oracle b/src/plugins/wp/tests/wp_acsl/oracle/struct_fields.res.oracle
index df6d4ce29fa743818fa496481c04b1901f967cef..0ffa139bbf1021b1267d76be1dd7466b7a0989e1 100644
--- a/src/plugins/wp/tests/wp_acsl/oracle/struct_fields.res.oracle
+++ b/src/plugins/wp/tests/wp_acsl/oracle/struct_fields.res.oracle
@@ -23,7 +23,7 @@ theory Chunk
   
   (* use map.Map *)
   
-  (* use frama_c_wp.memory.Memory *)
+  (* use frama_c_wp.memaddr.MemAddr *)
   
   (* use frama_c_wp.cint.Cint *)
   
@@ -101,7 +101,7 @@ theory Compound
   
   (* use map.Map *)
   
-  (* use frama_c_wp.memory.Memory *)
+  (* use frama_c_wp.memaddr.MemAddr *)
   
   function shiftfield_F1_X_a (p:addr) : addr = shift p 0
   
@@ -128,6 +128,8 @@ theory Compound
      separated p 3 q 1 ->
      Load_S1_X p (set mchar q v) mint mint1 = Load_S1_X p mchar mint mint1
   
+  (* use frama_c_wp.memory.Memory *)
+  
   axiom Q_Load_S1_X_eqmem_Mchar0 :
     forall mchar:addr -> int, mchar1:addr -> int, mint:addr -> int, mint1:
      addr -> int, n:int, p:addr, q:addr [Load_S1_X p mchar mint mint1,
@@ -226,10 +228,12 @@ end
     
     (* use map.Map *)
     
-    (* use frama_c_wp.memory.Memory *)
+    (* use frama_c_wp.memaddr.MemAddr *)
     
     (* use Chunk *)
     
+    (* use frama_c_wp.memory.Memory *)
+    
     (* use S1_X *)
     
     (* use Compound *)
@@ -262,12 +266,14 @@ end
     
     (* use map.Map *)
     
-    (* use frama_c_wp.memory.Memory *)
+    (* use frama_c_wp.memaddr.MemAddr *)
     
     (* use S1_X *)
     
     (* use Chunk *)
     
+    (* use frama_c_wp.memory.Memory *)
+    
     (* use Compound *)
     
     goal wp_goal :
diff --git a/src/plugins/wp/tests/wp_acsl/oracle_qualif/user_def_type_guard.2.res.oracle b/src/plugins/wp/tests/wp_acsl/oracle_qualif/user_def_type_guard.2.res.oracle
index 3ad47363a3d0d1f8b1322d46a972f1886968ca8d..4dd7571870e8792ccb83e5393c72d9938a506a54 100644
--- a/src/plugins/wp/tests/wp_acsl/oracle_qualif/user_def_type_guard.2.res.oracle
+++ b/src/plugins/wp/tests/wp_acsl/oracle_qualif/user_def_type_guard.2.res.oracle
@@ -21,7 +21,7 @@ theory Axiomatic1
   
   (* use map.Map *)
   
-  (* use frama_c_wp.memory.Memory *)
+  (* use frama_c_wp.memaddr.MemAddr *)
   
   function L_x (mint:addr -> int) (p:addr) : int = get mint p
 end
@@ -41,7 +41,7 @@ end
     
     (* use map.Map *)
     
-    (* use frama_c_wp.memory.Memory *)
+    (* use frama_c_wp.memaddr.MemAddr *)
     
     (* use Axiomatic1 *)
     
diff --git a/src/plugins/wp/tests/wp_bts/oracle/bts0843.res.oracle b/src/plugins/wp/tests/wp_bts/oracle/bts0843.res.oracle
index bb22d8bc45b0a108885ac01f90e3d684eb08e177..e5be0ef4afa81eb38f9e905b856536f5163e4a97 100644
--- a/src/plugins/wp/tests/wp_bts/oracle/bts0843.res.oracle
+++ b/src/plugins/wp/tests/wp_bts/oracle/bts0843.res.oracle
@@ -39,7 +39,7 @@ Let a = Mptr_0[global(G_p_20)].
 Let a_1 = shiftfield_F1_a(a).
 Assume {
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Goal *)
   When: !invalid(Malloc_0, a_1, 1).
   (* Pre-condition *)
diff --git a/src/plugins/wp/tests/wp_bts/oracle/bts_2110.res.oracle b/src/plugins/wp/tests/wp_bts/oracle/bts_2110.res.oracle
index b0b18afa3218d25c649b9d732df7428e85813d1a..9b86f82b147c87916da165d370fad7fdd4e03c39 100644
--- a/src/plugins/wp/tests/wp_bts/oracle/bts_2110.res.oracle
+++ b/src/plugins/wp/tests/wp_bts/oracle/bts_2110.res.oracle
@@ -52,7 +52,7 @@ theory Compound
   
   (* use map.Map *)
   
-  (* use frama_c_wp.memory.Memory *)
+  (* use frama_c_wp.memaddr.MemAddr *)
   
   function shiftfield_F2_A_dummy (p:addr) : addr = shift p 0
   
@@ -68,6 +68,8 @@ theory Compound
      [Load_S2_A p (set mint q v)].
      not q = p -> Load_S2_A p (set mint q v) = Load_S2_A p mint
   
+  (* use frama_c_wp.memory.Memory *)
+  
   axiom Q_Load_S2_A_eqmem_Mint0 :
     forall mint:addr -> int, mint1:addr -> int, n:int, p:addr, q:addr
      [Load_S2_A p mint, eqmem mint mint1 q n| Load_S2_A p mint1,
@@ -97,7 +99,7 @@ end
     
     (* use map.Map *)
     
-    (* use frama_c_wp.memory.Memory *)
+    (* use frama_c_wp.memaddr.MemAddr *)
     
     (* use Compound *)
     
diff --git a/src/plugins/wp/tests/wp_plugin/bigarray.c b/src/plugins/wp/tests/wp_plugin/bigarray.c
index 96637a1809758f92a16512c00adad0065276dfa6..f243f5d0f68bcf5f98019c8c870e84d1aa16a41c 100644
--- a/src/plugins/wp/tests/wp_plugin/bigarray.c
+++ b/src/plugins/wp/tests/wp_plugin/bigarray.c
@@ -1,21 +1,10 @@
-/* run.config
-   EXIT: 0
-   OPT: -cpp-extra-args="-DFIT"
-   EXIT: 1
-   OPT: -cpp-extra-args="-DLARGE"
- */
-
 /* run.config_qualif
    DONTRUN:
 */
 
 #include <stdint.h>
-#ifdef FIT
+
 #define SIZE (SIZE_MAX / sizeof(int))
-#endif
-#ifdef LARGE
-#define SIZE SIZE_MAX
-#endif
 
 /*@
   assigns \result \from p[0..n-1];
diff --git a/src/plugins/wp/tests/wp_plugin/oracle/bigarray.1.res.oracle b/src/plugins/wp/tests/wp_plugin/oracle/bigarray.1.res.oracle
deleted file mode 100644
index 41201e6e8348610aac541642ec2b5993b45413e1..0000000000000000000000000000000000000000
--- a/src/plugins/wp/tests/wp_plugin/oracle/bigarray.1.res.oracle
+++ /dev/null
@@ -1,12 +0,0 @@
-# frama-c -wp [...]
-[kernel] Parsing bigarray.c (with preprocessing)
-[kernel] bigarray.c:30: Warning: 
-  Cannot represent length of array as an attribute
-[wp] Running WP plugin...
-[wp] [Valid] Goal f_exits (Cfg) (Unreachable)
-[wp] [Valid] Goal f_terminates (Cfg) (Trivial)
-[wp] Warning: Missing RTE guards
-[wp] bigarray.c:30: Warning: Array size too large (0xFFFFFFFFFFFFFFFF)
-[wp] bigarray.c:31: Warning: Array size too large (0xFFFFFFFFFFFFFFFF)
-[wp] bigarray.c:21: User Error: Array size too large (0xFFFFFFFFFFFFFFFF)
-[kernel] Plug-in wp aborted: invalid user input.
diff --git a/src/plugins/wp/tests/wp_plugin/oracle/bigarray.0.res.oracle b/src/plugins/wp/tests/wp_plugin/oracle/bigarray.res.oracle
similarity index 75%
rename from src/plugins/wp/tests/wp_plugin/oracle/bigarray.0.res.oracle
rename to src/plugins/wp/tests/wp_plugin/oracle/bigarray.res.oracle
index d0aae4c8e069ee7f92b2b1db3d91bd19be7c80d7..edc3c3e8bd788ed5f4a240d6366891a8482ce2e2 100644
--- a/src/plugins/wp/tests/wp_plugin/oracle/bigarray.0.res.oracle
+++ b/src/plugins/wp/tests/wp_plugin/oracle/bigarray.res.oracle
@@ -1,6 +1,6 @@
 # frama-c -wp [...]
 [kernel] Parsing bigarray.c (with preprocessing)
-[kernel] bigarray.c:30: Warning: 
+[kernel] bigarray.c:19: Warning: 
   Cannot represent length of array as an attribute
 [wp] Running WP plugin...
 [wp] [Valid] Goal f_exits (Cfg) (Unreachable)
@@ -10,23 +10,23 @@
   Function f
 ------------------------------------------------------------
 
-Goal Loop assigns (file bigarray.c, line 27):
+Goal Loop assigns (file bigarray.c, line 16):
 Prove: true.
 
 ------------------------------------------------------------
 
 Goal Assigns nothing in 'f':
-Effect at line 30
+Effect at line 19
 Prove: true.
 
 ------------------------------------------------------------
 
-Goal Decreasing of Loop variant at loop (file bigarray.c, line 30):
+Goal Decreasing of Loop variant at loop (file bigarray.c, line 19):
 Prove: true.
 
 ------------------------------------------------------------
 
-Goal Positivity of Loop variant at loop (file bigarray.c, line 30):
+Goal Positivity of Loop variant at loop (file bigarray.c, line 19):
 Prove: true.
 
 ------------------------------------------------------------
diff --git a/src/plugins/wp/tests/wp_plugin/oracle/inductive.res.oracle b/src/plugins/wp/tests/wp_plugin/oracle/inductive.res.oracle
index e0b3a051e4e52ab6befe04639843d2ae5f3145d7..8705b618e28ca7a93f722e6f65d12d3bcc2502f2 100644
--- a/src/plugins/wp/tests/wp_plugin/oracle/inductive.res.oracle
+++ b/src/plugins/wp/tests/wp_plugin/oracle/inductive.res.oracle
@@ -20,7 +20,7 @@ theory Compound
   
   (* use map.Map *)
   
-  (* use frama_c_wp.memory.Memory *)
+  (* use frama_c_wp.memaddr.MemAddr *)
   
   function shift_sint32 (p:addr) (k:int) : addr = shift p k
   
@@ -42,7 +42,7 @@ end
     
     (* use map.Map *)
     
-    (* use frama_c_wp.memory.Memory *)
+    (* use frama_c_wp.memaddr.MemAddr *)
     
     (* use Compound *)
     
@@ -79,7 +79,7 @@ end
     
     (* use map.Map *)
     
-    (* use frama_c_wp.memory.Memory *)
+    (* use frama_c_wp.memaddr.MemAddr *)
     
     (* use Compound *)
     
diff --git a/src/plugins/wp/tests/wp_plugin/oracle/model.res.oracle b/src/plugins/wp/tests/wp_plugin/oracle/model.res.oracle
index 7db02668070e5454af37cffbff04a5556d0a7d9f..ee9bc1e90ab5a193c0b57242c70778df7de94e3a 100644
--- a/src/plugins/wp/tests/wp_plugin/oracle/model.res.oracle
+++ b/src/plugins/wp/tests/wp_plugin/oracle/model.res.oracle
@@ -25,7 +25,7 @@ theory Compound
   
   (* use map.Map *)
   
-  (* use frama_c_wp.memory.Memory *)
+  (* use frama_c_wp.memaddr.MemAddr *)
   
   function shift_sint32 (p:addr) (k:int) : addr = shift p k
 end
@@ -65,7 +65,7 @@ end
     
     (* use map.Map *)
     
-    (* use frama_c_wp.memory.Memory *)
+    (* use frama_c_wp.memaddr.MemAddr *)
     
     (* use frama_c_wp.cint.Cint *)
     
@@ -114,7 +114,7 @@ theory Compound1
   
   (* use map.Map1 *)
   
-  (* use frama_c_wp.memory.Memory1 *)
+  (* use frama_c_wp.memaddr.MemAddr1 *)
   
   function shift_sint321 (p:addr1) (k:int) : addr1 = shift1 p k
 end
@@ -154,7 +154,7 @@ end
     
     (* use map.Map1 *)
     
-    (* use frama_c_wp.memory.Memory1 *)
+    (* use frama_c_wp.memaddr.MemAddr1 *)
     
     (* use frama_c_wp.cint.Cint1 *)
     
diff --git a/src/plugins/wp/tests/wp_plugin/oracle_qualif/model.res.oracle b/src/plugins/wp/tests/wp_plugin/oracle_qualif/model.res.oracle
index 3a316233827c1609d8a4c72c8c96bb4c614205db..5e41d21fadff5991d7d2c0b6eec7fdefe0a3d6e6 100644
--- a/src/plugins/wp/tests/wp_plugin/oracle_qualif/model.res.oracle
+++ b/src/plugins/wp/tests/wp_plugin/oracle_qualif/model.res.oracle
@@ -25,7 +25,7 @@ theory Compound
   
   (* use map.Map *)
   
-  (* use frama_c_wp.memory.Memory *)
+  (* use frama_c_wp.memaddr.MemAddr *)
   
   function shift_sint32 (p:addr) (k:int) : addr = shift p k
 end
@@ -65,7 +65,7 @@ end
     
     (* use map.Map *)
     
-    (* use frama_c_wp.memory.Memory *)
+    (* use frama_c_wp.memaddr.MemAddr *)
     
     (* use frama_c_wp.cint.Cint *)
     
@@ -108,7 +108,7 @@ theory Compound1
   
   (* use map.Map1 *)
   
-  (* use frama_c_wp.memory.Memory1 *)
+  (* use frama_c_wp.memaddr.MemAddr1 *)
   
   function shift_sint321 (p:addr1) (k:int) : addr1 = shift1 p k
 end
@@ -148,7 +148,7 @@ end
     
     (* use map.Map1 *)
     
-    (* use frama_c_wp.memory.Memory1 *)
+    (* use frama_c_wp.memaddr.MemAddr1 *)
     
     (* use frama_c_wp.cint.Cint1 *)
     
diff --git a/src/plugins/wp/tests/wp_tip/oracle/split.res.oracle b/src/plugins/wp/tests/wp_tip/oracle/split.res.oracle
index 17b2f4d692c02a76896619f99aa84eb82dddae8b..4a51426aad2d032bde154cb779aa18cd690dd965 100644
--- a/src/plugins/wp/tests/wp_tip/oracle/split.res.oracle
+++ b/src/plugins/wp/tests/wp_tip/oracle/split.res.oracle
@@ -475,7 +475,7 @@
   typed_test_step_fa_or_ensures subgoal:
   
   Goal Wp.Tactical.typed_test_step_fa_or_ensures-0 (generated):
-  Assume { (* Goal 1/2 *) When: forall i : Z. P_Pi(i) \/ P_Qi(i). }
+  Assume { (* Goal 1/2 *) When: P_P \/ P_Q \/ P_R. }
   Prove: P_S.
   
   ------------------------------------------------------------
@@ -483,7 +483,7 @@
   typed_test_step_fa_or_ensures subgoal:
   
   Goal Wp.Tactical.typed_test_step_fa_or_ensures-1 (generated):
-  Assume { (* Goal 2/2 *) When: P_P \/ P_Q \/ P_R. }
+  Assume { (* Goal 2/2 *) When: forall i : Z. P_Pi(i) \/ P_Qi(i). }
   Prove: P_S.
   
   ------------------------------------------------------------
@@ -691,7 +691,7 @@
   
   Goal Wp.Tactical.typed_test_goal_ex_and_ensures-0 (generated):
   Assume { (* Pre-condition *) Have: P_S. }
-  Prove: exists i : Z. P_Pi(i) /\ P_Qi(i).
+  Prove: P_P /\ P_Q.
   
   ------------------------------------------------------------
 [wp:script:allgoals] 
@@ -699,7 +699,7 @@
   
   Goal Wp.Tactical.typed_test_goal_ex_and_ensures-1 (generated):
   Assume { (* Pre-condition *) Have: P_S. }
-  Prove: P_P /\ P_Q.
+  Prove: exists i : Z. P_Pi(i) /\ P_Qi(i).
   
   ------------------------------------------------------------
 [wp] [Unsuccess] typed_test_goal_ex_and_ensures (Tactic) (Qed)
diff --git a/src/plugins/wp/tests/wp_tip/oracle_qualif/pac.res.oracle b/src/plugins/wp/tests/wp_tip/oracle_qualif/pac.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..49efe1a3da3631597d500e68e61bc5f93786e3dc
--- /dev/null
+++ b/src/plugins/wp/tests/wp_tip/oracle_qualif/pac.res.oracle
@@ -0,0 +1,143 @@
+# frama-c -wp [...]
+[kernel] Parsing pac.i (no preprocessing)
+[wp] Running WP plugin...
+[wp] [Valid] Goal target3_no_match_exits (Cfg) (Unreachable)
+[wp] [Valid] Goal target3_no_match_terminates (Cfg) (Trivial)
+[wp] Warning: Missing RTE guards
+[wp] [Valid] Goal target4_exact_match_exits (Cfg) (Unreachable)
+[wp] [Valid] Goal target4_exact_match_terminates (Cfg) (Trivial)
+[wp] [Valid] Goal target5_extra_match_exits (Cfg) (Unreachable)
+[wp] [Valid] Goal target5_extra_match_terminates (Cfg) (Trivial)
+[wp] 6 goals scheduled
+[wp] [NoResult] typed_target3_no_match_ensures_post (Qed)
+[wp] [Valid] typed_target3_no_match_assigns (Qed)
+[wp] [Valid] typed_target4_exact_match_assigns (Qed)
+[wp] [Valid] typed_target5_extra_match_assigns (Qed)
+[wp] [Unsuccess] typed_target4_exact_match_ensures_post (Tactic) (Qed)
+[wp] [Unsuccess] typed_target5_extra_match_ensures_post (Tactic) (Qed)
+[wp] Proved goals:    9 / 12
+  Terminating:     3
+  Unreachable:     3
+  Qed:             3
+  Unsuccess:       3
+  Missing:         1
+------------------------------------------------------------
+  Function target3_no_match
+------------------------------------------------------------
+
+Goal Post-condition 'post' in 'target3_no_match':
+Assume {
+  Type: is_sint32(x) /\ is_sint32(y) /\ is_sint32(z).
+  (* Pre-condition *)
+  Have: (x != 0) \/ (y != 0) \/ (z != 0).
+}
+Prove: false.
+
+------------------------------------------------------------
+------------------------------------------------------------
+  Function target4_exact_match
+------------------------------------------------------------
+
+Goal Post-condition 'post' in 'target4_exact_match':
+Assume {
+  Type: is_sint32(r) /\ is_sint32(x) /\ is_sint32(y) /\ is_sint32(z).
+  (* Pre-condition *)
+  Have: (r != 0) \/ (x != 0) \/ (y != 0) \/ (z != 0).
+}
+Prove: false.
+Prover Script returns Unsuccess
+
+------------------------------------------------------------
+Subgoal 1/4:
+ - Post-condition 'post'
+ - Split (Case 1/4)
+Goal Wp.Tactical.typed_target4_exact_match_ensures_post-0 (generated):
+Assume { Type: is_sint32(r). (* Case 1/4 *) When: r != 0. }
+Prove: false.
+
+------------------------------------------------------------
+Subgoal 2/4:
+ - Post-condition 'post'
+ - Split (Case 2/4)
+Goal Wp.Tactical.typed_target4_exact_match_ensures_post-1 (generated):
+Assume { Type: is_sint32(x). (* Case 2/4 *) When: x != 0. }
+Prove: false.
+
+------------------------------------------------------------
+Subgoal 3/4:
+ - Post-condition 'post'
+ - Split (Case 3/4)
+Goal Wp.Tactical.typed_target4_exact_match_ensures_post-2 (generated):
+Assume { Type: is_sint32(y). (* Case 3/4 *) When: y != 0. }
+Prove: false.
+
+------------------------------------------------------------
+Subgoal 4/4:
+ - Post-condition 'post'
+ - Split (Case 4/4)
+Goal Wp.Tactical.typed_target4_exact_match_ensures_post-3 (generated):
+Assume { Type: is_sint32(z). (* Case 4/4 *) When: z != 0. }
+Prove: false.
+
+------------------------------------------------------------
+------------------------------------------------------------
+  Function target5_extra_match
+------------------------------------------------------------
+
+Goal Post-condition 'post' in 'target5_extra_match':
+Assume {
+  Type: is_sint32(r) /\ is_sint32(s) /\ is_sint32(x) /\ is_sint32(y) /\
+      is_sint32(z).
+  (* Pre-condition *)
+  Have: (r != 0) \/ (s != 0) \/ (x != 0) \/ (y != 0) \/ (z != 0).
+}
+Prove: false.
+Prover Script returns Unsuccess
+
+------------------------------------------------------------
+Subgoal 1/5:
+ - Post-condition 'post'
+ - Split (Case 1/5)
+Goal Wp.Tactical.typed_target5_extra_match_ensures_post-0 (generated):
+Assume { Type: is_sint32(r). (* Case 1/5 *) When: r != 0. }
+Prove: false.
+
+------------------------------------------------------------
+Subgoal 2/5:
+ - Post-condition 'post'
+ - Split (Case 2/5)
+Goal Wp.Tactical.typed_target5_extra_match_ensures_post-1 (generated):
+Assume { Type: is_sint32(s). (* Case 2/5 *) When: s != 0. }
+Prove: false.
+
+------------------------------------------------------------
+Subgoal 3/5:
+ - Post-condition 'post'
+ - Split (Case 3/5)
+Goal Wp.Tactical.typed_target5_extra_match_ensures_post-2 (generated):
+Assume { Type: is_sint32(x). (* Case 3/5 *) When: x != 0. }
+Prove: false.
+
+------------------------------------------------------------
+Subgoal 4/5:
+ - Post-condition 'post'
+ - Split (Case 4/5)
+Goal Wp.Tactical.typed_target5_extra_match_ensures_post-3 (generated):
+Assume { Type: is_sint32(y). (* Case 4/5 *) When: y != 0. }
+Prove: false.
+
+------------------------------------------------------------
+Subgoal 5/5:
+ - Post-condition 'post'
+ - Split (Case 5/5)
+Goal Wp.Tactical.typed_target5_extra_match_ensures_post-4 (generated):
+Assume { Type: is_sint32(z). (* Case 5/5 *) When: z != 0. }
+Prove: false.
+
+------------------------------------------------------------
+------------------------------------------------------------
+ Functions                 WP     Alt-Ergo  Total   Success
+  target3_no_match          1        -        2      50.0%
+  target4_exact_match       1        -        2      50.0%
+  target5_extra_match       1        -        2      50.0%
+------------------------------------------------------------
diff --git a/src/plugins/wp/tests/wp_tip/pac.i b/src/plugins/wp/tests/wp_tip/pac.i
new file mode 100644
index 0000000000000000000000000000000000000000..78106ed2ac1214873dbe6f7c639c7c8336516c78
--- /dev/null
+++ b/src/plugins/wp/tests/wp_tip/pac.i
@@ -0,0 +1,36 @@
+/* run.config
+   DONTRUN:
+*/
+
+/* run.config_qualif
+   OPT: -wp-status -wp-prover tip -wp-script dry
+ */
+
+/*@
+  strategy Split4:
+    \tactic("Wp.split"
+      ,\pattern( _ || _ || _ || _ )
+    );
+  proof Split4: post;
+*/
+
+/*@
+  requires x || y || z;
+  ensures post: \false;
+  assigns \nothing;
+*/
+void target3_no_match(int x, int y, int z) { return; }
+
+/*@
+  requires x || y || z || r;
+  ensures post: \false;
+  assigns \nothing;
+*/
+void target4_exact_match(int x, int y, int z, int r) { return; }
+
+/*@
+  requires x || y || z || r || s;
+  ensures post: \false;
+  assigns \nothing;
+*/
+void target5_extra_match(int x, int y, int z, int r, int s) { return; }
diff --git a/src/plugins/wp/tests/wp_typed/oracle/array_initialized.1.res.oracle b/src/plugins/wp/tests/wp_typed/oracle/array_initialized.1.res.oracle
index 276a519cb4af75159523a97ca1a56b148dbfa76e..3220f8249fa637918bb762119c9d617002cc6cc3 100644
--- a/src/plugins/wp/tests/wp_typed/oracle/array_initialized.1.res.oracle
+++ b/src/plugins/wp/tests/wp_typed/oracle/array_initialized.1.res.oracle
@@ -265,7 +265,7 @@ Goal Assertion (file array_initialized.c, line 283):
 Let a = global(K_p_34).
 Assume {
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Goal *)
   When: (0 <= i) /\ (i <= 499).
   (* Initializer *)
diff --git a/src/plugins/wp/tests/wp_typed/oracle/frame.0.res.oracle b/src/plugins/wp/tests/wp_typed/oracle/frame.0.res.oracle
index 3304372daa264226c76184055f11cf12ac33341f..b9c15212aa337d0ee7c40a55c780bff68098d014 100644
--- a/src/plugins/wp/tests/wp_typed/oracle/frame.0.res.oracle
+++ b/src/plugins/wp/tests/wp_typed/oracle/frame.0.res.oracle
@@ -52,7 +52,7 @@ Goal Assertion 'A,X' (file frame.i, line 34):
 Let a = Mptr_0[global(L_x_37)].
 Assume {
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Initializer *)
   Init: a = shiftfield_F2_S_b(global(P_s_36)).
 }
@@ -64,7 +64,7 @@ Goal Assertion 'A,Y' (file frame.i, line 35):
 Let a = Mptr_0[global(L_x_37)].
 Assume {
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Initializer *)
   Init: a = shiftfield_F2_S_b(global(P_s_36)).
   (* Assertion 'A,X' *)
@@ -81,7 +81,7 @@ Goal Assertion 'A,X' (file frame.i, line 25):
 Let a = Mptr_0[global(L_x_32)].
 Assume {
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Initializer *)
   Init: a = shift_sint8(global(L_b_31), 0).
 }
@@ -93,7 +93,7 @@ Goal Assertion 'A,Y' (file frame.i, line 26):
 Let a = Mptr_0[global(L_x_32)].
 Assume {
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Initializer *)
   Init: a = shift_sint8(global(L_b_31), 0).
   (* Assertion 'A,X' *)
diff --git a/src/plugins/wp/tests/wp_typed/oracle/frame.1.res.oracle b/src/plugins/wp/tests/wp_typed/oracle/frame.1.res.oracle
index 8b0ea16e32ef953268d9cac73ff69b01f1dd07a3..2e3d693fe257f10d9efed06a58e2506ff85a88e4 100644
--- a/src/plugins/wp/tests/wp_typed/oracle/frame.1.res.oracle
+++ b/src/plugins/wp/tests/wp_typed/oracle/frame.1.res.oracle
@@ -52,7 +52,7 @@ Goal Assertion 'A,X' (file frame.i, line 34):
 Let a = Mptr_0[global(L_x_37)].
 Assume {
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Initializer *)
   Init: a = shiftfield_F2_S_b(global(P_s_36)).
 }
@@ -64,7 +64,7 @@ Goal Assertion 'A,Y' (file frame.i, line 35):
 Let a = Mptr_0[global(L_x_37)].
 Assume {
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Initializer *)
   Init: a = shiftfield_F2_S_b(global(P_s_36)).
   (* Assertion 'A,X' *)
@@ -81,7 +81,7 @@ Goal Assertion 'A,X' (file frame.i, line 25):
 Let a = Mptr_0[global(L_x_32)].
 Assume {
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Initializer *)
   Init: a = shift_sint8(global(L_b_31), 0).
 }
@@ -93,7 +93,7 @@ Goal Assertion 'A,Y' (file frame.i, line 26):
 Let a = Mptr_0[global(L_x_32)].
 Assume {
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Initializer *)
   Init: a = shift_sint8(global(L_b_31), 0).
   (* Assertion 'A,X' *)
diff --git a/src/plugins/wp/tests/wp_typed/oracle/multi_matrix_types.res.oracle b/src/plugins/wp/tests/wp_typed/oracle/multi_matrix_types.res.oracle
index d1a36bd6df85721c2bbe1f11da15e714d5bb0b40..d12ad08ff0605a1f2fe73b3aa46ff670b4065553 100644
--- a/src/plugins/wp/tests/wp_typed/oracle/multi_matrix_types.res.oracle
+++ b/src/plugins/wp/tests/wp_typed/oracle/multi_matrix_types.res.oracle
@@ -81,7 +81,7 @@ theory Compound
   
   (* use map.Map *)
   
-  (* use frama_c_wp.memory.Memory *)
+  (* use frama_c_wp.memaddr.MemAddr *)
   
   function shiftfield_F1_S_f (p:addr) : addr = shift p 0
   
@@ -116,6 +116,8 @@ theory Compound
      [Array_uint32 p n (set mint q v)].
      not q = p -> Array_uint32 p n (set mint q v) = Array_uint32 p n mint
   
+  (* use frama_c_wp.memory.Memory *)
+  
   axiom Q_Array_uint32_eqmem_Mint0 :
     forall mint:addr -> int, mint1:addr -> int, n:int, n1:int, p:addr, q:addr
      [Array_uint32 p n mint, eqmem mint mint1 q n1| Array_uint32 p n mint1,
@@ -238,7 +240,7 @@ end
     
     (* use map.Map *)
     
-    (* use frama_c_wp.memory.Memory *)
+    (* use frama_c_wp.memaddr.MemAddr *)
     
     (* use S1_S *)
     
diff --git a/src/plugins/wp/tests/wp_typed/oracle/too_large_array.0.res.oracle b/src/plugins/wp/tests/wp_typed/oracle/too_large_array.0.res.oracle
deleted file mode 100644
index 7185f12777a04c6c3fb349320214af3da92c505a..0000000000000000000000000000000000000000
--- a/src/plugins/wp/tests/wp_typed/oracle/too_large_array.0.res.oracle
+++ /dev/null
@@ -1,12 +0,0 @@
-# frama-c -wp [...]
-[kernel] Parsing too_large_array.i (no preprocessing)
-[kernel] too_large_array.i:12: Warning: 
-  Cannot represent length of array as an attribute
-[wp] Running WP plugin...
-[wp] [Valid] Goal merge_exits (Cfg) (Unreachable)
-[wp] Warning: Missing RTE guards
-[wp] too_large_array.i:13: Warning: Array size too large (0xFFFFFFFFFFFFFFFF)
-[wp] too_large_array.i:14: Warning: 
-  Missing assigns clause (assigns 'everything' instead)
-[wp] too_large_array.i:11: User Error: Array size too large (0xFFFFFFFFFFFFFFFF)
-[kernel] Plug-in wp aborted: invalid user input.
diff --git a/src/plugins/wp/tests/wp_typed/oracle/too_large_array.1.res.oracle b/src/plugins/wp/tests/wp_typed/oracle/too_large_array.1.res.oracle
deleted file mode 100644
index 9d95ea7570c68ed69fbb86d77f665ba8fa95ce38..0000000000000000000000000000000000000000
--- a/src/plugins/wp/tests/wp_typed/oracle/too_large_array.1.res.oracle
+++ /dev/null
@@ -1,12 +0,0 @@
-# frama-c -wp -wp-model 'Typed (Ref)' [...]
-[kernel] Parsing too_large_array.i (no preprocessing)
-[kernel] too_large_array.i:12: Warning: 
-  Cannot represent length of array as an attribute
-[wp] Running WP plugin...
-[wp] [Valid] Goal merge_exits (Cfg) (Unreachable)
-[wp] Warning: Missing RTE guards
-[wp] too_large_array.i:13: Warning: Array size too large (0xFFFFFFFFFFFFFFFF)
-[wp] too_large_array.i:14: Warning: 
-  Missing assigns clause (assigns 'everything' instead)
-[wp] too_large_array.i:11: User Error: Array size too large (0xFFFFFFFFFFFFFFFF)
-[kernel] Plug-in wp aborted: invalid user input.
diff --git a/src/plugins/wp/tests/wp_typed/oracle_qualif/unit_string.res.oracle b/src/plugins/wp/tests/wp_typed/oracle_qualif/unit_string.res.oracle
index 9f67668adc8406b1a0f9382b45f032b7216d5f4d..05e2c69bcbb89ddc09111eba69bafec24230938b 100644
--- a/src/plugins/wp/tests/wp_typed/oracle_qualif/unit_string.res.oracle
+++ b/src/plugins/wp/tests/wp_typed/oracle_qualif/unit_string.res.oracle
@@ -5,11 +5,314 @@
 [wp] [Valid] Goal f_terminates (Cfg) (Trivial)
 [wp] Warning: Missing RTE guards
 [wp] 6 goals scheduled
+---------------------------------------------
+--- Context 'typed_f' Cluster 'Compound' 
+---------------------------------------------
+theory Compound
+  (* use why3.BuiltIn.BuiltIn *)
+  
+  (* use bool.Bool *)
+  
+  (* use int.Int *)
+  
+  (* use int.ComputerDivision *)
+  
+  (* use real.RealInfix *)
+  
+  (* use frama_c_wp.qed.Qed *)
+  
+  (* use map.Map *)
+  
+  (* use frama_c_wp.memaddr.MemAddr *)
+  
+  function shift_sint8 (p:addr) (k:int) : addr = shift p k
+end
+---------------------------------------------
+--- Context 'typed_f' Cluster 'cstring' 
+---------------------------------------------
+theory Cstring
+  (* use why3.BuiltIn.BuiltIn *)
+  
+  (* use bool.Bool *)
+  
+  (* use int.Int *)
+  
+  (* use int.ComputerDivision *)
+  
+  (* use real.RealInfix *)
+  
+  (* use frama_c_wp.qed.Qed *)
+  
+  (* use map.Map *)
+  
+  constant Str_1 : int
+  
+  constant Lit_75AD : int -> int
+  
+  constant Str_2 : int
+  
+  constant Lit_6152 : int -> int
+  
+  constant Str_3 : int
+  
+  constant Str_4 : int
+  
+  constant Lit_7BA4 : int -> int
+  
+  axiom Q_Str_1_base : Str_1 < 0
+  
+  axiom Q_Lit_75AD_literal :
+    (((((get Lit_75AD 0 = 97 /\ get Lit_75AD 1 = 98) /\ get Lit_75AD 2 = 99) /\
+       get Lit_75AD 3 = 100) /\
+      get Lit_75AD 4 = 101) /\
+     get Lit_75AD 5 = 102) /\
+    get Lit_75AD 6 = 0
+  
+  (* use frama_c_wp.memaddr.MemAddr *)
+  
+  axiom Q_Str_1_region : region Str_1 = (- 30125)
+  
+  axiom Q_Str_1_linked : forall t:int -> int. linked t -> get t Str_1 = 7
+  
+  (* use frama_c_wp.memory.Memory *)
+  
+  (* use Compound *)
+  
+  axiom Q_Str_1_literal :
+    forall mchar:addr -> int, i:int.
+     sconst mchar ->
+     get mchar (shift_sint8 (global Str_1) i) = get Lit_75AD i
+  
+  axiom Q_Str_2_base : Str_2 < 0
+  
+  axiom Q_Lit_6152_literal :
+    ((get Lit_6152 0 = 100 /\ get Lit_6152 1 = 101) /\ get Lit_6152 2 = 102) /\
+    get Lit_6152 3 = 0
+  
+  axiom Q_Str_2_region : region Str_2 = (- 24914)
+  
+  axiom Q_Str_2_linked : forall t:int -> int. linked t -> get t Str_2 = 4
+  
+  axiom Q_Str_2_literal :
+    forall mchar:addr -> int, i:int.
+     sconst mchar ->
+     get mchar (shift_sint8 (global Str_2) i) = get Lit_6152 i
+  
+  axiom Q_Str_3_base : Str_3 < 0
+  
+  axiom Q_Str_3_region : region Str_3 = (- 24914)
+  
+  axiom Q_Str_3_linked : forall t:int -> int. linked t -> get t Str_3 = 4
+  
+  axiom Q_Str_3_literal :
+    forall mchar:addr -> int, i:int.
+     sconst mchar ->
+     get mchar (shift_sint8 (global Str_3) i) = get Lit_6152 i
+  
+  axiom Q_Str_4_base : Str_4 < 0
+  
+  axiom Q_Lit_7BA4_literal :
+    ((get Lit_7BA4 0 = 97 /\ get Lit_7BA4 1 = 98) /\ get Lit_7BA4 2 = 99) /\
+    get Lit_7BA4 3 = 0
+  
+  axiom Q_Str_4_region : region Str_4 = (- 31652)
+  
+  axiom Q_Str_4_linked : forall t:int -> int. linked t -> get t Str_4 = 4
+  
+  axiom Q_Str_4_literal :
+    forall mchar:addr -> int, i:int.
+     sconst mchar ->
+     get mchar (shift_sint8 (global Str_4) i) = get Lit_7BA4 i
+end
+[wp:print-generated] 
+  theory WP
+    (* use why3.BuiltIn.BuiltIn *)
+    
+    (* use bool.Bool *)
+    
+    (* use int.Int *)
+    
+    (* use int.ComputerDivision *)
+    
+    (* use real.RealInfix *)
+    
+    (* use frama_c_wp.qed.Qed *)
+    
+    (* use map.Map *)
+    
+    (* use Cstring *)
+    
+    goal wp_goal : not Str_4 = Str_3
+  end
 [wp] [Valid] typed_f_assert_AB (Alt-Ergo) (Cached)
+[wp:print-generated] 
+  theory WP1
+    (* use why3.BuiltIn.BuiltIn *)
+    
+    (* use bool.Bool *)
+    
+    (* use int.Int *)
+    
+    (* use int.ComputerDivision *)
+    
+    (* use real.RealInfix *)
+    
+    (* use frama_c_wp.qed.Qed *)
+    
+    (* use map.Map *)
+    
+    (* use Cstring *)
+    
+    goal wp_goal :
+      forall t:int -> int.
+       not Str_4 = Str_3 ->
+       linked t -> valid_rd t (shift_sint8 (global Str_3) 0) 3
+  end
 [wp] [Valid] typed_f_assert_B_valid (Alt-Ergo) (Cached)
+[wp:print-generated] 
+  theory WP2
+    (* use why3.BuiltIn.BuiltIn *)
+    
+    (* use bool.Bool *)
+    
+    (* use int.Int *)
+    
+    (* use int.ComputerDivision *)
+    
+    (* use real.RealInfix *)
+    
+    (* use frama_c_wp.qed.Qed *)
+    
+    (* use map.Map *)
+    
+    (* use frama_c_wp.memaddr.MemAddr *)
+    
+    (* use Cstring *)
+    
+    (* use frama_c_wp.cint.Cint *)
+    
+    goal wp_goal :
+      let a = global Str_3 in
+      let a1 = shift_sint8 a 3 in
+      forall t:int -> int, t1:addr -> int.
+       let a2 = a in
+       let a3 = a1 in
+       let x = get t1 a3 in
+       not Str_4 = Str_3 ->
+       linked t ->
+       sconst t1 ->
+       is_sint8 x ->
+       valid_rd t (shift_sint8 a2 0) 3 -> x = 0 /\ valid_rd t a3 1
+  end
 [wp] [Valid] typed_f_assert_B_end (Alt-Ergo) (Cached)
+[wp:print-generated] 
+  theory WP3
+    (* use why3.BuiltIn.BuiltIn *)
+    
+    (* use bool.Bool *)
+    
+    (* use int.Int *)
+    
+    (* use int.ComputerDivision *)
+    
+    (* use real.RealInfix *)
+    
+    (* use frama_c_wp.qed.Qed *)
+    
+    (* use map.Map *)
+    
+    (* use frama_c_wp.memaddr.MemAddr *)
+    
+    (* use Cstring *)
+    
+    goal wp_goal :
+      let a = global Str_3 in
+      let a1 = shift_sint8 a 3 in
+      forall t:int -> int, t1:addr -> int.
+       let a2 = a in
+       let a3 = a1 in
+       not Str_4 = Str_3 ->
+       get t1 a3 = 0 ->
+       linked t ->
+       sconst t1 ->
+       valid_rd t (shift_sint8 a2 0) 3 ->
+       valid_rd t a3 1 -> not valid_rd t (shift_sint8 a2 4) 1
+  end
 [wp] [Valid] typed_f_assert_B_out (Alt-Ergo) (Cached)
+[wp:print-generated] 
+  theory WP4
+    (* use why3.BuiltIn.BuiltIn *)
+    
+    (* use bool.Bool *)
+    
+    (* use int.Int *)
+    
+    (* use int.ComputerDivision *)
+    
+    (* use real.RealInfix *)
+    
+    (* use frama_c_wp.qed.Qed *)
+    
+    (* use map.Map *)
+    
+    (* use frama_c_wp.memaddr.MemAddr *)
+    
+    (* use Cstring *)
+    
+    goal wp_goal :
+      let a = global Str_3 in
+      let a1 = shift_sint8 a 3 in
+      forall t:int -> int, t1:addr -> int.
+       let a2 = a in
+       let a3 = a1 in
+       not Str_4 = Str_3 ->
+       get t1 a3 = 0 ->
+       linked t ->
+       sconst t1 ->
+       valid_rd t (shift_sint8 a2 0) 3 ->
+       valid_rd t a3 1 ->
+       not valid_rd t (shift_sint8 a2 4) 1 ->
+       not valid_rw t (shift_sint8 a2 1) 1
+  end
 [wp] [Valid] typed_f_assert_B_rw (Alt-Ergo) (Cached)
+[wp:print-generated] 
+  theory WP5
+    (* use why3.BuiltIn.BuiltIn *)
+    
+    (* use bool.Bool *)
+    
+    (* use int.Int *)
+    
+    (* use int.ComputerDivision *)
+    
+    (* use real.RealInfix *)
+    
+    (* use frama_c_wp.qed.Qed *)
+    
+    (* use map.Map *)
+    
+    (* use frama_c_wp.memaddr.MemAddr *)
+    
+    (* use Cstring *)
+    
+    goal wp_goal :
+      let a = global Str_3 in
+      let a1 = shift_sint8 a 3 in
+      forall t:int -> int, t1:addr -> int, i:int.
+       let a2 = a in
+       let a3 = a1 in
+       not Str_4 = Str_3 ->
+       get t1 a3 = 0 ->
+       0 <= i ->
+       i <= 2 ->
+       linked t ->
+       sconst t1 ->
+       valid_rd t (shift_sint8 a2 0) 3 ->
+       valid_rd t a3 1 ->
+       not valid_rd t (shift_sint8 a2 4) 1 ->
+       not valid_rw t (shift_sint8 a2 1) 1 ->
+       get t1 (shift_sint8 (global Str_1) (3 + i)) = get t1 (shift_sint8 a2 i)
+  end
 [wp] [Valid] typed_f_assert_VAL (Alt-Ergo) (Cached)
 [wp] Proved goals:    8 / 8
   Terminating:     1
diff --git a/src/plugins/wp/tests/wp_typed/unit_string.i b/src/plugins/wp/tests/wp_typed/unit_string.i
index 16e907a20914644ecb17fd5fc4eac077136a5ac2..a5b2006e6f945300028ad455cf625149a0b8d801 100644
--- a/src/plugins/wp/tests/wp_typed/unit_string.i
+++ b/src/plugins/wp/tests/wp_typed/unit_string.i
@@ -1,5 +1,5 @@
 /* run.config_qualif
-   OPT: -wp-literals
+   OPT: -wp-literals -wp-msg-key print-generated
 */
 
 void f(void)
diff --git a/src/plugins/wp/tests/wp_usage/oracle/global.0.res.oracle b/src/plugins/wp/tests/wp_usage/oracle/global.0.res.oracle
index 564cf3d6ec4468b8f9e6322b4aa1cda2a977d7ee..596f28a8c0dd0200f5ea3914db799a12271663ed 100644
--- a/src/plugins/wp/tests/wp_usage/oracle/global.0.res.oracle
+++ b/src/plugins/wp/tests/wp_usage/oracle/global.0.res.oracle
@@ -12,7 +12,7 @@ Goal Assertion 'no_address_taken' (file global.c, line 17):
 Let a = Mptr_0[global(P_a_23)].
 Assume {
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Pre-condition *)
   Have: valid_rw(Malloc_0, a, 1).
 }
diff --git a/src/plugins/wp/tests/wp_usage/oracle/issue-189-bis.0.res.oracle b/src/plugins/wp/tests/wp_usage/oracle/issue-189-bis.0.res.oracle
index 492892655e7a24f04f8a0aa36f7383688786aec2..78be9b03031296ebcc358cecff7e9a2dafa3ce59 100644
--- a/src/plugins/wp/tests/wp_usage/oracle/issue-189-bis.0.res.oracle
+++ b/src/plugins/wp/tests/wp_usage/oracle/issue-189-bis.0.res.oracle
@@ -19,7 +19,7 @@ Let a_4 = shift_uint8(a_3, 0).
 Assume {
   Type: is_sint32(len_0) /\ is_sint32(len_1).
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Goal *)
   When: (0 <= i) /\ ((2 + i) <= len_0).
   (* Pre-condition 'write_access' *)
@@ -54,7 +54,7 @@ Let a_5 = shift_uint8(a_3, i).
 Assume {
   Type: is_sint32(len_0) /\ is_sint32(len_1).
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Goal *)
   When: (0 <= i) /\ ((2 + i) <= len_0).
   (* Pre-condition 'write_access' *)
@@ -89,7 +89,7 @@ Let a_5 = a_2[v <- a_2[v_1]].
 Assume {
   Type: is_sint32(len_0) /\ is_sint32(len_1) /\ is_sint32(len_1 - 1).
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Goal *)
   When: (0 <= i) /\ ((i + len_1) <= len_0).
   (* Pre-condition 'write_access' *)
@@ -140,7 +140,7 @@ Let a_4 = shift_uint8(a_3, 0).
 Assume {
   Type: is_sint32(len_1) /\ is_sint32(len_0) /\ is_sint32(len_0 - 1).
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Pre-condition 'write_access' *)
   Have: valid_rw(Malloc_0, a_1, len_1).
   (* Pre-condition 'read_access' *)
@@ -208,7 +208,7 @@ Let a_7 = shift_uint8(a_6, 0).
 Assume {
   Type: is_sint32(len_0) /\ is_sint32(len_1) /\ is_sint32(len_1 - 1).
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Goal *)
   When: !invalid(Malloc_0[P_src_24 <- 1][P_dst_25 <- 1], v, 1).
   (* Pre-condition 'write_access' *)
@@ -266,7 +266,7 @@ Let a_4 = shift_uint8(a_3, 0).
 Assume {
   Type: is_sint32(len_0) /\ is_sint32(len_1).
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Goal *)
   When: (0 <= i) /\ ((2 + i) <= len_0).
   (* Pre-condition 'write_access' *)
@@ -301,7 +301,7 @@ Let a_5 = shift_uint8(a_3, i).
 Assume {
   Type: is_sint32(len_0) /\ is_sint32(len_1).
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Goal *)
   When: (0 <= i) /\ ((2 + i) <= len_0).
   (* Pre-condition 'write_access' *)
@@ -336,7 +336,7 @@ Let a_5 = a_2[dst2_0 <- a_2[src2_0]].
 Assume {
   Type: is_sint32(len_0) /\ is_sint32(len_1) /\ is_sint32(len_1 - 1).
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Goal *)
   When: (0 <= i) /\ ((i + len_1) <= len_0).
   (* Pre-condition 'write_access' *)
@@ -387,7 +387,7 @@ Let a_4 = shift_uint8(a_3, 0).
 Assume {
   Type: is_sint32(len_1) /\ is_sint32(len_0) /\ is_sint32(len_0 - 1).
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Pre-condition 'write_access' *)
   Have: valid_rw(Malloc_0, a_1, len_1).
   (* Pre-condition 'read_access' *)
@@ -453,7 +453,7 @@ Let a_5 = shift_uint8(a_4, 0).
 Assume {
   Type: is_sint32(len_0) /\ is_sint32(len_1) /\ is_sint32(len_1 - 1).
   (* Heap *)
-  Type: framed(Mptr_0) /\ linked(Malloc_0).
+  Type: linked(Malloc_0) /\ framed(Mptr_0).
   (* Goal *)
   When: !invalid(Malloc_0[P_src_47 <- 1][P_dst_48 <- 1], tmp_0, 1).
   (* Pre-condition 'write_access' *)
diff --git a/src/plugins/wp/wpPropId.ml b/src/plugins/wp/wpPropId.ml
index c025c2b827997958d4f393738a1d22772495984c..2cce251f7c31daa2ede5dfb2e76136e53e23dd7c 100644
--- a/src/plugins/wp/wpPropId.ml
+++ b/src/plugins/wp/wpPropId.ml
@@ -622,7 +622,7 @@ let rec term_hints hs t =
   match t.term_node with
   | TLval(lv,_) -> lval_hints hs lv
   | TAddrOf(lv,_) -> lval_hints hs lv
-  | TCastE(_,t) -> term_hints hs t
+  | TCast (false, Ctype _,t) -> term_hints hs t
   | TBinOp((PlusPI|MinusPI),a,_) -> term_hints hs a
   | Tlet(_,t) -> term_hints hs t
   | _ -> ()
diff --git a/tests/builtins/oracle/alloc.0.res.oracle b/tests/builtins/oracle/alloc.0.res.oracle
index 3ef4276dae84fa303cf368b3375377e8ac2e783b..684b949a466e6344892b87d74be20242abcbd010 100644
--- a/tests/builtins/oracle/alloc.0.res.oracle
+++ b/tests/builtins/oracle/alloc.0.res.oracle
@@ -39,8 +39,7 @@
 [eva:alarm] alloc.c:26: Warning: 
   signed overflow. assert -((int)q) ≤ 2147483647;
 [eva:garbled-mix:write] alloc.c:26: 
-  Assigning imprecise value to r.
-  The imprecision originates from Arithmetic {alloc.c:26}
+  Assigning imprecise value to r because of arithmetic operation on addresses.
 [eva:alarm] alloc.c:27: Warning: out of bounds write. assert \valid(r);
 [eva:alarm] alloc.c:27: Warning: out of bounds read. assert \valid_read(r + 1);
 [eva] alloc.c:32: Call to builtin malloc
@@ -65,6 +64,10 @@
   all target addresses were invalid. This path is assumed to be dead.
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    alloc.c:26: arithmetic operation on addresses
+      (read 3 times, propagated 1 times) garbled mix of &{__malloc_main_l25}
 [eva] alloc.c:18: assertion 'Eva,mem_access' got final status invalid.
 [eva] alloc.c:19: assertion 'Eva,mem_access' got final status invalid.
 [eva] alloc.c:20: assertion 'Eva,mem_access' got final status invalid.
diff --git a/tests/builtins/oracle/alloc.1.res.oracle b/tests/builtins/oracle/alloc.1.res.oracle
index d2683593c4b609727030a1db6ff6813ea4a0f654..3ce9953a7b83089a4d07f17bbecd883f451dca85 100644
--- a/tests/builtins/oracle/alloc.1.res.oracle
+++ b/tests/builtins/oracle/alloc.1.res.oracle
@@ -22,8 +22,7 @@
 [eva:alarm] alloc.c:51: Warning: 
   signed overflow. assert -((int)q) ≤ 2147483647;
 [eva:garbled-mix:write] alloc.c:51: 
-  Assigning imprecise value to r.
-  The imprecision originates from Arithmetic {alloc.c:51}
+  Assigning imprecise value to r because of arithmetic operation on addresses.
 [eva:alarm] alloc.c:54: Warning: out of bounds write. assert \valid(r);
 [eva:alarm] alloc.c:54: Warning: 
   pointer downcast. assert (unsigned int)r ≤ 2147483647;
@@ -31,11 +30,16 @@
 [eva:alarm] alloc.c:56: Warning: signed overflow. assert *q + 1 ≤ 2147483647;
 [eva] Recording results for main_abs
 [eva] Done for function main_abs
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    alloc.c:51: arithmetic operation on addresses
+      (read 2 times, propagated 1 times)
+      garbled mix of &{__malloc_main_abs_l50}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main_abs:
   NULL[rbits 2048 to 4103] ∈
       {{ garbled mix of &{__malloc_main_abs_l50}
-       (origin: Misaligned {alloc.c:54}) }}
+       (origin: Misaligned write {alloc.c:54}) }}
   __fc_heap_status ∈ [--..--]
   q ∈ {{ &__malloc_main_abs_l50 }}
   r ∈ {{ NULL + [256..509] ; &__malloc_main_abs_l50 }}
diff --git a/tests/builtins/oracle/imprecise-malloc-free.res.oracle b/tests/builtins/oracle/imprecise-malloc-free.res.oracle
index 2d02014061a0fa9b8a3b45c488f4446d6f17f178..4cd01a4b78eb93961e52f4939f1736ed257095bb 100644
--- a/tests/builtins/oracle/imprecise-malloc-free.res.oracle
+++ b/tests/builtins/oracle/imprecise-malloc-free.res.oracle
@@ -13,10 +13,13 @@
 [eva:alarm] imprecise-malloc-free.c:13: Warning: 
   signed overflow. assert i + (int)((int)(&size2) >> 1) ≤ 2147483647;
 [eva:garbled-mix:write] imprecise-malloc-free.c:13: 
-  Assigning imprecise value to size2.
-  The imprecision originates from Arithmetic {imprecise-malloc-free.c:13}
+  Assigning imprecise value to size2
+  because of arithmetic operation on addresses.
 [eva:alarm] imprecise-malloc-free.c:14: Warning: 
   pointer downcast. assert (unsigned int)(&i) ≤ 2147483647;
+[eva:garbled-mix:write] imprecise-malloc-free.c:14: 
+  Assigning imprecise value to size
+  because of arithmetic operation on addresses.
 [eva] imprecise-malloc-free.c:14: Call to builtin malloc
 [eva] imprecise-malloc-free.c:14: allocating variable __malloc_main_l14
 [eva] imprecise-malloc-free.c:15: Call to builtin malloc
@@ -44,12 +47,16 @@
   pointer downcast. assert (unsigned int)(r + 3) ≤ 2147483647;
 [eva:alarm] imprecise-malloc-free.c:25: Warning: 
   pointer downcast. assert (unsigned int)p ≤ 2147483647;
+[eva:garbled-mix:write] imprecise-malloc-free.c:25: 
+  Assigning imprecise value to p because of arithmetic operation on addresses.
 [eva] imprecise-malloc-free.c:25: Call to builtin free
 [eva:alarm] imprecise-malloc-free.c:25: Warning: 
   function free: precondition 'freeable' got status unknown.
 [eva:malloc] imprecise-malloc-free.c:25: weak free on bases: {__malloc_main_l14}
 [eva:alarm] imprecise-malloc-free.c:26: Warning: 
   pointer downcast. assert (unsigned int)r ≤ 2147483647;
+[eva:garbled-mix:write] imprecise-malloc-free.c:26: 
+  Assigning imprecise value to p because of arithmetic operation on addresses.
 [eva] imprecise-malloc-free.c:26: Call to builtin free
 [eva:alarm] imprecise-malloc-free.c:26: Warning: 
   function free: precondition 'freeable' got status unknown.
@@ -57,6 +64,10 @@
   weak free on bases: {__malloc_main_l15, __malloc_main_l16}
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    imprecise-malloc-free.c:13: arithmetic operation on addresses
+      (read 1 times, propagated 2 times) garbled mix of &{size2}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main:
   __fc_heap_status ∈ [--..--]
diff --git a/tests/builtins/oracle/imprecise.res.oracle b/tests/builtins/oracle/imprecise.res.oracle
index bc169708e5bc2c84ecf6d7b2538ebbd7611b688d..d5857d6a3780f56d151fe939579bfa1bfc81ef4d 100644
--- a/tests/builtins/oracle/imprecise.res.oracle
+++ b/tests/builtins/oracle/imprecise.res.oracle
@@ -51,8 +51,7 @@
 [eva:alarm] imprecise.c:19: Warning: 
   pointer downcast. assert (unsigned int)(&k) ≤ 2147483647;
 [eva:garbled-mix:write] imprecise.c:19: 
-  Assigning imprecise value to p.
-  The imprecision originates from Arithmetic {imprecise.c:19}
+  Assigning imprecise value to p because of arithmetic operation on addresses.
 [eva:alarm] imprecise.c:20: Warning: out of bounds write. assert \valid(p);
 [eva] imprecise.c:21: 
   Frama_C_dump_each:
@@ -121,8 +120,7 @@
 [eva:alarm] imprecise.c:68: Warning: 
   signed overflow. assert (int)*((char *)(&p)) + 0 ≤ 2147483647;
 [eva:garbled-mix:write] imprecise.c:68: 
-  Assigning imprecise value to c3.
-  The imprecision originates from Misaligned {imprecise.c:68}
+  Assigning imprecise value to c3 because of misaligned read of addresses.
 [eva] Recording results for cast_address
 [from] Computing for function cast_address
 [from] Done for function cast_address
@@ -266,12 +264,16 @@
 [from] Computing for function main
 [from] Done for function main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    imprecise.c:19: arithmetic operation on addresses
+      (read 3 times, propagated 1 times) garbled mix of &{j; k}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function cast_address:
   p ∈ {{ &x }}
   c1 ∈ {{ (char)&x }}
   c2# ∈ {{ (? *)&x }}%32, bits 0 to 7 
-  c3 ∈ {{ garbled mix of &{x} (origin: Misaligned {imprecise.c:68}) }}
+  c3 ∈ {{ garbled mix of &{x} (origin: Misaligned read {imprecise.c:68}) }}
 [eva:final-states] Values at end of function garbled_mix_null:
   NULL[rbits 800 to 1607] ∈ [--..--] or ESCAPINGADDR
   p_gm_null ∈ [100..197]
@@ -315,11 +317,12 @@
   vy ∈ {1} or UNINITIALIZED
 [eva:final-states] Values at end of function write_garbled:
   NULL[rbits 800 to 1607] ∈
-      {{ garbled mix of &{j; k} (origin: Misaligned {imprecise.c:22}) }}
+      {{ garbled mix of &{j; k}
+       (origin: Misaligned write {imprecise.c:22}) }}
   i ∈ {1}
   j ∈ {{ NULL + [1..197] ; (int)&j ; &k + [0..16] }}
   k[0..4] ∈
-   {{ garbled mix of &{j; k} (origin: Misaligned {imprecise.c:22}) }}
+   {{ garbled mix of &{j; k} (origin: Misaligned write {imprecise.c:22}) }}
   p ∈ {{ NULL + [100..197] ; &j ; &k + [0..16] }}
 [eva:final-states] Values at end of function main:
   NULL[rbits 800 to 1607] ∈ [--..--] or ESCAPINGADDR
@@ -809,12 +812,16 @@
 [from] Computing for function main
 [from] Done for function main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    imprecise.c:19: arithmetic operation on addresses
+      (read 3 times, propagated 1 times) garbled mix of &{j; k}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function cast_address:
   p ∈ {{ &x }}
   c1 ∈ {{ (char)&x }}
   c2# ∈ {{ (? *)&x }}%32, bits 0 to 7 
-  c3 ∈ {{ garbled mix of &{x} (origin: Misaligned {imprecise.c:68}) }}
+  c3 ∈ {{ garbled mix of &{x} (origin: Misaligned read {imprecise.c:68}) }}
 [eva:final-states] Values at end of function garbled_mix_null:
   NULL[rbits 800 to 1607] ∈ [--..--] or ESCAPINGADDR
   p_gm_null ∈ [100..197]
@@ -855,11 +862,12 @@
   vy ∈ {1} or UNINITIALIZED
 [eva:final-states] Values at end of function write_garbled:
   NULL[rbits 800 to 1607] ∈
-      {{ garbled mix of &{j; k} (origin: Misaligned {imprecise.c:22}) }}
+      {{ garbled mix of &{j; k}
+       (origin: Misaligned write {imprecise.c:22}) }}
   i ∈ {1}
   j ∈ {{ NULL + [1..197] ; (int)&j ; &k + [0..16] }}
   k[0..4] ∈
-   {{ garbled mix of &{j; k} (origin: Misaligned {imprecise.c:22}) }}
+   {{ garbled mix of &{j; k} (origin: Misaligned write {imprecise.c:22}) }}
   p ∈ {{ NULL + [100..197] ; &j ; &k + [0..16] }}
 [eva:final-states] Values at end of function main:
   NULL[rbits 800 to 1607] ∈ [--..--] or ESCAPINGADDR
diff --git a/tests/builtins/oracle/linked_list.1.res.oracle b/tests/builtins/oracle/linked_list.1.res.oracle
index 16a5a8ec3b5bbdf8045da8874b28335e0b4bc819..c97ebeb2a70161b6c360d6cb8bf94962bf92fb3f 100644
--- a/tests/builtins/oracle/linked_list.1.res.oracle
+++ b/tests/builtins/oracle/linked_list.1.res.oracle
@@ -806,6 +806,10 @@
   Called from linked_list.c:51.
 [eva] using specification for function printf_va_1
 [eva] linked_list.c:51: function printf_va_1: precondition got status valid.
+[eva:garbled-mix:assigns] linked_list.c:51: 
+  The specification of function printf_va_1
+  has generated a garbled mix of addresses
+  for assigns clause __fc_stdout->__fc_FILE_data.
 [eva] Done for function printf_va_1
 [kernel] linked_list.c:51: 
   more than 100(128) elements to enumerate. Approximating.
diff --git a/tests/builtins/oracle/memcpy.res.oracle b/tests/builtins/oracle/memcpy.res.oracle
index 9354818cac31b53111b4fa4ed36dd05b396818c7..6fe4eedb72486a27ebdc2582a036bea66c8573cd 100644
--- a/tests/builtins/oracle/memcpy.res.oracle
+++ b/tests/builtins/oracle/memcpy.res.oracle
@@ -100,13 +100,22 @@
 [eva] memcpy.c:85: function memcpy: precondition 'separation' got status valid.
 [eva:alarm] memcpy.c:87: Warning: 
   pointer downcast. assert (unsigned int)((struct t1 *)t) ≤ 2147483647;
+[eva:garbled-mix:write] memcpy.c:87: 
+  Assigning imprecise value to src
+  because of arithmetic operation on addresses.
 [eva] memcpy.c:87: Call to builtin memcpy
 [eva] memcpy.c:87: function memcpy: precondition 'valid_dest' got status valid.
 [eva:alarm] memcpy.c:87: Warning: 
   function memcpy: precondition 'valid_src' got status unknown.
 [eva] memcpy.c:87: function memcpy: precondition 'separation' got status valid.
+[eva:garbled-mix:write] memcpy.c:87: 
+  Builtin memcpy: assigning imprecise value to v3
+  because of misaligned read of addresses.
 [eva:alarm] memcpy.c:89: Warning: 
   pointer downcast. assert (unsigned int)(&v4) ≤ 2147483647;
+[eva:garbled-mix:write] memcpy.c:89: 
+  Assigning imprecise value to dest
+  because of arithmetic operation on addresses.
 [eva] memcpy.c:89: Call to builtin memcpy
 [eva:alarm] memcpy.c:89: Warning: 
   function memcpy: precondition 'valid_dest' got status unknown.
@@ -118,6 +127,9 @@
   pointer downcast. assert (unsigned int)((struct t1 *)t) ≤ 2147483647;
 [eva:alarm] memcpy.c:91: Warning: 
   pointer downcast. assert (unsigned int)(&v5) ≤ 2147483647;
+[eva:garbled-mix:write] memcpy.c:91: 
+  Assigning imprecise value to dest
+  because of arithmetic operation on addresses.
 [eva] memcpy.c:91: Call to builtin memcpy
 [eva:alarm] memcpy.c:91: Warning: 
   function memcpy: precondition 'valid_dest' got status unknown.
@@ -564,11 +576,11 @@
   v2.x ∈ {5}
     .y ∈ {7}
     {.p; .padding[0..23]} ∈ {0}
-  v3 ∈ {{ garbled mix of &{v1} (origin: Misaligned {memcpy.c:87}) }}
+  v3 ∈ {{ garbled mix of &{v1} (origin: Misaligned read {memcpy.c:87}) }}
   v4.x ∈ [--..--]
     .y ∈ {{ (int)&t }}
     {.p; .padding[0..23]} ∈ [--..--]
-  v5 ∈ {{ garbled mix of &{t} (origin: Misaligned {memcpy.c:91}) }}
+  v5 ∈ {{ garbled mix of &{t} (origin: Arithmetic {memcpy.c:91}) }}
   t{[0]; [1]{.x; .y}} ∈ {0}
    [1].p ∈ {{ &v1.y }}
    {[1].padding[0..23]; [2]; [3]{.x; .y}} ∈ {0}
diff --git a/tests/builtins/oracle/memset.res.oracle b/tests/builtins/oracle/memset.res.oracle
index a71515ecdbf65f033962389a94fb5e9028f811f4..a6115d361b6b54206f7f038fd794ce01df915472 100644
--- a/tests/builtins/oracle/memset.res.oracle
+++ b/tests/builtins/oracle/memset.res.oracle
@@ -28,6 +28,8 @@
   cannot evaluate ACSL term, unsupported ACSL construct: logic function memset
 [eva:alarm] memset.c:34: Warning: 
   pointer downcast. assert (unsigned int)((int *)t2) ≤ 2147483647;
+[eva:garbled-mix:write] memset.c:34: 
+  Assigning imprecise value to s because of arithmetic operation on addresses.
 [eva] memset.c:34: Call to builtin memset
 [eva:alarm] memset.c:34: Warning: 
   function memset: precondition 'valid_s' got status unknown.
@@ -49,6 +51,9 @@
 [eva] memset.c:41: function memset: precondition 'valid_s' got status valid.
 [eva:imprecision] memset.c:41: 
   Call to builtin precise_memset(({{ (void *)&t5 }},{{ (int)&t1 }},{400})) failed; value to write is imprecise
+[eva:garbled-mix:write] memset.c:41: 
+  Builtin memset: assigning imprecise value to t5[0]
+  because of misaligned read of addresses.
 [eva] memset.c:44: Call to builtin memset
 [eva] memset.c:44: function memset: precondition 'valid_s' got status valid.
 [eva:imprecision] memset.c:44: 
@@ -108,7 +113,8 @@
   t3[0..9] ∈ {0}
     [10..99]# ∈ {0; 17} repeated %8 
   t4[0..99] ∈ {0}
-  t5[0..99] ∈ {{ garbled mix of &{t1} (origin: Misaligned {memset.c:41}) }}
+  t5[0..99] ∈
+    {{ garbled mix of &{t1} (origin: Misaligned read {memset.c:41}) }}
   t6[0..9] ∈ {0}
     [10..13]# ∈ {0; 34} repeated %8 
     [14..99] ∈ {0}
@@ -163,7 +169,8 @@
   t3[0..9] ∈ {0}
     [10..99]# ∈ {0; 17} repeated %8 
   t4[0..99] ∈ {0}
-  t5[0..99] ∈ {{ garbled mix of &{t1} (origin: Misaligned {memset.c:41}) }}
+  t5[0..99] ∈
+    {{ garbled mix of &{t1} (origin: Misaligned read {memset.c:41}) }}
   t6[0..9] ∈ {0}
     [10..13]# ∈ {0; 34} repeated %8 
     [14..99] ∈ {0}
diff --git a/tests/builtins/oracle/strchr.res.oracle b/tests/builtins/oracle/strchr.res.oracle
index e9cfcd8c7928de0aa61c8d1c8cf267de2e8dc1bd..e1298461c038a1977a5d897d8e9a7a897efa1975 100644
--- a/tests/builtins/oracle/strchr.res.oracle
+++ b/tests/builtins/oracle/strchr.res.oracle
@@ -640,6 +640,8 @@
 [eva] Done for function strchr_unbounded
 [eva] computing for function strchr_invalid <- main.
   Called from strchr.c:561.
+[eva:garbled-mix:write] strchr.c:536: 
+  Assigning imprecise value to s because of arithmetic operation on addresses.
 [eva] strchr.c:536: Call to builtin strchr
 [eva:alarm] strchr.c:536: Warning: 
   function strchr: precondition 'valid_string_s' got status unknown.
@@ -659,8 +661,8 @@
 [eva:alarm] strchr.c:541: Warning: 
   pointer downcast. assert (unsigned int)(&x) ≤ 2147483647;
 [eva:garbled-mix:write] strchr.c:541: 
-  Assigning imprecise value to garbled.
-  The imprecision originates from Arithmetic {strchr.c:541}
+  Assigning imprecise value to garbled
+  because of arithmetic operation on addresses.
 [eva:alarm] strchr.c:542: Warning: 
   pointer downcast. assert (unsigned int)garbled ≤ 2147483647;
 [eva] strchr.c:542: Call to builtin strchr
@@ -670,6 +672,10 @@
 [eva] Done for function strchr_garbled_mix_in_char
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    strchr.c:541: arithmetic operation on addresses
+      (read 1 times, propagated 3 times) garbled mix of &{x}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function init_array_nondet:
   from ∈ {-1}
diff --git a/tests/builtins/oracle_equality/imprecise.res.oracle b/tests/builtins/oracle_equality/imprecise.res.oracle
index eb4cf14573bb6394a0e018d936c72176c7b61f25..510c64aad8aaa51da0c6f9e5f58617e8b42eef36 100644
--- a/tests/builtins/oracle_equality/imprecise.res.oracle
+++ b/tests/builtins/oracle_equality/imprecise.res.oracle
@@ -1,13 +1,13 @@
-99a100,101
+98a99,100
 > [kernel] imprecise.c:51: 
 >   imprecise size for variable v3 (abstract type 'struct u')
-222a225,226
+220a223,224
 > [kernel] imprecise.c:111: 
 >   more than 200(300) elements to enumerate. Approximating.
-230a235,236
+228a233,234
 > [kernel] imprecise.c:114: 
 >   more than 200(300) elements to enumerate. Approximating.
-239,242d244
+237,240d242
 < [kernel] imprecise.c:111: 
 <   more than 200(300) elements to enumerate. Approximating.
 < [kernel] imprecise.c:114: 
diff --git a/tests/builtins/oracle_equality/linked_list.1.res.oracle b/tests/builtins/oracle_equality/linked_list.1.res.oracle
index dc1c07fbca0f6ce44824d4bdff2b3cf9110babd1..08a077ea283d0d72948ad4ac7cc139699f42818e 100644
--- a/tests/builtins/oracle_equality/linked_list.1.res.oracle
+++ b/tests/builtins/oracle_equality/linked_list.1.res.oracle
@@ -16,9 +16,9 @@
 720a731,732
 > [kernel] linked_list.c:44: 
 >   more than 100(128) elements to enumerate. Approximating.
-810,811d821
+814,815d825
 < [kernel] linked_list.c:51: 
 <   more than 100(128) elements to enumerate. Approximating.
-819,820d828
+823,824d832
 < [kernel] linked_list.c:44: 
 <   more than 100(128) elements to enumerate. Approximating.
diff --git a/tests/builtins/oracle_gauges/linked_list.1.res.oracle b/tests/builtins/oracle_gauges/linked_list.1.res.oracle
index ec6dff88c11d22b8f7b5764d51fe82406d5cd9e0..b4dd8f6901bfedbeff231430246bb6c77f704f48 100644
--- a/tests/builtins/oracle_gauges/linked_list.1.res.oracle
+++ b/tests/builtins/oracle_gauges/linked_list.1.res.oracle
@@ -1,4 +1,4 @@
-817a818,823
+821a822,827
 > [eva] computing for function printf_va_1 <- main.
 >   Called from linked_list.c:51.
 > [eva] Done for function printf_va_1
diff --git a/tests/builtins/oracle_gauges/memcpy.res.oracle b/tests/builtins/oracle_gauges/memcpy.res.oracle
index d2986d41912c0fe02c5048b90f543a07721ed311..78ce5790f07d21391745733139582ff60737e029 100644
--- a/tests/builtins/oracle_gauges/memcpy.res.oracle
+++ b/tests/builtins/oracle_gauges/memcpy.res.oracle
@@ -1,5 +1,5 @@
-138a139,140
+150a151,152
 > [eva] memcpy.c:96: Call to builtin memcpy
 > [eva] memcpy.c:96: Call to builtin memcpy
-364a367
+376a379
 > [eva] memcpy.c:230: starting to merge loop iterations
diff --git a/tests/builtins/oracle_octagon/imprecise.res.oracle b/tests/builtins/oracle_octagon/imprecise.res.oracle
index 4001ea81170eeff5bdf55aedd0eeb81230413cab..9633a07ab0e31c0bef97b7be3027233c2a4bf0db 100644
--- a/tests/builtins/oracle_octagon/imprecise.res.oracle
+++ b/tests/builtins/oracle_octagon/imprecise.res.oracle
@@ -1,10 +1,10 @@
-222a223,224
+220a221,222
 > [kernel] imprecise.c:111: 
 >   more than 200(300) elements to enumerate. Approximating.
-230a233,234
+228a231,232
 > [kernel] imprecise.c:114: 
 >   more than 200(300) elements to enumerate. Approximating.
-239,242d242
+237,240d240
 < [kernel] imprecise.c:111: 
 <   more than 200(300) elements to enumerate. Approximating.
 < [kernel] imprecise.c:114: 
diff --git a/tests/builtins/oracle_octagon/linked_list.1.res.oracle b/tests/builtins/oracle_octagon/linked_list.1.res.oracle
index 4083e687dd36eae966d07c6feea16e88f79ce698..166d64faad77cf59fe2003c8dda6ac23d5adf97d 100644
--- a/tests/builtins/oracle_octagon/linked_list.1.res.oracle
+++ b/tests/builtins/oracle_octagon/linked_list.1.res.oracle
@@ -10,9 +10,9 @@
 720a727,728
 > [kernel] linked_list.c:44: 
 >   more than 100(128) elements to enumerate. Approximating.
-810,811d817
+814,815d821
 < [kernel] linked_list.c:51: 
 <   more than 100(128) elements to enumerate. Approximating.
-819,820d824
+823,824d828
 < [kernel] linked_list.c:44: 
 <   more than 100(128) elements to enumerate. Approximating.
diff --git a/tests/builtins/oracle_symblocs/imprecise.res.oracle b/tests/builtins/oracle_symblocs/imprecise.res.oracle
index 4001ea81170eeff5bdf55aedd0eeb81230413cab..9633a07ab0e31c0bef97b7be3027233c2a4bf0db 100644
--- a/tests/builtins/oracle_symblocs/imprecise.res.oracle
+++ b/tests/builtins/oracle_symblocs/imprecise.res.oracle
@@ -1,10 +1,10 @@
-222a223,224
+220a221,222
 > [kernel] imprecise.c:111: 
 >   more than 200(300) elements to enumerate. Approximating.
-230a233,234
+228a231,232
 > [kernel] imprecise.c:114: 
 >   more than 200(300) elements to enumerate. Approximating.
-239,242d242
+237,240d240
 < [kernel] imprecise.c:111: 
 <   more than 200(300) elements to enumerate. Approximating.
 < [kernel] imprecise.c:114: 
diff --git a/tests/builtins/oracle_symblocs/linked_list.1.res.oracle b/tests/builtins/oracle_symblocs/linked_list.1.res.oracle
index 4083e687dd36eae966d07c6feea16e88f79ce698..166d64faad77cf59fe2003c8dda6ac23d5adf97d 100644
--- a/tests/builtins/oracle_symblocs/linked_list.1.res.oracle
+++ b/tests/builtins/oracle_symblocs/linked_list.1.res.oracle
@@ -10,9 +10,9 @@
 720a727,728
 > [kernel] linked_list.c:44: 
 >   more than 100(128) elements to enumerate. Approximating.
-810,811d817
+814,815d821
 < [kernel] linked_list.c:51: 
 <   more than 100(128) elements to enumerate. Approximating.
-819,820d824
+823,824d828
 < [kernel] linked_list.c:44: 
 <   more than 100(128) elements to enumerate. Approximating.
diff --git a/tests/fc_script/make-wrapper.t/run.t b/tests/fc_script/make-wrapper.t/run.t
index b64143a7e576c1148033632a3cd74eb5c60b700e..e70aaa31a57f87209702a00fbbae0814ef2f7258 100644
--- a/tests/fc_script/make-wrapper.t/run.t
+++ b/tests/fc_script/make-wrapper.t/run.t
@@ -11,7 +11,7 @@ verbose output for Make.
   [kernel] Parsing make-wrapper.c (with preprocessing)
   [kernel] Parsing make-wrapper2.c (with preprocessing)
   
-  Command: frama-c -kernel-warn-key annot:missing-spec=abort -kernel-warn-key typing:implicit-function-declaration=abort -eva -eva-no-print -eva-no-show-progress -eva-msg-key=-initial-state -eva-print-callstacks -eva-warn-key alarm=inactive -no-deps-print -no-calldeps-print -eva-warn-key garbled-mix=active,garbled-mix:write=feedback -calldeps -from-verbose 0 -eva-warn-key builtins:missing-spec=abort
+  Command: frama-c -kernel-warn-key annot:missing-spec=abort -kernel-warn-key typing:implicit-function-declaration=abort -eva -eva-no-print -eva-no-show-progress -eva-msg-key=-initial-state -eva-print-callstacks -eva-warn-key alarm=inactive -no-deps-print -no-calldeps-print -eva-warn-key garbled-mix=active,garbled-mix:write=active -calldeps -from-verbose 0 -eva-warn-key builtins:missing-spec=abort
   
   [eva] Analyzing a complete application starting at main
   [eva:recursion] make-wrapper.c:17: 
diff --git a/tests/float/oracle/builtins.res.oracle b/tests/float/oracle/builtins.res.oracle
index 0de9a86128d5d8b7f0db04b759781353078ab46f..5039c250f6b7711f4c2d73630e0df5ae8926e78d 100644
--- a/tests/float/oracle/builtins.res.oracle
+++ b/tests/float/oracle/builtins.res.oracle
@@ -125,15 +125,14 @@
   pointer downcast. assert (unsigned int)(&d) ≤ 2147483647;
 [eva:alarm] builtins.c:107: Warning: 
   non-finite double value. assert \is_finite((double)((int)(&d)));
+[eva:garbled-mix:write] builtins.c:107: 
+  Assigning imprecise value to x because of arithmetic operation on addresses.
 [eva] builtins.c:107: Call to builtin log
 [eva:alarm] builtins.c:107: Warning: 
   function log: precondition 'finite_arg' got status unknown.
 [eva:alarm] builtins.c:107: Warning: 
   function log: precondition 'arg_positive' got status unknown.
 [eva] builtins.c:107: function Frama_C_log applied to address
-[eva:garbled-mix:write] builtins.c:107: 
-  Assigning imprecise value to l7.
-  The imprecision originates from Arithmetic {builtins.c:107}
 [eva:alarm] builtins.c:111: Warning: 
   accessing uninitialized left-value. assert \initialized(&x);
 [eva] Recording results for main_log_exp
diff --git a/tests/float/oracle/nonlin.0.res.oracle b/tests/float/oracle/nonlin.0.res.oracle
index 3c25cbe9a7e7af49f5712d3551e3f897e2695832..043c52aa669533e1deb16aecb97093e67d3ede6e 100644
--- a/tests/float/oracle/nonlin.0.res.oracle
+++ b/tests/float/oracle/nonlin.0.res.oracle
@@ -236,15 +236,12 @@
   non-finite float value.
   assert \is_finite((float)((int)(&x_0 + (int)(&x_0))));
 [eva:garbled-mix:write] nonlin.c:98: 
-  Assigning imprecise value to a_0.
-  The imprecision originates from Arithmetic {nonlin.c:98}
+  Assigning imprecise value to a_0
+  because of arithmetic operation on addresses.
 [eva:alarm] nonlin.c:99: Warning: 
   non-finite float value. assert \is_finite(a_0);
 [eva:alarm] nonlin.c:99: Warning: 
   non-finite float value. assert \is_finite(\add_float(a_0, a_0));
-[eva:garbled-mix:write] nonlin.c:99: 
-  Assigning imprecise value to f.
-  The imprecision originates from Arithmetic
 [eva] Recording results for garbled
 [eva] Done for function garbled
 [eva] computing for function around_zeros <- main.
@@ -287,6 +284,10 @@
 [eva] Done for function subdivide_strategy
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    nonlin.c:98: arithmetic operation on addresses
+      (read 1 times, propagated 2 times) garbled mix of &{x_0}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function access_bits:
   rbits1 ∈ {0; 1; 2}
@@ -299,7 +300,7 @@
   res ∈ [-0x1.fffffe0000000p127 .. 0x1.fffffe0000000p127]
 [eva:final-states] Values at end of function garbled:
   a_0 ∈ {{ garbled mix of &{x_0} (origin: Arithmetic {nonlin.c:98}) }}
-  f ∈ {{ garbled mix of &{x_0} (origin: Arithmetic) }}
+  f ∈ {{ garbled mix of &{x_0} (origin: Arithmetic {nonlin.c:98}) }}
 [eva:final-states] Values at end of function nonlin_f:
   Frama_C_entropy_source ∈ [--..--]
   a ∈ [0x1.4000000000000p2 .. 0x1.c000000000000p2]
diff --git a/tests/float/oracle/nonlin.1.res.oracle b/tests/float/oracle/nonlin.1.res.oracle
index 5efd17ffac7dcc632dff44d55cc85a13e8898dfe..b69461ed024bb293807c22fcf863c634a5df7ae1 100644
--- a/tests/float/oracle/nonlin.1.res.oracle
+++ b/tests/float/oracle/nonlin.1.res.oracle
@@ -255,15 +255,12 @@
   non-finite float value.
   assert \is_finite((float)((int)(&x_0 + (int)(&x_0))));
 [eva:garbled-mix:write] nonlin.c:98: 
-  Assigning imprecise value to a_0.
-  The imprecision originates from Arithmetic {nonlin.c:98}
+  Assigning imprecise value to a_0
+  because of arithmetic operation on addresses.
 [eva:alarm] nonlin.c:99: Warning: 
   non-finite float value. assert \is_finite(a_0);
 [eva:alarm] nonlin.c:99: Warning: 
   non-finite float value. assert \is_finite(\add_float(a_0, a_0));
-[eva:garbled-mix:write] nonlin.c:99: 
-  Assigning imprecise value to f.
-  The imprecision originates from Arithmetic
 [eva] Recording results for garbled
 [eva] Done for function garbled
 [eva] computing for function around_zeros <- main.
@@ -314,6 +311,10 @@
 [eva] Done for function subdivide_strategy
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    nonlin.c:98: arithmetic operation on addresses
+      (read 1 times, propagated 2 times) garbled mix of &{x_0}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function access_bits:
   rbits1 ∈ {0; 1; 2}
@@ -326,7 +327,7 @@
   res ∈ {-0x1.0000000000000p0}
 [eva:final-states] Values at end of function garbled:
   a_0 ∈ {{ garbled mix of &{x_0} (origin: Arithmetic {nonlin.c:98}) }}
-  f ∈ {{ garbled mix of &{x_0} (origin: Arithmetic) }}
+  f ∈ {{ garbled mix of &{x_0} (origin: Arithmetic {nonlin.c:98}) }}
 [eva:final-states] Values at end of function nonlin_f:
   Frama_C_entropy_source ∈ [--..--]
   a ∈ [0x1.4000000000000p2 .. 0x1.c000000000000p2]
diff --git a/tests/float/oracle/nonlin.2.res.oracle b/tests/float/oracle/nonlin.2.res.oracle
index 861a2facbf87e30b66c3edbb44e96f26b64fdb9b..05b14b3983b595fd05c1a39dcc9fb51cac2aebcb 100644
--- a/tests/float/oracle/nonlin.2.res.oracle
+++ b/tests/float/oracle/nonlin.2.res.oracle
@@ -242,11 +242,8 @@
 [eva:alarm] nonlin.c:98: Warning: 
   pointer downcast. assert (unsigned int)(&x_0 + (int)(&x_0)) ≤ 2147483647;
 [eva:garbled-mix:write] nonlin.c:98: 
-  Assigning imprecise value to a_0.
-  The imprecision originates from Arithmetic {nonlin.c:98}
-[eva:garbled-mix:write] nonlin.c:99: 
-  Assigning imprecise value to f.
-  The imprecision originates from Arithmetic
+  Assigning imprecise value to a_0
+  because of arithmetic operation on addresses.
 [eva] Recording results for garbled
 [eva] Done for function garbled
 [eva] computing for function around_zeros <- main.
@@ -288,6 +285,10 @@
 [eva] Done for function subdivide_strategy
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    nonlin.c:98: arithmetic operation on addresses
+      (read 1 times, propagated 2 times) garbled mix of &{x_0}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function access_bits:
   rbits1 ∈ {0; 1; 2}
@@ -300,7 +301,7 @@
   res ∈ [-0x1.0000000000000p0 .. inf]
 [eva:final-states] Values at end of function garbled:
   a_0 ∈ {{ garbled mix of &{x_0} (origin: Arithmetic {nonlin.c:98}) }}
-  f ∈ {{ garbled mix of &{x_0} (origin: Arithmetic) }}
+  f ∈ {{ garbled mix of &{x_0} (origin: Arithmetic {nonlin.c:98}) }}
 [eva:final-states] Values at end of function nonlin_f:
   Frama_C_entropy_source ∈ [--..--]
   a ∈ [0x1.4000000000000p2 .. 0x1.c000000000000p2]
diff --git a/tests/float/oracle/nonlin.3.res.oracle b/tests/float/oracle/nonlin.3.res.oracle
index e59972c716fe567af8459aa206ab9eb68ddee54c..24ccbef205c1cd4e1a182e9eb30eebea036393c0 100644
--- a/tests/float/oracle/nonlin.3.res.oracle
+++ b/tests/float/oracle/nonlin.3.res.oracle
@@ -236,15 +236,12 @@
   non-finite float value.
   assert \is_finite((float)((int)(&x_0 + (int)(&x_0))));
 [eva:garbled-mix:write] nonlin.c:98: 
-  Assigning imprecise value to a_0.
-  The imprecision originates from Arithmetic {nonlin.c:98}
+  Assigning imprecise value to a_0
+  because of arithmetic operation on addresses.
 [eva:alarm] nonlin.c:99: Warning: 
   non-finite float value. assert \is_finite(a_0);
 [eva:alarm] nonlin.c:99: Warning: 
   non-finite float value. assert \is_finite(\add_float(a_0, a_0));
-[eva:garbled-mix:write] nonlin.c:99: 
-  Assigning imprecise value to f.
-  The imprecision originates from Arithmetic
 [eva] Recording results for garbled
 [eva] Done for function garbled
 [eva] computing for function around_zeros <- main.
@@ -287,6 +284,10 @@
 [eva] Done for function subdivide_strategy
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    nonlin.c:98: arithmetic operation on addresses
+      (read 1 times, propagated 2 times) garbled mix of &{x_0}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function access_bits:
   rbits1 ∈ {0; 1; 2}
@@ -299,7 +300,7 @@
   res ∈ [-0x1.fffffe0000000p127 .. 0x1.fffffe0000000p127]
 [eva:final-states] Values at end of function garbled:
   a_0 ∈ {{ garbled mix of &{x_0} (origin: Arithmetic {nonlin.c:98}) }}
-  f ∈ {{ garbled mix of &{x_0} (origin: Arithmetic) }}
+  f ∈ {{ garbled mix of &{x_0} (origin: Arithmetic {nonlin.c:98}) }}
 [eva:final-states] Values at end of function nonlin_f:
   Frama_C_entropy_source ∈ [--..--]
   a ∈ [0x1.4000000000000p2 .. 0x1.c000000000000p2]
diff --git a/tests/float/oracle/nonlin.4.res.oracle b/tests/float/oracle/nonlin.4.res.oracle
index a9cb1e55da7d560464a16b788891e8ebd15924c9..a0f41891c242df0ead1a4ee73efaea7f01404844 100644
--- a/tests/float/oracle/nonlin.4.res.oracle
+++ b/tests/float/oracle/nonlin.4.res.oracle
@@ -255,15 +255,12 @@
   non-finite float value.
   assert \is_finite((float)((int)(&x_0 + (int)(&x_0))));
 [eva:garbled-mix:write] nonlin.c:98: 
-  Assigning imprecise value to a_0.
-  The imprecision originates from Arithmetic {nonlin.c:98}
+  Assigning imprecise value to a_0
+  because of arithmetic operation on addresses.
 [eva:alarm] nonlin.c:99: Warning: 
   non-finite float value. assert \is_finite(a_0);
 [eva:alarm] nonlin.c:99: Warning: 
   non-finite float value. assert \is_finite(\add_float(a_0, a_0));
-[eva:garbled-mix:write] nonlin.c:99: 
-  Assigning imprecise value to f.
-  The imprecision originates from Arithmetic
 [eva] Recording results for garbled
 [eva] Done for function garbled
 [eva] computing for function around_zeros <- main.
@@ -314,6 +311,10 @@
 [eva] Done for function subdivide_strategy
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    nonlin.c:98: arithmetic operation on addresses
+      (read 1 times, propagated 2 times) garbled mix of &{x_0}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function access_bits:
   rbits1 ∈ {0; 1; 2}
@@ -326,7 +327,7 @@
   res ∈ {-0x1.0000000000000p0}
 [eva:final-states] Values at end of function garbled:
   a_0 ∈ {{ garbled mix of &{x_0} (origin: Arithmetic {nonlin.c:98}) }}
-  f ∈ {{ garbled mix of &{x_0} (origin: Arithmetic) }}
+  f ∈ {{ garbled mix of &{x_0} (origin: Arithmetic {nonlin.c:98}) }}
 [eva:final-states] Values at end of function nonlin_f:
   Frama_C_entropy_source ∈ [--..--]
   a ∈ [0x1.4000000000000p2 .. 0x1.c000000000000p2]
diff --git a/tests/float/oracle/nonlin.5.res.oracle b/tests/float/oracle/nonlin.5.res.oracle
index a41360104ac0b5d7e0e6c427029d9940bf1b7394..25cd26ba1ee0c29e381e99198b125dd655c37124 100644
--- a/tests/float/oracle/nonlin.5.res.oracle
+++ b/tests/float/oracle/nonlin.5.res.oracle
@@ -242,11 +242,8 @@
 [eva:alarm] nonlin.c:98: Warning: 
   pointer downcast. assert (unsigned int)(&x_0 + (int)(&x_0)) ≤ 2147483647;
 [eva:garbled-mix:write] nonlin.c:98: 
-  Assigning imprecise value to a_0.
-  The imprecision originates from Arithmetic {nonlin.c:98}
-[eva:garbled-mix:write] nonlin.c:99: 
-  Assigning imprecise value to f.
-  The imprecision originates from Arithmetic
+  Assigning imprecise value to a_0
+  because of arithmetic operation on addresses.
 [eva] Recording results for garbled
 [eva] Done for function garbled
 [eva] computing for function around_zeros <- main.
@@ -288,6 +285,10 @@
 [eva] Done for function subdivide_strategy
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    nonlin.c:98: arithmetic operation on addresses
+      (read 1 times, propagated 2 times) garbled mix of &{x_0}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function access_bits:
   rbits1 ∈ {0; 1; 2}
@@ -300,7 +301,7 @@
   res ∈ [-0x1.0000000000000p0 .. inf]
 [eva:final-states] Values at end of function garbled:
   a_0 ∈ {{ garbled mix of &{x_0} (origin: Arithmetic {nonlin.c:98}) }}
-  f ∈ {{ garbled mix of &{x_0} (origin: Arithmetic) }}
+  f ∈ {{ garbled mix of &{x_0} (origin: Arithmetic {nonlin.c:98}) }}
 [eva:final-states] Values at end of function nonlin_f:
   Frama_C_entropy_source ∈ [--..--]
   a ∈ [0x1.4000000000000p2 .. 0x1.c000000000000p2]
diff --git a/tests/float/oracle_octagon/nonlin.1.res.oracle b/tests/float/oracle_octagon/nonlin.1.res.oracle
index 47df4c6b3ec06d4d53cb840cd6daf42606770e89..6eefc1b9fe0c8e2bfb44c95f71f61bc9f761dcf4 100644
--- a/tests/float/oracle_octagon/nonlin.1.res.oracle
+++ b/tests/float/oracle_octagon/nonlin.1.res.oracle
@@ -1,5 +1,5 @@
-277a278,279
+274a275,276
 > [eva:nonlin] nonlin.c:113: non-linear 'f + f', lv 'f'
 > [eva:nonlin] nonlin.c:113: subdividing on f
-280d281
+277d278
 < [eva:nonlin] nonlin.c:113: subdividing on f
diff --git a/tests/float/oracle_octagon/nonlin.2.res.oracle b/tests/float/oracle_octagon/nonlin.2.res.oracle
index 32ee5946f24c027cb7bf9fbb4f5475f1efd4b0a9..af64eb11946572bd8f9d116a6d6731adf1112bcb 100644
--- a/tests/float/oracle_octagon/nonlin.2.res.oracle
+++ b/tests/float/oracle_octagon/nonlin.2.res.oracle
@@ -1,5 +1,5 @@
-260a261,262
+257a258,259
 > [eva:nonlin] nonlin.c:113: non-linear 'f + f', lv 'f'
 > [eva:nonlin] nonlin.c:113: subdividing on f
-263d264
+260d261
 < [eva:nonlin] nonlin.c:113: subdividing on f
diff --git a/tests/float/oracle_octagon/nonlin.4.res.oracle b/tests/float/oracle_octagon/nonlin.4.res.oracle
index 47df4c6b3ec06d4d53cb840cd6daf42606770e89..6eefc1b9fe0c8e2bfb44c95f71f61bc9f761dcf4 100644
--- a/tests/float/oracle_octagon/nonlin.4.res.oracle
+++ b/tests/float/oracle_octagon/nonlin.4.res.oracle
@@ -1,5 +1,5 @@
-277a278,279
+274a275,276
 > [eva:nonlin] nonlin.c:113: non-linear 'f + f', lv 'f'
 > [eva:nonlin] nonlin.c:113: subdividing on f
-280d281
+277d278
 < [eva:nonlin] nonlin.c:113: subdividing on f
diff --git a/tests/float/oracle_octagon/nonlin.5.res.oracle b/tests/float/oracle_octagon/nonlin.5.res.oracle
index 32ee5946f24c027cb7bf9fbb4f5475f1efd4b0a9..af64eb11946572bd8f9d116a6d6731adf1112bcb 100644
--- a/tests/float/oracle_octagon/nonlin.5.res.oracle
+++ b/tests/float/oracle_octagon/nonlin.5.res.oracle
@@ -1,5 +1,5 @@
-260a261,262
+257a258,259
 > [eva:nonlin] nonlin.c:113: non-linear 'f + f', lv 'f'
 > [eva:nonlin] nonlin.c:113: subdividing on f
-263d264
+260d261
 < [eva:nonlin] nonlin.c:113: subdividing on f
diff --git a/tests/libc/check_const.ml b/tests/libc/check_const.ml
index 6996d5ed0326d36527c4ac9f2521463a66dc03b6..8a38a17b5c194d2e537b6ba70747ed1cbd4f86c2 100644
--- a/tests/libc/check_const.ml
+++ b/tests/libc/check_const.ml
@@ -48,7 +48,7 @@ let check_annot kf _ (a: identified_predicate) =
         end
       | TBinOp ((PlusPI | MinusPI),
                 ({term_node = TLval (TVar lvi, _)} |
-                 {term_node = TCastE (_, {term_node = TLval (TVar lvi, _)})}),
+                 {term_node = TCast (false,_, {term_node = TLval (TVar lvi, _)})}),
                 _)
       | TLval (TVar lvi, _) -> begin
           match lvi.lv_origin with
diff --git a/tests/libc/oracle/fc_libc.1.res.oracle b/tests/libc/oracle/fc_libc.1.res.oracle
index bc1a0874a6a93bd9e5e05847cfa88d8d8b87858c..06f9fb802baed599d110bb2ce231aa39b7d831f2 100644
--- a/tests/libc/oracle/fc_libc.1.res.oracle
+++ b/tests/libc/oracle/fc_libc.1.res.oracle
@@ -8419,6 +8419,13 @@ extern int pipe(int pipefd[2]);
  */
 extern ssize_t read(int fd, void *buf, size_t count);
 
+/*@ requires valid_name: valid_read_string(name);
+    ensures result_ok_or_error: \result ≡ 0 ∨ \result ≡ -1;
+    assigns \result;
+    assigns \result \from (indirect: *(name + (0 .. strlen{Old}(name))));
+ */
+extern int rmdir(char const *name);
+
 /*@ ensures result_ok_or_error: \result ≡ 0 ∨ \result ≡ -1;
     assigns \result;
     assigns \result \from (indirect: gid);
diff --git a/tests/libc/oracle/signal_h.res.oracle b/tests/libc/oracle/signal_h.res.oracle
index 59925bcb9eb92e8536134c8ff904f55dacb491f5..fe4f9414bf77cb385fed69ef556d573f56ec2282 100644
--- a/tests/libc/oracle/signal_h.res.oracle
+++ b/tests/libc/oracle/signal_h.res.oracle
@@ -112,6 +112,9 @@
   function sigaction: precondition 'valid_read_act_or_null' got status valid.
 [eva] signal_h.c:45: 
   function sigaction: precondition 'separation,separated_acts' got status valid.
+[eva:garbled-mix:assigns] signal_h.c:45: 
+  The specification of function sigaction
+  has generated a garbled mix of addresses for assigns clause *oldact.
 [eva] Done for function sigaction
 [eva] computing for function sigaction <- main.
   Called from signal_h.c:45.
@@ -128,6 +131,9 @@
   function sigaction: precondition 'separation,separated_acts' got status valid.
 [eva] FRAMAC_SHARE/libc/signal.h:229: 
   cannot evaluate ACSL term, unsupported ACSL construct: logic coercion struct sigaction -> set<struct sigaction>
+[eva:garbled-mix:assigns] signal_h.c:48: 
+  The specification of function sigaction
+  has generated a garbled mix of addresses for assigns clause *oldact.
 [eva] Done for function sigaction
 [eva] computing for function sigaction <- main.
   Called from signal_h.c:51.
@@ -178,7 +184,7 @@
                 [9]{.sa_mask; .sa_flags} ∈ [--..--]
                 [10] ∈
                 {{ garbled mix of &{__fc_sigaction}
-                 (origin: Library function) }}
+                 (origin: Library function {signal_h.c:48}) }}
                 [11]{.sa_handler; .sa_sigaction} ∈ {0}
                 [11]{.sa_mask; .sa_flags} ∈ [--..--]
                 [12]{.sa_handler; .sa_sigaction} ∈ {0}
@@ -193,7 +199,7 @@
                 {[16]{.sa_mask; .sa_flags}; [17]} ∈ [--..--]
                 [18] ∈
                 {{ garbled mix of &{__fc_sigaction}
-                 (origin: Library function) }}
+                 (origin: Library function {signal_h.c:45}) }}
                 [19]{.sa_handler; .sa_sigaction} ∈ {0}
                 [19]{.sa_mask; .sa_flags} ∈ [--..--]
                 [20]{.sa_handler; .sa_sigaction} ∈ {0}
diff --git a/tests/libc/oracle/spawn_h.res.oracle b/tests/libc/oracle/spawn_h.res.oracle
index 01e765f74b0657f98adf4531504ffc36c9823a12..08866e9f1aa7e5bba94b7b62fabfa540d82d32a4 100644
--- a/tests/libc/oracle/spawn_h.res.oracle
+++ b/tests/libc/oracle/spawn_h.res.oracle
@@ -7,10 +7,10 @@
 [eva] computing for function getopt <- main.
   Called from spawn_h.c:36.
 [eva] using specification for function getopt
+[eva:garbled-mix:assigns] spawn_h.c:36: 
+  The specification of function getopt has generated a garbled mix of addresses
+  for assigns clause \result.
 [eva] Done for function getopt
-[eva:garbled-mix:write] spawn_h.c:36: 
-  Assigning imprecise value to opt.
-  The imprecision originates from Library function {spawn_h.c:36}
 [kernel:annot:missing-spec] spawn_h.c:43: Warning: 
   Neither code nor specification for function posix_spawn_file_actions_init,
    generating default assigns. See -generated-spec-* options for more info
@@ -148,6 +148,8 @@
 [eva] Done for function exit
 [eva:alarm] spawn_h.c:82: Warning: 
   out of bounds read. assert \valid_read(argv + optind);
+[eva:garbled-mix:write] spawn_h.c:82: 
+  Assigning imprecise value to file because of misaligned read of addresses.
 [kernel:annot:missing-spec] spawn_h.c:82: Warning: 
   Neither code nor specification for function posix_spawnp,
    generating default assigns. See -generated-spec-* options for more info
@@ -250,6 +252,11 @@
 [eva] Done for function exit
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    spawn_h.c:36: assigns clause on addresses
+      (read 20 times, propagated 13 times)
+      garbled mix of &{S_argv; S_0_S_argv; S_1_S_argv}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main:
   NON TERMINATING FUNCTION
diff --git a/tests/libc/oracle/unistd_h.0.res.oracle b/tests/libc/oracle/unistd_h.0.res.oracle
index 24a810167ef1b8fa7ffc5041926c514863c09381..745680bb6430b69a9fe9a4977cd4d1a4ce99c5c5 100644
--- a/tests/libc/oracle/unistd_h.0.res.oracle
+++ b/tests/libc/oracle/unistd_h.0.res.oracle
@@ -12,6 +12,7 @@
   \return(lseek) == -1 (auto)
   \return(pipe) == 0 (auto)
   \return(read) == -1, 32 (auto)
+  \return(rmdir) == 0 (auto)
   \return(setegid) == 0 (auto)
   \return(seteuid) == 0 (auto)
   \return(setgid) == 0 (auto)
@@ -58,6 +59,9 @@
   function execv: precondition 'valid_string_path' got status valid.
 [eva] unistd_h.c:17: 
   function execv: precondition 'valid_string_argv0' got status valid.
+[eva:garbled-mix:assigns] unistd_h.c:17: 
+  The specification of function execv has generated a garbled mix of addresses
+  for assigns clause \result.
 [eva] Done for function execv
 [eva] computing for function execv <- main.
   Called from unistd_h.c:17.
@@ -612,6 +616,13 @@
 [eva] computing for function read <- main.
   Called from unistd_h.c:118.
 [eva] Done for function read
+[eva] computing for function rmdir <- main.
+  Called from unistd_h.c:120.
+[eva] using specification for function rmdir
+[eva] unistd_h.c:120: 
+  function rmdir: precondition 'valid_name' got status valid.
+[eva] Done for function rmdir
+[eva] unistd_h.c:121: check 'ok' got status valid.
 [eva] Recording results for main
 [eva] Done for function main
 [eva] ====== VALUES COMPUTED ======
diff --git a/tests/libc/oracle/unistd_h.1.res.oracle b/tests/libc/oracle/unistd_h.1.res.oracle
index 6700c7c0c09d7703e48a21bede0c3d93060c8d80..03cb1465a1931d15e35283c9f6b6dbee89388c8f 100644
--- a/tests/libc/oracle/unistd_h.1.res.oracle
+++ b/tests/libc/oracle/unistd_h.1.res.oracle
@@ -12,6 +12,7 @@
   \return(lseek) == -1 (auto)
   \return(pipe) == 0 (auto)
   \return(read) == -1, 32 (auto)
+  \return(rmdir) == 0 (auto)
   \return(setegid) == 0 (auto)
   \return(seteuid) == 0 (auto)
   \return(setgid) == 0 (auto)
@@ -612,6 +613,13 @@
 [eva] computing for function read <- main.
   Called from unistd_h.c:118.
 [eva] Done for function read
+[eva] computing for function rmdir <- main.
+  Called from unistd_h.c:120.
+[eva] using specification for function rmdir
+[eva] unistd_h.c:120: 
+  function rmdir: precondition 'valid_name' got status valid.
+[eva] Done for function rmdir
+[eva] unistd_h.c:121: check 'ok' got status valid.
 [eva] Recording results for main
 [eva] Done for function main
 [eva] ====== VALUES COMPUTED ======
diff --git a/tests/libc/unistd_h.c b/tests/libc/unistd_h.c
index a8b8dbba169df6fe6632a2f50137619af62162b1..89c9ac5baae555a1d8d91918abca6148f7b2420a 100644
--- a/tests/libc/unistd_h.c
+++ b/tests/libc/unistd_h.c
@@ -117,5 +117,8 @@ int main() {
   rread = read(fd, buf, SSIZE_MAX);
   rread = read(fd, buf, SIZE_MAX);
 
+  r = rmdir("/tmp/foo");
+  //@ check ok: r == 0 || r == -1;
+
   return 0;
 }
diff --git a/tests/metrics/oracle/libc.json b/tests/metrics/oracle/libc.json
index 7acca29f4fea0e177826075be8ee65194383e8da..912a2a97651516f781c7c5ec2cd1328614c060f7 100644
--- a/tests/metrics/oracle/libc.json
+++ b/tests/metrics/oracle/libc.json
@@ -104,6 +104,7 @@
     { "remove": { "calls": 0, "address_taken": false } },
     { "rename": { "calls": 0, "address_taken": false } },
     { "rewind": { "calls": 0, "address_taken": false } },
+    { "rmdir": { "calls": 0, "address_taken": false } },
     { "setbuf": { "calls": 0, "address_taken": false } },
     { "setegid": { "calls": 0, "address_taken": false } },
     { "seteuid": { "calls": 0, "address_taken": false } },
diff --git a/tests/misc/bts1347.ml b/tests/misc/bts1347.ml
index b89b9009d34d9dc3f4a9b9fbecf6593eb6a3aca6..71eab2c4a2a414f9abe38e41eb366d5aa1169c78 100644
--- a/tests/misc/bts1347.ml
+++ b/tests/misc/bts1347.ml
@@ -5,7 +5,7 @@ let emitter =
 let run () =
   Globals.Functions.iter
     (fun kf ->
-       if not (Cil_builtins.is_builtin (Kernel_function.get_vi kf)) then begin
+       if not (Cil_builtins.has_fc_builtin_attr (Kernel_function.get_vi kf)) then begin
          Globals.set_entry_point (Kernel_function.get_name kf) true;
          Eva.Analysis.compute();
          let hyps =
diff --git a/tests/misc/conditionnal_void_operands.i b/tests/misc/conditionnal_void_operands.i
new file mode 100644
index 0000000000000000000000000000000000000000..a5d76bee84035d21e581236d93e8bbefbb3f108f
--- /dev/null
+++ b/tests/misc/conditionnal_void_operands.i
@@ -0,0 +1,9 @@
+/* run.config
+   OPT: -no-autoload-plugins -print
+*/
+
+void f(int x) {
+  // ISO 6.5.15#3 : both operands have void type
+  void a, b;
+  x ? a : b;
+}
diff --git a/tests/misc/oracle/audit-out.json b/tests/misc/oracle/audit-out.json
index b80ff7dde480bdca61583ab08da82fa153e10286..50dffc4456619419bf73da47d9715b0a4ee6ba1c 100644
--- a/tests/misc/oracle/audit-out.json
+++ b/tests/misc/oracle/audit-out.json
@@ -44,10 +44,10 @@
         "unknown-size"
       ],
       "disabled": [
-        "garbled-mix:assigns", "garbled-mix:read", "garbled-mix:summary",
-        "garbled-mix:write", "invalid-assigns", "loop-unroll:auto",
-        "loop-unroll:missing", "loop-unroll:missing:for",
-        "loop-unroll:partial", "malloc:weak", "watchpoint"
+        "garbled-mix:assigns", "garbled-mix:summary", "garbled-mix:write",
+        "invalid-assigns", "loop-unroll:auto", "loop-unroll:missing",
+        "loop-unroll:missing:for", "loop-unroll:partial", "malloc:weak",
+        "watchpoint"
       ]
     }
   },
@@ -61,8 +61,9 @@
         "ghost:bad-use", "inline", "linker",
         "linker:drop-conflicting-unused", "linker:weak", "parser",
         "parser:conditional-feature", "parser:unnamed-typedef",
-        "parser:unsupported", "pp", "pp:compilation-db", "pp:line-directive",
-        "typing", "typing:implicit-conv-void-ptr",
+        "parser:unsupported", "parser:unsupported:attributes", "pp",
+        "pp:compilation-db", "pp:line-directive", "typing",
+        "typing:implicit-conv-void-ptr",
         "typing:implicit-function-declaration",
         "typing:incompatible-pointer-types",
         "typing:incompatible-types-call", "typing:inconsistent-specifier",
diff --git a/tests/misc/oracle/conditionnal_void_operands.res.oracle b/tests/misc/oracle/conditionnal_void_operands.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..b33472979d2cca274f19e16dec03d718e97daee0
--- /dev/null
+++ b/tests/misc/oracle/conditionnal_void_operands.res.oracle
@@ -0,0 +1,16 @@
+[kernel] Parsing conditionnal_void_operands.i (no preprocessing)
+/* Generated by Frama-C */
+void f(int x)
+{
+  void a;
+  void b;
+  if (x) {
+    void tmp = a;
+  }
+  else {
+    void tmp_3 = b;
+  }
+  return;
+}
+
+
diff --git a/tests/slicing/oracle/loops.10.res.oracle b/tests/slicing/oracle/loops.10.res.oracle
index 8b074bf06abdd613754931d1720a4884ceb3f673..7ba1874acead31fd20c084a227d3c52fa55f6fac 100644
--- a/tests/slicing/oracle/loops.10.res.oracle
+++ b/tests/slicing/oracle/loops.10.res.oracle
@@ -12,6 +12,9 @@
 [eva] computing for function may_write_Y_from_Z <- main.
   Called from loops.i:199.
 [eva] using specification for function may_write_Y_from_Z
+[eva:garbled-mix:assigns] loops.i:199: 
+  The specification of function may_write_Y_from_Z
+  has generated a garbled mix of addresses for assigns clause *p.
 [eva] Done for function may_write_Y_from_Z
 [eva] computing for function loop <- main.
   Called from loops.i:202.
diff --git a/tests/slicing/oracle/loops.19.res.oracle b/tests/slicing/oracle/loops.19.res.oracle
index 34457cfad25d07e2868e3518708480733f7473fa..0998264ade13e755871e320c9cd50baadbcf6c06 100644
--- a/tests/slicing/oracle/loops.19.res.oracle
+++ b/tests/slicing/oracle/loops.19.res.oracle
@@ -12,6 +12,9 @@
 [eva] computing for function may_write_Y_from_Z <- main.
   Called from loops.i:199.
 [eva] using specification for function may_write_Y_from_Z
+[eva:garbled-mix:assigns] loops.i:199: 
+  The specification of function may_write_Y_from_Z
+  has generated a garbled mix of addresses for assigns clause *p.
 [eva] Done for function may_write_Y_from_Z
 [eva] computing for function loop <- main.
   Called from loops.i:202.
diff --git a/tests/slicing/oracle/loops.20.res.oracle b/tests/slicing/oracle/loops.20.res.oracle
index 27d8cdb835562da76ec04f76f72017aa7aaba1b0..6e18bd872d2d86d795df7d8d77af2cc984dd6a76 100644
--- a/tests/slicing/oracle/loops.20.res.oracle
+++ b/tests/slicing/oracle/loops.20.res.oracle
@@ -12,6 +12,9 @@
 [eva] computing for function may_write_Y_from_Z <- main.
   Called from loops.i:199.
 [eva] using specification for function may_write_Y_from_Z
+[eva:garbled-mix:assigns] loops.i:199: 
+  The specification of function may_write_Y_from_Z
+  has generated a garbled mix of addresses for assigns clause *p.
 [eva] Done for function may_write_Y_from_Z
 [eva] computing for function loop <- main.
   Called from loops.i:202.
diff --git a/tests/slicing/oracle/loops.21.res.oracle b/tests/slicing/oracle/loops.21.res.oracle
index 9adf543884b06243c38d066d660dce7d01610e18..8636ad07b17046ce79ca5ca1ab0eb519c01bf81c 100644
--- a/tests/slicing/oracle/loops.21.res.oracle
+++ b/tests/slicing/oracle/loops.21.res.oracle
@@ -12,6 +12,9 @@
 [eva] computing for function may_write_Y_from_Z <- main.
   Called from loops.i:199.
 [eva] using specification for function may_write_Y_from_Z
+[eva:garbled-mix:assigns] loops.i:199: 
+  The specification of function may_write_Y_from_Z
+  has generated a garbled mix of addresses for assigns clause *p.
 [eva] Done for function may_write_Y_from_Z
 [eva] computing for function loop <- main.
   Called from loops.i:202.
diff --git a/tests/slicing/oracle/loops.22.res.oracle b/tests/slicing/oracle/loops.22.res.oracle
index 7d41e9a40cdb66446abcee9448378d0a0ddbef06..3313fbc32d943908d3b6701ed97fdd379ff18096 100644
--- a/tests/slicing/oracle/loops.22.res.oracle
+++ b/tests/slicing/oracle/loops.22.res.oracle
@@ -12,6 +12,9 @@
 [eva] computing for function may_write_Y_from_Z <- main.
   Called from loops.i:199.
 [eva] using specification for function may_write_Y_from_Z
+[eva:garbled-mix:assigns] loops.i:199: 
+  The specification of function may_write_Y_from_Z
+  has generated a garbled mix of addresses for assigns clause *p.
 [eva] Done for function may_write_Y_from_Z
 [eva] computing for function loop <- main.
   Called from loops.i:202.
diff --git a/tests/slicing/oracle/loops.23.res.oracle b/tests/slicing/oracle/loops.23.res.oracle
index 24eb43a90cba0b80c99d1795f5b1566d2443857b..ae8f97a78fc3c8b783c571ad7895d4ad8ea25d81 100644
--- a/tests/slicing/oracle/loops.23.res.oracle
+++ b/tests/slicing/oracle/loops.23.res.oracle
@@ -12,6 +12,9 @@
 [eva] computing for function may_write_Y_from_Z <- main.
   Called from loops.i:199.
 [eva] using specification for function may_write_Y_from_Z
+[eva:garbled-mix:assigns] loops.i:199: 
+  The specification of function may_write_Y_from_Z
+  has generated a garbled mix of addresses for assigns clause *p.
 [eva] Done for function may_write_Y_from_Z
 [eva] computing for function loop <- main.
   Called from loops.i:202.
diff --git a/tests/slicing/oracle/loops.8.res.oracle b/tests/slicing/oracle/loops.8.res.oracle
index 3c7880c3af1ec26d5a6c78fa64382ce48b28eaf5..f1d9bbd86696821f18cab14e3276c13346963cb5 100644
--- a/tests/slicing/oracle/loops.8.res.oracle
+++ b/tests/slicing/oracle/loops.8.res.oracle
@@ -12,6 +12,9 @@
 [eva] computing for function may_write_Y_from_Z <- main.
   Called from loops.i:199.
 [eva] using specification for function may_write_Y_from_Z
+[eva:garbled-mix:assigns] loops.i:199: 
+  The specification of function may_write_Y_from_Z
+  has generated a garbled mix of addresses for assigns clause *p.
 [eva] Done for function may_write_Y_from_Z
 [eva] computing for function loop <- main.
   Called from loops.i:202.
diff --git a/tests/slicing/oracle/loops.9.res.oracle b/tests/slicing/oracle/loops.9.res.oracle
index abc0b21b556922c6b9b00615dfba3fe01f412bbb..a2caa35921cfccd62af77a1b13f943464086f2cd 100644
--- a/tests/slicing/oracle/loops.9.res.oracle
+++ b/tests/slicing/oracle/loops.9.res.oracle
@@ -12,6 +12,9 @@
 [eva] computing for function may_write_Y_from_Z <- main.
   Called from loops.i:199.
 [eva] using specification for function may_write_Y_from_Z
+[eva:garbled-mix:assigns] loops.i:199: 
+  The specification of function may_write_Y_from_Z
+  has generated a garbled mix of addresses for assigns clause *p.
 [eva] Done for function may_write_Y_from_Z
 [eva] computing for function loop <- main.
   Called from loops.i:202.
diff --git a/tests/syntax/cast-struct-function-attr.i b/tests/syntax/cast-struct-function-attr.i
new file mode 100644
index 0000000000000000000000000000000000000000..d284cd66c6f948349613fb3d9e87e405cc1a98f5
--- /dev/null
+++ b/tests/syntax/cast-struct-function-attr.i
@@ -0,0 +1,15 @@
+/* run.config*
+  LOG: @PTEST_NAME@_ocode.i
+  STDOPT: -print -ocode @PTEST_NAME@_ocode.i
+ENABLED_IF: %{bin-available:gcc}
+  EXECNOW: LOG @PTEST_NAME@.out LOG @PTEST_NAME@.err gcc %{dep:@PTEST_NAME@_ocode.i} -c -o @DEV_NULL@ > @PTEST_NAME@.out 2> @PTEST_NAME@.err
+*/
+
+struct t {
+  int a;
+};
+typedef struct t t;
+__attribute__((visibility("hidden"))) t f() {
+  t res = {0};
+  return res;
+}
diff --git a/tests/syntax/enum-attr-init.i b/tests/syntax/enum-attr-init.i
new file mode 100644
index 0000000000000000000000000000000000000000..ada94efeba0c08e06920ebd8e087bbc9b0f09a86
--- /dev/null
+++ b/tests/syntax/enum-attr-init.i
@@ -0,0 +1,10 @@
+//excerpt based on glib's gregex.h
+typedef enum {
+  G_REGEX_BSR_ANYCRLF = 1 << 23,
+  G_REGEX_JAVASCRIPT_COMPAT __attribute__((deprecated)) = 1 << 25
+} GRegexCompileFlags;
+
+enum enum2 {
+  FALSE __attribute__((false)),
+  TRUE __attribute__((true))
+};
diff --git a/tests/syntax/oracle/cast-struct-function-attr.res.oracle b/tests/syntax/oracle/cast-struct-function-attr.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..e2ac976c5094141a728ffa2760e13a24725641ca
--- /dev/null
+++ b/tests/syntax/oracle/cast-struct-function-attr.res.oracle
@@ -0,0 +1 @@
+[kernel] Parsing cast-struct-function-attr.i (no preprocessing)
diff --git a/tests/syntax/oracle/cast-struct-function-attr_ocode.i b/tests/syntax/oracle/cast-struct-function-attr_ocode.i
new file mode 100644
index 0000000000000000000000000000000000000000..03dbb7f08ee8af4eae99b62f8a1e7e64c920b8e5
--- /dev/null
+++ b/tests/syntax/oracle/cast-struct-function-attr_ocode.i
@@ -0,0 +1,12 @@
+/* Generated by Frama-C */
+struct t {
+   int a ;
+};
+typedef struct t t;
+t __attribute__((__visibility__("hidden"))) f(void)
+{
+  t res = {.a = 0};
+  return res;
+}
+
+
diff --git a/tests/syntax/oracle/enum-attr-init.res.oracle b/tests/syntax/oracle/enum-attr-init.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..b74990576c2790c37f19b44e5685df85f51c8f42
--- /dev/null
+++ b/tests/syntax/oracle/enum-attr-init.res.oracle
@@ -0,0 +1,12 @@
+[kernel] Parsing enum-attr-init.i (no preprocessing)
+[kernel:parser:unsupported:attributes] enum-attr-init.i:4: Warning: 
+  Discarding attributes in enumerator (unsupported feature): 
+  __attribute__((deprecated))
+[kernel:parser:unsupported:attributes] enum-attr-init.i:8: Warning: 
+  Discarding attributes in enumerator (unsupported feature): 
+  __attribute__((false))
+[kernel:parser:unsupported:attributes] enum-attr-init.i:9: Warning: 
+  Discarding attributes in enumerator (unsupported feature): 
+  __attribute__((true))
+/* Generated by Frama-C */
+
diff --git a/tests/syntax/oracle/too_large_array.res.oracle b/tests/syntax/oracle/too_large_array.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..1db88ceff98a128c833f34e29b0639593793b8a8
--- /dev/null
+++ b/tests/syntax/oracle/too_large_array.res.oracle
@@ -0,0 +1,6 @@
+[kernel] Parsing too_large_array.i (no preprocessing)
+[kernel] too_large_array.i:12: User Error: Array length is too large.
+[kernel] too_large_array.i:12: Warning: 
+  Cannot represent length of array as an attribute
+[kernel] User Error: stopping on file "too_large_array.i" that has errors.
+[kernel] Frama-C aborted: invalid user input.
diff --git a/tests/syntax/oracle/variadic_fresh_names.res.oracle b/tests/syntax/oracle/variadic_fresh_names.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..1fb230dff45abd65517f9051ac02522c249c33fa
--- /dev/null
+++ b/tests/syntax/oracle/variadic_fresh_names.res.oracle
@@ -0,0 +1,39 @@
+[kernel] Parsing variadic_fresh_names.c (with preprocessing)
+/* Generated by Frama-C */
+#include "errno.h"
+#include "stdarg.h"
+#include "stddef.h"
+#include "stdio.h"
+/*@ requires valid_read_string(format);
+    assigns \result, stream->__fc_FILE_data;
+    assigns \result
+      \from (indirect: stream->__fc_FILE_id),
+            (indirect: stream->__fc_FILE_data),
+            (indirect: *(format + (0 ..))), (indirect: param0);
+    assigns stream->__fc_FILE_data
+      \from (indirect: stream->__fc_FILE_id), stream->__fc_FILE_data,
+            (indirect: *(format + (0 ..))), param0;
+ */
+int fprintf_va_1(FILE * restrict stream, char const * restrict format,
+                 int param0);
+
+/*@ requires valid_read_string(format);
+    assigns \result, stream->__fc_FILE_data;
+    assigns \result
+      \from (indirect: stream->__fc_FILE_id),
+            (indirect: stream->__fc_FILE_data),
+            (indirect: *(format + (0 ..))), (indirect: param0);
+    assigns stream->__fc_FILE_data
+      \from (indirect: stream->__fc_FILE_id), stream->__fc_FILE_data,
+            (indirect: *(format + (0 ..))), param0;
+ */
+int fprintf_va_2(FILE * restrict stream, char const * restrict format,
+                 int param0);
+
+void main(void)
+{
+  fprintf(__fc_stderr,"%d ",42); /* fprintf_va_2 */
+  return;
+}
+
+
diff --git a/tests/syntax/oracle/very_large_integers.1.res.oracle b/tests/syntax/oracle/very_large_integers.1.res.oracle
index 4f4479d850994060abd17b9c1bb2c03213580381..543e2f77a34315e860d772c2f77dff770b5c85e6 100644
--- a/tests/syntax/oracle/very_large_integers.1.res.oracle
+++ b/tests/syntax/oracle/very_large_integers.1.res.oracle
@@ -1,4 +1,5 @@
 [kernel] Parsing very_large_integers.c (with preprocessing)
+[kernel] very_large_integers.c:41: User Error: Array length is too large.
 [kernel] very_large_integers.c:42: User Error: 
   Cannot represent the integer 99999999999999999999U
 [kernel] very_large_integers.c:42: User Error: 
diff --git a/tests/syntax/oracle/very_large_integers.14.res.oracle b/tests/syntax/oracle/very_large_integers.14.res.oracle
index 258dd40268376ba56fbcb9483b044db1419715b2..bfd5d8b7eb57423236a1136fb001b9e59c49351b 100644
--- a/tests/syntax/oracle/very_large_integers.14.res.oracle
+++ b/tests/syntax/oracle/very_large_integers.14.res.oracle
@@ -4,6 +4,7 @@
 [kernel] very_large_integers.c:84: Warning: 
   ignoring invalid aligned attribute: __aligned__((9223372036854775808)+
                                                    (9223372036854775808) )
+[kernel] very_large_integers.c:106: User Error: Array length is too large.
 [kernel] very_large_integers.c:113: User Error: 
   array length too large: 7205759403792794
   111   };
diff --git a/tests/syntax/oracle/very_large_integers.4.res.oracle b/tests/syntax/oracle/very_large_integers.4.res.oracle
index ca9b712f16e76c21ccb54af94f7894a05433dd92..77a8b542245f0fbe7d3a2607a9f110cf9a092df9 100644
--- a/tests/syntax/oracle/very_large_integers.4.res.oracle
+++ b/tests/syntax/oracle/very_large_integers.4.res.oracle
@@ -1,4 +1,5 @@
 [kernel] Parsing very_large_integers.c (with preprocessing)
+[kernel] very_large_integers.c:62: User Error: Array length is too large.
 [kernel] very_large_integers.c:62: User Error: 
   Array length 9999999999999999999U is too big: no explicit initializer allowed.
   60    
diff --git a/src/plugins/wp/tests/wp_typed/too_large_array.i b/tests/syntax/too_large_array.i
similarity index 100%
rename from src/plugins/wp/tests/wp_typed/too_large_array.i
rename to tests/syntax/too_large_array.i
diff --git a/tests/syntax/variadic_fresh_names.c b/tests/syntax/variadic_fresh_names.c
new file mode 100644
index 0000000000000000000000000000000000000000..46615262b2d8bdc38fdafb9b32a4b4b5a65296fa
--- /dev/null
+++ b/tests/syntax/variadic_fresh_names.c
@@ -0,0 +1,24 @@
+/* run.config
+PLUGIN: variadic
+STDOPT:
+*/
+#include "stdio.h"
+
+/*@ requires valid_read_string(format);
+    assigns \result, stream->__fc_FILE_data;
+    assigns \result
+      \from (indirect: stream->__fc_FILE_id),
+            (indirect: stream->__fc_FILE_data),
+            (indirect: *(format + (0 ..))), (indirect: param0);
+    assigns stream->__fc_FILE_data
+      \from (indirect: stream->__fc_FILE_id), stream->__fc_FILE_data,
+            (indirect: *(format + (0 ..))), param0;
+ */
+int fprintf_va_1(FILE * restrict stream, char const * restrict format,
+                 int param0);
+
+void main(void)
+{
+  fprintf(__fc_stderr,"%d ",42); /* fprintf_va_1 */
+  return;
+}
diff --git a/tests/value/oracle/addition.res.oracle b/tests/value/oracle/addition.res.oracle
index bb68a90bfb7a65ffac5bbbed34e7e8fa86d5bc50..394936b8b9df05a61b4935cb721c0e66380efa36 100644
--- a/tests/value/oracle/addition.res.oracle
+++ b/tests/value/oracle/addition.res.oracle
@@ -57,27 +57,23 @@
 [eva:alarm] addition.i:34: Warning: 
   signed overflow. assert &p2 - &p3 ≤ 2147483647;
 [eva:garbled-mix:write] addition.i:34: Warning: 
-  Assigning imprecise value to p1.
-  The imprecision originates from Arithmetic {addition.i:34}
+  Assigning imprecise value to p1 because of arithmetic operation on addresses.
 [eva:alarm] addition.i:36: Warning: 
   pointer downcast. assert (unsigned int)(&p1) ≤ 2147483647;
 [eva:garbled-mix:write] addition.i:36: Warning: 
-  Assigning imprecise value to p2.
-  The imprecision originates from Arithmetic {addition.i:36}
+  Assigning imprecise value to p2 because of arithmetic operation on addresses.
 [eva:alarm] addition.i:38: Warning: 
   pointer downcast. assert (unsigned int)(&p1) ≤ 127;
 [eva:alarm] addition.i:38: Warning: 
   pointer downcast. assert (unsigned int)(&t[(char)(&p1)]) ≤ 2147483647;
 [eva:garbled-mix:write] addition.i:38: Warning: 
-  Assigning imprecise value to p3.
-  The imprecision originates from Arithmetic {addition.i:38}
+  Assigning imprecise value to p3 because of arithmetic operation on addresses.
 [eva:alarm] addition.i:40: Warning: 
   pointer downcast. assert (unsigned int)(&p1) ≤ 127;
 [eva:alarm] addition.i:40: Warning: 
   pointer downcast. assert (unsigned int)(&tt[(char)(&p1)].a) ≤ 2147483647;
 [eva:garbled-mix:write] addition.i:40: Warning: 
-  Assigning imprecise value to p4.
-  The imprecision originates from Arithmetic {addition.i:40}
+  Assigning imprecise value to p4 because of arithmetic operation on addresses.
 [eva:alarm] addition.i:42: Warning: 
   pointer downcast. assert (unsigned int)(&p1) ≤ 127;
 [eva:alarm] addition.i:42: Warning: 
@@ -86,24 +82,21 @@
   pointer downcast.
   assert (unsigned int)(&ttt[(char)(&p1)][(char)(&p2)]) ≤ 2147483647;
 [eva:garbled-mix:write] addition.i:42: Warning: 
-  Assigning imprecise value to p5.
-  The imprecision originates from Arithmetic {addition.i:42}
+  Assigning imprecise value to p5 because of arithmetic operation on addresses.
 [eva:alarm] addition.i:44: Warning: 
   pointer downcast. assert (unsigned int)(&p1) ≤ 127;
 [eva:alarm] addition.i:44: Warning: 
   pointer downcast.
   assert (unsigned int)(&ttt[(char)(&p1)][u2]) ≤ 2147483647;
 [eva:garbled-mix:write] addition.i:44: Warning: 
-  Assigning imprecise value to p6.
-  The imprecision originates from Arithmetic {addition.i:44}
+  Assigning imprecise value to p6 because of arithmetic operation on addresses.
 [eva:alarm] addition.i:46: Warning: 
   pointer downcast. assert (unsigned int)(&p2) ≤ 127;
 [eva:alarm] addition.i:46: Warning: 
   pointer downcast.
   assert (unsigned int)(&ttt[u2][(char)(&p2)]) ≤ 2147483647;
 [eva:garbled-mix:write] addition.i:46: Warning: 
-  Assigning imprecise value to p7.
-  The imprecision originates from Arithmetic {addition.i:46}
+  Assigning imprecise value to p7 because of arithmetic operation on addresses.
 [eva:alarm] addition.i:48: Warning: 
   pointer comparison.
   assert \pointer_comparable((void *)(&p1 + 1), (void *)(&p2));
@@ -114,57 +107,37 @@
 [eva:alarm] addition.i:50: Warning: 
   signed overflow. assert (int)(&p1) / 2 ≤ 2147483647;
 [eva:garbled-mix:write] addition.i:50: Warning: 
-  Assigning imprecise value to p9.
-  The imprecision originates from Arithmetic {addition.i:50}
+  Assigning imprecise value to p9 because of arithmetic operation on addresses.
 [eva:alarm] addition.i:52: Warning: 
   pointer downcast. assert (unsigned int)(&p1) ≤ 2147483647;
 [eva:garbled-mix:write] addition.i:52: Warning: 
-  Assigning imprecise value to p10.
-  The imprecision originates from Arithmetic {addition.i:52}
+  Assigning imprecise value to p10
+  because of arithmetic operation on addresses.
 [eva:alarm] addition.i:56: Warning: 
   pointer downcast. assert (unsigned int)(&p1) ≤ 2147483647;
 [eva:alarm] addition.i:56: Warning: 
   pointer downcast. assert (unsigned int)(&p2) ≤ 2147483647;
 [eva:garbled-mix:write] addition.i:56: Warning: 
-  Assigning imprecise value to p12.
-  The imprecision originates from Arithmetic {addition.i:56}
+  Assigning imprecise value to p12
+  because of arithmetic operation on addresses.
 [eva:alarm] addition.i:59: Warning: 
   signed overflow. assert -2147483648 ≤ (int)*((char *)(&q1)) + 2;
 [eva:alarm] addition.i:59: Warning: 
   signed overflow. assert (int)*((char *)(&q1)) + 2 ≤ 2147483647;
 [eva:garbled-mix:write] addition.i:59: Warning: 
-  Assigning imprecise value to p13.
-  The imprecision originates from Misaligned {addition.i:59}
+  Assigning imprecise value to p13 because of misaligned read of addresses.
 [eva:alarm] addition.i:61: Warning: 
   signed overflow. assert -2147483648 ≤ (int)*((char *)(&q1)) + 2;
 [eva:alarm] addition.i:61: Warning: 
   signed overflow. assert (int)*((char *)(&q1)) + 2 ≤ 2147483647;
 [eva:garbled-mix:write] addition.i:61: Warning: 
-  Assigning imprecise value to p14.
-  The imprecision originates from Misaligned {addition.i:61}
+  Assigning imprecise value to p14 because of misaligned read of addresses.
 [eva:alarm] addition.i:66: Warning: 
   out of bounds read. assert \valid_read(*((int **)45));
 [eva] addition.i:87: Frama_C_show_each_1: [-10..15]
 [eva] addition.i:88: assertion got status valid.
 [eva] Recording results for main
 [eva] Done for function main
-[eva:garbled-mix:summary] Warning: 
-  Garbled mix generated during analysis:
-  {{ garbled mix of &{p3} (origin: Arithmetic {addition.i:34}) }}
-  {{ garbled mix of &{p2} (origin: Arithmetic {addition.i:34}) }}
-  {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:36}) }}
-  {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:38}) }}
-  {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:40}) }}
-  {{ garbled mix of &{p2} (origin: Arithmetic {addition.i:42}) }}
-  {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:42}) }}
-  {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:44}) }}
-  {{ garbled mix of &{p2} (origin: Arithmetic {addition.i:46}) }}
-  {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:50}) }}
-  {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:52}) }}
-  {{ garbled mix of &{p2} (origin: Arithmetic {addition.i:56}) }}
-  {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:56}) }}
-  {{ garbled mix of &{p1} (origin: Misaligned {addition.i:59}) }}
-  {{ garbled mix of &{p1} (origin: Misaligned {addition.i:61}) }}
 [scope:rm_asserts] removing 9 assertion(s)
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main:
@@ -186,8 +159,10 @@
   p10 ∈ {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:52}) }}
   p11 ∈ [-2147483648..0],0%4
   p12 ∈ {{ garbled mix of &{p1; p2} (origin: Arithmetic {addition.i:56}) }}
-  p13 ∈ {{ garbled mix of &{p1} (origin: Misaligned {addition.i:59}) }}
-  p14 ∈ {{ garbled mix of &{p1} (origin: Misaligned {addition.i:61}) }}
+  p13 ∈
+     {{ garbled mix of &{p1} (origin: Misaligned read {addition.i:59}) }}
+  p14 ∈
+     {{ garbled mix of &{p1} (origin: Misaligned read {addition.i:61}) }}
   p15 ∈ {-1}
   p16 ∈ {2949122}
   p17 ∈ {-2147483648; 0}
@@ -390,23 +365,6 @@
 [eva] addition.i:87: Frama_C_show_each_1: [-10..15]
 [eva] Recording results for main
 [eva] Done for function main
-[eva:garbled-mix:summary] Warning: 
-  Garbled mix generated during analysis:
-  {{ garbled mix of &{p3} (origin: Arithmetic {addition.i:34}) }}
-  {{ garbled mix of &{p2} (origin: Arithmetic {addition.i:34}) }}
-  {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:36}) }}
-  {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:38}) }}
-  {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:40}) }}
-  {{ garbled mix of &{p2} (origin: Arithmetic {addition.i:42}) }}
-  {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:42}) }}
-  {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:44}) }}
-  {{ garbled mix of &{p2} (origin: Arithmetic {addition.i:46}) }}
-  {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:50}) }}
-  {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:52}) }}
-  {{ garbled mix of &{p2} (origin: Arithmetic {addition.i:56}) }}
-  {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:56}) }}
-  {{ garbled mix of &{p1} (origin: Misaligned {addition.i:59}) }}
-  {{ garbled mix of &{p1} (origin: Misaligned {addition.i:61}) }}
 [scope:rm_asserts] removing 9 assertion(s)
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main:
@@ -429,8 +387,10 @@
   p10 ∈ {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:52}) }}
   p11 ∈ [-2147483648..0],0%4
   p12 ∈ {{ garbled mix of &{p1; p2} (origin: Arithmetic {addition.i:56}) }}
-  p13 ∈ {{ garbled mix of &{p1} (origin: Misaligned {addition.i:59}) }}
-  p14 ∈ {{ garbled mix of &{p1} (origin: Misaligned {addition.i:61}) }}
+  p13 ∈
+     {{ garbled mix of &{p1} (origin: Misaligned read {addition.i:59}) }}
+  p14 ∈
+     {{ garbled mix of &{p1} (origin: Misaligned read {addition.i:61}) }}
   p15 ∈ {-1}
   p16 ∈ {2; 2949122; 3014658}
   p17 ∈ {-2147483648; 0}
diff --git a/tests/value/oracle/arith_pointer.res.oracle b/tests/value/oracle/arith_pointer.res.oracle
index 2397783f775ed506dd5127623508426785d8e2c2..2261d0849e3e6080bb275a5c6d6ea2a23ef5ef62 100644
--- a/tests/value/oracle/arith_pointer.res.oracle
+++ b/tests/value/oracle/arith_pointer.res.oracle
@@ -25,17 +25,13 @@
 [eva:alarm] arith_pointer.c:54: Warning: 
   pointer downcast. assert (unsigned int)(&x) ≤ 2147483647;
 [eva:garbled-mix:write] arith_pointer.c:54: 
-  Assigning imprecise value to p1.
-  The imprecision originates from Arithmetic {arith_pointer.c:54}
+  Assigning imprecise value to p1 because of arithmetic operation on addresses.
 [eva:alarm] arith_pointer.c:56: Warning: 
   pointer subtraction. assert \base_addr(p2) ≡ \base_addr(p1);
 [eva:alarm] arith_pointer.c:56: Warning: 
   signed overflow. assert -2147483648 ≤ p2 - p1;
 [eva:alarm] arith_pointer.c:56: Warning: 
   signed overflow. assert p2 - p1 ≤ 2147483647;
-[eva:garbled-mix:write] arith_pointer.c:56: 
-  Assigning imprecise value to d.
-  The imprecision originates from Arithmetic {arith_pointer.c:54}
 [eva] arith_pointer.c:57: 
   Frama_C_show_each:
   {{ garbled mix of &{x} (origin: Arithmetic {arith_pointer.c:54}) }}
@@ -46,6 +42,10 @@
 [eva] Done for function main2
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    arith_pointer.c:54: arithmetic operation on addresses
+      (read 2 times, propagated 2 times) garbled mix of &{x}
 [eva] arith_pointer.c:30: 
   assertion 'Eva,differing_blocks' got final status invalid.
 [eva] ====== VALUES COMPUTED ======
@@ -117,8 +117,7 @@
 [eva:alarm] arith_pointer.c:30: Warning: 
   signed overflow. assert p1 - p2 ≤ 2147483647;
 [eva:garbled-mix:write] arith_pointer.c:30: 
-  Assigning imprecise value to d.
-  The imprecision originates from Arithmetic {arith_pointer.c:30}
+  Assigning imprecise value to d because of arithmetic operation on addresses.
 [eva] arith_pointer.c:31: 
   Frama_C_show_each:
   {{ garbled mix of &{x; y} (origin: Arithmetic {arith_pointer.c:30}) }}
@@ -129,8 +128,7 @@
 [eva:alarm] arith_pointer.c:49: Warning: 
   signed overflow. assert p2 - p1 ≤ 2147483647;
 [eva:garbled-mix:write] arith_pointer.c:49: 
-  Assigning imprecise value to d.
-  The imprecision originates from Arithmetic {arith_pointer.c:49}
+  Assigning imprecise value to d because of arithmetic operation on addresses.
 [eva] arith_pointer.c:50: 
   Frama_C_show_each:
   {{ garbled mix of &{x; y} (origin: Arithmetic {arith_pointer.c:49}) }}
@@ -139,8 +137,7 @@
 [eva:alarm] arith_pointer.c:51: Warning: 
   signed overflow. assert p2 - p2 ≤ 2147483647;
 [eva:garbled-mix:write] arith_pointer.c:51: 
-  Assigning imprecise value to d.
-  The imprecision originates from Arithmetic {arith_pointer.c:51}
+  Assigning imprecise value to d because of arithmetic operation on addresses.
 [eva] arith_pointer.c:52: 
   Frama_C_show_each:
   {{ garbled mix of &{x; y} (origin: Arithmetic {arith_pointer.c:51}) }}
@@ -150,16 +147,24 @@
   signed overflow. assert -2147483648 ≤ p2 - p1;
 [eva:alarm] arith_pointer.c:56: Warning: 
   signed overflow. assert p2 - p1 ≤ 2147483647;
-[eva:garbled-mix:write] arith_pointer.c:56: 
-  Assigning imprecise value to d.
-  The imprecision originates from Arithmetic
 [eva] arith_pointer.c:57: 
-  Frama_C_show_each: {{ garbled mix of &{x} (origin: Arithmetic) }}
+  Frama_C_show_each:
+  {{ garbled mix of &{x} (origin: Arithmetic {arith_pointer.c:54}) }}
 [eva] arith_pointer.c:64: Frama_C_show_each: [-3..5]
 [eva] Recording results for main2
 [eva] Done for function main2
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    arith_pointer.c:54: arithmetic operation on addresses
+      (read 2 times, propagated 2 times) garbled mix of &{x}
+    arith_pointer.c:30: arithmetic operation on addresses
+      (read 1 times, propagated 1 times) garbled mix of &{x; y}
+    arith_pointer.c:49: arithmetic operation on addresses
+      (read 1 times, propagated 1 times) garbled mix of &{x; y}
+    arith_pointer.c:51: arithmetic operation on addresses
+      (read 1 times, propagated 1 times) garbled mix of &{x; y}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main1:
   t[0..1] ∈ {-3}
diff --git a/tests/value/oracle/assign-leaf-indirect.res.oracle b/tests/value/oracle/assign-leaf-indirect.res.oracle
index d1632315bcb6bce72993ab83ee145e4ba4229247..4d4a939a92b3718e5132e1408fe9eef94151bfa8 100644
--- a/tests/value/oracle/assign-leaf-indirect.res.oracle
+++ b/tests/value/oracle/assign-leaf-indirect.res.oracle
@@ -9,6 +9,9 @@
 [eva] computing for function f <- main.
   Called from assign-leaf-indirect.i:8.
 [eva] using specification for function f
+[eva:garbled-mix:assigns] assign-leaf-indirect.i:8: 
+  The specification of function f has generated a garbled mix of addresses
+  for assigns clause y.
 [eva] Done for function f
 [eva] computing for function g <- main.
   Called from assign-leaf-indirect.i:9.
diff --git a/tests/value/oracle/assigns.res.oracle b/tests/value/oracle/assigns.res.oracle
index 744d7aab558ef0bcada92ce5326773be1186e880..110f45908bae6a5907c06fea0ab8efd97a7332c5 100644
--- a/tests/value/oracle/assigns.res.oracle
+++ b/tests/value/oracle/assigns.res.oracle
@@ -50,6 +50,9 @@
   signed overflow. assert -2147483648 ≤ 2 * (int)(&T);
 [eva:alarm] assigns.i:51: Warning: 
   signed overflow. assert 2 * (int)(&T) ≤ 2147483647;
+[eva:garbled-mix:write] assigns.i:51: 
+  Assigning imprecise value to len
+  because of arithmetic operation on addresses.
 [eva] computing for function g <- main1 <- main.
   Called from assigns.i:51.
 [eva] using specification for function g
@@ -60,6 +63,8 @@
   signed overflow. assert -2147483648 ≤ 2 * (int)(&t3);
 [eva:alarm] assigns.i:52: Warning: 
   signed overflow. assert 2 * (int)(&t3) ≤ 2147483647;
+[eva:garbled-mix:write] assigns.i:52: 
+  Assigning imprecise value to p because of arithmetic operation on addresses.
 [eva] computing for function h <- main1 <- main.
   Called from assigns.i:52.
 [eva] using specification for function h
diff --git a/tests/value/oracle/assigns_from.res.oracle b/tests/value/oracle/assigns_from.res.oracle
index 002087f31ba8abd39638d82d19e0589a787a698a..be60cecebede8380f7df749aecdd254fe0bcc968 100644
--- a/tests/value/oracle/assigns_from.res.oracle
+++ b/tests/value/oracle/assigns_from.res.oracle
@@ -298,6 +298,9 @@
 [eva] computing for function f18 <- main18 <- main.
   Called from assigns_from.i:215.
 [eva] using specification for function f18
+[eva:garbled-mix:assigns] assigns_from.i:215: 
+  The specification of function f18 has generated a garbled mix of addresses
+  for assigns clause *x.
 [eva] Done for function f18
 [eva] Recording results for main18
 [from] Computing for function main18
@@ -370,17 +373,17 @@
   base_a ∈ {17}
   a_0.addr ∈
      {{ garbled mix of &{base_a; base_b}
-      (origin: Misaligned {assigns_from.i:215}) }}
+      (origin: Misaligned read {assigns_from.i:215}) }}
      .i ∈
      {{ garbled mix of &{base_a; base_b}
-      (origin: Misaligned {assigns_from.i:215}) }} or UNINITIALIZED
+      (origin: Misaligned read {assigns_from.i:215}) }} or UNINITIALIZED
   base_b ∈ {11}
   b.addr ∈
    {{ garbled mix of &{base_a; base_b}
-    (origin: Misaligned {assigns_from.i:215}) }}
+    (origin: Misaligned read {assigns_from.i:215}) }}
    .i ∈
    {{ garbled mix of &{base_a; base_b}
-    (origin: Misaligned {assigns_from.i:215}) }} or UNINITIALIZED
+    (origin: Misaligned read {assigns_from.i:215}) }} or UNINITIALIZED
 [eva:final-states] Values at end of function main2:
   a[0..2] ∈ {0}
    [3] ∈ {2}
diff --git a/tests/value/oracle/backward_add_ptr.res.oracle b/tests/value/oracle/backward_add_ptr.res.oracle
index aa5bb85d7250e40cd2b703b4a4807dcc83115c30..35d0fce388bc2f9a9d8e16c79392d358cc71385b 100644
--- a/tests/value/oracle/backward_add_ptr.res.oracle
+++ b/tests/value/oracle/backward_add_ptr.res.oracle
@@ -40,16 +40,10 @@
 [eva] computing for function gm <- main3 <- main.
   Called from backward_add_ptr.c:75.
 [eva:garbled-mix:write] backward_add_ptr.c:68: Warning: 
-  Assigning imprecise value to __retres.
-  The imprecision originates from Arithmetic {backward_add_ptr.c:68}
-[eva:garbled-mix:write] backward_add_ptr.c:68: Warning: 
-  Assigning imprecise value to \result<gm>.
-  The imprecision originates from Arithmetic {backward_add_ptr.c:68}
+  Assigning imprecise value to __retres
+  because of arithmetic operation on addresses.
 [eva] Recording results for gm
 [eva] Done for function gm
-[eva:garbled-mix:write] backward_add_ptr.c:75: Warning: 
-  Assigning imprecise value to p.
-  The imprecision originates from Arithmetic {backward_add_ptr.c:68}
 [eva:alarm] backward_add_ptr.c:81: Warning: 
   out of bounds read. assert \valid_read(p + (uintptr_t)q);
 [eva] backward_add_ptr.c:82: 
@@ -62,18 +56,12 @@
   {{ NULL + {0; 1; 2; 3} ; &a + [-4294967295..3] }},
   {{ NULL + [0..4294967295] ; &b }}
 [eva] backward_add_ptr.c:91: Reusing old results for call to gm
-[eva:garbled-mix:write] backward_add_ptr.c:91: Warning: 
-  Assigning imprecise value to p.
-  The imprecision originates from Arithmetic {backward_add_ptr.c:68}
 [eva:alarm] backward_add_ptr.c:96: Warning: 
   out of bounds read. assert \valid_read(p + (uintptr_t)q);
 [eva] computing for function gm <- main3 <- main.
   Called from backward_add_ptr.c:100.
 [eva] Recording results for gm
 [eva] Done for function gm
-[eva:garbled-mix:write] backward_add_ptr.c:100: Warning: 
-  Assigning imprecise value to p.
-  The imprecision originates from Arithmetic {backward_add_ptr.c:68}
 [eva:alarm] backward_add_ptr.c:106: Warning: 
   out of bounds read. assert \valid_read(p + (uintptr_t)q);
 [eva] backward_add_ptr.c:107: 
@@ -82,9 +70,6 @@
   (origin: Arithmetic {backward_add_ptr.c:68}) }},
   {{ NULL + [0..4294967295] ; &b }}
 [eva] backward_add_ptr.c:110: Reusing old results for call to gm
-[eva:garbled-mix:write] backward_add_ptr.c:110: Warning: 
-  Assigning imprecise value to p.
-  The imprecision originates from Arithmetic {backward_add_ptr.c:68}
 [eva:alarm] backward_add_ptr.c:115: Warning: 
   out of bounds read. assert \valid_read((char *)p + (uintptr_t)q);
 [eva] backward_add_ptr.c:116: Frama_C_show_each_GM_only_c: {0}, {{ &c }}
@@ -94,9 +79,6 @@
   Frama_C_show_each_GM_only_b:
   {{ &b + [-17179869180..0],0%4 }}, [0..4294967295]
 [eva] backward_add_ptr.c:125: Reusing old results for call to gm
-[eva:garbled-mix:write] backward_add_ptr.c:125: Warning: 
-  Assigning imprecise value to p.
-  The imprecision originates from Arithmetic {backward_add_ptr.c:68}
 [eva:alarm] backward_add_ptr.c:130: Warning: 
   out of bounds read. assert \valid_read((char *)p + (uintptr_t)q);
 [eva:alarm] backward_add_ptr.c:136: Warning: 
@@ -114,19 +96,10 @@
   Called from backward_add_ptr.c:145.
 [eva] Recording results for gm
 [eva] Done for function gm
-[eva:garbled-mix:write] backward_add_ptr.c:145: Warning: 
-  Assigning imprecise value to tmp_0.
-  The imprecision originates from Arithmetic {backward_add_ptr.c:68}
-[eva:garbled-mix:write] backward_add_ptr.c:145: Warning: 
-  Assigning imprecise value to p.
-  The imprecision originates from Arithmetic {backward_add_ptr.c:68}
 [eva] computing for function gm <- main4 <- main.
   Called from backward_add_ptr.c:146.
 [eva] Recording results for gm
 [eva] Done for function gm
-[eva:garbled-mix:write] backward_add_ptr.c:146: Warning: 
-  Assigning imprecise value to q.
-  The imprecision originates from Arithmetic {backward_add_ptr.c:68}
 [eva:alarm] backward_add_ptr.c:150: Warning: 
   out of bounds read. assert \valid_read(p + (uintptr_t)q);
 [eva] backward_add_ptr.c:151: 
@@ -143,16 +116,10 @@
   (origin: Arithmetic {backward_add_ptr.c:68}) }},
   [0..4294967295]
 [eva] backward_add_ptr.c:160: Reusing old results for call to gm
-[eva:garbled-mix:write] backward_add_ptr.c:160: Warning: 
-  Assigning imprecise value to p.
-  The imprecision originates from Arithmetic {backward_add_ptr.c:68}
 [eva] computing for function gm <- main4 <- main.
   Called from backward_add_ptr.c:161.
 [eva] Recording results for gm
 [eva] Done for function gm
-[eva:garbled-mix:write] backward_add_ptr.c:161: Warning: 
-  Assigning imprecise value to q.
-  The imprecision originates from Arithmetic {backward_add_ptr.c:68}
 [eva:alarm] backward_add_ptr.c:165: Warning: 
   out of bounds read. assert \valid_read((char *)p + (uintptr_t)q);
 [eva] backward_add_ptr.c:166: 
@@ -182,31 +149,9 @@
 [eva] Recording results for main
 [eva] Done for function main
 [eva:garbled-mix:summary] Warning: 
-  Garbled mix generated during analysis:
-  {{ garbled mix of &{b} (origin: Arithmetic {backward_add_ptr.c:25}) }}
-  {{ garbled mix of &{a} (origin: Arithmetic {backward_add_ptr.c:25}) }}
-  {{ garbled mix of &{b} (origin: Arithmetic {backward_add_ptr.c:32}) }}
-  {{ garbled mix of &{a} (origin: Arithmetic {backward_add_ptr.c:32}) }}
-  {{ garbled mix of &{b} (origin: Arithmetic {backward_add_ptr.c:38}) }}
-  {{ garbled mix of &{a} (origin: Arithmetic {backward_add_ptr.c:38}) }}
-  {{ garbled mix of &{b} (origin: Arithmetic {backward_add_ptr.c:54}) }}
-  {{ garbled mix of &{a} (origin: Arithmetic {backward_add_ptr.c:54}) }}
-  {{ garbled mix of &{b} (origin: Arithmetic {backward_add_ptr.c:60}) }}
-  {{ garbled mix of &{a} (origin: Arithmetic {backward_add_ptr.c:60}) }}
-  {{ garbled mix of &{a} (origin: Arithmetic {backward_add_ptr.c:68}) }}
-  {{ garbled mix of &{b} (origin: Arithmetic {backward_add_ptr.c:81}) }}
-  {{ garbled mix of &{b} (origin: Arithmetic {backward_add_ptr.c:87}) }}
-  {{ garbled mix of &{b} (origin: Arithmetic {backward_add_ptr.c:96}) }}
-  {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:68}) }}
-  {{ garbled mix of &{b} (origin: Arithmetic {backward_add_ptr.c:106}) }}
-  {{ garbled mix of &{c} (origin: Arithmetic {backward_add_ptr.c:115}) }}
-  {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:115}) }}
-  {{ garbled mix of &{c} (origin: Arithmetic {backward_add_ptr.c:121}) }}
-  {{ garbled mix of &{b} (origin: Arithmetic {backward_add_ptr.c:130}) }}
-  {{ garbled mix of &{b} (origin: Arithmetic {backward_add_ptr.c:136}) }}
-  {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:68}) }}
-  {{ garbled mix of &{c} (origin: Arithmetic {backward_add_ptr.c:68}) }}
-  {{ garbled mix of &{b; c} (origin: Arithmetic {backward_add_ptr.c:68}) }}
+  Origins of garbled mix generated during analysis:
+    backward_add_ptr.c:68: arithmetic operation on addresses
+      (read 81 times, propagated 20 times) garbled mix of &{a; b; a; b; c}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function gm:
   __retres ∈
diff --git a/tests/value/oracle/behaviors1.res.oracle b/tests/value/oracle/behaviors1.res.oracle
index 980bd317335a3fc4d47b65acd11b2e391f2e1c3b..6266ee5cf357f02688368950dbcf890d81a35c02 100644
--- a/tests/value/oracle/behaviors1.res.oracle
+++ b/tests/value/oracle/behaviors1.res.oracle
@@ -305,22 +305,16 @@
 [eva] computing for function f <- test_assigns <- main.
   Called from behaviors1.i:473.
 [eva] using specification for function f
+[eva:garbled-mix:assigns] behaviors1.i:473: 
+  The specification of function f has generated a garbled mix of addresses
+  for assigns clause \result.
 [eva] Done for function f
-[eva:garbled-mix:write] behaviors1.i:473: 
-  Assigning imprecise value to tmp.
-  The imprecision originates from Library function {behaviors1.i:473}
-[eva:garbled-mix:write] behaviors1.i:473: 
-  Assigning imprecise value to p1.
-  The imprecision originates from Library function {behaviors1.i:473}
 [eva] computing for function f <- test_assigns <- main.
   Called from behaviors1.i:474.
+[eva:garbled-mix:assigns] behaviors1.i:474: 
+  The specification of function f has generated a garbled mix of addresses
+  for assigns clause \result.
 [eva] Done for function f
-[eva:garbled-mix:write] behaviors1.i:474: 
-  Assigning imprecise value to tmp_0.
-  The imprecision originates from Library function {behaviors1.i:474}
-[eva:garbled-mix:write] behaviors1.i:474: 
-  Assigning imprecise value to p2.
-  The imprecision originates from Library function {behaviors1.i:474}
 [eva] computing for function f <- test_assigns <- main.
   Called from behaviors1.i:475.
 [eva] Done for function f
@@ -452,6 +446,12 @@
 [eva] Done for function test_narrow
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    behaviors1.i:473: assigns clause on addresses
+      (read 1 times, propagated 3 times) garbled mix of &{a}
+    behaviors1.i:474: assigns clause on addresses
+      (read 1 times, propagated 3 times) garbled mix of &{b}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function test_123_comp_2345_comp_disj:
   a ∈ [--..--]
diff --git a/tests/value/oracle/bitfield.res.oracle b/tests/value/oracle/bitfield.res.oracle
index 45acf78958063456e7bd3d636503dc555b6f337a..cae0f2d2936a0ef67c6846b8e569f6073fa67bb2 100644
--- a/tests/value/oracle/bitfield.res.oracle
+++ b/tests/value/oracle/bitfield.res.oracle
@@ -31,8 +31,8 @@
 [eva:alarm] bitfield.i:123: Warning: 
   pointer downcast. assert (unsigned int)(&v) ≤ 2147483647;
 [eva:garbled-mix:write] bitfield.i:123: 
-  Assigning imprecise value to v.c.
-  The imprecision originates from Arithmetic {bitfield.i:123}
+  Assigning imprecise value to v.c
+  because of arithmetic operation on addresses.
 [eva:alarm] bitfield.i:124: Warning: 
   pointer downcast. assert (unsigned int)(&v + 1) ≤ 2147483647;
 [eva:alarm] bitfield.i:125: Warning: 
@@ -83,8 +83,8 @@
 [eva:alarm] bitfield.i:130: Warning: 
   pointer downcast. assert (unsigned int)(&v + 1) ≤ 2147483647;
 [eva:garbled-mix:write] bitfield.i:130: 
-  Assigning imprecise value to h.c.
-  The imprecision originates from Arithmetic {bitfield.i:130}
+  Assigning imprecise value to h.c
+  because of arithmetic operation on addresses.
 [eva] computing for function return_8 <- main_old <- main.
   Called from bitfield.i:133.
 [eva] Recording results for return_8
@@ -105,31 +105,31 @@
 [eva] computing for function leaf <- imprecise_bts_1671 <- main.
   Called from bitfield.i:70.
 [eva] using specification for function leaf
+[eva:garbled-mix:assigns] bitfield.i:70: 
+  The specification of function leaf has generated a garbled mix of addresses
+  for assigns clause *p1.
 [eva] Done for function leaf
 [eva] bitfield.i:71: 
   Frama_C_show_each:
-  {{ garbled mix of &{b} (origin: Misaligned {bitfield.i:70}) }}
+  {{ garbled mix of &{b} (origin: Misaligned read {bitfield.i:70}) }}
 [eva] bitfield.i:73: 
   Frama_C_show_each:
-  .next ∈ {{ garbled mix of &{b} (origin: Misaligned {bitfield.i:70}) }}
+  .next ∈ {{ garbled mix of &{b} (origin: Misaligned read {bitfield.i:70}) }}
   .bitf ∈ {0}
   .[bits 65 to 95] ∈
-  {{ garbled mix of &{b} (origin: Misaligned {bitfield.i:70}) }}
-[eva:garbled-mix:write] bitfield.i:74: 
-  Assigning imprecise value to c.
-  The imprecision originates from Misaligned {bitfield.i:70}
+  {{ garbled mix of &{b} (origin: Misaligned read {bitfield.i:70}) }}
 [eva] bitfield.i:69: starting to merge loop iterations
 [eva] computing for function leaf <- imprecise_bts_1671 <- main.
   Called from bitfield.i:70.
 [eva] Done for function leaf
 [eva] bitfield.i:71: 
   Frama_C_show_each:
-  {{ garbled mix of &{b} (origin: Misaligned {bitfield.i:70}) }}
+  {{ garbled mix of &{b} (origin: Misaligned read {bitfield.i:70}) }}
 [eva:alarm] bitfield.i:72: Warning: 
   out of bounds write. assert \valid(&c->bitf);
 [eva] bitfield.i:73: 
   Frama_C_show_each:
-  {{ garbled mix of &{b} (origin: Misaligned {bitfield.i:70}) }}
+  {{ garbled mix of &{b} (origin: Misaligned read {bitfield.i:70}) }}
 [eva:alarm] bitfield.i:74: Warning: 
   out of bounds read. assert \valid_read(&c->next.next);
 [eva] computing for function leaf <- imprecise_bts_1671 <- main.
@@ -187,8 +187,8 @@
   G ∈ {1}
   H ∈ {0}
   b ∈ {0}
-  c ∈ {{ garbled mix of &{b; ee} (origin: Misaligned {bitfield.i:70}) }}
-  ee ∈ {{ garbled mix of &{b} (origin: Misaligned {bitfield.i:70}) }}
+  c ∈ {{ garbled mix of &{b; ee} (origin: Misaligned read {bitfield.i:70}) }}
+  ee ∈ {{ garbled mix of &{b} (origin: Misaligned read {bitfield.i:70}) }}
   foo ∈ [--..--]
   y.v0_3 ∈ [--..--]
    .v4 ∈ {0}
@@ -207,6 +207,10 @@
 [eva] Done for function char_short
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    bitfield.i:70: misaligned read of addresses
+      (read 5 times, propagated 7 times) garbled mix of &{b; ee}
 [eva] bitfield.i:102: assertion 'Eva,initialization' got final status invalid.
 [scope:rm_asserts] removing 1 assertion(s)
 [eva] ====== VALUES COMPUTED ======
@@ -225,8 +229,9 @@
   r ∈ {1}
 [eva:final-states] Values at end of function imprecise_bts_1671:
   b ∈ {0}
-  c ∈ {{ garbled mix of &{b; ee} (origin: Misaligned {bitfield.i:70}) }}
-  ee ∈ {{ garbled mix of &{b} (origin: Misaligned {bitfield.i:70}) }}
+  c ∈
+   {{ garbled mix of &{b; ee} (origin: Misaligned read {bitfield.i:70}) }}
+  ee ∈ {{ garbled mix of &{b} (origin: Misaligned read {bitfield.i:70}) }}
 [eva:final-states] Values at end of function logic:
   y.v0_3 ∈ [--..--]
    .v4 ∈ {0}
@@ -276,8 +281,9 @@
   G ∈ {1}
   H ∈ {0}
   b ∈ {0}
-  c ∈ {{ garbled mix of &{b; ee} (origin: Misaligned {bitfield.i:70}) }}
-  ee ∈ {{ garbled mix of &{b} (origin: Misaligned {bitfield.i:70}) }}
+  c ∈
+   {{ garbled mix of &{b; ee} (origin: Misaligned read {bitfield.i:70}) }}
+  ee ∈ {{ garbled mix of &{b} (origin: Misaligned read {bitfield.i:70}) }}
   y.v0_3 ∈ [--..--]
    .v4 ∈ {0}
    .v5_31 ∈ [--..--]
diff --git a/tests/value/oracle/bitwise_pointer.0.res.oracle b/tests/value/oracle/bitwise_pointer.0.res.oracle
index c45fec9776b8c8ee44359a0cbb5211514ab29f2e..6b52884383aab14b10f97928c0c5f0ad1b923ba5 100644
--- a/tests/value/oracle/bitwise_pointer.0.res.oracle
+++ b/tests/value/oracle/bitwise_pointer.0.res.oracle
@@ -32,19 +32,23 @@
 [eva:alarm] bitwise_pointer.i:18: Warning: 
   pointer downcast. assert (unsigned int)(&t[7]) ≤ 2147483647;
 [eva:garbled-mix:write] bitwise_pointer.i:18: 
-  Assigning imprecise value to p.
-  The imprecision originates from Arithmetic {bitwise_pointer.i:18}
+  Assigning imprecise value to p because of arithmetic operation on addresses.
 [eva:alarm] bitwise_pointer.i:19: Warning: 
   out of bounds write. assert \valid(p);
 [eva:alarm] bitwise_pointer.i:22: Warning: 
   pointer downcast. assert (unsigned int)(&t1[mask]) ≤ 2147483647;
 [eva:garbled-mix:write] bitwise_pointer.i:22: 
-  Assigning imprecise value to p1.
-  The imprecision originates from Arithmetic {bitwise_pointer.i:22}
+  Assigning imprecise value to p1 because of arithmetic operation on addresses.
 [eva:alarm] bitwise_pointer.i:23: Warning: 
   out of bounds write. assert \valid(p1);
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    bitwise_pointer.i:18: arithmetic operation on addresses
+      (read 2 times, propagated 1 times) garbled mix of &{t}
+    bitwise_pointer.i:22: arithmetic operation on addresses
+      (read 2 times, propagated 1 times) garbled mix of &{t1}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main:
   t[0] ∈ {0; 5}
diff --git a/tests/value/oracle/bitwise_pointer.1.res.oracle b/tests/value/oracle/bitwise_pointer.1.res.oracle
index c45fec9776b8c8ee44359a0cbb5211514ab29f2e..6b52884383aab14b10f97928c0c5f0ad1b923ba5 100644
--- a/tests/value/oracle/bitwise_pointer.1.res.oracle
+++ b/tests/value/oracle/bitwise_pointer.1.res.oracle
@@ -32,19 +32,23 @@
 [eva:alarm] bitwise_pointer.i:18: Warning: 
   pointer downcast. assert (unsigned int)(&t[7]) ≤ 2147483647;
 [eva:garbled-mix:write] bitwise_pointer.i:18: 
-  Assigning imprecise value to p.
-  The imprecision originates from Arithmetic {bitwise_pointer.i:18}
+  Assigning imprecise value to p because of arithmetic operation on addresses.
 [eva:alarm] bitwise_pointer.i:19: Warning: 
   out of bounds write. assert \valid(p);
 [eva:alarm] bitwise_pointer.i:22: Warning: 
   pointer downcast. assert (unsigned int)(&t1[mask]) ≤ 2147483647;
 [eva:garbled-mix:write] bitwise_pointer.i:22: 
-  Assigning imprecise value to p1.
-  The imprecision originates from Arithmetic {bitwise_pointer.i:22}
+  Assigning imprecise value to p1 because of arithmetic operation on addresses.
 [eva:alarm] bitwise_pointer.i:23: Warning: 
   out of bounds write. assert \valid(p1);
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    bitwise_pointer.i:18: arithmetic operation on addresses
+      (read 2 times, propagated 1 times) garbled mix of &{t}
+    bitwise_pointer.i:22: arithmetic operation on addresses
+      (read 2 times, propagated 1 times) garbled mix of &{t1}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main:
   t[0] ∈ {0; 5}
diff --git a/tests/value/oracle/context_free.res.oracle b/tests/value/oracle/context_free.res.oracle
index ded8a88ce5e55edf2670cfc8359f746cb22b25e7..ba68025f931ff6945455604a0f240ca29897ba3a 100644
--- a/tests/value/oracle/context_free.res.oracle
+++ b/tests/value/oracle/context_free.res.oracle
@@ -77,26 +77,11 @@
 [eva:initial-state] creating variable S_1_S_vvv with imprecise size (type void)
 [eva:initial-state] creating variable S_vv with imprecise size (type void)
 [eva:alarm] context_free.i:46: Warning: out of bounds write. assert \valid(p);
-[eva:garbled-mix:write] context_free.i:51: 
-  Assigning imprecise value to vv.
-  The imprecision originates from Well
 [eva:alarm] context_free.i:52: Warning: out of bounds write. assert \valid(vvv);
-[eva:garbled-mix:write] context_free.i:52: 
-  Assigning imprecise value to *vvv (pointing to S_vvv with offsets {0}).
-  The imprecision originates from Well
-[eva:garbled-mix:write] context_free.i:54: 
-  Assigning imprecise value to uu.u1.
-  The imprecision originates from Well
 [eva:alarm] context_free.i:56: Warning: 
   out of bounds write. assert \valid(ta + 1);
-[eva:garbled-mix:write] context_free.i:58: 
-  Assigning imprecise value to pvoid.
-  The imprecision originates from Well
 [eva:alarm] context_free.i:59: Warning: 
   out of bounds write. assert \valid(pvoid);
-[eva:garbled-mix:write] context_free.i:60: 
-  Assigning imprecise value to pvoid.
-  The imprecision originates from Well
 [eva:alarm] context_free.i:61: Warning: 
   out of bounds write. assert \valid(pvoid);
 [eva:alarm] context_free.i:61: Warning: 
@@ -105,6 +90,10 @@
   pointer to function with incompatible type. assert \valid_function(g);
 [eva] Recording results for f
 [eva] Done for function f
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    Initial state (read 9 times, propagated 5 times)
+      garbled mix of &{WELL_uu; S_p_svoid; S_qvoid; S_0_S_vvv; S_vv}
 [eva] context_free.i:62: 
   assertion 'Eva,function_pointer' got final status invalid.
 [eva] ====== VALUES COMPUTED ======
diff --git a/tests/value/oracle/conversion.res.oracle b/tests/value/oracle/conversion.res.oracle
index a5eac26eb5864977bc397b24838f33c695313822..8e34af8ffa8cd0bbe61d85a13d38a00d5badd442 100644
--- a/tests/value/oracle/conversion.res.oracle
+++ b/tests/value/oracle/conversion.res.oracle
@@ -163,8 +163,7 @@
 [eva:alarm] conversion.i:39: Warning: 
   non-finite float value. assert \is_finite(*((float *)(&x)));
 [eva:garbled-mix:write] conversion.i:39: 
-  Assigning imprecise value to f.
-  The imprecision originates from Arithmetic {conversion.i:39}
+  Assigning imprecise value to f because of arithmetic operation on addresses.
 [eva] conversion.i:40: 
   Frama_C_dump_each:
   # cvalue:
diff --git a/tests/value/oracle/degeneration2.res.oracle b/tests/value/oracle/degeneration2.res.oracle
index b8f35c91cf1d94287e82e88c045e04502e9214ed..e792578b81a6454041457f7b7d52776de01325ce 100644
--- a/tests/value/oracle/degeneration2.res.oracle
+++ b/tests/value/oracle/degeneration2.res.oracle
@@ -13,8 +13,7 @@
 [eva:alarm] degeneration2.i:14: Warning: 
   signed overflow. assert -((int)A) ≤ 2147483647;
 [eva:garbled-mix:write] degeneration2.i:14: 
-  Assigning imprecise value to A.
-  The imprecision originates from Arithmetic {degeneration2.i:14}
+  Assigning imprecise value to A because of arithmetic operation on addresses.
 [eva:alarm] degeneration2.i:17: Warning: 
   accessing uninitialized left-value. assert \initialized((int *)A);
 [eva:alarm] degeneration2.i:17: Warning: 
@@ -24,6 +23,10 @@
   accessing uninitialized left-value. assert \initialized(&offset_uninit);
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    degeneration2.i:14: arithmetic operation on addresses
+      (read 6 times, propagated 1 times) garbled mix of &{B; C; D; E}
 [eva] degeneration2.i:25: 
   assertion 'Eva,initialization' got final status invalid.
 [eva] ====== VALUES COMPUTED ======
diff --git a/tests/value/oracle/deps_mixed.res.oracle b/tests/value/oracle/deps_mixed.res.oracle
index 446d6ada2d274f86c552e0abac55ffbbe73eef09..c1b9017883b5e17ab37579df0ddf684097d9acc4 100644
--- a/tests/value/oracle/deps_mixed.res.oracle
+++ b/tests/value/oracle/deps_mixed.res.oracle
@@ -33,11 +33,8 @@
 [eva:alarm] deps_mixed.i:24: Warning: 
   pointer downcast. assert (unsigned int)(p + (int)q) ≤ 2147483647;
 [eva:garbled-mix:write] deps_mixed.i:24: 
-  Assigning imprecise value to __retres.
-  The imprecision originates from Arithmetic {deps_mixed.i:24}
-[eva:garbled-mix:write] deps_mixed.i:24: 
-  Assigning imprecise value to \result<main>.
-  The imprecision originates from Arithmetic {deps_mixed.i:24}
+  Assigning imprecise value to __retres
+  because of arithmetic operation on addresses.
 [eva] Recording results for main
 [eva] Done for function main
 [eva] ====== VALUES COMPUTED ======
diff --git a/tests/value/oracle/div.0.res.oracle b/tests/value/oracle/div.0.res.oracle
index 28621d9706abb4ce92bdb0c1b6c61043fe28fccc..5595ff6926a98d1312568297b44dd166c8d063ce 100644
--- a/tests/value/oracle/div.0.res.oracle
+++ b/tests/value/oracle/div.0.res.oracle
@@ -38,8 +38,7 @@
 [eva:alarm] div.i:33: Warning: 
   signed overflow. assert (int)(&Z2) / Z2 ≤ 2147483647;
 [eva:garbled-mix:write] div.i:33: 
-  Assigning imprecise value to b.
-  The imprecision originates from Arithmetic {div.i:33}
+  Assigning imprecise value to b because of arithmetic operation on addresses.
 [eva:alarm] div.i:34: Warning: 
   pointer downcast. assert (unsigned int)(&X + 2) ≤ 2147483647;
 [eva:alarm] div.i:34: Warning: division by zero. assert (int)(&X + 2) ≢ 0;
@@ -48,8 +47,7 @@
 [eva:alarm] div.i:34: Warning: 
   signed overflow. assert 100 / (int)(&X + 2) ≤ 2147483647;
 [eva:garbled-mix:write] div.i:34: 
-  Assigning imprecise value to d2.
-  The imprecision originates from Arithmetic {div.i:34}
+  Assigning imprecise value to d2 because of arithmetic operation on addresses.
 [eva:alarm] div.i:35: Warning: 
   pointer downcast. assert (unsigned int)(&X + 1) ≤ 2147483647;
 [eva:alarm] div.i:35: Warning: 
@@ -57,8 +55,7 @@
 [eva:alarm] div.i:35: Warning: 
   signed overflow. assert 100 / (int)(&X + 1) ≤ 2147483647;
 [eva:garbled-mix:write] div.i:35: 
-  Assigning imprecise value to d1.
-  The imprecision originates from Arithmetic {div.i:35}
+  Assigning imprecise value to d1 because of arithmetic operation on addresses.
 [eva:alarm] div.i:36: Warning: 
   pointer downcast. assert (unsigned int)(&X) ≤ 2147483647;
 [eva:alarm] div.i:36: Warning: 
@@ -66,8 +63,7 @@
 [eva:alarm] div.i:36: Warning: 
   signed overflow. assert 100 / (int)(&X) ≤ 2147483647;
 [eva:garbled-mix:write] div.i:36: 
-  Assigning imprecise value to d0.
-  The imprecision originates from Arithmetic {div.i:36}
+  Assigning imprecise value to d0 because of arithmetic operation on addresses.
 [eva:alarm] div.i:37: Warning: 
   pointer downcast. assert (unsigned int)(&X) ≤ 2147483647;
 [eva:alarm] div.i:37: Warning: 
@@ -75,8 +71,7 @@
 [eva:alarm] div.i:37: Warning: 
   signed overflow. assert -((int)(&X)) ≤ 2147483647;
 [eva:garbled-mix:write] div.i:37: 
-  Assigning imprecise value to e.
-  The imprecision originates from Arithmetic {div.i:37}
+  Assigning imprecise value to e because of arithmetic operation on addresses.
 [eva] Recording results for main
 [eva] Done for function main
 [scope:rm_asserts] removing 2 assertion(s)
diff --git a/tests/value/oracle/div.1.res.oracle b/tests/value/oracle/div.1.res.oracle
index 6eabca0d307bcee7d1a03dad4795ec22a4f54530..d2a683468cbd53aa220ad3eab5454b1ab977ed7c 100644
--- a/tests/value/oracle/div.1.res.oracle
+++ b/tests/value/oracle/div.1.res.oracle
@@ -60,8 +60,7 @@
 [eva:alarm] div.i:33: Warning: 
   signed overflow. assert (int)(&Z2) / Z2 ≤ 2147483647;
 [eva:garbled-mix:write] div.i:33: 
-  Assigning imprecise value to b.
-  The imprecision originates from Arithmetic {div.i:33}
+  Assigning imprecise value to b because of arithmetic operation on addresses.
 [eva:alarm] div.i:34: Warning: 
   assertion 'rte,pointer_downcast' got status unknown.
 [eva:alarm] div.i:34: Warning: 
@@ -74,8 +73,7 @@
 [eva:alarm] div.i:34: Warning: 
   signed overflow. assert 100 / (int)(&X + 2) ≤ 2147483647;
 [eva:garbled-mix:write] div.i:34: 
-  Assigning imprecise value to d2.
-  The imprecision originates from Arithmetic {div.i:34}
+  Assigning imprecise value to d2 because of arithmetic operation on addresses.
 [eva:alarm] div.i:35: Warning: 
   assertion 'rte,pointer_downcast' got status unknown.
 [eva] div.i:35: assertion 'rte,division_by_zero' got status valid.
@@ -86,8 +84,7 @@
 [eva:alarm] div.i:35: Warning: 
   signed overflow. assert 100 / (int)(&X + 1) ≤ 2147483647;
 [eva:garbled-mix:write] div.i:35: 
-  Assigning imprecise value to d1.
-  The imprecision originates from Arithmetic {div.i:35}
+  Assigning imprecise value to d1 because of arithmetic operation on addresses.
 [eva:alarm] div.i:36: Warning: 
   assertion 'rte,pointer_downcast' got status unknown.
 [eva] div.i:36: assertion 'rte,division_by_zero' got status valid.
@@ -98,8 +95,7 @@
 [eva:alarm] div.i:36: Warning: 
   signed overflow. assert 100 / (int)(&X) ≤ 2147483647;
 [eva:garbled-mix:write] div.i:36: 
-  Assigning imprecise value to d0.
-  The imprecision originates from Arithmetic {div.i:36}
+  Assigning imprecise value to d0 because of arithmetic operation on addresses.
 [eva:alarm] div.i:37: Warning: 
   assertion 'rte,pointer_downcast' got status unknown.
 [eva:alarm] div.i:37: Warning: 
@@ -111,8 +107,7 @@
 [eva:alarm] div.i:37: Warning: 
   signed overflow. assert -((int)(&X)) ≤ 2147483647;
 [eva:garbled-mix:write] div.i:37: 
-  Assigning imprecise value to e.
-  The imprecision originates from Arithmetic {div.i:37}
+  Assigning imprecise value to e because of arithmetic operation on addresses.
 [eva] Recording results for main
 [eva] Done for function main
 [eva] div.i:22: assertion 'rte,signed_overflow' got final status valid.
diff --git a/tests/value/oracle/downcast.4.res.oracle b/tests/value/oracle/downcast.4.res.oracle
index aaae6f3d0b6996f66845a397c8e56dceb80aa583..5417bdf0ee0768eba91482a4a276e95abf21b4e5 100644
--- a/tests/value/oracle/downcast.4.res.oracle
+++ b/tests/value/oracle/downcast.4.res.oracle
@@ -46,11 +46,9 @@
 [eva] computing for function main6_val_warn_converted_signed <- main.
   Called from downcast.i:161.
 [eva:garbled-mix:write] downcast.i:96: 
-  Assigning imprecise value to y.
-  The imprecision originates from Arithmetic {downcast.i:96}
+  Assigning imprecise value to y because of arithmetic operation on addresses.
 [eva:garbled-mix:write] downcast.i:97: 
-  Assigning imprecise value to z.
-  The imprecision originates from Arithmetic {downcast.i:97}
+  Assigning imprecise value to z because of arithmetic operation on addresses.
 [eva] Recording results for main6_val_warn_converted_signed
 [eva] Done for function main6_val_warn_converted_signed
 [eva] computing for function main7_signed_upcast <- main.
diff --git a/tests/value/oracle/empty_base.1.res.oracle b/tests/value/oracle/empty_base.1.res.oracle
index eb0f8ece4e0737806ec80e0a2bea560d2eddb641..bba69f8432c7a4c311b70f979773601645d4e353 100644
--- a/tests/value/oracle/empty_base.1.res.oracle
+++ b/tests/value/oracle/empty_base.1.res.oracle
@@ -1,8 +1,14 @@
 [kernel] Parsing empty_base.c (with preprocessing)
 [kernel] empty_base.c:13: User Error: 
   empty structs only allowed for GCC/MSVC machdeps; see option -machdep or run 'frama-c -machdep help' for the list of available machdeps
+[kernel] empty_base.c:48: User Error: 
+  Unable to compute the size of array element 'struct empty': empty struct 'struct empty'
 [kernel] empty_base.c:48: User Error: 
   zero-length arrays only allowed for GCC/MSVC machdeps; see option -machdep or run 'frama-c -machdep help' for the list of available machdeps
+[kernel] empty_base.c:49: User Error: 
+  Unable to compute the size of array element 'struct empty': empty struct 'struct empty'
+[kernel] empty_base.c:50: User Error: 
+  Unable to compute the size of array element 'struct empty': empty struct 'struct empty'
 [kernel] empty_base.c:50: User Error: 
   empty initializers only allowed for GCC/MSVC machdeps; see option -machdep or run 'frama-c -machdep help' for the list of available machdeps
   48    struct empty empty_array_of_empty[0];
diff --git a/tests/value/oracle/empty_struct.6.res.oracle b/tests/value/oracle/empty_struct.6.res.oracle
index c67a99bfed4c23f7e2f3276860441cc21fd2ad5f..cf2ce4f7e5017fc89087bc192e005d7dec7f2189 100644
--- a/tests/value/oracle/empty_struct.6.res.oracle
+++ b/tests/value/oracle/empty_struct.6.res.oracle
@@ -8,10 +8,10 @@
 [eva] computing for function f <- main4.
   Called from empty_struct.c:99.
 [eva] using specification for function f
+[eva:garbled-mix:assigns] empty_struct.c:99: 
+  The specification of function f has generated a garbled mix of addresses
+  for assigns clause \result.
 [eva] Done for function f
-[eva:garbled-mix:write] empty_struct.c:99: 
-  Assigning imprecise value to r.
-  The imprecision originates from Library function {empty_struct.c:99}
 [kernel:annot:missing-spec] empty_struct.c:100: Warning: 
   Neither code nor specification for function g,
    generating default assigns. See -generated-spec-* options for more info
@@ -21,6 +21,10 @@
 [eva] Done for function g
 [eva] Recording results for main4
 [eva] Done for function main4
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    empty_struct.c:99: assigns clause on addresses
+      (read 2 times, propagated 3 times) garbled mix of &{gs}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main4:
   r ∈
diff --git a/tests/value/oracle/eval_separated.res.oracle b/tests/value/oracle/eval_separated.res.oracle
index 899ef89f2cc0386e2732a8e9c87eb7b835dcd3a1..de147cad6d37b70214fd95bc61ec7c25842b6875 100644
--- a/tests/value/oracle/eval_separated.res.oracle
+++ b/tests/value/oracle/eval_separated.res.oracle
@@ -18,8 +18,7 @@
 [eva:alarm] eval_separated.c:11: Warning: 
   signed overflow. assert (int)(&q) + (int)(&q) ≤ 2147483647;
 [eva:garbled-mix:write] eval_separated.c:11: 
-  Assigning imprecise value to q.
-  The imprecision originates from Arithmetic {eval_separated.c:11}
+  Assigning imprecise value to q because of arithmetic operation on addresses.
 [eva:alarm] eval_separated.c:12: Warning: 
   pointer downcast. assert (unsigned int)(&r) ≤ 2147483647;
 [eva:alarm] eval_separated.c:12: Warning: 
@@ -27,8 +26,7 @@
 [eva:alarm] eval_separated.c:12: Warning: 
   signed overflow. assert (int)(&r) + (int)(&r) ≤ 2147483647;
 [eva:garbled-mix:write] eval_separated.c:12: 
-  Assigning imprecise value to r.
-  The imprecision originates from Arithmetic {eval_separated.c:12}
+  Assigning imprecise value to r because of arithmetic operation on addresses.
 [eva:alarm] eval_separated.c:13: Warning: assertion got status unknown.
 [eva:alarm] eval_separated.c:14: Warning: assertion got status unknown.
 [eva:alarm] eval_separated.c:15: Warning: assertion got status unknown.
diff --git a/tests/value/oracle/from_call.0.res.oracle b/tests/value/oracle/from_call.0.res.oracle
index 88c6c5d8c6d416983f927de6f9655687531bbebf..f3377d39ae638c90c299fa32083c399803a221ef 100644
--- a/tests/value/oracle/from_call.0.res.oracle
+++ b/tests/value/oracle/from_call.0.res.oracle
@@ -178,6 +178,9 @@
 [eva] computing for function unavailable_f <- main.
   Called from from_call.i:96.
 [eva] using specification for function unavailable_f
+[eva:garbled-mix:assigns] from_call.i:96: 
+  The specification of function unavailable_f
+  has generated a garbled mix of addresses for assigns clause AR.
 [eva] Done for function unavailable_f
 [eva] Recording results for main
 [from] Computing for function main
diff --git a/tests/value/oracle/from_call.1.res.oracle b/tests/value/oracle/from_call.1.res.oracle
index 560d21d929a84ba7eec01b95ef43454445de32a5..18901931cee6b75386e480ca4f21c8681cb5955b 100644
--- a/tests/value/oracle/from_call.1.res.oracle
+++ b/tests/value/oracle/from_call.1.res.oracle
@@ -142,6 +142,9 @@
 [eva] computing for function unavailable_f <- main.
   Called from from_call.i:96.
 [eva] using specification for function unavailable_f
+[eva:garbled-mix:assigns] from_call.i:96: 
+  The specification of function unavailable_f
+  has generated a garbled mix of addresses for assigns clause AR.
 [eva] Done for function unavailable_f
 [eva] Recording results for main
 [eva] Done for function main
diff --git a/tests/value/oracle/gauges.res.oracle b/tests/value/oracle/gauges.res.oracle
index 050ed73c53ad6db810ce0e3f0b9c795c17b33450..4b7f0372dd0bb9eb70ae5e95a7ad3d083f33c162 100644
--- a/tests/value/oracle/gauges.res.oracle
+++ b/tests/value/oracle/gauges.res.oracle
@@ -235,11 +235,7 @@
 [eva:alarm] gauges.c:188: Warning: 
   signed overflow. assert (int)p + (int)q ≤ 2147483647;
 [eva:garbled-mix:write] gauges.c:188: 
-  Assigning imprecise value to z.
-  The imprecision originates from Arithmetic {gauges.c:188}
-[eva:garbled-mix:write] gauges.c:189: 
-  Assigning imprecise value to r.
-  The imprecision originates from Arithmetic {gauges.c:188}
+  Assigning imprecise value to z because of arithmetic operation on addresses.
 [eva:alarm] gauges.c:190: Warning: out of bounds write. assert \valid(r);
 [eva:alarm] gauges.c:192: Warning: out of bounds write. assert \valid(p);
 [eva:alarm] gauges.c:193: Warning: out of bounds write. assert \valid(q);
@@ -714,6 +710,10 @@
 [eva] Done for function main17
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    gauges.c:188: arithmetic operation on addresses
+      (read 14 times, propagated 12 times) garbled mix of &{x; y}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main0:
   i ∈ {1; 162}
diff --git a/tests/value/oracle/imprecise_invalid_write.res.oracle b/tests/value/oracle/imprecise_invalid_write.res.oracle
index 3edbb6d07b05abbb8a627315a7e04d341fcd40ee..49172ffd8d93700972e082185b7f3d691c1be222 100644
--- a/tests/value/oracle/imprecise_invalid_write.res.oracle
+++ b/tests/value/oracle/imprecise_invalid_write.res.oracle
@@ -24,8 +24,7 @@
 [eva:alarm] imprecise_invalid_write.i:9: Warning: 
   pointer downcast. assert (unsigned int)(&main1) ≤ 2147483647;
 [eva:garbled-mix:write] imprecise_invalid_write.i:9: 
-  Assigning imprecise value to p.
-  The imprecision originates from Arithmetic {imprecise_invalid_write.i:9}
+  Assigning imprecise value to p because of arithmetic operation on addresses.
 [eva:alarm] imprecise_invalid_write.i:10: Warning: 
   out of bounds write. assert \valid((int *)p);
 [kernel] imprecise_invalid_write.i:10: Warning: 
@@ -37,8 +36,7 @@
 [eva:alarm] imprecise_invalid_write.i:16: Warning: 
   pointer downcast. assert (unsigned int)s ≤ 2147483647;
 [eva:garbled-mix:write] imprecise_invalid_write.i:16: 
-  Assigning imprecise value to p.
-  The imprecision originates from Arithmetic {imprecise_invalid_write.i:16}
+  Assigning imprecise value to p because of arithmetic operation on addresses.
 [eva:alarm] imprecise_invalid_write.i:17: Warning: 
   out of bounds write. assert \valid(p);
 [kernel] imprecise_invalid_write.i:17: Warning: 
@@ -47,6 +45,12 @@
 [eva] Done for function main3
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    imprecise_invalid_write.i:9: arithmetic operation on addresses
+      (read 2 times, propagated 1 times) garbled mix of &{main1}
+    imprecise_invalid_write.i:16: arithmetic operation on addresses
+      (read 2 times, propagated 1 times) garbled mix of &{"abc"}
 [eva] imprecise_invalid_write.i:5: 
   assertion 'Eva,mem_access' got final status invalid.
 [eva] imprecise_invalid_write.i:10: 
diff --git a/tests/value/oracle/initialized.res.oracle b/tests/value/oracle/initialized.res.oracle
index d7b4af3ec6e4bc9398250cf52ce0acc4a026ff7e..150e3f1824268b9374592e59ea74da1ccc0c4429 100644
--- a/tests/value/oracle/initialized.res.oracle
+++ b/tests/value/oracle/initialized.res.oracle
@@ -73,11 +73,8 @@
 [eva:alarm] initialized.c:50: Warning: 
   signed overflow. assert (int)(&b4) + (int)(&b4) ≤ 2147483647;
 [eva:garbled-mix:write] initialized.c:50: 
-  Assigning imprecise value to t[6].
-  The imprecision originates from Arithmetic {initialized.c:50}
-[eva:garbled-mix:write] initialized.c:51: 
-  Assigning imprecise value to t[7].
-  The imprecision originates from Arithmetic {initialized.c:50}
+  Assigning imprecise value to t[6]
+  because of arithmetic operation on addresses.
 [eva] initialized.c:63: 
   Frama_C_dump_each:
   # cvalue:
@@ -234,6 +231,10 @@
 [eva] Done for function reduce_by_negation
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    initialized.c:50: arithmetic operation on addresses
+      (read 1 times, propagated 2 times) garbled mix of &{b4}
 [eva] initialized.c:93: assertion 'Eva,initialization' got final status invalid.
 [eva] initialized.c:104: 
   assertion 'Eva,initialization' got final status invalid.
diff --git a/tests/value/oracle/inout_proto.res.oracle b/tests/value/oracle/inout_proto.res.oracle
index 77fcb77f70191983ad3627233361879ec9e288a7..d96ee3689cbfcaf14df1fbc700e908385e2a6247 100644
--- a/tests/value/oracle/inout_proto.res.oracle
+++ b/tests/value/oracle/inout_proto.res.oracle
@@ -13,6 +13,9 @@
 [eva] computing for function SendBuffer <- main <- main_main.
   Called from inout_proto.i:19.
 [eva] using specification for function SendBuffer
+[eva:garbled-mix:assigns] inout_proto.i:19: 
+  The specification of function SendBuffer
+  has generated a garbled mix of addresses for assigns clause *RETURN_CODE.
 [eva] Done for function SendBuffer
 [eva] Recording results for main
 [eva] Done for function main
diff --git a/tests/value/oracle/join_misaligned.res.oracle b/tests/value/oracle/join_misaligned.res.oracle
index 82adf0d093dbffd8bfb9b2ca4928d6650ad4e8af..923f7c4aa5d06383052e0ed08a4ac10cfc406200 100644
--- a/tests/value/oracle/join_misaligned.res.oracle
+++ b/tests/value/oracle/join_misaligned.res.oracle
@@ -20,10 +20,6 @@
   pointer downcast. assert (unsigned int)(&u) ≤ 2147483647;
 [eva] Recording results for main
 [eva] Done for function main
-[eva:garbled-mix:summary] Warning: 
-  Garbled mix generated during analysis:
-  {{ garbled mix of &{t} (origin: Merge {join_misaligned.i:42}) }}
-  {{ garbled mix of &{u} (origin: Merge {join_misaligned.i:42}) }}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main:
   t{[0]; [1][bits 0 to 15]} ∈ {0}
diff --git a/tests/value/oracle/label.res.oracle b/tests/value/oracle/label.res.oracle
index 7634f9cc0083b4c837f6a2435f8269b29c667ea5..4b44fa1adfa728e27f6f9d97a39125ec045b12c2 100644
--- a/tests/value/oracle/label.res.oracle
+++ b/tests/value/oracle/label.res.oracle
@@ -14,20 +14,7 @@
   pointer downcast. assert (unsigned int)(&d + 1) ≤ 2147483647;
 [eva:garbled-mix:write] label.i:18: 
   Assigning imprecise value to *((char *)(& p) + i)
-  (pointing to p with offsets {0}).
-  The imprecision originates from Misaligned {label.i:18}
-[eva:garbled-mix:write] label.i:18: 
-  Assigning imprecise value to *((char *)(& p) + i)
-  (pointing to p with offsets {0; 8}).
-  The imprecision originates from Misaligned {label.i:18}
-[eva:garbled-mix:write] label.i:18: 
-  Assigning imprecise value to *((char *)(& p) + i)
-  (pointing to p with offsets {0; 8; 16}).
-  The imprecision originates from Misaligned {label.i:18}
-[eva:garbled-mix:write] label.i:18: 
-  Assigning imprecise value to *((char *)(& p) + i)
-  (pointing to p with offsets {0; 8; 16; 24}).
-  The imprecision originates from Misaligned {label.i:18}
+  because of misaligned read of addresses.
 [eva] Recording results for main
 [eva] Done for function main
 [eva] ====== VALUES COMPUTED ======
@@ -35,7 +22,7 @@
   a ∈ {{ &d + {4} }}
   b ∈ {1; 2}
   i ∈ {4}
-  p ∈ {{ garbled mix of &{a; b} (origin: Misaligned {label.i:18}) }}
+  p ∈ {{ garbled mix of &{a; b} (origin: Misaligned read {label.i:18}) }}
   q ∈ {{ &a }}
 [from] Computing for function main
 [from] Done for function main
diff --git a/tests/value/oracle/leaf.res.oracle b/tests/value/oracle/leaf.res.oracle
index 7ccd5e0302a676eb3ee7293c6683d039208b0eca..865b2bc8486622735e111a273c8a8300c3b277a9 100644
--- a/tests/value/oracle/leaf.res.oracle
+++ b/tests/value/oracle/leaf.res.oracle
@@ -39,20 +39,20 @@
 [eva] computing for function f_int_star_int <- main.
   Called from leaf.i:50.
 [eva] using specification for function f_int_star_int
+[eva:garbled-mix:assigns] leaf.i:50: 
+  The specification of function f_int_star_int
+  has generated a garbled mix of addresses for assigns clause \result.
 [eva] Done for function f_int_star_int
-[eva:garbled-mix:write] leaf.i:50: 
-  Assigning imprecise value to p.
-  The imprecision originates from Library function {leaf.i:50}
 [eva] leaf.i:51: Frama_C_show_each_F: [-2147483648..2147483647]
 [eva:alarm] leaf.i:52: Warning: out of bounds write. assert \valid(p);
 [eva] leaf.i:53: Frama_C_show_each_F: {5}
 [eva] computing for function f_int_star_int_star_int <- main.
   Called from leaf.i:55.
 [eva] using specification for function f_int_star_int_star_int
+[eva:garbled-mix:assigns] leaf.i:55: 
+  The specification of function f_int_star_int_star_int
+  has generated a garbled mix of addresses for assigns clause \result.
 [eva] Done for function f_int_star_int_star_int
-[eva:garbled-mix:write] leaf.i:55: 
-  Assigning imprecise value to pp.
-  The imprecision originates from Library function {leaf.i:55}
 [eva] leaf.i:56: Frama_C_show_each_G: {{ &g }}
 [eva] leaf.i:57: Frama_C_show_each_F: {5}
 [eva] leaf.i:59: Frama_C_show_each_G: {{ &g }}
@@ -91,20 +91,20 @@
 [eva] computing for function f_st_star_cint_st_star_cint <- main.
   Called from leaf.i:68.
 [eva] using specification for function f_st_star_cint_st_star_cint
+[eva:garbled-mix:assigns] leaf.i:68: 
+  The specification of function f_st_star_cint_st_star_cint
+  has generated a garbled mix of addresses for assigns clause \result.
 [eva] Done for function f_st_star_cint_st_star_cint
-[eva:garbled-mix:write] leaf.i:68: 
-  Assigning imprecise value to st_star_cint_1.
-  The imprecision originates from Library function {leaf.i:68}
 [kernel:annot:missing-spec] leaf.i:69: Warning: 
   Neither code nor specification for function f_st_star_int_st_star_int,
    generating default assigns. See -generated-spec-* options for more info
 [eva] computing for function f_st_star_int_st_star_int <- main.
   Called from leaf.i:69.
 [eva] using specification for function f_st_star_int_st_star_int
+[eva:garbled-mix:assigns] leaf.i:69: 
+  The specification of function f_st_star_int_st_star_int
+  has generated a garbled mix of addresses for assigns clause \result.
 [eva] Done for function f_st_star_int_st_star_int
-[eva:garbled-mix:write] leaf.i:69: 
-  Assigning imprecise value to st_star_int_1.
-  The imprecision originates from Library function {leaf.i:69}
 [kernel:annot:missing-spec] leaf.i:70: Warning: 
   Neither code nor specification for function f_st_tab3_int_st_tab3_int,
    generating default assigns. See -generated-spec-* options for more info
@@ -118,6 +118,9 @@
 [eva] computing for function f_star_st_star_cint_int <- main.
   Called from leaf.i:72.
 [eva] using specification for function f_star_st_star_cint_int
+[eva:garbled-mix:assigns] leaf.i:72: 
+  The specification of function f_star_st_star_cint_int
+  has generated a garbled mix of addresses for assigns clause \result.
 [eva] Done for function f_star_st_star_cint_int
 [kernel:annot:missing-spec] leaf.i:73: Warning: 
   Neither code nor specification for function f_star_st_star_int_int,
@@ -125,6 +128,9 @@
 [eva] computing for function f_star_st_star_int_int <- main.
   Called from leaf.i:73.
 [eva] using specification for function f_star_st_star_int_int
+[eva:garbled-mix:assigns] leaf.i:73: 
+  The specification of function f_star_st_star_int_int
+  has generated a garbled mix of addresses for assigns clause \result.
 [eva] Done for function f_star_st_star_int_int
 [kernel:annot:missing-spec] leaf.i:74: Warning: 
   Neither code nor specification for function f_star_st_tab3_int_int,
@@ -135,6 +141,12 @@
 [eva] Done for function f_star_st_tab3_int_int
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    leaf.i:55: assigns clause on addresses (read 10 times, propagated 2 times)
+      garbled mix of &{pg}
+    leaf.i:50: assigns clause on addresses (read 4 times, propagated 2 times)
+      garbled mix of &{g}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main:
   T[0] ∈ [--..--]
diff --git a/tests/value/oracle/leaf2.res.oracle b/tests/value/oracle/leaf2.res.oracle
index 3f486d154c0c0f64d200520942925f611f485b1d..c03b05b96d49fc64e90e969fc0d3b0d84c0cd8fd 100644
--- a/tests/value/oracle/leaf2.res.oracle
+++ b/tests/value/oracle/leaf2.res.oracle
@@ -14,17 +14,18 @@
 [eva] computing for function f <- main.
   Called from leaf2.i:6.
 [eva] using specification for function f
+[eva:garbled-mix:assigns] leaf2.i:6: 
+  The specification of function f has generated a garbled mix of addresses
+  for assigns clause \result.
 [eva] Done for function f
-[eva:garbled-mix:write] leaf2.i:6: 
-  Assigning imprecise value to G.
-  The imprecision originates from Library function {leaf2.i:6}
 [eva:alarm] leaf2.i:7: Warning: signed overflow. assert -2147483648 ≤ G + 1;
 [eva:alarm] leaf2.i:7: Warning: signed overflow. assert G + 1 ≤ 2147483647;
-[eva:garbled-mix:write] leaf2.i:7: 
-  Assigning imprecise value to G.
-  The imprecision originates from Library function {leaf2.i:6}
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    leaf2.i:6: assigns clause on addresses (read 4 times, propagated 4 times)
+      garbled mix of &{I}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main:
   G ∈ {{ garbled mix of &{I} (origin: Library function {leaf2.i:6}) }}
diff --git a/tests/value/oracle/library.res.oracle b/tests/value/oracle/library.res.oracle
index 3a3a113d63804454659655d9caeb4b00194905de..992d56c788e072721596736c0b2e43b90e331267 100644
--- a/tests/value/oracle/library.res.oracle
+++ b/tests/value/oracle/library.res.oracle
@@ -86,10 +86,10 @@
 [eva] computing for function f_star_int <- main.
   Called from library.i:31.
 [eva] using specification for function f_star_int
+[eva:garbled-mix:assigns] library.i:31: 
+  The specification of function f_star_int
+  has generated a garbled mix of addresses for assigns clause \result.
 [eva] Done for function f_star_int
-[eva:garbled-mix:write] library.i:31: 
-  Assigning imprecise value to G1.
-  The imprecision originates from Library function {library.i:31}
 [eva:alarm] library.i:32: Warning: out of bounds write. assert \valid(G1);
 [eva:alarm] library.i:33: Warning: out of bounds read. assert \valid_read(G);
 [eva:alarm] library.i:33: Warning: out of bounds read. assert \valid_read(*G);
@@ -112,10 +112,10 @@
 [eva] computing for function i <- main.
   Called from library.i:41.
 [eva] using specification for function i
+[eva:garbled-mix:assigns] library.i:41: 
+  The specification of function i has generated a garbled mix of addresses
+  for assigns clause \result.
 [eva] Done for function i
-[eva:garbled-mix:write] library.i:41: 
-  Assigning imprecise value to pf.
-  The imprecision originates from Library function {library.i:41}
 [eva:alarm] library.i:42: Warning: out of bounds read. assert \valid_read(pf);
 [eva:alarm] library.i:42: Warning: 
   non-finite float value. assert \is_finite(*pf);
@@ -128,13 +128,21 @@
 [eva] computing for function k <- main.
   Called from library.i:45.
 [eva] using specification for function k
+[eva:garbled-mix:assigns] library.i:45: 
+  The specification of function k has generated a garbled mix of addresses
+  for assigns clause \result.
 [eva] Done for function k
-[eva:garbled-mix:write] library.i:45: 
-  Assigning imprecise value to pd.
-  The imprecision originates from Library function {library.i:45}
 [eva:alarm] library.i:46: Warning: out of bounds write. assert \valid(pd);
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    library.i:31: assigns clause on addresses
+      (read 2 times, propagated 2 times) garbled mix of &{S_gpi}
+    library.i:41: assigns clause on addresses
+      (read 2 times, propagated 2 times) garbled mix of &{S_gpf}
+    library.i:45: assigns clause on addresses
+      (read 2 times, propagated 2 times) garbled mix of &{S_gpd}
 [eva] library.i:38: assertion 'Eva,function_pointer' got final status invalid.
 [eva] library.i:39: assertion 'Eva,function_pointer' got final status invalid.
 [eva] library.i:40: assertion 'Eva,function_pointer' got final status invalid.
diff --git a/tests/value/oracle/logic.res.oracle b/tests/value/oracle/logic.res.oracle
index f88f05e9117129bb86b043b56223a54f5c3c6475..77e8322bc7e61c9497bbd89beac20ade5492cac4 100644
--- a/tests/value/oracle/logic.res.oracle
+++ b/tests/value/oracle/logic.res.oracle
@@ -415,10 +415,10 @@
 [eva] logic.c:408: Frama_C_show_each_set: {0; 1; 2; 3; 4; 5}
 [eva] computing for function abs <- int_abs <- main.
   Called from logic.c:411.
+[eva:garbled-mix:assigns] logic.c:411: 
+  The specification of function abs has generated a garbled mix of addresses
+  for assigns clause \result.
 [eva] Done for function abs
-[eva:garbled-mix:write] logic.c:411: 
-  Assigning imprecise value to x_0.
-  The imprecision originates from Library function {logic.c:411}
 [eva] logic.c:412: 
   Frama_C_show_each_gm:
   {{ garbled mix of &{x_0} (origin: Library function {logic.c:411}) }}
@@ -563,6 +563,10 @@
 [eva] Done for function plet
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    logic.c:411: assigns clause on addresses (read 1 times, propagated 2 times)
+      garbled mix of &{x_0}
 [eva] logic.c:530: 
   Cannot evaluate range bound __fc_len - 1
   (unsupported logic var __fc_len). Approximating
diff --git a/tests/value/oracle/logic_ptr_cast.res.oracle b/tests/value/oracle/logic_ptr_cast.res.oracle
index 2cc7cbd033fd40684cf2d7c55f957e8a43fb8e41..8c23da7de9a82c9380add324962fc335b475540e 100644
--- a/tests/value/oracle/logic_ptr_cast.res.oracle
+++ b/tests/value/oracle/logic_ptr_cast.res.oracle
@@ -6,8 +6,7 @@
   p ∈ {0}
   t[0..89] ∈ {0}
 [eva:garbled-mix:write] logic_ptr_cast.i:8: 
-  Assigning imprecise value to p.
-  The imprecision originates from Arithmetic {logic_ptr_cast.i:8}
+  Assigning imprecise value to p because of arithmetic operation on addresses.
 [eva:alarm] logic_ptr_cast.i:9: Warning: assertion got status unknown.
 [eva] logic_ptr_cast.i:14: 
   Frama_C_show_each: {{ &t + {0; 1; 2; 3; 4; 5; 6; 7} }}
diff --git a/tests/value/oracle/multidim-relations.res.oracle b/tests/value/oracle/multidim-relations.res.oracle
index e7f1d9da7ace7a3640b02aab980928a144b93e12..aa7000e536dc44b7605a8c08d43d786b47352cd0 100644
--- a/tests/value/oracle/multidim-relations.res.oracle
+++ b/tests/value/oracle/multidim-relations.res.oracle
@@ -48,6 +48,12 @@
 [eva] Done for function use_array
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    multidim-relations.c:18: imprecise merge of addresses
+      (read 7 times, propagated 0 times) garbled mix of &{g; h}
+    multidim-relations.c:19: imprecise merge of addresses
+      (read 4 times, propagated 0 times) garbled mix of &{g; h}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function init_array:
   t[0]{.kind; .[bits 8 to 31]#} ∈ {0; 1} repeated %8 
diff --git a/tests/value/oracle/not_ct_array_arg.res.oracle b/tests/value/oracle/not_ct_array_arg.res.oracle
index bc4b35bcb5822c058be586eea8fc6709cfdad55d..560745bc9b332a6c91f73d247be11f3fdde05bd8 100644
--- a/tests/value/oracle/not_ct_array_arg.res.oracle
+++ b/tests/value/oracle/not_ct_array_arg.res.oracle
@@ -35,10 +35,11 @@
   tc ∈ {{ NULL ; &S_tc[0] }}
   S_tc[0..1][0..9] ∈ [--..--]
   S_tb[bits 0 to 31] ∈
-      {{ garbled mix of &{tb} (origin: Misaligned {not_ct_array_arg.i:12}) }}
+      {{ garbled mix of &{tb}
+       (origin: Misaligned write {not_ct_array_arg.i:12}) }}
       [bits 32 to ..] ∈
       {{ garbled mix of &{tb}
-       (origin: Misaligned {not_ct_array_arg.i:12}) }} or UNINITIALIZED
+       (origin: Misaligned write {not_ct_array_arg.i:12}) }} or UNINITIALIZED
   ==END OF DUMP==
 [eva:alarm] not_ct_array_arg.i:14: Warning: 
   out of bounds write. assert \valid(&(*(tc + 1))[1]);
@@ -56,10 +57,11 @@
       [1][1] ∈ {3}
       [1][2..9] ∈ [--..--]
   S_tb[bits 0 to 31] ∈
-      {{ garbled mix of &{tb} (origin: Misaligned {not_ct_array_arg.i:12}) }}
+      {{ garbled mix of &{tb}
+       (origin: Misaligned write {not_ct_array_arg.i:12}) }}
       [bits 32 to ..] ∈
       {{ garbled mix of &{tb}
-       (origin: Misaligned {not_ct_array_arg.i:12}) }} or UNINITIALIZED
+       (origin: Misaligned write {not_ct_array_arg.i:12}) }} or UNINITIALIZED
 [from] Computing for function main
 [from] Done for function main
 [from] ====== DEPENDENCIES COMPUTED ======
diff --git a/tests/value/oracle/origin.0.res.oracle b/tests/value/oracle/origin.0.res.oracle
index 21313b3be754e82c6d4c9570db9f1ae65208e409..e93befd14488bc1553a17bdd7359fd79315a146c 100644
--- a/tests/value/oracle/origin.0.res.oracle
+++ b/tests/value/oracle/origin.0.res.oracle
@@ -61,8 +61,8 @@
 [eva:alarm] origin.i:14: Warning: 
   signed overflow. assert -((int)((int *)ta1)) ≤ 2147483647;
 [eva:garbled-mix:write] origin.i:14: 
-  Assigning imprecise value to pa1.
-  The imprecision originates from Arithmetic {origin.i:14}
+  Assigning imprecise value to pa1
+  because of arithmetic operation on addresses.
 [eva:alarm] origin.i:15: Warning: out of bounds write. assert \valid(pa1);
 [eva] Recording results for origin_arithmetic_1
 [eva] Done for function origin_arithmetic_1
@@ -75,11 +75,8 @@
 [eva:alarm] origin.i:19: Warning: 
   signed overflow. assert -((int)((int *)ta2)) ≤ 2147483647;
 [eva:garbled-mix:write] origin.i:19: 
-  Assigning imprecise value to pa2.
-  The imprecision originates from Arithmetic {origin.i:19}
-[eva:garbled-mix:write] origin.i:20: 
-  Assigning imprecise value to qa2.
-  The imprecision originates from Arithmetic {origin.i:19}
+  Assigning imprecise value to pa2
+  because of arithmetic operation on addresses.
 [eva:alarm] origin.i:20: Warning: 
   pointer downcast. assert (unsigned int)((int *)tta2) ≤ 2147483647;
 [eva:alarm] origin.i:20: Warning: 
@@ -87,8 +84,8 @@
 [eva:alarm] origin.i:20: Warning: 
   signed overflow. assert -((int)((int *)tta2)) ≤ 2147483647;
 [eva:garbled-mix:write] origin.i:20: 
-  Assigning imprecise value to qa2.
-  The imprecision originates from Arithmetic {origin.i:20}
+  Assigning imprecise value to qa2
+  because of arithmetic operation on addresses.
 [eva:alarm] origin.i:21: Warning: out of bounds write. assert \valid(qa2);
 [eva:alarm] origin.i:21: Warning: 
   pointer downcast. assert (unsigned int)(&aa2) ≤ 2147483647;
@@ -103,8 +100,8 @@
 [eva:alarm] origin.i:25: Warning: 
   signed overflow. assert -((int)((int *)ta3)) ≤ 2147483647;
 [eva:garbled-mix:write] origin.i:25: 
-  Assigning imprecise value to pa3.
-  The imprecision originates from Arithmetic {origin.i:25}
+  Assigning imprecise value to pa3
+  because of arithmetic operation on addresses.
 [eva:alarm] origin.i:26: Warning: out of bounds write. assert \valid(pa3);
 [eva] Recording results for origin_arithmetic_3
 [eva] Done for function origin_arithmetic_3
@@ -131,27 +128,25 @@
 [eva] computing for function gp <- main.
   Called from origin.i:100.
 [eva] using specification for function gp
+[eva:garbled-mix:assigns] origin.i:100: 
+  The specification of function gp has generated a garbled mix of addresses
+  for assigns clause \result.
 [eva] Done for function gp
-[eva:garbled-mix:write] origin.i:100: 
-  Assigning imprecise value to pl.
-  The imprecision originates from Library function {origin.i:100}
 [eva:alarm] origin.i:101: Warning: out of bounds read. assert \valid_read(pl);
 [eva] computing for function origin_misalign_1 <- main.
   Called from origin.i:102.
 [eva:garbled-mix:write] origin.i:48: 
-  Assigning imprecise value to pm1.
-  The imprecision originates from Misaligned {origin.i:48}
+  Assigning imprecise value to pm1 because of misaligned read of addresses.
 [eva:alarm] origin.i:49: Warning: out of bounds write. assert \valid(pm1);
 [eva] Recording results for origin_misalign_1
 [eva] Done for function origin_misalign_1
 [eva] computing for function origin_misalign_2 <- main.
   Called from origin.i:103.
 [eva:garbled-mix:write] origin.i:54: 
-  Assigning imprecise value to qm2.
-  The imprecision originates from Misaligned {origin.i:54}
+  Assigning imprecise value to qm2 because of misaligned read of addresses.
 [eva] origin.i:55: 
   Frama_C_show_each:
-  {{ garbled mix of &{a; b} (origin: Misaligned {origin.i:54}) }}
+  {{ garbled mix of &{a; b} (origin: Misaligned read {origin.i:54}) }}
 [eva:alarm] origin.i:56: Warning: out of bounds write. assert \valid(qm2);
 [eva:alarm] origin.i:56: Warning: 
   pointer downcast. assert (unsigned int)(&a) ≤ 2147483647;
@@ -184,8 +179,8 @@
 [eva:alarm] origin.i:85: Warning: 
   signed overflow. assert -((int)(&arg)) ≤ 2147483647;
 [eva:garbled-mix:write] origin.i:85: 
-  Assigning imprecise value to esc3.
-  The imprecision originates from Arithmetic {origin.i:85}
+  Assigning imprecise value to esc3
+  because of arithmetic operation on addresses.
 [eva:alarm] origin.i:87: Warning: 
   pointer downcast. assert (unsigned int)(&local1) ≤ 2147483647;
 [eva:alarm] origin.i:88: Warning: 
@@ -202,6 +197,20 @@
   locals {local1} escaping the scope of local_escape_1 through esc4
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    origin.i:19: arithmetic operation on addresses
+      (read 3 times, propagated 2 times) garbled mix of &{ta2; tta2}
+    origin.i:54: misaligned read of addresses
+      (read 3 times, propagated 1 times) garbled mix of &{a; b}
+    origin.i:14: arithmetic operation on addresses
+      (read 2 times, propagated 1 times) garbled mix of &{ta1}
+    origin.i:25: arithmetic operation on addresses
+      (read 2 times, propagated 1 times) garbled mix of &{ta3}
+    origin.i:100: assigns clause on addresses
+      (read 2 times, propagated 2 times) garbled mix of &{S_gpp}
+    origin.i:48: misaligned read of addresses
+      (read 2 times, propagated 1 times) garbled mix of &{a; b}
 [eva] origin.i:75: assertion 'Eva,initialization' got final status invalid.
 [scope:rm_asserts] removing 2 assertion(s)
 [eva] ====== VALUES COMPUTED ======
@@ -219,9 +228,9 @@
   pa2 ∈ {{ garbled mix of &{ta2} (origin: Arithmetic {origin.i:19}) }}
   qa2 ∈ {{ &ta2 + [0..36] ; &tta2 + [0..36] }}
   ta2[0..9] ∈
-     {{ garbled mix of &{aa2} (origin: Misaligned {origin.i:21}) }}
+     {{ garbled mix of &{aa2} (origin: Misaligned write {origin.i:21}) }}
   tta2[0..9] ∈
-      {{ garbled mix of &{aa2} (origin: Misaligned {origin.i:21}) }}
+      {{ garbled mix of &{aa2} (origin: Misaligned write {origin.i:21}) }}
 [eva:final-states] Values at end of function origin_arithmetic_3:
   pa3 ∈ {{ &ta3 + [0..36] }}
   ta3[0..9] ∈ [--..--]
@@ -260,10 +269,10 @@
    {{ garbled mix of &{b} (origin: Merge {origin.i:106}) }}
   ta1[0..9] ∈ {0}
   ta2[0..9] ∈
-     {{ garbled mix of &{aa2} (origin: Misaligned {origin.i:21}) }}
+     {{ garbled mix of &{aa2} (origin: Misaligned write {origin.i:21}) }}
   ta3[0..9] ∈ [--..--]
   tta2[0..9] ∈
-      {{ garbled mix of &{aa2} (origin: Misaligned {origin.i:21}) }}
+      {{ garbled mix of &{aa2} (origin: Misaligned write {origin.i:21}) }}
   l1 ∈ [--..--]
   l2 ∈ [--..--]
   l3 ∈ [--..--]
diff --git a/tests/value/oracle/origin.1.res.oracle b/tests/value/oracle/origin.1.res.oracle
index 2d7eae48a93c4432e4dac6e0f18275b4fdc43432..f9c473570c4ed0ed91b4da38d351db512e6bfbf2 100644
--- a/tests/value/oracle/origin.1.res.oracle
+++ b/tests/value/oracle/origin.1.res.oracle
@@ -60,11 +60,9 @@
 [eva] using specification for function f
 [eva] Done for function f
 [eva:garbled-mix:write] origin.i:126: 
-  Assigning imprecise value to r.p.
-  The imprecision originates from Misaligned {origin.i:126}
+  Assigning imprecise value to r.p because of misaligned read of addresses.
 [eva:garbled-mix:write] origin.i:129: 
-  Assigning imprecise value to r.t[0].
-  The imprecision originates from Merge {origin.i:129}
+  Assigning imprecise value to r.t[0] because of imprecise merge of addresses.
 [eva:alarm] origin.i:130: Warning: 
   pointer downcast. assert (unsigned int)(&x) ≤ 2147483647;
 [eva:alarm] origin.i:130: Warning: 
@@ -72,19 +70,20 @@
 [eva:alarm] origin.i:130: Warning: 
   signed overflow. assert -((int)(&x)) ≤ 2147483647;
 [eva:garbled-mix:write] origin.i:130: 
-  Assigning imprecise value to r.t[1].
-  The imprecision originates from Arithmetic {origin.i:130}
-[eva:garbled-mix:write] origin.i:131: 
-  Assigning imprecise value to \result<origin>.
-  The imprecision originates from Misaligned {origin.i:126}
+  Assigning imprecise value to r.t[1]
+  because of arithmetic operation on addresses.
 [eva] Recording results for origin
 [eva] Done for function origin
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    origin.i:126: misaligned read of addresses
+      (read 1 times, propagated 2 times) garbled mix of &{x; y}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function origin:
   r.c ∈ [--..--]
    .[bits 8 to 15] ∈ UNINITIALIZED
    .i ∈ [--..--]
-   .p ∈ {{ garbled mix of &{x} (origin: Misaligned {origin.i:126}) }}
+   .p ∈ {{ garbled mix of &{x} (origin: Misaligned read {origin.i:126}) }}
    .t[0][bits 0 to 7] ∈
    {{ garbled mix of &{y} (origin: Merge {origin.i:129}) }}
    .t[0][bits 8 to 15]# ∈ {{ NULL ; (? *)&y }}%32, bits 24 to 31 
diff --git a/tests/value/oracle/period.res.oracle b/tests/value/oracle/period.res.oracle
index cca040e6158d8cb00ae2ab1bb22e787b08bec17a..3f7cc6e99f50ff733afed56c83c82de26a529a36 100644
--- a/tests/value/oracle/period.res.oracle
+++ b/tests/value/oracle/period.res.oracle
@@ -83,23 +83,28 @@
 [eva:alarm] period.c:51: Warning: 
   pointer downcast. assert (unsigned int)(&g) ≤ 2147483647;
 [eva:garbled-mix:write] period.c:51: 
-  Assigning imprecise value to p.
-  The imprecision originates from Arithmetic {period.c:51}
+  Assigning imprecise value to p because of arithmetic operation on addresses.
 [eva:alarm] period.c:52: Warning: out of bounds write. assert \valid(p);
 [eva:alarm] period.c:53: Warning: 
   pointer downcast. assert (unsigned int)(&g) ≤ 2147483647;
 [eva:garbled-mix:write] period.c:53: 
-  Assigning imprecise value to p.
-  The imprecision originates from Arithmetic {period.c:53}
+  Assigning imprecise value to p because of arithmetic operation on addresses.
 [eva:alarm] period.c:54: Warning: out of bounds read. assert \valid_read(p);
 [eva:alarm] period.c:55: Warning: 
   pointer downcast. assert (unsigned int)(&vg) ≤ 2147483647;
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    period.c:51: arithmetic operation on addresses
+      (read 2 times, propagated 1 times) garbled mix of &{g}
+    period.c:53: arithmetic operation on addresses
+      (read 2 times, propagated 1 times) garbled mix of &{g}
 [scope:rm_asserts] removing 1 assertion(s)
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main:
-  g[0..9] ∈ {{ garbled mix of &{vg} (origin: Misaligned {period.c:55}) }}
+  g[0..9] ∈
+   {{ garbled mix of &{vg} (origin: Misaligned write {period.c:55}) }}
   Frama_C_periodic_t_320[0] ∈ {1}
                         [1..3] ∈ {0}
                         [4] ∈ {24}
diff --git a/tests/value/oracle/recursion.0.res.oracle b/tests/value/oracle/recursion.0.res.oracle
index fd044aab639e3557a18f31a7ca6e5c4194ca3689..cb1dcc89815e6b7e167b7eb1a22971dcd955bda1 100644
--- a/tests/value/oracle/recursion.0.res.oracle
+++ b/tests/value/oracle/recursion.0.res.oracle
@@ -226,6 +226,9 @@
   Analysis of function escaping_stack is thus incomplete and its soundness
   relies on the written specification.
 [eva] using specification for function escaping_stack
+[eva:garbled-mix:assigns] recursion.c:311: 
+  The specification of function escaping_stack
+  has generated a garbled mix of addresses for assigns clause p.
 [eva:alarm] recursion.c:313: Warning: out of bounds write. assert \valid(p);
 [eva] recursion.c:314: Frama_C_show_each_1_2: {5}
 [eva:locals-escaping] recursion.c:312: Warning: 
@@ -236,6 +239,10 @@
   Analysis of function decr is thus incomplete and its soundness
   relies on the written specification.
 [eva] using specification for function decr
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    recursion.c:311: assigns clause on addresses
+      (read 2 times, propagated 1 times) garbled mix of &{x; a; \copy<x>[1]}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function alarm:
   res ∈ [10..2147483647]
diff --git a/tests/value/oracle/reduce_by_valid.res.oracle b/tests/value/oracle/reduce_by_valid.res.oracle
index dcea93719575ad63fc979a58b76af32c6ed72407..826021d49273bf80cfb3f3e201cd0fa2cc3507dc 100644
--- a/tests/value/oracle/reduce_by_valid.res.oracle
+++ b/tests/value/oracle/reduce_by_valid.res.oracle
@@ -145,10 +145,10 @@
 [eva] computing for function garbled_mix <- main12 <- main.
   Called from reduce_by_valid.i:272.
 [eva] using specification for function garbled_mix
+[eva:garbled-mix:assigns] reduce_by_valid.i:272: 
+  The specification of function garbled_mix
+  has generated a garbled mix of addresses for assigns clause \result.
 [eva] Done for function garbled_mix
-[eva:garbled-mix:write] reduce_by_valid.i:272: 
-  Assigning imprecise value to p.
-  The imprecision originates from Library function {reduce_by_valid.i:272}
 [eva] reduce_by_valid.i:273: 
   Frama_C_show_each_gm:
   {{ garbled mix of &{x; a}
@@ -170,15 +170,19 @@
   out of bounds write. assert \valid(r);
 [eva] computing for function garbled_mix <- main12 <- main.
   Called from reduce_by_valid.i:290.
+[eva:garbled-mix:assigns] reduce_by_valid.i:290: 
+  The specification of function garbled_mix
+  has generated a garbled mix of addresses for assigns clause \result.
 [eva] Done for function garbled_mix
-[eva:garbled-mix:write] reduce_by_valid.i:290: 
-  Assigning imprecise value to r.
-  The imprecision originates from Library function {reduce_by_valid.i:290}
 [eva:alarm] reduce_by_valid.i:291: Warning: assertion got status unknown.
 [eva] Recording results for main12
 [eva] Done for function main12
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    reduce_by_valid.i:272: assigns clause on addresses
+      (read 3 times, propagated 2 times) garbled mix of &{x; a}
 [scope:rm_asserts] removing 12 assertion(s)
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main1:
diff --git a/tests/value/oracle/shift.0.res.oracle b/tests/value/oracle/shift.0.res.oracle
index bb1cdf0553127b21f9ad900a7b60b2580fc218de..38218467e1391e87dd16adb079beca1594aa854e 100644
--- a/tests/value/oracle/shift.0.res.oracle
+++ b/tests/value/oracle/shift.0.res.oracle
@@ -42,8 +42,7 @@
 [eva:alarm] shift.i:52: Warning: 
   unsigned overflow. assert (unsigned long)((char *)t) << 8 ≤ 4294967295;
 [eva:garbled-mix:write] shift.i:52: 
-  Assigning imprecise value to r.
-  The imprecision originates from Arithmetic {shift.i:52}
+  Assigning imprecise value to r because of arithmetic operation on addresses.
 [eva:alarm] shift.i:53: Warning: 
   pointer downcast. assert (unsigned int)((char *)t) ≤ 2147483647;
 [eva:alarm] shift.i:53: Warning: 
@@ -58,13 +57,14 @@
 [eva:alarm] shift.i:53: Warning: 
   signed overflow.
   assert (long)r + (long)((long)((char *)t) << 8) ≤ 2147483647;
-[eva:garbled-mix:write] shift.i:53: 
-  Assigning imprecise value to r.
-  The imprecision originates from Arithmetic
 [eva:alarm] shift.i:58: Warning: 
   unsigned overflow. assert 2U << 31 ≤ 4294967295;
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    shift.i:52: arithmetic operation on addresses
+      (read 1 times, propagated 2 times) garbled mix of &{t}
 [eva] shift.i:35: assertion 'Eva,shift' got final status invalid.
 [eva] shift.i:36: assertion 'Eva,shift' got final status invalid.
 [eva] shift.i:40: assertion 'Eva,shift' got final status invalid.
diff --git a/tests/value/oracle/shift.1.res.oracle b/tests/value/oracle/shift.1.res.oracle
index 601488698eb84a19f1a5ff51d8cd97c3ac787d0e..cf118f59bd758f7162dbcf25ddf0b285625eaa62 100644
--- a/tests/value/oracle/shift.1.res.oracle
+++ b/tests/value/oracle/shift.1.res.oracle
@@ -36,8 +36,7 @@
 [eva] shift.i:48: 
   Frama_C_show_each: {{ "ua:%u\nub:%u\n" }}, {1401}, {1073741074}
 [eva:garbled-mix:write] shift.i:52: 
-  Assigning imprecise value to r.
-  The imprecision originates from Arithmetic {shift.i:52}
+  Assigning imprecise value to r because of arithmetic operation on addresses.
 [eva:alarm] shift.i:53: Warning: 
   pointer downcast. assert (unsigned int)((char *)t) ≤ 2147483647;
 [eva:alarm] shift.i:53: Warning: 
@@ -50,11 +49,12 @@
 [eva:alarm] shift.i:53: Warning: 
   signed overflow.
   assert (long)r + (long)((long)((char *)t) << 8) ≤ 2147483647;
-[eva:garbled-mix:write] shift.i:53: 
-  Assigning imprecise value to r.
-  The imprecision originates from Arithmetic
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    shift.i:52: arithmetic operation on addresses
+      (read 1 times, propagated 2 times) garbled mix of &{t}
 [eva] shift.i:35: assertion 'Eva,shift' got final status invalid.
 [eva] shift.i:36: assertion 'Eva,shift' got final status invalid.
 [eva] shift.i:40: assertion 'Eva,shift' got final status invalid.
diff --git a/tests/value/oracle/sizeof.res.oracle b/tests/value/oracle/sizeof.res.oracle
index e9b64cb2ded5b0d9df7a1b6e5661cfc40e6f782e..aa6a36837e24f63aa3c3f9e895594f1743c78872 100644
--- a/tests/value/oracle/sizeof.res.oracle
+++ b/tests/value/oracle/sizeof.res.oracle
@@ -21,8 +21,7 @@
 [eva:alarm] sizeof.i:32: Warning: 
   pointer downcast. assert (unsigned int)(&s1) ≤ 2147483647;
 [eva:garbled-mix:write] sizeof.i:32: 
-  Assigning imprecise value to p.
-  The imprecision originates from Arithmetic {sizeof.i:32}
+  Assigning imprecise value to p because of arithmetic operation on addresses.
 [eva:alarm] sizeof.i:33: Warning: 
   accessing out of bounds index.
   assert (unsigned int)(sizeof(int [10]) - (unsigned int)i) < 10;
@@ -47,6 +46,10 @@
 [eva] Done for function f
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    sizeof.i:32: arithmetic operation on addresses
+      (read 2 times, propagated 1 times) garbled mix of &{s1}
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function f:
   
diff --git a/tests/value/oracle/struct3.res.oracle b/tests/value/oracle/struct3.res.oracle
index 20c83c1fc97b7e5983a55566c669ea7d3b98d68c..795a309294796edcca100322d47c6aa0466208fb 100644
--- a/tests/value/oracle/struct3.res.oracle
+++ b/tests/value/oracle/struct3.res.oracle
@@ -24,13 +24,10 @@
 [eva:alarm] struct3.i:46: Warning: 
   pointer downcast. assert (unsigned int)(s2.c + (int)s2.c) ≤ 2147483647;
 [eva:garbled-mix:write] struct3.i:46: Warning: 
-  Assigning imprecise value to s2.a.
-  The imprecision originates from Arithmetic {struct3.i:46}
+  Assigning imprecise value to s2.a
+  because of arithmetic operation on addresses.
 [eva] Recording results for main
 [eva] Done for function main
-[eva:garbled-mix:summary] Warning: 
-  Garbled mix generated during analysis:
-  {{ garbled mix of &{s1} (origin: Arithmetic {struct3.i:46}) }}
 [eva] struct3.i:42: assertion 'Eva,index_bound' got final status invalid.
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main:
diff --git a/tests/value/oracle/va_list2.0.res.oracle b/tests/value/oracle/va_list2.0.res.oracle
index 619211814b41de75cdd428ff271735802110dfd5..2b3a7d3e4a6bb9f37aa3a50764303572b75e81ae 100644
--- a/tests/value/oracle/va_list2.0.res.oracle
+++ b/tests/value/oracle/va_list2.0.res.oracle
@@ -13,12 +13,6 @@
   out of bounds read. assert \valid_read(args);
 [eva:alarm] va_list2.c:15: Warning: 
   out of bounds read. assert \valid_read((int *)*args);
-[eva:garbled-mix:write] va_list2.c:15: 
-  Assigning imprecise value to tmp.
-  The imprecision originates from Well
-[eva:garbled-mix:write] va_list2.c:15: 
-  Assigning imprecise value to i.
-  The imprecision originates from Well
 [eva] va_list2.c:16: 
   Frama_C_show_each_i: {{ garbled mix of &{S_0_S___va_params} (origin: Well) }}
 [eva:alarm] va_list2.c:20: Warning: 
@@ -27,15 +21,9 @@
   out of bounds read. assert \valid_read((float *)*args);
 [eva:alarm] va_list2.c:20: Warning: 
   non-finite float value. assert \is_finite(*((float *)*args));
-[eva:garbled-mix:write] va_list2.c:20: 
-  Assigning imprecise value to tmp_0.
-  The imprecision originates from Well
 [eva:alarm] va_list2.c:20: Warning: 
   non-finite float value. assert \is_finite(tmp_0);
                           (tmp_0 from vararg)
-[eva:garbled-mix:write] va_list2.c:20: 
-  Assigning imprecise value to f.
-  The imprecision originates from Well
 [eva] va_list2.c:21: 
   Frama_C_show_each_f: {{ garbled mix of &{S_0_S___va_params} (origin: Well) }}
 [eva] va_list2.c:12: starting to merge loop iterations
@@ -48,6 +36,10 @@
   {{ garbled mix of &{S_0_S___va_params; S_1_S___va_params} (origin: Well) }}
 [eva] Recording results for main
 [eva] Done for function main
+[eva:garbled-mix:summary] 
+  Origins of garbled mix generated during analysis:
+    Initial state (read 24 times, propagated 10 times)
+      garbled mix of &{S_0_S___va_params; S_1_S___va_params}
 [scope:rm_asserts] removing 1 assertion(s)
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main:
diff --git a/tests/value/oracle_apron/backward_add_ptr.res.oracle b/tests/value/oracle_apron/backward_add_ptr.res.oracle
index 0b3c21f037c9ee69262a15f6e7398ffa44360062..04bf26aed2a3d76fb3e5f7a704d63846dbaab183 100644
--- a/tests/value/oracle_apron/backward_add_ptr.res.oracle
+++ b/tests/value/oracle_apron/backward_add_ptr.res.oracle
@@ -1,28 +1,32 @@
-64c64,67
+58c58,61
 < [eva] backward_add_ptr.c:91: Reusing old results for call to gm
 ---
 > [eva] computing for function gm <- main3 <- main.
 >   Called from backward_add_ptr.c:91.
 > [eva] Recording results for gm
 > [eva] Done for function gm
-84c87,90
+72c75,78
 < [eva] backward_add_ptr.c:110: Reusing old results for call to gm
 ---
 > [eva] computing for function gm <- main3 <- main.
 >   Called from backward_add_ptr.c:110.
 > [eva] Recording results for gm
 > [eva] Done for function gm
-96c102,105
+81c87,90
 < [eva] backward_add_ptr.c:125: Reusing old results for call to gm
 ---
 > [eva] computing for function gm <- main3 <- main.
 >   Called from backward_add_ptr.c:125.
 > [eva] Recording results for gm
 > [eva] Done for function gm
-145c154,157
+118c127,130
 < [eva] backward_add_ptr.c:160: Reusing old results for call to gm
 ---
 > [eva] computing for function gm <- main4 <- main.
 >   Called from backward_add_ptr.c:160.
 > [eva] Recording results for gm
 > [eva] Done for function gm
+154c166
+<       (read 81 times, propagated 20 times) garbled mix of &{a; b; a; b; c}
+---
+>       (read 81 times, propagated 28 times) garbled mix of &{a; b; a; b; c}
diff --git a/tests/value/oracle_apron/gauges.res.oracle b/tests/value/oracle_apron/gauges.res.oracle
index f92d9c4624085811acfa7d68741f16f06a0b61c4..e39bbda029892bd78f7dccf1f133ee3e51428468 100644
--- a/tests/value/oracle_apron/gauges.res.oracle
+++ b/tests/value/oracle_apron/gauges.res.oracle
@@ -17,36 +17,36 @@
 < [eva:alarm] gauges.c:99: Warning: signed overflow. assert c + 1 ≤ 2147483647;
 175d171
 < [eva:alarm] gauges.c:140: Warning: signed overflow. assert j + 1 ≤ 2147483647;
-285,286d280
+281,282d276
 < [eva:alarm] gauges.c:220: Warning: 
 <   signed overflow. assert -2147483648 ≤ n - 1;
-300,302c294
+296,298c290
 < [eva:alarm] gauges.c:240: Warning: signed overflow. assert j + 1 ≤ 2147483647;
 < [eva] gauges.c:242: 
 <   Frama_C_show_each: {45; 46; 47; 48; 49; 50; 51}, [0..2147483647]
 ---
 > [eva] gauges.c:242: Frama_C_show_each: {45; 46; 47; 48; 49; 50; 51}, [0..46]
-308,310c300
+304,306c296
 < [eva:alarm] gauges.c:251: Warning: signed overflow. assert j + 1 ≤ 2147483647;
 < [eva] gauges.c:254: 
 <   Frama_C_show_each: {48; 49; 50; 51; 52; 53; 54}, [0..2147483647]
 ---
 > [eva] gauges.c:254: Frama_C_show_each: {48; 49; 50; 51; 52; 53; 54}, [0..49]
-316d305
+312d301
 < [eva:alarm] gauges.c:263: Warning: signed overflow. assert j + 1 ≤ 2147483647;
-318c307
+314c303
 <   Frama_C_show_each: {-59; -58; -57; -56; -55; -54; -53}, [0..2147483647]
 ---
 >   Frama_C_show_each: {-59; -58; -57; -56; -55; -54; -53}, [0..65]
-324d312
+320d308
 < [eva:alarm] gauges.c:274: Warning: signed overflow. assert j + 1 ≤ 2147483647;
-326c314
+322c310
 <   Frama_C_show_each: {-64; -63; -62; -61; -60; -59; -58}, [0..2147483647]
 ---
 >   Frama_C_show_each: {-64; -63; -62; -61; -60; -59; -58}, [0..70]
-334d321
+330d317
 < [eva:alarm] gauges.c:293: Warning: signed overflow. assert j + 1 ≤ 2147483647;
-336c323
+332c319
 <   Frama_C_show_each: {-593; -592; -591; -590; -589; -588}, [0..2147483647]
 ---
 >   Frama_C_show_each: {-593; -592; -591; -590; -589; -588}, [0..598]
diff --git a/tests/value/oracle_bitwise/addition.res.oracle b/tests/value/oracle_bitwise/addition.res.oracle
deleted file mode 100644
index f65148d676c435df46dbec93bc4f3958019e7208..0000000000000000000000000000000000000000
--- a/tests/value/oracle_bitwise/addition.res.oracle
+++ /dev/null
@@ -1,16 +0,0 @@
-123d122
-<   The imprecision originates from Arithmetic {addition.i:52}
-162a162
->   {{ garbled mix of &{p1} (origin: Misaligned {addition.i:52}) }}
-163a164
->   {{ garbled mix of &{p2} (origin: Misaligned {addition.i:56}) }}
-186c187
-<   p10 ∈ {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:52}) }}
----
->   p10 ∈ {{ garbled mix of &{p1} }}
-405a407
->   {{ garbled mix of &{p1} (origin: Misaligned {addition.i:52}) }}
-429c431
-<   p10 ∈ {{ garbled mix of &{p1} (origin: Arithmetic {addition.i:52}) }}
----
->   p10 ∈ {{ garbled mix of &{p1} }}
diff --git a/tests/value/oracle_bitwise/bitwise_pointer.0.res.oracle b/tests/value/oracle_bitwise/bitwise_pointer.0.res.oracle
deleted file mode 100644
index 370739039c6f31f1307fdab215ccdd958820f386..0000000000000000000000000000000000000000
--- a/tests/value/oracle_bitwise/bitwise_pointer.0.res.oracle
+++ /dev/null
@@ -1,12 +0,0 @@
-34,36c34
-< [eva:garbled-mix:write] bitwise_pointer.i:18: 
-<   Assigning imprecise value to p.
-<   The imprecision originates from Arithmetic {bitwise_pointer.i:18}
----
-> [eva:garbled-mix:write] bitwise_pointer.i:18: Assigning imprecise value to p.
-41,43c39
-< [eva:garbled-mix:write] bitwise_pointer.i:22: 
-<   Assigning imprecise value to p1.
-<   The imprecision originates from Arithmetic {bitwise_pointer.i:22}
----
-> [eva:garbled-mix:write] bitwise_pointer.i:22: Assigning imprecise value to p1.
diff --git a/tests/value/oracle_bitwise/bitwise_pointer.1.res.oracle b/tests/value/oracle_bitwise/bitwise_pointer.1.res.oracle
deleted file mode 100644
index 370739039c6f31f1307fdab215ccdd958820f386..0000000000000000000000000000000000000000
--- a/tests/value/oracle_bitwise/bitwise_pointer.1.res.oracle
+++ /dev/null
@@ -1,12 +0,0 @@
-34,36c34
-< [eva:garbled-mix:write] bitwise_pointer.i:18: 
-<   Assigning imprecise value to p.
-<   The imprecision originates from Arithmetic {bitwise_pointer.i:18}
----
-> [eva:garbled-mix:write] bitwise_pointer.i:18: Assigning imprecise value to p.
-41,43c39
-< [eva:garbled-mix:write] bitwise_pointer.i:22: 
-<   Assigning imprecise value to p1.
-<   The imprecision originates from Arithmetic {bitwise_pointer.i:22}
----
-> [eva:garbled-mix:write] bitwise_pointer.i:22: Assigning imprecise value to p1.
diff --git a/tests/value/oracle_bitwise/logic_ptr_cast.res.oracle b/tests/value/oracle_bitwise/logic_ptr_cast.res.oracle
deleted file mode 100644
index 60fe515050a5108521f39a3d59b01e51cb848735..0000000000000000000000000000000000000000
--- a/tests/value/oracle_bitwise/logic_ptr_cast.res.oracle
+++ /dev/null
@@ -1,6 +0,0 @@
-8,10c8
-< [eva:garbled-mix:write] logic_ptr_cast.i:8: 
-<   Assigning imprecise value to p.
-<   The imprecision originates from Arithmetic {logic_ptr_cast.i:8}
----
-> [eva:garbled-mix:write] logic_ptr_cast.i:8: Assigning imprecise value to p.
diff --git a/tests/value/oracle_equality/addition.res.oracle b/tests/value/oracle_equality/addition.res.oracle
index 05493bd86cacf8b5cd209c6f697a5afa28c210c5..5a0da48b045e46f9201b4058cfc0010bef15e6cc 100644
--- a/tests/value/oracle_equality/addition.res.oracle
+++ b/tests/value/oracle_equality/addition.res.oracle
@@ -1,18 +1,36 @@
-138,141d137
+129,134d128
 < [eva:alarm] addition.i:61: Warning: 
 <   signed overflow. assert -2147483648 ≤ (int)*((char *)(&q1)) + 2;
 < [eva:alarm] addition.i:61: Warning: 
 <   signed overflow. assert (int)*((char *)(&q1)) + 2 ≤ 2147483647;
-168c164
+< [eva:garbled-mix:write] addition.i:61: Warning: 
+<   Assigning imprecise value to p14 because of misaligned read of addresses.
+141c135,139
 < [scope:rm_asserts] removing 9 assertion(s)
 ---
+> [eva:garbled-mix:summary] Warning: 
+>   Origins of garbled mix generated during analysis:
+>     addition.i:59: misaligned read of addresses
+>       (read 1 times, propagated 2 times) garbled mix of &{p1}
 > [scope:rm_asserts] removing 7 assertion(s)
-384,387d379
+165c163
+<      {{ garbled mix of &{p1} (origin: Misaligned read {addition.i:61}) }}
+---
+>      {{ garbled mix of &{p1} (origin: Misaligned read {addition.i:59}) }}
+359,362d356
 < [eva:alarm] addition.i:61: Warning: 
 <   signed overflow. assert -2147483648 ≤ (int)*((char *)(&q1)) + 2;
 < [eva:alarm] addition.i:61: Warning: 
 <   signed overflow. assert (int)*((char *)(&q1)) + 2 ≤ 2147483647;
-410c402
+368c362,366
 < [scope:rm_asserts] removing 9 assertion(s)
 ---
+> [eva:garbled-mix:summary] Warning: 
+>   Origins of garbled mix generated during analysis:
+>     addition.i:59: misaligned read of addresses
+>       (read 1 times, propagated 2 times) garbled mix of &{p1}
 > [scope:rm_asserts] removing 7 assertion(s)
+393c391
+<      {{ garbled mix of &{p1} (origin: Misaligned read {addition.i:61}) }}
+---
+>      {{ garbled mix of &{p1} (origin: Misaligned read {addition.i:59}) }}
diff --git a/tests/value/oracle_equality/arith_pointer.res.oracle b/tests/value/oracle_equality/arith_pointer.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..e8d12d536a5435ae4567640619599a9d10b2e3ab
--- /dev/null
+++ b/tests/value/oracle_equality/arith_pointer.res.oracle
@@ -0,0 +1,8 @@
+48c48
+<       (read 2 times, propagated 2 times) garbled mix of &{x}
+---
+>       (read 3 times, propagated 2 times) garbled mix of &{x}
+161c161
+<       (read 2 times, propagated 2 times) garbled mix of &{x}
+---
+>       (read 3 times, propagated 2 times) garbled mix of &{x}
diff --git a/tests/value/oracle_equality/assigns.res.oracle b/tests/value/oracle_equality/assigns.res.oracle
index 0f5f7cdfe8d3e4b52e991076bcc82bf5bf9d9539..f423e4eb8cc93ea8dd508d87d6f093838268f3b4 100644
--- a/tests/value/oracle_equality/assigns.res.oracle
+++ b/tests/value/oracle_equality/assigns.res.oracle
@@ -1,6 +1,6 @@
-149,150d148
+154,155d153
 <   more than 200(1000) locations to update in array. Approximating.
 < [kernel] assigns.i:104: 
-151a150,151
+156a155,156
 > [kernel] assigns.i:104: 
 >   more than 200(1000) locations to update in array. Approximating.
diff --git a/tests/value/oracle_equality/backward_add_ptr.res.oracle b/tests/value/oracle_equality/backward_add_ptr.res.oracle
index 3a6305e610f4b9491eff8fa269924571213a2b3b..1b7ff53fec0b3b7db573cd6fc15fa8834ae8b229 100644
--- a/tests/value/oracle_equality/backward_add_ptr.res.oracle
+++ b/tests/value/oracle_equality/backward_add_ptr.res.oracle
@@ -2,88 +2,28 @@
 < [eva] backward_add_ptr.c:26: Frama_C_show_each_only_a: {0; 1}, {{ &a }}, {0}
 ---
 > [eva] backward_add_ptr.c:26: Frama_C_show_each_only_a: {0}, {{ &a }}, {0}
-84c84,87
+72c72,75
 < [eva] backward_add_ptr.c:110: Reusing old results for call to gm
 ---
 > [eva] computing for function gm <- main3 <- main.
 >   Called from backward_add_ptr.c:110.
 > [eva] Recording results for gm
 > [eva] Done for function gm
-96c99,102
+81c84,87
 < [eva] backward_add_ptr.c:125: Reusing old results for call to gm
 ---
 > [eva] computing for function gm <- main3 <- main.
 >   Called from backward_add_ptr.c:125.
 > [eva] Recording results for gm
 > [eva] Done for function gm
-107c113
-<   (origin: Arithmetic {backward_add_ptr.c:68}) }},
----
->   (origin: Arithmetic Bottom) }},
-142,145c148,152
-<   {{ garbled mix of &{b}
-<   (origin: Arithmetic {backward_add_ptr.c:68}) }},
-<   [0..4294967295]
+118c124,127
 < [eva] backward_add_ptr.c:160: Reusing old results for call to gm
 ---
->   {{ garbled mix of &{b} (origin: Arithmetic Bottom) }}, [0..4294967295]
 > [eva] computing for function gm <- main4 <- main.
 >   Called from backward_add_ptr.c:160.
 > [eva] Recording results for gm
 > [eva] Done for function gm
-161c168
-<   (origin: Arithmetic {backward_add_ptr.c:68}) }},
----
->   (origin: Arithmetic Bottom) }},
-163c170
-<   (origin: Arithmetic {backward_add_ptr.c:68}) }}
----
->   (origin: Arithmetic Bottom) }}
-171c178
-<   (origin: Arithmetic {backward_add_ptr.c:68}) }}
----
->   (origin: Arithmetic Bottom) }}
-177c184
-<   (origin: Arithmetic {backward_add_ptr.c:68}) }},
----
->   (origin: Arithmetic Bottom) }},
-189a197,198
->   {{ garbled mix of &{b} (origin: Arithmetic {backward_add_ptr.c:33}) }}
->   {{ garbled mix of &{a} (origin: Arithmetic {backward_add_ptr.c:33}) }}
-200a210
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:106}) }}
-202c212
-<   {{ garbled mix of &{c} (origin: Arithmetic {backward_add_ptr.c:115}) }}
+154c163
+<       (read 81 times, propagated 20 times) garbled mix of &{a; b; a; b; c}
 ---
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:107}) }}
-203a214,216
->   {{ garbled mix of &{c} (origin: Arithmetic {backward_add_ptr.c:115}) }}
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:116}) }}
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:121}) }}
-204a218,219
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:122}) }}
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:130}) }}
-205a221
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:136}) }}
-206a223
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:137}) }}
-207a225
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:145}) }}
-208a227,230
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:150}) }}
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:151}) }}
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:156}) }}
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:157}) }}
-209a232,243
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:165}) }}
->   {{ garbled mix of &{b; c} (origin: Arithmetic {backward_add_ptr.c:165}) }}
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:166}) }}
->   {{ garbled mix of &{b; c} (origin: Arithmetic {backward_add_ptr.c:166}) }}
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:171}) }}
->   {{ garbled mix of &{b; c} (origin: Arithmetic {backward_add_ptr.c:171}) }}
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:172}) }}
->   {{ garbled mix of &{b; c} (origin: Arithmetic {backward_add_ptr.c:172}) }}
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:177}) }}
->   {{ garbled mix of &{b; c} (origin: Arithmetic {backward_add_ptr.c:177}) }}
->   {{ garbled mix of &{a; b} (origin: Arithmetic {backward_add_ptr.c:178}) }}
->   {{ garbled mix of &{b; c} (origin: Arithmetic {backward_add_ptr.c:178}) }}
+>       (read 86 times, propagated 26 times) garbled mix of &{a; b; a; b; c}
diff --git a/tests/value/oracle_equality/bitfield.res.oracle b/tests/value/oracle_equality/bitfield.res.oracle
index 9886a5a3b66d5f82e84afc4a5a3b268b67994a12..d8fa5662f8993ea18aae6c740069a2253c9740e2 100644
--- a/tests/value/oracle_equality/bitfield.res.oracle
+++ b/tests/value/oracle_equality/bitfield.res.oracle
@@ -1,4 +1,8 @@
 137a138,140
 > [eva] bitfield.i:71: 
 >   Frama_C_show_each:
->   {{ garbled mix of &{b} (origin: Misaligned {bitfield.i:70}) }}
+>   {{ garbled mix of &{b} (origin: Misaligned read {bitfield.i:70}) }}
+213c216
+<       (read 5 times, propagated 7 times) garbled mix of &{b; ee}
+---
+>       (read 6 times, propagated 7 times) garbled mix of &{b; ee}
diff --git a/tests/value/oracle_equality/bitwise_pointer.0.res.oracle b/tests/value/oracle_equality/bitwise_pointer.0.res.oracle
index f04f7077977a5a61ea7d346c6ff6f90a2e4237e4..688b8e07ea0d94b9b3a3e8c2d26e5ff3a5a8f9e6 100644
--- a/tests/value/oracle_equality/bitwise_pointer.0.res.oracle
+++ b/tests/value/oracle_equality/bitwise_pointer.0.res.oracle
@@ -1,8 +1,8 @@
-62c62
+66c66
 <   x ∈ [0..9]
 ---
 >   x ∈ {5}
-75c75
+79c79
 <   x1 ∈ [0..9]
 ---
 >   x1 ∈ {5}
diff --git a/tests/value/oracle_equality/bitwise_pointer.1.res.oracle b/tests/value/oracle_equality/bitwise_pointer.1.res.oracle
index f04f7077977a5a61ea7d346c6ff6f90a2e4237e4..688b8e07ea0d94b9b3a3e8c2d26e5ff3a5a8f9e6 100644
--- a/tests/value/oracle_equality/bitwise_pointer.1.res.oracle
+++ b/tests/value/oracle_equality/bitwise_pointer.1.res.oracle
@@ -1,8 +1,8 @@
-62c62
+66c66
 <   x ∈ [0..9]
 ---
 >   x ∈ {5}
-75c75
+79c79
 <   x1 ∈ [0..9]
 ---
 >   x1 ∈ {5}
diff --git a/tests/value/oracle_equality/context_free.res.oracle b/tests/value/oracle_equality/context_free.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..edf1bab4ce0f782dcf8cacb94936e89dd482ddbb
--- /dev/null
+++ b/tests/value/oracle_equality/context_free.res.oracle
@@ -0,0 +1,4 @@
+95c95
+<     Initial state (read 9 times, propagated 5 times)
+---
+>     Initial state (read 11 times, propagated 5 times)
diff --git a/tests/value/oracle_equality/empty_struct.6.res.oracle b/tests/value/oracle_equality/empty_struct.6.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..a5fdd6006f01b6a3c868dca147b94ac07083a5ae
--- /dev/null
+++ b/tests/value/oracle_equality/empty_struct.6.res.oracle
@@ -0,0 +1,4 @@
+27c27
+<       (read 2 times, propagated 3 times) garbled mix of &{gs}
+---
+>       (read 3 times, propagated 3 times) garbled mix of &{gs}
diff --git a/tests/value/oracle_equality/gauges.res.oracle b/tests/value/oracle_equality/gauges.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..1375772daf32d94c39da70a45a329a0af7e75df1
--- /dev/null
+++ b/tests/value/oracle_equality/gauges.res.oracle
@@ -0,0 +1,4 @@
+716c716
+<       (read 14 times, propagated 12 times) garbled mix of &{x; y}
+---
+>       (read 20 times, propagated 12 times) garbled mix of &{x; y}
diff --git a/tests/value/oracle_equality/imprecise_invalid_write.res.oracle b/tests/value/oracle_equality/imprecise_invalid_write.res.oracle
index bb982e73d80195bfc94798bd4ae7791b502f93ef..1306d9d6c575eaba355d3aa332df2ba32c5ef554 100644
--- a/tests/value/oracle_equality/imprecise_invalid_write.res.oracle
+++ b/tests/value/oracle_equality/imprecise_invalid_write.res.oracle
@@ -1,3 +1,3 @@
-28a29,30
+27a28,29
 > [kernel] imprecise_invalid_write.i:9: 
 >   imprecise size for variable main1 (Undefined sizeof on a function.)
diff --git a/tests/value/oracle_equality/origin.0.res.oracle b/tests/value/oracle_equality/origin.0.res.oracle
index fca55cdcd1617b76c6bd48031be44f3befefd3c2..a12449e315cdcbf000a4adcafec176f044d53066 100644
--- a/tests/value/oracle_equality/origin.0.res.oracle
+++ b/tests/value/oracle_equality/origin.0.res.oracle
@@ -1,9 +1,9 @@
-237,238c237
+246,247c246
 <   pm2[bits 0 to 15]# ∈ {{ (? *)&a }}%32, bits 16 to 31 
 <      [bits 16 to 31]# ∈ {{ (? *)&b }}%32, bits 0 to 15 
 ---
 >   pm2 ∈ {{ &a + {-4} ; &b + {-4} }}
-272,273c271
+281,282c280
 <   pm2[bits 0 to 15]# ∈ {{ (? *)&a }}%32, bits 16 to 31 
 <      [bits 16 to 31]# ∈ {{ (? *)&b }}%32, bits 0 to 15 
 ---
diff --git a/tests/value/oracle_equality/period.res.oracle b/tests/value/oracle_equality/period.res.oracle
index 315304aca0443b62c2263315e5e8e4a5b70abc99..657c13125d1d186b4e4b752cd479fb28e639a08b 100644
--- a/tests/value/oracle_equality/period.res.oracle
+++ b/tests/value/oracle_equality/period.res.oracle
@@ -1,9 +1,10 @@
-89,94d88
+88,92d87
 < [eva:alarm] period.c:53: Warning: 
 <   pointer downcast. assert (unsigned int)(&g) ≤ 2147483647;
 < [eva:garbled-mix:write] period.c:53: 
-<   Assigning imprecise value to p.
-<   The imprecision originates from Arithmetic {period.c:53}
+<   Assigning imprecise value to p because of arithmetic operation on addresses.
 < [eva:alarm] period.c:54: Warning: out of bounds read. assert \valid_read(p);
-99d92
+101,103d95
+<     period.c:53: arithmetic operation on addresses
+<       (read 2 times, propagated 1 times) garbled mix of &{g}
 < [scope:rm_asserts] removing 1 assertion(s)
diff --git a/tests/value/oracle_equality/va_list2.0.res.oracle b/tests/value/oracle_equality/va_list2.0.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..2907faaa45d2cec4207024217ed66cf9699b41f8
--- /dev/null
+++ b/tests/value/oracle_equality/va_list2.0.res.oracle
@@ -0,0 +1,4 @@
+41c41
+<     Initial state (read 24 times, propagated 10 times)
+---
+>     Initial state (read 28 times, propagated 10 times)
diff --git a/tests/value/oracle_gauges/bitfield.res.oracle b/tests/value/oracle_gauges/bitfield.res.oracle
index e0125a5db691f59d2cacd6f04887d761975891e2..619b7b85a2389c7c7816e21f58c56851130dcdb0 100644
--- a/tests/value/oracle_gauges/bitfield.res.oracle
+++ b/tests/value/oracle_gauges/bitfield.res.oracle
@@ -1,16 +1,20 @@
 137a138,152
 > [eva] bitfield.i:71: 
 >   Frama_C_show_each:
->   {{ garbled mix of &{b} (origin: Misaligned {bitfield.i:70}) }}
+>   {{ garbled mix of &{b} (origin: Misaligned read {bitfield.i:70}) }}
 > [eva] bitfield.i:73: 
 >   Frama_C_show_each:
->   {{ garbled mix of &{b} (origin: Misaligned {bitfield.i:70}) }}
+>   {{ garbled mix of &{b} (origin: Misaligned read {bitfield.i:70}) }}
 > [eva] computing for function leaf <- imprecise_bts_1671 <- main.
 >   Called from bitfield.i:70.
 > [eva] Done for function leaf
 > [eva] bitfield.i:71: 
 >   Frama_C_show_each:
->   {{ garbled mix of &{b} (origin: Misaligned {bitfield.i:70}) }}
+>   {{ garbled mix of &{b} (origin: Misaligned read {bitfield.i:70}) }}
 > [eva] bitfield.i:73: 
 >   Frama_C_show_each:
->   {{ garbled mix of &{b} (origin: Misaligned {bitfield.i:70}) }}
+>   {{ garbled mix of &{b} (origin: Misaligned read {bitfield.i:70}) }}
+213c228
+<       (read 5 times, propagated 7 times) garbled mix of &{b; ee}
+---
+>       (read 9 times, propagated 11 times) garbled mix of &{b; ee}
diff --git a/tests/value/oracle_gauges/gauges.res.oracle b/tests/value/oracle_gauges/gauges.res.oracle
index 89bba971700e381aecb42f0a87e0010a27a5a7d7..9d4462e029b227ddad11d18dc38dee160fab8cff 100644
--- a/tests/value/oracle_gauges/gauges.res.oracle
+++ b/tests/value/oracle_gauges/gauges.res.oracle
@@ -54,82 +54,82 @@
 ---
 > [eva] gauges.c:172: Frama_C_show_each: [2147483647..4294967294]
 > [eva] gauges.c:172: Frama_C_show_each: [2147483647..4294967294]
-244,245d225
+240,241d221
 < [eva:alarm] gauges.c:192: Warning: out of bounds write. assert \valid(p);
 < [eva:alarm] gauges.c:193: Warning: out of bounds write. assert \valid(q);
-253,258d232
+249,254d228
 < [eva:alarm] gauges.c:202: Warning: 
 <   out of bounds read. assert \valid_read(tmp);
 <                       (tmp from A++)
 < [eva:alarm] gauges.c:202: Warning: 
 <   out of bounds read. assert \valid_read(tmp_0);
 <                       (tmp_0 from B++)
-285,286d258
+281,282d254
 < [eva:alarm] gauges.c:220: Warning: 
 <   signed overflow. assert -2147483648 ≤ n - 1;
-300,302c272
+296,298c268
 < [eva:alarm] gauges.c:240: Warning: signed overflow. assert j + 1 ≤ 2147483647;
 < [eva] gauges.c:242: 
 <   Frama_C_show_each: {45; 46; 47; 48; 49; 50; 51}, [0..2147483647]
 ---
 > [eva] gauges.c:242: Frama_C_show_each: {47; 48}, {6}
-308,310c278
+304,306c274
 < [eva:alarm] gauges.c:251: Warning: signed overflow. assert j + 1 ≤ 2147483647;
 < [eva] gauges.c:254: 
 <   Frama_C_show_each: {48; 49; 50; 51; 52; 53; 54}, [0..2147483647]
 ---
 > [eva] gauges.c:254: Frama_C_show_each: {48; 49; 50; 51; 52; 53; 54}, {6; 7}
-316,318c284
+312,314c280
 < [eva:alarm] gauges.c:263: Warning: signed overflow. assert j + 1 ≤ 2147483647;
 < [eva] gauges.c:265: 
 <   Frama_C_show_each: {-59; -58; -57; -56; -55; -54; -53}, [0..2147483647]
 ---
 > [eva] gauges.c:265: Frama_C_show_each: {-58; -57}, {9}
-324d289
+320d285
 < [eva:alarm] gauges.c:274: Warning: signed overflow. assert j + 1 ≤ 2147483647;
-326c291
+322c287
 <   Frama_C_show_each: {-64; -63; -62; -61; -60; -59; -58}, [0..2147483647]
 ---
 >   Frama_C_show_each: {-64; -63; -62; -61; -60; -59; -58}, {9; 10}
-334d298
+330d294
 < [eva:alarm] gauges.c:293: Warning: signed overflow. assert j + 1 ≤ 2147483647;
-336c300
+332c296
 <   Frama_C_show_each: {-593; -592; -591; -590; -589; -588}, [0..2147483647]
 ---
 >   Frama_C_show_each: {-593; -592; -591; -590; -589; -588}, [99..119]
-398a363,366
+394a359,362
 >   # gauges:
 >   V: [{[ p -> {{ &x }}
 >          i -> {1} ]}]
 >   s398: λ(0)
-458a427,430
+454a423,426
 >   # gauges:
 >   V: [{[ i -> {1} ]}]
 >   s398: λ([0 .. 1])
 >         {[ i -> {1} ]}
-517a490,493
+513a486,489
 >   # gauges:
 >   V: [{[ i -> {1} ]}]
 >   s398: λ([0 .. 2])
 >         {[ i -> {1} ]}
-576a553,556
+572a549,552
 >   # gauges:
 >   V: [{[ i -> {1} ]}]
 >   s398: λ([0 .. 10])
 >         {[ i -> {1} ]}
-641a622,626
+637a618,622
 >   # gauges:
 >   V: [{[ p -> {{ &a }}
 >          i -> {2} ]}]
 >   s412: λ(0)
 >   s411: λ(0)
-702a688,692
+698a684,688
 >   # gauges:
 >   V: [{[ i -> {2} ]}]
 >   s412: λ(0)
 >   s411: λ([0 .. 1])
 >         {[ i -> {0} ]}
-704a695,822
+700a691,818
 > [eva] gauges.c:325: 
 >   Frama_C_dump_each:
 >   # cvalue:
@@ -258,9 +258,13 @@
 >   s411: λ([0 .. +oo])
 >         {[ i -> {0} ]}
 >   ==END OF DUMP==
-712a831,832
+708a827,828
 > [eva] gauges.c:343: Call to builtin malloc
 > [eva] gauges.c:343: Call to builtin malloc
+716c836
+<       (read 14 times, propagated 12 times) garbled mix of &{x; y}
+---
+>       (read 12 times, propagated 11 times) garbled mix of &{x; y}
 765,766c885,886
 <   A ∈ {{ &A + [0..--],0%4 }}
 <   B ∈ {{ &B + [0..--],0%4 }}
diff --git a/tests/value/oracle_gauges/va_list2.0.res.oracle b/tests/value/oracle_gauges/va_list2.0.res.oracle
index 028514ddc800f41a22034f68671bf0c604ea9734..70defd3cb22fe585b3ac25d1cbc4a5509d95456b 100644
--- a/tests/value/oracle_gauges/va_list2.0.res.oracle
+++ b/tests/value/oracle_gauges/va_list2.0.res.oracle
@@ -1,4 +1,4 @@
-48a49,60
+36a37,48
 > [eva] va_list2.c:16: 
 >   Frama_C_show_each_i:
 >   {{ garbled mix of &{S_0_S___va_params; S_1_S___va_params} (origin: Well) }}
@@ -11,3 +11,7 @@
 > [eva] va_list2.c:21: 
 >   Frama_C_show_each_f:
 >   {{ garbled mix of &{S_0_S___va_params; S_1_S___va_params} (origin: Well) }}
+41c53
+<     Initial state (read 24 times, propagated 10 times)
+---
+>     Initial state (read 36 times, propagated 16 times)
diff --git a/tests/value/oracle_octagon/assigns.res.oracle b/tests/value/oracle_octagon/assigns.res.oracle
index 0f5f7cdfe8d3e4b52e991076bcc82bf5bf9d9539..f423e4eb8cc93ea8dd508d87d6f093838268f3b4 100644
--- a/tests/value/oracle_octagon/assigns.res.oracle
+++ b/tests/value/oracle_octagon/assigns.res.oracle
@@ -1,6 +1,6 @@
-149,150d148
+154,155d153
 <   more than 200(1000) locations to update in array. Approximating.
 < [kernel] assigns.i:104: 
-151a150,151
+156a155,156
 > [kernel] assigns.i:104: 
 >   more than 200(1000) locations to update in array. Approximating.
diff --git a/tests/value/oracle_octagon/bitfield.res.oracle b/tests/value/oracle_octagon/bitfield.res.oracle
index 9886a5a3b66d5f82e84afc4a5a3b268b67994a12..d8fa5662f8993ea18aae6c740069a2253c9740e2 100644
--- a/tests/value/oracle_octagon/bitfield.res.oracle
+++ b/tests/value/oracle_octagon/bitfield.res.oracle
@@ -1,4 +1,8 @@
 137a138,140
 > [eva] bitfield.i:71: 
 >   Frama_C_show_each:
->   {{ garbled mix of &{b} (origin: Misaligned {bitfield.i:70}) }}
+>   {{ garbled mix of &{b} (origin: Misaligned read {bitfield.i:70}) }}
+213c216
+<       (read 5 times, propagated 7 times) garbled mix of &{b; ee}
+---
+>       (read 6 times, propagated 7 times) garbled mix of &{b; ee}
diff --git a/tests/value/oracle_octagon/gauges.res.oracle b/tests/value/oracle_octagon/gauges.res.oracle
index a5e47e28258fe4726d31ff83cb80079321750697..1b2c6b235548585fb2d4218526d8c76fbed82258 100644
--- a/tests/value/oracle_octagon/gauges.res.oracle
+++ b/tests/value/oracle_octagon/gauges.res.oracle
@@ -1,7 +1,7 @@
-259,260d258
+255,256d254
 < [eva:alarm] gauges.c:201: Warning: 
 <   signed overflow. assert -2147483648 ≤ numNonZero - 1;
-282,286d279
+278,282d275
 < [eva] gauges.c:218: Frama_C_show_each:
 < [eva] gauges.c:218: Frama_C_show_each:
 < [eva] gauges.c:218: Frama_C_show_each:
diff --git a/tests/value/oracle_symblocs/assigns.res.oracle b/tests/value/oracle_symblocs/assigns.res.oracle
index 0f5f7cdfe8d3e4b52e991076bcc82bf5bf9d9539..f423e4eb8cc93ea8dd508d87d6f093838268f3b4 100644
--- a/tests/value/oracle_symblocs/assigns.res.oracle
+++ b/tests/value/oracle_symblocs/assigns.res.oracle
@@ -1,6 +1,6 @@
-149,150d148
+154,155d153
 <   more than 200(1000) locations to update in array. Approximating.
 < [kernel] assigns.i:104: 
-151a150,151
+156a155,156
 > [kernel] assigns.i:104: 
 >   more than 200(1000) locations to update in array. Approximating.
diff --git a/tests/value/oracle_symblocs/bitwise_pointer.0.res.oracle b/tests/value/oracle_symblocs/bitwise_pointer.0.res.oracle
index f04f7077977a5a61ea7d346c6ff6f90a2e4237e4..688b8e07ea0d94b9b3a3e8c2d26e5ff3a5a8f9e6 100644
--- a/tests/value/oracle_symblocs/bitwise_pointer.0.res.oracle
+++ b/tests/value/oracle_symblocs/bitwise_pointer.0.res.oracle
@@ -1,8 +1,8 @@
-62c62
+66c66
 <   x ∈ [0..9]
 ---
 >   x ∈ {5}
-75c75
+79c79
 <   x1 ∈ [0..9]
 ---
 >   x1 ∈ {5}
diff --git a/tests/value/oracle_symblocs/bitwise_pointer.1.res.oracle b/tests/value/oracle_symblocs/bitwise_pointer.1.res.oracle
index f04f7077977a5a61ea7d346c6ff6f90a2e4237e4..688b8e07ea0d94b9b3a3e8c2d26e5ff3a5a8f9e6 100644
--- a/tests/value/oracle_symblocs/bitwise_pointer.1.res.oracle
+++ b/tests/value/oracle_symblocs/bitwise_pointer.1.res.oracle
@@ -1,8 +1,8 @@
-62c62
+66c66
 <   x ∈ [0..9]
 ---
 >   x ∈ {5}
-75c75
+79c79
 <   x1 ∈ [0..9]
 ---
 >   x1 ∈ {5}
diff --git a/tools/hdrck/frama-c-hdrck.opam b/tools/hdrck/frama-c-hdrck.opam
index fec9d987234512e1d424a8d748714a8c00b55cee..019afc381da04856c7be0502bda0b5bdbafd86f4 100644
--- a/tools/hdrck/frama-c-hdrck.opam
+++ b/tools/hdrck/frama-c-hdrck.opam
@@ -1,7 +1,7 @@
 opam-version: "2.0"
 name: "frama-c-hdrck"
 synopsis: "Frama-C header check tool"
-version: "28.0"
+version: "28.1"
 description:"""
 Performs all checks related to file headers as required by the Frama-C
 continuous integration.
diff --git a/tools/lint/frama-c-lint.opam b/tools/lint/frama-c-lint.opam
index 69aff8dd9a434002f600ebfa3e72432ccc1cae84..cd26b633ec0524104b67329f536e448bd87f661c 100644
--- a/tools/lint/frama-c-lint.opam
+++ b/tools/lint/frama-c-lint.opam
@@ -1,7 +1,7 @@
 opam-version: "2.0"
 name: "frama-c-lint"
 synopsis: "Frama-C lint tool"
-version: "28.0"
+version: "28.1"
 description:"""
 Performs all checks related to source code formatting as required by the Frama-C
 continuous integration. Namely: OCP-indent for ML files, clang-format for E-ACSL