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 c1553b7d0b1522944e20bfa89be3e53c188ce7d2..24963982abf4105729497815964daef086a88026 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 @@ -136,21 +136,29 @@ static int initialized(void * ptr, size_t size) { return 0; } -static size_t get_heap_size(void) { - return heap_size; +static size_t get_heap_allocation_size(void) { + return heap_allocation_size; } static void memory_init(int *argc_ref, char *** argv_ref, size_t ptr_size) { + /** Verify that the given size of a pointer matches the one in the present + * architecture. This is a guard against Frama-C instrumentations using + * architectures different to the given one. */ arch_assert(ptr_size); + /* Initialize report file with debug logs (only in debug mode). */ initialize_report_file(argc_ref, argv_ref); - init_pgm_layout(argc_ref, argv_ref); + /* Lift stack limit to account for extra stack memory overhead. */ + increase_stack_limit(get_stack_size()*2); + /* Allocate and log shadow memory layout of the execution. */ + init_memory_layout(argc_ref, argv_ref); + DEBUG_PRINT_LAYOUT; + /* Track program arguments. */ if (argc_ref && argv_ref) argv_alloca(*argc_ref, *argv_ref); - DEBUG_PRINT_LAYOUT; } static void memory_clean(void) { - clean_pgm_layout(); + clean_memory_layout(); } /* API BINDINGS {{{ */ @@ -181,6 +189,6 @@ public_alias(full_init) public_alias(memory_clean) public_alias(memory_init) /* Heap size */ -public_alias(get_heap_size) -public_alias(heap_size) +public_alias(get_heap_allocation_size) +public_alias(heap_allocation_size) /* }}} */ 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 abc3fdc4405344d6602dadb44f8010d4c04a2ce2..ebc8c99abef6253f19a0f4e6774c782112acce8f 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 @@ -43,10 +43,10 @@ /*! \brief Size (in bytes) of a long block on the stack. */ #define LONG_BLOCK 8 -/*! \brief Bit offset in a short shadow byte that represents initialization. */ +/*! \brief Bit offset in a primary shadow byte that represents initialization. */ #define INIT_BIT 0 -/*! \brief Bit offset in a short shadow byte that represents read-only or +/*! \brief Bit offset in a primary shadow byte that represents read-only or * read-write access. * * This is such that the value of 1 is read-only, and 0 is read/write */ @@ -67,16 +67,16 @@ /*! \brief Short shadow of a long block consists of a 8-byte segment + a * remainder. For instance, a 18-byte block is represented by two 8-byte - * segments + 2 bytes. Each byte of a segment stores an offset in the long + * segments + 2 bytes. Each byte of a segment stores an offset in the secondary * shadow. The offsets for each such segment can be expressed using the * following number obtained by compressing all eight bytes with offsets set * into a single block. */ #define LONG_BLOCK_MASK 15913703276567643328UL /*! \brief 6 higher bytes of a memory cell on stack that belongs to a long - * memory block store offsets relative to meta-data in long shadow. The offsets - * start with the below number. E.g., if the bits store 51, then the offset at - * which to read meta-data is (51 - 48). */ + * memory block store offsets relative to meta-data in the secondary shadow. The + * offsets start with the below number. E.g., if the bits store 51, then the + * offset at which to read meta-data is (51 - 48). */ #define LONG_BLOCK_INDEX_START 48 /*! \brief Increase the size to a multiple of a segment size. */ @@ -211,7 +211,7 @@ static int freeable(void *ptr); * This macro really belongs where static_allocated is defined, but * since it is used across this whole file it needs to be defined here. */ #define static_allocated_one(addr, global) \ - ((int)SHORT_SHADOW(addr, global)) + ((int)PRIMARY_SHADOW(addr, global)) /* Runtime assertions */ #define VALIDATE_ALIGNMENT(_addr) \ @@ -221,7 +221,7 @@ static int freeable(void *ptr); /* Debug-level macros for validating memory accesses and allocation */ #ifdef E_ACSL_DEBUG # define DVALIDATE_SHADOW_LAYOUT \ - DVASSERT(pgm_layout.initialized != 0, "Un-initialized shadow layout", NULL) + DVASSERT(mem_layout.initialized != 0, "Un-initialized shadow layout", NULL) # define DVALIDATE_HEAP_ACCESS(_addr, _size) \ DVALIDATE_SHADOW_LAYOUT; \ @@ -326,8 +326,8 @@ static uintptr_t predicate(uintptr_t addr, char p) { * and then for a block of 5 bytes its base offset if 11 etc. */ static const char short_offsets_base [] = { 0, 1, 2, 4, 7, 11, 16, 22, 29 }; -/*! \brief Static (stack or global) memory-allocation. Record allocation of a - * given memory block and update shadow regions. +/*! \brief Stack or global memory-allocation. Record allocation of a + * given memory block and update shadows. * * \param ptr - pointer to a base memory address of the stack memory block. * \param size - size of the stack memory block. @@ -337,11 +337,11 @@ static void shadow_alloca(void *ptr, size_t size, int global) { DVALIDATE_SHADOW_LAYOUT; unsigned char *short_shadowed = - (unsigned char*)SHORT_SHADOW((uintptr_t)ptr, global); + (unsigned char*)PRIMARY_SHADOW(ptr, global); uint64_t *short_shadowed_alt = - (uint64_t *)SHORT_SHADOW((uintptr_t)ptr, global); + (uint64_t *)PRIMARY_SHADOW(ptr, global); unsigned int *long_shadowed = - (unsigned int*)LONG_SHADOW((uintptr_t)ptr, global); + (unsigned int*)SECONDARY_SHADOW(ptr, global); /* Flip read-only bit for zero-size blocks. That is, physically it exists * but one cannot write to it. Further, the flipped read-only bit will also @@ -391,8 +391,8 @@ static void static_shadow_freea(void *ptr, int global) { size_t size = block_length(ptr); - memset((void*)SHORT_SHADOW(ptr, global), 0, size); - memset((void*)LONG_SHADOW(ptr, global), 0, size); + memset((void*)PRIMARY_SHADOW(ptr, global), 0, size); + memset((void*)SECONDARY_SHADOW(ptr, global), 0, size); } /*! \brief Wrapper around ::static_shadow_freea for stack addresses */ @@ -409,7 +409,7 @@ static void static_shadow_freea(void *ptr, int global) { * applied to a stack or global address. */ static int static_allocated(uintptr_t addr, long size, int global) { DVALIDATE_SHADOW_LAYOUT; - unsigned char *short_shadowed = (unsigned char*)SHORT_SHADOW(addr, global); + unsigned char *short_shadowed = (unsigned char*)PRIMARY_SHADOW(addr, global); /* Unless the address belongs to tracked allocation 0 is returned */ if (short_shadowed[0]) { unsigned int code = (short_shadowed[0] >> 2); @@ -418,7 +418,7 @@ static int static_allocated(uintptr_t addr, long size, int global) { if (long_block) { offset = code - LONG_BLOCK_INDEX_START; unsigned int *long_shadowed = - (unsigned int*)LONG_SHADOW(addr - offset, global) ; + (unsigned int*)SECONDARY_SHADOW(addr - offset, global) ; length = long_shadowed[0]; offset = long_shadowed[1] + offset; } else { @@ -444,7 +444,7 @@ static int static_initialized(uintptr_t addr, long size, int global) { DVALIDATE_STATIC_ACCESS(addr, size, global); int result = 1; - uint64_t *shadow = (uint64_t*)SHORT_SHADOW(addr, global); + uint64_t *shadow = (uint64_t*)PRIMARY_SHADOW(addr, global); while (size > 0) { int rem = (size >= ULONG_BYTES) ? ULONG_BYTES : size; uint64_t mask = static_init_masks[rem]; @@ -471,7 +471,7 @@ static int static_initialized(uintptr_t addr, long size, int global) { * read-only parts, that is to check whether the block has read-only access it * is sufficient to check any of its bytes. */ #define global_readonly(_addr) \ - checkbit(READONLY_BIT, (*(char*)SHORT_GLOBAL_SHADOW(addr))) + checkbit(READONLY_BIT, (*(char*)PRIMARY_GLOBAL_SHADOW(addr))) /*! \brief Querying information about a specific global or stack memory address * (based on the value of parameter `global'). The return value is interpreted @@ -490,7 +490,7 @@ static int static_initialized(uintptr_t addr, long size, int global) { * unspecified. */ static uintptr_t static_info(uintptr_t addr, char type, int global) { DVALIDATE_STATIC_LOCATION(addr, global); - unsigned char *short_shadowed = (unsigned char*)SHORT_SHADOW(addr, global); + unsigned char *short_shadowed = (unsigned char*)PRIMARY_SHADOW(addr, global); /* Unless the address belongs to tracked allocation 0 is returned */ if (short_shadowed[0]) { @@ -499,7 +499,7 @@ static uintptr_t static_info(uintptr_t addr, char type, int global) { if (long_block) { unsigned int offset = code - LONG_BLOCK_INDEX_START; unsigned int *long_shadowed = - (unsigned int*)LONG_SHADOW(addr - offset, global) ; + (unsigned int*)SECONDARY_SHADOW(addr - offset, global) ; switch(type) { case 'B': /* Base address */ return addr - offset - long_shadowed[1]; @@ -567,7 +567,7 @@ static void initialize_static_region(uintptr_t addr, long size, int global) { * That is, `*shadow |= static_init_masks[1]` will set only the least * significant bit in *shadow. */ - uint64_t *shadow = (uint64_t*)SHORT_SHADOW(addr, global); + uint64_t *shadow = (uint64_t*)PRIMARY_SHADOW(addr, global); while (size > 0) { int rem = (size >= ULONG_BYTES) ? ULONG_BYTES : size; size -= ULONG_BYTES; @@ -603,7 +603,7 @@ static void mark_readonly (uintptr_t addr, long size) { size, addr, block_length(addr), base_addr(addr)); /* See comments in ::initialize_static_region for details */ - uint64_t *shadow = (uint64_t*)SHORT_GLOBAL_SHADOW(addr); + uint64_t *shadow = (uint64_t*)PRIMARY_GLOBAL_SHADOW(addr); while (size > 0) { int rem = (size >= ULONG_BYTES) ? ULONG_BYTES : size; size -= ULONG_BYTES; @@ -632,7 +632,7 @@ static void argv_alloca(int argc, char ** argv) { /*! \brief Amount of heap memory allocated by the program. * Variable visible externally. */ -static size_t heap_size = 0; +static size_t heap_allocation_size = 0; /*! \brief Create a heap shadow for an allocated memory block starting at `ptr` * and of length `size`. Optionally mark it as initialized if `init` @@ -644,7 +644,7 @@ static void set_heap_segment(void *ptr, size_t size, size_t init) { return; VALIDATE_ALIGNMENT(ptr); /* Make sure alignment is right */ - heap_size += size; /* Adjuct tracked allocation size */ + heap_allocation_size += size; /* Adjuct tracked allocation size */ /* Get aligned size of the block, i.e., an actual size of the * allocated block */ @@ -743,8 +743,8 @@ static void shadow_free(void *res) { void *meta_shadow = (void*)(HEAP_SHADOW(ptr) - HEAP_SEGMENT); memset(meta_shadow, 0, HEAP_SHADOW_BLOCK_SIZE(size)); native_free(ptr - HEAP_SEGMENT); - /* Adjuct tracked allocation size carried via `__e_acsl_heap_size` */ - heap_size -= size; + /* Adjuct tracked allocation size carried via `__e_acsl_heap_allocation_size` */ + heap_allocation_size -= size; } else { vabort("Not a start of block (%a) in free\n", ptr); } @@ -780,7 +780,7 @@ static void* shadow_realloc(void *p, size_t size) { /* Number of block segments in the new allocation */ size_t new_segments = BLOCK_SEGMENTS(size); /* Adjuct tracked allocation size */ - heap_size += -old_size + size; + heap_allocation_size += -old_size + size; /* Address of the meta-block in old allocation */ uintptr_t *meta_shadow = (uintptr_t*)(HEAP_SHADOW(ptr) - HEAP_SEGMENT); @@ -1080,7 +1080,7 @@ static void initialize(void *ptr, size_t n) { /* Internal state print {{{ */ #ifdef E_ACSL_DEBUG -/* ! \brief Print human-readable representation of a byte in a short (byte) +/* ! \brief Print human-readable representation of a byte in a primary * shadow */ static void printbyte(unsigned char c, char buf[]) { if (c >> 2 < LONG_BLOCK_INDEX_START) { @@ -1095,13 +1095,13 @@ static void printbyte(unsigned char c, char buf[]) { } /*! \brief Print human-readable (well, ish) representation of a memory block - * using short (byte) and long (block) shadow regions */ + * using primary and secondary shadows. */ static void print_static_shadows(uintptr_t addr, size_t size, int global) { char short_buf[256]; char long_buf[256]; - unsigned char *short_shadowed = (unsigned char*)SHORT_SHADOW(addr, global); - unsigned int *long_shadowed = (unsigned int*)LONG_SHADOW(addr, global); + unsigned char *short_shadowed = (unsigned char*)PRIMARY_SHADOW(addr, global); + unsigned int *long_shadowed = (unsigned int*)SECONDARY_SHADOW(addr, global); int i, j = 0; for (i = 0; i < size; i++) { @@ -1152,60 +1152,27 @@ static void print_shadows(uintptr_t addr, size_t size) { print_heap_shadows(addr, size); } -static void print_pgm_layout() { - DLOG("| --- Stack ------------------------------------\n"); - DLOG("|Stack Shadow Size: %16lu MB\n", - MB_SZ(pgm_layout.stack_shadow_size)); - DLOG("|Stack Start: %19lu\n", pgm_layout.stack_start); - DLOG("|Stack End: %19lu\n", pgm_layout.stack_end); - DLOG("|Stack Soft Bound: %19lu\n", pgm_layout.stack_soft_bound); - DLOG("| --- Short Stack Shadow -----------------------\n"); - DLOG("|Short Stack Shadow Offset: %19lu\n", - pgm_layout.short_stack_shadow_offset); - DLOG("|Short Stack Shadow Start: %19lu\n", - pgm_layout.short_stack_shadow_start); - DLOG("|Short Stack Shadow End: %19lu\n", - pgm_layout.short_stack_shadow_end); - DLOG("| --- Long Stack Shadow ------------------------\n"); - DLOG("|Long Stack Shadow Offset: %19lu\n", - pgm_layout.long_stack_shadow_offset); - DLOG("|Long Stack Shadow Start: %19lu\n", - pgm_layout.long_stack_shadow_start); - DLOG("|Long Stack Shadow End: %19lu\n", - pgm_layout.long_stack_shadow_end); - DLOG("| --- Heap -------------------------------------\n"); - DLOG("|Heap Shadow Size: %16lu MB\n", - MB_SZ(pgm_layout.heap_shadow_size)); - DLOG("|Heap Shadow Offset: %19lu\n", pgm_layout.heap_shadow_offset); - DLOG("|Heap Start: %19lu\n", pgm_layout.heap_start); - DLOG("|Heap End: %19lu\n", pgm_layout.heap_end); - DLOG("|Heap Shadow Start: %19lu\n", pgm_layout.heap_shadow_start); - DLOG("|Heap Shadow End: %19lu\n", pgm_layout.heap_shadow_end); - DLOG("| --- Global -----------------------------------\n"); - DLOG("|Global Shadow Size: %16lu MB\n", MB_SZ(pgm_layout.global_shadow_size)); - DLOG("|Global Start: %19lu\n", pgm_layout.global_start); - DLOG("|Global End: %19lu\n", pgm_layout.global_end); - DLOG("| --- Short Global Shadow ----------------------\n"); - DLOG("|Short Global Shadow Offset: %19lu\n", pgm_layout.short_global_shadow_offset); - DLOG("|Short Global Shadow Start: %19lu\n", pgm_layout.short_global_shadow_start); - DLOG("|Short Global Shadow End: %19lu\n", pgm_layout.short_global_shadow_end); - DLOG("| --- Long Global Shadow -----------------------\n"); - DLOG("|Long Global Shadow Offset: %19lu\n", pgm_layout.long_global_shadow_offset); - DLOG("|Long Global Shadow Start: %19lu\n", pgm_layout.long_global_shadow_start); - DLOG("|Long Global Shadow End: %19lu\n", pgm_layout.long_global_shadow_end); - DLOG("| --- TLS -----------------------------------\n"); - DLOG("|TLS Shadow Size: %16lu MB\n", MB_SZ(pgm_layout.tls_shadow_size)); - DLOG("|TLS Start: %19lu\n", pgm_layout.tls_start); - DLOG("|TLS End: %19lu\n", pgm_layout.tls_end); - DLOG("| --- Short TLS Shadow ----------------------\n"); - DLOG("|Short TLS Shadow Offset: %19lu\n", pgm_layout.short_tls_shadow_offset); - DLOG("|Short TLS Shadow Start: %19lu\n", pgm_layout.short_tls_shadow_start); - DLOG("|Short TLS Shadow End: %19lu\n", pgm_layout.short_tls_shadow_end); - DLOG("| --- Long TLS Shadow -----------------------\n"); - DLOG("|Long TLS Shadow Offset: %19lu\n", pgm_layout.long_tls_shadow_offset); - DLOG("|Long TLS Shadow Start: %19lu\n", pgm_layout.long_tls_shadow_start); - DLOG("|Long TLS Shadow End: %19lu\n", pgm_layout.long_tls_shadow_end); - DLOG("------------------------------------------------\n"); +static void print_memory_segment(struct memory_segment *seg, const char *name) { + DLOG(" --- %s ------------------------------------------\n", name); + DLOG("%s Shadow Size: %16lu MB\n", name, MB_SZ(seg->shadow_size)); + DLOG("%s Start: %19lu\n", name, seg->start); + DLOG("%s End: %19lu\n", name, seg->end); + DLOG("%s Primary Shadow Offset: %19lu\n", name, seg->prim_offset); + DLOG("%s Primary Shadow Start: %19lu\n", name, seg->prim_start); + DLOG("%s Primary Shadow End: %19lu\n", name, seg->prim_end); + if (seg->sec_start) { + DLOG("%s Secondary Shadow Offset: %19lu\n", name, seg->sec_offset); + DLOG("%s Secondary Shadow Start: %19lu\n", name, seg->sec_start); + DLOG("%s Secondary Shadow End: %19lu\n", name, seg->sec_end); + } +} + +static void print_memory_layout() { + print_memory_segment(&mem_layout.heap, "Heap"); + print_memory_segment(&mem_layout.stack, "Stack"); + print_memory_segment(&mem_layout.global, "Global"); + print_memory_segment(&mem_layout.tls, "TLS"); + DLOG("-----------------------------------------------------\n"); } /*! \brief Output the shadow segment the address belongs to */ @@ -1229,7 +1196,7 @@ static void which_segment(uintptr_t addr) { /*! \brief Print program layout. This function outputs start/end addresses of * various program segments, their shadow counterparts and sizes of shadow * regions used. */ -#define DEBUG_PRINT_LAYOUT print_pgm_layout() +#define DEBUG_PRINT_LAYOUT print_memory_layout() void ___e_acsl_debug_print_layout() { DEBUG_PRINT_LAYOUT; } /*! \brief Print the shadow segment address addr belongs to */ 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 896d6c272c1843922f842a4d980397b893b886ff..73f591d3909083416f4304ca05cf06a476fac4d3 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,8 +25,7 @@ * \brief Setup for memory tracking using shadowing ***************************************************************************/ -/*! \brief The first address past the end of the uninitialized data (BSS) - * segment . */ +/*! \brief The first address past the end of BSS segment */ extern char end; /* \cond */ @@ -49,15 +48,6 @@ char *strerror(int errnum); #define MB_SZ(_s) (_s/MB) //!< Convert bytes to megabytes #define GB_SZ(_s) (_s/GB) //!< Convert bytes to gigabytes -/*! \brief Size of the heap shadow */ -#define HEAP_SHADOW_SIZE (1024 * MB) - -/*! \brief Size of a stack shadow */ -#define STACK_SHADOW_SIZE (72 * MB) - -/*! \brief Size of the TLS shadow */ -#define TLS_SHADOW_SIZE (64 * MB) - /*! \brief Pointer size (in bytes) for a given system */ #define PTR_SZ sizeof(uintptr_t) @@ -68,7 +58,15 @@ char *strerror(int errnum); #define ULONG_BYTES 8 #define ULONG_BITS 64 -/* Thread-local storage information {{{ */ +/** Hardcoded sizes of tracked program segments {{{ */ +/*! \brief Size of the heap segment */ +#define PGM_HEAP_SIZE (256 * MB) + +/*! \brief Size of the TLS segment */ +#define PGM_TLS_SIZE (8 * MB) +/* }}} */ + +/** Thread-local storage information {{{ */ /*! Thread-local storage (TLS) keeps track of copies of per-thread variables. * Even though at the present stage RTL of E-ACSL is not thread-safe, some @@ -90,32 +88,43 @@ char *strerror(int errnum); * start TLS address (&id_bss - TLS_SHADOW_SIZE/2) */ +/*! Get byte-size of TLS segment */ +static size_t get_tls_size() { + return PGM_TLS_SIZE; +} + static __thread int id_tdata = 1; static __thread int id_tbss; /*! Set TLS size and its end and start addresses. */ -static void set_tls_bounds(uintptr_t *tls_end, - uintptr_t *tls_start, uintptr_t *tls_size) { - uintptr_t - data = (uintptr_t)&id_tdata, - bss = (uintptr_t)&id_tbss; - - *tls_end = ((data > bss) ? data : bss) + TLS_SHADOW_SIZE/2; - *tls_start = ((data > bss) ? bss : data) - TLS_SHADOW_SIZE/2, - *tls_size = *tls_end - *tls_start; +static uintptr_t get_tls_start() { + size_t tls_size = get_tls_size(); + uintptr_t data = (uintptr_t)&id_tdata, + bss = (uintptr_t)&id_tbss; + return ((data > bss ? bss : data) - tls_size/2); } + /* }}} */ -/* Program stack information {{{ */ +/** Program stack information {{{ */ extern char ** environ; +/*! \brief Get the stack size (in bytes) as used by the program. The return + * value is the soft stack limit, i.e., it can be programmatically increased + * at runtime */ +static size_t get_stack_size() { + struct rlimit rlim; + assert(!getrlimit(RLIMIT_STACK, &rlim)); + return rlim.rlim_cur; +} + /*! \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 * stored below environ, which holds for GCC/GLIBC but is not necessarily * true. In general, a reliable way of detecting the upper bound of a stack * segment is needed. */ -static uintptr_t get_stack_end(int *argc_ref, char *** argv_ref) { +static uintptr_t get_stack_start(int *argc_ref, char *** argv_ref) { char **env = environ; while (env[1]) env++; @@ -126,16 +135,9 @@ static uintptr_t get_stack_end(int *argc_ref, char *** argv_ref) { * to be able to set initialization and read-only bits ::ULONG_BITS * at a time. If not respected, this may cause a segfault in * ::argv_alloca. */ - return addr + ULONG_BITS; -} - -/*! \brief Get the stack size (in bytes) as used by the program. The return - * value is the soft stack limit, i.e., it can be programmatically increased - * at runtime */ -static size_t get_stack_size() { - struct rlimit rlim; - assert(!getrlimit(RLIMIT_STACK, &rlim)); - return rlim.rlim_cur; + uintptr_t stack_end = addr + ULONG_BITS; + uintptr_t stack_start = stack_end - get_stack_size(); + return stack_start; } /*! \brief Set a new stack limit @@ -156,6 +158,30 @@ static void increase_stack_limit(const size_t size) { } /* }}} */ +/** Program heap information {{{ */ +static uintptr_t get_heap_start() { + return (uintptr_t)sbrk(0); +} + +static size_t get_heap_size() { + return PGM_HEAP_SIZE; +} +/** }}} */ + +/** Program global information {{{ */ +static uintptr_t get_global_start() { + return (uintptr_t)(PTR_SZ*2); +} + +/*! \brief Get byte-size of global segment */ +static size_t get_global_size() { +/* In all likelihood it is reasonably safe to assume that first + * 2x*pointer-size bytes of the memory space will not be used. */ + return ((uintptr_t)&end - get_global_start()); +} +/** }}} */ + + /** MMAP allocation {{{ */ /*! \brief Allocate a memory block of `size` bytes with `mmap` and return a * pointer to its base address. Since this function is used to set-up shadowing @@ -176,15 +202,12 @@ static void *do_mmap(size_t size) { * start address of a segment */ static uintptr_t shadow_offset(void *shadow, uintptr_t start_addr) { uintptr_t start_shadow = (uintptr_t)shadow; - return (start_shadow > start_addr) ? start_shadow - start_addr : start_addr - start_shadow; } /* }}} */ -/* Program Layout {{{ */ - - +/** Program Layout {{{ */ /***************************************************************************** * Memory Layout ************************************************************* ***************************************************************************** @@ -227,197 +250,89 @@ NOTE: With mmap allocations heap does not necessarily grows from program break upwards from program break. */ -static struct program_layout pgm_layout; - -/*! \brief Structure for tracking shadow regions and boundaries of memory - * segments. */ -struct program_layout { - uintptr_t stack_start; //!< Least address in program stack - uintptr_t stack_end; //!< Greatest address in program stack. - uintptr_t stack_soft_bound; /*!< \brief Address of the soft stack bound. - A program using stack addresses beyond (i.e., less than) the soft bound - runs into a stack overflow. */ - size_t stack_shadow_size; /*!< \brief Size (in bytes) of a stack shadow. - Same size if used for short and long shadow regions. */ - - uintptr_t short_stack_shadow_start; //!< Least address in short shadow region - uintptr_t short_stack_shadow_end; //!< Greatest address in short shadow region - uintptr_t short_stack_shadow_offset; /*!< \brief Short shadow offset. - The offset is kept as a positive (unsigned) integer - relative to the stack shadow region situated below the stack. That is, - to get a shadow address from an actual one the offset needs to be - subtracted. */ - - uintptr_t long_stack_shadow_start; //!< Least address in long shadow region - uintptr_t long_stack_shadow_end; //!< Greatest address in long shadow region - uintptr_t long_stack_shadow_offset; /*!< \brief Long shadow offset. Similar - to #short_stack_shadow_offset */ - - uintptr_t heap_start; //!< Least address in a program's heap. - uintptr_t heap_end; //!< Greatest address in a program's heap. - - uintptr_t heap_shadow_start; /*!< \brief Least address in a program's shadow - heap region. */ - uintptr_t heap_shadow_end; /*!< \brief Greatest address in a program's - shadow heap region. */ - size_t heap_shadow_size; //!< Size (in bytes) of the heap shadow region. */ - uintptr_t heap_shadow_offset; /*!< \brief Short shadow offset. - * The offset is kept as a positive (unsigned) integer - * relative to the heap shadow region situated above the heap. That is, - * unlike stack shadow, to get a shadow address from an actual one the - * offset needs to be added. */ - - /* Same as `stack_...` but for shadowing globals */ - uintptr_t global_end; - uintptr_t global_start; - size_t global_shadow_size; - - uintptr_t short_global_shadow_end; - uintptr_t short_global_shadow_start; - uintptr_t short_global_shadow_offset; - - uintptr_t long_global_shadow_end; - uintptr_t long_global_shadow_start; - uintptr_t long_global_shadow_offset; - - /* Same as `global_...` but for shadowing thread-local storage */ - uintptr_t tls_end; - uintptr_t tls_start; - size_t tls_shadow_size; - - uintptr_t short_tls_shadow_end; - uintptr_t short_tls_shadow_start; - uintptr_t short_tls_shadow_offset; - - uintptr_t long_tls_shadow_end; - uintptr_t long_tls_shadow_start; - uintptr_t long_tls_shadow_offset; - - /*! Carries a non-zero value if shadow layout has been initialized and - * evaluates to zero otherwise. */ +struct memory_segment { + uintptr_t start; //!< Least address + uintptr_t end; //!< Greatest address + + size_t shadow_size; //!< Byte-size of shadow + + uintptr_t prim_start; //!< Least address in primary shadow + uintptr_t prim_end; //!< Greatest address in primary shadow + uintptr_t prim_offset; //!< Primary shadow offset + + uintptr_t sec_start; //!< Least address in secondary shadow + uintptr_t sec_end; //!< Greatest address in secondary shadow + uintptr_t sec_offset; //!< Secondary shadow offset + int initialized; }; -/*! \brief Setting program layout for analysys, namely: - * - Detect boundaries of different program segments - * - Allocate shadow regions (1 heap region + 2 stack regions) - * - Compute shadow offsets - * - * *TODO*: This function should be a part of ::__e_acsl_memory_init visible - * externally */ -static void init_pgm_layout(int *argc_ref, char ***argv_ref) { - DLOG("<<< Initialize shadow layout >>>\n"); - /* Setting up stack. Stack grows downwards starting from the stack end - * address initialization. */ - pgm_layout.stack_shadow_size = STACK_SHADOW_SIZE; - pgm_layout.stack_end = get_stack_end(argc_ref, argv_ref); - pgm_layout.stack_start = - pgm_layout.stack_end - pgm_layout.stack_shadow_size; - /* Soft bound can be increased programmatically, thus detecting - * stack overflows using this stack bound needs to take into account such - * changes. Very approximate for the moment, */ - pgm_layout.stack_soft_bound = pgm_layout.stack_end - get_stack_size(); - - /* Primary stack shadow region */ - void * short_stack_shadow = do_mmap(pgm_layout.stack_shadow_size); - pgm_layout.short_stack_shadow_start = (uintptr_t)short_stack_shadow; - pgm_layout.short_stack_shadow_end = - (uintptr_t)short_stack_shadow + pgm_layout.stack_shadow_size; - pgm_layout.short_stack_shadow_offset = - shadow_offset(short_stack_shadow, pgm_layout.stack_start); - - /* Secondary stack shadow region */ - void *long_stack_shadow = do_mmap(pgm_layout.stack_shadow_size); - pgm_layout.long_stack_shadow_start = (uintptr_t)long_stack_shadow; - pgm_layout.long_stack_shadow_end = - (uintptr_t)long_stack_shadow + pgm_layout.stack_shadow_size; - pgm_layout.long_stack_shadow_offset = - shadow_offset(long_stack_shadow, pgm_layout.stack_start); - - /* Setting heap. Heap grows upwards starting from the current program break. - Alternative approach would be to use the end of BSS but in fact the end of - BSS and the current program break are not really close to each other, so - some space will be wasted. Another reason is that sbrk is likely to return - an aligned address which makes the access faster. */ - pgm_layout.heap_start = (uintptr_t)sbrk(0); - pgm_layout.heap_shadow_size = HEAP_SHADOW_SIZE; - pgm_layout.heap_end = pgm_layout.heap_start + pgm_layout.heap_shadow_size; - - void* heap_shadow = do_mmap(pgm_layout.heap_shadow_size); - pgm_layout.heap_shadow_start = (uintptr_t)heap_shadow; - pgm_layout.heap_shadow_end = - (uintptr_t)heap_shadow + pgm_layout.heap_shadow_size; - pgm_layout.heap_shadow_offset = - shadow_offset(heap_shadow, pgm_layout.heap_start); - - /* Setting shadow for globals */ - /* In all likelihood it is reasonably safe to assume that first - * 2x*pointer-size bytes of the memory space will not be used. */ - pgm_layout.global_start = PTR_SZ*2; - pgm_layout.global_end = (uintptr_t)&end; - pgm_layout.global_shadow_size - = pgm_layout.global_end - pgm_layout.global_start; - - /* Primary global shadow region */ - void * short_global_shadow = do_mmap(pgm_layout.global_shadow_size); - pgm_layout.short_global_shadow_start = (uintptr_t)short_global_shadow; - pgm_layout.short_global_shadow_end = - (uintptr_t)short_global_shadow + pgm_layout.global_shadow_size; - pgm_layout.short_global_shadow_offset = - shadow_offset(short_global_shadow, pgm_layout.global_start); - - /* Secondary global shadow */ - void *long_global_shadow = do_mmap(pgm_layout.global_shadow_size); - pgm_layout.long_global_shadow_start = (uintptr_t)long_global_shadow; - pgm_layout.long_global_shadow_end = - (uintptr_t)long_global_shadow + pgm_layout.global_shadow_size; - pgm_layout.long_global_shadow_offset = - shadow_offset(long_global_shadow, pgm_layout.global_start); - - /* Setting shadow for thread-local storage (TLS). */ - set_tls_bounds(&pgm_layout.tls_end, &pgm_layout.tls_start, - &pgm_layout.tls_shadow_size); - - /* Primary TLS shadow */ - void * short_tls_shadow = do_mmap(pgm_layout.tls_shadow_size); - pgm_layout.short_tls_shadow_start = (uintptr_t)short_tls_shadow; - pgm_layout.short_tls_shadow_end = - (uintptr_t)short_tls_shadow + pgm_layout.tls_shadow_size; - pgm_layout.short_tls_shadow_offset = - shadow_offset(short_tls_shadow, pgm_layout.tls_start); - - /* Secondary TLS shadow */ - void *long_tls_shadow = do_mmap(pgm_layout.tls_shadow_size); - pgm_layout.long_tls_shadow_start = (uintptr_t)long_tls_shadow; - pgm_layout.long_tls_shadow_end = - (uintptr_t)long_tls_shadow + pgm_layout.tls_shadow_size; - pgm_layout.long_tls_shadow_offset = - shadow_offset(long_tls_shadow, pgm_layout.tls_start); - - /* The shadow layout has been initialized */ - pgm_layout.initialized = 1; +static struct memory_layout mem_layout; + +struct memory_layout { + struct memory_segment heap; + struct memory_segment stack; + struct memory_segment global; + struct memory_segment tls; + int initialized; +}; + +static void set_shadow_segment(struct memory_segment *seg, uintptr_t start, uintptr_t size, int secondary) { + seg->start = start; + seg->end = seg->start + size; + seg->shadow_size = size; + + void *prim_shadow = do_mmap(seg->shadow_size); + seg->prim_start = (uintptr_t)prim_shadow; + seg->prim_end = seg->prim_start + seg->shadow_size; + seg->prim_offset = shadow_offset(prim_shadow, start); + + if (secondary) { + void *sec_shadow = do_mmap(seg->shadow_size); + seg->sec_start = (uintptr_t)sec_shadow; + seg->sec_end = seg->sec_start + seg->shadow_size; + seg->sec_offset = shadow_offset(sec_shadow, seg->start); + } else { + seg->sec_start = seg->sec_end = seg->sec_offset = 0; + } } -/*! \brief Unmap (de-allocate) shadow regions used by runtime analysis */ -static void clean_pgm_layout() { +static void init_memory_layout(int *argc_ref, char ***argv_ref) { + DLOG("<<< Initialize heap shadow >>>\n"); + struct memory_segment *heap = &mem_layout.heap; + set_shadow_segment(heap, get_heap_start(), get_heap_size(), 0); + + DLOG("<<< Initialize stack shadow >>>\n"); + struct memory_segment *stack = &mem_layout.stack; + set_shadow_segment(stack, get_stack_start(argc_ref, argv_ref), get_stack_size(), 1); + + DLOG("<<< Initialize global shadow >>>\n"); + struct memory_segment *global = &mem_layout.global; + set_shadow_segment(global, get_global_start(), get_global_size(), 1); + + DLOG("<<< Initialize TLS shadow >>>\n"); + struct memory_segment *tls = &mem_layout.tls; + set_shadow_segment(tls, get_tls_start(), get_tls_size(), 1); + + mem_layout.initialized = 1; +} + +/*! \brief Deallocate a shadow segment */ +void clean_memory_segment(struct memory_segment *seg, int secondary) { + munmap((void*)seg->prim_start, seg->shadow_size); + if (secondary) + munmap((void*)seg->sec_start, seg->shadow_size); +} + +/*! \brief Deallocate shadow regions used by runtime analysis */ +static void clean_memory_layout() { DLOG("<<< Clean shadow layout >>>\n"); - /* Unmap global shadows */ - if (pgm_layout.long_global_shadow_start) - munmap((void*)pgm_layout.long_global_shadow_start, - pgm_layout.global_shadow_size); - if (pgm_layout.short_global_shadow_start) - munmap((void*)pgm_layout.short_global_shadow_start, - pgm_layout.global_shadow_size); - /* Unmap stack shadows */ - if (pgm_layout.long_stack_shadow_start) - munmap((void*)pgm_layout.long_stack_shadow_start, - pgm_layout.stack_shadow_size); - if (pgm_layout.short_stack_shadow_start) - munmap((void*)pgm_layout.short_stack_shadow_start, - pgm_layout.stack_shadow_size); - /* Unmap heap shadow */ - if (pgm_layout.heap_shadow_start) - munmap((void*)pgm_layout.heap_shadow_start, pgm_layout.heap_shadow_size); + if (mem_layout.initialized) { + clean_memory_segment(&mem_layout.heap, 0); + clean_memory_segment(&mem_layout.stack, 1); + clean_memory_segment(&mem_layout.global, 1); + clean_memory_segment(&mem_layout.tls, 1); + } } /* }}} */ @@ -437,60 +352,66 @@ static void clean_pgm_layout() { * are given using the following macros. */ -/*! \brief Convert a stack address into its short (byte) shadow counterpart */ -#define SHORT_STACK_SHADOW(_addr) \ - ((uintptr_t)((uintptr_t)_addr - pgm_layout.short_stack_shadow_offset)) -/*! \brief Convert a stack address into its long (block) shadow counterpart */ -#define LONG_STACK_SHADOW(_addr) \ - ((uintptr_t)((uintptr_t)_addr - pgm_layout.long_stack_shadow_offset)) +/*! \brief Convert a stack address into its primary shadow counterpart */ +#define PRIMARY_STACK_SHADOW(_addr) \ + ((uintptr_t)((uintptr_t)_addr - mem_layout.stack.prim_offset)) +/*! \brief Convert a stack address into its secondary shadow counterpart */ +#define SECONDARY_STACK_SHADOW(_addr) \ + ((uintptr_t)((uintptr_t)_addr - mem_layout.stack.sec_offset)) -/*! \brief Convert a global address into its short (byte) shadow counterpart */ -#define SHORT_GLOBAL_SHADOW(_addr) \ - ((uintptr_t)((uintptr_t)_addr + pgm_layout.short_global_shadow_offset)) -/*! \brief Convert a global address into its long (block) shadow counterpart */ -#define LONG_GLOBAL_SHADOW(_addr) \ - ((uintptr_t)((uintptr_t)_addr + pgm_layout.long_global_shadow_offset)) +/*! \brief Convert a global address into its primary shadow counterpart */ +#define PRIMARY_GLOBAL_SHADOW(_addr) \ + ((uintptr_t)((uintptr_t)_addr + mem_layout.global.prim_offset)) +/*! \brief Convert a global address into its secondary shadow counterpart */ +#define SECONDARY_GLOBAL_SHADOW(_addr) \ + ((uintptr_t)((uintptr_t)_addr + mem_layout.global.sec_offset)) /*! \brief Select stack or global shadow based on the value of `_global` * - * - SHORT_SHADOW(_addr, 0) is equivalent to STACK_SHORT_SHADOW(_addr) - * - SHORT_SHADOW(_addr, 1) is equivalent to GLOBAL_SHORT_SHADOW(_addr) */ -#define SHORT_SHADOW(_addr, _global) \ - (_global ? SHORT_GLOBAL_SHADOW(_addr) : SHORT_STACK_SHADOW(_addr)) + * - PRIMARY_SHADOW(_addr, 0) is equivalent to PRIMARY_STACK_SHADOW(_addr) + * - PRIMARY_SHADOW(_addr, 1) is equivalent to PRIMARY_GLOBAL_SHADOW(_addr) */ +#define PRIMARY_SHADOW(_addr, _global) \ + (_global ? PRIMARY_GLOBAL_SHADOW(_addr) : PRIMARY_STACK_SHADOW(_addr)) -/*! \brief Same as above but for long stack/global shadows */ -#define LONG_SHADOW(_addr, _global) \ - (_global ? LONG_GLOBAL_SHADOW(_addr) : LONG_STACK_SHADOW(_addr)) +/*! \brief Same as above but for secondary stack/global shadows */ +#define SECONDARY_SHADOW(_addr, _global) \ + (_global ? SECONDARY_GLOBAL_SHADOW(_addr) : SECONDARY_STACK_SHADOW(_addr)) /*! \brief Convert a heap address into its shadow counterpart */ #define HEAP_SHADOW(_addr) \ - ((uintptr_t)((uintptr_t)_addr + pgm_layout.heap_shadow_offset)) + ((uintptr_t)((uintptr_t)_addr + mem_layout.heap.prim_offset)) /*! \brief Evaluate to a true value if a given address is a heap address */ #define IS_ON_HEAP(_addr) ( \ - ((uintptr_t)_addr) >= pgm_layout.heap_start && \ - ((uintptr_t)_addr) <= pgm_layout.heap_end \ + ((uintptr_t)_addr) >= mem_layout.heap.start && \ + ((uintptr_t)_addr) <= mem_layout.heap.end \ ) /*! \brief Evaluate to a true value if a given address is a stack address */ #define IS_ON_STACK(_addr) ( \ - ((uintptr_t)_addr) >= pgm_layout.stack_start && \ - ((uintptr_t)_addr) <= pgm_layout.stack_end \ + ((uintptr_t)_addr) >= mem_layout.stack.start && \ + ((uintptr_t)_addr) <= mem_layout.stack.end \ ) /*! \brief Evaluate to a true value if a given address is a global address */ #define IS_ON_GLOBAL(_addr) ( \ - ((uintptr_t)_addr) >= pgm_layout.global_start && \ - ((uintptr_t)_addr) <= pgm_layout.global_end \ + ((uintptr_t)_addr) >= mem_layout.global.start && \ + ((uintptr_t)_addr) <= mem_layout.global.end \ +) + +/*! \brief Evaluate to a true value if a given address is a TLS address */ +#define IS_ON_TLS(_addr) ( \ + ((uintptr_t)_addr) >= mem_layout.tls.start && \ + ((uintptr_t)_addr) <= mem_layout.tls.end \ ) /*! \brief Shortcut for evaluating an address via ::IS_ON_STACK or - * ::IS_ON_GLOBAL based on the valua of the second parameter */ + * ::IS_ON_GLOBAL based on the value of the second parameter */ #define IS_ON_STATIC(_addr, _global) \ (_global ? IS_ON_GLOBAL(_addr) : IS_ON_STACK(_addr)) /*! \brief Evaluate to a true value if a given address belongs to tracked - * allocation (i.e., found within stack, heap oor globally) */ + * allocation (i.e., found within stack, heap or globally) */ #define IS_ON_VALID(_addr) \ (IS_ON_STACK(_addr) || IS_ON_HEAP(_addr) || IS_ON_GLOBAL(_addr)) /* }}} */