From a9c057385e03948d5f57a979dd2f43ab59abe2fd Mon Sep 17 00:00:00 2001
From: Allan Blanchard <allan.blanchard@cea.fr>
Date: Thu, 24 Oct 2019 10:37:45 +0200
Subject: [PATCH] [Builtin] Tests for stdlib.h functions

---
 src/plugins/builtin/Makefile.in               |   2 +-
 src/plugins/builtin/stdlib/calloc.ml          |   8 +-
 src/plugins/builtin/tests/stdlib/calloc.c     |  23 +
 src/plugins/builtin/tests/stdlib/free.c       |  11 +
 src/plugins/builtin/tests/stdlib/malloc.c     |  23 +
 .../tests/stdlib/oracle/calloc.res.oracle     | 543 ++++++++++++++++++
 .../tests/stdlib/oracle/free.res.oracle       | 207 +++++++
 .../tests/stdlib/oracle/malloc.res.oracle     | 429 ++++++++++++++
 src/plugins/builtin/tests/stdlib/test_config  |   1 +
 9 files changed, 1245 insertions(+), 2 deletions(-)
 create mode 100644 src/plugins/builtin/tests/stdlib/calloc.c
 create mode 100644 src/plugins/builtin/tests/stdlib/free.c
 create mode 100644 src/plugins/builtin/tests/stdlib/malloc.c
 create mode 100644 src/plugins/builtin/tests/stdlib/oracle/calloc.res.oracle
 create mode 100644 src/plugins/builtin/tests/stdlib/oracle/free.res.oracle
 create mode 100644 src/plugins/builtin/tests/stdlib/oracle/malloc.res.oracle
 create mode 100644 src/plugins/builtin/tests/stdlib/test_config

diff --git a/src/plugins/builtin/Makefile.in b/src/plugins/builtin/Makefile.in
index a124d63c70e..810ca5c502f 100644
--- a/src/plugins/builtin/Makefile.in
+++ b/src/plugins/builtin/Makefile.in
@@ -62,7 +62,7 @@ PLUGIN_CMO := \
 PLUGIN_DISTRIBUTED := $(PLUGIN_ENABLE)
 PLUGIN_DISTRIB_EXTERNAL:= Makefile.in configure.ac configure
 #PLUGIN_NO_DEFAULT_TEST := no
-PLUGIN_TESTS_DIRS := string options
+PLUGIN_TESTS_DIRS := string stdlib options
 
 ################
 # Generic part #
diff --git a/src/plugins/builtin/stdlib/calloc.ml b/src/plugins/builtin/stdlib/calloc.ml
index 8d11849cc72..10ba0682d7a 100644
--- a/src/plugins/builtin/stdlib/calloc.ml
+++ b/src/plugins/builtin/stdlib/calloc.ml
@@ -61,7 +61,13 @@ let generate_requires ?loc alloc_type num size =
 
 let pinitialized_len ?loc alloc_type num size =
   let result = tresult ?loc (ptr_of alloc_type) in
-  let initialized ?loc t = pinitialized ?loc (here_label, t) in
+  let initialized ?loc t =
+    let t = match t.term_node, t.term_type with
+      | TLval (lv), Ctype t -> taddrof ?loc lv (Ctype (ptr_of t))
+      | _ -> assert false
+    in
+    pinitialized ?loc (here_label, t)
+  in
   let p = if Cil.has_flexible_array_member alloc_type then
       let access = Cil.mkTermMem ~addr:result ~off:TNoOffset in
       let access = term ?loc (TLval access) (Ctype alloc_type) in
