From 195e1b452ed5fd7b3e57947b614bffed90da9a4b Mon Sep 17 00:00:00 2001
From: Kostyantyn Vorobyov <kostyantyn.vorobyov@cea.fr>
Date: Mon, 15 May 2017 14:54:53 +0200
Subject: [PATCH] Set heap/stack shadow size via macros + debug macros

---
 .../segment_model/e_acsl_segment_mmodel.c     | 23 ++++---
 .../segment_model/e_acsl_segment_tracking.h   | 55 +++++++++++++++--
 .../segment_model/e_acsl_shadow_layout.h      | 60 ++++++++++++-------
 3 files changed, 102 insertions(+), 36 deletions(-)

diff --git a/src/plugins/e-acsl/share/e-acsl/segment_model/e_acsl_segment_mmodel.c b/src/plugins/e-acsl/share/e-acsl/segment_model/e_acsl_segment_mmodel.c
index 9385d11fa79..96c5b76e128 100644
--- a/src/plugins/e-acsl/share/e-acsl/segment_model/e_acsl_segment_mmodel.c
+++ b/src/plugins/e-acsl/share/e-acsl/segment_model/e_acsl_segment_mmodel.c
@@ -26,13 +26,16 @@
  *   model. See e_acsl_mmodel_api.h for details.
 ***************************************************************************/
 
-static int valid(void*, size_t, void*, void*);
-static int valid_read(void*, size_t, void*, void*);
-
 #include "e_acsl_shadow_layout.h"
 #include "e_acsl_segment_tracking.h"
 #include "e_acsl_mmodel_api.h"
 
