From 5ed93d579371ebc07eec3c4543a1b8d7b3620018 Mon Sep 17 00:00:00 2001
From: Allan Blanchard <allan.blanchard@cea.fr>
Date: Wed, 25 Mar 2020 18:30:44 +0100
Subject: [PATCH] [Instantiate] m/c alloc: refuse incomplete types

---
 src/plugins/instantiate/stdlib/calloc.ml      |  3 +-
 src/plugins/instantiate/stdlib/malloc.ml      |  3 +-
 src/plugins/instantiate/tests/stdlib/calloc.c |  1 +
 src/plugins/instantiate/tests/stdlib/free.c   |  3 +
 src/plugins/instantiate/tests/stdlib/malloc.c |  3 +
 .../tests/stdlib/oracle/calloc.res.oracle     |  7 +-
 .../tests/stdlib/oracle/free.res.oracle       | 76 ++++++++++++++++++-
 .../tests/stdlib/oracle/malloc.res.oracle     | 11 ++-
 8 files changed, 97 insertions(+), 10 deletions(-)

diff --git a/src/plugins/instantiate/stdlib/calloc.ml b/src/plugins/instantiate/stdlib/calloc.ml
index 1ea994392c6..e1cc1460c39 100644
--- a/src/plugins/instantiate/stdlib/calloc.ml
+++ b/src/plugins/instantiate/stdlib/calloc.ml
@@ -133,7 +133,8 @@ let well_typed_call ret args =
   match ret, args with
   | Some ret, [ _ ; _ ] ->
     let t = Cil.typeOfLval ret in
-    Cil.isPointerType t && not (Cil.isVoidPtrType t)
+    Cil.isPointerType t && not (Cil.isVoidPtrType t) &&
+    Cil.isCompleteType (Cil.typeOf_pointed t)
   | _ -> false
 
 let key_from_call ret _ =
diff --git a/src/plugins/instantiate/stdlib/malloc.ml b/src/plugins/instantiate/stdlib/malloc.ml
index a6debf251e1..9cc215a7711 100644
--- a/src/plugins/instantiate/stdlib/malloc.ml
+++ b/src/plugins/instantiate/stdlib/malloc.ml
@@ -72,7 +72,8 @@ let well_typed_call ret args =
   match ret, args with
   | Some ret, [ _ ] ->
     let t = Cil.typeOfLval ret in
-    Cil.isPointerType t && not (Cil.isVoidPtrType t)
+    Cil.isPointerType t && not (Cil.isVoidPtrType t) &&
+    Cil.isCompleteType (Cil.typeOf_pointed t)
   | _ -> false
 
 let key_from_call ret _ =
diff --git a/src/plugins/instantiate/tests/stdlib/calloc.c b/src/plugins/instantiate/tests/stdlib/calloc.c
index 77be4d292f1..87b1f9338cc 100644
--- a/src/plugins/instantiate/tests/stdlib/calloc.c
+++ b/src/plugins/instantiate/tests/stdlib/calloc.c
@@ -19,4 +19,5 @@ int main(void){
   int (*pa) [10] = calloc(10, sizeof(int[10])) ;
   struct Flex* f = calloc(1, sizeof(struct Flex) + 3 * sizeof(int)) ;
   void *v = calloc(10, sizeof(char));
+  struct incomplete* inc = calloc(10, 10);
 }
\ No newline at end of file
diff --git a/src/plugins/instantiate/tests/stdlib/free.c b/src/plugins/instantiate/tests/stdlib/free.c
index 40cab4f547c..e61ed8864c1 100644
--- a/src/plugins/instantiate/tests/stdlib/free.c
+++ b/src/plugins/instantiate/tests/stdlib/free.c
@@ -11,4 +11,7 @@ void baz(int (*x) [10]){
 }
 void with_void(void * x){
   free(x);
+}
+void with_incomplete(struct incomplete* t){
+  free(t);
 }
\ No newline at end of file
diff --git a/src/plugins/instantiate/tests/stdlib/malloc.c b/src/plugins/instantiate/tests/stdlib/malloc.c
index 0d5aa4ea04a..00a07820a9a 100644
--- a/src/plugins/instantiate/tests/stdlib/malloc.c
+++ b/src/plugins/instantiate/tests/stdlib/malloc.c
@@ -11,6 +11,8 @@ struct Flex {
   int f[] ;
 } ;
 
