diff --git a/Changelog b/Changelog
index feb9fbd3b5f7370d162bd509f5fafbee17feb9d6..c46d534ad769b7d9bb0d1fb6c5b9d83edb7a1dc9 100644
--- a/Changelog
+++ b/Changelog
@@ -17,6 +17,10 @@
 Open Source Release <next-release>
 ##################################
 
+###################################
+Open Source Release 24.0 (Chromium)
+###################################
+
 -   Kernel    [2021-09-02] 0-sized flexible array members only available in
               gcc_* machdeps, that now also support FAM in nested struct.
 -   Eva       [2021-07-26] Removes the maximum limit of option -eva-ilevel.
diff --git a/Makefile b/Makefile
index a5f8daa3d76f371459e0586a27400b34d9037aee..fbcc54a8fb3c0966658a4a3e3b418e582244dd4b 100644
--- a/Makefile
+++ b/Makefile
@@ -894,11 +894,11 @@ PLUGIN_CMO:= partitioning/split_strategy domains/domain_mode value_parameters \
 	domains/cvalue/cvalue_transfer domains/cvalue/cvalue_init \
 	domains/cvalue/cvalue_specification \
 	domains/cvalue/cvalue_domain \
-	engine/subdivided_evaluation engine/evaluation engine/abstractions \
-	engine/recursion engine/transfer_stmt engine/transfer_specification \
 	partitioning/auto_loop_unroll \
 	partitioning/partition partitioning/partitioning_parameters \
 	partitioning/partitioning_index partitioning/trace_partitioning \
+	engine/subdivided_evaluation engine/evaluation engine/abstractions \
+	engine/recursion engine/transfer_stmt engine/transfer_specification \
 	engine/mem_exec engine/iterator engine/initialization \
 	engine/compute_functions engine/analysis register \
 	domains/taint_domain \
diff --git a/headers/header_spec.txt b/headers/header_spec.txt
index 95e9f72a6f9d21e5558b33525c9cf242887155e0..87f24681b2572e9ab46479914004e7934bc928e5 100644
--- a/headers/header_spec.txt
+++ b/headers/header_spec.txt
@@ -180,6 +180,7 @@ share/libc/__fc_define_clockid_t.h: CEA_LGPL
 share/libc/__fc_define_dev_t.h: CEA_LGPL
 share/libc/__fc_define_eof.h: CEA_LGPL
 share/libc/__fc_define_fd_set_t.h: CEA_LGPL
+share/libc/__fc_define_fds.h: CEA_LGPL
 share/libc/__fc_define_file.h: CEA_LGPL
 share/libc/__fc_define_fpos_t.h: CEA_LGPL
 share/libc/__fc_define_fs_cnt.h: CEA_LGPL
@@ -206,6 +207,7 @@ share/libc/__fc_define_suseconds_t.h: CEA_LGPL
 share/libc/__fc_define_time_t.h: CEA_LGPL
 share/libc/__fc_define_timer_t.h: CEA_LGPL
 share/libc/__fc_define_timespec.h: CEA_LGPL
+share/libc/__fc_define_timeval.h: CEA_LGPL
 share/libc/__fc_define_uid_and_gid.h: CEA_LGPL
 share/libc/__fc_define_useconds_t.h: CEA_LGPL
 share/libc/__fc_define_wchar_t.h: CEA_LGPL
diff --git a/share/Makefile.plugin.template b/share/Makefile.plugin.template
index ca77423063136672f4335cfd2192a467e2580977..9d10617bd82b958d477087115c17e3fd8583c11f 100644
--- a/share/Makefile.plugin.template
+++ b/share/Makefile.plugin.template
@@ -444,7 +444,7 @@ $(NAME_OFLAGS):=$(OFLAGS) $(INCLUDE_FLAGS) $(PLUGIN_OFLAGS)
 # DO NOT include the plugin's own directory as search path for compiling
 # ml test scripts: they will be loaded in a separate phase, and will only see
 # the plugin through its static API
-$(NAME_TEST_BFLAGS):= $(BFLAGS) -w -70 $(INCLUDE_EXT_FLAGS) $(PLUGIN_BFLAGS)
+$(NAME_TEST_BFLAGS):= $(BFLAGS) $(INCLUDE_EXT_FLAGS) $(PLUGIN_BFLAGS) -w -70
 $(NAME_TEST_OFLAGS):= $(OFLAGS) $(INCLUDE_EXT_FLAGS) $(PLUGIN_OFLAGS)
 
 $(TARGET_BFLAGS):= $(PLUGIN_LINK_BFLAGS)
diff --git a/share/analysis-scripts/make_wrapper.py b/share/analysis-scripts/make_wrapper.py
index 2fa09b4071263c4e8a86aad0726fffee8da0a601..0ae1736eebe66d66ca052706a244501f4d6f643b 100755
--- a/share/analysis-scripts/make_wrapper.py
+++ b/share/analysis-scripts/make_wrapper.py
@@ -22,7 +22,7 @@
 #                                                                        #
 ##########################################################################
 
-# This script serves as wrapper to 'make' (when using the analysis-scripts
+# This script serves as wrapper to GNU make (when using the analysis-scripts
 # GNUmakefile template): it parses the output and suggests useful commands
 # whenever it can, by calling frama-c-script itself.
 
@@ -38,6 +38,16 @@ MIN_PYTHON = (3, 6) # for automatic Path conversions
 if sys.version_info < MIN_PYTHON:
     sys.exit("Python %s.%s or later is required.\n" % MIN_PYTHON)
 
+# Check if GNU make is available and has the minimal required version
+# (4.0). Otherwise, this script will fail.
+# We first test with 'gmake', then 'make', then fail.
+make_cmd = "gmake"
+get_make_major_version_args = r" --version | grep 'GNU Make\s\+\([0-9]\+\)\..*$' | sed -E 's|GNU Make +([0-9]+)\..*|\1|'"
+if os.system(f"test $({make_cmd} {get_make_major_version_args}) -ge 4") != 0:
+    make_cmd = "make"
+    if os.system(f"test $({make_cmd} {get_make_major_version_args}) -ge 4") != 0:
+        sys.exit("error: could not find GNU make >= 4.0 (tried 'gmake' and 'make')")
+
 parser = argparse.ArgumentParser(description="""
 Builds the specified target, parsing the output to identify and recommend
 actions in case of failure.""")
@@ -54,7 +64,7 @@ if not framac_bin:
 framac_script = f"{framac_bin}/frama-c-script"
 
 output_lines = []
-cmd_list = ['make', "-C", make_dir] + args
+cmd_list = [make_cmd, "-C", make_dir] + args
 with subprocess.Popen(cmd_list,
                       stdout=subprocess.PIPE,
                       stderr=subprocess.PIPE) as proc:
diff --git a/share/libc/__fc_define_fd_set_t.h b/share/libc/__fc_define_fd_set_t.h
index 5f9b7c721b2124a2158961a07c7db38eda5506e3..5e6bbe0272593c03712707a3966a0cd086f32250 100644
--- a/share/libc/__fc_define_fd_set_t.h
+++ b/share/libc/__fc_define_fd_set_t.h
@@ -29,40 +29,6 @@ __PUSH_FC_STDLIB
 __BEGIN_DECLS
 typedef struct __fc_fd_set { long __fc_fd_set[FD_SETSIZE / NFDBITS]; } fd_set;
 
-/*@
-  requires valid_fdset: \valid(fdset);
-  requires initialization: \initialized(fdset);
-  assigns *fdset \from *fdset, indirect:fd;
-*/
-extern void FD_CLR(int fd, fd_set *fdset);
-#define FD_CLR FD_CLR
-
-// Note: the 2nd argument in FD_ISSET is not const in some implementations
-// due to historical and compatibility reasons.
-/*@
-  requires valid_fdset: \valid_read(fdset);
-  requires initialization: \initialized(fdset);
-  assigns \result \from indirect:*fdset, indirect:fd;
-*/
-extern int FD_ISSET(int fd, const fd_set *fdset);
-#define FD_ISSET FD_ISSET
-
-/*@
-  requires valid_fdset: \valid(fdset);
-  requires initialization: \initialized(fdset);
-  assigns *fdset \from *fdset, indirect:fd;
-*/
-extern void FD_SET(int fd, fd_set *fdset);
-#define FD_SET FD_SET
-
-/*@
-  requires valid_fdset: \valid(fdset);
-  assigns *fdset \from \nothing;
-  ensures initialization: \initialized(fdset);
-*/
-extern void FD_ZERO(fd_set *fdset);
-#define FD_ZERO FD_ZERO
-
 __END_DECLS
 __POP_FC_STDLIB
 #endif
diff --git a/share/libc/__fc_define_fds.h b/share/libc/__fc_define_fds.h
new file mode 100644
index 0000000000000000000000000000000000000000..6905aad49acb612be5e77082bcd23d64356053a9
--- /dev/null
+++ b/share/libc/__fc_define_fds.h
@@ -0,0 +1,40 @@
+/**************************************************************************/
+/*                                                                        */
+/*  This file is part of Frama-C.                                         */
+/*                                                                        */
+/*  Copyright (C) 2007-2021                                               */
+/*    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).            */
+/*                                                                        */
+/**************************************************************************/
+
+#ifndef __FC_DEFINE_FDS
+#define __FC_DEFINE_FDS
+#include "features.h"
+__PUSH_FC_STDLIB
+__BEGIN_DECLS
+
+// arbitrary number
+#ifndef __FC_MAX_OPEN_FILES
+#define __FC_MAX_OPEN_FILES 1024
+#endif
+
+// __fc_fds represents the state of open file descriptors.
+extern volatile int __fc_fds[__FC_MAX_OPEN_FILES];
+
+__END_DECLS
+
+__POP_FC_STDLIB
+#endif
diff --git a/share/libc/__fc_define_timeval.h b/share/libc/__fc_define_timeval.h
new file mode 100644
index 0000000000000000000000000000000000000000..34db8894a582b2e7a28779182505194efadaed79
--- /dev/null
+++ b/share/libc/__fc_define_timeval.h
@@ -0,0 +1,36 @@
+/**************************************************************************/
+/*                                                                        */
+/*  This file is part of Frama-C.                                         */
+/*                                                                        */
+/*  Copyright (C) 2007-2021                                               */
+/*    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).            */
+/*                                                                        */
+/**************************************************************************/
+
+#ifndef __FC_DEFINE_TIMEVAL
+#define __FC_DEFINE_TIMEVAL
+#include "features.h"
+__PUSH_FC_STDLIB
+__BEGIN_DECLS
+#include "__fc_define_suseconds_t.h"
+#include "__fc_define_time_t.h"
+struct timeval {
+  time_t         tv_sec;
+  suseconds_t    tv_usec;
+};
+__END_DECLS
+__POP_FC_STDLIB
+#endif
diff --git a/share/libc/__fc_select.h b/share/libc/__fc_select.h
index 4fc0f3b0aa6e161a24d6daefa686adb5e5223392..1fad5956e876ce077f8db6bfccda7db5ddd8c7d4 100644
--- a/share/libc/__fc_select.h
+++ b/share/libc/__fc_select.h
@@ -24,13 +24,11 @@
 #define __FC_SELECT__
 #include "features.h"
 __PUSH_FC_STDLIB
-#include "__fc_define_time_t.h"
-#include "__fc_define_suseconds_t.h"
 #include "__fc_define_fd_set_t.h"
 #include "__fc_define_sigset_t.h"
-
-#include "sys/time.h"
-
+#include "__fc_define_suseconds_t.h"
+#include "__fc_define_timeval.h"
+#include "__fc_define_timespec.h"
 __BEGIN_DECLS
 
 /* assigns \result \from nfds, *readfds, *writefds,*errorfds,*timeout,*sigmask;
diff --git a/share/libc/getopt.h b/share/libc/getopt.h
index ed3f45384b71e51ed761a1e0d67c7f38462eb608..380abc7f5aba56b890fa82bd197dbce6e5acead3 100644
--- a/share/libc/getopt.h
+++ b/share/libc/getopt.h
@@ -24,10 +24,9 @@
 #define __FC_GETOPT_H
 #include "features.h"
 __PUSH_FC_STDLIB
-
+#include "unistd.h"
 __BEGIN_DECLS
 
-#include "unistd.h"
 
 /* GNU specific */
 struct option
diff --git a/share/libc/limits.h b/share/libc/limits.h
index be32d497acd2883f59ef9096978290932287fc37..7c19508f17883e2954384f61b9d79f6ca228440a 100644
--- a/share/libc/limits.h
+++ b/share/libc/limits.h
@@ -95,4 +95,9 @@
  */
 #define ARG_MAX 4096
 
+// POSIX; used by <sys/uio.h>.
+// Must be >= _XOPEN_IOV_MAX, which is 16.
+// 1024 is the value used by some Linux implementations.
+#define IOV_MAX 1024
+
 #endif
diff --git a/share/libc/sys/select.h b/share/libc/sys/select.h
index c680c04d2e2ec48a879ee4b74dccc8468abfbdd2..d3ceb4b58487f35543d5c5fdf13ec56deea00c6a 100644
--- a/share/libc/sys/select.h
+++ b/share/libc/sys/select.h
@@ -28,6 +28,40 @@ __BEGIN_DECLS
 
 #include "../__fc_select.h"
 
+/*@
+  requires valid_fdset: \valid(fdset);
+  requires initialization: \initialized(fdset);
+  assigns *fdset \from *fdset, indirect:fd;
+*/
+extern void FD_CLR(int fd, fd_set *fdset);
+#define FD_CLR FD_CLR
+
+// Note: the 2nd argument in FD_ISSET is not const in some implementations
+// due to historical and compatibility reasons.
+/*@
+  requires valid_fdset: \valid_read(fdset);
+  requires initialization: \initialized(fdset);
+  assigns \result \from indirect:*fdset, indirect:fd;
+*/
+extern int FD_ISSET(int fd, const fd_set *fdset);
+#define FD_ISSET FD_ISSET
+
+/*@
+  requires valid_fdset: \valid(fdset);
+  requires initialization: \initialized(fdset);
+  assigns *fdset \from *fdset, indirect:fd;
+*/
+extern void FD_SET(int fd, fd_set *fdset);
+#define FD_SET FD_SET
+
+/*@
+  requires valid_fdset: \valid(fdset);
+  assigns *fdset \from \nothing;
+  ensures initialization: \initialized(fdset);
+*/
+extern void FD_ZERO(fd_set *fdset);
+#define FD_ZERO FD_ZERO
+
 __END_DECLS
 __POP_FC_STDLIB
 #endif
diff --git a/share/libc/sys/time.h b/share/libc/sys/time.h
index fbd3da31927d47879bb7ef0c81bf878ba4b5fbc7..db0a5b17b0b5ce5a9eaac4e983ac9bdd0eb45abd 100644
--- a/share/libc/sys/time.h
+++ b/share/libc/sys/time.h
@@ -24,17 +24,12 @@
 #define __FC_SYS_TIME_H__
 #include "../features.h"
 __PUSH_FC_STDLIB
-__BEGIN_DECLS
-
-#include "../__fc_define_time_t.h"
-#include "../__fc_define_suseconds_t.h"
 #include "../__fc_define_fd_set_t.h"
-#include "../__fc_define_timespec.h"
+#include "../__fc_define_suseconds_t.h"
+#include "../__fc_define_time_t.h"
+#include "../__fc_define_timeval.h"
 #include "../__fc_string_axiomatic.h"