+/* Forward declarations */
+static int valid(void*, size_t, void*, void*);
+static int valid_read(void*, size_t, void*, void*);
+
+#define ALLOCATED(_ptr,_size) allocated((uintptr_t)_ptr, _size, (uintptr_t)_ptr)
+
 static void * store_block(void * ptr, size_t size) {
   /* Only stack-global memory blocks are recorded explicitly via this function.
    * Heap blocks should be tracked internally using memory allocation functions
@@ -62,9 +65,9 @@ static void mark_readonly(void * ptr) {
   mark_readonly_region((uintptr_t)ptr, block_length(ptr));
 }
 
-/* ****************** */
-/* E-ACSL annotations */
-/* ****************** */
+/* ********************** */
+/* E-ACSL annotations {{{ */
+/* ********************** */
 
 /** \brief Return 1 if a given memory location is read-only and 0 otherwise */
 static int readonly (void *ptr) {
@@ -72,11 +75,13 @@ static int readonly (void *ptr) {
   return IS_ON_GLOBAL(addr) && global_readonly(addr) ? 1 : 0;
 }
 
-static int valid(void * ptr, size_t size, void *ptr_base, void *addr_of_base) {
-  return allocated((uintptr_t)ptr, size, (uintptr_t)ptr_base) && !readonly(ptr);
+static int valid(void * ptr, size_t size, void *ptr_base, void *addrof_base) {
+  return
+    allocated((uintptr_t)ptr, size, (uintptr_t)ptr_base) &&
+    !readonly(ptr);
 }
 
-static int valid_read(void * ptr, size_t size, void *ptr_base, void *addr_of_base) {
+static int valid_read(void * ptr, size_t size, void *ptr_base, void *addrof_base) {
   return allocated((uintptr_t)ptr, size, (uintptr_t)ptr_base);
 }
 
diff --git a/src/plugins/e-acsl/share/e-acsl/segment_model/e_acsl_segment_tracking.h b/src/plugins/e-acsl/share/e-acsl/segment_model/e_acsl_segment_tracking.h
index 75983f80bbb..2cce5183102 100644
--- a/src/plugins/e-acsl/share/e-acsl/segment_model/e_acsl_segment_tracking.h
+++ b/src/plugins/e-acsl/share/e-acsl/segment_model/e_acsl_segment_tracking.h
@@ -353,6 +353,25 @@ static void validate_memory_layout() {
   } \
 }
 
+/* Assert neither of `_len` addresses immediately preceding `_addr` are
+ * base addresses of some other block and that `_len` addresses past
+ * `_addr` are free */
+#define DVALIDATE_STATIC_SUFFICIENTLY_ALIGNED(_addr, _len) { \
+  int _i; \
+  for (_i = 0; _i < _len; _i++) { \
+    uintptr_t _prev = _addr - _i; \
+    if (static_allocated_one(_prev)) { \
+      vassert(base_addr(_prev) != _prev, \
+        "Potential backward overlap of: \n  previous block       [%a]\n" \
+        "  with allocated block [%a]\n", _prev, _addr); \
+    } \
+    uintptr_t _next = _addr + _i; \
+    vassert(!static_allocated_one(_next), \
+      "Potential forward overlap of:\n  following block location [%a]\n" \
+      "  with allocated block [%a]\n", _next, _addr); \
+  } \
+}
+
 /* Assert that a memory block [_addr, _addr + _size] is nullified */
 # define DVALIDATE_NULLIFIED(_addr, _size) \
   DVASSERT(zeroed_out((void *)_addr, _size), \
@@ -369,7 +388,7 @@ static void validate_memory_layout() {
 # define DVALIDATE_RW_ACCESS(_addr, _size) { \
   DVALIDATE_ALLOCATED((uintptr_t)_addr, _size, (uintptr_t)_addr); \
   DVASSERT(!readonly((void*)_addr), \
-    "Unexpected readonly address: %lu\n", _addr) \
+    "Unexpected readonly address: %lu\n", _addr); \
 }
 
 /* Assert that memory block [_addr, _addr + _size] is allocated */
@@ -396,13 +415,21 @@ static void validate_memory_layout() {
 #  define DVALIDATE_HEAP_FREE
 #  define DVALIDATE_RO_ACCESS
 #  define DVALIDATE_RW_ACCESS
-#	 define DVALIDATE_ALLOCATED
+#  define DVALIDATE_ALLOCATED
+#  define DVALIDATE_STATIC_SUFFICIENTLY_ALIGNED
 /*! \endcond */
 #endif
 /* }}} */
 
+/* Runtime assertions  {{{ */
+#define VALIDATE_HEAP_ALLOCATION(_res, _size) \
+  vassert(mem_layout.heap.end > (uintptr_t)_res + _size, \
+    "e-acsl error: Insufficient heap size %lu\n", E_ACSL_HEAP_SIZE);
+/* }}} */
+
 /* E-ACSL predicates {{{ */
 /* See definitions for documentation */
+static void *shadow_copy(const void *ptr, size_t size, int init);
 static uintptr_t heap_info(uintptr_t addr, char type);
 static uintptr_t static_info(uintptr_t addr, char type);
 static int heap_allocated(uintptr_t addr, size_t size, uintptr_t base_ptr);
@@ -825,8 +852,11 @@ static void* shadow_malloc(size_t size) {
   char* res = alloc_size ?
     (char*)native_aligned_alloc(HEAP_SEGMENT, alloc_size) : NULL;
 
-  if (res)
+  if (res) {
+    /* Make sure there is sufficient room in shadow */
+    VALIDATE_HEAP_ALLOCATION(res, alloc_size);
     set_heap_segment(res, size, alloc_size, 0, "malloc");
+  }
 
   return res;
 }
@@ -843,15 +873,23 @@ static void* shadow_calloc(size_t nmemb, size_t size) {
 
   /* Since aligned size is required by the model do the allocation through
    * `malloc` and nullify the memory space by hand */
-  char* res = size ? (char*)native_malloc(alloc_size) : NULL;
+  char* res =
+    size ? (char*)native_aligned_alloc(HEAP_SEGMENT, alloc_size) : NULL;
 
   if (res) {
+    /* Make sure there is sufficient room in shadow */
+    VALIDATE_HEAP_ALLOCATION(res, alloc_size);
     memset(res, 0, size);
     set_heap_segment(res, size, alloc_size, 1, "calloc");
   }
-
   return res;
 }
+
+/** \brief Return shadowed copy of a memory chunk on a program's heap */
+static void *shadow_copy(const void *ptr, size_t size, int init) {
+  char *ret = (init) ?	shadow_calloc(1, size) : shadow_malloc(size);
+  return memcpy(ret, ptr, size);
+}
 /* }}} */
 
 /* Heap deallocation (free) {{{ */
@@ -908,6 +946,7 @@ static void* shadow_realloc(void *ptr, size_t size) {
     if (freeable(ptr)) { /* ... and can be used as an input to `free` */
       size_t alloc_size = ALLOC_SIZE(size);
       res = native_realloc(ptr, alloc_size);
+      VALIDATE_HEAP_ALLOCATION(res, alloc_size);
       DVALIDATE_ALIGNMENT(res);
 
       /* realloc succeeds, otherwise nothing needs to be done */
@@ -965,8 +1004,11 @@ static void *shadow_aligned_alloc(size_t alignment, size_t size) {
     return NULL;
 
   char *res = native_aligned_alloc(alignment, size);
-  if (res)
+
+  if (res) {
+    VALIDATE_HEAP_ALLOCATION(res, ALLOC_SIZE(size));
     set_heap_segment(res, size, ALLOC_SIZE(size), 0, "aligned_alloc");
+  }
 
   return (void*)res;
 }
@@ -987,6 +1029,7 @@ static int shadow_posix_memalign(void **memptr, size_t alignment, size_t size) {
 
   int res = native_posix_memalign(memptr, alignment, size);
   if (!res) {
+    VALIDATE_HEAP_ALLOCATION(*memptr, ALLOC_SIZE(size));
     set_heap_segment(*memptr, size, ALLOC_SIZE(size), 0, "posix_memalign");
   }
   return res;
diff --git a/src/plugins/e-acsl/share/e-acsl/segment_model/e_acsl_shadow_layout.h b/src/plugins/e-acsl/share/e-acsl/segment_model/e_acsl_shadow_layout.h
index f2490f3164d..ef8d8ed379d 100644
--- a/src/plugins/e-acsl/share/e-acsl/segment_model/e_acsl_shadow_layout.h
+++ b/src/plugins/e-acsl/share/e-acsl/segment_model/e_acsl_shadow_layout.h
@@ -25,6 +25,16 @@
  * \brief Setup for memory tracking using shadowing
 ***************************************************************************/
 
+/* Default size of a program's heap tracked via shadow memory */
+#ifndef E_ACSL_HEAP_SIZE
+#define E_ACSL_HEAP_SIZE 512
+#endif
+
+/* Default size of a program's stack tracked via shadow memory */
+#ifndef E_ACSL_STACK_SIZE
+#define E_ACSL_STACK_SIZE 64
+#endif
+
 /* Symbols exported by the linker script */
 
 /*!\brief The first address past the end of the text segment. */
@@ -68,7 +78,7 @@ char *strerror(int errnum);
 
 /** Hardcoded sizes of tracked program segments {{{ */
 /*! \brief Size of a program's heap */
-#define PGM_HEAP_SIZE (512 * MB)
+#define PGM_HEAP_SIZE (E_ACSL_HEAP_SIZE * MB)
 
 /*! \brief Size of a program's Thread-local storage (TLS) */
 #define PGM_TLS_SIZE (16 * MB)
@@ -117,14 +127,40 @@ static uintptr_t get_tls_start() {
 /** Program stack information {{{ */
 extern char ** environ;
 
+/*! \brief Set a new soft stack limit
+ * \param size - new stack size in bytes */
+static size_t increase_stack_limit(const size_t size) {
+  const rlim_t stacksz = (rlim_t)size;
+  struct rlimit rl;
+  int result = getrlimit(RLIMIT_STACK, &rl);
+  if (result == 0) {
+    if (rl.rlim_cur < stacksz) {
+      rl.rlim_cur = stacksz;
+      result = setrlimit(RLIMIT_STACK, &rl);
+      if (result != 0) {
+        vabort("setrlimit: %s \n", strerror(errno));
+      }
+    }
+  }
+  return size;
+}
+
 /*! \brief Return byte-size of a program's stack. The return value is the soft
  * stack limit, i.e., it can be programmatically increased at runtime. */
-static size_t get_stack_size() {
+static size_t get_default_stack_size() {
   struct rlimit rlim;
   assert(!getrlimit(RLIMIT_STACK, &rlim));
   return rlim.rlim_cur;
 }
 
+static size_t get_stack_size() {
+#ifndef E_ACSL_STACK_SIZE
+  return get_default_stack_size();
+#else
+  return increase_stack_limit(E_ACSL_STACK_SIZE*MB);
+#endif
+}
+
 /*! \brief Return greatest (known) address on a program's stack.
  * This function presently determines the address using the address of the
  * last string in `environ`. That is, it assumes that argc and argv are
@@ -145,23 +181,6 @@ static uintptr_t get_stack_start(int *argc_ref,  char *** argv_ref) {
   uintptr_t stack_start = stack_end - get_stack_size();
   return stack_start;
 }
-
-/*! \brief Set a new soft stack limit
- * \param size - new stack size in bytes */
-static void increase_stack_limit(const size_t size) {
-  const rlim_t stacksz = (rlim_t)size;
-  struct rlimit rl;
-  int result = getrlimit(RLIMIT_STACK, &rl);
-  if (result == 0) {
-    if (rl.rlim_cur < stacksz) {
-      rl.rlim_cur = stacksz;
-      result = setrlimit(RLIMIT_STACK, &rl);
-      if (result != 0) {
-        vabort("setrlimit: %s \n", strerror(errno));
-      }
-    }
-  }
-}
 /* }}} */
 
 /** Program heap information {{{ */
@@ -345,7 +364,7 @@ static void set_shadow_segment(struct memory_segment *seg, uintptr_t start,
  * allocate shadow memory spaces and compute offsets. This function populates
  * global struct ::mem_layout holding that information with data. */
 static void init_memory_layout(int *argc_ref, char ***argv_ref) {
-  /* Use DEBUG_PRINT_LAYOUT to output the details (if they are needed) */
+  /* Use DEBUG_PRINT_LAYOUT to output the details */
   set_shadow_segment(&mem_layout.heap,
     get_heap_start(), get_heap_size(), 1, 8, "heap");
   set_shadow_segment(&mem_layout.stack,
@@ -367,7 +386,6 @@ void clean_memory_segment(struct memory_segment *seg) {
 
 /*! \brief Deallocate shadow regions used by runtime analysis */
 static void clean_memory_layout() {
-  DLOG("<<< Clean shadow layout >>>\n");
   if (mem_layout.initialized) {
     clean_memory_segment(&mem_layout.heap);
     clean_memory_segment(&mem_layout.stack);
-- 
GitLab