+struct incomplete ;
+
 int main(void){
   int* pi = malloc(sizeof(int) * 10) ;
   float* pf = malloc(sizeof(float) * 10) ;
@@ -19,4 +21,5 @@ int main(void){
   int (*pa) [10] = malloc(sizeof(int[10]) * 10) ;
   struct Flex* f = malloc(sizeof(struct Flex) + 3 * sizeof(int)) ;
   void *v = malloc(sizeof(char) * 10);
+  struct incomplete* inc = malloc(10);
 }
\ No newline at end of file
diff --git a/src/plugins/instantiate/tests/stdlib/oracle/calloc.res.oracle b/src/plugins/instantiate/tests/stdlib/oracle/calloc.res.oracle
index 5fb370ab29a..81cf9b246df 100644
--- a/src/plugins/instantiate/tests/stdlib/oracle/calloc.res.oracle
+++ b/src/plugins/instantiate/tests/stdlib/oracle/calloc.res.oracle
@@ -1,5 +1,6 @@
 [kernel] Parsing tests/stdlib/calloc.c (with preprocessing)
 [instantiate] tests/stdlib/calloc.c:21: Warning: Ignore call: not well typed
+[instantiate] tests/stdlib/calloc.c:22: Warning: Ignore call: not well typed
 /* Generated by Frama-C */
 #include "stdlib.h"
 struct X {
@@ -11,6 +12,7 @@ struct Flex {
    char c ;
    int f[] ;
 };
+struct incomplete;
 /*@ requires correct_size: 0 ≤ size - 8 ∧ 0 ≡ (size - 8) % 4;
     requires only_one: num ≡ 1;
     assigns \result, __fc_heap_status;
@@ -263,6 +265,7 @@ int main(void)
     calloc_st_Flex((unsigned int)1,
                    sizeof(struct Flex) + (unsigned int)3 * sizeof(int));
   void *v = calloc((unsigned int)10,sizeof(char));
+  struct incomplete *inc = calloc((unsigned int)10,(unsigned int)10);
   __retres = 0;
   return __retres;
 }
@@ -271,7 +274,7 @@ int main(void)
 [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 6403) conflicts with the one at tests/stdlib/result/calloc.c:252 (sum 8177); keeping the one at tests/stdlib/result/calloc.c:252.
+  def'n of func main at tests/stdlib/calloc.c:14 (sum 7290) conflicts with the one at tests/stdlib/result/calloc.c:253 (sum 9064); keeping the one at tests/stdlib/result/calloc.c:253.
 /* Generated by Frama-C */
 #include "stdlib.h"
 struct X {
@@ -283,6 +286,7 @@ struct Flex {
    char c ;
    int f[] ;
 };
+struct incomplete;
 /*@ requires correct_size: 0 ≤ size - 8 ∧ 0 ≡ (size - 8) % 4;
     requires only_one: num ≡ 1;
     assigns \result, __fc_heap_status;
@@ -539,6 +543,7 @@ int main(void)
     calloc_st_Flex((unsigned int)1,
                    sizeof(struct Flex) + (unsigned int)3 * sizeof(int));
   void *v = calloc((unsigned int)10,sizeof(char));
+  struct incomplete *inc = calloc((unsigned int)10,(unsigned int)10);
   __retres = 0;
   return __retres;
 }
diff --git a/src/plugins/instantiate/tests/stdlib/oracle/free.res.oracle b/src/plugins/instantiate/tests/stdlib/oracle/free.res.oracle
index 1e764fcd7c6..11f5ef65b0e 100644
--- a/src/plugins/instantiate/tests/stdlib/oracle/free.res.oracle
+++ b/src/plugins/instantiate/tests/stdlib/oracle/free.res.oracle
@@ -2,6 +2,7 @@
 [instantiate] tests/stdlib/free.c:13: Warning: Ignore call: not well typed
 /* Generated by Frama-C */
 #include "stdlib.h"
+struct incomplete;
 /*@ requires freeable: ptr ≡ \null ∨ \freeable(ptr);
     assigns __fc_heap_status;
     assigns __fc_heap_status \from __fc_heap_status, ptr;
@@ -104,19 +105,54 @@ void with_void(void *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_st_incomplete(struct incomplete *ptr)
+{
+  free((void *)ptr);
+  return;
+}
+
+void with_incomplete(struct incomplete *t)
+{
+  free_st_incomplete(t);
+  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
+  dropping duplicate def'n of func foo at tests/stdlib/free.c:3 in favor of that at tests/stdlib/result/free.c:30
 [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
+  dropping duplicate def'n of func bar at tests/stdlib/free.c:6 in favor of that at tests/stdlib/result/free.c:62
 [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
+  dropping duplicate def'n of func baz at tests/stdlib/free.c:9 in favor of that at tests/stdlib/result/free.c:94
 [kernel] tests/stdlib/free.c:12: Warning: 
-  dropping duplicate def'n of func with_void at tests/stdlib/free.c:12 in favor of that at tests/stdlib/result/free.c:99
+  dropping duplicate def'n of func with_void at tests/stdlib/free.c:12 in favor of that at tests/stdlib/result/free.c:100
+[kernel] tests/stdlib/free.c:15: Warning: 
+  dropping duplicate def'n of func with_incomplete at tests/stdlib/free.c:15 in favor of that at tests/stdlib/result/free.c:132
 /* Generated by Frama-C */
 #include "stdlib.h"
+struct incomplete;
 /*@ requires freeable: ptr ≡ \null ∨ \freeable(ptr);
     assigns __fc_heap_status;
     assigns __fc_heap_status \from __fc_heap_status, ptr;
@@ -219,4 +255,36 @@ void with_void(void *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_st_incomplete(struct incomplete *ptr)
+{
+  free((void *)ptr);
+  return;
+}
+
+void with_incomplete(struct incomplete *t)
+{
+  free_st_incomplete(t);
+  return;
+}
+
 
diff --git a/src/plugins/instantiate/tests/stdlib/oracle/malloc.res.oracle b/src/plugins/instantiate/tests/stdlib/oracle/malloc.res.oracle
index feb0c41909d..485abcec7f4 100644
--- a/src/plugins/instantiate/tests/stdlib/oracle/malloc.res.oracle
+++ b/src/plugins/instantiate/tests/stdlib/oracle/malloc.res.oracle
@@ -1,5 +1,6 @@
 [kernel] Parsing tests/stdlib/malloc.c (with preprocessing)
-[instantiate] tests/stdlib/malloc.c:21: Warning: Ignore call: not well typed
+[instantiate] tests/stdlib/malloc.c:23: Warning: Ignore call: not well typed
+[instantiate] tests/stdlib/malloc.c:24: Warning: Ignore call: not well typed
 /* Generated by Frama-C */
 #include "stdlib.h"
 struct X {
@@ -11,6 +12,7 @@ struct Flex {
    char c ;
    int f[] ;
 };
+struct incomplete;
 /*@ requires correct_size: 0 ≤ size - 8 ∧ 0 ≡ (size - 8) % 4;
     assigns \result, __fc_heap_status;
     assigns \result \from __fc_heap_status, size;
@@ -208,6 +210,7 @@ int main(void)
   struct Flex *f =
     malloc_st_Flex(sizeof(struct Flex) + (unsigned int)3 * sizeof(int));
   void *v = malloc(sizeof(char) * (unsigned int)10);
+  struct incomplete *inc = malloc((unsigned int)10);
   __retres = 0;
   return __retres;
 }
@@ -215,8 +218,8 @@ int main(void)
 
 [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 6403) conflicts with the one at tests/stdlib/result/malloc.c:198 (sum 8177); keeping the one at tests/stdlib/result/malloc.c:198.
+[kernel] tests/stdlib/malloc.c:16: Warning: 
+  def'n of func main at tests/stdlib/malloc.c:16 (sum 7290) conflicts with the one at tests/stdlib/result/malloc.c:199 (sum 9064); keeping the one at tests/stdlib/result/malloc.c:199.
 /* Generated by Frama-C */
 #include "stdlib.h"
 struct X {
@@ -228,6 +231,7 @@ struct Flex {
    char c ;
    int f[] ;
 };
+struct incomplete;
 /*@ requires correct_size: 0 ≤ size - 8 ∧ 0 ≡ (size - 8) % 4;
     assigns \result, __fc_heap_status;
     assigns \result \from __fc_heap_status, size;
@@ -425,6 +429,7 @@ int main(void)
   struct Flex *f =
     malloc_st_Flex(sizeof(struct Flex) + (unsigned int)3 * sizeof(int));
   void *v = malloc(sizeof(char) * (unsigned int)10);
+  struct incomplete *inc = malloc((unsigned int)10);
   __retres = 0;
   return __retres;
 }
-- 
GitLab