-struct timeval {
-  time_t         tv_sec;
-  suseconds_t    tv_usec;
-};
+__BEGIN_DECLS
 
 struct timezone {
   int tz_minuteswest;
diff --git a/share/libc/sys/uio.h b/share/libc/sys/uio.h
index 7ef6ce26a73b7c58c36a3413b228658349faa9ff..b46a65c70647568e1d8dd517c2be12e83bd64bc7 100644
--- a/share/libc/sys/uio.h
+++ b/share/libc/sys/uio.h
@@ -28,15 +28,49 @@ __PUSH_FC_STDLIB
 #include "../__fc_define_ssize_t.h"
 #include "../__fc_define_size_t.h"
 #include "../__fc_define_iovec.h"
+#include "../__fc_define_fds.h"
+#include "../limits.h"
 
 __BEGIN_DECLS
 
-/*@ requires valid_read_iov: \valid_read( &iov[0..iovcnt-1] );
-// Value cannot yet interpret the precise assigns clause; we use the weaker one as a fallback.
-//@ assigns { ((char *) iov[i].iov_base)[0..iov[i].iov_len - 1] | integer i; 0 <= i < iovcnt };
-  @ assigns   ((char *) iov[0..iovcnt -1].iov_base)[0..];
+
+
+/*@
+  requires valid_fd: 0 <= fd < __FC_MAX_OPEN_FILES;
+  requires initialization:initialized_inputs:
+    \forall integer i; 0 <= i < iovcnt ==>
+      \initialized(&iov[i].iov_base) && \initialized(&iov[i].iov_len);
+  requires valid_iov: \forall integer i; 0 <= i < iovcnt ==>
+    \valid( ((char*)&iov[i].iov_base)+(0 .. iov[i].iov_len-1));
+  requires bounded_iovcnt: 0 <= iovcnt <= IOV_MAX;
+  assigns { ((char*)iov[i].iov_base)[j] |
+            integer i, j; 0 <= i < iovcnt && 0 <= j < iov[i].iov_len }
+    \from indirect:fd, indirect:iovcnt, indirect:__fc_fds[fd];
+  assigns \result \from indirect:fd, indirect:__fc_fds[fd], indirect:iov[0 ..],
+                        indirect:iovcnt;
+  ensures result_error_or_read_bytes: \result == -1 ||
+            0 <= \result <= \sum(0,iovcnt-1, \lambda integer k; iov[k].iov_len);
  */
 extern ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
+
+/*@
+  requires valid_fd: 0 <= fd < __FC_MAX_OPEN_FILES;
+  requires initialization:initialized_inputs:
+    \forall integer i; 0 <= i < iovcnt ==>
+      \initialized(&iov[i].iov_base) && \initialized(&iov[i].iov_len);
+  requires valid_read_iov: \valid_read(&iov[0 .. iovcnt-1]);
+  requires valid_read_iov_bases:
+    \forall integer i; 0 <= i < iovcnt ==>
+      \valid_read(((char*)iov[i].iov_base) + (0 .. iov[i].iov_len-1));
+  requires bounded_iovcnt: 0 <= iovcnt <= IOV_MAX;
+  requires bounded_lengths:
+     \sum(0, iovcnt-1, \lambda integer k; iov[k].iov_len) <= SSIZE_MAX;
+  assigns \result \from indirect:fd, indirect:__fc_fds[fd], indirect:iov[0 ..],
+                        indirect:iovcnt;
+  assigns __fc_fds[fd] \from indirect:iov[0 ..], indirect:iovcnt;
+  ensures result_error_or_written_bytes: \result == -1 ||
+          0 <= \result <= \sum(0, iovcnt-1, \lambda integer k; iov[k].iov_len);
+ */
 extern ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
 
 __END_DECLS
diff --git a/share/libc/time.h b/share/libc/time.h
index d156b59c620e759c9709a9b8da294049b57e0476..fe6304ce88d58490ddb41494e6608c6ffed332b0 100644
--- a/share/libc/time.h
+++ b/share/libc/time.h
@@ -24,14 +24,16 @@
 #define __FC_TIME_H
 #include "features.h"
 __PUSH_FC_STDLIB
+#include "__fc_define_clockid_t.h"
 #include "__fc_define_null.h"
 #include "__fc_define_size_t.h"
-#include "__fc_define_clockid_t.h"
+#include "__fc_define_time_t.h"
 #include "__fc_define_timer_t.h"
+#include "__fc_define_timespec.h"
 #include "__fc_string_axiomatic.h"
-
 #include "errno.h"
 #include "signal.h"
+
 /*
  * Names of the interval timers, and structure
  * defining a timer setting:
@@ -47,7 +49,6 @@ __BEGIN_DECLS
 typedef unsigned int clock_t;
 #define __clock_t_defined
 #endif
-#include "__fc_define_time_t.h"
 // From POSIX.1-2008: "The value of CLOCKS_PER_SEC shall be 1 million on
 // XSI-conformant systems. [...]"
 #define CLOCKS_PER_SEC ((time_t)1000000)
@@ -64,8 +65,6 @@ struct tm {
   int tm_isdst; // Daylight Saving Time flag
 };
 
-#include "__fc_define_timespec.h"
-
 struct itimerspec {
   struct timespec  it_interval;
   struct timespec  it_value;
diff --git a/share/libc/unistd.h b/share/libc/unistd.h
index a8c71c4da66bfde812e77250d56ab9b6192509b8..5979b51c4d998f8883c3d332861a36a51cd86688 100644
--- a/share/libc/unistd.h
+++ b/share/libc/unistd.h
@@ -29,16 +29,16 @@ __PUSH_FC_STDLIB
 #include "__fc_define_max_open_files.h"
 #include "__fc_define_size_t.h"
 #include "__fc_define_null.h"
+#include "__fc_define_seek_macros.h"
 #include "__fc_define_ssize_t.h"
 #include "__fc_define_uid_and_gid.h"
 #include "__fc_define_off_t.h"
 #include "__fc_define_pid_t.h"
 #include "__fc_define_useconds_t.h"
 #include "__fc_define_intptr_t.h"
-
-
-
+#include "__fc_define_fds.h"
 #include "limits.h"
+__BEGIN_DECLS
 
 extern volatile int Frama_C_entropy_source;
 
@@ -54,8 +54,6 @@ extern volatile int Frama_C_entropy_source;
 #define	STDOUT_FILENO	1	/* Standard output.  */
 #define	STDERR_FILENO	2	/* Standard error output.  */
 
-#include "__fc_define_seek_macros.h"
-
 /* compatibility macros */
 
 #ifndef __FC_NO_MONOTONIC_CLOCK
@@ -66,8 +64,6 @@ extern volatile int Frama_C_entropy_source;
 #define _POSIX_MONOTONIC_CLOCK 0
 #endif
 
-__BEGIN_DECLS
-
 /* Values for the NAME argument to `pathconf' and `fpathconf'.  */
 enum __fc_pathconf_name
   {
@@ -722,16 +718,6 @@ enum __fc_confstr_name
 #define _CS_V7_ENV			_CS_V7_ENV
   };
 
-
-// arbitrary number
-#define __FC_MAX_OPEN_FILES 1024
-
-// __fc_fds represents the state of open file descriptors.
-//@ ghost int __fc_fds[__FC_MAX_OPEN_FILES];
-// TODO: Model the state of some functions more precisely.
-// TODO: define __fc_fds as volatile.
-
-
 /*@ // missing: may assign to errno: EACCES, ELOOP, ENAMETOOLONG, ENOENT,
     //                               ENOTDIR, EROFS, ETXTBSY
     //                               (EINVAL prevented by precondition)
diff --git a/src/kernel_services/analysis/interpreted_automata.ml b/src/kernel_services/analysis/interpreted_automata.ml
index d5fa853278e19b22221722a1c0f9ea1304cb2c28..5fe9660ff361769705090186ba8aaec7dd5486e7 100644
--- a/src/kernel_services/analysis/interpreted_automata.ml
+++ b/src/kernel_services/analysis/interpreted_automata.ml
@@ -594,6 +594,27 @@ let build_automaton ~annotations kf =
   in
   G.iter_edges_e bind_labels g;
 
+  (* Recursively removes unreachable vertices, except those bound to a statement
+     in [table]. *)
+  let stmt_vertices =
+    let add _stmt (v1, v2) acc = Vertex.Set.(add v1 (add v2 acc)) in
+    StmtTable.fold add table Vertex.Set.empty
+  in
+  let is_unreachable vertex =
+    G.in_degree g vertex = 0
+    && not (Vertex.equal vertex entry_point)
+    && not (Vertex.Set.mem vertex stmt_vertices)
+  in
+  let rec remove_unreachable vertex =
+    let succs = G.succ g vertex in
+    G.remove_vertex g vertex;
+    List.iter remove_unreachable (List.filter is_unreachable succs)
+  in
+  let unreachables =
+    G.fold_vertex (fun v l -> if is_unreachable v then v :: l else l)  g []
+  in
+  List.iter remove_unreachable unreachables;
+
   (* Return the result *)
   {graph = g; entry_point; return_point; stmt_table = table}
 
diff --git a/src/plugins/aorai/tests/Aorai_test.mli b/src/plugins/aorai/tests/Aorai_test.mli
deleted file mode 100644
index 93dd0917c8512b2e33b4b288d70faf3435badb4a..0000000000000000000000000000000000000000
--- a/src/plugins/aorai/tests/Aorai_test.mli
+++ /dev/null
@@ -1 +0,0 @@
-(* Nothing is exported. *)
diff --git a/src/plugins/aorai/tests/ya/name_projects.mli b/src/plugins/aorai/tests/ya/name_projects.mli
deleted file mode 100644
index 257f4adfc7668a67011f2f6a5043a211ae5b882a..0000000000000000000000000000000000000000
--- a/src/plugins/aorai/tests/ya/name_projects.mli
+++ /dev/null
@@ -1 +0,0 @@
-(* nothing is exported. *)
diff --git a/src/plugins/e-acsl/tests/builtin/oracle/gen_strcat.c b/src/plugins/e-acsl/tests/builtin/oracle/gen_strcat.c
index 1a7afd5bee9eaa585b2e079469cfdabf548079f3..313fcf00ef198538e9a90fa4e936f8e944731937 100644
--- a/src/plugins/e-acsl/tests/builtin/oracle/gen_strcat.c
+++ b/src/plugins/e-acsl/tests/builtin/oracle/gen_strcat.c
@@ -342,7 +342,7 @@ pid_t __gen_e_acsl_fork(void)
     else __gen_e_acsl_or_2 = __retres == -1;
     __e_acsl_assert(__gen_e_acsl_or_2,1,"Postcondition","fork",
                     "result_ok_child_or_error: \\result == 0 || \\result > 0 || \\result == -1",
-                    "FRAMAC_SHARE/libc/unistd.h",860);
+                    "FRAMAC_SHARE/libc/unistd.h",846);
     return __retres;
   }
 }
diff --git a/src/plugins/e-acsl/tests/builtin/oracle/gen_strcmp.c b/src/plugins/e-acsl/tests/builtin/oracle/gen_strcmp.c
index 487f9d89b834415fa5940e86bf8bd1822b28bedc..cb77e05860c921f2af86471a47a16fd3556fad20 100644
--- a/src/plugins/e-acsl/tests/builtin/oracle/gen_strcmp.c
+++ b/src/plugins/e-acsl/tests/builtin/oracle/gen_strcmp.c
@@ -187,7 +187,7 @@ pid_t __gen_e_acsl_fork(void)
     else __gen_e_acsl_or_2 = __retres == -1;
     __e_acsl_assert(__gen_e_acsl_or_2,1,"Postcondition","fork",
                     "result_ok_child_or_error: \\result == 0 || \\result > 0 || \\result == -1",
-                    "FRAMAC_SHARE/libc/unistd.h",860);
+                    "FRAMAC_SHARE/libc/unistd.h",846);
     return __retres;
   }
 }
diff --git a/src/plugins/e-acsl/tests/builtin/oracle/gen_strcpy.c b/src/plugins/e-acsl/tests/builtin/oracle/gen_strcpy.c
index 2e37d64c5d53416ced6c10ada81782b526bf3fb9..bb72f2bbc63f1b9bba44621ad6fa764bf561cf00 100644
--- a/src/plugins/e-acsl/tests/builtin/oracle/gen_strcpy.c
+++ b/src/plugins/e-acsl/tests/builtin/oracle/gen_strcpy.c
@@ -366,7 +366,7 @@ pid_t __gen_e_acsl_fork(void)
     else __gen_e_acsl_or_2 = __retres == -1;
     __e_acsl_assert(__gen_e_acsl_or_2,1,"Postcondition","fork",
                     "result_ok_child_or_error: \\result == 0 || \\result > 0 || \\result == -1",
-                    "FRAMAC_SHARE/libc/unistd.h",860);
+                    "FRAMAC_SHARE/libc/unistd.h",846);
     return __retres;
   }
 }
diff --git a/src/plugins/e-acsl/tests/builtin/oracle/gen_strlen.c b/src/plugins/e-acsl/tests/builtin/oracle/gen_strlen.c
index 44170551c065847fe09d7c0e1cebbfc1f4e0d11b..5288ad885239b257ee03115041beef1d1b10e5e5 100644
--- a/src/plugins/e-acsl/tests/builtin/oracle/gen_strlen.c
+++ b/src/plugins/e-acsl/tests/builtin/oracle/gen_strlen.c
@@ -161,7 +161,7 @@ pid_t __gen_e_acsl_fork(void)
     else __gen_e_acsl_or_2 = __retres == -1;
     __e_acsl_assert(__gen_e_acsl_or_2,1,"Postcondition","fork",
                     "result_ok_child_or_error: \\result == 0 || \\result > 0 || \\result == -1",
-                    "FRAMAC_SHARE/libc/unistd.h",860);
+                    "FRAMAC_SHARE/libc/unistd.h",846);
     return __retres;
   }
 }
diff --git a/src/plugins/e-acsl/tests/builtin/oracle/strcat.res.oracle b/src/plugins/e-acsl/tests/builtin/oracle/strcat.res.oracle
index e5596bda75141d559c531b4d72aeb27b6bf732cd..355bf7bb1f029994a75c785588cf61c82170aeb9 100644
--- a/src/plugins/e-acsl/tests/builtin/oracle/strcat.res.oracle
+++ b/src/plugins/e-acsl/tests/builtin/oracle/strcat.res.oracle
@@ -8,7 +8,7 @@
 [e-acsl] Warning: annotating undefined function `fork':
   the generated program may miss memory instrumentation
   if there are memory-related annotations.
-[e-acsl] FRAMAC_SHARE/libc/unistd.h:857: Warning: 
+[e-acsl] FRAMAC_SHARE/libc/unistd.h:843: Warning: 
   E-ACSL construct `assigns clause in behavior' is not yet supported.
   Ignoring annotation.
 [e-acsl] FRAMAC_SHARE/libc/sys/wait.h:79: Warning: 
diff --git a/src/plugins/e-acsl/tests/builtin/oracle/strcmp.res.oracle b/src/plugins/e-acsl/tests/builtin/oracle/strcmp.res.oracle
index 077e7e1b7111003c5ae82c748c084ea16eaf0819..62a192f51bb497bafc4593371ad9b0a29aa1e3ef 100644
--- a/src/plugins/e-acsl/tests/builtin/oracle/strcmp.res.oracle
+++ b/src/plugins/e-acsl/tests/builtin/oracle/strcmp.res.oracle
@@ -66,7 +66,7 @@
 [e-acsl] FRAMAC_SHARE/libc/string.h:493: Warning: 
   E-ACSL construct `assigns clause in behavior' is not yet supported.
   Ignoring annotation.
-[e-acsl] FRAMAC_SHARE/libc/unistd.h:857: Warning: 
+[e-acsl] FRAMAC_SHARE/libc/unistd.h:843: Warning: 
   E-ACSL construct `assigns clause in behavior' is not yet supported.
   Ignoring annotation.
 [e-acsl] FRAMAC_SHARE/libc/sys/wait.h:79: Warning: 
diff --git a/src/plugins/e-acsl/tests/builtin/oracle/strcpy.res.oracle b/src/plugins/e-acsl/tests/builtin/oracle/strcpy.res.oracle
index 406978ac5f39a280b111b1dc00a11a06c240af64..6d74b78c4afc235b980f246374e40a7ed1a19c5c 100644
--- a/src/plugins/e-acsl/tests/builtin/oracle/strcpy.res.oracle
+++ b/src/plugins/e-acsl/tests/builtin/oracle/strcpy.res.oracle
@@ -60,7 +60,7 @@
 [e-acsl] FRAMAC_SHARE/libc/string.h:493: Warning: 
   E-ACSL construct `assigns clause in behavior' is not yet supported.
   Ignoring annotation.
-[e-acsl] FRAMAC_SHARE/libc/unistd.h:857: Warning: 
+[e-acsl] FRAMAC_SHARE/libc/unistd.h:843: Warning: 
   E-ACSL construct `assigns clause in behavior' is not yet supported.
   Ignoring annotation.
 [e-acsl] FRAMAC_SHARE/libc/sys/wait.h:79: Warning: 
diff --git a/src/plugins/e-acsl/tests/builtin/oracle/strlen.res.oracle b/src/plugins/e-acsl/tests/builtin/oracle/strlen.res.oracle
index b1e0c13ab7c0c81ddca966a75862fbafdb2ce343..2a293aeb5a71df9b7843ceaf791a0bc6ab4ed61f 100644
--- a/src/plugins/e-acsl/tests/builtin/oracle/strlen.res.oracle
+++ b/src/plugins/e-acsl/tests/builtin/oracle/strlen.res.oracle
@@ -63,7 +63,7 @@
 [e-acsl] FRAMAC_SHARE/libc/string.h:493: Warning: 
   E-ACSL construct `assigns clause in behavior' is not yet supported.
   Ignoring annotation.
-[e-acsl] FRAMAC_SHARE/libc/unistd.h:857: Warning: 
+[e-acsl] FRAMAC_SHARE/libc/unistd.h:843: Warning: 
   E-ACSL construct `assigns clause in behavior' is not yet supported.
   Ignoring annotation.
 [e-acsl] FRAMAC_SHARE/libc/sys/wait.h:79: Warning: 
diff --git a/src/plugins/e-acsl/tests/format/oracle/fprintf.res.oracle b/src/plugins/e-acsl/tests/format/oracle/fprintf.res.oracle
index 2ce7032a3b70da634ea4cb3411354f33cc617c46..665e3c0b1cc2ecddafda0d677d2f1f1a72337ef9 100644
--- a/src/plugins/e-acsl/tests/format/oracle/fprintf.res.oracle
+++ b/src/plugins/e-acsl/tests/format/oracle/fprintf.res.oracle
@@ -19,7 +19,7 @@
   `logic functions or predicates with no definition nor reads clause'
   is not yet supported.
   Ignoring annotation.
-[e-acsl] FRAMAC_SHARE/libc/unistd.h:857: Warning: 
+[e-acsl] FRAMAC_SHARE/libc/unistd.h:843: Warning: 
   E-ACSL construct `assigns clause in behavior' is not yet supported.
   Ignoring annotation.
 [e-acsl] FRAMAC_SHARE/libc/sys/wait.h:79: Warning: 
diff --git a/src/plugins/e-acsl/tests/format/oracle/gen_fprintf.c b/src/plugins/e-acsl/tests/format/oracle/gen_fprintf.c
index 0fb3e03f963f1ca84c2d99208f7a971bf4e3ab08..09a3554adf54d4a676e021dc16c0d7fb3e087768 100644
--- a/src/plugins/e-acsl/tests/format/oracle/gen_fprintf.c
+++ b/src/plugins/e-acsl/tests/format/oracle/gen_fprintf.c
@@ -110,7 +110,7 @@ pid_t __gen_e_acsl_fork(void)
     else __gen_e_acsl_or_2 = __retres == -1;
     __e_acsl_assert(__gen_e_acsl_or_2,1,"Postcondition","fork",
                     "result_ok_child_or_error: \\result == 0 || \\result > 0 || \\result == -1",
-                    "FRAMAC_SHARE/libc/unistd.h",860);
+                    "FRAMAC_SHARE/libc/unistd.h",846);
     return __retres;
   }
 }
diff --git a/src/plugins/e-acsl/tests/format/oracle/gen_printf.c b/src/plugins/e-acsl/tests/format/oracle/gen_printf.c
index 3db1acf837ee0515dc48f8c484b27563489afa38..a4f24c803d736d1fbbdf9803ba71b612cb937a6a 100644
--- a/src/plugins/e-acsl/tests/format/oracle/gen_printf.c
+++ b/src/plugins/e-acsl/tests/format/oracle/gen_printf.c
@@ -903,7 +903,7 @@ pid_t __gen_e_acsl_fork(void)
     else __gen_e_acsl_or_2 = __retres == -1;
     __e_acsl_assert(__gen_e_acsl_or_2,1,"Postcondition","fork",
                     "result_ok_child_or_error: \\result == 0 || \\result > 0 || \\result == -1",
-                    "FRAMAC_SHARE/libc/unistd.h",860);
+                    "FRAMAC_SHARE/libc/unistd.h",846);
     return __retres;
   }
 }
diff --git a/src/plugins/e-acsl/tests/format/oracle/printf.res.oracle b/src/plugins/e-acsl/tests/format/oracle/printf.res.oracle
index 98b179a6be2383e26aac0d389ef7972ac799ecac..b09140dee729c28a7f1f65cee93f96e57c0e5fdc 100644
--- a/src/plugins/e-acsl/tests/format/oracle/printf.res.oracle
+++ b/src/plugins/e-acsl/tests/format/oracle/printf.res.oracle
@@ -96,7 +96,7 @@
 [e-acsl] FRAMAC_SHARE/libc/string.h:141: Warning: 
   E-ACSL construct `assigns clause in behavior' is not yet supported.
   Ignoring annotation.
-[e-acsl] FRAMAC_SHARE/libc/unistd.h:857: Warning: 
+[e-acsl] FRAMAC_SHARE/libc/unistd.h:843: Warning: 
   E-ACSL construct `assigns clause in behavior' is not yet supported.
   Ignoring annotation.
 [e-acsl] FRAMAC_SHARE/libc/sys/wait.h:79: Warning: 
diff --git a/src/plugins/e-acsl/tests/print.mli b/src/plugins/e-acsl/tests/print.mli
deleted file mode 100644
index 9e846eed54c8875c271b1dd7eb248405cf485798..0000000000000000000000000000000000000000
--- a/src/plugins/e-acsl/tests/print.mli
+++ /dev/null
@@ -1,21 +0,0 @@
-(**************************************************************************)
-(*                                                                        *)
-(*  This file is part of the Frama-C's E-ACSL plug-in.                    *)
-(*                                                                        *)
-(*  Copyright (C) 2012-2020                                               *)
-(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
-(*         alternatives)                                                  *)
-(*                                                                        *)
-(*  you can redistribute it and/or modify it under the terms of the GNU   *)
-(*  Lesser General Public License as published by the Free Software       *)
-(*  Foundation, version 2.1.                                              *)
-(*                                                                        *)
-(*  It is distributed in the hope that it will be useful,                 *)
-(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
-(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
-(*  GNU Lesser General Public License for more details.                   *)
-(*                                                                        *)
-(*  See the GNU Lesser General Public License version 2.1                 *)
-(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
-(*                                                                        *)
-(**************************************************************************)
diff --git a/src/plugins/value/engine/compute_functions.ml b/src/plugins/value/engine/compute_functions.ml
index 5d0cf41b0baab78657e85110dd86b5c3bd2cae33..718da24a52985bef50b701c9ca5e90154106c37e 100644
--- a/src/plugins/value/engine/compute_functions.ml
+++ b/src/plugins/value/engine/compute_functions.ml
@@ -278,8 +278,8 @@ module Make (Abstract: Abstractions.Eva) = struct
 
   let join_states = function
     | [] -> `Bottom
-    | [state] -> `Value state
-    | s :: l  -> `Value (List.fold_left Abstract.Dom.join s l)
+    | (_k,s) :: l  ->
+      `Value (List.fold_left Abstract.Dom.join s (List.map snd l))
 
   let compute_call_or_builtin stmt call recursion state =
     match Builtins.find_builtin_override call.kf with
@@ -299,7 +299,7 @@ module Make (Abstract: Abstractions.Eva) = struct
         Spec.compute_using_specification ~warn:false kinstr call spec state
       in
       Locations.Location_Bytes.do_track_garbled_mix true;
-      let final_state = states >>- join_states in
+      let final_state = join_states states in
       let cvalue_state = Abstract.Dom.get_cvalue_or_top state in
       match final_state with
       | `Bottom ->
@@ -314,9 +314,10 @@ module Make (Abstract: Abstractions.Eva) = struct
           Builtins.apply_builtin builtin cvalue_call ~pre:cvalue_state ~post
         in
         let insert cvalue_state =
+          Partition.Key.empty,
           Abstract.Dom.set Cvalue_domain.State.key cvalue_state final_state
         in
-        let states = Bottom.bot_of_list (List.map insert cvalue_states) in
+        let states = List.map insert cvalue_states in
         Transfer.{states; cacheable; builtin=true}
 
   let compute_call =
@@ -344,8 +345,8 @@ module Make (Abstract: Abstractions.Eva) = struct
       let final_result =
         compute_using_spec_or_body Kglobal call None init_state
       in
-      let final_states = final_result.Transfer.states in
-      let final_state = PowersetDomain.(final_states >>-: of_list >>- join) in
+      let final_states = List.map snd (final_result.Transfer.states) in
+      let final_state = PowersetDomain.(final_states |> of_list |> join) in
       Value_util.pop_call_stack ();
       Value_parameters.feedback "done for function %a" Kernel_function.pretty kf;
       Abstract.Dom.Store.mark_as_computed ();
diff --git a/src/plugins/value/engine/iterator.ml b/src/plugins/value/engine/iterator.ml
index 933035419a65831bb45ff24fc2c41ae84fd27181..773be0b00ab90f64fae7ca4f1b72b32c17e62b67 100644
--- a/src/plugins/value/engine/iterator.ml
+++ b/src/plugins/value/engine/iterator.ml
@@ -95,12 +95,12 @@ module Make_Dataflow
 
   (* --- Abstract values storage --- *)
 
-  module Partition = Trace_partitioning.Make (Abstract) (AnalysisParam)
+  module Partitioning = Trace_partitioning.Make (Abstract) (AnalysisParam)
 
-  type store = Partition.store
-  type flow = Partition.flow
-  type tank = Partition.tank
-  type widening = Partition.widening
+  type store = Partitioning.store
+  type flow = Partitioning.flow
+  type tank = Partitioning.tank
+  type widening = Partitioning.widening
 
   type edge_info = {
     mutable fireable : bool (* Does any states survive the transition ? *)
@@ -141,9 +141,9 @@ module Make_Dataflow
     | `Value state -> state
 
   let initial_tank =
-    Partition.initial_tank (States.to_list initial_states)
+    Partitioning.initial_tank (States.to_list initial_states)
   let get_initial_flow () =
-    -1 (* Dummy edge id *), Partition.drain initial_tank
+    -1 (* Dummy edge id *), Partitioning.drain initial_tank
 
   let post_conditions = ref false
 
@@ -180,11 +180,11 @@ module Make_Dataflow
 
   (* Default (Initial) stores on vertex and edges *)
   let default_vertex_store (v : vertex) () : store =
-    Partition.empty_store ~stmt:v.vertex_start_of
+    Partitioning.empty_store ~stmt:v.vertex_start_of
   let default_vertex_widening (v : vertex) () : widening =
-    Partition.empty_widening ~stmt:v.vertex_start_of
+    Partitioning.empty_widening ~stmt:v.vertex_start_of
   let default_edge_tank () : tank * edge_info =
-    Partition.empty_tank (), { fireable = false }
+    Partitioning.empty_tank (), { fireable = false }
 
   (* Get the stores associated to a control point or edge *)
   let get_vertex_store (v : vertex) : store =
@@ -217,20 +217,24 @@ module Make_Dataflow
 
   (* --- Transfer functions application --- *)
 
+  type key = Partition.key
   type state = Domain.t
 
-  type transfer_function = state -> state list
+  type transfer_function = (key * state) -> (key * state) list
 
-  let id : transfer_function = fun x -> [x]
+  let id : transfer_function = fun (k,x) -> [(k,x)]
 
   (* Thse lifting function helps to uniformize the transfer functions to a
      common signature *)
 
   let lift (f : state -> state) : transfer_function =
-    fun x -> [f x]
+    fun (k,x) -> [(k,f x)]
 
   let lift' (f : state -> state or_bottom) : transfer_function =
-    fun x -> Bottom.to_list (f x)
+    fun (k,x) -> Bottom.to_list (f x >>-: fun y -> k,y)
+
+  let lift'' (f : state -> state list) : transfer_function =
+    fun (k,x) -> List.map (fun y -> k,y) (f x)
 
   let sequence (f1 : transfer_function) (f2 : transfer_function)
     : transfer_function =
@@ -269,14 +273,15 @@ module Make_Dataflow
     if vars = [] then id else lift (Domain.leave_scope kf vars)
 
   let transfer_call (stmt : stmt) (dest : lval option) (callee : exp)
-      (args : exp list) (state : state) : state list =
+      (args : exp list) (key, state : key * state) : (key * state) list =
     let result, call_cacheable =
       Transfer.call stmt dest callee args state
     in
     if call_cacheable = Eval.NoCacheCallers then
       (* Propagate info that the current call cannot be cached either *)
       cacheable := Eval.NoCacheCallers;
-    Bottom.list_of_bot result
+    (* Recombine callee partitioning keys with caller key *)
+    Partitioning.call_return ~caller:key result
 
   let transfer_instr (stmt : stmt) (instr : instr) : transfer_function =
     match instr with
@@ -289,13 +294,13 @@ module Make_Dataflow
       lift' transfer
     | Local_init (vi, ConsInit (f, args, k), loc) ->
       let kind = Abstract_domain.Local kf in
-      let as_func dest callee args _loc state =
+      let as_func dest callee args _loc (key, state) =
         (* This variable enters the scope too early, as it should
            be introduced after the call to [f] but before the assignment
            to [v]. This is currently not possible, at least without
            splitting Transfer.call in two. *)
         let state = Domain.enter_scope kind [vi] state in
-        transfer_call stmt dest callee args state
+        transfer_call stmt dest callee args (key, state)
       in
       Cil.treat_constructor_as_func as_func vi f args k loc
     | Set (dest, exp, _loc) ->
@@ -331,7 +336,7 @@ module Make_Dataflow
     (* Assign the return value *)
     and assign_retval =
       match return_exp with
-      | None -> id
+      | None -> fun state -> [state]
       | Some return_exp ->
         let vi_ret = Option.get (Library_functions.get_retres_vi kf) in
         let return_lval = Var vi_ret, NoOffset in
@@ -342,7 +347,7 @@ module Make_Dataflow
           let state' = Transfer.assign state kstmt return_lval return_exp in
           Bottom.to_list state'
     in
-    sequence check_postconditions assign_retval
+    sequence (lift'' check_postconditions) (lift'' assign_retval)
 
   let transfer_transition (t : vertex transition) : transfer_function =
     match t with
@@ -357,7 +362,8 @@ module Make_Dataflow
     | Leave (block) ->            transfer_leave block
     | Prop _ -> id (* Annotations are interpreted in [transfer_statement]. *)
 
-  let transfer_annotations (stmt : stmt) ~(record : bool) : transfer_function =
+  let transfer_annotations (stmt : stmt) ~(record : bool)
+    : state -> state list =
     let annots =
       (* We do not interpret annotations that come from statement contracts
          and everything previously emitted by Value (currently, alarms) *)
@@ -395,20 +401,20 @@ module Make_Dataflow
       (transition : vertex transition) (flow : flow) : flow =
     (* Split return *)
     let flow = match transition with
-      | Return (return_exp, _) -> Partition.split_return flow return_exp
+      | Return (return_exp, _) -> Partitioning.split_return flow return_exp
       | _ -> flow
     in
     (* Loop transitions *)
     let the_stmt v = Option.get v.vertex_start_of in
     let enter_loop f v =
-      let f = Partition.enter_loop f (the_stmt v) in
-      Partition.transfer (lift (Domain.enter_loop (the_stmt v))) f
+      let f = Partitioning.enter_loop f (the_stmt v) in
+      Partitioning.transfer (lift (Domain.enter_loop (the_stmt v))) f
     and leave_loop f v =
-      let f = Partition.leave_loop f (the_stmt v) in
-      Partition.transfer (lift (Domain.leave_loop (the_stmt v))) f
+      let f = Partitioning.leave_loop f (the_stmt v) in
+      Partitioning.transfer (lift (Domain.leave_loop (the_stmt v))) f
     and incr_loop_counter f v =
-      let f = Partition.next_loop_iteration f (the_stmt v) in
-      Partition.transfer (lift (Domain.incr_loop_counter (the_stmt v))) f
+      let f = Partitioning.next_loop_iteration f (the_stmt v) in
+      Partitioning.transfer (lift (Domain.incr_loop_counter (the_stmt v))) f
     in
     let loops_left, loops_entered =
       Interpreted_automata.get_wto_index_diff kf v1 v2
@@ -422,14 +428,14 @@ module Make_Dataflow
   let process_edge (v1,e,v2 : G.edge) : flow =
     let {edge_transition=transition; edge_kinstr=kinstr} = e in
     let tank,edge_info = get_edge_data e in
-    let flow = Partition.drain tank in
+    let flow = Partitioning.drain tank in
     Db.yield ();
     check_signals ();
     current_ki := kinstr;
     Cil.CurrentLoc.set e.edge_loc;
-    let flow = Partition.transfer (transfer_transition transition) flow in
+    let flow = Partitioning.transfer (transfer_transition transition) flow in
     let flow = process_partitioning_transitions v1 v2 transition flow in
-    if not (Partition.is_empty_flow flow) then
+    if not (Partitioning.is_empty_flow flow) then
       edge_info.fireable <- true;
     flow
 
@@ -439,7 +445,7 @@ module Make_Dataflow
 
   let call_statement_callbacks (stmt : stmt) (f : flow) : unit =
     (* TODO: apply on all domains. *)
-    let states = Partition.contents f in
+    let states = Partitioning.contents f in
     let cvalue_states = gather_cvalues states in
     Db.Value.Compute_Statement_Callbacks.apply
       (stmt, Value_util.call_stack (), cvalue_states)
@@ -457,36 +463,37 @@ module Make_Dataflow
     (* Get vertex store *)
     let store = get_vertex_store v in
     (* Join incoming s tates *)
-    let flow = Partition.join sources store in
+    let flow = Partitioning.join sources store in
     let flow =
       match v.vertex_start_of with
       | Some stmt ->
         (* Callbacks *)
         call_statement_callbacks stmt flow;
         (* Transfer function associated to the statement *)
-        Partition.transfer (transfer_statement stmt) flow
+        Partitioning.transfer (lift'' (transfer_statement stmt)) flow
       | _ -> flow
     in
     (* Widen if necessary *)
     let flow =
-      if widening && not (Partition.is_empty_flow flow) then begin
-        let flow = Partition.widen (get_vertex_widening v) flow in
+      if widening && not (Partitioning.is_empty_flow flow) then begin
+        let flow = Partitioning.widen (get_vertex_widening v) flow in
         (* Try to correct over-widenings *)
         let correct_over_widening stmt =
           (* Do *not* record the status after interpreting the annotation
              here. Possible unproven assertions have already been recorded
              when the assertion has been interpreted the first time higher
              in this function. *)
-          Partition.transfer (transfer_annotations stmt ~record:false) flow
+          Partitioning.transfer
+            (lift'' (transfer_annotations stmt ~record:false)) flow
         in
         Option.fold ~some:correct_over_widening ~none:flow v.vertex_start_of
       end else
         flow
     in
     (* Dispatch to successors *)
-    List.iter (fun into -> Partition.fill flow ~into) (get_succ_tanks v);
+    List.iter (fun into -> Partitioning.fill flow ~into) (get_succ_tanks v);
     (* Return whether the iterator should stop or not *)
-    Partition.is_empty_flow flow
+    Partitioning.is_empty_flow flow
 
   let process_vertex ?(widening : bool = false) (v : vertex) : bool =
     (* Process predecessors *)
@@ -509,7 +516,7 @@ module Make_Dataflow
     (* Try every possible successor *)
     let add_if_fireable (_,e,succ as edge) acc =
       let f = process_edge edge in
-      if Partition.is_empty_flow f
+      if Partitioning.is_empty_flow f
       then acc
       else (e.edge_key,f,succ) :: acc
     in
@@ -525,13 +532,13 @@ module Make_Dataflow
   let reset_component (vertex_list : vertex list) : unit =
     let reset_edge (_,e,_) =
       let t,_ = get_edge_data e in
-      Partition.reset_tank t
+      Partitioning.reset_tank t
     in
     let reset_vertex v =
       let s = get_vertex_store v
       and w = get_vertex_widening v in
-      Partition.reset_store s;
-      Partition.reset_widening w;
+      Partitioning.reset_store s;
+      Partitioning.reset_widening w;
       List.iter reset_edge (G.succ_e graph v)
     in
     List.iter reset_vertex vertex_list
@@ -547,7 +554,7 @@ module Make_Dataflow
          is especially useful for nested loops. *)
       if hierachical_convergence
       then reset_component (v :: Wto.flatten w)
-      else Partition.reset_widening_counter (get_vertex_widening v);
+      else Partitioning.reset_widening_counter (get_vertex_widening v);
       (* Iterate until convergence *)
       let iteration_count = ref 0 in
       while
@@ -578,7 +585,7 @@ module Make_Dataflow
   let mark_degeneration () =
     let f stmt (v,_) =
       let l = get_succ_tanks v in
-      if not (List.for_all Partition.is_empty_tank l) then
+      if not (List.for_all Partitioning.is_empty_tank l) then
         Value_util.DegenerationPoints.replace stmt false
     in
     StmtTable.iter f automaton.stmt_table;
@@ -594,7 +601,7 @@ module Make_Dataflow
     ignore (Logic.check_fct_postconditions kf active_behaviors Normal
               ~pre_state:initial_state ~post_states:States.empty ~result:None)
 
-  let compute () : state list or_bottom =
+  let compute () : (key * state) list =
     if interpreter_mode then
       simulate automaton.entry_point (get_initial_flow ())
     else begin
@@ -603,7 +610,7 @@ module Make_Dataflow
     end;
     if not !post_conditions then mark_postconds_as_true ();
     let final_store = get_vertex_store automaton.return_point in
-    Bottom.bot_of_list (Partition.expanded final_store)
+    Partitioning.expanded final_store
 
 
   (* --- Results conversion --- *)
@@ -664,7 +671,7 @@ module Make_Dataflow
       let merged_states = VertexTable.create control_point_count
       and get_smashed_store v =
         let store = get_vertex_store v in
-        Partition.smashed store
+        Partitioning.smashed store
       in
       fun ~all stmt (v : vertex) ->
         if all || is_instr stmt
@@ -685,8 +692,8 @@ module Make_Dataflow
     let unmerged_pre_cvalues = lazy
       (StmtTable.map (fun _stmt (v,_) ->
            let store = get_vertex_store v in
-           let states = Partition.expanded store in
-           List.map (fun x -> Domain.get_cvalue_or_top x) states)
+           let states = Partitioning.expanded store in
+           List.map (fun (_k,x) -> Domain.get_cvalue_or_top x) states)
           automaton.stmt_table)
     in
     let merged_pre_cvalues = lazy (lift_to_cvalues merged_pre_states)
@@ -772,12 +779,10 @@ module Computer
           Kernel_function.pretty kf;
       Dataflow.merge_results ();
       let f = Kernel_function.get_definition kf in
-      (match results with
-       | `Value (_::_) when Cil.hasAttribute "noreturn" f.svar.vattr ->
-         Value_util.warning_once_current
-           "function %a may terminate but has the noreturn attribute"
-           Kernel_function.pretty kf;
-       | _ -> ());
+      if Cil.hasAttribute "noreturn" f.svar.vattr && results <> [] then
+        Value_util.warning_once_current
+          "function %a may terminate but has the noreturn attribute"
+          Kernel_function.pretty kf;
       results, !Dataflow.cacheable
     in
     let cleanup () =
diff --git a/src/plugins/value/engine/iterator.mli b/src/plugins/value/engine/iterator.mli
index 163796d15e9f89c74a07ebdc070d07dbd5e92352..b76ecae19a4dfb7d01a4a1a431ab8f245f067dc7 100644
--- a/src/plugins/value/engine/iterator.mli
+++ b/src/plugins/value/engine/iterator.mli
@@ -21,7 +21,6 @@
 (**************************************************************************)
 
 open Cil_types
-open Eval
 
 (** Mark the analysis as aborted. It will be stopped at the next safe point *)
 val signal_abort: unit -> unit
@@ -46,7 +45,7 @@ module Computer
 
     val compute:
       kernel_function -> kinstr -> Abstract.Dom.t ->
-      Abstract.Dom.t list or_bottom * Eval.cacheable
+      (Partition.key * Abstract.Dom.t) list * Eval.cacheable
 
   end
 
diff --git a/src/plugins/value/engine/mem_exec.ml b/src/plugins/value/engine/mem_exec.ml
index 7a8e035182171a115ef14e51c0f8b27a4a4790e0..54c5d3f5e9fed0290d05a783a031fb9d0db34f70 100644
--- a/src/plugins/value/engine/mem_exec.ml
+++ b/src/plugins/value/engine/mem_exec.ml
@@ -53,7 +53,7 @@ module Make
 
   incr counter;
 
-  module CallOutput = Datatype.List (Domain)
+  module CallOutput = Datatype.List (Datatype.Pair (Partition.Key) (Domain))
 
   module StoredResult =
     Datatype.Triple
@@ -145,7 +145,7 @@ module Make
       else expand_inputs_with_relations (count - 1) kf expanded_bases state
 
   let store_computed_call kf input_state args
-      (call_result: Domain.t list Bottom.or_bottom) =
+      (call_result: (Partition.key * Domain.t) list) =
     match Transfer_stmt.current_kf_inout () with
     | None -> ()
     | Some inout ->
@@ -196,10 +196,8 @@ module Make
         let all_output_bases =
           Extlib.opt_fold Base.Hptset.add return_base all_output_bases
         in
-        let clear state = Domain.filter kf `Post all_output_bases state in
-        let call_result = match call_result with
-          | `Bottom -> []
-          | `Value list -> list
+        let clear (key,state) =
+          key, Domain.filter kf `Post all_output_bases state
         in
         let outputs = List.map clear call_result in
         let call_number = current_counter () in
@@ -248,7 +246,8 @@ module Make
           let bases, outputs, i = Domain.Hashtbl.find hstates st_filtered in
           (* We have found a previous execution, in which the outputs are
              [outputs]. Copy them in [state] and return this result. *)
-          let process output =
+          let process (key,output) =
+            key,
             Domain.reuse kf bases ~current_input:state ~previous_output:output
           in
           let outputs = List.map process outputs in
@@ -268,7 +267,7 @@ module Make
     | Not_found -> None
     | Result_found (outputs, i) ->
       let call_result = outputs in
-      Some (Bottom.bot_of_list call_result, i)
+      Some (call_result, i)
 
 end
 
diff --git a/src/plugins/value/engine/mem_exec.mli b/src/plugins/value/engine/mem_exec.mli
index afc29371ac5d18fcf22ff5951e266d3a33a63448..cb2a641032a00a2411246ebba9a16d8a0230b072 100644
--- a/src/plugins/value/engine/mem_exec.mli
+++ b/src/plugins/value/engine/mem_exec.mli
@@ -41,7 +41,7 @@ module Make
         to be reused in subsequent calls *)
     val store_computed_call:
       kernel_function -> Domain.t -> Value.t or_bottom list ->
-      Domain.t list or_bottom ->
+      (Partition.key * Domain.t) list ->
       unit
 
     (** [reuse_previous_call kf init_state args] searches amongst the previous
@@ -52,7 +52,7 @@ module Make
         by the plugins that have registered Value callbacks.) *)
     val reuse_previous_call:
       kernel_function -> Domain.t -> Value.t or_bottom list ->
-      (Domain.t list or_bottom * int) option
+      ((Partition.key * Domain.t) list * int) option
   end
 
 
diff --git a/src/plugins/value/engine/transfer_specification.ml b/src/plugins/value/engine/transfer_specification.ml
index 5e782e06f03b02524bd062c667909e29cc063d00..1bd620279bfbd9acdfb0797536bcc5f5e71d3e19 100644
--- a/src/plugins/value/engine/transfer_specification.ml
+++ b/src/plugins/value/engine/transfer_specification.ml
@@ -567,7 +567,7 @@ module Make
   let compute_using_specification ~warn kinstr call spec state =
     let vi = Kernel_function.get_vi call.kf in
     if Cil.hasAttribute "noreturn" vi.vattr
-    then `Bottom
+    then []
     else
       (* Initializes the variable returned by the function. *)
       let state = match call.return with
@@ -582,8 +582,6 @@ module Make
       let states =
         compute_specification ~warn kinstr call.kf call.return spec state
       in
-      if States.is_empty states
-      then `Bottom
-      else `Value (States.to_list states)
+      List.map (fun s -> Partition.Key.empty, s) (States.to_list states)
 
 end
diff --git a/src/plugins/value/engine/transfer_specification.mli b/src/plugins/value/engine/transfer_specification.mli
index 06af47c468ce3f30d5eeb4acc8d9f8e8f63e79df..93ea891b66ca643709c14845b09d4b984bf4f2a6 100644
--- a/src/plugins/value/engine/transfer_specification.mli
+++ b/src/plugins/value/engine/transfer_specification.mli
@@ -35,6 +35,6 @@ module Make
     val compute_using_specification:
       warn:bool ->
       kinstr -> (Abstract.Loc.location, Abstract.Val.t) call -> spec ->
-      Abstract.Dom.t -> Abstract.Dom.t list or_bottom
+      Abstract.Dom.t -> (Partition.key*Abstract.Dom.t) list
 
   end
diff --git a/src/plugins/value/engine/transfer_stmt.ml b/src/plugins/value/engine/transfer_stmt.ml
index 1ce8dd5d91ed1f126de402825f9d2298151ea620..261bfb1116eee5def3195c54a383529c0c533e3b 100644
--- a/src/plugins/value/engine/transfer_stmt.ml
+++ b/src/plugins/value/engine/transfer_stmt.ml
@@ -32,19 +32,19 @@ module type S = sig
   val assume: state -> stmt -> exp -> bool -> state or_bottom
   val call:
     stmt -> lval option -> exp -> exp list -> state ->
-    state list or_bottom * Eval.cacheable
+    (Partition.key * state) list * Eval.cacheable
   val check_unspecified_sequence:
     stmt ->
     state -> (stmt * lval list * lval list * lval list * stmt ref list) list ->
     unit or_bottom
   val enter_scope: kernel_function -> varinfo list -> state -> state
   type call_result = {
-    states: state list or_bottom;
+    states: (Partition.key * state) list;
     cacheable: Eval.cacheable;
     builtin: bool;
   }
   val compute_call_ref:
-    (stmt -> (loc, value) call -> recursion option ->state -> call_result) ref
+    (stmt -> (loc, value) call -> recursion option -> state -> call_result) ref
 end
 
 (* Reference filled in by the callwise-inout callback *)
@@ -296,14 +296,15 @@ module Make (Abstract: Abstractions.Eva) = struct
   (* ------------------------------------------------------------------------ *)
 
   type call_result = {
-    states: state list or_bottom;
+    states: (Partition.key * state) list;
     cacheable: cacheable;
     builtin: bool;
   }
 
   (* Forward reference to [Eval_funs.compute_call] *)
   let compute_call_ref :
-    (stmt -> (loc, value) call -> recursion option -> state -> call_result) ref
+    (stmt -> (loc, value) call -> recursion option -> state ->
+     call_result) ref
     = ref (fun _ -> assert false)
 
   (* Returns the result of a call, and a boolean that indicates whether a
@@ -324,7 +325,7 @@ module Make (Abstract: Abstractions.Eva) = struct
           Domain.Store.register_initial_state (Value_util.call_stack ()) state;
           !compute_call_ref stmt call recursion state
         | `Bottom ->
-          { states = `Bottom; cacheable = Cacheable; builtin=false }
+          { states = []; cacheable = Cacheable; builtin=false }
       in
       cleanup ();
       res
@@ -460,8 +461,6 @@ module Make (Abstract: Abstractions.Eva) = struct
     let pre = state in
     (* Process the call according to the domain decision. *)
     let call_result = process_call stmt call recursion valuation state in
-    call_result.cacheable,
-    call_result.states >>- fun result ->
     let leaving_vars = leaving_vars kf_callee in
     (* Do not try to reduce concrete arguments if a builtin was used. *)
     let gather_reduced_arguments =
@@ -488,11 +487,11 @@ module Make (Abstract: Abstractions.Eva) = struct
     in
     let states =
       List.fold_left
-        (fun acc return -> Bottom.add_to_list (process return) acc)
-        [] result
+        (fun acc (k,x) -> Bottom.add_to_list (process x >>-: fun y -> k,y) acc)
+        [] call_result.states
     in
     InOutCallback.clear ();
-    Bottom.bot_of_list states
+    call_result.cacheable, states
 
 
   (* ------------------- Evaluation of the arguments ------------------------ *)
@@ -747,39 +746,40 @@ module Make (Abstract: Abstractions.Eva) = struct
     Alarmset.emit ki_call alarms;
     let cacheable = ref Cacheable in
     let eval =
-      functions >>- fun functions ->
+      functions >>-: fun functions ->
       let current_kf = Value_util.current_kf () in
       let process_one_function kf valuation =
         (* The special Frama_C_ functions to print states are handled here. *)
         if apply_special_directives ~subdivnb kf args state
         then
           let () = apply_cvalue_callback kf ki_call state in
-          `Value ([state])
+          [(Partition.Key.empty, state)]
         else
           (* Create the call. *)
           let eval, alarms = make_call ~subdivnb kf args valuation state in
           Alarmset.emit ki_call alarms;
-          eval >>- fun (call, recursion, valuation) ->
-          (* Register the call. *)
-          Value_results.add_kf_caller call.kf ~caller:(current_kf, stmt);
-          (* Do the call. *)
-          let c, states =
-            do_one_call valuation stmt lval_option call recursion state
+          let states =
+            eval >>-: fun (call, recursion, valuation) ->
+            (* Register the call. *)
+            Value_results.add_kf_caller call.kf ~caller:(current_kf, stmt);
+            (* Do the call. *)
+            let c, states =
+              do_one_call valuation stmt lval_option call recursion state
+            in
+            (* If needed, propagate that callers cannot be cached. *)
+            if c = NoCacheCallers then
+              cacheable := NoCacheCallers;
+            states
           in
-          (* If needed, propagate that callers cannot be cached. *)
-          if c = NoCacheCallers then
-            cacheable := NoCacheCallers;
-          states
+          Bottom.list_of_bot states
       in
       (* Process each possible function apart, and append the result list. *)
       let process acc (kf, valuation) =
-        let res = process_one_function kf valuation in
-        (Bottom.list_of_bot res) @ acc
+        process_one_function kf valuation @ acc
       in
-      let states_list = List.fold_left process [] functions in
-      Bottom.bot_of_list states_list
+      List.fold_left process [] functions
     in
-    eval, !cacheable
+    Bottom.list_of_bot eval, !cacheable
 
   (* ------------------------------------------------------------------------ *)
   (*                            Unspecified Sequence                          *)
diff --git a/src/plugins/value/engine/transfer_stmt.mli b/src/plugins/value/engine/transfer_stmt.mli
index 87c505e24111ca06f51ce4a9cb5ee3fe9178c788..414b093dbf482237bc4ce17da97da025ac7b1edd 100644
--- a/src/plugins/value/engine/transfer_stmt.mli
+++ b/src/plugins/value/engine/transfer_stmt.mli
@@ -37,7 +37,7 @@ module type S = sig
 
   val call:
     stmt -> lval option -> exp -> exp list -> state ->
-    state list or_bottom * Eval.cacheable
+    (Partition.key * state) list * Eval.cacheable
 
   val check_unspecified_sequence:
     Cil_types.stmt ->
@@ -49,7 +49,7 @@ module type S = sig
   val enter_scope: kernel_function -> varinfo list -> state -> state
 
   type call_result = {
-    states: state list or_bottom;
+    states: (Partition.key * state) list;
     cacheable: Eval.cacheable;
     builtin: bool;
   }
diff --git a/src/plugins/value/partitioning/partition.ml b/src/plugins/value/partitioning/partition.ml
index 1867b8a07201ab6228366f4fb1cff4ce9c212815..d055a778be839921a4cc8f6d1cddb54a2482aaff 100644
--- a/src/plugins/value/partitioning/partition.ml
+++ b/src/plugins/value/partitioning/partition.ml
@@ -34,6 +34,37 @@ let new_monitor ~split_limit = {
   split_values = Datatype.Integer.Set.empty;
 }
 
+module SplitMonitor = Datatype.Make_with_collections (
+  struct
+    include Datatype.Serializable_undefined
+    module Values = Datatype.Integer.Set
+
+    type t = split_monitor
+
+    let name = "Partition.SplitMonitor"
+
+    let reprs = [ new_monitor ~split_limit:0 ]
+
+    let structural_descr =
+      Structural_descr.t_record
+        [| Datatype.Int.packed_descr; Values.packed_descr |]
+
+    let compare m1 m2 =
+      let c = Int.compare m1.split_limit m2.split_limit in
+      if c <> 0 then c else Values.compare m1.split_values m2.split_values
+
+    let equal = Datatype.from_compare
+
+    let pretty fmt m =
+      Format.fprintf fmt "%d/%d" (Values.cardinal m.split_values) m.split_limit
+
+    let hash m =
+      hash (Datatype.Int.hash m.split_limit, Values.hash m.split_values)
+
+    let copy m =
+      { m with split_values = m.split_values }
+  end)
+
 (* --- Stamp rationing --- *)
 
 (* Stamps used to label states according to slevel.
@@ -57,24 +88,44 @@ type split_term = Eva_annotations.split_term =
   | Expression of Cil_types.exp
   | Predicate of Cil_types.predicate
 
-module SplitTerm = struct
-  type t = split_term
-  let compare x y =
-    match x, y with
-    | Expression e1, Expression e2 -> Cil_datatype.ExpStructEq.compare e1 e2
-    | Predicate p1, Predicate p2 -> Logic_utils.compare_predicate p1 p2
-    | Expression _, Predicate _ -> 1
-    | Predicate _, Expression _ -> -1
-
-  let pretty fmt = function
-    | Expression e -> Printer.pp_exp fmt e
-    | Predicate p -> Printer.pp_predicate fmt p
-end
+module SplitTerm = Datatype.Make_with_collections (struct
+    include Datatype.Serializable_undefined
+
+    module Expressions = Cil_datatype.ExpStructEq
+    module Predicates = Cil_datatype.PredicateStructEq
+
+    type t = split_term
 
-module SplitMap = Map.Make (SplitTerm)
-module IntPair = Datatype.Pair (Datatype.Int) (Datatype.Int)
-module LoopList = Datatype.List (IntPair)
-module BranchList = Datatype.List (Datatype.Int)
+    let name = "Partition.SplitTerm"
+
+    let reprs =
+      Stdlib.List.map (fun e -> Expression e) Expressions.reprs @
+      Stdlib.List.map (fun p -> Predicate p) Predicates.reprs
+
+    let structural_descr =
+      Structural_descr.t_sum [|
+        [| Expressions.packed_descr |] ;
+        [| Predicates.packed_descr |] |]
+
+    let compare x y =
+      match x, y with
+      | Expression e1, Expression e2 -> Expressions.compare e1 e2
+      | Predicate p1, Predicate p2 -> Logic_utils.compare_predicate p1 p2
+      | Expression _, Predicate _ -> 1
+      | Predicate _, Expression _ -> -1
+
+    let equal = Datatype.from_compare
+
+    let pretty fmt = function
+      | Expression e -> Printer.pp_exp fmt e
+      | Predicate p -> Printer.pp_predicate fmt p
+
+    let hash = function
+      | Expression e -> FCHashtbl.hash (1,Expressions.hash e)
+      | Predicate p -> FCHashtbl.hash (2,Predicates.hash p)
+  end)
+
+module SplitMap = SplitTerm.Map
 
 type branch = int
 
@@ -108,12 +159,25 @@ type key = {
   dynamic_splits : split_monitor SplitMap.t; (* term -> monitor *)
 }
 
+type call_return_policy = {
+  callee_splits: bool;
+  callee_history: bool;
+  caller_history: bool;
+  history_size: int;
+}
+
 module Key =
 struct
-  type t = key
+
+  module IntPair = Datatype.Pair (Datatype.Int) (Datatype.Int)
+  module Stamp = Datatype.Option (IntPair)
+  module BranchList = Datatype.List (Datatype.Int)
+  module LoopList = Datatype.List (IntPair)
+  module Splits = SplitMap.Make (Datatype.Integer)
+  module DSplits = SplitMap.Make (SplitMonitor)
 
   (* Initial key, before any partitioning *)
-  let zero = {
+  let empty = {
     ration_stamp = None;
     branches = [];
     loops = [];
@@ -121,43 +185,101 @@ struct
     dynamic_splits = SplitMap.empty;
   }
 
-  let compare k1 k2 =
-    let (<?>) c (cmp,x,y) =
-      if c = 0 then cmp x y else c
-    in
-    Option.compare IntPair.compare k1.ration_stamp k2.ration_stamp
-    <?> (LoopList.compare, k1.loops, k2.loops)
-    <?> (SplitMap.compare Integer.compare, k1.splits, k2.splits)
-    <?> (SplitMap.compare (fun _ _ -> 0), k1.dynamic_splits, k2.dynamic_splits)
-    <?> (BranchList.compare, k1.branches, k2.branches)
-
-  let pretty fmt key =
-    begin match key.ration_stamp with
-      | Some (n,_) -> Format.fprintf fmt "#%d" n
-      | None -> ()
-    end;
-    Pretty_utils.pp_list ~pre:"[@[" ~sep:" ;@ " ~suf:"@]]"
-      Format.pp_print_int
-      fmt
-      key.branches;
-    Pretty_utils.pp_list ~pre:"(@[" ~sep:" ;@ " ~suf:"@])"
-      (fun fmt (i,_j) -> Format.pp_print_int fmt i)
-      fmt
-      key.loops;
-    Pretty_utils.pp_list ~pre:"{@[" ~sep:" ;@ " ~suf:"@]}"
-      (fun fmt (t, i) -> Format.fprintf fmt "%a:%a"
-          SplitTerm.pretty t
-          (Integer.pretty ~hexa:false) i)
-      fmt
-      (SplitMap.bindings key.splits)
+  include Datatype.Make_with_collections (struct
+      include Datatype.Serializable_undefined
+
+      type t = key
+
+      let name = "Partition.Key"
+
+      let reprs = [ empty ]
+
+      let structural_descr =
+        Structural_descr.t_record [|
+          Stamp.packed_descr;
+          BranchList.packed_descr;
+          LoopList.packed_descr;
+          Splits.packed_descr;
+          DSplits.packed_descr;
+        |]
+
+      let compare k1 k2 =
+        let (<?>) c (cmp,x,y) =
+          if c = 0 then cmp x y else c
+        in
+        Stdlib.Option.compare IntPair.compare k1.ration_stamp k2.ration_stamp
+        <?> (LoopList.compare, k1.loops, k2.loops)
+        <?> (Splits.compare, k1.splits, k2.splits)
+        (* Ignore monitors in comparison *)
+        <?> (SplitMap.compare (fun _ _ -> 0), k1.dynamic_splits, k2.dynamic_splits)
+        <?> (BranchList.compare, k1.branches, k2.branches)
+
+      let equal = Datatype.from_compare
+
+      let hash k =
+        Stdlib.Hashtbl.hash (
+          Stamp.hash k.ration_stamp,
+          BranchList.hash k.branches,
+          LoopList.hash k.loops,
+          Splits.hash k.splits,
+          DSplits.hash k.dynamic_splits) (* Monitors probably shouldn't be hashed *)
+
+      let pretty fmt key =
+        begin match key.ration_stamp with
+          | Some (n,_) -> Format.fprintf fmt "#%d" n
+          | None -> ()
+        end;
+        Pretty_utils.pp_list ~pre:"[@[" ~sep:" ;@ " ~suf:"@]]"
+          Format.pp_print_int
+          fmt
+          key.branches;
+        Pretty_utils.pp_list ~pre:"(@[" ~sep:" ;@ " ~suf:"@])"
+          (fun fmt (i,_j) -> Format.pp_print_int fmt i)
+          fmt
+          key.loops;
+        Pretty_utils.pp_list ~pre:"{@[" ~sep:" ;@ " ~suf:"@]}"
+          (fun fmt (t, i) -> Format.fprintf fmt "%a:%a"
+              SplitTerm.pretty t
+              Datatype.Integer.pretty i)
+          fmt
+          (SplitMap.bindings key.splits)
+    end)
 
   let exceed_rationing key = key.ration_stamp = None
+
+  let combine ~policy ~caller ~callee =
+    let keep_second _ v1 v2 =
+      match v1, v2 with
+      | None, None -> None
+      | Some x, None | (Some _ | None), Some x -> Some x
+    in
+    (* There is no need to preserve the uniqueness of ration stamps here, as
+       keys will always be given new stamps before the merge of identical keys.
+       This invariant depends on the sequence of operations performed by
+       the iterator and the trace_partitioning. *)
+    {
+      ration_stamp = None;
+      branches =
+        Extlib.list_first_n policy.history_size (
+          (if policy.callee_history then callee.branches else []) @
+          (if policy.caller_history then caller.branches else [])
+        );
+      loops = caller.loops;
+      splits =
+        if policy.callee_splits
+        then SplitMap.merge keep_second caller.splits callee.splits
+        else caller.splits;
+      dynamic_splits =
+        if policy.callee_splits
+        then SplitMap.merge keep_second caller.dynamic_splits callee.dynamic_splits
+        else caller.dynamic_splits;
+    }
 end
 
 
 (* --- Partitions --- *)
 
-module KMap = Map.Make (Key)
+module KMap = Key.Map
 
 type 'a partition = 'a KMap.t
 
@@ -171,8 +293,8 @@ let map = KMap.map
 let filter = KMap.filter
 let merge = KMap.merge
 
-let to_list (p : 'a partition) : 'a list =
-  KMap.fold (fun _k x l -> x :: l) p []
+let to_list (p : 'a partition) : (key * 'a) list =
+  KMap.fold (fun k x l -> (k, x) :: l) p []
 
 
 (* --- Partitioning actions --- *)
@@ -207,7 +329,7 @@ struct
   let empty = []
 
   let initial (p : 'a list) : t =
-    List.map (fun state -> Key.zero, state) p
+    List.map (fun state -> Key.empty, state) p
 
   let to_list (f : t) : state list =
     List.map snd f
@@ -511,20 +633,20 @@ struct
       in
       map_keys transfer p
 
-  let transfer_states (f : state -> state list) (p : t) : t =
+  let transfer (f : (key * state) -> (key * state) list) (p : t) : t =
     let n = ref 0 in
-    let transfer acc (k,x) =
-      let add =
+    let transfer acc key_state =
+      let add l (k, y) =
         match k.ration_stamp with
         (* No ration stamp, just add the state to the list *)
-        | None -> fun l y -> (k,y) :: l
+        | None -> (k, y) :: l
         (* There is a ration stamp, set the second part of the stamp to a unique transfer number *)
-        | Some (s,_) -> fun l y ->
+        | Some (s,_) ->
           let k' = { k with ration_stamp = Some (s, !n) } in
           incr n;
-          (k',y) :: l
+          (k', y) :: l
       in
-      List.fold_left add acc (f x)
+      List.fold_left add acc (f key_state)
     in
     List.fold_left transfer [] p
 
diff --git a/src/plugins/value/partitioning/partition.mli b/src/plugins/value/partitioning/partition.mli
index fe3dc9f303f8332f8009fdf419dc10f6676509c1..042c0e4ae6e04332c242b493c2f91f3d390ec1d8 100644
--- a/src/plugins/value/partitioning/partition.mli
+++ b/src/plugins/value/partitioning/partition.mli
@@ -41,11 +41,19 @@
 (** Partitioning keys attached to states. *)
 type key
 
+type call_return_policy = {
+  callee_splits: bool;
+  callee_history: bool;
+  caller_history: bool;
+  history_size: int;
+}
+
 module Key : sig
-  val zero : key (** Initial key: no partitioning. *)
-  val compare : key -> key -> int
-  val pretty : Format.formatter -> key -> unit
-  val exceed_rationing: key -> bool
+  include Datatype.S_with_collections with type t = key
+  val empty : t (** Initial key: no partitioning. *)
+  val exceed_rationing: t -> bool
+  val combine : policy:call_return_policy -> caller:t -> callee:t -> t
+  (** Recombinaison of keys after a call *)
 end
 
 (** Collection of states, each identified by a unique key. *)
@@ -54,7 +62,7 @@ type 'state partition
 val empty : 'a partition
 val is_empty : 'a partition -> bool
 val size : 'a partition -> int
-val to_list : 'a partition -> 'a list
+val to_list : 'a partition -> (key*'a) list
 val find : key -> 'a partition -> 'a
 val replace : key -> 'a -> 'a partition -> 'a partition
 val merge : (key -> 'a option -> 'b option -> 'c option) -> 'a partition ->
@@ -182,8 +190,8 @@ sig
 
   val union : t -> t -> t
 
+  val transfer : ((key * state) -> (key * state) list) -> t -> t
   val transfer_keys : t -> action -> t
-  val transfer_states : (state -> state list) -> t -> t
 
   val iter : (state -> unit) -> t -> unit
   val filter_map: (key -> state -> state option) -> t -> t
diff --git a/src/plugins/value/partitioning/partitioning_parameters.ml b/src/plugins/value/partitioning/partitioning_parameters.ml
index 4ddcf1835217ca9caa6cdfdd8bd8c3f28c1979ce..77aecd2890d236914afb00f77473f73f280a2f4e 100644
--- a/src/plugins/value/partitioning/partitioning_parameters.ml
+++ b/src/plugins/value/partitioning/partitioning_parameters.ml
@@ -139,4 +139,12 @@ struct
         acc (* Impossible to convert term to lval *)
     in
     List.fold_left map_annot [] (get_flow_annot stmt)
+
+  let call_return_policy =
+    Partition.{
+      callee_splits = Value_parameters.InterproceduralSplits.get ();
+      callee_history = Value_parameters.InterproceduralHistory.get ();
+      caller_history = true;
+      history_size = history_size;
+    }
 end
diff --git a/src/plugins/value/partitioning/partitioning_parameters.mli b/src/plugins/value/partitioning/partitioning_parameters.mli
index 891a2b72b6f988cd8a56f2495f90d55f87a71be1..636eabc5bcf6a76ace74f4b637c1cb8c9d51851a 100644
--- a/src/plugins/value/partitioning/partitioning_parameters.mli
+++ b/src/plugins/value/partitioning/partitioning_parameters.mli
@@ -31,4 +31,5 @@ module Make (Kf : sig val kf: kernel_function end) : sig
   val history_size : int
   val universal_splits : Partition.action list
   val flow_actions : stmt -> Partition.action list
+  val call_return_policy : Partition.call_return_policy
 end
diff --git a/src/plugins/value/partitioning/trace_partitioning.ml b/src/plugins/value/partitioning/trace_partitioning.ml
index 9ba46bb5eefd06b26813c24013ac7fa535c1911b..61f2b7a458ffc32bdefebcfae7d7048304662d08 100644
--- a/src/plugins/value/partitioning/trace_partitioning.ml
+++ b/src/plugins/value/partitioning/trace_partitioning.ml
@@ -112,13 +112,13 @@ struct
 
   (* Accessors *)
 
-  let expanded (s : store) : state list =
+  let expanded (s : store) : (key * state) list =
     Partition.to_list s.store_partition
 
   let smashed (s : store) : state or_bottom =
     match expanded s with
     | [] -> `Bottom
-    | v1 :: l -> `Value (List.fold_left Domain.join v1 l)
+    | (_k, v1) :: l -> `Value (List.fold_left Domain.join v1 (List.map snd l))
 
   let contents (flow : flow) : state list =
     Flow.to_list flow
@@ -175,6 +175,10 @@ struct
           then apply (Restrict (return_exp, i))
           else apply (Ration empty_rationing)
 
+  let call_return ~caller result =
+    let combine = Partition.Key.combine ~policy:call_return_policy in
+    List.map (fun (k, s) -> combine ~caller ~callee:k, s) result
+
   (* Reset state (for hierchical convergence) *)
 
   let reset_store (s : store) : unit =
@@ -210,7 +214,7 @@ struct
     in
     into.tank_states <- Partition.merge join into.tank_states new_states
 
-  let transfer = Flow.transfer_states
+  let transfer = Flow.transfer
 
   let output_slevel : int -> unit =
     let slevel_display_step = Value_parameters.ShowSlevel.get () in
@@ -239,6 +243,7 @@ struct
     in
     (* Get every source flow *)
     let sources_states =
+      (* Is there more than one non-empty incomming flow ? *)
       match sources with
       | [(_,flow)] -> [flow]
       | sources ->
diff --git a/src/plugins/value/partitioning/trace_partitioning.mli b/src/plugins/value/partitioning/trace_partitioning.mli
index 0fbd96f2888d225aa4c01880e71f5b51c9ecfcef..dbdd548600b7ae0c8926bbfb29adc164f79ea709 100644
--- a/src/plugins/value/partitioning/trace_partitioning.mli
+++ b/src/plugins/value/partitioning/trace_partitioning.mli
@@ -50,7 +50,7 @@ sig
 
   (* --- Accessors --- *)
 
-  val expanded : store -> state list
+  val expanded : store -> (Partition.key * state) list
   val smashed : store -> state or_bottom
   val contents : flow -> state list
   val is_empty_store : store -> bool
@@ -81,6 +81,12 @@ sig
   val next_loop_iteration : flow -> Cil_types.stmt -> flow
   val split_return : flow -> Cil_types.exp option -> flow
 
+  (** After the analysis of a function call, recombines callee partitioning keys
+      with the caller key. *)
+  val call_return:
+    caller:Partition.key ->
+    (Partition.key * state) list -> (Partition.key * state) list
+
   (* --- Operators --- *)
 
   (** Remove all states from the tank, leaving it empty as if it was just
@@ -91,7 +97,8 @@ sig
   val fill : into:tank -> flow -> unit
 
   (** Apply a transfer function to all the states of a propagation. *)
-  val transfer : (state -> state list) -> flow -> flow
+  val transfer : ((Partition.key * state) -> (Partition.key * state) list) ->
+    flow -> flow
 
   (** Join all incoming propagations into the given store. This function returns
       a set of states which still need to be propagated past the store.
diff --git a/src/plugins/value/value_parameters.ml b/src/plugins/value/value_parameters.ml
index c1a44a5949f45fbb30df7eb57e360f70bc44e22d..11f8cce3e58081ea89ad878f2ad8534a50e6507e 100644
--- a/src/plugins/value/value_parameters.ml
+++ b/src/plugins/value/value_parameters.ml
@@ -791,6 +791,24 @@ module SplitLimit =
 let () = add_precision_dep SplitLimit.parameter
 let () = SplitLimit.set_range 0 max_int
 
+let () = Parameter_customize.set_group precision_tuning
+module InterproceduralSplits =
+  False
+    (struct
+      let option_name = "-eva-interprocedural-splits"
+      let help = "Keep partitioning splits through function returns"
+    end)
+let () = add_precision_dep InterproceduralSplits.parameter
+
+let () = Parameter_customize.set_group precision_tuning
+module InterproceduralHistory =
+  False
+    (struct
+      let option_name = "-eva-interprocedural-history"
+      let help = "Keep partitioning history through function returns"
+    end)
+let () = add_precision_dep InterproceduralHistory.parameter
+
 let () = Parameter_customize.set_group precision_tuning
 let () = Parameter_customize.argument_may_be_fundecl ()
 module SplitReturnFunction =
diff --git a/src/plugins/value/value_parameters.mli b/src/plugins/value/value_parameters.mli
index 0442dbcc0bb22414545f59df80dc386b49b15061..a05cde2a46d6bbdf015865524e5dda608eb4d91d 100644
--- a/src/plugins/value/value_parameters.mli
+++ b/src/plugins/value/value_parameters.mli
@@ -79,6 +79,8 @@ module DefaultLoopUnroll : Parameter_sig.Int
 module HistoryPartitioning : Parameter_sig.Int
 module ValuePartitioning : Parameter_sig.String_set
 module SplitLimit : Parameter_sig.Int
+module InterproceduralSplits : Parameter_sig.Bool
+module InterproceduralHistory : Parameter_sig.Bool
 
 module ArrayPrecisionLevel: Parameter_sig.Int
 
diff --git a/src/plugins/variadic/tests/erroneous/oracle/exec.res.oracle b/src/plugins/variadic/tests/erroneous/oracle/exec.res.oracle
index 3964a37c4107508e018d69cb6119d25a96bbcbe6..d28bedfb6dede9344daeab4b60386b4636bcb9e2 100644
--- a/src/plugins/variadic/tests/erroneous/oracle/exec.res.oracle
+++ b/src/plugins/variadic/tests/erroneous/oracle/exec.res.oracle
@@ -1,8 +1,8 @@
-[variadic] FRAMAC_SHARE/libc/unistd.h:814: 
+[variadic] FRAMAC_SHARE/libc/unistd.h:800: 
   Declaration of variadic function execl.
-[variadic] FRAMAC_SHARE/libc/unistd.h:819: 
+[variadic] FRAMAC_SHARE/libc/unistd.h:805: 
   Declaration of variadic function execle.
-[variadic] FRAMAC_SHARE/libc/unistd.h:824: 
+[variadic] FRAMAC_SHARE/libc/unistd.h:810: 
   Declaration of variadic function execlp.
 [variadic] tests/erroneous/exec.c:5: Warning: 
   Incorrect type for argument 3. The argument will be cast from int to char *.
diff --git a/src/plugins/variadic/tests/known/oracle/exec.res.oracle b/src/plugins/variadic/tests/known/oracle/exec.res.oracle
index d3df0e6caaecd4de576cc56e389dabf8762146eb..85b39e35a56ab3ba5e2efcf128af74add1b33744 100644
--- a/src/plugins/variadic/tests/known/oracle/exec.res.oracle
+++ b/src/plugins/variadic/tests/known/oracle/exec.res.oracle
@@ -1,8 +1,8 @@
-[variadic] FRAMAC_SHARE/libc/unistd.h:814: 
+[variadic] FRAMAC_SHARE/libc/unistd.h:800: 
   Declaration of variadic function execl.
-[variadic] FRAMAC_SHARE/libc/unistd.h:819: 
+[variadic] FRAMAC_SHARE/libc/unistd.h:805: 
   Declaration of variadic function execle.
-[variadic] FRAMAC_SHARE/libc/unistd.h:824: 
+[variadic] FRAMAC_SHARE/libc/unistd.h:810: 
   Declaration of variadic function execlp.
 [variadic] tests/known/exec.c:9: Translating call to execle to a call to execve.
 [variadic] tests/known/exec.c:11: Warning: 
diff --git a/src/plugins/variadic/tests/known/oracle/exec_failed_requirement.res.oracle b/src/plugins/variadic/tests/known/oracle/exec_failed_requirement.res.oracle
index a8e29aef564f9e3150640adc472080a1bb437a93..f04568a4d68f71534e09b863b40a96c050d3b06a 100644
--- a/src/plugins/variadic/tests/known/oracle/exec_failed_requirement.res.oracle
+++ b/src/plugins/variadic/tests/known/oracle/exec_failed_requirement.res.oracle
@@ -1,8 +1,8 @@
-[variadic] FRAMAC_SHARE/libc/unistd.h:814: 
+[variadic] FRAMAC_SHARE/libc/unistd.h:800: 
   Declaration of variadic function execl.
-[variadic] FRAMAC_SHARE/libc/unistd.h:819: 
+[variadic] FRAMAC_SHARE/libc/unistd.h:805: 
   Declaration of variadic function execle.
-[variadic] FRAMAC_SHARE/libc/unistd.h:824: 
+[variadic] FRAMAC_SHARE/libc/unistd.h:810: 
   Declaration of variadic function execlp.
 [variadic] tests/known/exec_failed_requirement.c:7: 
   Translating call to execl to a call to execv.
diff --git a/tests/fc_script/make-wrapper.c b/tests/fc_script/make-wrapper.c
index b52d6c74e87425c96857b0e0bedbcc77f6085f7e..ff8453e32a8f53fa964378522ca13e4b7f822604 100644
--- a/tests/fc_script/make-wrapper.c
+++ b/tests/fc_script/make-wrapper.c
@@ -1,7 +1,7 @@
 /* run.config
    NOFRAMAC: testing frama-c-script
-   COMMENT: we must filter 'make:' output lines, since they differ when run by the CI (e.g. mention to jobserver)
-   EXECNOW: LOG make-wrapper.res LOG make-wrapper.err cd @PTEST_DIR@ && touch make-wrapper2.c && touch make-wrapper3.c && FRAMAC=../../bin/frama-c ../../bin/frama-c-script make-wrapper --make-dir . -f make-for-make-wrapper.mk | sed -e "s:$PWD:PWD:g" | grep -v "^make.*" | grep -v "recipe for target.*failed" > result/make-wrapper.res 2> result/make-wrapper.err && rm -rf make-for-make-wrapper.parse make-for-make-wrapper.eva
+   COMMENT: we must filter 'make:'/'gmake:' output lines, since they differ when run by the CI (e.g. mention to jobserver)
+   EXECNOW: LOG make-wrapper.res LOG make-wrapper.err cd @PTEST_DIR@ && touch make-wrapper2.c && touch make-wrapper3.c && FRAMAC=../../bin/frama-c ../../bin/frama-c-script make-wrapper --make-dir . -f make-for-make-wrapper.mk | sed -E -e "s:$PWD:PWD:g;/^(real|user|sys)/d;" | grep -E -v "^g?make.*" | grep -v "recipe for target.*failed" | grep -v '^$' > result/make-wrapper.res 2> result/make-wrapper.err && rm -rf make-for-make-wrapper.parse make-for-make-wrapper.eva
 */
 
 int defined(int a);
diff --git a/tests/fc_script/oracle/make-wrapper.res b/tests/fc_script/oracle/make-wrapper.res
index 8370fe5e49498ce18397bc847647adac6ce49eaf..30db8dfd928cbfe5194bba8de7cbadd796f82029 100644
--- a/tests/fc_script/oracle/make-wrapper.res
+++ b/tests/fc_script/oracle/make-wrapper.res
@@ -1,11 +1,7 @@
-
 Command: ../../bin/frama-c -kernel-warn-key annot:missing-spec=abort -kernel-warn-key typing:implicit-function-declaration=abort -cpp-extra-args= make-wrapper.c make-wrapper2.c
-
 [kernel] Parsing make-wrapper.c (with preprocessing)
 [kernel] Parsing make-wrapper2.c (with preprocessing)
-
 Command: ../../bin/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 -calldeps -from-verbose 0 -eva-warn-key builtins:missing-spec=abort
-
 [eva] Analyzing a complete application starting at main
 [eva] Computing initial state
 [eva] Initial state computed
@@ -28,19 +24,14 @@ Command: ../../bin/frama-c -kernel-warn-key annot:missing-spec=abort -kernel-war
 [eva] Clean up and save partial results.
 [kernel] Frama-C aborted: invalid user input.
 [kernel] Warning: attempting to save on non-zero exit code: modifying filename into `PWD/make-for-make-wrapper.eva/framac.sav.error'.
-
 ***** make-wrapper recommendations *****
-
 *** recommendation #1 ***
-
 1. Found recursive call at:
   stack: large_name_to_force_line_break_in_stack_msg :: make-wrapper.c:14 <-
          large_name_to_force_line_break_in_stack_msg :: make-wrapper.c:18 <-
          rec :: make-wrapper.c:23 <-
          main
-
 Consider patching, stubbing or adding an ACSL specification to the recursive call, then re-run the analysis.
-
 *** recommendation #2 ***
 2. Found function with missing spec: large_name_to_force_line_break_in_stack_msg
    Looking for files defining it...
diff --git a/tests/libc/check_compliance.ml b/tests/libc/check_compliance.ml
index 3fab55c7989fe06a0dd332dafeb7f3bb9c6c47d8..fabf605d2b8d14f9aa8503e6553d945e16256a37 100644
--- a/tests/libc/check_compliance.ml
+++ b/tests/libc/check_compliance.ml
@@ -81,6 +81,49 @@ struct
       table
 end
 
+let ident_to_be_ignored id headers =
+  Extlib.string_prefix "__" id ||
+  Extlib.string_prefix "Frama_C" id ||
+  List.filter (fun h -> not (Extlib.string_prefix "__fc" h)) headers = []
+
+let check_ident c11 posix glibc nonstandard c11_headers id headers =
+  if ident_to_be_ignored id headers then (* nothing to check *) ()
+  else begin
+    if Hashtbl.mem c11 id then begin
+      (* Check that the header is the expected one.
+         Note that some symbols may appear in more than one header,
+         possibly due to collisions
+         e.g. 'flock' as type and function). *)
+      let h = Hashtbl.find c11 id in
+      if not (StringSet.mem h c11_headers) then
+        Kernel.warning "<%a>:%s : C11 says %s"
+          (Pretty_utils.pp_list ~sep:"," Format.pp_print_string) headers
+          id h
+    end
+    else if Hashtbl.mem posix id then begin
+      (* check that the header is the expected one *)
+      let (h, _) = Hashtbl.find posix id in
+      (* arpa/inet.h and netinet/in.h are special cases: due to mutual
+         inclusion, there are always issues with their symbols;
+         also, timezone is a special case, since it is a type in
+         sys/time.h, but a variable in time.h in POSIX. However, its
+         declaration as extern is erased by rmtmps, since it is
+         unused. *)
+      if not (List.mem h headers) &&
+         not (List.mem "arpa/inet.h" headers && h = "netinet/in.h" ||
+              List.mem "netinet/in.h" headers && h = "arpa/inet.h") &&
+         id <> "timezone"
+      then
+        Kernel.warning "<%a>:%s : POSIX says %s"
+          (Pretty_utils.pp_list ~sep:"," Format.pp_print_string) headers
+          id h
+    end
+    else if not (StringSet.(mem id glibc || mem id nonstandard)) then
+      Kernel.warning "<%a>:%s : unknown identifier"
+        (Pretty_utils.pp_list ~sep:"," Format.pp_print_string) headers
+        id
+  end
+
 let () =
   Db.Main.extend (fun () ->
       if not !run_once then begin
@@ -94,49 +137,6 @@ let () =
         and glibc_idents = Json.(to_set (parse dir "glibc_functions.json"))
         and posix_idents = Json.(to_table HeadersAndExtensions (parse dir "posix_identifiers.json"))
         and nonstandard_idents = Json.(keys (parse dir "nonstandard_identifiers.json")) in
-        Hashtbl.iter (fun id headers ->
-            if not (Extlib.string_prefix "__" id) &&
-               not (Extlib.string_prefix "Frama_C" id) &&
-               List.filter (fun h -> not (Extlib.string_prefix "__fc" h))
-                 headers <> []
-            then
-              let id_in_c11 = Hashtbl.mem c11_idents id in
-              let id_in_posix = Hashtbl.mem posix_idents id in
-              let id_in_glibc = StringSet.mem id glibc_idents in
-              let id_in_nonstd = StringSet.mem id nonstandard_idents in
-              let header_in_c11 h = StringSet.mem h c11_headers in
-              if id_in_c11 then begin
-                (* Check that the header is the expected one.
-                   Note that some symbols may appear in more than one header,
-                   possibly due to collisions
-                   (e.g. 'flock' as type and function). *)
-                let h = Hashtbl.find c11_idents id in
-                if not (header_in_c11 h) then
-                  Kernel.warning "<%a>:%s : C11 says %s"
-                    (Pretty_utils.pp_list ~sep:"," Format.pp_print_string) headers
-                    id h
-              end
-              else if id_in_posix then begin
-                (* check the header is the expected one *)
-                let (h, _) = Hashtbl.find posix_idents id in
-                (* arpa/inet.h and netinet/in.h are special cases: due to mutual
-                   inclusion, there are always issues with their symbols;
-                   also, timezone is a special case, since it is a type in
-                   sys/time.h, but a variable in time.h in POSIX. However, its
-                   declaration as extern is erased by rmtmps, since it is
-                   unused. *)
-                if not (List.mem h headers) &&
-                   not (List.mem "arpa/inet.h" headers && h = "netinet/in.h" ||
-                        List.mem "netinet/in.h" headers && h = "arpa/inet.h") &&
-                   id <> "timezone"
-                then
-                  Kernel.warning "<%a>:%s : POSIX says %s"
-                    (Pretty_utils.pp_list ~sep:"," Format.pp_print_string) headers
-                    id h
-              end
-              else if not (id_in_glibc || id_in_nonstd) then
-                Kernel.warning "<%a>:%s : unknown identifier"
-                  (Pretty_utils.pp_list ~sep:"," Format.pp_print_string) headers
-                  id
-          ) fc_stdlib_idents;
+        let check_ident_fun = check_ident c11_idents posix_idents glibc_idents nonstandard_idents c11_headers in
+        Hashtbl.iter check_ident_fun fc_stdlib_idents
       end)
diff --git a/tests/libc/fc_libc.c b/tests/libc/fc_libc.c
index 1345145e950c37a80e559c9426ab5a2ce0dc968e..53b38f02cd517ecf8d921d0aefa51f5aa9693d40 100644
--- a/tests/libc/fc_libc.c
+++ b/tests/libc/fc_libc.c
@@ -44,6 +44,7 @@
 #include "__fc_define_dev_t.h"
 #include "__fc_define_eof.h"
 #include "__fc_define_fd_set_t.h"
+#include "__fc_define_fds.h"
 #include "__fc_define_file.h"
 #include "__fc_define_fpos_t.h"
 #include "__fc_define_fs_cnt.h"
@@ -67,9 +68,10 @@
 #include "__fc_define_ssize_t.h"
 #include "__fc_define_stat.h"
 #include "__fc_define_suseconds_t.h"
-#include "__fc_define_timespec.h"
 #include "__fc_define_time_t.h"
 #include "__fc_define_timer_t.h"
+#include "__fc_define_timespec.h"
+#include "__fc_define_timeval.h"
 #include "__fc_define_uid_and_gid.h"
 #include "__fc_define_useconds_t.h"
 #include "__fc_define_wchar_t.h"
diff --git a/tests/libc/oracle/fc_libc.0.res.oracle b/tests/libc/oracle/fc_libc.0.res.oracle
index 881040218e6562ae1c75d17f17b57abbc7866064..c300bb3596b525db3b01f89b6ba8215600e143c2 100644
--- a/tests/libc/oracle/fc_libc.0.res.oracle
+++ b/tests/libc/oracle/fc_libc.0.res.oracle
@@ -4,10 +4,10 @@
 [eva] Initial state computed
 [eva:initial-state] Values of globals at initialization
   
-[eva] tests/libc/fc_libc.c:164: assertion got status valid.
-[eva] tests/libc/fc_libc.c:165: assertion got status valid.
 [eva] tests/libc/fc_libc.c:166: assertion got status valid.
 [eva] tests/libc/fc_libc.c:167: assertion got status valid.
+[eva] tests/libc/fc_libc.c:168: assertion got status valid.
+[eva] tests/libc/fc_libc.c:169: assertion got status valid.
 [eva] Recording results for main
 [eva] done for function main
 [eva] ====== VALUES COMPUTED ======
@@ -47,7 +47,7 @@
    wcslen (3 calls); wcsncat (0 call); wcsncpy (0 call); wmemcpy (1 call);
    wmemset (0 call); 
   
-  Specified-only functions (426)
+  Specified-only functions (427)
   ==============================
    FD_CLR (0 call); FD_ISSET (0 call); FD_SET (0 call); FD_ZERO (0 call);
    Frama_C_int_interval (0 call); Frama_C_long_interval (0 call);
@@ -175,20 +175,20 @@
    wcscmp (0 call); wcscspn (0 call); wcslcat (0 call); wcslcpy (0 call);
    wcsncmp (0 call); wcspbrk (0 call); wcsrchr (0 call); wcsspn (0 call);
    wcsstr (0 call); wcstombs (0 call); wctomb (0 call); wmemchr (0 call);
-   wmemcmp (0 call); wmemmove (0 call); write (0 call); 
+   wmemcmp (0 call); wmemmove (0 call); write (0 call); writev (0 call); 
   
   Undefined and unspecified functions (1)
   =======================================
    __builtin_abort (1 call); 
   
-  'Extern' global variables (21)
+  'Extern' global variables (22)
   ==============================
-   __fc_basename; __fc_dirname; __fc_getpwuid_pw_dir; __fc_getpwuid_pw_name;
-   __fc_getpwuid_pw_passwd; __fc_getpwuid_pw_shell; __fc_heap_status;
-   __fc_hostname; __fc_locale; __fc_locale_names; __fc_mblen_state;
-   __fc_mbtowc_state; __fc_random_counter; __fc_socket_counter;
-   __fc_stack_status; __fc_tz; __fc_wctomb_state; optarg; opterr; optopt;
-   tzname
+   __fc_basename; __fc_dirname; __fc_fds; __fc_getpwuid_pw_dir;
+   __fc_getpwuid_pw_name; __fc_getpwuid_pw_passwd; __fc_getpwuid_pw_shell;
+   __fc_heap_status; __fc_hostname; __fc_locale; __fc_locale_names;
+   __fc_mblen_state; __fc_mbtowc_state; __fc_random_counter;
+   __fc_socket_counter; __fc_stack_status; __fc_tz; __fc_wctomb_state; optarg;
+   opterr; optopt; tzname
   
   Potential entry points (1)
   ==========================
@@ -204,7 +204,7 @@
   Goto = 113
   Assignment = 625
   Exit point = 100
-  Function = 527
+  Function = 528
   Function call = 144
   Pointer dereferencing = 254
   Cyclomatic complexity = 371
@@ -214,6 +214,7 @@
 #include "__fc_builtin.c"
 #include "__fc_builtin.h"
 #include "__fc_define_fd_set_t.h"
+#include "__fc_define_timeval.h"
 #include "__fc_gcc_builtins.h"
 #include "__fc_integer.h"
 #include "__fc_select.h"
@@ -264,6 +265,7 @@
 #include "stropts.h"
 #include "sys/file.h"
 #include "sys/resource.h"
+#include "sys/select.h"
 #include "sys/sendfile.h"
 #include "sys/socket.h"
 #include "sys/stat.h"
diff --git a/tests/libc/oracle/fc_libc.1.res.oracle b/tests/libc/oracle/fc_libc.1.res.oracle
index c794e4be1b1caaec773f9e4c3f342430a01ce82f..38af9dde42f8d8384e4405f44b8a48c050d6ff67 100644
--- a/tests/libc/oracle/fc_libc.1.res.oracle
+++ b/tests/libc/oracle/fc_libc.1.res.oracle
@@ -270,6 +270,10 @@ typedef struct __fc_FILE FILE;
 typedef unsigned int id_t;
 typedef int suseconds_t;
 typedef int clockid_t;
+struct timespec {
+   long tv_sec ;
+   long tv_nsec ;
+};
 typedef unsigned int clock_t;
 struct tm {
    int tm_sec ;
@@ -282,10 +286,6 @@ struct tm {
    int tm_yday ;
    int tm_isdst ;
 };
-struct timespec {
-   long tv_sec ;
-   long tv_nsec ;
-};
 struct dirent {
    ino_t d_ino ;
    off_t d_off ;
@@ -304,6 +304,10 @@ struct __fc_fd_set {
    long __fc_fd_set[(unsigned int)1024 / ((unsigned int)8 * sizeof(long))] ;
 };
 typedef struct __fc_fd_set fd_set;
+struct timeval {
+   time_t tv_sec ;
+   suseconds_t tv_usec ;
+};
 struct flock {
    short l_type ;
    short l_whence ;
@@ -311,18 +315,6 @@ struct flock {
    off_t l_len ;
    pid_t l_pid ;
 };
-struct timeval {
-   time_t tv_sec ;
-   suseconds_t tv_usec ;
-};
-struct timezone {
-   int tz_minuteswest ;
-   int tz_dsttime ;
-};
-struct itimerval {
-   struct timeval it_interval ;
-   struct timeval it_value ;
-};
 typedef void * iconv_t;
 struct pollfd {
    int fd ;
@@ -350,6 +342,14 @@ struct __fc_code {
    int c_val ;
 };
 typedef struct __fc_code CODE;
+struct timezone {
+   int tz_minuteswest ;
+   int tz_dsttime ;
+};
+struct itimerval {
+   struct timeval it_interval ;
+   struct timeval it_value ;
+};
 typedef unsigned long rlim_t;
 struct rlimit {
    rlim_t rlim_cur ;
@@ -2875,7 +2875,8 @@ int fesetenv(fenv_t const *envp)
   return __retres;
 }
 
-/*@ ghost int __fc_fds[1024]; */
+extern int volatile __fc_fds[1024];
+
 /*@ requires valid_string_path: valid_read_string(path);
     requires valid_amode: (amode & ~((4 | 2) | 1)) ≡ 0 ∨ amode ≡ 0;
     ensures result_ok_or_error: \result ≡ 0 ∨ \result ≡ -1;
@@ -4518,11 +4519,70 @@ extern int kill(pid_t pid, int sig);
  */
 extern int killpg(pid_t pgrp, int sig);
 
-/*@ requires valid_read_iov: \valid_read(iov + (0 .. iovcnt - 1));
-    assigns *((char *)(iov + (0 .. iovcnt - 1))->iov_base + (0 ..));
+/*@ requires valid_fd: 0 ≤ fd < 1024;
+    requires
+      initialization: initialized_inputs:
+        ∀ ℤ i;
+          0 ≤ i < iovcnt ⇒
+          \initialized(&(iov + i)->iov_base) ∧
+          \initialized(&(iov + i)->iov_len);
+    requires
+      valid_iov:
+        ∀ ℤ i;
+          0 ≤ i < iovcnt ⇒
+          \valid((char *)(&(iov + i)->iov_base) +
+                 (0 .. (iov + i)->iov_len - 1));
+    requires bounded_iovcnt: 0 ≤ iovcnt ≤ 1024;
+    ensures
+      result_error_or_read_bytes:
+        \result ≡ -1 ∨
+        (0 ≤ \result ≤
+         \sum(0, \old(iovcnt) - 1, \lambda ℤ k; (\old(iov) + k)->iov_len));
+    assigns {*((char *)(iov + i)->iov_base + j) |
+             ℤ i, ℤ j; 0 ≤ i < iovcnt ∧ 0 ≤ j < (iov + i)->iov_len},
+            \result;
+    assigns
+    {*((char *)(iov + i)->iov_base + j) |
+     ℤ i, ℤ j; 0 ≤ i < iovcnt ∧ 0 ≤ j < (iov + i)->iov_len}
+      \from (indirect: fd), (indirect: iovcnt), (indirect: __fc_fds[fd]);
+    assigns \result
+      \from (indirect: fd), (indirect: __fc_fds[fd]),
+            (indirect: *(iov + (0 ..))), (indirect: iovcnt);
  */
 extern ssize_t readv(int fd, struct iovec const *iov, int iovcnt);
 
+/*@ requires valid_fd: 0 ≤ fd < 1024;
+    requires
+      initialization: initialized_inputs:
+        ∀ ℤ i;
+          0 ≤ i < iovcnt ⇒
+          \initialized(&(iov + i)->iov_base) ∧
+          \initialized(&(iov + i)->iov_len);
+    requires valid_read_iov: \valid_read(iov + (0 .. iovcnt - 1));
+    requires
+      valid_read_iov_bases:
+        ∀ ℤ i;
+          0 ≤ i < iovcnt ⇒
+          \valid_read((char *)(iov + i)->iov_base +
+                      (0 .. (iov + i)->iov_len - 1));
+    requires bounded_iovcnt: 0 ≤ iovcnt ≤ 1024;
+    requires
+      bounded_lengths:
+        \sum(0, iovcnt - 1, \lambda ℤ k; (iov + k)->iov_len) ≤ 2147483647;
+    ensures
+      result_error_or_written_bytes:
+        \result ≡ -1 ∨
+        (0 ≤ \result ≤
+         \sum(0, \old(iovcnt) - 1, \lambda ℤ k; (\old(iov) + k)->iov_len));
+    assigns \result, __fc_fds[fd];
+    assigns \result
+      \from (indirect: fd), (indirect: __fc_fds[fd]),
+            (indirect: *(iov + (0 ..))), (indirect: iovcnt);
+    assigns __fc_fds[fd]
+      \from (indirect: *(iov + (0 ..))), (indirect: iovcnt);
+ */
+extern ssize_t writev(int fd, struct iovec const *iov, int iovcnt);
+
 /*@ ghost struct __fc_sockfds_type __fc_sockfds[1024]; */
 /*@ ghost extern int __fc_socket_counter; */
 
@@ -7777,34 +7837,6 @@ extern DIR *opendir(char const *path);
  */
 extern struct dirent *readdir(DIR *dirp);
 
-/*@ requires valid_fdset: \valid(fdset);
-    requires initialization: \initialized(fdset);
-    assigns *fdset;
-    assigns *fdset \from *fdset, (indirect: fd);
- */
-extern void FD_CLR(int fd, fd_set *fdset);
-
-/*@ requires valid_fdset: \valid_read(fdset);
-    requires initialization: \initialized(fdset);
-    assigns \result;
-    assigns \result \from (indirect: *fdset), (indirect: fd);
- */
-extern int FD_ISSET(int fd, fd_set const *fdset);
-
-/*@ requires valid_fdset: \valid(fdset);
-    requires initialization: \initialized(fdset);
-    assigns *fdset;
-    assigns *fdset \from *fdset, (indirect: fd);
- */
-extern void FD_SET(int fd, fd_set *fdset);
-
-/*@ requires valid_fdset: \valid(fdset);
-    ensures initialization: \initialized(\old(fdset));
-    assigns *fdset;
-    assigns *fdset \from \nothing;
- */
-extern void FD_ZERO(fd_set *fdset);
-
 /*@ requires valid_res: \valid(res);
     ensures initialization: res: \initialized(\old(res));
     ensures res_wrapped: *\old(res) ≡ (int)(\old(a) + \old(b));
@@ -8220,192 +8252,6 @@ extern int __va_openat_void(int dirfd, char const *filename, int flags);
 extern int __va_openat_mode_t(int dirfd, char const *filename, int flags,
                               mode_t mode);
 
-/*@ ghost extern int __fc_tz; */
-
-/*@ requires valid_path: valid_read_string(path);
-    requires
-      valid_times_or_null: \valid_read(times + (0 .. 1)) ∨ times ≡ \null;
-    assigns \result;
-    assigns \result
-      \from (indirect: *(path + (0 .. strlen{Old}(path)))),
-            (indirect: times), (indirect: *(times + (0 .. 1)));
- */
-extern int utimes(char const *path, struct timeval const times[2]);
-
-/*@ ensures result_ok_or_error: \result ≡ 0 ∨ \result ≡ -1;
-    assigns tv->tv_sec, tv->tv_usec, *((struct timezone *)tz), \result;
-    assigns tv->tv_sec \from __fc_time;
-    assigns tv->tv_usec \from __fc_time;
-    assigns *((struct timezone *)tz) \from __fc_tz;
-    assigns \result
-      \from (indirect: tv), (indirect: tz), *tv, *((struct timezone *)tz),
-            __fc_tz;
-    
-    behavior tv_and_tz_null:
-      assumes null_tv_tz: tv ≡ \null ∧ tz ≡ \null;
-      assigns \result;
-      assigns \result \from (indirect: __fc_tz);
-    
-    behavior tv_not_null:
-      assumes non_null_tv_null_tz: tv ≢ \null ∧ tz ≡ \null;
-      ensures
-        initialization: tv_sec: tv_usec:
-          \initialized(&\old(tv)->tv_sec) ∧
-          \initialized(&\old(tv)->tv_usec);
-      ensures tv_usec_bounded: 0 ≤ \old(tv)->tv_usec ≤ 999999;
-      assigns tv->tv_sec, tv->tv_usec, \result;
-      assigns tv->tv_sec \from (indirect: __fc_time);
-      assigns tv->tv_usec \from (indirect: __fc_time);
-      assigns \result \from (indirect: *tv), (indirect: __fc_tz);
-    
-    behavior tz_not_null:
-      assumes null_tv_non_null_tz: tv ≡ \null ∧ tz ≢ \null;
-      ensures initialization: tz: \initialized((struct timezone *)\old(tz));
-      assigns *((struct timezone *)tz), \result;
-      assigns *((struct timezone *)tz) \from __fc_tz;
-      assigns \result
-        \from (indirect: *((struct timezone *)tz)), (indirect: __fc_tz);
-    
-    behavior tv_and_tz_not_null:
-      assumes non_null_tv_tz: tv ≢ \null ∧ tz ≢ \null;
-      ensures
-        initialization: tv_sec: tv_usec:
-          \initialized(&\old(tv)->tv_sec) ∧
-          \initialized(&\old(tv)->tv_usec);
-      ensures initialization: tz: \initialized((struct timezone *)\old(tz));
-      assigns tv->tv_sec, tv->tv_usec, *((struct timezone *)tz), \result;
-      assigns tv->tv_sec \from (indirect: __fc_time);
-      assigns tv->tv_usec \from (indirect: __fc_time);
-      assigns *((struct timezone *)tz) \from __fc_tz;
-      assigns \result
-        \from (indirect: *tv), (indirect: *((struct timezone *)tz)),
-              (indirect: __fc_tz);
-    
-    complete behaviors tv_and_tz_not_null,
-                       tz_not_null,
-                       tv_not_null,
-                       tv_and_tz_null;
-    disjoint behaviors tv_and_tz_not_null,
-                       tz_not_null,
-                       tv_not_null,
-                       tv_and_tz_null;
- */
-extern int gettimeofday(struct timeval * restrict tv, void * restrict tz);
-
-/*@ requires valid_tv_or_null: \valid_read(tv) ∨ tv ≡ \null;
-    requires valid_tz_or_null: \valid_read(tz) ∨ tz ≡ \null;
-    ensures result_ok_or_error: \result ≡ 0 ∨ \result ≡ -1;
-    assigns __fc_time, __fc_tz, \result;
-    assigns __fc_time
-      \from tv->tv_sec, tv->tv_usec, tz->tz_dsttime, tz->tz_minuteswest;
-    assigns __fc_tz
-      \from tv->tv_sec, tv->tv_usec, tz->tz_dsttime, tz->tz_minuteswest;
-    assigns \result \from (indirect: *tv), (indirect: *tz);
- */
-extern int settimeofday(struct timeval const *tv, struct timezone const *tz);
-
-/*@ ghost struct itimerval volatile __fc_itimer_real; */
-/*@ ghost struct itimerval volatile __fc_itimer_virtual; */
-/*@ ghost struct itimerval volatile __fc_itimer_prof; */
-/*@ requires valid_curr_value: \valid(curr_value);
-    ensures initialization: curr_value: \initialized(\old(curr_value));
-    assigns \result, *curr_value;
-    assigns \result \from (indirect: which);
-    assigns *curr_value
-      \from __fc_itimer_real, __fc_itimer_virtual, __fc_itimer_prof;
-    
-    behavior real:
-      assumes itimer_real: which ≡ 0;
-      ensures result_ok: \result ≡ 0;
-      assigns \result, *curr_value;
-      assigns \result \from \nothing;
-      assigns *curr_value \from __fc_itimer_real;
-    
-    behavior virtual:
-      assumes itimer_virtual: which ≡ 1;
-      ensures result_ok: \result ≡ 0;
-      assigns \result, *curr_value;
-      assigns \result \from \nothing;
-      assigns *curr_value \from __fc_itimer_virtual;
-    
-    behavior prof:
-      assumes itimer_prof: which ≡ 2;
-      ensures result_ok: \result ≡ 0;
-      assigns \result, *curr_value;
-      assigns \result \from \nothing;
-      assigns *curr_value \from __fc_itimer_prof;
-    
-    behavior invalid:
-      assumes invalid_which: which ≢ 0 ∧ which ≢ 1 ∧ which ≢ 2;
-      ensures result_error: \result ≡ -1;
-      assigns \result;
-      assigns \result \from \nothing;
-    
-    complete behaviors invalid, prof, virtual, real;
-    disjoint behaviors invalid, prof, virtual, real;
- */
-extern int getitimer(int which, struct itimerval *curr_value);
-
-/*@ requires valid_new_value: \valid_read(new_value);
-    requires
-      old_value_null_or_valid: old_value ≡ \null ∨ \valid(old_value);
-    ensures result_ok_or_error: \result ≡ 0 ∨ \result ≡ -1;
-    assigns *old_value, \result;
-    assigns *old_value
-      \from (indirect: which), (indirect: old_value), (indirect: new_value),
-            __fc_itimer_real, __fc_itimer_virtual, __fc_itimer_prof;
-    assigns \result
-      \from (indirect: which), (indirect: new_value), (indirect: *new_value);
-    
-    behavior real:
-      assumes
-        itimer_real_and_valid:
-          which ≡ 0 ≤ new_value->it_value.tv_usec ≤ 999999 ∧
-          0 ≤ new_value->it_interval.tv_usec ≤ 999999;
-      ensures result_ok: \result ≡ 0;
-      ensures initialization: old_value: \initialized(\old(old_value));
-      assigns \result, *old_value, __fc_itimer_real;
-      assigns \result \from \nothing;
-      assigns *old_value \from __fc_itimer_real;
-      assigns __fc_itimer_real \from *new_value;
-    
-    behavior virtual:
-      assumes
-        itimer_virtual_and_valid:
-          which ≡ 1 ∧ 0 ≤ new_value->it_value.tv_usec ≤ 999999 ∧
-          0 ≤ new_value->it_interval.tv_usec ≤ 999999;
-      ensures result_ok: \result ≡ 0;
-      ensures initialization: old_value: \initialized(\old(old_value));
-      assigns \result, *old_value;
-      assigns \result \from \nothing;
-      assigns *old_value \from __fc_itimer_virtual;
-    
-    behavior prof:
-      assumes
-        itimer_prof_and_valid:
-          which ≡ 2 ∧ 0 ≤ new_value->it_value.tv_usec ≤ 999999 ∧
-          0 ≤ new_value->it_interval.tv_usec ≤ 999999;
-      ensures result_ok: \result ≡ 0;
-      ensures initialization: old_value: \initialized(\old(old_value));
-      assigns \result, *old_value;
-      assigns \result \from \nothing;
-      assigns *old_value \from __fc_itimer_prof;
-    
-    behavior invalid:
-      assumes
-        invalid_itimer_or_new_value:
-          (which ≢ 0 ∧ which ≢ 1 ∧ which ≢ 2) ∨
-          ¬(0 ≤ new_value->it_value.tv_usec ≤ 999999 ∧
-             0 ≤ new_value->it_interval.tv_usec ≤ 999999);
-      ensures result_error: \result ≡ -1;
-      assigns \result;
-      assigns \result \from \nothing;
-    
-    disjoint behaviors invalid, prof, virtual, real;
- */
-extern int setitimer(int which, struct itimerval const * restrict new_value,
-                     struct itimerval * restrict old_value);
-
 /*@ ghost int volatile __fc_fds_state; */
 /*@ requires nfds: nfds ≥ 0;
     requires readfs: readfds ≡ \null ∨ \valid(readfds);
@@ -8861,6 +8707,220 @@ extern void syslog(int __x0, char const *__x1, void * const *__va_params);
 /*@ assigns \nothing; */
 extern void vsyslog(int __x0, char const *__x1, va_list __x2);
 
+/*@ ghost extern int __fc_tz; */
+
+/*@ requires valid_path: valid_read_string(path);
+    requires
+      valid_times_or_null: \valid_read(times + (0 .. 1)) ∨ times ≡ \null;
+    assigns \result;
+    assigns \result
+      \from (indirect: *(path + (0 .. strlen{Old}(path)))),
+            (indirect: times), (indirect: *(times + (0 .. 1)));
+ */
+extern int utimes(char const *path, struct timeval const times[2]);
+
+/*@ ensures result_ok_or_error: \result ≡ 0 ∨ \result ≡ -1;
+    assigns tv->tv_sec, tv->tv_usec, *((struct timezone *)tz), \result;
+    assigns tv->tv_sec \from __fc_time;
+    assigns tv->tv_usec \from __fc_time;
+    assigns *((struct timezone *)tz) \from __fc_tz;
+    assigns \result
+      \from (indirect: tv), (indirect: tz), *tv, *((struct timezone *)tz),
+            __fc_tz;
+    
+    behavior tv_and_tz_null:
+      assumes null_tv_tz: tv ≡ \null ∧ tz ≡ \null;
+      assigns \result;
+      assigns \result \from (indirect: __fc_tz);
+    
+    behavior tv_not_null:
+      assumes non_null_tv_null_tz: tv ≢ \null ∧ tz ≡ \null;
+      ensures
+        initialization: tv_sec: tv_usec:
+          \initialized(&\old(tv)->tv_sec) ∧
+          \initialized(&\old(tv)->tv_usec);
+      ensures tv_usec_bounded: 0 ≤ \old(tv)->tv_usec ≤ 999999;
+      assigns tv->tv_sec, tv->tv_usec, \result;
+      assigns tv->tv_sec \from (indirect: __fc_time);
+      assigns tv->tv_usec \from (indirect: __fc_time);
+      assigns \result \from (indirect: *tv), (indirect: __fc_tz);
+    
+    behavior tz_not_null:
+      assumes null_tv_non_null_tz: tv ≡ \null ∧ tz ≢ \null;
+      ensures initialization: tz: \initialized((struct timezone *)\old(tz));
+      assigns *((struct timezone *)tz), \result;
+      assigns *((struct timezone *)tz) \from __fc_tz;
+      assigns \result
+        \from (indirect: *((struct timezone *)tz)), (indirect: __fc_tz);
+    
+    behavior tv_and_tz_not_null:
+      assumes non_null_tv_tz: tv ≢ \null ∧ tz ≢ \null;
+      ensures
+        initialization: tv_sec: tv_usec:
+          \initialized(&\old(tv)->tv_sec) ∧
+          \initialized(&\old(tv)->tv_usec);
+      ensures initialization: tz: \initialized((struct timezone *)\old(tz));
+      assigns tv->tv_sec, tv->tv_usec, *((struct timezone *)tz), \result;
+      assigns tv->tv_sec \from (indirect: __fc_time);
+      assigns tv->tv_usec \from (indirect: __fc_time);
+      assigns *((struct timezone *)tz) \from __fc_tz;
+      assigns \result
+        \from (indirect: *tv), (indirect: *((struct timezone *)tz)),
+              (indirect: __fc_tz);
+    
+    complete behaviors tv_and_tz_not_null,
+                       tz_not_null,
+                       tv_not_null,
+                       tv_and_tz_null;
+    disjoint behaviors tv_and_tz_not_null,
+                       tz_not_null,
+                       tv_not_null,
+                       tv_and_tz_null;
+ */
+extern int gettimeofday(struct timeval * restrict tv, void * restrict tz);
+
+/*@ requires valid_tv_or_null: \valid_read(tv) ∨ tv ≡ \null;
+    requires valid_tz_or_null: \valid_read(tz) ∨ tz ≡ \null;
+    ensures result_ok_or_error: \result ≡ 0 ∨ \result ≡ -1;
+    assigns __fc_time, __fc_tz, \result;
+    assigns __fc_time
+      \from tv->tv_sec, tv->tv_usec, tz->tz_dsttime, tz->tz_minuteswest;
+    assigns __fc_tz
+      \from tv->tv_sec, tv->tv_usec, tz->tz_dsttime, tz->tz_minuteswest;
+    assigns \result \from (indirect: *tv), (indirect: *tz);
+ */
+extern int settimeofday(struct timeval const *tv, struct timezone const *tz);
+
+/*@ ghost struct itimerval volatile __fc_itimer_real; */
+/*@ ghost struct itimerval volatile __fc_itimer_virtual; */
+/*@ ghost struct itimerval volatile __fc_itimer_prof; */
+/*@ requires valid_curr_value: \valid(curr_value);
+    ensures initialization: curr_value: \initialized(\old(curr_value));
+    assigns \result, *curr_value;
+    assigns \result \from (indirect: which);
+    assigns *curr_value
+      \from __fc_itimer_real, __fc_itimer_virtual, __fc_itimer_prof;
+    
+    behavior real:
+      assumes itimer_real: which ≡ 0;
+      ensures result_ok: \result ≡ 0;
+      assigns \result, *curr_value;
+      assigns \result \from \nothing;
+      assigns *curr_value \from __fc_itimer_real;
+    
+    behavior virtual:
+      assumes itimer_virtual: which ≡ 1;
+      ensures result_ok: \result ≡ 0;
+      assigns \result, *curr_value;
+      assigns \result \from \nothing;
+      assigns *curr_value \from __fc_itimer_virtual;
+    
+    behavior prof:
+      assumes itimer_prof: which ≡ 2;
+      ensures result_ok: \result ≡ 0;
+      assigns \result, *curr_value;
+      assigns \result \from \nothing;
+      assigns *curr_value \from __fc_itimer_prof;
+    
+    behavior invalid:
+      assumes invalid_which: which ≢ 0 ∧ which ≢ 1 ∧ which ≢ 2;
+      ensures result_error: \result ≡ -1;
+      assigns \result;
+      assigns \result \from \nothing;
+    
+    complete behaviors invalid, prof, virtual, real;
+    disjoint behaviors invalid, prof, virtual, real;
+ */
+extern int getitimer(int which, struct itimerval *curr_value);
+
+/*@ requires valid_new_value: \valid_read(new_value);
+    requires
+      old_value_null_or_valid: old_value ≡ \null ∨ \valid(old_value);
+    ensures result_ok_or_error: \result ≡ 0 ∨ \result ≡ -1;
+    assigns *old_value, \result;
+    assigns *old_value
+      \from (indirect: which), (indirect: old_value), (indirect: new_value),
+            __fc_itimer_real, __fc_itimer_virtual, __fc_itimer_prof;
+    assigns \result
+      \from (indirect: which), (indirect: new_value), (indirect: *new_value);
+    
+    behavior real:
+      assumes
+        itimer_real_and_valid:
+          which ≡ 0 ≤ new_value->it_value.tv_usec ≤ 999999 ∧
+          0 ≤ new_value->it_interval.tv_usec ≤ 999999;
+      ensures result_ok: \result ≡ 0;
+      ensures initialization: old_value: \initialized(\old(old_value));
+      assigns \result, *old_value, __fc_itimer_real;
+      assigns \result \from \nothing;
+      assigns *old_value \from __fc_itimer_real;
+      assigns __fc_itimer_real \from *new_value;
+    
+    behavior virtual:
+      assumes
+        itimer_virtual_and_valid:
+          which ≡ 1 ∧ 0 ≤ new_value->it_value.tv_usec ≤ 999999 ∧
+          0 ≤ new_value->it_interval.tv_usec ≤ 999999;
+      ensures result_ok: \result ≡ 0;
+      ensures initialization: old_value: \initialized(\old(old_value));
+      assigns \result, *old_value;
+      assigns \result \from \nothing;
+      assigns *old_value \from __fc_itimer_virtual;
+    
+    behavior prof:
+      assumes
+        itimer_prof_and_valid:
+          which ≡ 2 ∧ 0 ≤ new_value->it_value.tv_usec ≤ 999999 ∧
+          0 ≤ new_value->it_interval.tv_usec ≤ 999999;
+      ensures result_ok: \result ≡ 0;
+      ensures initialization: old_value: \initialized(\old(old_value));
+      assigns \result, *old_value;
+      assigns \result \from \nothing;
+      assigns *old_value \from __fc_itimer_prof;
+    
+    behavior invalid:
+      assumes
+        invalid_itimer_or_new_value:
+          (which ≢ 0 ∧ which ≢ 1 ∧ which ≢ 2) ∨
+          ¬(0 ≤ new_value->it_value.tv_usec ≤ 999999 ∧
+             0 ≤ new_value->it_interval.tv_usec ≤ 999999);
+      ensures result_error: \result ≡ -1;
+      assigns \result;
+      assigns \result \from \nothing;
+    
+    disjoint behaviors invalid, prof, virtual, real;
+ */
+extern int setitimer(int which, struct itimerval const * restrict new_value,
+                     struct itimerval * restrict old_value);
+
+/*@ requires valid_fdset: \valid(fdset);
+    requires initialization: \initialized(fdset);
+    assigns *fdset;
+    assigns *fdset \from *fdset, (indirect: fd);
+ */
+extern void FD_CLR(int fd, fd_set *fdset);
+
+/*@ requires valid_fdset: \valid_read(fdset);
+    requires initialization: \initialized(fdset);
+    assigns \result;
+    assigns \result \from (indirect: *fdset), (indirect: fd);
+ */
+extern int FD_ISSET(int fd, fd_set const *fdset);
+
+/*@ requires valid_fdset: \valid(fdset);
+    requires initialization: \initialized(fdset);
+    assigns *fdset;
+    assigns *fdset \from *fdset, (indirect: fd);
+ */
+extern void FD_SET(int fd, fd_set *fdset);
+
+/*@ requires valid_fdset: \valid(fdset);
+    ensures initialization: \initialized(\old(fdset));
+    assigns *fdset;
+    assigns *fdset \from \nothing;
+ */
+extern void FD_ZERO(fd_set *fdset);
+
 /*@ assigns \result;
     assigns \result \from which, who; */
 extern int getpriority(int which, id_t who);
diff --git a/tests/libc/oracle/fc_libc.2.res.oracle b/tests/libc/oracle/fc_libc.2.res.oracle
index 815b277af9e8e3fecf6f395a1b1b023ea8dd3ffa..eca9057a10e161facaeb91f1b8b069d8788ad038 100644
--- a/tests/libc/oracle/fc_libc.2.res.oracle
+++ b/tests/libc/oracle/fc_libc.2.res.oracle
@@ -6,6 +6,7 @@
 [kernel] Parsing share/libc/__fc_define_dev_t.h (with preprocessing)
 [kernel] Parsing share/libc/__fc_define_eof.h (with preprocessing)
 [kernel] Parsing share/libc/__fc_define_fd_set_t.h (with preprocessing)
+[kernel] Parsing share/libc/__fc_define_fds.h (with preprocessing)
 [kernel] Parsing share/libc/__fc_define_file.h (with preprocessing)
 [kernel] Parsing share/libc/__fc_define_fpos_t.h (with preprocessing)
 [kernel] Parsing share/libc/__fc_define_fs_cnt.h (with preprocessing)
@@ -32,6 +33,7 @@
 [kernel] Parsing share/libc/__fc_define_time_t.h (with preprocessing)
 [kernel] Parsing share/libc/__fc_define_timer_t.h (with preprocessing)
 [kernel] Parsing share/libc/__fc_define_timespec.h (with preprocessing)
+[kernel] Parsing share/libc/__fc_define_timeval.h (with preprocessing)
 [kernel] Parsing share/libc/__fc_define_uid_and_gid.h (with preprocessing)
 [kernel] Parsing share/libc/__fc_define_useconds_t.h (with preprocessing)
 [kernel] Parsing share/libc/__fc_define_wchar_t.h (with preprocessing)
diff --git a/tests/libc/oracle/netdb_c.res.oracle b/tests/libc/oracle/netdb_c.res.oracle
index 75b421147917c7fdf6b9f9bcbd1001f867f21829..884473c2427f4106a9d6c5fded60ee06f15b1c86 100644
--- a/tests/libc/oracle/netdb_c.res.oracle
+++ b/tests/libc/oracle/netdb_c.res.oracle
@@ -317,8 +317,8 @@
 [eva:final-states] Values at end of function main:
   __fc_errno ∈ [--..--]
   __fc_heap_status ∈ [--..--]
+  __fc_fds[0..1023] ∈ [--..--]
   Frama_C_entropy_source ∈ [--..--]
-  __fc_fds[0..1023] ∈ {0}
   __fc_sockfds[0..1023] ∈ [--..--]
   __fc_socket_counter ∈ [--..--]
   __fc_ghbn.host.h_name ∈ {{ NULL ; &__fc_ghbn.hostbuf[0] }}
diff --git a/tests/libc/oracle/socket.0.res.oracle b/tests/libc/oracle/socket.0.res.oracle
index c0f9285b9913c93af17f9c46cecdd5f9e2b994d1..276fcf21362da709bfb1e3539c7ad646d8272d88 100644
--- a/tests/libc/oracle/socket.0.res.oracle
+++ b/tests/libc/oracle/socket.0.res.oracle
@@ -68,24 +68,20 @@
 [eva] Done for function test_read
 [eva] computing for function test_readv <- main.
   Called from tests/libc/socket.c:127.
-[eva] computing for function init_reception <- test_readv <- main.
-  Called from tests/libc/socket.c:68.
-[eva] computing for function bzero <- init_reception <- test_readv <- main.
-  Called from tests/libc/socket.c:43.
-[eva] Done for function bzero
-[eva] computing for function write <- init_reception <- test_readv <- main.
-  Called from tests/libc/socket.c:44.
-[eva] Done for function write
-[eva] Recording results for init_reception
-[eva] Done for function init_reception
+[eva] tests/libc/socket.c:68: Reusing old results for call to init_reception
 [eva] computing for function readv <- test_readv <- main.
   Called from tests/libc/socket.c:69.
 [eva] using specification for function readv
 [eva] tests/libc/socket.c:69: 
-  function readv: precondition 'valid_read_iov' got status valid.
-[eva] share/libc/sys/uio.h:37: Warning: 
-  no \from part
-  for clause 'assigns *((char *)(iov + (0 .. iovcnt - 1))->iov_base + (0 ..));'
+  function readv: precondition 'valid_fd' got status valid.
+[eva] tests/libc/socket.c:69: 
+  function readv: precondition 'initialization,initialized_inputs' got status valid.
+[eva] tests/libc/socket.c:69: 
+  function readv: precondition 'valid_iov' got status valid.
+[eva] tests/libc/socket.c:69: 
+  function readv: precondition 'bounded_iovcnt' got status valid.
+[eva] share/libc/sys/uio.h:52: 
+  cannot evaluate ACSL term, unsupported ACSL construct: logic function \sum
 [eva] Done for function readv
 [eva:alarm] tests/libc/socket.c:72: Warning: 
   accessing uninitialized left-value.
@@ -240,8 +236,8 @@
                             [2].iov_len ∈ {3}
   S___fc_stdout[0..1] ∈ [--..--]
 [eva:final-states] Values at end of function test_recvmsg:
-  __fc_sockfds[0..1023] ∈ [--..--]
   __fc_fds[0..1023] ∈ [--..--]
+  __fc_sockfds[0..1023] ∈ [--..--]
   rcv_buffer[0..9] ∈ {0}
   rcv_buffer_scattered1[0] ∈ [--..--]
                        [1] ∈ [--..--] or UNINITIALIZED
@@ -265,9 +261,9 @@
      .msg_flags ∈ [--..--] or UNINITIALIZED
   S___fc_stdout[0..1] ∈ [--..--]
 [eva:final-states] Values at end of function test_server_echo:
+  __fc_fds[0..1023] ∈ [--..--]
   __fc_sockfds[0..1023] ∈ [--..--]
   __fc_socket_counter ∈ [--..--]
-  __fc_fds[0..1023] ∈ [--..--]
   fd ∈ [-1..1023]
   addr ∈ [--..--] or UNINITIALIZED
   addrlen ∈ {8}
@@ -276,9 +272,9 @@
   r ∈ [-1..64]
   __retres ∈ {0; 1; 5; 20; 100; 200; 300; 400}
 [eva:final-states] Values at end of function main:
+  __fc_fds[0..1023] ∈ [--..--]
   __fc_sockfds[0..1023] ∈ [--..--]
   __fc_socket_counter ∈ [--..--]
-  __fc_fds[0..1023] ∈ [--..--]
   rcv_buffer[0..9] ∈ {0}
   socket_fd[0..1] ∈ [0..1023]
   r ∈ {0; 1; 5; 20; 100; 200; 300; 400}
diff --git a/tests/libc/oracle/socket.1.res.oracle b/tests/libc/oracle/socket.1.res.oracle
index a60c6913b0fb68fee18a85d1c2bc363f9fadb3a7..82d1a5a2090728ffd2cadaba116d11e3f9084d6a 100644
--- a/tests/libc/oracle/socket.1.res.oracle
+++ b/tests/libc/oracle/socket.1.res.oracle
@@ -68,24 +68,20 @@
 [eva] Done for function test_read
 [eva] computing for function test_readv <- main.
   Called from tests/libc/socket.c:127.
-[eva] computing for function init_reception <- test_readv <- main.
-  Called from tests/libc/socket.c:68.
-[eva] computing for function bzero <- init_reception <- test_readv <- main.
-  Called from tests/libc/socket.c:43.
-[eva] Done for function bzero
-[eva] computing for function write <- init_reception <- test_readv <- main.
-  Called from tests/libc/socket.c:44.
-[eva] Done for function write
-[eva] Recording results for init_reception
-[eva] Done for function init_reception
+[eva] tests/libc/socket.c:68: Reusing old results for call to init_reception
 [eva] computing for function readv <- test_readv <- main.
   Called from tests/libc/socket.c:69.
 [eva] using specification for function readv
 [eva] tests/libc/socket.c:69: 
-  function readv: precondition 'valid_read_iov' got status valid.
-[eva] share/libc/sys/uio.h:37: Warning: 
-  no \from part
-  for clause 'assigns *((char *)(iov + (0 .. iovcnt - 1))->iov_base + (0 ..));'
+  function readv: precondition 'valid_fd' got status valid.
+[eva] tests/libc/socket.c:69: 
+  function readv: precondition 'initialization,initialized_inputs' got status valid.
+[eva] tests/libc/socket.c:69: 
+  function readv: precondition 'valid_iov' got status valid.
+[eva] tests/libc/socket.c:69: 
+  function readv: precondition 'bounded_iovcnt' got status valid.
+[eva] share/libc/sys/uio.h:52: 
+  cannot evaluate ACSL term, unsupported ACSL construct: logic function \sum
 [eva] Done for function readv
 [eva:alarm] tests/libc/socket.c:72: Warning: 
   accessing uninitialized left-value.
@@ -240,8 +236,8 @@
                             [2].iov_len ∈ {3}
   S___fc_stdout[0..1] ∈ [--..--]
 [eva:final-states] Values at end of function test_recvmsg:
-  __fc_sockfds[0..1023] ∈ [--..--]
   __fc_fds[0..1023] ∈ [--..--]
+  __fc_sockfds[0..1023] ∈ [--..--]
   rcv_buffer[0..9] ∈ {0}
   rcv_buffer_scattered1[0] ∈ [--..--]
                        [1] ∈ [--..--] or UNINITIALIZED
@@ -267,9 +263,9 @@
      .msg_flags ∈ [--..--] or UNINITIALIZED
   S___fc_stdout[0..1] ∈ [--..--]
 [eva:final-states] Values at end of function test_server_echo:
+  __fc_fds[0..1023] ∈ [--..--]
   __fc_sockfds[0..1023] ∈ [--..--]
   __fc_socket_counter ∈ [--..--]
-  __fc_fds[0..1023] ∈ [--..--]
   fd ∈ [-1..1023]
   addr ∈ [--..--] or UNINITIALIZED
   addrlen ∈ {8}
@@ -278,9 +274,9 @@
   r ∈ [-1..64]
   __retres ∈ {0; 1; 5; 20; 100; 200; 300; 400}
 [eva:final-states] Values at end of function main:
+  __fc_fds[0..1023] ∈ [--..--]
   __fc_sockfds[0..1023] ∈ [--..--]
   __fc_socket_counter ∈ [--..--]
-  __fc_fds[0..1023] ∈ [--..--]
   rcv_buffer[0..9] ∈ {0}
   socket_fd[0..1] ∈ [0..1023]
   r ∈ {0; 1; 5; 20; 100; 200; 300; 400}
diff --git a/tests/libc/oracle/sys_uio_h.res.oracle b/tests/libc/oracle/sys_uio_h.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..feee0f8a0d4570603b66fd56bf5d8a7389ebe5d3
--- /dev/null
+++ b/tests/libc/oracle/sys_uio_h.res.oracle
@@ -0,0 +1,112 @@
+[kernel] Parsing tests/libc/sys_uio_h.c (with preprocessing)
+[eva] Analyzing a complete application starting at main
+[eva] Computing initial state
+[eva] Initial state computed
+[eva:initial-state] Values of globals at initialization
+  nondet ∈ [--..--]
+[eva] computing for function __va_open_mode_t <- main.
+  Called from tests/libc/sys_uio_h.c:17.
+[eva] using specification for function __va_open_mode_t
+[eva] tests/libc/sys_uio_h.c:17: 
+  function __va_open_mode_t: precondition 'valid_filename' got status valid.
+[eva] Done for function __va_open_mode_t
+[eva] tests/libc/sys_uio_h.c:19: assertion got status valid.
+[eva] tests/libc/sys_uio_h.c:20: assertion got status valid.
+[eva] tests/libc/sys_uio_h.c:21: assertion got status valid.
+[eva] computing for function writev <- main.
+  Called from tests/libc/sys_uio_h.c:22.
+[eva] using specification for function writev
+[eva] tests/libc/sys_uio_h.c:22: 
+  function writev: precondition 'valid_fd' got status valid.
+[eva] tests/libc/sys_uio_h.c:22: 
+  function writev: precondition 'initialization,initialized_inputs' got status valid.
+[eva] tests/libc/sys_uio_h.c:22: 
+  function writev: precondition 'valid_read_iov' got status valid.
+[eva:alarm] tests/libc/sys_uio_h.c:22: Warning: 
+  function writev: precondition 'valid_read_iov_bases' got status unknown.
+[eva] tests/libc/sys_uio_h.c:22: 
+  function writev: precondition 'bounded_iovcnt' got status valid.
+[eva] share/libc/sys/uio.h:67: 
+  cannot evaluate ACSL term, unsupported ACSL construct: logic function \sum
+[eva:alarm] tests/libc/sys_uio_h.c:22: Warning: 
+  function writev: precondition 'bounded_lengths' got status unknown.
+[eva] share/libc/sys/uio.h:72: 
+  cannot evaluate ACSL term, unsupported ACSL construct: logic function \sum
+[eva] Done for function writev
+[eva] computing for function close <- main.
+  Called from tests/libc/sys_uio_h.c:23.
+[eva] using specification for function close
+[eva] tests/libc/sys_uio_h.c:23: 
+  function close: precondition 'valid_fd' got status valid.
+[eva] Done for function close
+[eva] computing for function __va_open_void <- main.
+  Called from tests/libc/sys_uio_h.c:24.
+[eva] using specification for function __va_open_void
+[eva] tests/libc/sys_uio_h.c:24: 
+  function __va_open_void: precondition 'valid_filename' got status valid.
+[eva] tests/libc/sys_uio_h.c:24: 
+  function __va_open_void: precondition 'flag_not_CREAT' got status valid.
+[eva] Done for function __va_open_void
+[eva] computing for function readv <- main.
+  Called from tests/libc/sys_uio_h.c:25.
+[eva] using specification for function readv
+[eva:alarm] tests/libc/sys_uio_h.c:25: Warning: 
+  function readv: precondition 'valid_fd' got status unknown.
+[eva] tests/libc/sys_uio_h.c:25: 
+  function readv: precondition 'initialization,initialized_inputs' got status valid.
+[eva:alarm] tests/libc/sys_uio_h.c:25: Warning: 
+  function readv: precondition 'valid_iov' got status unknown.
+[eva] tests/libc/sys_uio_h.c:25: 
+  function readv: precondition 'bounded_iovcnt' got status valid.
+[eva] share/libc/sys/uio.h:52: 
+  cannot evaluate ACSL term, unsupported ACSL construct: logic function \sum
+[eva] Done for function readv
+[eva] computing for function close <- main.
+  Called from tests/libc/sys_uio_h.c:26.
+[eva] tests/libc/sys_uio_h.c:26: 
+  function close: precondition 'valid_fd' got status valid.
+[eva] Done for function close
+[eva] computing for function __va_open_mode_t <- main.
+  Called from tests/libc/sys_uio_h.c:37.
+[eva] tests/libc/sys_uio_h.c:37: 
+  function __va_open_mode_t: precondition 'valid_filename' got status valid.
+[eva] Done for function __va_open_mode_t
+[eva] computing for function writev <- main.
+  Called from tests/libc/sys_uio_h.c:39.
+[eva] tests/libc/sys_uio_h.c:39: 
+  function writev: precondition 'valid_fd' got status valid.
+[eva] tests/libc/sys_uio_h.c:39: 
+  function writev: precondition 'initialization,initialized_inputs' got status valid.
+[eva] tests/libc/sys_uio_h.c:39: 
+  function writev: precondition 'valid_read_iov' got status valid.
+[eva:alarm] tests/libc/sys_uio_h.c:39: Warning: 
+  function writev: precondition 'valid_read_iov_bases' got status unknown.
+[eva] tests/libc/sys_uio_h.c:39: 
+  function writev: precondition 'bounded_iovcnt' got status valid.
+[eva:alarm] tests/libc/sys_uio_h.c:39: Warning: 
+  function writev: precondition 'bounded_lengths' got status unknown.
+[eva] Done for function writev
+[eva:alarm] tests/libc/sys_uio_h.c:40: Warning: 
+  assertion 'unreachable' got status invalid (stopping propagation).
+[eva:alarm] tests/libc/sys_uio_h.c:43: Warning: 
+  signed overflow. assert w + r ≤ 2147483647;
+[eva] Recording results for main
+[eva] done for function main
+[eva] ====== VALUES COMPUTED ======
+[eva:final-states] Values at end of function main:
+  __fc_fds[0..1023] ∈ [--..--]
+  str ∈ {{ "A small string" }}
+  empty_buf ∈ {0}
+  buf[0..9] ∈ [--..--]
+  buf2[0..13] ∈ [--..--] or UNINITIALIZED
+  v[0].iov_base ∈ {{ "A small string" }}
+   [0].iov_len ∈ {15}
+   [1] ∈ {0}
+   [2].iov_base ∈ {{ (void *)&buf }}
+   [2].iov_len ∈ {10}
+   [3].iov_base ∈ {{ (void *)&buf2 }}
+   [3].iov_len ∈ {14}
+  fd ∈ [-1..1023]
+  w ∈ [-1..2147483647]
+  r ∈ [-1..2147483647]
+  __retres ∈ [-2..2147483647]
diff --git a/tests/libc/oracle/unistd_h.0.res.oracle b/tests/libc/oracle/unistd_h.0.res.oracle
index 55e6a1c528de73a57f89e7f4b640206bc2f38233..5173981ab82804e60d054d1f19aea51cd3f81bc2 100644
--- a/tests/libc/oracle/unistd_h.0.res.oracle
+++ b/tests/libc/oracle/unistd_h.0.res.oracle
@@ -570,9 +570,8 @@
 [eva] done for function main
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main:
+  __fc_fds[0..1023] ∈ [--..--]
   Frama_C_entropy_source ∈ [--..--]
-  __fc_fds[0] ∈ {0}
-          [1..1023] ∈ [--..--]
   r ∈ {-1; 0}
   hostname[0..255] ∈ [--..--] or UNINITIALIZED
   fd ∈ [-1..1023]
diff --git a/tests/libc/oracle/unistd_h.1.res.oracle b/tests/libc/oracle/unistd_h.1.res.oracle
index 1ce6be573a566003223a378d330cfdb7e4c1744b..fa6d33a9d1b05edf653138dc9d4527f5421f3532 100644
--- a/tests/libc/oracle/unistd_h.1.res.oracle
+++ b/tests/libc/oracle/unistd_h.1.res.oracle
@@ -570,9 +570,8 @@
 [eva] done for function main
 [eva] ====== VALUES COMPUTED ======
 [eva:final-states] Values at end of function main:
+  __fc_fds[0..1023] ∈ [--..--]
   Frama_C_entropy_source ∈ [--..--]
-  __fc_fds[0] ∈ {0}
-          [1..1023] ∈ [--..--]
   r ∈ {-1; 0}
   hostname[0..255] ∈ [--..--] or UNINITIALIZED
   fd ∈ [-1..1023]
diff --git a/tests/libc/sys_uio_h.c b/tests/libc/sys_uio_h.c
new file mode 100644
index 0000000000000000000000000000000000000000..2bde83999ac582c7c96456c572735e9c3ceef108
--- /dev/null
+++ b/tests/libc/sys_uio_h.c
@@ -0,0 +1,44 @@
+#include <sys/uio.h>
+#include <unistd.h>
+#include <fcntl.h>
+volatile int nondet;
+int main() {
+  char *str = "A small string";
+  char *empty_buf = 0;
+  char buf[10] = "\n\n\nbuffer";
+  char buf2[14];
+  struct iovec v[4] =
+    {
+     {str, 15},
+     {empty_buf, 0},
+     {buf, 10},
+     {buf2, 14},
+    };
+  int fd = open("/tmp/uio.txt", O_WRONLY | O_CREAT, 0660);
+  if (fd < 0) return 1;
+  //@ assert \valid_read(((char*)v[0].iov_base) + (0 .. v[0].iov_len-1));
+  //@ assert \valid_read(((char*)v[1].iov_base) + (0 .. v[1].iov_len-1));
+  //@ assert \valid_read(((char*)v[2].iov_base) + (0 .. v[2].iov_len-1));
+  ssize_t w = writev(fd, v, 3);
+  close(fd);
+  fd = open("/tmp/uio.txt", O_RDONLY);
+  ssize_t r = readv(fd, v+2, 2);
+  close(fd);
+
+  if (nondet) {
+    char buf3[10] = "\n\n\nbuffer";
+    char buf4[14];
+    struct iovec v2[4] =
+      {
+        {str, 15},
+        {empty_buf, 0},
+        {buf3, 11}, // invalid length
+      };
+    int fd2 = open("/tmp/uio2.txt", O_WRONLY | O_CREAT, 0660);
+    if (fd2 < 0) return 1;
+    ssize_t w = writev(fd2, v2, 3); // must fail
+    //@ assert unreachable: \false;
+  }
+
+  return w + r;
+}
diff --git a/tests/metrics/oracle/libc.1.res.oracle b/tests/metrics/oracle/libc.1.res.oracle
index a57305d1570190ba61230b014b4c0bec1da423ae..189a5298dc644b531bbc585f569754593b007010 100644
--- a/tests/metrics/oracle/libc.1.res.oracle
+++ b/tests/metrics/oracle/libc.1.res.oracle
@@ -44,10 +44,11 @@
   =======================================
    
   
-  'Extern' global variables (11)
+  'Extern' global variables (12)
   ==============================
-   Frama_C_entropy_source; __fc_errno; __fc_heap_status; __fc_hostname;
-   __fc_stdin; __fc_stdout; __fc_ttyname; optarg; opterr; optind; optopt
+   Frama_C_entropy_source; __fc_errno; __fc_fds; __fc_heap_status;
+   __fc_hostname; __fc_stdin; __fc_stdout; __fc_ttyname; optarg; opterr;
+   optind; optopt
   
   Potential entry points (2)
   ==========================
diff --git a/tests/metrics/oracle/libc.json b/tests/metrics/oracle/libc.json
index afe73bccdad6b27be86cc5b509fb01fda44e6ce4..de14067e7a65d53a82dd943adb71c6cb31536f68 100644
--- a/tests/metrics/oracle/libc.json
+++ b/tests/metrics/oracle/libc.json
@@ -136,7 +136,7 @@
   ],
   "undefined-functions": [],
   "extern-global-vars": [
-    "Frama_C_entropy_source", "__fc_errno", "__fc_heap_status",
+    "Frama_C_entropy_source", "__fc_errno", "__fc_fds", "__fc_heap_status",
     "__fc_hostname", "__fc_stdin", "__fc_stdout", "__fc_ttyname", "optarg",
     "opterr", "optind", "optopt"
   ],
diff --git a/tests/misc/oracle/interpreted_automata_dataflow_backward.dot b/tests/misc/oracle/interpreted_automata_dataflow_backward.dot
index 47e6019ac1093ecdc6ea36d337a1a351c2cb8f0d..90f737cafe26b8a2a85f1a103dadd5cf611984da 100644
--- a/tests/misc/oracle/interpreted_automata_dataflow_backward.dot
+++ b/tests/misc/oracle/interpreted_automata_dataflow_backward.dot
@@ -4,77 +4,73 @@ digraph G {
   cp1 [label=<x>, ];
   cp2 [label=< >, ];
   cp3 [label=<x>, ];
-  cp4 [label=< >, ];
+  cp4 [label=<x, y>, ];
   cp5 [label=<x, y>, ];
   cp6 [label=<x, y>, ];
-  cp7 [label=<x, y>, ];
-  cp8 [label=<x>, ];
-  cp9 [label=<x, a>, ];
-  cp10 [label=<x>, ];
-  cp11 [label=<x, a>, ];
-  cp12 [label=<x>, ];
+  cp7 [label=<x>, ];
+  cp8 [label=<x, a>, ];
+  cp9 [label=<x>, ];
+  cp10 [label=<x, a>, ];
+  cp11 [label=<x>, ];
+  cp12 [label=<x, a, i>, ];
   cp13 [label=<x, a, i>, ];
-  cp14 [label=<x, a, i>, ];
-  cp15 [label=<x, a, i>, shape=invtriangle, ];
+  cp14 [label=<x, a, i>, shape=invtriangle, ];
+  cp15 [label=<x, a, i>, ];
   cp16 [label=<x, a, i>, ];
   cp17 [label=<x, a, i>, ];
-  cp18 [label=<x, a, i>, ];
+  cp18 [label=<x>, ];
   cp19 [label=<x>, ];
-  cp20 [label=<x>, ];
+  cp20 [label=<x, a, i>, ];
   cp21 [label=<x, a, i>, ];
   cp22 [label=<x, a, i>, ];
   cp23 [label=<x, a, i>, ];
   cp24 [label=<x, a, i>, ];
-  cp25 [label=<x, a, i>, ];
-  cp26 [label=<x, a, i>, ];
+  cp25 [label=< >, ];
+  cp26 [label=< >, ];
   cp27 [label=< >, ];
   cp28 [label=< >, ];
   cp29 [label=< >, ];
   cp30 [label=< >, ];
-  cp31 [label=< >, ];
-  cp32 [label=< >, ];
+  cp31 [label=<x>, ];
+  cp32 [label=<x>, ];
   cp33 [label=<x>, ];
-  cp34 [label=<x>, ];
-  cp35 [label=<x>, ];
   
-  subgraph cluster_1 { cp26;cp25;cp24;cp23;cp22;cp18;cp17;cp16;cp15;cp14;
+  subgraph cluster_1 { cp24;cp23;cp22;cp21;cp20;cp17;cp16;cp15;cp14;cp13;
      };
   
   cp1 -> cp3 [label=<Enter y, z, w, a>, ];
-  cp3 -> cp5 [label=<int y = 3;>, ];
-  cp4 -> cp2 [label=<Exit y, z, w, a>, ];
-  cp5 -> cp6 [label=<y *= 2;>, ];
-  cp6 -> cp7 [label=<int z = y + 1;>, ];
-  cp7 -> cp8 [label=<int w = y + x;>, ];
-  cp8 -> cp9 [label=<int a = 1;>, ];
-  cp9 -> cp11 [label=<Enter i>, ];
-  cp10 -> cp28 [label=<x != 3>, ];
-  cp10 -> cp29 [label=<!(x != 3)>, ];
-  cp11 -> cp13 [label=<int i = 0;>, ];
-  cp12 -> cp10 [label=<Exit i>, ];
-  cp13 -> cp14 [label=< >, ];
-  cp14 -> cp15 [constraint=false, label=<Enter >, ];
-  cp15 -> cp18 [label=<i &lt; 10>, ];
-  cp15 -> cp19 [label=<!(i &lt; 10)>, ];
-  cp16 -> cp14 [label=<Exit >, ];
-  cp17 -> cp23 [label=<Enter b, c>, ];
-  cp18 -> cp17 [label=< >, ];
-  cp19 -> cp20 [label=<Enter >, ];
-  cp20 -> cp33 [label=< >, ];
-  cp21 -> cp17 [label=<Exit >, ];
-  cp22 -> cp16 [label=<i ++;>, ];
-  cp23 -> cp25 [label=<int b = 3;>, ];
-  cp24 -> cp22 [label=<Exit b, c>, ];
-  cp25 -> cp26 [label=<int c = i + 1;>, ];
-  cp26 -> cp24 [label=<a ++;>, ];
-  cp27 -> cp32 [label=<return>, ];
-  cp28 -> cp30 [label=<Enter >, ];
-  cp29 -> cp27 [label=< >, ];
-  cp30 -> cp31 [label=<x = 3;>, ];
-  cp31 -> cp27 [label=<Exit >, ];
-  cp32 -> cp2 [label=<Exit y, z, w, a>, ];
-  cp33 -> cp34 [label=<Exit i>, ];
-  cp34 -> cp35 [label=<Exit >, ];
-  cp35 -> cp10 [label=<Exit >, ];
+  cp3 -> cp4 [label=<int y = 3;>, ];
+  cp4 -> cp5 [label=<y *= 2;>, ];
+  cp5 -> cp6 [label=<int z = y + 1;>, ];
+  cp6 -> cp7 [label=<int w = y + x;>, ];
+  cp7 -> cp8 [label=<int a = 1;>, ];
+  cp8 -> cp10 [label=<Enter i>, ];
+  cp9 -> cp26 [label=<x != 3>, ];
+  cp9 -> cp27 [label=<!(x != 3)>, ];
+  cp10 -> cp12 [label=<int i = 0;>, ];
+  cp11 -> cp9 [label=<Exit i>, ];
+  cp12 -> cp13 [label=< >, ];
+  cp13 -> cp14 [constraint=false, label=<Enter >, ];
+  cp14 -> cp17 [label=<i &lt; 10>, ];
+  cp14 -> cp18 [label=<!(i &lt; 10)>, ];
+  cp15 -> cp13 [label=<Exit >, ];
+  cp16 -> cp21 [label=<Enter b, c>, ];
+  cp17 -> cp16 [label=< >, ];
+  cp18 -> cp19 [label=<Enter >, ];
+  cp19 -> cp31 [label=< >, ];
+  cp20 -> cp15 [label=<i ++;>, ];
+  cp21 -> cp23 [label=<int b = 3;>, ];
+  cp22 -> cp20 [label=<Exit b, c>, ];
+  cp23 -> cp24 [label=<int c = i + 1;>, ];
+  cp24 -> cp22 [label=<a ++;>, ];
+  cp25 -> cp30 [label=<return>, ];
+  cp26 -> cp28 [label=<Enter >, ];
+  cp27 -> cp25 [label=< >, ];
+  cp28 -> cp29 [label=<x = 3;>, ];
+  cp29 -> cp25 [label=<Exit >, ];
+  cp30 -> cp2 [label=<Exit y, z, w, a>, ];
+  cp31 -> cp32 [label=<Exit i>, ];
+  cp32 -> cp33 [label=<Exit >, ];
+  cp33 -> cp9 [label=<Exit >, ];
   
   }
\ No newline at end of file
diff --git a/tests/misc/oracle/interpreted_automata_dataflow_forward.dot b/tests/misc/oracle/interpreted_automata_dataflow_forward.dot
index 65c37595f4a46b8fde1a551920de17f3ecb8e92a..715c5beae70f84dfde5c5e293af5ab22b7f2c25f 100644
--- a/tests/misc/oracle/interpreted_automata_dataflow_forward.dot
+++ b/tests/misc/oracle/interpreted_automata_dataflow_forward.dot
@@ -4,77 +4,73 @@ digraph G {
   cp1 [label=< >, ];
   cp2 [label=<x: 3<br />y: 6<br />z: 7>, ];
   cp3 [label=< >, ];
-  cp4 [label=<⊥>, style="dashed", ];
-  cp5 [label=<y: 3>, ];
-  cp6 [label=<y: 6>, ];
+  cp4 [label=<y: 3>, ];
+  cp5 [label=<y: 6>, ];
+  cp6 [label=<y: 6<br />z: 7>, ];
   cp7 [label=<y: 6<br />z: 7>, ];
-  cp8 [label=<y: 6<br />z: 7>, ];
-  cp9 [label=<y: 6<br />z: 7<br />a: 1>, ];
-  cp10 [label=<y: 6<br />z: 7>, ];
-  cp11 [label=<y: 6<br />z: 7<br />a: 1>, ];
-  cp12 [label=<⊥>, style="dashed", ];
-  cp13 [label=<y: 6<br />z: 7<br />a: 1<br />i: 0>, ];
-  cp14 [label=<y: 6<br />z: 7>, shape=invtriangle, ];
-  cp15 [label=<y: 6<br />z: 7>, ];
-  cp16 [label=<y: 6<br />z: 7<br />b: 3>, ];
+  cp8 [label=<y: 6<br />z: 7<br />a: 1>, ];
+  cp9 [label=<y: 6<br />z: 7>, ];
+  cp10 [label=<y: 6<br />z: 7<br />a: 1>, ];
+  cp11 [label=<⊥>, style="dashed", ];
+  cp12 [label=<y: 6<br />z: 7<br />a: 1<br />i: 0>, ];
+  cp13 [label=<y: 6<br />z: 7>, shape=invtriangle, ];
+  cp14 [label=<y: 6<br />z: 7>, ];
+  cp15 [label=<y: 6<br />z: 7<br />b: 3>, ];
+  cp16 [label=<y: 6<br />z: 7>, ];
   cp17 [label=<y: 6<br />z: 7>, ];
   cp18 [label=<y: 6<br />z: 7>, ];
   cp19 [label=<y: 6<br />z: 7>, ];
-  cp20 [label=<y: 6<br />z: 7>, ];
-  cp21 [label=<⊥>, style="dashed", ];
+  cp20 [label=<y: 6<br />z: 7<br />b: 3>, ];
+  cp21 [label=<y: 6<br />z: 7>, ];
   cp22 [label=<y: 6<br />z: 7<br />b: 3>, ];
-  cp23 [label=<y: 6<br />z: 7>, ];
+  cp23 [label=<y: 6<br />z: 7<br />b: 3>, ];
   cp24 [label=<y: 6<br />z: 7<br />b: 3>, ];
-  cp25 [label=<y: 6<br />z: 7<br />b: 3>, ];
-  cp26 [label=<y: 6<br />z: 7<br />b: 3>, ];
+  cp25 [label=<x: 3<br />y: 6<br />z: 7>, ];
+  cp26 [label=<y: 6<br />z: 7>, ];
   cp27 [label=<x: 3<br />y: 6<br />z: 7>, ];
   cp28 [label=<y: 6<br />z: 7>, ];
   cp29 [label=<x: 3<br />y: 6<br />z: 7>, ];
-  cp30 [label=<y: 6<br />z: 7>, ];
-  cp31 [label=<x: 3<br />y: 6<br />z: 7>, ];
-  cp32 [label=<x: 3<br />y: 6<br />z: 7>, ];
+  cp30 [label=<x: 3<br />y: 6<br />z: 7>, ];
+  cp31 [label=<y: 6<br />z: 7>, ];
+  cp32 [label=<y: 6<br />z: 7>, ];
   cp33 [label=<y: 6<br />z: 7>, ];
-  cp34 [label=<y: 6<br />z: 7>, ];
-  cp35 [label=<y: 6<br />z: 7>, ];
   
-  subgraph cluster_1 { cp26;cp25;cp24;cp23;cp22;cp18;cp17;cp16;cp15;cp14;
+  subgraph cluster_1 { cp24;cp23;cp22;cp21;cp20;cp17;cp16;cp15;cp14;cp13;
      };
   
   cp1 -> cp3 [label=<Enter y, z, w, a>, ];
-  cp3 -> cp5 [label=<int y = 3;>, ];
-  cp4 -> cp2 [label=<Exit y, z, w, a>, style="dashed", ];
-  cp5 -> cp6 [label=<y *= 2;>, ];
-  cp6 -> cp7 [label=<int z = y + 1;>, ];
-  cp7 -> cp8 [label=<int w = y + x;>, ];
-  cp8 -> cp9 [label=<int a = 1;>, ];
-  cp9 -> cp11 [label=<Enter i>, ];
-  cp10 -> cp28 [label=<x != 3>, ];
-  cp10 -> cp29 [label=<!(x != 3)>, ];
-  cp11 -> cp13 [label=<int i = 0;>, ];
-  cp12 -> cp10 [label=<Exit i>, style="dashed", ];
-  cp13 -> cp14 [label=< >, ];
-  cp14 -> cp15 [label=<Enter >, ];
-  cp15 -> cp18 [label=<i &lt; 10>, ];
-  cp15 -> cp19 [label=<!(i &lt; 10)>, ];
-  cp16 -> cp14 [constraint=false, label=<Exit >, ];
-  cp17 -> cp23 [label=<Enter b, c>, ];
-  cp18 -> cp17 [label=< >, ];
-  cp19 -> cp20 [label=<Enter >, ];
-  cp20 -> cp33 [label=< >, ];
-  cp21 -> cp17 [label=<Exit >, style="dashed", ];
-  cp22 -> cp16 [label=<i ++;>, ];
-  cp23 -> cp25 [label=<int b = 3;>, ];
-  cp24 -> cp22 [label=<Exit b, c>, ];
-  cp25 -> cp26 [label=<int c = i + 1;>, ];
-  cp26 -> cp24 [label=<a ++;>, ];
-  cp27 -> cp32 [label=<return>, ];
-  cp28 -> cp30 [label=<Enter >, ];
-  cp29 -> cp27 [label=< >, ];
-  cp30 -> cp31 [label=<x = 3;>, ];
-  cp31 -> cp27 [label=<Exit >, ];
-  cp32 -> cp2 [label=<Exit y, z, w, a>, ];
-  cp33 -> cp34 [label=<Exit i>, ];
-  cp34 -> cp35 [label=<Exit >, ];
-  cp35 -> cp10 [label=<Exit >, ];
+  cp3 -> cp4 [label=<int y = 3;>, ];
+  cp4 -> cp5 [label=<y *= 2;>, ];
+  cp5 -> cp6 [label=<int z = y + 1;>, ];
+  cp6 -> cp7 [label=<int w = y + x;>, ];
+  cp7 -> cp8 [label=<int a = 1;>, ];
+  cp8 -> cp10 [label=<Enter i>, ];
+  cp9 -> cp26 [label=<x != 3>, ];
+  cp9 -> cp27 [label=<!(x != 3)>, ];
+  cp10 -> cp12 [label=<int i = 0;>, ];
+  cp11 -> cp9 [label=<Exit i>, style="dashed", ];
+  cp12 -> cp13 [label=< >, ];
+  cp13 -> cp14 [label=<Enter >, ];
+  cp14 -> cp17 [label=<i &lt; 10>, ];
+  cp14 -> cp18 [label=<!(i &lt; 10)>, ];
+  cp15 -> cp13 [constraint=false, label=<Exit >, ];
+  cp16 -> cp21 [label=<Enter b, c>, ];
+  cp17 -> cp16 [label=< >, ];
+  cp18 -> cp19 [label=<Enter >, ];
+  cp19 -> cp31 [label=< >, ];
+  cp20 -> cp15 [label=<i ++;>, ];
+  cp21 -> cp23 [label=<int b = 3;>, ];
+  cp22 -> cp20 [label=<Exit b, c>, ];
+  cp23 -> cp24 [label=<int c = i + 1;>, ];
+  cp24 -> cp22 [label=<a ++;>, ];
+  cp25 -> cp30 [label=<return>, ];
+  cp26 -> cp28 [label=<Enter >, ];
+  cp27 -> cp25 [label=< >, ];
+  cp28 -> cp29 [label=<x = 3;>, ];
+  cp29 -> cp25 [label=<Exit >, ];
+  cp30 -> cp2 [label=<Exit y, z, w, a>, ];
+  cp31 -> cp32 [label=<Exit i>, ];
+  cp32 -> cp33 [label=<Exit >, ];
+  cp33 -> cp9 [label=<Exit >, ];
   
   }
\ No newline at end of file
diff --git a/tests/value/oracle/partitioning-interproc.0.res.oracle b/tests/value/oracle/partitioning-interproc.0.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..4481fdb71c75b560b40d5f611f615da44aa446a3
--- /dev/null
+++ b/tests/value/oracle/partitioning-interproc.0.res.oracle
@@ -0,0 +1,62 @@
+[kernel] Parsing tests/value/partitioning-interproc.c (with preprocessing)
+[eva] Analyzing a complete application starting at cassign_test
+[eva] Computing initial state
+[eva] Initial state computed
+[eva:initial-state] Values of globals at initialization
+  
+[eva] computing for function cassign <- cassign_test.
+  Called from tests/value/partitioning-interproc.c:24.
+[eva] computing for function Frama_C_nondet <- cassign <- cassign_test.
+  Called from tests/value/partitioning-interproc.c:11.
+[eva] using specification for function Frama_C_nondet
+[eva] Done for function Frama_C_nondet
+[eva] Recording results for cassign
+[eva] Done for function cassign
+[eva] tests/value/partitioning-interproc.c:26: Frama_C_show_each: {1}
+[eva] tests/value/partitioning-interproc.c:30: 
+  Reusing old results for call to cassign
+[eva] computing for function cassign <- cassign_test.
+  Called from tests/value/partitioning-interproc.c:30.
+[eva] computing for function Frama_C_nondet <- cassign <- cassign_test.
+  Called from tests/value/partitioning-interproc.c:11.
+[eva] Done for function Frama_C_nondet
+[eva] Recording results for cassign
+[eva] Done for function cassign
+[eva] tests/value/partitioning-interproc.c:32: Frama_C_show_each: {1}
+[eva] Recording results for cassign_test
+[eva] done for function cassign_test
+[eva] ====== VALUES COMPUTED ======
+[eva:final-states] Values at end of function cassign:
+  Frama_C_entropy_source ∈ [--..--]
+  x ∈ {0} or UNINITIALIZED
+  __retres ∈ {0; 1}
+[eva:final-states] Values at end of function cassign_test:
+  Frama_C_entropy_source ∈ [--..--]
+  x ∈ {0} or UNINITIALIZED
+  y ∈ {1} or UNINITIALIZED
+[from] Computing for function cassign
+[from] Computing for function Frama_C_nondet <-cassign
+[from] Done for function Frama_C_nondet
+[from] Done for function cassign
+[from] Computing for function cassign_test
+[from] Done for function cassign_test
+[from] ====== DEPENDENCIES COMPUTED ======
+  These dependencies hold at termination for the executions that terminate:
+[from] Function Frama_C_nondet:
+  Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF)
+  \result FROM Frama_C_entropy_source; a; b
+[from] Function cassign:
+  Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF)
+  x FROM Frama_C_entropy_source; p (and SELF)
+  \result FROM Frama_C_entropy_source
+[from] Function cassign_test:
+  Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF)
+[from] ====== END OF DEPENDENCIES ======
+[inout] Out (internal) for function cassign:
+    Frama_C_entropy_source; tmp; x; __retres
+[inout] Inputs for function cassign:
+    Frama_C_entropy_source
+[inout] Out (internal) for function cassign_test:
+    Frama_C_entropy_source; x; y; tmp; tmp_0
+[inout] Inputs for function cassign_test:
+    Frama_C_entropy_source
diff --git a/tests/value/oracle/partitioning-interproc.1.res.oracle b/tests/value/oracle/partitioning-interproc.1.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..dfd3684a60556eb5eb3f3103610e38cf700f7c6a
--- /dev/null
+++ b/tests/value/oracle/partitioning-interproc.1.res.oracle
@@ -0,0 +1,36 @@
+[kernel] Parsing tests/value/partitioning-interproc.c (with preprocessing)
+[eva] Analyzing a complete application starting at fabs_test
+[eva] Computing initial state
+[eva] Initial state computed
+[eva:initial-state] Values of globals at initialization
+  
+[eva] computing for function fabs <- fabs_test.
+  Called from tests/value/partitioning-interproc.c:50.
+[eva] Recording results for fabs
+[eva] Done for function fabs
+[eva] Recording results for fabs_test
+[eva] done for function fabs_test
+[eva] ====== VALUES COMPUTED ======
+[eva:final-states] Values at end of function fabs:
+  __retres ∈ [-0. .. 1.79769313486e+308]
+[eva:final-states] Values at end of function fabs_test:
+  x ∈ [-1. .. 1.]
+[from] Computing for function fabs
+[from] Done for function fabs
+[from] Computing for function fabs_test
+[from] Done for function fabs_test
+[from] ====== DEPENDENCIES COMPUTED ======
+  These dependencies hold at termination for the executions that terminate:
+[from] Function fabs:
+  \result FROM x
+[from] Function fabs_test:
+  NO EFFECTS
+[from] ====== END OF DEPENDENCIES ======
+[inout] Out (internal) for function fabs:
+    __retres
+[inout] Inputs for function fabs:
+    \nothing
+[inout] Out (internal) for function fabs_test:
+    x; tmp
+[inout] Inputs for function fabs_test:
+    \nothing
diff --git a/tests/value/oracle/partitioning-interproc.2.res.oracle b/tests/value/oracle/partitioning-interproc.2.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..25cdbcbd6200484db29211b2522b308cd086c023
--- /dev/null
+++ b/tests/value/oracle/partitioning-interproc.2.res.oracle
@@ -0,0 +1,36 @@
+[kernel] Parsing tests/value/partitioning-interproc.c (with preprocessing)
+[eva] Analyzing a complete application starting at fabs_splits_test
+[eva] Computing initial state
+[eva] Initial state computed
+[eva:initial-state] Values of globals at initialization
+  
+[eva] computing for function fabs_splits <- fabs_splits_test.
+  Called from tests/value/partitioning-interproc.c:71.
+[eva] Recording results for fabs_splits
+[eva] Done for function fabs_splits
+[eva] Recording results for fabs_splits_test
+[eva] done for function fabs_splits_test
+[eva] ====== VALUES COMPUTED ======
+[eva:final-states] Values at end of function fabs_splits:
+  __retres ∈ [0. .. 1.79769313486e+308]
+[eva:final-states] Values at end of function fabs_splits_test:
+  x ∈ [-1. .. 1.]
+[from] Computing for function fabs_splits
+[from] Done for function fabs_splits
+[from] Computing for function fabs_splits_test
+[from] Done for function fabs_splits_test
+[from] ====== DEPENDENCIES COMPUTED ======
+  These dependencies hold at termination for the executions that terminate:
+[from] Function fabs_splits:
+  \result FROM x
+[from] Function fabs_splits_test:
+  NO EFFECTS
+[from] ====== END OF DEPENDENCIES ======
+[inout] Out (internal) for function fabs_splits:
+    __retres
+[inout] Inputs for function fabs_splits:
+    \nothing
+[inout] Out (internal) for function fabs_splits_test:
+    x; tmp
+[inout] Inputs for function fabs_splits_test:
+    \nothing
diff --git a/tests/value/oracle/partitioning-interproc.res.oracle b/tests/value/oracle/partitioning-interproc.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..b7f81ec5b367882ea010952fffc47aeae9e2d5c2
--- /dev/null
+++ b/tests/value/oracle/partitioning-interproc.res.oracle
@@ -0,0 +1,62 @@
+[kernel] Parsing tests/value/partitioning-interproc.c (with preprocessing)
+[eva] Analyzing a complete application starting at main
+[eva] Computing initial state
+[eva] Initial state computed
+[eva:initial-state] Values of globals at initialization
+  
+[eva] computing for function conditional_assign <- main.
+  Called from tests/value/partitioning-interproc.c:23.
+[eva] computing for function Frama_C_nondet <- conditional_assign <- main.
+  Called from tests/value/partitioning-interproc.c:10.
+[eva] using specification for function Frama_C_nondet
+[eva] Done for function Frama_C_nondet
+[eva] Recording results for conditional_assign
+[eva] Done for function conditional_assign
+[eva] tests/value/partitioning-interproc.c:25: Frama_C_show_each: {1}
+[eva] tests/value/partitioning-interproc.c:29: 
+  Reusing old results for call to conditional_assign
+[eva] computing for function conditional_assign <- main.
+  Called from tests/value/partitioning-interproc.c:29.
+[eva] computing for function Frama_C_nondet <- conditional_assign <- main.
+  Called from tests/value/partitioning-interproc.c:10.
+[eva] Done for function Frama_C_nondet
+[eva] Recording results for conditional_assign
+[eva] Done for function conditional_assign
+[eva] tests/value/partitioning-interproc.c:31: Frama_C_show_each: {1}
+[eva] Recording results for main
+[eva] done for function main
+[eva] ====== VALUES COMPUTED ======
+[eva:final-states] Values at end of function conditional_assign:
+  Frama_C_entropy_source ∈ [--..--]
+  x ∈ {0} or UNINITIALIZED
+  __retres ∈ {0; 1}
+[eva:final-states] Values at end of function main:
+  Frama_C_entropy_source ∈ [--..--]
+  x ∈ {0} or UNINITIALIZED
+  y ∈ {1} or UNINITIALIZED
+[from] Computing for function conditional_assign
+[from] Computing for function Frama_C_nondet <-conditional_assign
+[from] Done for function Frama_C_nondet
+[from] Done for function conditional_assign
+[from] Computing for function main
+[from] Done for function main
+[from] ====== DEPENDENCIES COMPUTED ======
+  These dependencies hold at termination for the executions that terminate:
+[from] Function Frama_C_nondet:
+  Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF)
+  \result FROM Frama_C_entropy_source; a; b
+[from] Function conditional_assign:
+  Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF)
+  x FROM Frama_C_entropy_source; p (and SELF)
+  \result FROM Frama_C_entropy_source
+[from] Function main:
+  Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF)
+[from] ====== END OF DEPENDENCIES ======
+[inout] Out (internal) for function conditional_assign:
+    Frama_C_entropy_source; tmp; x; __retres
+[inout] Inputs for function conditional_assign:
+    Frama_C_entropy_source
+[inout] Out (internal) for function main:
+    Frama_C_entropy_source; x; y; tmp; tmp_0
+[inout] Inputs for function main:
+    Frama_C_entropy_source
diff --git a/tests/value/oracle_apron/partitioning-interproc.0.res.oracle b/tests/value/oracle_apron/partitioning-interproc.0.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..e64c57f27312171ca2f44caf1d8123951bdc7206
--- /dev/null
+++ b/tests/value/oracle_apron/partitioning-interproc.0.res.oracle
@@ -0,0 +1,11 @@
+16,17c16,22
+< [eva] tests/value/partitioning-interproc.c:30: 
+<   Reusing old results for call to cassign
+---
+> [eva] computing for function cassign <- cassign_test.
+>   Called from tests/value/partitioning-interproc.c:30.
+> [eva] computing for function Frama_C_nondet <- cassign <- cassign_test.
+>   Called from tests/value/partitioning-interproc.c:11.
+> [eva] Done for function Frama_C_nondet
+> [eva] Recording results for cassign
+> [eva] Done for function cassign
diff --git a/tests/value/partitioning-interproc.c b/tests/value/partitioning-interproc.c
new file mode 100644
index 0000000000000000000000000000000000000000..e4094424342e522149e90672f435887c25cfd652
--- /dev/null
+++ b/tests/value/partitioning-interproc.c
@@ -0,0 +1,74 @@
+/* run.config*
+
+   STDOPT: #"-main cassign_test -eva-partition-history 1 -eva-interprocedural-history"
+   STDOPT: #"-main fabs_test -eva-partition-history 1 -eva-domains equality -eva-interprocedural-history"
+   STDOPT: #"-main fabs_splits_test -eva-partition-history 1 -eva-domains equality -eva-interprocedural-splits"
+   */
+#include "__fc_builtin.h"
+
+int cassign(int *p)
+{
+  if (Frama_C_nondet(0,1))
+  {
+    *p = 0;
+    return 1;
+  }
+
+  return 0;
+}
+
+void cassign_test(void) {
+  int x, y;
+
+  // First call
+  if (cassign(&x)) {
+    y = x + 1;
+    Frama_C_show_each(y);
+  }
+
+  // Second call with some MemExec hit
+  if (cassign(&x)) {
+    y = x + 1;
+    Frama_C_show_each(y);
+  }
+}
+
+
+double fabs(double x)
+{
+  if (x == 0.0) {
+    return 0.0;
+  } else if (x > 0.0) {
+    return x;
+  } else {
+    return -x;
+  } 
+}
+
+void fabs_test(double x)
+{
+  if (fabs(x) > 1.0) {
+    x = x < 0 ? -1.0 : 1.0;
+  }
+}
+
+
+double fabs_splits(double x)
+{
+  //@ split x > 0.0;
+  //@ split x < 0.0;
+  if (x == 0.0) {
+    return 0.0;
+  } else if (x > 0.0) {
+    return x;
+  } else {
+    return -x;
+  } 
+}
+
+void fabs_splits_test(double x)
+{
+  if (fabs_splits(x) > 1.0) {
+    x = x < 0 ? -1.0 : 1.0;
+  }
+}