diff --git a/src/plugins/builtin/tests/stdlib/calloc.c b/src/plugins/builtin/tests/stdlib/calloc.c
new file mode 100644
index 00000000000..58286c59dda
--- /dev/null
+++ b/src/plugins/builtin/tests/stdlib/calloc.c
@@ -0,0 +1,23 @@
+#include <stdlib.h>
+
+struct X {
+  int x ;
+  int y ;
+} ;
+
+struct Flex {
+  int x ;
+  char c ;
+  int f[] ;
+} ;
+
+int main(void){
+  int* pi = calloc(10, sizeof(int)) ;
+  float* pf = calloc(10, sizeof(float)) ;
+  struct X* px = calloc(10, sizeof(struct X)) ;
+  char* pc = calloc(10, sizeof(char)) ;
+
+  int (*pa) [10] = calloc(10, sizeof(int[10])) ;
+
+  struct Flex* f = calloc(1, sizeof(struct Flex) + 3 * sizeof(int)) ;
+}
\ No newline at end of file
diff --git a/src/plugins/builtin/tests/stdlib/free.c b/src/plugins/builtin/tests/stdlib/free.c
new file mode 100644
index 00000000000..eb0ff860035
--- /dev/null
+++ b/src/plugins/builtin/tests/stdlib/free.c
@@ -0,0 +1,11 @@
+#include <stdlib.h>
+
+void foo(int * x){
+  free(x);
+}
+void bar(float * x){
+  free(x);
+}
+void baz(int (*x) [10]){
+  free(x);
+}
\ No newline at end of file
diff --git a/src/plugins/builtin/tests/stdlib/malloc.c b/src/plugins/builtin/tests/stdlib/malloc.c
new file mode 100644
index 00000000000..e39f5d9c638
--- /dev/null
+++ b/src/plugins/builtin/tests/stdlib/malloc.c
@@ -0,0 +1,23 @@
+#include <stdlib.h>
+
+struct X {
+  int x ;
+  int y ;
+} ;
+
+struct Flex {
+  int x ;
+  char c ;
+  int f[] ;
+} ;
+
+int main(void){
+  int* pi = malloc(sizeof(int) * 10) ;
+  float* pf = malloc(sizeof(float) * 10) ;
+  struct X* px = malloc(sizeof(struct X) * 10) ;
+  char* pc = malloc(10) ;
+
+  int (*pa) [10] = malloc(sizeof(int[10]) * 10) ;
+
+  struct Flex* f = malloc(sizeof(struct Flex) + 3 * sizeof(int)) ;
+}
\ No newline at end of file
diff --git a/src/plugins/builtin/tests/stdlib/oracle/calloc.res.oracle b/src/plugins/builtin/tests/stdlib/oracle/calloc.res.oracle
new file mode 100644
index 00000000000..e3e9e4bc0c8
--- /dev/null
+++ b/src/plugins/builtin/tests/stdlib/oracle/calloc.res.oracle
@@ -0,0 +1,543 @@
+[kernel] Parsing tests/stdlib/calloc.c (with preprocessing)
+/* Generated by Frama-C */
+#include "stdlib.h"
+struct X {
+   int x ;
+   int y ;
+};
+struct Flex {
+   int x ;
+   char c ;
+   int f[] ;
+};
+/*@ requires correct_size: 0 ≤ size - 8 ∧ 0 ≡ (size - 8) % 4;
+    requires only_one: num ≡ 1;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, num, size;
+    assigns __fc_heap_status \from __fc_heap_status, num, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(num * size);
+      ensures fresh_result: \fresh{Old, Here}(\result,num * size);
+      ensures
+        zero_initialization:
+          \let __fc_flexlen = (size - 8) / 4;
+            \result->x ≡ 0 ∧
+            \result->c ≡ 0 ∧
+            (∀ ℤ j1; 0 ≤ j1 < __fc_flexlen ⇒ \result->f[j1] ≡ 0);
+      ensures
+        initialization:
+          \let __fc_flexlen = (size - 8) / 4;
+            \initialized(&\result->x) ∧
+            \initialized(&\result->c) ∧
+            (∀ ℤ j1;
+               0 ≤ j1 < __fc_flexlen ⇒ \initialized(&\result->f[j1]));
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, num, size;
+      assigns __fc_heap_status \from __fc_heap_status, num, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(num * size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+struct Flex *calloc_Flex(size_t num, size_t size)
+{
+  struct Flex *__retres;
+  __retres = (struct Flex *)calloc(num,size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 40;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, num, size;
+    assigns __fc_heap_status \from __fc_heap_status, num, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(num * size);
+      ensures fresh_result: \fresh{Old, Here}(\result,num * size);
+      ensures
+        zero_initialization:
+          ∀ ℤ j0;
+            0 ≤ j0 < num ⇒
+            (∀ ℤ j1; 0 ≤ j1 < 10 ⇒ (*(\result + j0))[j1] ≡ 0);
+      ensures
+        initialization:
+          ∀ ℤ j0;
+            0 ≤ j0 < num ⇒
+            (∀ ℤ j1;
+               0 ≤ j1 < 10 ⇒ \initialized(&(*(\result + j0))[j1]));
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, num, size;
+      assigns __fc_heap_status \from __fc_heap_status, num, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(num * size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+int (*calloc_arr10_int(size_t num, size_t size))[10]
+{
+  int (*__retres)[10];
+  __retres = (int (*)[10])calloc(num,size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 1;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, num, size;
+    assigns __fc_heap_status \from __fc_heap_status, num, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(num * size);
+      ensures fresh_result: \fresh{Old, Here}(\result,num * size);
+      ensures
+        zero_initialization:
+          ∀ ℤ j0; 0 ≤ j0 < num ⇒ *(\result + j0) ≡ 0;
+      ensures
+        initialization:
+          ∀ ℤ j0; 0 ≤ j0 < num ⇒ \initialized(\result + j0);
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, num, size;
+      assigns __fc_heap_status \from __fc_heap_status, num, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(num * size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+char *calloc_char(size_t num, size_t size)
+{
+  char *__retres;
+  __retres = (char *)calloc(num,size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 8;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, num, size;
+    assigns __fc_heap_status \from __fc_heap_status, num, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(num * size);
+      ensures fresh_result: \fresh{Old, Here}(\result,num * size);
+      ensures
+        zero_initialization:
+          ∀ ℤ j0;
+            0 ≤ j0 < num ⇒
+            (\result + j0)->x ≡ 0 ∧ (\result + j0)->y ≡ 0;
+      ensures
+        initialization:
+          ∀ ℤ j0;
+            0 ≤ j0 < num ⇒
+            \initialized(&(\result + j0)->x) ∧
+            \initialized(&(\result + j0)->y);
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, num, size;
+      assigns __fc_heap_status \from __fc_heap_status, num, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(num * size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+struct X *calloc_X(size_t num, size_t size)
+{
+  struct X *__retres;
+  __retres = (struct X *)calloc(num,size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 4;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, num, size;
+    assigns __fc_heap_status \from __fc_heap_status, num, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(num * size);
+      ensures fresh_result: \fresh{Old, Here}(\result,num * size);
+      ensures
+        zero_initialization:
+          ∀ ℤ j0; 0 ≤ j0 < num ⇒ *(\result + j0) ≡ 0.;
+      ensures
+        initialization:
+          ∀ ℤ j0; 0 ≤ j0 < num ⇒ \initialized(\result + j0);
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, num, size;
+      assigns __fc_heap_status \from __fc_heap_status, num, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(num * size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+float *calloc_float(size_t num, size_t size)
+{
+  float *__retres;
+  __retres = (float *)calloc(num,size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 4;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, num, size;
+    assigns __fc_heap_status \from __fc_heap_status, num, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(num * size);
+      ensures fresh_result: \fresh{Old, Here}(\result,num * size);
+      ensures
+        zero_initialization:
+          ∀ ℤ j0; 0 ≤ j0 < num ⇒ *(\result + j0) ≡ 0;
+      ensures
+        initialization:
+          ∀ ℤ j0; 0 ≤ j0 < num ⇒ \initialized(\result + j0);
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, num, size;
+      assigns __fc_heap_status \from __fc_heap_status, num, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(num * size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+int *calloc_int(size_t num, size_t size)
+{
+  int *__retres;
+  __retres = (int *)calloc(num,size);
+  return __retres;
+}
+
+int main(void)
+{
+  int __retres;
+  int *pi = calloc_int((unsigned int)10,sizeof(int));
+  float *pf = calloc_float((unsigned int)10,sizeof(float));
+  struct X *px = calloc_X((unsigned int)10,sizeof(struct X));
+  char *pc = calloc_char((unsigned int)10,sizeof(char));
+  int (*pa)[10] = calloc_arr10_int((unsigned int)10,sizeof(int [10]));
+  struct Flex *f =
+    calloc_Flex((unsigned int)1,
+                sizeof(struct Flex) + (unsigned int)3 * sizeof(int));
+  __retres = 0;
+  return __retres;
+}
+
+
+[kernel] Parsing tests/stdlib/result/calloc.c (with preprocessing)
+[kernel] Parsing tests/stdlib/calloc.c (with preprocessing)
+[kernel] tests/stdlib/calloc.c:14: Warning: 
+  def'n of func main at tests/stdlib/calloc.c:14 (sum 5516) conflicts with the one at tests/stdlib/result/calloc.c:252 (sum 7290); keeping the one at tests/stdlib/result/calloc.c:252.
+/* Generated by Frama-C */
+#include "stdlib.h"
+struct X {
+   int x ;
+   int y ;
+};
+struct Flex {
+   int x ;
+   char c ;
+   int f[] ;
+};
+/*@ requires correct_size: 0 ≤ size - 8 ∧ 0 ≡ (size - 8) % 4;
+    requires only_one: num ≡ 1;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, num, size;
+    assigns __fc_heap_status \from __fc_heap_status, num, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(num * size);
+      ensures
+        fresh_result: \fresh{Old, Here}(\result,\old(num) * \old(size));
+      ensures
+        zero_initialization:
+          \let __fc_flexlen = (\old(size) - 8) / 4;
+            \result->x ≡ 0 ∧ \result->c ≡ 0 ∧
+            (∀ ℤ j1; 0 ≤ j1 < __fc_flexlen ⇒ \result->f[j1] ≡ 0);
+      ensures
+        initialization:
+          \let __fc_flexlen = (\old(size) - 8) / 4;
+            \initialized(&\result->x) ∧ \initialized(&\result->c) ∧
+            (∀ ℤ j1;
+               0 ≤ j1 < __fc_flexlen ⇒ \initialized(&\result->f[j1]));
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, num, size;
+      assigns __fc_heap_status \from __fc_heap_status, num, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(num * size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+struct Flex *calloc_Flex(size_t num, size_t size)
+{
+  struct Flex *__retres;
+  __retres = (struct Flex *)calloc(num,size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 40;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, num, size;
+    assigns __fc_heap_status \from __fc_heap_status, num, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(num * size);
+      ensures
+        fresh_result: \fresh{Old, Here}(\result,\old(num) * \old(size));
+      ensures
+        zero_initialization:
+          ∀ ℤ j0;
+            0 ≤ j0 < \old(num) ⇒
+            (∀ ℤ j1; 0 ≤ j1 < 10 ⇒ (*(\result + j0))[j1] ≡ 0);
+      ensures
+        initialization:
+          ∀ ℤ j0;
+            0 ≤ j0 < \old(num) ⇒
+            (∀ ℤ j1;
+               0 ≤ j1 < 10 ⇒ \initialized(&(*(\result + j0))[j1]));
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, num, size;
+      assigns __fc_heap_status \from __fc_heap_status, num, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(num * size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+int (*calloc_arr10_int(size_t num, size_t size))[10]
+{
+  int (*__retres)[10];
+  __retres = (int (*)[10])calloc(num,size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 1;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, num, size;
+    assigns __fc_heap_status \from __fc_heap_status, num, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(num * size);
+      ensures
+        fresh_result: \fresh{Old, Here}(\result,\old(num) * \old(size));
+      ensures
+        zero_initialization:
+          ∀ ℤ j0; 0 ≤ j0 < \old(num) ⇒ *(\result + j0) ≡ 0;
+      ensures
+        initialization:
+          ∀ ℤ j0; 0 ≤ j0 < \old(num) ⇒ \initialized(\result + j0);
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, num, size;
+      assigns __fc_heap_status \from __fc_heap_status, num, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(num * size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+char *calloc_char(size_t num, size_t size)
+{
+  char *__retres;
+  __retres = (char *)calloc(num,size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 8;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, num, size;
+    assigns __fc_heap_status \from __fc_heap_status, num, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(num * size);
+      ensures
+        fresh_result: \fresh{Old, Here}(\result,\old(num) * \old(size));
+      ensures
+        zero_initialization:
+          ∀ ℤ j0;
+            0 ≤ j0 < \old(num) ⇒
+            (\result + j0)->x ≡ 0 ∧ (\result + j0)->y ≡ 0;
+      ensures
+        initialization:
+          ∀ ℤ j0;
+            0 ≤ j0 < \old(num) ⇒
+            \initialized(&(\result + j0)->x) ∧
+            \initialized(&(\result + j0)->y);
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, num, size;
+      assigns __fc_heap_status \from __fc_heap_status, num, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(num * size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+struct X *calloc_X(size_t num, size_t size)
+{
+  struct X *__retres;
+  __retres = (struct X *)calloc(num,size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 4;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, num, size;
+    assigns __fc_heap_status \from __fc_heap_status, num, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(num * size);
+      ensures
+        fresh_result: \fresh{Old, Here}(\result,\old(num) * \old(size));
+      ensures
+        zero_initialization:
+          ∀ ℤ j0; 0 ≤ j0 < \old(num) ⇒ *(\result + j0) ≡ 0.;
+      ensures
+        initialization:
+          ∀ ℤ j0; 0 ≤ j0 < \old(num) ⇒ \initialized(\result + j0);
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, num, size;
+      assigns __fc_heap_status \from __fc_heap_status, num, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(num * size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+float *calloc_float(size_t num, size_t size)
+{
+  float *__retres;
+  __retres = (float *)calloc(num,size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 4;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, num, size;
+    assigns __fc_heap_status \from __fc_heap_status, num, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(num * size);
+      ensures
+        fresh_result: \fresh{Old, Here}(\result,\old(num) * \old(size));
+      ensures
+        zero_initialization:
+          ∀ ℤ j0; 0 ≤ j0 < \old(num) ⇒ *(\result + j0) ≡ 0;
+      ensures
+        initialization:
+          ∀ ℤ j0; 0 ≤ j0 < \old(num) ⇒ \initialized(\result + j0);
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, num, size;
+      assigns __fc_heap_status \from __fc_heap_status, num, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(num * size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+int *calloc_int(size_t num, size_t size)
+{
+  int *__retres;
+  __retres = (int *)calloc(num,size);
+  return __retres;
+}
+
+int main(void)
+{
+  int __retres;
+  int *pi = calloc_int((unsigned int)10,sizeof(int));
+  float *pf = calloc_float((unsigned int)10,sizeof(float));
+  struct X *px = calloc_X((unsigned int)10,sizeof(struct X));
+  char *pc = calloc_char((unsigned int)10,sizeof(char));
+  int (*pa)[10] = calloc_arr10_int((unsigned int)10,sizeof(int [10]));
+  struct Flex *f =
+    calloc_Flex((unsigned int)1,
+                sizeof(struct Flex) + (unsigned int)3 * sizeof(int));
+  __retres = 0;
+  return __retres;
+}
+
+
diff --git a/src/plugins/builtin/tests/stdlib/oracle/free.res.oracle b/src/plugins/builtin/tests/stdlib/oracle/free.res.oracle
new file mode 100644
index 00000000000..425d46815eb
--- /dev/null
+++ b/src/plugins/builtin/tests/stdlib/oracle/free.res.oracle
@@ -0,0 +1,207 @@
+[kernel] Parsing tests/stdlib/free.c (with preprocessing)
+/* Generated by Frama-C */
+#include "stdlib.h"
+/*@ requires freeable: ptr ≡ \null ∨ \freeable(ptr);
+    assigns __fc_heap_status;
+    assigns __fc_heap_status \from __fc_heap_status, ptr;
+    frees ptr;
+    
+    behavior allocation:
+      assumes ptr ≢ \null;
+      ensures freed: \allocable(ptr);
+      assigns __fc_heap_status;
+      assigns __fc_heap_status \from __fc_heap_status, ptr;
+      frees ptr;
+    
+    behavior no_allocation:
+      assumes ptr ≡ \null;
+      assigns \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+void free_int(int *ptr)
+{
+  free((void *)ptr);
+  return;
+}
+
+void foo(int *x)
+{
+  free_int(x);
+  return;
+}
+
+/*@ requires freeable: ptr ≡ \null ∨ \freeable(ptr);
+    assigns __fc_heap_status;
+    assigns __fc_heap_status \from __fc_heap_status, ptr;
+    frees ptr;
+    
+    behavior allocation:
+      assumes ptr ≢ \null;
+      ensures freed: \allocable(ptr);
+      assigns __fc_heap_status;
+      assigns __fc_heap_status \from __fc_heap_status, ptr;
+      frees ptr;
+    
+    behavior no_allocation:
+      assumes ptr ≡ \null;
+      assigns \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+void free_float(float *ptr)
+{
+  free((void *)ptr);
+  return;
+}
+
+void bar(float *x)
+{
+  free_float(x);
+  return;
+}
+
+/*@ requires freeable: ptr ≡ \null ∨ \freeable(ptr);
+    assigns __fc_heap_status;
+    assigns __fc_heap_status \from __fc_heap_status, ptr;
+    frees ptr;
+    
+    behavior allocation:
+      assumes ptr ≢ \null;
+      ensures freed: \allocable(ptr);
+      assigns __fc_heap_status;
+      assigns __fc_heap_status \from __fc_heap_status, ptr;
+      frees ptr;
+    
+    behavior no_allocation:
+      assumes ptr ≡ \null;
+      assigns \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+void free_arr10_int(int (*ptr)[10])
+{
+  free((void *)ptr);
+  return;
+}
+
+void baz(int (*x)[10])
+{
+  free_arr10_int(x);
+  return;
+}
+
+
+[kernel] Parsing tests/stdlib/result/free.c (with preprocessing)
+[kernel] Parsing tests/stdlib/free.c (with preprocessing)
+[kernel] tests/stdlib/free.c:3: Warning: 
+  dropping duplicate def'n of func foo at tests/stdlib/free.c:3 in favor of that at tests/stdlib/result/free.c:29
+[kernel] tests/stdlib/free.c:6: Warning: 
+  dropping duplicate def'n of func bar at tests/stdlib/free.c:6 in favor of that at tests/stdlib/result/free.c:61
+[kernel] tests/stdlib/free.c:9: Warning: 
+  dropping duplicate def'n of func baz at tests/stdlib/free.c:9 in favor of that at tests/stdlib/result/free.c:93
+/* Generated by Frama-C */
+#include "stdlib.h"
+/*@ requires freeable: ptr ≡ \null ∨ \freeable(ptr);
+    assigns __fc_heap_status;
+    assigns __fc_heap_status \from __fc_heap_status, ptr;
+    frees ptr;
+    
+    behavior allocation:
+      assumes ptr ≢ \null;
+      ensures freed: \allocable(\old(ptr));
+      assigns __fc_heap_status;
+      assigns __fc_heap_status \from __fc_heap_status, ptr;
+      frees ptr;
+    
+    behavior no_allocation:
+      assumes ptr ≡ \null;
+      assigns \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+void free_int(int *ptr)
+{
+  free((void *)ptr);
+  return;
+}
+
+void foo(int *x)
+{
+  free_int(x);
+  return;
+}
+
+/*@ requires freeable: ptr ≡ \null ∨ \freeable(ptr);
+    assigns __fc_heap_status;
+    assigns __fc_heap_status \from __fc_heap_status, ptr;
+    frees ptr;
+    
+    behavior allocation:
+      assumes ptr ≢ \null;
+      ensures freed: \allocable(\old(ptr));
+      assigns __fc_heap_status;
+      assigns __fc_heap_status \from __fc_heap_status, ptr;
+      frees ptr;
+    
+    behavior no_allocation:
+      assumes ptr ≡ \null;
+      assigns \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+void free_float(float *ptr)
+{
+  free((void *)ptr);
+  return;
+}
+
+void bar(float *x)
+{
+  free_float(x);
+  return;
+}
+
+/*@ requires freeable: ptr ≡ \null ∨ \freeable(ptr);
+    assigns __fc_heap_status;
+    assigns __fc_heap_status \from __fc_heap_status, ptr;
+    frees ptr;
+    
+    behavior allocation:
+      assumes ptr ≢ \null;
+      ensures freed: \allocable(\old(ptr));
+      assigns __fc_heap_status;
+      assigns __fc_heap_status \from __fc_heap_status, ptr;
+      frees ptr;
+    
+    behavior no_allocation:
+      assumes ptr ≡ \null;
+      assigns \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+void free_arr10_int(int (*ptr)[10])
+{
+  free((void *)ptr);
+  return;
+}
+
+void baz(int (*x)[10])
+{
+  free_arr10_int(x);
+  return;
+}
+
+
diff --git a/src/plugins/builtin/tests/stdlib/oracle/malloc.res.oracle b/src/plugins/builtin/tests/stdlib/oracle/malloc.res.oracle
new file mode 100644
index 00000000000..bc6d992efeb
--- /dev/null
+++ b/src/plugins/builtin/tests/stdlib/oracle/malloc.res.oracle
@@ -0,0 +1,429 @@
+[kernel] Parsing tests/stdlib/malloc.c (with preprocessing)
+/* Generated by Frama-C */
+#include "stdlib.h"
+struct X {
+   int x ;
+   int y ;
+};
+struct Flex {
+   int x ;
+   char c ;
+   int f[] ;
+};
+/*@ requires correct_size: 0 ≤ size - 8 ∧ 0 ≡ (size - 8) % 4;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, size;
+    assigns __fc_heap_status \from __fc_heap_status, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(size);
+      ensures fresh_result: \fresh{Old, Here}(\result,size);
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, size;
+      assigns __fc_heap_status \from __fc_heap_status, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+struct Flex *malloc_Flex(size_t size)
+{
+  struct Flex *__retres;
+  __retres = (struct Flex *)malloc(size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 40;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, size;
+    assigns __fc_heap_status \from __fc_heap_status, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(size);
+      ensures fresh_result: \fresh{Old, Here}(\result,size);
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, size;
+      assigns __fc_heap_status \from __fc_heap_status, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+int (*malloc_arr10_int(size_t size))[10]
+{
+  int (*__retres)[10];
+  __retres = (int (*)[10])malloc(size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 1;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, size;
+    assigns __fc_heap_status \from __fc_heap_status, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(size);
+      ensures fresh_result: \fresh{Old, Here}(\result,size);
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, size;
+      assigns __fc_heap_status \from __fc_heap_status, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+char *malloc_char(size_t size)
+{
+  char *__retres;
+  __retres = (char *)malloc(size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 8;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, size;
+    assigns __fc_heap_status \from __fc_heap_status, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(size);
+      ensures fresh_result: \fresh{Old, Here}(\result,size);
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, size;
+      assigns __fc_heap_status \from __fc_heap_status, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+struct X *malloc_X(size_t size)
+{
+  struct X *__retres;
+  __retres = (struct X *)malloc(size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 4;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, size;
+    assigns __fc_heap_status \from __fc_heap_status, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(size);
+      ensures fresh_result: \fresh{Old, Here}(\result,size);
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, size;
+      assigns __fc_heap_status \from __fc_heap_status, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+float *malloc_float(size_t size)
+{
+  float *__retres;
+  __retres = (float *)malloc(size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 4;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, size;
+    assigns __fc_heap_status \from __fc_heap_status, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(size);
+      ensures fresh_result: \fresh{Old, Here}(\result,size);
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, size;
+      assigns __fc_heap_status \from __fc_heap_status, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+int *malloc_int(size_t size)
+{
+  int *__retres;
+  __retres = (int *)malloc(size);
+  return __retres;
+}
+
+int main(void)
+{
+  int __retres;
+  int *pi = malloc_int(sizeof(int) * (unsigned int)10);
+  float *pf = malloc_float(sizeof(float) * (unsigned int)10);
+  struct X *px = malloc_X(sizeof(struct X) * (unsigned int)10);
+  char *pc = malloc_char((unsigned int)10);
+  int (*pa)[10] = malloc_arr10_int(sizeof(int [10]) * (unsigned int)10);
+  struct Flex *f =
+    malloc_Flex(sizeof(struct Flex) + (unsigned int)3 * sizeof(int));
+  __retres = 0;
+  return __retres;
+}
+
+
+[kernel] Parsing tests/stdlib/result/malloc.c (with preprocessing)
+[kernel] Parsing tests/stdlib/malloc.c (with preprocessing)
+[kernel] tests/stdlib/malloc.c:14: Warning: 
+  def'n of func main at tests/stdlib/malloc.c:14 (sum 5516) conflicts with the one at tests/stdlib/result/malloc.c:198 (sum 7290); keeping the one at tests/stdlib/result/malloc.c:198.
+/* Generated by Frama-C */
+#include "stdlib.h"
+struct X {
+   int x ;
+   int y ;
+};
+struct Flex {
+   int x ;
+   char c ;
+   int f[] ;
+};
+/*@ requires correct_size: 0 ≤ size - 8 ∧ 0 ≡ (size - 8) % 4;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, size;
+    assigns __fc_heap_status \from __fc_heap_status, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(size);
+      ensures fresh_result: \fresh{Old, Here}(\result,\old(size));
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, size;
+      assigns __fc_heap_status \from __fc_heap_status, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+struct Flex *malloc_Flex(size_t size)
+{
+  struct Flex *__retres;
+  __retres = (struct Flex *)malloc(size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 40;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, size;
+    assigns __fc_heap_status \from __fc_heap_status, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(size);
+      ensures fresh_result: \fresh{Old, Here}(\result,\old(size));
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, size;
+      assigns __fc_heap_status \from __fc_heap_status, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+int (*malloc_arr10_int(size_t size))[10]
+{
+  int (*__retres)[10];
+  __retres = (int (*)[10])malloc(size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 1;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, size;
+    assigns __fc_heap_status \from __fc_heap_status, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(size);
+      ensures fresh_result: \fresh{Old, Here}(\result,\old(size));
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, size;
+      assigns __fc_heap_status \from __fc_heap_status, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+char *malloc_char(size_t size)
+{
+  char *__retres;
+  __retres = (char *)malloc(size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 8;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, size;
+    assigns __fc_heap_status \from __fc_heap_status, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(size);
+      ensures fresh_result: \fresh{Old, Here}(\result,\old(size));
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, size;
+      assigns __fc_heap_status \from __fc_heap_status, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+struct X *malloc_X(size_t size)
+{
+  struct X *__retres;
+  __retres = (struct X *)malloc(size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 4;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, size;
+    assigns __fc_heap_status \from __fc_heap_status, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(size);
+      ensures fresh_result: \fresh{Old, Here}(\result,\old(size));
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, size;
+      assigns __fc_heap_status \from __fc_heap_status, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+float *malloc_float(size_t size)
+{
+  float *__retres;
+  __retres = (float *)malloc(size);
+  return __retres;
+}
+
+/*@ requires correct_size: 0 ≡ size % 4;
+    assigns \result, __fc_heap_status;
+    assigns \result \from __fc_heap_status, size;
+    assigns __fc_heap_status \from __fc_heap_status, size;
+    allocates \result;
+    
+    behavior allocation:
+      assumes allocable: is_allocable(size);
+      ensures fresh_result: \fresh{Old, Here}(\result,\old(size));
+      assigns \result, __fc_heap_status;
+      assigns \result \from __fc_heap_status, size;
+      assigns __fc_heap_status \from __fc_heap_status, size;
+      allocates \result;
+    
+    behavior no_allocation:
+      assumes allocable: ¬is_allocable(size);
+      ensures null_result: \result ≡ \null;
+      assigns \result;
+      assigns \result \from \nothing;
+      allocates \nothing;
+    
+    complete behaviors no_allocation, allocation;
+    disjoint behaviors no_allocation, allocation;
+ */
+int *malloc_int(size_t size)
+{
+  int *__retres;
+  __retres = (int *)malloc(size);
+  return __retres;
+}
+
+int main(void)
+{
+  int __retres;
+  int *pi = malloc_int(sizeof(int) * (unsigned int)10);
+  float *pf = malloc_float(sizeof(float) * (unsigned int)10);
+  struct X *px = malloc_X(sizeof(struct X) * (unsigned int)10);
+  char *pc = malloc_char((unsigned int)10);
+  int (*pa)[10] = malloc_arr10_int(sizeof(int [10]) * (unsigned int)10);
+  struct Flex *f =
+    malloc_Flex(sizeof(struct Flex) + (unsigned int)3 * sizeof(int));
+  __retres = 0;
+  return __retres;
+}
+
+
diff --git a/src/plugins/builtin/tests/stdlib/test_config b/src/plugins/builtin/tests/stdlib/test_config
new file mode 100644
index 00000000000..467fffb4bcb
--- /dev/null
+++ b/src/plugins/builtin/tests/stdlib/test_config
@@ -0,0 +1 @@
+OPT: @PTEST_FILE@ -builtin -print -check -then -ocode @PTEST_DIR@/result/@PTEST_NAME@.c -print -then -no-builtin @PTEST_DIR@/result/@PTEST_NAME@.c @PTEST_FILE@ -ocode="" -print
\ No newline at end of file
-- 
GitLab