diff --git a/src/plugins/e-acsl/share/e-acsl/bittree_model/e_acsl_bittree.h b/src/plugins/e-acsl/share/e-acsl/bittree_model/e_acsl_bittree.h index 7f3d799a5653c5f96f1b2d490869d534a460cd4a..617807e4b7b2e1b43668884afe979097b3838676 100644 --- a/src/plugins/e-acsl/share/e-acsl/bittree_model/e_acsl_bittree.h +++ b/src/plugins/e-acsl/share/e-acsl/bittree_model/e_acsl_bittree.h @@ -21,7 +21,7 @@ /**************************************************************************/ /*! *********************************************************************** - * \file e_acsl_bittree.h + * \file e_acsl_bittree.h * \brief Patricia Trie API Implementation ***************************************************************************/ @@ -468,7 +468,7 @@ static void bt_print_node(bt_node * ptr, int depth) { } } -static void bt_print() { +static void bt_print_tree() { DLOG("------------DEBUG\n"); bt_print_node(bt_root, 0); DLOG("-----------------\n"); diff --git a/src/plugins/e-acsl/share/e-acsl/bittree_model/e_acsl_bittree_api.h b/src/plugins/e-acsl/share/e-acsl/bittree_model/e_acsl_bittree_api.h index 5f32ca605431b54c86ca074f0eb03e52c5b273ab..2913a829f55684b268d06caccad8a870389df99c 100644 --- a/src/plugins/e-acsl/share/e-acsl/bittree_model/e_acsl_bittree_api.h +++ b/src/plugins/e-acsl/share/e-acsl/bittree_model/e_acsl_bittree_api.h @@ -46,7 +46,7 @@ typedef struct bt_block bt_block; /*! \brief Structure representing a bittree node */ struct bt_node { _Bool is_leaf; - size_t addr, mask; + size_t addr, mask; struct bt_node * left, * right, * parent; bt_block * leaf; }; diff --git a/src/plugins/e-acsl/share/e-acsl/bittree_model/e_acsl_bittree_mmodel.c b/src/plugins/e-acsl/share/e-acsl/bittree_model/e_acsl_bittree_mmodel.c index 8aab4628b7b58d77ca15fc02de73dc150c4b0aac..406eebb83b1f70074012f63812eef6fa62261e73 100644 --- a/src/plugins/e-acsl/share/e-acsl/bittree_model/e_acsl_bittree_mmodel.c +++ b/src/plugins/e-acsl/share/e-acsl/bittree_model/e_acsl_bittree_mmodel.c @@ -21,8 +21,8 @@ /**************************************************************************/ /*! *********************************************************************** - * \file e_acsl_bittree_mmodel.c - * \brief Implementation of E-ACSL public API using a memory model based + * \file e_acsl_bittree_mmodel.c + * \brief Implementation of E-ACSL public API using a memory model based * on Patricia Trie. See e_acsl_mmodel_api.h for details. ***************************************************************************/ @@ -38,8 +38,9 @@ #include "e_acsl_mmodel_api.h" #include "e_acsl_bittree.h" -size_t __e_acsl_heap_size = 0; - +/**************************/ +/* SUPPORT {{{ */ +/**************************/ static const int nbr_bits_to_1[256] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,1,2,2,3,2,3, 3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4, @@ -50,182 +51,28 @@ static const int nbr_bits_to_1[256] = { 4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 }; -size_t __get_memory_size(void) { - return __e_acsl_heap_size; -} - /* given the size of the memory block (_size) return (or rather evaluate to) * size in bytes requred to represent its partial initialization */ #define needed_bytes(_size) \ ((_size % 8) == 0 ? (_size/8) : (_size/8 + 1)) +/* }}} */ /**************************/ -/* ALLOCATION */ +/* HEAP USAGE {{{ */ /**************************/ +static size_t heap_size = 0; -/* store the block of size bytes starting at ptr, the new block is returned. - * Warning: the return type is implicitly (bt_block*). */ -void* __e_acsl_store_block(void* ptr, size_t size) { - bt_block * tmp; - DASSERT(ptr != NULL); - tmp = native_malloc(sizeof(bt_block)); - DASSERT(tmp != NULL); - tmp->ptr = (size_t)ptr; - tmp->size = size; - tmp->init_ptr = NULL; - tmp->init_bytes = 0; - tmp->is_readonly = false; - tmp->freeable = false; - bt_insert(tmp); - return tmp; -} - -/* remove the block starting at ptr */ -void __e_acsl_delete_block(void* ptr) { - DASSERT(ptr != NULL); - bt_block * tmp = bt_lookup(ptr); - DASSERT(tmp != NULL); - bt_clean_block_init(tmp); - bt_remove(tmp); - native_free(tmp); -} - -/* allocate size bytes and store the returned block - * for further information, see malloc */ -void* malloc(size_t size) { - void * tmp; - bt_block * new_block; - if(size <= 0) - return NULL; - tmp = native_malloc(size); - if(tmp == NULL) - return NULL; - new_block = __e_acsl_store_block(tmp, size); - __e_acsl_heap_size += size; - DASSERT(new_block != NULL && (void*)new_block->ptr != NULL); - new_block->freeable = true; - return (void*)new_block->ptr; -} - -/* free the block starting at ptr, - * for further information, see free */ -void free(void* ptr) { - bt_block * tmp; - if(ptr == NULL) - return; - tmp = bt_lookup(ptr); - DASSERT(tmp != NULL); - native_free(ptr); - bt_clean_block_init(tmp); - __e_acsl_heap_size -= tmp->size; - bt_remove(tmp); - native_free(tmp); -} - -int __e_acsl_freeable(void* ptr) { - bt_block * tmp; - if(ptr == NULL) - return false; - tmp = bt_lookup(ptr); - if(tmp == NULL) - return false; - return tmp->freeable; -} - -/* resize the block starting at ptr to fit its new size, - * for further information, see realloc */ -void* realloc(void* ptr, size_t size) { - bt_block * tmp; - void * new_ptr; - /* ptr is NULL - malloc */ - if(ptr == NULL) - return malloc(size); - /* size is zero - free */ - if(size == 0) { - free(ptr); - return NULL; - } - tmp = bt_lookup(ptr); - DASSERT(tmp != NULL); - new_ptr = native_realloc((void*)tmp->ptr, size); - if(new_ptr == NULL) - return NULL; - __e_acsl_heap_size -= tmp->size; - /* realloc changes start address -- re-enter the element */ - if (tmp->ptr != (size_t)new_ptr) { - bt_remove(tmp); - tmp->ptr = (size_t)new_ptr; - bt_insert(tmp); - } - /* uninitialized, do nothing */ - if(tmp->init_bytes == 0) ; - /* already fully initialized block */ - else if (tmp->init_bytes == tmp->size) { - /* realloc smaller block */ - if(size <= tmp->size) - /* adjust new size, allocation not necessary */ - tmp->init_bytes = size; - /* realloc bigger larger block */ - else { - /* size of tmp->init_ptr in the new block */ - int nb = needed_bytes(size); - /* number of bits that need to be set in tmp->init_ptr */ - int nb_old = needed_bytes(tmp->size); - /* allocate memory to store partial initialization */ - tmp->init_ptr = native_calloc(1, nb); - /* carry out initialization of the old block */ - setbits(tmp->init_ptr, tmp->size); - } - } - /* contains initialized and uninitialized parts */ - else { - int nb = needed_bytes(size); - int nb_old = needed_bytes(tmp->size); - int i; - tmp->init_ptr = native_realloc(tmp->init_ptr, nb); - for(i = nb_old; i < nb; i++) - tmp->init_ptr[i] = 0; - tmp->init_bytes = 0; - for(i = 0; i < nb; i++) - tmp->init_bytes += nbr_bits_to_1[tmp->init_ptr[i]]; - if(tmp->init_bytes == size || tmp->init_bytes == 0) { - native_free(tmp->init_ptr); - tmp->init_ptr = NULL; - } - } - tmp->size = size; - tmp->freeable = true; - __e_acsl_heap_size += size; - return (void*)tmp->ptr; -} - -/* allocate memory for an array of nbr_block elements of size_block size, - * this memory is set to zero, the returned block is stored, - * for further information, see calloc */ -void* calloc(size_t nbr_block, size_t size_block) { - void * tmp; - size_t size = nbr_block * size_block; - bt_block * new_block; - if(size <= 0) - return NULL; - tmp = native_calloc(nbr_block, size_block); - if(tmp == NULL) - return NULL; - new_block = __e_acsl_store_block(tmp, size); - __e_acsl_heap_size += nbr_block * size_block; - DASSERT(new_block != NULL && (void*)new_block->ptr != NULL); - /* Mark allocated block as freeable and initialized */ - new_block->freeable = true; - new_block->init_bytes = size; - return (void*)new_block->ptr; +static size_t get_heap_size(void) { + return heap_size; } +/* }}} */ /**************************/ -/* INITIALIZATION */ +/* INITIALIZATION {{{ */ /**************************/ /* mark the size bytes of ptr as initialized */ -void __e_acsl_initialize (void * ptr, size_t size) { +static void initialize (void * ptr, size_t size) { bt_block * tmp; if(!ptr) return; @@ -275,7 +122,7 @@ void __e_acsl_initialize (void * ptr, size_t size) { } /* mark all bytes of ptr as initialized */ -void __e_acsl_full_init (void * ptr) { +static void full_init (void * ptr) { bt_block * tmp; if (ptr == NULL) return; @@ -292,7 +139,7 @@ void __e_acsl_full_init (void * ptr) { } /* mark a block as read-only */ -void __e_acsl_readonly (void * ptr) { +static void readonly(void * ptr) { bt_block * tmp; if (ptr == NULL) return; @@ -301,13 +148,24 @@ void __e_acsl_readonly (void * ptr) { return; tmp->is_readonly = true; } +/* }}} */ /**************************/ -/* PREDICATES */ +/* PREDICATES {{{ */ /**************************/ +static int freeable(void* ptr) { + bt_block * tmp; + if(ptr == NULL) + return false; + tmp = bt_lookup(ptr); + if(tmp == NULL) + return false; + return tmp->freeable; +} + /* return whether the size bytes of ptr are initialized */ -int __e_acsl_initialized (void * ptr, size_t size) { +static int initialized(void * ptr, size_t size) { unsigned i; bt_block * tmp = bt_find(ptr); if(tmp == NULL) @@ -320,7 +178,7 @@ int __e_acsl_initialized (void * ptr, size_t size) { if(tmp->init_bytes == tmp->size) return true; - /* see implementation of function __e_acsl_initialize for details */ + /* see implementation of function `initialize` for details */ for(i = 0; i < size; i++) { size_t offset = (uintptr_t)ptr - tmp->ptr + i; int byte = offset/8; @@ -332,90 +190,293 @@ int __e_acsl_initialized (void * ptr, size_t size) { } /* return the length (in bytes) of the block containing ptr */ -size_t __e_acsl_block_length(void* ptr) { +static size_t block_length(void* ptr) { bt_block * tmp = bt_find(ptr); - /* Hard failure when un-allocated memory is used */ + /* Hard failure when un-allocated memory is used */ vassert(tmp != NULL, "\\block_length of unallocated memory", NULL); return tmp->size; } /* return whether the size bytes of ptr are readable/writable */ -int __e_acsl_valid(void* ptr, size_t size) { - bt_block * tmp; +static int valid(void* ptr, size_t size) { if(ptr == NULL) return false; - tmp = bt_find(ptr); - return (tmp == NULL) ? - false : ( tmp->size - ( (size_t)ptr - tmp->ptr ) >= size - && !tmp->is_readonly); + bt_block * tmp = bt_find(ptr); + return (tmp == NULL) ? false : + (tmp->size - ((size_t)ptr - tmp->ptr ) >= size && !tmp->is_readonly); } /* return whether the size bytes of ptr are readable */ -int __e_acsl_valid_read(void* ptr, size_t size) { - bt_block * tmp; +static int valid_read(void* ptr, size_t size) { if(ptr == NULL) return false; - tmp = bt_find(ptr); + bt_block * tmp = bt_find(ptr); return (tmp == NULL) ? false : (tmp->size - ((size_t)ptr - tmp->ptr) >= size); } /* return the base address of the block containing ptr */ -void* __e_acsl_base_addr(void* ptr) { +static void* base_addr(void* ptr) { bt_block * tmp = bt_find(ptr); vassert(tmp != NULL, "\\base_addr of unallocated memory", NULL); return (void*)tmp->ptr; } /* return the offset of `ptr` within its block */ -int __e_acsl_offset(void* ptr) { +static int offset(void* ptr) { bt_block * tmp = bt_find(ptr); vassert(tmp != NULL, "\\offset of unallocated memory", NULL); - return ((size_t)ptr - tmp->ptr); + return ((uintptr_t)ptr - tmp->ptr); } +/* }}} */ /**************************/ -/* PROGRAM INITIALIZATION */ +/* ALLOCATION {{{ */ /**************************/ +/* STACK ALLOCATION {{{ */ +/* store the block of size bytes starting at ptr, the new block is returned. + * Warning: the return type is implicitly (bt_block*). */ +static void* store_block(void* ptr, size_t size) { + bt_block * tmp; + DASSERT(ptr != NULL); + tmp = native_malloc(sizeof(bt_block)); + DASSERT(tmp != NULL); + tmp->ptr = (uintptr_t)ptr; + tmp->size = size; + tmp->init_ptr = NULL; + tmp->init_bytes = 0; + tmp->is_readonly = false; + tmp->freeable = false; + bt_insert(tmp); + return tmp; +} + +/* remove the block starting at ptr */ +static void delete_block(void* ptr) { + DASSERT(ptr != NULL); + bt_block * tmp = bt_lookup(ptr); + DASSERT(tmp != NULL); + bt_clean_block_init(tmp); + bt_remove(tmp); + native_free(tmp); +} +/* }}} */ + +/* HEAP ALLOCATION {{{ */ +/*! \brief Replacement for `malloc` with memory tracking */ +static void* bittree_malloc(size_t size) { + if(size == 0) + return NULL; + + void *res = native_malloc(size); + if (res) { + bt_block * new_block = store_block(res, size); + heap_size += size; + new_block->freeable = true; + } + return res; +} + +/*! \brief Replacement for `calloc` with memory tracking */ +static void* bittree_calloc(size_t nbr_block, size_t size_block) { + /* FIXME: Need an integer overflow check here */ + size_t size = nbr_block * size_block; + if (size == 0) + return NULL; + + void *res = native_calloc(nbr_block, size_block); + if (res) { + bt_block * new_block = store_block(res, size); + heap_size += size; + new_block->freeable = 1; + /* Mark allocated block as freeable and initialized */ + new_block->init_bytes = size; + } + return res; +} + +/*! \brief Replacement for `aligned_alloc` with memory tracking */ +static void *bittree_aligned_alloc(size_t alignment, size_t size) { + /* Check if: + * - size and alignment are greater than zero + * - alignment is a power of 2 + * - size is a multiple of alignment */ + if (!size || !alignment || !powof2(alignment) || (size%alignment)) + return NULL; + + void *res = native_aligned_alloc(alignment, size); + if (res) { + bt_block * new_block = store_block(res, size); + new_block->freeable = 1; + heap_size += size; + } + return res; +} + +/*! \brief Replacement for `posix_memalign` with memory tracking */ +static int bittree_posix_memalign(void **memptr, size_t alignment, size_t size) { + /* Check if: + * - size and alignment are greater than zero + * - alignment is a power of 2 and a multiple of sizeof(void*) */ + if (!size || !alignment || !powof2(alignment) || alignment%sizeof(void*)) + return -1; + + /* Make sure that the first argument to posix memalign is indeed allocated */ + vassert(valid(memptr, sizeof(void*)), + "\\invalid memptr in posix_memalign", NULL); + + int res = native_posix_memalign(memptr, alignment, size); + if (!res) { + bt_block * new_block = store_block(*memptr, size); + new_block->freeable = 1; + heap_size += size; + } + return res; +} + +/*! \brief Replacement for `realloc` with memory tracking */ +static void* bittree_realloc(void* ptr, size_t size) { + bt_block * tmp; + void * new_ptr; + /* ptr is NULL - malloc */ + if(ptr == NULL) + return malloc(size); + /* size is zero - free */ + if(size == 0) { + free(ptr); + return NULL; + } + tmp = bt_lookup(ptr); + DASSERT(tmp != NULL); + new_ptr = native_realloc((void*)tmp->ptr, size); + if(new_ptr == NULL) + return NULL; + heap_size -= tmp->size; + /* realloc changes start address -- re-enter the element */ + if (tmp->ptr != (uintptr_t)new_ptr) { + bt_remove(tmp); + tmp->ptr = (uintptr_t)new_ptr; + bt_insert(tmp); + } + /* uninitialized, do nothing */ + if(tmp->init_bytes == 0) ; + /* already fully initialized block */ + else if (tmp->init_bytes == tmp->size) { + /* realloc smaller block */ + if (size <= tmp->size) { + /* adjust new size, allocation not necessary */ + tmp->init_bytes = size; + /* realloc bigger larger block */ + } else { + /* size of tmp->init_ptr in the new block */ + int nb = needed_bytes(size); + /* number of bits that need to be set in tmp->init_ptr */ + int nb_old = needed_bytes(tmp->size); + /* allocate memory to store partial initialization */ + tmp->init_ptr = native_calloc(1, nb); + /* carry out initialization of the old block */ + setbits(tmp->init_ptr, tmp->size); + } + } else { /* contains initialized and uninitialized parts */ + int nb = needed_bytes(size); + int nb_old = needed_bytes(tmp->size); + int i; + tmp->init_ptr = native_realloc(tmp->init_ptr, nb); + for (i = nb_old; i < nb; i++) + tmp->init_ptr[i] = 0; + tmp->init_bytes = 0; + for (i = 0; i < nb; i++) + tmp->init_bytes += nbr_bits_to_1[tmp->init_ptr[i]]; + if (tmp->init_bytes == size || tmp->init_bytes == 0) { + native_free(tmp->init_ptr); + tmp->init_ptr = NULL; + } + } + tmp->size = size; + tmp->freeable = true; + heap_size += size; + return (void*)tmp->ptr; +} + +/*! \brief Replacement for `free` with memory tracking */ +static void bittree_free(void* ptr) { + if (!ptr) + return; + bt_block * res = bt_lookup(ptr); + if (!res) { + vabort("Not a start of block (%a) in free\n", ptr); + } else { + heap_size -= res->size; + native_free(ptr); + bt_clean_block_init(res); + bt_remove(res); + } +} +/* }}} */ +/* }}} */ + +/******************************/ +/* PROGRAM INITIALIZATION {{{ */ +/******************************/ + /* erase the content of the abstract structure */ -void __e_acsl_memory_clean() { +static void memory_clean() { bt_clean(); } /* add `argv` to the memory model */ -static void __init_argv(int argc, char **argv) { +static void init_argv(int argc, char **argv) { int i; - __e_acsl_store_block(argv, (argc+1)*sizeof(char*)); - __e_acsl_full_init(argv); + store_block(argv, (argc+1)*sizeof(char*)); + full_init(argv); for (i = 0; i < argc; i++) { - __e_acsl_store_block(argv[i], strlen(argv[i])+1); - __e_acsl_full_init(argv[i]); + store_block(argv[i], strlen(argv[i])+1); + full_init(argv[i]); } } -void __e_acsl_memory_init(int *argc_ref, char ***argv_ref, size_t ptr_size) { +static void memory_init(int *argc_ref, char ***argv_ref, size_t ptr_size) { arch_assert(ptr_size); if (argc_ref) - __init_argv(*argc_ref, *argv_ref); -} - -/**********************/ -/* DEBUG */ -/**********************/ -#ifdef E_ACSL_DEBUG -/*! \brief print the information about a tracked block */ -void __e_acsl_print_block (bt_block * ptr) { - bt_print_block(ptr); -} - -/*! \brief print the content of the bittree */ -void __e_acsl_print_bittree() { - bt_print(); + init_argv(*argc_ref, *argv_ref); } +/* }}} */ + +/* API BINDINGS {{{ */ +/* Heap allocation (native) */ +strong_alias(bittree_malloc, malloc) +strong_alias(bittree_calloc, calloc) +strong_alias(bittree_realloc, realloc) +strong_alias(bittree_free, free) +strong_alias(bittree_posix_memalign, posix_memalign) +strong_alias(bittree_aligned_alloc, aligned_alloc) +/* Explicit tracking */ +public_alias(delete_block) +public_alias(store_block) +/* Predicates */ +public_alias(offset) +public_alias(base_addr) +public_alias(valid_read) +public_alias(valid) +public_alias(block_length) +public_alias(initialized) +public_alias(freeable) +public_alias(readonly) +/* Block initialization */ +public_alias(initialize) +public_alias(full_init) +/* Memory state initialization */ +public_alias(memory_clean) +public_alias(memory_init) +/* Heap size */ +public_alias(get_heap_size) +public_alias(heap_size) +#ifdef E_ACSL_DEBUG /* Debug */ +public_alias(bt_print_block) +public_alias(bt_print_tree) #endif +/* }}} */ #endif - - diff --git a/src/plugins/e-acsl/share/e-acsl/e_acsl_malloc.h b/src/plugins/e-acsl/share/e-acsl/e_acsl_malloc.h index e1e18e6993a5e1fff033bd9decd6f00c848206c8..1640746c7642518bd18f214fe892bda589f0c501 100644 --- a/src/plugins/e-acsl/share/e-acsl/e_acsl_malloc.h +++ b/src/plugins/e-acsl/share/e-acsl/e_acsl_malloc.h @@ -21,7 +21,7 @@ /**************************************************************************/ /*! *********************************************************************** - * \file e_acsl_malloc.h + * \file e_acsl_malloc.h * * \brief E-ACSL memory allocation bindings. ***************************************************************************/ @@ -34,12 +34,12 @@ #ifndef E_ACSL_MALLOC #define E_ACSL_MALLOC -/* Define ALIASNAME as a strong alias for NAME. */ +/** Define `aliasname` as a strong alias for `name`. */ # define strong_alias(name, aliasname) _strong_alias(name, aliasname) # define _strong_alias(name, aliasname) \ extern __typeof (name) aliasname __attribute__ ((alias (#name))); -/* Define ALIASNAME as a weak alias for NAME. */ +/** Define `aliasname` as a weak alias for `name`. */ # define weak_alias(name, aliasname) _weak_alias (name, aliasname) # define _weak_alias(name, aliasname) \ extern __typeof (name) aliasname __attribute__ ((weak, alias (#name))); @@ -47,25 +47,45 @@ # define preconcat(x,y) x ## y # define concat(x,y) preconcat(x,y) -/* Prefix added to all jemalloc functions, e.g., an actual jemalloc `malloc` +/** Prefix added to all jemalloc functions, e.g., an actual jemalloc `malloc` * is renamed to `__e_acsl_native_malloc` */ -# define native_prefix __e_acsl_native_ +# define native_prefix __e_acsl_native_ # define alloc_func_def(f,...) concat(native_prefix,f)(__VA_ARGS__) -# define alloc_func_macro(f) concat(native_prefix,f) +# define alloc_func_macro(f) concat(native_prefix,f) +/** Prefix added to public functions of E-ACSL public API */ +# define public_prefix __e_acsl_ +/** Make a strong alias from some function named `f` to __e_acsl_f */ +# define public_alias(f) strong_alias(f, concat(public_prefix,f)) +/** Make a strong alias from some function named `f1` to __e_acsl_f2 */ +# define public_alias2(f1,f2) strong_alias(f1, concat(public_prefix,f2)) + +/* The following declares jemalloc allocation functions. + * For instance: + * extern void *alloc_func_def(malloc, size_t); + * becomes: + * extern void *__e_acsl_native_malloc(size_t); */ extern void *alloc_func_def(malloc, size_t); extern void *alloc_func_def(calloc, size_t, size_t); extern void *alloc_func_def(realloc, void*, size_t); -extern void alloc_func_def(free,void*); +extern void *alloc_func_def(aligned_alloc, size_t, size_t); extern int alloc_func_def(posix_memalign, void **, size_t, size_t); +extern void alloc_func_def(free,void*); -# define native_malloc alloc_func_macro(malloc) -# define native_realloc alloc_func_macro(realloc) -# define native_calloc alloc_func_macro(calloc) -# define native_memalign alloc_func_macro(posix_memalign) -# define native_free alloc_func_macro(free) +/* Shortcuts for allocation functions used within this RTL (so they are not + * tracked). For example: + * native_malloc => __e_acsl_native_malloc */ +# define native_malloc alloc_func_macro(malloc) +# define native_realloc alloc_func_macro(realloc) +# define native_calloc alloc_func_macro(calloc) +# define native_posix_memalign alloc_func_macro(posix_memalign) +# define native_aligned_alloc alloc_func_macro(aligned_alloc) +# define native_free alloc_func_macro(free) +/* \return a true value if x is a power of 2 and false otherwise */ +static int powof2(size_t x) { + while (((x & 1) == 0) && x > 1) /* while x is even and > 1 */ + x >>= 1; + return (x == 1); +} #endif - - - diff --git a/src/plugins/e-acsl/share/e-acsl/e_acsl_mmodel_api.h b/src/plugins/e-acsl/share/e-acsl/e_acsl_mmodel_api.h index 021af64d8d1e38f6c930031f0ac39cad2bd88dda..66b47387ada98ef2b3bfffc58c10198061a2bb3c 100644 --- a/src/plugins/e-acsl/share/e-acsl/e_acsl_mmodel_api.h +++ b/src/plugins/e-acsl/share/e-acsl/e_acsl_mmodel_api.h @@ -36,7 +36,7 @@ * * For further information, see \p malloc(3). */ void * malloc(size_t size) - __attribute__((FC_BUILTIN)) ; + __attribute__((FC_BUILTIN)); /*! \brief Drop-in replacement for \p calloc with memory tracking enabled. * @@ -56,6 +56,23 @@ void * realloc(void * ptr, size_t size) void free(void * ptr) __attribute__((FC_BUILTIN)); +/*! \brief Allocate `size` bytes of memory such that the allocation's base + * address is an even multiple of alignment. + * + * \param alignment - should be the power of two + * \param size - should be the multiple of alignment + * \return - pointer to the allocated memory if the restrictions placed on size + * and alignment parameters hold. NULL is returned otherwise. */ +void *aligned_alloc(size_t alignment, size_t size) + __attribute__((FC_BUILTIN)); + +/*! \brief Allocate size bytes and place the address of the allocated memory in + * `*memptr`. The address of the allocated memory will be a multiple of + * `alignment`, which must be a power of two and a multiple of `sizeof(void*)`. + * If size is 0, then the value placed in *memptr is NULL. */ +int posix_memalign(void **memptr, size_t alignment, size_t size) + __attribute__((FC_BUILTIN)); + /*! \brief Store stack or globally-allocated memory block * starting at an address given by \p ptr. * @@ -102,8 +119,8 @@ int __e_acsl_freeable(void * ptr) /*! \brief Implementation of the \b \\valid predicate of E-ACSL. * - * Return a non-zero value if the first \p size bytes starting at an address given - * by \p ptr are readable and writable and 0 otherwise. */ + * Return a non-zero value if the first \p size bytes starting at an address + * given by \p ptr are readable and writable and 0 otherwise. */ /*@ ensures \result == 0 || \result == 1; @ ensures \result == 1 ==> \valid(((char *)ptr)+(0..size-1)); @ assigns \result \from *(((char*)ptr)+(0..size-1)); */ diff --git a/src/plugins/e-acsl/tests/e-acsl-runtime/memalign.c b/src/plugins/e-acsl/tests/e-acsl-runtime/memalign.c new file mode 100644 index 0000000000000000000000000000000000000000..f88e16873420998d41e04aa21655e3ae9524e8c3 --- /dev/null +++ b/src/plugins/e-acsl/tests/e-acsl-runtime/memalign.c @@ -0,0 +1,41 @@ +/* run.config + COMMENT: Check aligned heap memory allocation +*/ + +#include <stdlib.h> + +int posix_memalign(void **memptr, size_t alignment, size_t size); +void *aligned_alloc(size_t alignment, size_t size); + +int main(int argc, const char **argv) { + char **memptr = malloc(sizeof(void*)); + int res2 = posix_memalign((void**)memptr, 256, 15); + + char *p = *memptr; + /*@assert \valid(p); */ + /*@assert \block_length(p) == 15; */ + /*@assert \freeable(p); */ + free(p); + /*@assert ! \valid(p); */ + + char *a; + a = aligned_alloc(256, 12); + /*@assert a == \null; */ + + a = aligned_alloc(255, 512); + /*@assert a == \null; */ + + a = aligned_alloc(0, 512); + /*@assert a == \null; */ + + a = aligned_alloc(256, 512); + /*@assert a != \null; */ + /*@assert \valid(a); */ + /*@assert \block_length(a) == 512; */ + /*@assert \freeable(a); */ + + free(a); + /*@assert ! \valid(a); */ + + return 0; +} diff --git a/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/gen_memalign.c b/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/gen_memalign.c new file mode 100644 index 0000000000000000000000000000000000000000..12ea80643550b1c7d858a4de045856f0a9f9db4f --- /dev/null +++ b/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/gen_memalign.c @@ -0,0 +1,137 @@ +/* Generated by Frama-C */ +int main(int argc, char const **argv) +{ + int __retres; + char **memptr; + int res2; + char *p; + char *a; + __e_acsl_memory_init(& argc,(char ***)(& argv),8UL); + __e_acsl_store_block((void *)(& a),8UL); + __e_acsl_store_block((void *)(& p),8UL); + __e_acsl_store_block((void *)(& memptr),8UL); + __e_acsl_full_init((void *)(& memptr)); + memptr = (char **)malloc(sizeof(void *)); + res2 = posix_memalign((void **)memptr,(unsigned long)256,(unsigned long)15); + __e_acsl_full_init((void *)(& p)); + /*@ assert Value: mem_access: \valid_read(memptr); */ + p = *memptr; + /*@ assert \valid(p); */ + { + int __gen_e_acsl_initialized; + int __gen_e_acsl_and; + __gen_e_acsl_initialized = __e_acsl_initialized((void *)(& p), + sizeof(char *)); + if (__gen_e_acsl_initialized) { + int __gen_e_acsl_valid; + __gen_e_acsl_valid = __e_acsl_valid((void *)p,sizeof(char)); + __gen_e_acsl_and = __gen_e_acsl_valid; + } + else __gen_e_acsl_and = 0; + __e_acsl_assert(__gen_e_acsl_and,(char *)"Assertion",(char *)"main", + (char *)"\\valid(p)",15); + } + /*@ assert \block_length(p) ≡ 15; */ + { + unsigned long __gen_e_acsl_block_length; + __gen_e_acsl_block_length = __e_acsl_block_length((void *)p); + __e_acsl_assert(__gen_e_acsl_block_length == 15UL,(char *)"Assertion", + (char *)"main",(char *)"\\block_length(p) == 15",16); + } + /*@ assert \freeable(p); */ + { + int __gen_e_acsl_freeable; + __gen_e_acsl_freeable = __e_acsl_freeable((void *)p); + __e_acsl_assert(__gen_e_acsl_freeable,(char *)"Assertion",(char *)"main", + (char *)"\\freeable(p)",17); + } + free((void *)p); + /*@ assert ¬\valid(p); */ + { + int __gen_e_acsl_initialized_2; + int __gen_e_acsl_and_2; + __gen_e_acsl_initialized_2 = __e_acsl_initialized((void *)(& p), + sizeof(char *)); + if (__gen_e_acsl_initialized_2) { + int __gen_e_acsl_valid_2; + __gen_e_acsl_valid_2 = __e_acsl_valid((void *)p,sizeof(char)); + __gen_e_acsl_and_2 = __gen_e_acsl_valid_2; + } + else __gen_e_acsl_and_2 = 0; + __e_acsl_assert(! __gen_e_acsl_and_2,(char *)"Assertion",(char *)"main", + (char *)"!\\valid(p)",19); + } + __e_acsl_full_init((void *)(& a)); + a = (char *)aligned_alloc((unsigned long)256,(unsigned long)12); + /*@ assert a ≡ \null; */ + __e_acsl_assert(a == (void *)0,(char *)"Assertion",(char *)"main", + (char *)"a == \\null",23); + __e_acsl_full_init((void *)(& a)); + a = (char *)aligned_alloc((unsigned long)255,(unsigned long)512); + /*@ assert a ≡ \null; */ + __e_acsl_assert(a == (void *)0,(char *)"Assertion",(char *)"main", + (char *)"a == \\null",26); + __e_acsl_full_init((void *)(& a)); + a = (char *)aligned_alloc((unsigned long)0,(unsigned long)512); + /*@ assert a ≡ \null; */ + __e_acsl_assert(a == (void *)0,(char *)"Assertion",(char *)"main", + (char *)"a == \\null",29); + __e_acsl_full_init((void *)(& a)); + a = (char *)aligned_alloc((unsigned long)256,(unsigned long)512); + /*@ assert a ≢ \null; */ + __e_acsl_assert(a != (void *)0,(char *)"Assertion",(char *)"main", + (char *)"a != \\null",32); + /*@ assert \valid(a); */ + { + int __gen_e_acsl_initialized_3; + int __gen_e_acsl_and_3; + __gen_e_acsl_initialized_3 = __e_acsl_initialized((void *)(& a), + sizeof(char *)); + if (__gen_e_acsl_initialized_3) { + int __gen_e_acsl_valid_3; + __gen_e_acsl_valid_3 = __e_acsl_valid((void *)a,sizeof(char)); + __gen_e_acsl_and_3 = __gen_e_acsl_valid_3; + } + else __gen_e_acsl_and_3 = 0; + __e_acsl_assert(__gen_e_acsl_and_3,(char *)"Assertion",(char *)"main", + (char *)"\\valid(a)",33); + } + /*@ assert \block_length(a) ≡ 512; */ + { + unsigned long __gen_e_acsl_block_length_2; + __gen_e_acsl_block_length_2 = __e_acsl_block_length((void *)a); + __e_acsl_assert(__gen_e_acsl_block_length_2 == 512UL,(char *)"Assertion", + (char *)"main",(char *)"\\block_length(a) == 512",34); + } + /*@ assert \freeable(a); */ + { + int __gen_e_acsl_freeable_2; + __gen_e_acsl_freeable_2 = __e_acsl_freeable((void *)a); + __e_acsl_assert(__gen_e_acsl_freeable_2,(char *)"Assertion", + (char *)"main",(char *)"\\freeable(a)",35); + } + free((void *)a); + /*@ assert ¬\valid(a); */ + { + int __gen_e_acsl_initialized_4; + int __gen_e_acsl_and_4; + __gen_e_acsl_initialized_4 = __e_acsl_initialized((void *)(& a), + sizeof(char *)); + if (__gen_e_acsl_initialized_4) { + int __gen_e_acsl_valid_4; + __gen_e_acsl_valid_4 = __e_acsl_valid((void *)a,sizeof(char)); + __gen_e_acsl_and_4 = __gen_e_acsl_valid_4; + } + else __gen_e_acsl_and_4 = 0; + __e_acsl_assert(! __gen_e_acsl_and_4,(char *)"Assertion",(char *)"main", + (char *)"!\\valid(a)",38); + } + __retres = 0; + __e_acsl_delete_block((void *)(& a)); + __e_acsl_delete_block((void *)(& p)); + __e_acsl_delete_block((void *)(& memptr)); + __e_acsl_memory_clean(); + return __retres; +} + + diff --git a/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/memalign.err.oracle b/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/memalign.err.oracle new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/memalign.res.oracle b/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/memalign.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..48ed44b405da8727e629464d8dc8762c5640be83 --- /dev/null +++ b/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/memalign.res.oracle @@ -0,0 +1,18 @@ +[e-acsl] beginning translation. +FRAMAC_SHARE/libc/stdlib.h:147:[kernel] warning: No code nor implicit assigns clause for function calloc, generating default assigns from the prototype +[e-acsl] translation done in project "e-acsl". +tests/e-acsl-runtime/memalign.c:12:[kernel] warning: Neither code nor specification for function posix_memalign, generating default assigns from the prototype +tests/e-acsl-runtime/memalign.c:14:[value] warning: out of bounds read. assert \valid_read(memptr); +tests/e-acsl-runtime/memalign.c:15:[value] warning: assertion got status unknown. +FRAMAC_SHARE/e-acsl/e_acsl.h:43:[value] warning: function __e_acsl_assert: precondition got status unknown. +tests/e-acsl-runtime/memalign.c:16:[value] warning: assertion got status unknown. +tests/e-acsl-runtime/memalign.c:17:[value] warning: assertion got status unknown. +FRAMAC_SHARE/libc/stdlib.h:179:[value] warning: function free, behavior deallocation: precondition 'freeable' got status unknown. +tests/e-acsl-runtime/memalign.c:19:[value] warning: assertion got status unknown. +tests/e-acsl-runtime/memalign.c:22:[kernel] warning: Neither code nor specification for function aligned_alloc, generating default assigns from the prototype +tests/e-acsl-runtime/memalign.c:23:[value] warning: assertion got status unknown. +tests/e-acsl-runtime/memalign.c:26:[value] warning: assertion got status unknown. +tests/e-acsl-runtime/memalign.c:29:[value] warning: assertion got status unknown. +tests/e-acsl-runtime/memalign.c:32:[value] warning: assertion got status unknown. +tests/e-acsl-runtime/memalign.c:33:[value] warning: assertion got status unknown. +tests/e-acsl-runtime/memalign.c:34:[value] warning: assertion got status invalid (stopping propagation).