From 10a0c017e8c45fa585e65ce4a97fd688bd9152ba Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 15 Aug 2017 17:52:46 +0100 Subject: [PATCH 01/65] Pointers returned by getenv must not be manipulated In partiular, pointers need not and must not be free'd -- but still shouldn't be considered memory leaks. --- src/ansi-c/library/stdlib.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ansi-c/library/stdlib.c b/src/ansi-c/library/stdlib.c index 3b85223320e..8126b3b0b6a 100644 --- a/src/ansi-c/library/stdlib.c +++ b/src/ansi-c/library/stdlib.c @@ -301,6 +301,8 @@ inline long atol(const char *nptr) #define __CPROVER_LIMITS_H_INCLUDED #endif +inline void *__builtin_alloca(__CPROVER_size_t alloca_size); + inline char *getenv(const char *name) { __CPROVER_HIDE:; @@ -330,7 +332,7 @@ inline char *getenv(const char *name) // the range. __CPROVER_assume(1<=buf_size && buf_size<=SSIZE_MAX); - buffer=(char *)__CPROVER_malloc(buf_size); + buffer=(char *)__builtin_alloca(buf_size); buffer[buf_size-1]=0; return buffer; From 6d6834516fe487df82dfd60a00cb300bcc7635e1 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 15 Aug 2017 19:19:22 +0100 Subject: [PATCH 02/65] ansi-c library: explicit non-det initialisation, cleanup, syntax fixes --- src/ansi-c/library/fcntl.c | 4 +- src/ansi-c/library/getopt.c | 27 +++-- src/ansi-c/library/inet.c | 12 +- src/ansi-c/library/math.c | 84 +++++++------ src/ansi-c/library/netdb.c | 12 +- src/ansi-c/library/new.c | 20 +++- src/ansi-c/library/process.c | 8 +- src/ansi-c/library/pthread_lib.c | 26 +++-- src/ansi-c/library/setjmp.c | 4 +- src/ansi-c/library/signal.c | 4 +- src/ansi-c/library/stdio.c | 195 ++++++++++++++++++++++++++----- src/ansi-c/library/stdlib.c | 28 +++-- src/ansi-c/library/string.c | 22 +++- src/ansi-c/library/time.c | 12 +- src/ansi-c/library/unistd.c | 25 +++- 15 files changed, 353 insertions(+), 130 deletions(-) diff --git a/src/ansi-c/library/fcntl.c b/src/ansi-c/library/fcntl.c index 30f8c5e39fc..7001724c9bf 100644 --- a/src/ansi-c/library/fcntl.c +++ b/src/ansi-c/library/fcntl.c @@ -5,10 +5,12 @@ #define __CPROVER_FCNTL_H_INCLUDED #endif +int __VERIFIER_nondet_int(); + int fcntl(int fd, int cmd, ...) { __CPROVER_HIDE:; - int return_value; + int return_value=__VERIFIER_nondet_int(); (void)fd; (void)cmd; return return_value; diff --git a/src/ansi-c/library/getopt.c b/src/ansi-c/library/getopt.c index 458f9d2e414..0045cbd105d 100644 --- a/src/ansi-c/library/getopt.c +++ b/src/ansi-c/library/getopt.c @@ -8,8 +8,11 @@ extern int optind; #define __CPROVER_STRING_H_INCLUDED #endif -inline int getopt(int argc, char * const argv[], - const char *optstring) +__CPROVER_bool __VERIFIER_nondet___CPROVER_bool(); +size_t __VERIFIER_nondet_size_t(); + +inline int getopt( + int argc, char * const argv[], const char *optstring) { __CPROVER_HIDE:; int result=-1; @@ -20,7 +23,7 @@ inline int getopt(int argc, char * const argv[], if(optind>=argc || argv[optind][0]!='-') return -1; - size_t result_index; + size_t result_index=__VERIFIER_nondet_size_t(); __CPROVER_assume( result_index +#define __CPROVER_GETOPT_H_INCLUDED +#endif -inline int getopt_long(int argc, char * const argv[], const char *optstring, - const struct option *longopts, int *longindex) +inline int getopt_long( + int argc, + char * const argv[], + const char *optstring, + const struct option *longopts, + int *longindex) { // trigger valid-pointer checks (if enabled), even though we don't // use the parameter in this model diff --git a/src/ansi-c/library/inet.c b/src/ansi-c/library/inet.c index 0d24a393620..88a508cc47f 100644 --- a/src/ansi-c/library/inet.c +++ b/src/ansi-c/library/inet.c @@ -2,6 +2,8 @@ #include +in_addr_t __VERIFIER_nondet_in_addr_t(); + in_addr_t inet_addr(const char *cp) { __CPROVER_HIDE:; @@ -10,12 +12,14 @@ in_addr_t inet_addr(const char *cp) __CPROVER_assert(__CPROVER_is_zero_string(cp), "inet_addr zero-termination of argument"); #endif - in_addr_t result; + in_addr_t result=__VERIFIER_nondet_in_addr_t(); return result; } /* FUNCTION: inet_aton */ +int __VERIFIER_nondet_int(); + int inet_aton(const char *cp, struct in_addr *pin) { __CPROVER_HIDE:; @@ -25,12 +29,14 @@ int inet_aton(const char *cp, struct in_addr *pin) __CPROVER_assert(__CPROVER_is_zero_string(cp), "inet_aton zero-termination of name argument"); #endif - int result; + int result=__VERIFIER_nondet_int(); return result; } /* FUNCTION: inet_network */ +in_addr_t __VERIFIER_nondet_in_addr_t(); + in_addr_t inet_network(const char *cp) { __CPROVER_HIDE:; @@ -39,6 +45,6 @@ in_addr_t inet_network(const char *cp) __CPROVER_assert(__CPROVER_is_zero_string(cp), "inet_network zero-termination of name argument"); #endif - in_addr_t result; + in_addr_t result=__VERIFIER_nondet_in_addr_t(); return result; } diff --git a/src/ansi-c/library/math.c b/src/ansi-c/library/math.c index 1af12148d83..c9f52dc8f76 100644 --- a/src/ansi-c/library/math.c +++ b/src/ansi-c/library/math.c @@ -64,22 +64,17 @@ int __CPROVER_islessgreaterd(double f, double g) { return (f < g) || (f > g); } /* FUNCTION: __CPROVER_isunorderedf */ -#ifndef __CPROVER_MATH_H_INCLUDED -#include -#define __CPROVER_MATH_H_INCLUDED -#endif - -int __CPROVER_isunorderedf(float f, float g) { return isnanf(f) || isnanf(g); } +int __CPROVER_isunorderedf(float f, float g) +{ + return __CPROVER_isnanf(f) || __CPROVER_isnanf(g); +} /* FUNCTION: __CPROVER_isunorderedd */ -#ifndef __CPROVER_MATH_H_INCLUDED -#include -#define __CPROVER_MATH_H_INCLUDED -#endif - -int __CPROVER_isunorderedd(double f, double g) { return isnan(f) || isnan(g); } - +int __CPROVER_isunorderedd(double f, double g) +{ + return __CPROVER_isnand(f) || __CPROVER_isnand(g); +} /* FUNCTION: isfinite */ @@ -363,10 +358,12 @@ inline int __fpclassify(double d) { /* FUNCTION: sin */ +double __VERIFIER_nondet_double(); + double sin(double x) { // gross over-approximation - double ret; + double ret=__VERIFIER_nondet_double(); if(__CPROVER_isinfd(x) || __CPROVER_isnand(x)) __CPROVER_assume(__CPROVER_isnand(ret)); @@ -382,10 +379,12 @@ double sin(double x) /* FUNCTION: sinl */ +long double __VERIFIER_nondet_long_double(); + long double sinl(long double x) { // gross over-approximation - long double ret; + long double ret=__VERIFIER_nondet_long_double(); if(__CPROVER_isinfld(x) || __CPROVER_isnanld(x)) __CPROVER_assume(__CPROVER_isnanld(ret)); @@ -401,10 +400,12 @@ long double sinl(long double x) /* FUNCTION: sinf */ +float __VERIFIER_nondet_float(); + float sinf(float x) { // gross over-approximation - float ret; + float ret=__VERIFIER_nondet_float(); if(__CPROVER_isinff(x) || __CPROVER_isnanf(x)) __CPROVER_assume(__CPROVER_isnanf(ret)); @@ -420,10 +421,12 @@ float sinf(float x) /* FUNCTION: cos */ +double __VERIFIER_nondet_double(); + double cos(double x) { // gross over-approximation - double ret; + double ret=__VERIFIER_nondet_double(); if(__CPROVER_isinfd(x) || __CPROVER_isnand(x)) __CPROVER_assume(__CPROVER_isnand(ret)); @@ -439,10 +442,12 @@ double cos(double x) /* FUNCTION: cosl */ +long double __VERIFIER_nondet_long_double(); + long double cosl(long double x) { // gross over-approximation - long double ret; + long double ret=__VERIFIER_nondet_long_double(); if(__CPROVER_isinfld(x) || __CPROVER_isnanld(x)) __CPROVER_assume(__CPROVER_isnanld(ret)); @@ -458,11 +463,13 @@ long double cosl(long double x) /* FUNCTION: cosf */ +float __VERIFIER_nondet_float(); + float cosf(float x) { __CPROVER_hide:; // gross over-approximation - float ret; + float ret=__VERIFIER_nondet_float(); if(__CPROVER_isinff(x) || __CPROVER_isnanf(x)) __CPROVER_assume(__CPROVER_isnanf(ret)); @@ -512,11 +519,6 @@ __CPROVER_hide:; /* FUNCTION: nan */ -#ifndef __CPROVER_MATH_H_INCLUDED -#include -#define __CPROVER_MATH_H_INCLUDED -#endif - double nan(const char *str) { // the 'str' argument is not yet used __CPROVER_hide:; @@ -526,11 +528,6 @@ double nan(const char *str) { /* FUNCTION: nanf */ -#ifndef __CPROVER_MATH_H_INCLUDED -#include -#define __CPROVER_MATH_H_INCLUDED -#endif - float nanf(const char *str) { // the 'str' argument is not yet used __CPROVER_hide:; @@ -540,11 +537,6 @@ float nanf(const char *str) { /* FUNCTION: nanl */ -#ifndef __CPROVER_MATH_H_INCLUDED -#include -#define __CPROVER_MATH_H_INCLUDED -#endif - long double nanl(const char *str) { // the 'str' argument is not yet used __CPROVER_hide:; @@ -552,10 +544,6 @@ long double nanl(const char *str) { return 0.0/0.0; } - - - - /* FUNCTION: nextUpf */ #ifndef __CPROVER_LIMITS_H_INCLUDED @@ -738,6 +726,8 @@ __CPROVER_hide:; float nextUpf(float f); +float __VERIFIER_nondet_float(); + float sqrtf(float f) { __CPROVER_hide:; @@ -750,7 +740,7 @@ float sqrtf(float f) return f; else if (__CPROVER_isnormalf(f)) { - float lower; // Intentionally non-deterministic + float lower=__VERIFIER_nondet_float(); __CPROVER_assume(lower > 0.0f); __CPROVER_assume(__CPROVER_isnormalf(lower)); // Tighter bounds can be given but are dependent on the @@ -795,7 +785,7 @@ float sqrtf(float f) // With respect to the algebra of floating point number // all subnormals seem to be perfect squares, thus ... - float root; // Intentionally non-deterministic + float root=__VERIFIER_nondet_float(); __CPROVER_assume(root >= 0.0f); __CPROVER_assume(root * root == f); @@ -823,6 +813,8 @@ float sqrtf(float f) double nextUp(double d); +double __VERIFIER_nondet_double(); + double sqrt(double d) { __CPROVER_hide:; @@ -835,7 +827,7 @@ double sqrt(double d) return d; else if (__CPROVER_isnormald(d)) { - double lower; // Intentionally non-deterministic + double lower=__VERIFIER_nondet_double(); __CPROVER_assume(lower > 0.0); __CPROVER_assume(__CPROVER_isnormald(lower)); @@ -867,7 +859,7 @@ double sqrt(double d) //assert(fpclassify(d) == FP_SUBNORMAL); //assert(d > 0.0); - double root; // Intentionally non-deterministic + double root=__VERIFIER_nondet_double(); __CPROVER_assume(root >= 0.0); __CPROVER_assume(root * root == d); @@ -892,6 +884,8 @@ double sqrt(double d) long double nextUpl(long double d); +long double __VERIFIER_nondet_long_double(); + long double sqrtl(long double d) { __CPROVER_hide:; @@ -904,7 +898,7 @@ long double sqrtl(long double d) return d; else if (__CPROVER_isnormalld(d)) { - long double lower; // Intentionally non-deterministic + long double lower=__VERIFIER_nondet_long_double(); __CPROVER_assume(lower > 0.0l); __CPROVER_assume(__CPROVER_isnormalld(lower)); @@ -936,7 +930,7 @@ long double sqrtl(long double d) //assert(fpclassify(d) == FP_SUBNORMAL); //assert(d > 0.0l); - long double root; // Intentionally non-deterministic + long double root=__VERIFIER_nondet_long_double(); __CPROVER_assume(root >= 0.0l); __CPROVER_assume(root * root == d); @@ -2316,7 +2310,7 @@ long double fabsl (long double d); long double copysignl(long double x, long double y) { - long double abs = fabs(x); + long double abs = fabsl(x); return (signbit(y)) ? -abs : abs; } diff --git a/src/ansi-c/library/netdb.c b/src/ansi-c/library/netdb.c index 40cb4e4eecc..d1f78941724 100644 --- a/src/ansi-c/library/netdb.c +++ b/src/ansi-c/library/netdb.c @@ -2,6 +2,8 @@ #include +__CPROVER_bool __VERIFIER_nondet___CPROVER_bool(); + struct hostent *gethostbyname(const char *name) { __CPROVER_HIDE:; @@ -10,7 +12,7 @@ struct hostent *gethostbyname(const char *name) __CPROVER_assert(__CPROVER_is_zero_string(name), "gethostbyname zero-termination of name argument"); #endif - __CPROVER_bool error; + __CPROVER_bool error=__VERIFIER_nondet___CPROVER_bool(); if(error) return 0; // quite restrictive, as will alias between calls @@ -22,6 +24,8 @@ struct hostent *gethostbyname(const char *name) /* FUNCTION: gethostbyaddr */ +__CPROVER_bool __VERIFIER_nondet___CPROVER_bool(); + struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type) { __CPROVER_HIDE:; @@ -29,7 +33,7 @@ struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type) (void)len; (void)type; - __CPROVER_bool error; + __CPROVER_bool error=__VERIFIER_nondet___CPROVER_bool(); if(error) return 0; // quite restrictive, as will alias between calls @@ -41,11 +45,13 @@ struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type) /* FUNCTION: gethostent */ +__CPROVER_bool __VERIFIER_nondet___CPROVER_bool(); + struct hostent *gethostent(void) { __CPROVER_HIDE:; - __CPROVER_bool error; + __CPROVER_bool error=__VERIFIER_nondet___CPROVER_bool(); if(error) return 0; // quite restrictive, as will alias between calls diff --git a/src/ansi-c/library/new.c b/src/ansi-c/library/new.c index beb4e70e1bf..0cd78bd72ac 100644 --- a/src/ansi-c/library/new.c +++ b/src/ansi-c/library/new.c @@ -1,5 +1,7 @@ /* FUNCTION: __new */ +__CPROVER_bool __VERIFIER_nondet___CPROVER_bool(); + inline void *__new(__typeof__(sizeof(int)) malloc_size) { // The constructor call is done by the front-end. @@ -12,13 +14,13 @@ inline void *__new(__typeof__(sizeof(int)) malloc_size) __CPROVER_deallocated=(res==__CPROVER_deallocated)?0:__CPROVER_deallocated; // non-derministically record the object size for bounds checking - __CPROVER_bool record_malloc; + __CPROVER_bool record_malloc=__VERIFIER_nondet___CPROVER_bool(); __CPROVER_malloc_object=record_malloc?res:__CPROVER_malloc_object; __CPROVER_malloc_size=record_malloc?malloc_size:__CPROVER_malloc_size; __CPROVER_malloc_is_new_array=record_malloc?0:__CPROVER_malloc_is_new_array; // detect memory leaks - __CPROVER_bool record_may_leak; + __CPROVER_bool record_may_leak=__VERIFIER_nondet___CPROVER_bool(); __CPROVER_memory_leak=record_may_leak?res:__CPROVER_memory_leak; return res; @@ -26,6 +28,8 @@ inline void *__new(__typeof__(sizeof(int)) malloc_size) /* FUNCTION: __new_array */ +__CPROVER_bool __VERIFIER_nondet___CPROVER_bool(); + inline void *__new_array(__CPROVER_size_t count, __CPROVER_size_t size) { // The constructor call is done by the front-end. @@ -38,13 +42,13 @@ inline void *__new_array(__CPROVER_size_t count, __CPROVER_size_t size) __CPROVER_deallocated=(res==__CPROVER_deallocated)?0:__CPROVER_deallocated; // non-deterministically record the object size for bounds checking - __CPROVER_bool record_malloc; + __CPROVER_bool record_malloc=__VERIFIER_nondet___CPROVER_bool(); __CPROVER_malloc_object=record_malloc?res:__CPROVER_malloc_object; __CPROVER_malloc_size=record_malloc?size*count:__CPROVER_malloc_size; __CPROVER_malloc_is_new_array=record_malloc?1:__CPROVER_malloc_is_new_array; // detect memory leaks - __CPROVER_bool record_may_leak; + __CPROVER_bool record_may_leak=__VERIFIER_nondet___CPROVER_bool(); __CPROVER_memory_leak=record_may_leak?res:__CPROVER_memory_leak; return res; @@ -63,6 +67,8 @@ inline void *__placement_new(__typeof__(sizeof(int)) malloc_size, void *p) /* FUNCTION: __delete */ +__CPROVER_bool __VERIFIER_nondet___CPROVER_bool(); + inline void __delete(void *ptr) { __CPROVER_HIDE:; @@ -85,13 +91,15 @@ inline void __delete(void *ptr) "delete of array object"); // non-deterministically record as deallocated - __CPROVER_bool record; + __CPROVER_bool record=__VERIFIER_nondet___CPROVER_bool(); __CPROVER_deallocated=record?ptr:__CPROVER_deallocated; } } /* FUNCTION: __delete_array */ +__CPROVER_bool __VERIFIER_nondet___CPROVER_bool(); + inline void __delete_array(void *ptr) { __CPROVER_HIDE:; @@ -114,7 +122,7 @@ inline void __delete_array(void *ptr) "delete[] of non-array object"); // non-deterministically record as deallocated - __CPROVER_bool record; + __CPROVER_bool record=__VERIFIER_nondet___CPROVER_bool(); __CPROVER_deallocated=record?ptr:__CPROVER_deallocated; } } diff --git a/src/ansi-c/library/process.c b/src/ansi-c/library/process.c index c7de7fa5746..f1a89b9f7f4 100644 --- a/src/ansi-c/library/process.c +++ b/src/ansi-c/library/process.c @@ -1,5 +1,7 @@ /* FUNCTION: _beginthread */ +__CPROVER_size_t __VERIFIER_nondet___CPROVER_size_t(); + __CPROVER_size_t _beginthread( void (*start_address)(void *), unsigned stack_size, @@ -8,12 +10,14 @@ __CPROVER_size_t _beginthread( __CPROVER_HIDE:; __CPROVER_ASYNC_1: start_address(arglist); (void)stack_size; - __CPROVER_size_t handle; + __CPROVER_size_t handle=__VERIFIER_nondet___CPROVER_size_t(); return handle; } /* FUNCTION: _beginthreadex */ +__CPROVER_size_t __VERIFIER_nondet___CPROVER_size_t(); + __CPROVER_size_t _beginthreadex( void *security, unsigned stack_size, @@ -29,6 +33,6 @@ __CPROVER_size_t _beginthreadex( (void)stack_size; (void)initflag; (void)*thrdaddr; - __CPROVER_size_t handle; + __CPROVER_size_t handle=__VERIFIER_nondet___CPROVER_size_t(); return handle; } diff --git a/src/ansi-c/library/pthread_lib.c b/src/ansi-c/library/pthread_lib.c index ac3e6a18c3e..71af169c91b 100644 --- a/src/ansi-c/library/pthread_lib.c +++ b/src/ansi-c/library/pthread_lib.c @@ -5,6 +5,8 @@ #define __CPROVER_PTHREAD_H_INCLUDED #endif +int __VERIFIER_nondet_int(); + inline int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) { __CPROVER_HIDE:; @@ -17,7 +19,7 @@ inline int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) (void)type; #endif - int result; + int result=__VERIFIER_nondet_int(); return result; } @@ -28,6 +30,8 @@ inline int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) #define __CPROVER_PTHREAD_H_INCLUDED #endif +int __VERIFIER_nondet_int(); + inline int pthread_cancel(pthread_t thread) { __CPROVER_HIDE:; @@ -38,7 +42,7 @@ inline int pthread_cancel(pthread_t thread) "pthread_cancel must be given valid thread ID"); #endif - int result; + int result=__VERIFIER_nondet_int(); return result; } @@ -532,12 +536,8 @@ inline int pthread_create( if(thread) { - #ifdef __APPLE__ - // pthread_t is a pointer type on the Mac + // pthread_t is a pointer type on some systems *thread=(pthread_t)this_thread_id; - #else - *thread=this_thread_id; - #endif } #ifdef __CPROVER_CUSTOM_BITVECTOR_ANALYSIS @@ -729,6 +729,8 @@ int pthread_spin_trylock(pthread_spinlock_t *lock) #define __CPROVER_PTHREAD_H_INCLUDED #endif +int __VERIFIER_nondet_int(); + // no pthread_barrier_t on the Mac #ifndef __APPLE__ inline int pthread_barrier_init( @@ -745,7 +747,7 @@ inline int pthread_barrier_init( __CPROVER_clear_may(barrier, "barrier-destroyed"); #endif - int result; + int result=__VERIFIER_nondet_int(); return result; } #endif @@ -757,6 +759,8 @@ inline int pthread_barrier_init( #define __CPROVER_PTHREAD_H_INCLUDED #endif +int __VERIFIER_nondet_int(); + // no pthread_barrier_t on the Mac #ifndef __APPLE__ inline int pthread_barrier_destroy(pthread_barrier_t *barrier) @@ -773,7 +777,7 @@ inline int pthread_barrier_destroy(pthread_barrier_t *barrier) __CPROVER_set_may(barrier, "barrier-destroyed"); #endif - int result; + int result=__VERIFIER_nondet_int(); return result; } #endif @@ -785,6 +789,8 @@ inline int pthread_barrier_destroy(pthread_barrier_t *barrier) #define __CPROVER_PTHREAD_H_INCLUDED #endif +int __VERIFIER_nondet_int(); + // no pthread_barrier_t on the Mac #ifndef __APPLE__ inline int pthread_barrier_wait(pthread_barrier_t *barrier) @@ -800,7 +806,7 @@ inline int pthread_barrier_wait(pthread_barrier_t *barrier) "pthread barrier must not be destroyed"); #endif - int result; + int result=__VERIFIER_nondet_int(); return result; } #endif diff --git a/src/ansi-c/library/setjmp.c b/src/ansi-c/library/setjmp.c index 64e99e98f8b..57c14998bb3 100644 --- a/src/ansi-c/library/setjmp.c +++ b/src/ansi-c/library/setjmp.c @@ -51,10 +51,12 @@ inline void siglongjmp(sigjmp_buf env, int val) #define __CPROVER_SETJMP_H_INCLUDED #endif +int __VERIFIER_nondet_int(); + inline int setjmp(jmp_buf env) { // store PC - int retval; + int retval=__VERIFIER_nondet_int(); (void)env; return retval; } diff --git a/src/ansi-c/library/signal.c b/src/ansi-c/library/signal.c index c08ec34909a..45fb723a7a4 100644 --- a/src/ansi-c/library/signal.c +++ b/src/ansi-c/library/signal.c @@ -10,10 +10,12 @@ #define __CPROVER_SIGNAL_H_INCLUDED #endif +__CPROVER_bool __VERIFIER_nondet___CPROVER_bool(); + int kill(pid_t pid, int sig) { (void)pid; (void)sig; - __CPROVER_bool error; + __CPROVER_bool error=__VERIFIER_nondet___CPROVER_bool(); return error ? -1 : 0; } diff --git a/src/ansi-c/library/stdio.c b/src/ansi-c/library/stdio.c index 0472908d744..a9ce6e7ec15 100644 --- a/src/ansi-c/library/stdio.c +++ b/src/ansi-c/library/stdio.c @@ -6,10 +6,13 @@ #define __CPROVER_STDIO_H_INCLUDED #endif +__CPROVER_bool __VERIFIER_nondet___CPROVER_bool(); + inline int putchar(int c) { - __CPROVER_bool error; - __CPROVER_HIDE: printf("%c", c); + __CPROVER_HIDE:; + __CPROVER_bool error=__VERIFIER_nondet___CPROVER_bool(); + printf("%c", c); return (error?-1:c); } @@ -20,11 +23,14 @@ inline int putchar(int c) #define __CPROVER_STDIO_H_INCLUDED #endif +__CPROVER_bool __VERIFIER_nondet___CPROVER_bool(); +int __VERIFIER_nondet_int(); + inline int puts(const char *s) { __CPROVER_HIDE:; - __CPROVER_bool error; - int ret; + __CPROVER_bool error=__VERIFIER_nondet___CPROVER_bool(); + int ret=__VERIFIER_nondet_int(); printf("%s\n", s); if(error) ret=-1; else __CPROVER_assume(ret>=0); return ret; @@ -52,6 +58,8 @@ inline void fclose_cleanup(void *stream) } #endif +__CPROVER_bool __VERIFIER_nondet___CPROVER_bool(); + inline FILE *fopen(const char *filename, const char *mode) { __CPROVER_HIDE:; @@ -64,7 +72,7 @@ inline FILE *fopen(const char *filename, const char *mode) FILE *fopen_result; - _Bool fopen_error; + __CPROVER_bool fopen_error=__VERIFIER_nondet___CPROVER_bool(); #if !defined(__linux__) || defined(__GLIBC__) fopen_result=fopen_error?NULL:malloc(sizeof(FILE)); @@ -94,7 +102,11 @@ inline FILE* freopen(const char *filename, const char *mode, FILE *f) __CPROVER_HIDE:; (void)*filename; (void)*mode; + #if !defined(__linux__) || defined(__GLIBC__) (void)*f; + #else + (void)*(char*)f; + #endif return f; } @@ -111,6 +123,8 @@ inline FILE* freopen(const char *filename, const char *mode, FILE *f) #define __CPROVER_STDLIB_H_INCLUDED #endif +int __VERIFIER_nondet_int(); + inline int fclose(FILE *stream) { __CPROVER_HIDE:; @@ -120,7 +134,7 @@ inline int fclose(FILE *stream) __CPROVER_clear_must(stream, "open"); __CPROVER_set_must(stream, "closed"); #endif - int return_value; + int return_value=__VERIFIER_nondet_int(); free(stream); return return_value; } @@ -160,7 +174,10 @@ inline FILE *fdopen(int handle, const char *mode) /* FUNCTION: _fdopen */ -// This is for Apple +// This is for Apple; we cannot fall back to fdopen as we need +// header files to have a definition of FILE available; the same +// header files rename fdopen to _fdopen and would thus yield +// unbounded recursion. #ifndef __CPROVER_STDIO_H_INCLUDED #include @@ -196,13 +213,20 @@ inline FILE *_fdopen(int handle, const char *mode) #define __CPROVER_STDIO_H_INCLUDED #endif +__CPROVER_bool __VERIFIER_nondet___CPROVER_bool(); +int __VERIFIER_nondet_int(); + char *fgets(char *str, int size, FILE *stream) { __CPROVER_HIDE:; - __CPROVER_bool error; + __CPROVER_bool error=__VERIFIER_nondet___CPROVER_bool(); (void)size; + #if !defined(__linux__) || defined(__GLIBC__) (void)*stream; + #else + (void)*(char*)stream; + #endif #ifdef __CPROVER_CUSTOM_BITVECTOR_ANALYSIS __CPROVER_assert(__CPROVER_get_must(stream, "open"), @@ -221,7 +245,7 @@ char *fgets(char *str, int size, FILE *stream) #else if(size>0) { - int str_length; + int str_length=__VERIFIER_nondet_int(); __CPROVER_assume(str_length>=0 && str_length=-1 && return_value<=255); @@ -437,11 +509,18 @@ inline int fgetc(FILE *stream) #define __CPROVER_STDIO_H_INCLUDED #endif +int __VERIFIER_nondet_int(); + inline int getc(FILE *stream) { __CPROVER_HIDE:; - int return_value; + int return_value=__VERIFIER_nondet_int(); + + #if !defined(__linux__) || defined(__GLIBC__) (void)*stream; + #else + (void)*(char*)stream; + #endif #ifdef __CPROVER_CUSTOM_BITVECTOR_ANALYSIS __CPROVER_assert(__CPROVER_get_must(stream, "open"), @@ -463,10 +542,12 @@ inline int getc(FILE *stream) #define __CPROVER_STDIO_H_INCLUDED #endif +int __VERIFIER_nondet_int(); + inline int getchar() { __CPROVER_HIDE:; - int return_value; + int return_value=__VERIFIER_nondet_int(); // it's a byte or EOF __CPROVER_assume(return_value>=-1 && return_value<=255); __CPROVER_input("getchar", return_value); @@ -480,11 +561,18 @@ inline int getchar() #define __CPROVER_STDIO_H_INCLUDED #endif +int __VERIFIER_nondet_int(); + inline int getw(FILE *stream) { __CPROVER_HIDE:; - int return_value; + int return_value=__VERIFIER_nondet_int(); + + #if !defined(__linux__) || defined(__GLIBC__) (void)*stream; + #else + (void)*(char*)stream; + #endif #ifdef __CPROVER_CUSTOM_BITVECTOR_ANALYSIS __CPROVER_assert(__CPROVER_get_must(stream, "open"), @@ -504,11 +592,18 @@ inline int getw(FILE *stream) #define __CPROVER_STDIO_H_INCLUDED #endif +int __VERIFIER_nondet_int(); + inline int fseek(FILE *stream, long offset, int whence) { __CPROVER_HIDE:; - int return_value; + int return_value=__VERIFIER_nondet_int(); + + #if !defined(__linux__) || defined(__GLIBC__) (void)*stream; + #else + (void)*(char*)stream; + #endif (void)offset; (void)whence; @@ -527,11 +622,18 @@ inline int fseek(FILE *stream, long offset, int whence) #define __CPROVER_STDIO_H_INCLUDED #endif +long __VERIFIER_nondet_long(); + inline long ftell(FILE *stream) { __CPROVER_HIDE:; - int return_value; + long return_value=__VERIFIER_nondet_long(); + + #if !defined(__linux__) || defined(__GLIBC__) (void)*stream; + #else + (void)*(char*)stream; + #endif #ifdef __CPROVER_CUSTOM_BITVECTOR_ANALYSIS __CPROVER_assert(__CPROVER_get_must(stream, "open"), @@ -551,7 +653,12 @@ inline long ftell(FILE *stream) void rewind(FILE *stream) { __CPROVER_HIDE: + + #if !defined(__linux__) || defined(__GLIBC__) (void)*stream; + #else + (void)*(char*)stream; + #endif #ifdef __CPROVER_CUSTOM_BITVECTOR_ANALYSIS __CPROVER_assert(__CPROVER_get_must(stream, "open"), @@ -566,6 +673,8 @@ void rewind(FILE *stream) #define __CPROVER_STDIO_H_INCLUDED #endif +size_t __VERIFIER_nondet_size_t(); + size_t fwrite( const void *ptr, size_t size, @@ -575,14 +684,19 @@ size_t fwrite( __CPROVER_HIDE:; (void)*(char*)ptr; (void)size; + + #if !defined(__linux__) || defined(__GLIBC__) (void)*stream; + #else + (void)*(char*)stream; + #endif #ifdef __CPROVER_CUSTOM_BITVECTOR_ANALYSIS __CPROVER_assert(__CPROVER_get_must(stream, "open"), "fwrite file must be open"); #endif - size_t nwrite; + size_t nwrite=__VERIFIER_nondet_size_t(); __CPROVER_assume(nwrite<=nitems); return nwrite; } @@ -688,11 +802,17 @@ inline int sscanf(const char *restrict s, const char *restrict format, ...) #define __CPROVER_STDARG_H_INCLUDED #endif +int __VERIFIER_nondet_int(); + inline int vfscanf(FILE *restrict stream, const char *restrict format, va_list arg) { __CPROVER_HIDE:; - int result; + int result=__VERIFIER_nondet_int(); + #if !defined(__linux__) || defined(__GLIBC__) (void)*stream; + #else + (void)*(char*)stream; + #endif (void)*format; (void)arg; @@ -734,10 +854,12 @@ inline int vscanf(const char *restrict format, va_list arg) #define __CPROVER_STDARG_H_INCLUDED #endif +int __VERIFIER_nondet_int(); + inline int vsscanf(const char *restrict s, const char *restrict format, va_list arg) { __CPROVER_HIDE:; - int result; + int result=__VERIFIER_nondet_int(); (void)*s; (void)*format; (void)arg; @@ -778,12 +900,19 @@ inline int fprintf(FILE *stream, const char *restrict format, ...) #define __CPROVER_STDARG_H_INCLUDED #endif +int __VERIFIER_nondet_int(); + inline int vfprintf(FILE *stream, const char *restrict format, va_list arg) { __CPROVER_HIDE:; - int result; + int result=__VERIFIER_nondet_int(); + + #if !defined(__linux__) || defined(__GLIBC__) (void)*stream; + #else + (void)*(char*)stream; + #endif (void)*format; (void)arg; @@ -812,19 +941,23 @@ inline int vfprintf(FILE *stream, const char *restrict format, va_list arg) #define __CPROVER_STDLIB_H_INCLUDED #endif +char __VERIFIER_nondet_char(); +int __VERIFIER_nondet_int(); + inline int vasprintf(char **ptr, const char *fmt, va_list ap) { (void)*fmt; (void)ap; - int result_buffer_size; + int result_buffer_size=__VERIFIER_nondet_int(); if(result_buffer_size<=0) return -1; *ptr=malloc(result_buffer_size); - for(int i=0; i=0 && result<=2147483647); return result; } diff --git a/src/ansi-c/library/string.c b/src/ansi-c/library/string.c index bfc81bca82b..35cf46f7f66 100644 --- a/src/ansi-c/library/string.c +++ b/src/ansi-c/library/string.c @@ -55,7 +55,7 @@ __inline char *__builtin___strcat_chk(char *dst, const char *src, __CPROVER_size char ch; do { - char ch=src[j]; + ch=src[j]; dst[i]=ch; i++; j++; @@ -298,7 +298,12 @@ inline char *strncat(char *dst, const char *src, size_t n) inline int strcmp(const char *s1, const char *s2) { __CPROVER_HIDE:; + #if !defined(__linux__) || defined(__GLIBC__) if(s1!=0 && s1==s2) return 0; + #else + // musl guarantees non-null of s1 + if(s1==s2) return 0; + #endif #ifdef __CPROVER_STRING_ABSTRACTION int retval; __CPROVER_assert(__CPROVER_is_zero_string(s1), "strcmp zero-termination of 1st argument"); @@ -340,7 +345,12 @@ inline int strcmp(const char *s1, const char *s2) inline int strcasecmp(const char *s1, const char *s2) { __CPROVER_HIDE:; + #if !defined(__linux__) || defined(__GLIBC__) if(s1!=0 && s1==s2) return 0; + #else + // musl guarantees non-null of s1 + if(s1==s2) return 0; + #endif #ifdef __CPROVER_STRING_ABSTRACTION int retval; __CPROVER_assert(__CPROVER_is_zero_string(s1), "strcasecmp zero-termination of 1st argument"); @@ -385,7 +395,12 @@ inline int strcasecmp(const char *s1, const char *s2) inline int strncmp(const char *s1, const char *s2, size_t n) { __CPROVER_HIDE:; + #if !defined(__linux__) || defined(__GLIBC__) if(s1!=0 && s1==s2) return 0; + #else + // musl guarantees non-null of s1 + if(s1==s2) return 0; + #endif #ifdef __CPROVER_STRING_ABSTRACTION __CPROVER_assert(__CPROVER_is_zero_string(s1) || __CPROVER_buffer_size(s1)>=n, "strncmp zero-termination of 1st argument"); __CPROVER_assert(__CPROVER_is_zero_string(s2) || __CPROVER_buffer_size(s2)>=n, "strncmp zero-termination of 2nd argument"); @@ -424,7 +439,12 @@ inline int strncmp(const char *s1, const char *s2, size_t n) inline int strncasecmp(const char *s1, const char *s2, size_t n) { __CPROVER_HIDE:; + #if !defined(__linux__) || defined(__GLIBC__) if(s1!=0 && s1==s2) return 0; + #else + // musl guarantees non-null of s1 + if(s1==s2) return 0; + #endif #ifdef __CPROVER_STRING_ABSTRACTION int retval; __CPROVER_assert(__CPROVER_is_zero_string(s1), "strncasecmp zero-termination of 1st argument"); diff --git a/src/ansi-c/library/time.c b/src/ansi-c/library/time.c index 6c1fb1259a8..71606de0012 100644 --- a/src/ansi-c/library/time.c +++ b/src/ansi-c/library/time.c @@ -7,9 +7,11 @@ #undef time +time_t __VERIFIER_nondet_time_t(); + time_t time(time_t *tloc) { - time_t res; + time_t res=__VERIFIER_nondet_time_t(); if(!tloc) *tloc=res; return res; } @@ -105,10 +107,12 @@ struct tm *localtime_r(const time_t *clock, struct tm *result) #undef mktime +time_t __VERIFIER_nondet_time_t(); + time_t mktime(struct tm *timeptr) { (void)*timeptr; - time_t result; + time_t result=__VERIFIER_nondet_time_t(); return result; } @@ -121,10 +125,12 @@ time_t mktime(struct tm *timeptr) #undef timegm +time_t __VERIFIER_nondet_time_t(); + time_t timegm(struct tm *timeptr) { (void)*timeptr; - time_t result; + time_t result=__VERIFIER_nondet_time_t(); return result; } diff --git a/src/ansi-c/library/unistd.c b/src/ansi-c/library/unistd.c index 00af7246882..06a5859de81 100644 --- a/src/ansi-c/library/unistd.c +++ b/src/ansi-c/library/unistd.c @@ -1,10 +1,12 @@ /* FUNCTION: sleep */ +unsigned __VERIFIER_nondet_unsigned(); + unsigned int sleep(unsigned int seconds) { __CPROVER_HIDE:; // do nothing, but return nondet value - unsigned remaining_time; + unsigned remaining_time=__VERIFIER_nondet_unsigned(); if(remaining_time>seconds) remaining_time=seconds; @@ -23,6 +25,8 @@ inline unsigned int _sleep(unsigned int seconds) /* FUNCTION: unlink */ +int __VERIFIER_nondet_int(); + int unlink(const char *s) { __CPROVER_HIDE:; @@ -30,7 +34,7 @@ int unlink(const char *s) #ifdef __CPROVER_STRING_ABSTRACTION __CPROVER_assert(__CPROVER_is_zero_string(s), "unlink zero-termination"); #endif - int retval; + int retval=__VERIFIER_nondet_int(); return retval; } @@ -46,10 +50,12 @@ extern struct __CPROVER_pipet __CPROVER_pipes[]; extern const int __CPROVER_pipe_offset; extern unsigned __CPROVER_pipe_count; +__CPROVER_bool __VERIFIER_nondet___CPROVER_bool(); + int pipe(int fildes[2]) { __CPROVER_HIDE:; - char error; + __CPROVER_bool error=__VERIFIER_nondet___CPROVER_bool(); if(error) { errno=error==1 ? EMFILE : ENFILE; @@ -102,6 +108,8 @@ int close(int fildes) /* FUNCTION: _close */ +int close(int fildes); + inline int _close(int fildes) { __CPROVER_HIDE:; @@ -126,12 +134,14 @@ extern struct __CPROVER_pipet __CPROVER_pipes[]; // offset to make sure we don't collide with other fds extern const int __CPROVER_pipe_offset; +ssize_t __VERIFIER_nondet_ssize_t(); + ssize_t write(int fildes, const void *buf, size_t nbyte) { __CPROVER_HIDE:; if((fildes>=0 && fildes<=2) || fildes < __CPROVER_pipe_offset) { - ssize_t retval; + ssize_t retval=__VERIFIER_nondet_ssize_t(); __CPROVER_assume(retval>=-1 && retval<=(ssize_t)nbyte); return retval; } @@ -192,12 +202,15 @@ extern struct __CPROVER_pipet __CPROVER_pipes[]; // offset to make sure we don't collide with other fds extern const int __CPROVER_pipe_offset; +__CPROVER_bool __VERIFIER_nondet___CPROVER_bool(); +ssize_t __VERIFIER_nondet_ssize_t(); + ssize_t read(int fildes, void *buf, size_t nbyte) { __CPROVER_HIDE:; if((fildes>=0 && fildes<=2) || fildes < __CPROVER_pipe_offset) { - ssize_t nread; + ssize_t nread=__VERIFIER_nondet_ssize_t(); __CPROVER_assume(0<=nread && (size_t)nread<=nbyte); #if 0 @@ -212,7 +225,7 @@ ssize_t read(int fildes, void *buf, size_t nbyte) __CPROVER_array_replace((char*)buf, nondet_bytes); #endif - __CPROVER_bool error; + __CPROVER_bool error=__VERIFIER_nondet___CPROVER_bool(); return error ? -1 : nread; } From e49c751c98dafc88ed43055c9f040f656787febd Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 15 Aug 2017 19:18:53 +0100 Subject: [PATCH 03/65] Improve ansi-c library syntax check and run via travis --- .travis.yml | 2 ++ src/ansi-c/Makefile | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1dcbb7d02b3..a772cb400d1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -158,6 +158,8 @@ install: - ccache --max-size=1G - COMMAND="make -C src minisat2-download" && eval ${PRE_COMMAND} ${COMMAND} + - COMMAND="make -C src/ansi-c library_check" && + eval ${PRE_COMMAND} ${COMMAND} - COMMAND="make -C src CXX=\"$COMPILER\" CXXFLAGS=\"-Wall -Werror -pedantic -O2 -g $EXTRA_CXXFLAGS\" -j2" && eval ${PRE_COMMAND} ${COMMAND} - COMMAND="make -C src CXX=\"$COMPILER\" CXXFLAGS=\"$FLAGS $EXTRA_CXXFLAGS\" -j2 clobber.dir memory-models.dir musketeer.dir" && diff --git a/src/ansi-c/Makefile b/src/ansi-c/Makefile index 90bdd1e6a56..f251dc3910c 100644 --- a/src/ansi-c/Makefile +++ b/src/ansi-c/Makefile @@ -94,14 +94,15 @@ else endif library_check: library/*.c for f in $(filter-out $(platform_unavail), $^) ; do \ + echo "Checking $$f" ; \ cp $$f __libcheck.c ; \ - sed -i 's/__builtin_[^v]/s&/' __libcheck.c ; \ - sed -i 's/__sync_/s&/' __libcheck.c ; \ - sed -i 's/__noop/s&/' __libcheck.c ; \ + perl -p -i -e 's/(__builtin_[^v])/s$$1/' __libcheck.c ; \ + perl -p -i -e 's/(__sync_)/s$$1/' __libcheck.c ; \ + perl -p -i -e 's/(__noop)/s$$1/' __libcheck.c ; \ $(CC) -std=gnu99 -E -include library/cprover.h -D__CPROVER_bool=_Bool \ -D__CPROVER_thread_local=__thread -DLIBRARY_CHECK -o __libcheck.i __libcheck.c ; \ $(CC) -S -Wall -Werror -pedantic -Wextra -std=gnu99 __libcheck.i -o __libcheck.s \ - -Wno-unused-label -Wno-uninitialized ; \ + -Wno-unused-label ; \ ec=$$? ; \ $(RM) __libcheck.s __libcheck.i __libcheck.c ; \ [ $$ec -eq 0 ] || exit $$ec ; \ From b142da4330c00c3bf8c806f9d0c335688b325458 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Thu, 5 Jan 2017 17:36:20 +0000 Subject: [PATCH 04/65] Check for memory leaks in C++ new/delete --- src/ansi-c/library/new.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ansi-c/library/new.c b/src/ansi-c/library/new.c index 0cd78bd72ac..81bd62b2093 100644 --- a/src/ansi-c/library/new.c +++ b/src/ansi-c/library/new.c @@ -93,6 +93,9 @@ inline void __delete(void *ptr) // non-deterministically record as deallocated __CPROVER_bool record=__VERIFIER_nondet___CPROVER_bool(); __CPROVER_deallocated=record?ptr:__CPROVER_deallocated; + + // detect memory leaks + if(__CPROVER_memory_leak==ptr) __CPROVER_memory_leak=0; } } @@ -124,5 +127,8 @@ inline void __delete_array(void *ptr) // non-deterministically record as deallocated __CPROVER_bool record=__VERIFIER_nondet___CPROVER_bool(); __CPROVER_deallocated=record?ptr:__CPROVER_deallocated; + + // detect memory leaks + if(__CPROVER_memory_leak==ptr) __CPROVER_memory_leak=0; } } From b934a1365d335a1a3e23abdb21ee7a10af998748 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Thu, 31 Aug 2017 11:48:16 +0100 Subject: [PATCH 05/65] Flag java internal functions as internal in JSON/XML output Btw, entry point now starts with CPROVER_PREFIX. --- src/goto-programs/show_goto_functions_json.cpp | 7 +++++-- src/goto-programs/show_goto_functions_xml.cpp | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/goto-programs/show_goto_functions_json.cpp b/src/goto-programs/show_goto_functions_json.cpp index 3cb1dfd4dd8..6c365820178 100644 --- a/src/goto-programs/show_goto_functions_json.cpp +++ b/src/goto-programs/show_goto_functions_json.cpp @@ -48,8 +48,11 @@ json_objectt show_goto_functions_jsont::convert( json_function["name"]=json_stringt(id2string(function_name)); json_function["isBodyAvailable"]= jsont::json_boolean(function.body_available()); - bool is_internal=(has_prefix(id2string(function_name), CPROVER_PREFIX) || - function_name==goto_functions.entry_point()); + bool is_internal= + has_prefix(id2string(function_name), CPROVER_PREFIX) || + has_prefix(id2string(function_name), "java::array[") || + has_prefix(id2string(function_name), "java::org.cprover") || + has_prefix(id2string(function_name), "java::java"); json_function["isInternal"]=jsont::json_boolean(is_internal); if(function.body_available()) diff --git a/src/goto-programs/show_goto_functions_xml.cpp b/src/goto-programs/show_goto_functions_xml.cpp index 33424074949..6d69ec0f33c 100644 --- a/src/goto-programs/show_goto_functions_xml.cpp +++ b/src/goto-programs/show_goto_functions_xml.cpp @@ -49,8 +49,11 @@ xmlt show_goto_functions_xmlt::convert( xml_function.set_attribute("name", id2string(function_name)); xml_function.set_attribute_bool( "is_body_available", function.body_available()); - bool is_internal=(has_prefix(id2string(function_name), CPROVER_PREFIX) || - function_name==goto_functions.entry_point()); + bool is_internal= + has_prefix(id2string(function_name), CPROVER_PREFIX) || + has_prefix(id2string(function_name), "java::array[") || + has_prefix(id2string(function_name), "java::org.cprover") || + has_prefix(id2string(function_name), "java::java"); xml_function.set_attribute_bool("is_internal", is_internal); if(function.body_available()) From 94ec79079d8cfc12da9670a9b7af7dfdb75e63a0 Mon Sep 17 00:00:00 2001 From: Nathan Phillips Date: Thu, 31 Aug 2017 16:46:51 +0100 Subject: [PATCH 06/65] Clarified INVARIANT message in get_message_handler --- src/util/message.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/util/message.h b/src/util/message.h index 9da886b0404..758fdd06879 100644 --- a/src/util/message.h +++ b/src/util/message.h @@ -137,7 +137,9 @@ class messaget message_handlert &get_message_handler() { - INVARIANT(message_handler!=nullptr, "message handler is set"); + INVARIANT( + message_handler!=nullptr, + "message handler should be set before calling get_message_handler"); return *message_handler; } From d5a504507a0d9c2f37d5fbdc472632d772bc7a3c Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Thu, 31 Aug 2017 23:12:17 +0100 Subject: [PATCH 07/65] HAVE_BV_REFINEMENT and HAVE_JAVA_BYTECODE are no longer needed --- src/clobber/Makefile | 11 +---------- src/goto-diff/Makefile | 6 +----- src/goto-diff/goto_diff_languages.cpp | 4 ---- src/goto-instrument/Makefile | 6 +----- src/symex/Makefile | 11 +---------- 5 files changed, 4 insertions(+), 34 deletions(-) diff --git a/src/clobber/Makefile b/src/clobber/Makefile index f3a4c8aed20..74a133782c6 100644 --- a/src/clobber/Makefile +++ b/src/clobber/Makefile @@ -3,6 +3,7 @@ SRC = clobber_main.cpp \ # Empty last line OBJ += ../ansi-c/ansi-c$(LIBEXT) \ ../cpp/cpp$(LIBEXT) \ + ../java_bytecode/java_bytecode$(LIBEXT) \ ../linking/linking$(LIBEXT) \ ../big-int/big-int$(LIBEXT) \ ../goto-programs/goto-programs$(LIBEXT) \ @@ -30,16 +31,6 @@ CLEANFILES = clobber$(EXEEXT) all: clobber$(EXEEXT) -ifneq ($(wildcard ../bv_refinement/Makefile),) - OBJ += ../bv_refinement/bv_refinement$(LIBEXT) - CP_CXXFLAGS += -DHAVE_BV_REFINEMENT -endif - -ifneq ($(wildcard ../java_bytecode/Makefile),) - OBJ += ../java_bytecode/java_bytecode$(LIBEXT) - CP_CXXFLAGS += -DHAVE_JAVA_BYTECODE -endif - ifneq ($(wildcard ../specc/Makefile),) OBJ += ../specc/specc$(LIBEXT) CP_CXXFLAGS += -DHAVE_SPECC diff --git a/src/goto-diff/Makefile b/src/goto-diff/Makefile index b11cb008b3a..17b2d253561 100644 --- a/src/goto-diff/Makefile +++ b/src/goto-diff/Makefile @@ -9,6 +9,7 @@ SRC = change_impact.cpp \ OBJ += ../ansi-c/ansi-c$(LIBEXT) \ ../cpp/cpp$(LIBEXT) \ + ../java_bytecode/java_bytecode$(LIBEXT) \ ../linking/linking$(LIBEXT) \ ../big-int/big-int$(LIBEXT) \ ../goto-programs/goto-programs$(LIBEXT) \ @@ -33,11 +34,6 @@ CLEANFILES = goto-diff$(EXEEXT) all: goto-diff$(EXEEXT) -ifneq ($(wildcard ../java_bytecode/Makefile),) - OBJ += ../java_bytecode/java_bytecode$(LIBEXT) - CP_CXXFLAGS += -DHAVE_JAVA_BYTECODE -endif - ifneq ($(wildcard ../specc/Makefile),) OBJ += ../specc/specc$(LIBEXT) CP_CXXFLAGS += -DHAVE_SPECC diff --git a/src/goto-diff/goto_diff_languages.cpp b/src/goto-diff/goto_diff_languages.cpp index c55f82e637e..c930f20e77b 100644 --- a/src/goto-diff/goto_diff_languages.cpp +++ b/src/goto-diff/goto_diff_languages.cpp @@ -20,9 +20,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #endif -#ifdef HAVE_JAVA_BYTECODE #include -#endif void goto_diff_languagest::register_languages() { @@ -33,7 +31,5 @@ void goto_diff_languagest::register_languages() register_language(new_specc_language); #endif - #ifdef HAVE_JAVA_BYTECODE register_language(new_java_bytecode_language); - #endif } diff --git a/src/goto-instrument/Makefile b/src/goto-instrument/Makefile index bc3cb10f1b3..6d54c94fae3 100644 --- a/src/goto-instrument/Makefile +++ b/src/goto-instrument/Makefile @@ -65,6 +65,7 @@ SRC = accelerate/accelerate.cpp \ OBJ += ../ansi-c/ansi-c$(LIBEXT) \ ../cpp/cpp$(LIBEXT) \ + ../java_bytecode/java_bytecode$(LIBEXT) \ ../linking/linking$(LIBEXT) \ ../big-int/big-int$(LIBEXT) \ ../goto-programs/goto-programs$(LIBEXT) \ @@ -90,11 +91,6 @@ include ../common all: goto-instrument$(EXEEXT) -ifneq ($(wildcard ../java_bytecode/Makefile),) - OBJ += ../java_bytecode/java_bytecode$(LIBEXT) - CP_CXXFLAGS += -DHAVE_JAVA_BYTECODE -endif - ifneq ($(LIB_GLPK),) LIBS += $(LIB_GLPK) CP_CXXFLAGS += -DHAVE_GLPK diff --git a/src/symex/Makefile b/src/symex/Makefile index 672b2e07fc2..46236715d9c 100644 --- a/src/symex/Makefile +++ b/src/symex/Makefile @@ -6,6 +6,7 @@ SRC = path_search.cpp \ OBJ += ../ansi-c/ansi-c$(LIBEXT) \ ../cpp/cpp$(LIBEXT) \ + ../java_bytecode/java_bytecode$(LIBEXT) \ ../linking/linking$(LIBEXT) \ ../big-int/big-int$(LIBEXT) \ ../goto-programs/goto-programs$(LIBEXT) \ @@ -34,16 +35,6 @@ CLEANFILES = symex$(EXEEXT) all: symex$(EXEEXT) -ifneq ($(wildcard ../bv_refinement/Makefile),) - OBJ += ../bv_refinement/bv_refinement$(LIBEXT) - CP_CXXFLAGS += -DHAVE_BV_REFINEMENT -endif - -ifneq ($(wildcard ../java_bytecode/Makefile),) - OBJ += ../java_bytecode/java_bytecode$(LIBEXT) - CP_CXXFLAGS += -DHAVE_JAVA_BYTECODE -endif - ifneq ($(wildcard ../specc/Makefile),) OBJ += ../specc/specc$(LIBEXT) CP_CXXFLAGS += -DHAVE_SPECC From 4be7685978cc9050930fb4036c6bdf9e868722f4 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Fri, 1 Sep 2017 11:03:53 +0100 Subject: [PATCH 08/65] Do not add an "l" prefix to double constants when double==long double --- regression/cbmc/Float24/main.c | 6 ++++++ regression/cbmc/Float24/test.desc | 10 ++++++++++ src/ansi-c/expr2c.cpp | 3 ++- 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 regression/cbmc/Float24/main.c create mode 100644 regression/cbmc/Float24/test.desc diff --git a/regression/cbmc/Float24/main.c b/regression/cbmc/Float24/main.c new file mode 100644 index 00000000000..0e12f24780a --- /dev/null +++ b/regression/cbmc/Float24/main.c @@ -0,0 +1,6 @@ +int main() +{ + double d=5.1; + __CPROVER_assert(0, ""); + return 0; +} diff --git a/regression/cbmc/Float24/test.desc b/regression/cbmc/Float24/test.desc new file mode 100644 index 00000000000..6a7c97325db --- /dev/null +++ b/regression/cbmc/Float24/test.desc @@ -0,0 +1,10 @@ +CORE +main.c +--win32 --xml-ui +^EXIT=10$ +^SIGNAL=0$ +VERIFICATION FAILED +5\.1 +-- +^warning: ignoring +5\.1l diff --git a/src/ansi-c/expr2c.cpp b/src/ansi-c/expr2c.cpp index eecc856a0f7..b889476a73f 100644 --- a/src/ansi-c/expr2c.cpp +++ b/src/ansi-c/expr2c.cpp @@ -1859,7 +1859,8 @@ std::string expr2ct::convert_constant( // ANSI-C: double is default; float/long-double require annotation if(src.type()==float_type()) dest+='f'; - else if(src.type()==long_double_type()) + else if(src.type()==long_double_type() && + double_type()!=long_double_type()) dest+='l'; } else if(dest.size()==4 && From e8129a0b7b11cf9a83679d699192a5b5dd85eb2a Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Tue, 15 Aug 2017 13:43:35 +0100 Subject: [PATCH 09/65] Merge basic blocks that are chains of unconditional gotos --- src/goto-instrument/cover.cpp | 92 +++++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 21 deletions(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index 2c3abfe2108..b70abf734ff 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -11,6 +11,7 @@ Date: May 2016 /// \file /// Coverage Instrumentation + #include "cover.h" #include @@ -32,23 +33,54 @@ class basic_blockst explicit basic_blockst(const goto_programt &_goto_program) { bool next_is_target=true; - unsigned block_count=0; + unsigned current_block=0; forall_goto_program_instructions(it, _goto_program) { + // Is it a potential beginning of a block? if(next_is_target || it->is_target()) - block_count++; + { + // We keep the block number if this potential block + // is a continuation of a previous block through + // unconditional forward gotos; otherwise we increase the + // block number. + bool increase_block_nr=true; + if(it->incoming_edges.size()==1) + { + goto_programt::targett in_t=*it->incoming_edges.begin(); + if(in_t->is_goto() && + !in_t->is_backwards_goto() && + in_t->guard.is_true()) + { + current_block=block_map[in_t]; + increase_block_nr=false; + } + } + if(increase_block_nr) + { + block_infos.push_back(block_infot()); + block_infos.back().source_location=source_locationt::nil(); + current_block=block_infos.size()-1; + } + } + INVARIANT( + current_blocksource_location.get_line(); if(!line.empty()) - block_line_cover_map[block_count] - .insert(unsafe_string2unsigned(id2string(line))); - - block_map[it]=block_count; + block_info.lines.insert(unsafe_string2unsigned(id2string(line))); if(!it->source_location.is_nil() && - source_location_map.find(block_count)==source_location_map.end()) - source_location_map[block_count]=it->source_location; + !it->source_location.get_file().empty() && + !it->source_location.get_line().empty() && + block_info.source_location.is_nil()) + block_info.source_location=it->source_location; next_is_target= #if 0 @@ -62,16 +94,19 @@ class basic_blockst // create list of covered lines as CSV string and set as property of source // location of basic block, compress to ranges if applicable format_number_ranget format_lines; - for(const auto &cover_set : block_line_cover_map) + for(auto &block_info : block_infos) { - INVARIANT(!cover_set.second.empty(), + if(block_info.source_location.is_nil()) + continue; + + const auto &cover_set=block_info.lines; + INVARIANT(!cover_set.empty(), "covered lines set must not be empty"); std::vector - line_list{cover_set.second.begin(), cover_set.second.end()}; + line_list{cover_set.begin(), cover_set.end()}; std::string covered_lines=format_lines(line_list); - source_location_map[cover_set.first] - .set_basic_block_covered_lines(covered_lines); + block_info.source_location.set_basic_block_covered_lines(covered_lines); } } @@ -79,20 +114,35 @@ class basic_blockst typedef std::map block_mapt; block_mapt block_map; - // map block numbers to source code locations - typedef std::map source_location_mapt; - source_location_mapt source_location_map; + struct block_infot + { + /// the source location representative for this block + // (we need a separate copy of source locations because we attach + // the line number ranges to them) + source_locationt source_location; - // map block numbers to set of line numbers - typedef std::map > - block_line_cover_mapt; - block_line_cover_mapt block_line_cover_map; + // map block numbers to source code locations + /// the set of lines belonging to this block + std::unordered_set lines; + }; + + typedef std::vector block_infost; + block_infost block_infos; inline unsigned operator[](goto_programt::const_targett t) { return block_map[t]; } + /// \param block_nr a block number + /// \return the source location corresponding to the given block number + const source_locationt &source_location_of( + unsigned block_nr) + { + INVARIANT(block_nrfunction)+"#"+b; source_locationt source_location= - basic_blocks.source_location_map[block_nr]; + basic_blocks.source_location_of(block_nr); // check whether the current goal already exists if(!goals.is_existing_goal(source_location) && From 6a8b46fca1a3124f49c85f1cfb2d52e9933da863 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Tue, 15 Aug 2017 22:18:33 +0100 Subject: [PATCH 10/65] Instruction to be instrumented representative for basic block --- src/goto-instrument/cover.cpp | 47 +++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index b70abf734ff..208c1c22f8d 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -59,6 +59,7 @@ class basic_blockst if(increase_block_nr) { block_infos.push_back(block_infot()); + block_infos.back().representative_inst=it; block_infos.back().source_location=source_locationt::nil(); current_block=block_infos.size()-1; } @@ -76,11 +77,15 @@ class basic_blockst if(!line.empty()) block_info.lines.insert(unsafe_string2unsigned(id2string(line))); + // set representative program location to instrument if(!it->source_location.is_nil() && !it->source_location.get_file().empty() && !it->source_location.get_line().empty() && block_info.source_location.is_nil()) + { + block_info.representative_inst=it; // update block_info.source_location=it->source_location; + } next_is_target= #if 0 @@ -116,6 +121,9 @@ class basic_blockst struct block_infot { + /// the program location to instrument for this block + goto_programt::const_targett representative_inst; + /// the source location representative for this block // (we need a separate copy of source locations because we attach // the line number ranges to them) @@ -129,13 +137,28 @@ class basic_blockst typedef std::vector block_infost; block_infost block_infos; - inline unsigned operator[](goto_programt::const_targett t) + /// \param t a goto instruction + /// \return the block number of the block + /// the given goto instruction is part of + unsigned block_of(goto_programt::const_targett t) + { + block_mapt::const_iterator it=block_map.find(t); + INVARIANT(it!=block_map.end(), "instruction must be part of a block"); + return it->second; + } + + /// \param block_nr a block number + /// \return the instruction selected for + /// instrumentation representative of the given block + goto_programt::const_targett instruction_of(unsigned block_nr) { - return block_map[t]; + INVARIANT(block_nr blocks_done; - // ignore if built-in library if(!goto_program.instructions.empty() && goto_program.instructions.front().source_location.is_built_in()) return; + const namespacet ns(symbol_table); + basic_blockst basic_blocks(goto_program); + const irep_idt coverage_criterion=as_string(criterion); const irep_idt property_class="coverage"; @@ -1177,10 +1199,12 @@ void instrument_cover_goals( i_it->make_skip(); { - unsigned block_nr=basic_blocks[i_it]; - if(blocks_done.insert(block_nr).second) + unsigned block_nr=basic_blocks.block_of(i_it); + goto_programt::const_targett in_t=basic_blocks.instruction_of(block_nr); + // we only instrument the selected instruction + if(in_t==i_it) { - std::string b=std::to_string(block_nr); + std::string b=std::to_string(block_nr+1); // start with 1 std::string id=id2string(i_it->function)+"#"+b; source_locationt source_location= basic_blocks.source_location_of(block_nr); @@ -1234,7 +1258,8 @@ void instrument_cover_goals( if(i_it->is_goto() && !i_it->guard.is_true() && cover_curr_function && !i_it->source_location.is_built_in()) { - std::string b=std::to_string(basic_blocks[i_it]); + std::string b= + std::to_string(basic_blocks.block_of(i_it)+1); // start with 1 std::string true_comment= "function "+id2string(i_it->function)+" block "+b+" branch true"; std::string false_comment= From 317f7e851f23c57a7768a6547fe3c35dc00ad5b0 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Wed, 30 Aug 2017 18:36:02 +0100 Subject: [PATCH 11/65] Protect internals of basic_blockst --- src/goto-instrument/cover.cpp | 45 ++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index 208c1c22f8d..da8038f7ae1 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -115,28 +115,6 @@ class basic_blockst } } - // map program locations to block numbers - typedef std::map block_mapt; - block_mapt block_map; - - struct block_infot - { - /// the program location to instrument for this block - goto_programt::const_targett representative_inst; - - /// the source location representative for this block - // (we need a separate copy of source locations because we attach - // the line number ranges to them) - source_locationt source_location; - - // map block numbers to source code locations - /// the set of lines belonging to this block - std::unordered_set lines; - }; - - typedef std::vector block_infost; - block_infost block_infos; - /// \param t a goto instruction /// \return the block number of the block /// the given goto instruction is part of @@ -176,6 +154,29 @@ class basic_blockst << " -> " << b_it->second << '\n'; } + +protected: + // map program locations to block numbers + typedef std::map block_mapt; + block_mapt block_map; + + struct block_infot + { + /// the program location to instrument for this block + goto_programt::const_targett representative_inst; + + /// the source location representative for this block + // (we need a separate copy of source locations because we attach + // the line number ranges to them) + source_locationt source_location; + + // map block numbers to source code locations + /// the set of lines belonging to this block + std::unordered_set lines; + }; + + typedef std::vector block_infost; + block_infost block_infos; }; bool coverage_goalst::get_coverage_goals( From 60eb74e7cb3601e75def7ce21f6bb18ed3fff1eb Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Thu, 31 Aug 2017 19:04:13 +0100 Subject: [PATCH 12/65] Factor out updating of covered lines in block --- src/goto-instrument/cover.cpp | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index da8038f7ae1..bdf9a5deba4 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -96,23 +96,8 @@ class basic_blockst #endif } - // create list of covered lines as CSV string and set as property of source - // location of basic block, compress to ranges if applicable - format_number_ranget format_lines; for(auto &block_info : block_infos) - { - if(block_info.source_location.is_nil()) - continue; - - const auto &cover_set=block_info.lines; - INVARIANT(!cover_set.empty(), - "covered lines set must not be empty"); - std::vector - line_list{cover_set.begin(), cover_set.end()}; - - std::string covered_lines=format_lines(line_list); - block_info.source_location.set_basic_block_covered_lines(covered_lines); - } + update_covered_lines(block_info); } /// \param t a goto instruction @@ -177,6 +162,24 @@ class basic_blockst typedef std::vector block_infost; block_infost block_infos; + + /// create list of covered lines as CSV string and set as property of source + /// location of basic block, compress to ranges if applicable + void update_covered_lines(block_infot &block_info) + { + if(block_info.source_location.is_nil()) + return; + + const auto &cover_set=block_info.lines; + INVARIANT(!cover_set.empty(), + "covered lines set must not be empty"); + std::vector + line_list{cover_set.begin(), cover_set.end()}; + + format_number_ranget format_lines; + std::string covered_lines=format_lines(line_list); + block_info.source_location.set_basic_block_covered_lines(covered_lines); + } }; bool coverage_goalst::get_coverage_goals( From f9ac37a63927ec1ec94106935471339a5981d721 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Tue, 15 Aug 2017 22:27:45 +0100 Subject: [PATCH 13/65] Select basic block representative instruction such that java bytecode indices are unique for each basic block --- src/goto-instrument/cover.cpp | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index bdf9a5deba4..ba97f841cac 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -129,6 +129,58 @@ class basic_blockst return block_infos.at(block_nr).source_location; } + /// Select an instruction to be instrumented for each basic block such that + /// the java bytecode indices for each basic block is unique + /// \param goto_program The goto program + void select_unique_java_bytecode_indices(const goto_programt &goto_program) + { + std::set blocks_seen; + std::set bytecode_indices_seen; + + forall_goto_program_instructions(it, goto_program) + { + unsigned block_nr=block_of(it); + if(blocks_seen.find(block_nr)!=blocks_seen.end()) + continue; + + INVARIANT(block_nrsource_location.get_java_bytecode_index().empty()) + { + // search for a representative + if(bytecode_indices_seen.insert( + it->source_location.get_java_bytecode_index()).second) + { + block_info.representative_inst=it; + block_info.source_location=it->source_location; + update_covered_lines(block_info); + blocks_seen.insert(block_nr); + } + } + } + else if(it==block_info.representative_inst) + { + // check the existing representative + if(!it->source_location.get_java_bytecode_index().empty()) + { + if(bytecode_indices_seen.insert( + it->source_location.get_java_bytecode_index()).second) + { + blocks_seen.insert(block_nr); + } + else + { + // clash, reset to search for a new one + block_info.representative_inst=goto_program.instructions.end(); + block_info.source_location=source_locationt::nil(); + } + } + } + } + } + void output(std::ostream &out) { for(block_mapt::const_iterator @@ -1145,6 +1197,7 @@ void instrument_cover_goals( const namespacet ns(symbol_table); basic_blockst basic_blocks(goto_program); + basic_blocks.select_unique_java_bytecode_indices(goto_program); const irep_idt coverage_criterion=as_string(criterion); const irep_idt property_class="coverage"; From 7f374b3e9c8df01ac5776ba4ccc5d3400dbb9e39 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Tue, 15 Aug 2017 22:36:52 +0100 Subject: [PATCH 14/65] Warn about anomalies in basic block instrumentation --- src/goto-instrument/cover.cpp | 52 +++++++++++++++++++++++++++++-- src/goto-instrument/cover.h | 4 +++ src/symex/symex_parse_options.cpp | 3 +- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index ba97f841cac..5c7d07bb404 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -181,6 +181,43 @@ class basic_blockst } } + /// Output warnings about ignored blocks + /// \param goto_program The goto program + /// \param message_handler The message handler + void report_block_anomalies( + const goto_programt &goto_program, + message_handlert &message_handler) + { + messaget msg(message_handler); + std::set blocks_seen; + forall_goto_program_instructions(it, goto_program) + { + unsigned block_nr=block_of(it); + const block_infot &block_info=block_infos.at(block_nr); + + if(blocks_seen.insert(block_nr).second && + block_info.representative_inst==goto_program.instructions.end()) + { + msg.warning() << "Ignoring block " << (block_nr+1) << " location " + << it->location_number << " " + << it->source_location + << " (bytecode-index already instrumented)" + << messaget::eom; + } + else if(block_info.representative_inst==it && + block_info.source_location.is_nil()) + { + msg.warning() << "Ignoring block " << (block_nr+1) << " location " + << it->location_number << " " + << it->function + << " (missing source location)" + << messaget::eom; + } + // The location numbers printed here are those + // before the coverage instrumentation. + } + } + void output(std::ostream &out) { for(block_mapt::const_iterator @@ -1140,6 +1177,7 @@ void instrument_cover_goals( const symbol_tablet &symbol_table, goto_programt &goto_program, coverage_criteriont criterion, + message_handlert &message_handler, bool function_only) { coverage_goalst goals; // empty already covered goals @@ -1147,6 +1185,7 @@ void instrument_cover_goals( symbol_table, goto_program, criterion, + message_handler, goals, function_only, false); @@ -1182,6 +1221,7 @@ void instrument_cover_goals( const symbol_tablet &symbol_table, goto_programt &goto_program, coverage_criteriont criterion, + message_handlert &message_handler, coverage_goalst &goals, bool function_only, bool ignore_trivial) @@ -1198,6 +1238,7 @@ void instrument_cover_goals( const namespacet ns(symbol_table); basic_blockst basic_blocks(goto_program); basic_blocks.select_unique_java_bytecode_indices(goto_program); + basic_blocks.report_block_anomalies(goto_program, message_handler); const irep_idt coverage_criterion=as_string(criterion); const irep_idt property_class="coverage"; @@ -1529,6 +1570,7 @@ void instrument_cover_goals( const symbol_tablet &symbol_table, goto_functionst &goto_functions, coverage_criteriont criterion, + message_handlert &message_handler, coverage_goalst &goals, bool function_only, bool ignore_trivial) @@ -1544,6 +1586,7 @@ void instrument_cover_goals( symbol_table, f_it->second.body, criterion, + message_handler, goals, function_only, ignore_trivial); @@ -1554,6 +1597,7 @@ void instrument_cover_goals( const symbol_tablet &symbol_table, goto_functionst &goto_functions, coverage_criteriont criterion, + message_handlert &message_handler, bool function_only) { // empty set of existing goals @@ -1562,6 +1606,7 @@ void instrument_cover_goals( symbol_table, goto_functions, criterion, + message_handler, goals, function_only, false); @@ -1571,9 +1616,9 @@ bool instrument_cover_goals( const cmdlinet &cmdline, const symbol_tablet &symbol_table, goto_functionst &goto_functions, - message_handlert &msgh) + message_handlert &message_handler) { - messaget msg(msgh); + messaget msg(message_handler); std::list criteria_strings=cmdline.get_values("cover"); std::set criteria; bool keep_assertions=false; @@ -1650,7 +1695,7 @@ bool instrument_cover_goals( const std::string coverage=cmdline.get_value("existing-coverage"); // get a coverage_goalst object if(coverage_goalst::get_coverage_goals( - coverage, msgh, existing_goals, mode)) + coverage, message_handler, existing_goals, mode)) { msg.error() << "get_coverage_goals failed" << messaget::eom; return true; @@ -1665,6 +1710,7 @@ bool instrument_cover_goals( symbol_table, goto_functions, criterion, + message_handler, existing_goals, cmdline.isset("cover-function-only"), cmdline.isset("no-trivial-tests")); diff --git a/src/goto-instrument/cover.h b/src/goto-instrument/cover.h index 47086714737..4ad0b4992ab 100644 --- a/src/goto-instrument/cover.h +++ b/src/goto-instrument/cover.h @@ -49,18 +49,21 @@ void instrument_cover_goals( const symbol_tablet &, goto_functionst &, coverage_criteriont, + message_handlert &message_handler, bool function_only=false); void instrument_cover_goals( const symbol_tablet &, goto_programt &, coverage_criteriont, + message_handlert &message_handler, bool function_only=false); void instrument_cover_goals( const symbol_tablet &, goto_functionst &, coverage_criteriont, + message_handlert &message_handler, coverage_goalst &, bool function_only=false, bool ignore_trivial=false); @@ -69,6 +72,7 @@ void instrument_cover_goals( const symbol_tablet &, goto_programt &, coverage_criteriont, + message_handlert &message_handler, coverage_goalst &goals, bool function_only=false, bool ignore_trivial=false); diff --git a/src/symex/symex_parse_options.cpp b/src/symex/symex_parse_options.cpp index 2361f3c494c..d5fd98ff686 100644 --- a/src/symex/symex_parse_options.cpp +++ b/src/symex/symex_parse_options.cpp @@ -368,7 +368,8 @@ bool symex_parse_optionst::process_goto_program(const optionst &options) } status() << "Instrumenting coverage goals" << eom; - instrument_cover_goals(symbol_table, goto_model.goto_functions, c); + instrument_cover_goals( + symbol_table, goto_model.goto_functions, c, get_message_handler()); goto_model.goto_functions.update(); } From 99d9613db3fb8ce4d3c66ebf8a38be8f0c83ee31 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Mon, 21 Aug 2017 17:39:22 +0100 Subject: [PATCH 15/65] Expect existing coverage file only to contain array of goals --- src/goto-instrument/cover.cpp | 98 ++++++++++++++++------------------- 1 file changed, 45 insertions(+), 53 deletions(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index 5c7d07bb404..3b991682890 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -300,66 +300,58 @@ bool coverage_goalst::get_coverage_goals( } // traverse the given JSON file - for(const auto &goals_in_json : json.array) + for(const auto &each_goal : json.array) { - // get the set of goals - if(goals_in_json["goals"].is_array()) + // ensure minimal requirements for a goal entry + PRECONDITION( + (!each_goal["goal"].is_null()) || + (!each_goal["sourceLocation"]["bytecodeIndex"].is_null()) || + (!each_goal["sourceLocation"]["file"].is_null() && + !each_goal["sourceLocation"]["function"].is_null() && + !each_goal["sourceLocation"]["line"].is_null())); + + // check whether bytecodeIndex is provided for Java programs + if(mode==ID_java && + each_goal["sourceLocation"]["bytecodeIndex"].is_null()) { - // store the source location for each existing goal - for(const auto &each_goal : goals_in_json["goals"].array) - { - // ensure minimal requirements for a goal entry - PRECONDITION( - (!each_goal["goal"].is_null()) || - (!each_goal["sourceLocation"]["bytecodeIndex"].is_null()) || - (!each_goal["sourceLocation"]["file"].is_null() && - !each_goal["sourceLocation"]["function"].is_null() && - !each_goal["sourceLocation"]["line"].is_null())); - - // check whether bytecodeIndex is provided for Java programs - if(mode==ID_java && - each_goal["sourceLocation"]["bytecodeIndex"].is_null()) - { - messaget message(message_handler); - message.error() << coverage_file - << " file does not contain bytecodeIndex" - << messaget::eom; - return true; - } - - if(!each_goal["sourceLocation"]["bytecodeIndex"].is_null()) - { - // get and set the bytecodeIndex - irep_idt bytecode_index= - each_goal["sourceLocation"]["bytecodeIndex"].value; - source_location.set_java_bytecode_index(bytecode_index); - } + messaget message(message_handler); + message.error() << coverage_file + << " file does not contain bytecodeIndex" + << messaget::eom; + return true; + } - if(!each_goal["sourceLocation"]["file"].is_null()) - { - // get and set the file - irep_idt file=each_goal["sourceLocation"]["file"].value; - source_location.set_file(file); - } + if(!each_goal["sourceLocation"]["bytecodeIndex"].is_null()) + { + // get and set the bytecodeIndex + irep_idt bytecode_index= + each_goal["sourceLocation"]["bytecodeIndex"].value; + source_location.set_java_bytecode_index(bytecode_index); + } - if(!each_goal["sourceLocation"]["function"].is_null()) - { - // get and set the function - irep_idt function=each_goal["sourceLocation"]["function"].value; - source_location.set_function(function); - } + if(!each_goal["sourceLocation"]["file"].is_null()) + { + // get and set the file + irep_idt file=each_goal["sourceLocation"]["file"].value; + source_location.set_file(file); + } - if(!each_goal["sourceLocation"]["line"].is_null()) - { - // get and set the line - irep_idt line=each_goal["sourceLocation"]["line"].value; - source_location.set_line(line); - } + if(!each_goal["sourceLocation"]["function"].is_null()) + { + // get and set the function + irep_idt function=each_goal["sourceLocation"]["function"].value; + source_location.set_function(function); + } - // store the existing goal - goals.add_goal(source_location); - } + if(!each_goal["sourceLocation"]["line"].is_null()) + { + // get and set the line + irep_idt line=each_goal["sourceLocation"]["line"].value; + source_location.set_line(line); } + + // store the existing goal + goals.add_goal(source_location); } return false; } From 5e7a328fe41e237ff2c34ab1d9d322e3e599f9cc Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Mon, 21 Aug 2017 18:17:18 +0100 Subject: [PATCH 16/65] List existing goals --- src/goto-instrument/cover.cpp | 30 +++++++++++++++--------------- src/goto-instrument/cover.h | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index 3b991682890..8993445250a 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -277,13 +277,15 @@ bool coverage_goalst::get_coverage_goals( coverage_goalst &goals, const irep_idt &mode) { + messaget message(message_handler); jsont json; source_locationt source_location; + message.status() << "Load existing coverage goals\n"; + // check coverage file if(parse_json(coverage_file, message_handler, json)) { - messaget message(message_handler); message.error() << coverage_file << " file is not a valid json file" << messaget::eom; return true; @@ -292,7 +294,6 @@ bool coverage_goalst::get_coverage_goals( // make sure that we have an array of elements if(!json.is_array()) { - messaget message(message_handler); message.error() << "expecting an array in the " << coverage_file << " file, but got " << json << messaget::eom; @@ -352,7 +353,10 @@ bool coverage_goalst::get_coverage_goals( // store the existing goal goals.add_goal(source_location); + message.status() << " " << source_location << "\n"; } + message.status() << messaget::eom; + return false; } @@ -363,20 +367,18 @@ void coverage_goalst::add_goal(source_locationt goal) existing_goals[goal]=false; } -/// check whether we have an existing goal that is uncovered -/// \param msg: message to be printed about the uncovered goal -void coverage_goalst::check_uncovered_goals(messaget &msg) +/// check whether we have an existing goal that does not match +/// an instrumented goal +/// \param msg: Message stream +void coverage_goalst::check_existing_goals(messaget &msg) { for(const auto &existing_loc : existing_goals) { if(!existing_loc.second) { msg.warning() - << "Warning: existing goal in file " - << existing_loc.first.get_file() - << " line " << existing_loc.first.get_line() - << " function " << existing_loc.first.get_function() - << " is uncovered" << messaget::eom; + << "Warning: unmatched existing goal " + << existing_loc.first << messaget::eom; } } } @@ -1682,14 +1684,13 @@ bool instrument_cover_goals( namespacet ns(symbol_table); const irep_idt &mode=ns.lookup(goto_functions.entry_point()).mode; - msg.status() << "Add existing coverage goals" << messaget::eom; // get file with covered test goals const std::string coverage=cmdline.get_value("existing-coverage"); // get a coverage_goalst object if(coverage_goalst::get_coverage_goals( coverage, message_handler, existing_goals, mode)) { - msg.error() << "get_coverage_goals failed" << messaget::eom; + msg.error() << "Loading existing coverage goals failed" << messaget::eom; return true; } } @@ -1708,9 +1709,8 @@ bool instrument_cover_goals( cmdline.isset("no-trivial-tests")); } - // check whether all existing goals have been covered - msg.status() << "Checking uncovered goals" << messaget::eom; - existing_goals.check_uncovered_goals(msg); + // check whether all existing goals match with instrumented goals + existing_goals.check_existing_goals(msg); if(cmdline.isset("cover-traces-must-terminate")) { diff --git a/src/goto-instrument/cover.h b/src/goto-instrument/cover.h index 4ad0b4992ab..a5a7a26ee2b 100644 --- a/src/goto-instrument/cover.h +++ b/src/goto-instrument/cover.h @@ -30,7 +30,7 @@ class coverage_goalst const irep_idt &mode); void add_goal(source_locationt goal); bool is_existing_goal(source_locationt source_loc); - void check_uncovered_goals(messaget &msg); + void check_existing_goals(messaget &msg); private: std::map existing_goals; From e641d76f64ebc69b2abfcb72737b26b933fdc2b7 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Wed, 16 Aug 2017 14:17:14 +0100 Subject: [PATCH 17/65] Use target source location for java code branches --- src/goto-programs/goto_convert.cpp | 3 +++ .../java_bytecode_convert_method.cpp | 15 ++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/goto-programs/goto_convert.cpp b/src/goto-programs/goto_convert.cpp index 710c90595cd..b13702d4d43 100644 --- a/src/goto-programs/goto_convert.cpp +++ b/src/goto-programs/goto_convert.cpp @@ -281,6 +281,9 @@ void goto_convertt::finish_guarded_gotos(goto_programt &dest) // Simplify: remove whatever code was generated for the condition // and attach the original guard to the goto instruction. gg.gotoiter->guard=gg.guard; + // inherit the source location (otherwise the guarded goto will + // have the source location of the else branch) + gg.gotoiter->source_location=gg.ifiter->source_location; // goto_programt doesn't provide an erase operation, // perhaps for a good reason, so let's be cautious and just // flatten the unneeded instructions into skips. diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index 89c5afc82ac..840b214049a 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -1779,7 +1779,8 @@ codet java_bytecode_convert_methodt::convert_instructions( code_branch.cond()=condition; code_branch.cond().add_source_location()=i_it->source_location; code_branch.then_case()=code_gotot(label(integer2string(number))); - code_branch.then_case().add_source_location()=i_it->source_location; + code_branch.then_case().add_source_location()= + address_map.at(integer2unsigned(number)).source->source_location; code_branch.add_source_location()=i_it->source_location; c=code_branch; @@ -1808,7 +1809,8 @@ codet java_bytecode_convert_methodt::convert_instructions( code_branch.cond().add_source_location()=i_it->source_location; code_branch.cond().add_source_location().set_function(method_id); code_branch.then_case()=code_gotot(label(integer2string(number))); - code_branch.then_case().add_source_location()=i_it->source_location; + code_branch.then_case().add_source_location()= + address_map.at(integer2unsigned(number)).source->source_location; code_branch.then_case().add_source_location().set_function(method_id); code_branch.add_source_location()=i_it->source_location; code_branch.add_source_location().set_function(method_id); @@ -1826,7 +1828,8 @@ codet java_bytecode_convert_methodt::convert_instructions( const exprt rhs(null_pointer_exprt(to_pointer_type(lhs.type()))); code_branch.cond()=binary_relation_exprt(lhs, ID_notequal, rhs); code_branch.then_case()=code_gotot(label(integer2string(number))); - code_branch.then_case().add_source_location()=i_it->source_location; + code_branch.then_case().add_source_location()= + address_map.at(integer2unsigned(number)).source->source_location; code_branch.add_source_location()=i_it->source_location; c=code_branch; @@ -1842,7 +1845,8 @@ codet java_bytecode_convert_methodt::convert_instructions( const exprt rhs(null_pointer_exprt(to_pointer_type(lhs.type()))); code_branch.cond()=binary_relation_exprt(lhs, ID_equal, rhs); code_branch.then_case()=code_gotot(label(integer2string(number))); - code_branch.then_case().add_source_location()=i_it->source_location; + code_branch.then_case().add_source_location()= + address_map.at(integer2unsigned(number)).source->source_location; code_branch.add_source_location()=i_it->source_location; c=code_branch; @@ -2348,7 +2352,8 @@ codet java_bytecode_convert_methodt::convert_instructions( bool ret=to_integer(to_constant_expr(*a_it), number); DATA_INVARIANT(!ret, "case label expected to be integer"); code_case.code()=code_gotot(label(integer2string(number))); - code_case.code().add_source_location()=i_it->source_location; + code_case.code().add_source_location()= + address_map.at(integer2unsigned(number)).source->source_location; if(a_it==i_it->args.begin()) code_case.set_default(); From d8fdbdb49f23103a396624de101a85cdc55211ec Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Tue, 29 Aug 2017 20:32:46 +0100 Subject: [PATCH 18/65] Regex match on files to be coverage-instrumented --- src/goto-instrument/cover.cpp | 19 +++++++++++++++---- src/goto-instrument/cover.h | 3 ++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index 8993445250a..bc416bbf24e 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -17,6 +17,7 @@ Date: May 2016 #include #include #include +#include #include #include @@ -1567,13 +1568,21 @@ void instrument_cover_goals( message_handlert &message_handler, coverage_goalst &goals, bool function_only, - bool ignore_trivial) + bool ignore_trivial, + const std::string &cover_include_pattern) { + std::smatch string_matcher; + std::regex regex_matcher(cover_include_pattern); + bool do_include_pattern_match=!cover_include_pattern.empty(); + Forall_goto_functions(f_it, goto_functions) { if(f_it->first==goto_functions.entry_point() || f_it->first==(CPROVER_PREFIX "initialize") || - f_it->second.is_hidden()) + f_it->second.is_hidden() || + (do_include_pattern_match && + !std::regex_match( + id2string(f_it->first), string_matcher, regex_matcher))) continue; instrument_cover_goals( @@ -1603,7 +1612,8 @@ void instrument_cover_goals( message_handler, goals, function_only, - false); + false, + ""); } bool instrument_cover_goals( @@ -1706,7 +1716,8 @@ bool instrument_cover_goals( message_handler, existing_goals, cmdline.isset("cover-function-only"), - cmdline.isset("no-trivial-tests")); + cmdline.isset("no-trivial-tests"), + cmdline.get_value("cover-include-pattern")); } // check whether all existing goals match with instrumented goals diff --git a/src/goto-instrument/cover.h b/src/goto-instrument/cover.h index a5a7a26ee2b..a7e0a960726 100644 --- a/src/goto-instrument/cover.h +++ b/src/goto-instrument/cover.h @@ -66,7 +66,8 @@ void instrument_cover_goals( message_handlert &message_handler, coverage_goalst &, bool function_only=false, - bool ignore_trivial=false); + bool ignore_trivial=false, + const std::string &cover_inclue_pattern=""); void instrument_cover_goals( const symbol_tablet &, From 45ca4082dde9979aa98eacb286c47be6a9e6babe Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Tue, 29 Aug 2017 20:38:25 +0100 Subject: [PATCH 19/65] Do not instrument java array built-in functions --- src/goto-instrument/cover.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index bc416bbf24e..e6127722c42 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -1582,7 +1582,9 @@ void instrument_cover_goals( f_it->second.is_hidden() || (do_include_pattern_match && !std::regex_match( - id2string(f_it->first), string_matcher, regex_matcher))) + id2string(f_it->first), string_matcher, regex_matcher)) || + // ignore Java array built-ins + has_prefix(id2string(f_it->first), "java::array")) continue; instrument_cover_goals( From 6fee43738d0a8ef1e932a099d7545db8fd646fab Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Thu, 31 Aug 2017 12:59:05 +0100 Subject: [PATCH 20/65] Debug info for unique bytecode instrumentation selection --- src/goto-instrument/cover.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index e6127722c42..e1d50d4ac17 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -133,8 +133,12 @@ class basic_blockst /// Select an instruction to be instrumented for each basic block such that /// the java bytecode indices for each basic block is unique /// \param goto_program The goto program - void select_unique_java_bytecode_indices(const goto_programt &goto_program) + /// \param message_handler The message handler + void select_unique_java_bytecode_indices( + const goto_programt &goto_program, + message_handlert &message_handler) { + messaget msg(message_handler); std::set blocks_seen; std::set bytecode_indices_seen; @@ -158,6 +162,12 @@ class basic_blockst block_info.source_location=it->source_location; update_covered_lines(block_info); blocks_seen.insert(block_nr); + msg.debug() << it->function + << " block " << (block_nr+1) + << ": location " << it->location_number + << ", bytecode-index " + << it->source_location.get_java_bytecode_index() + << " selected for instrumentation." << messaget::eom; } } } @@ -176,6 +186,14 @@ class basic_blockst // clash, reset to search for a new one block_info.representative_inst=goto_program.instructions.end(); block_info.source_location=source_locationt::nil(); + msg.debug() << it->function + << " block " << (block_nr+1) + << ", location " << it->location_number + << ": bytecode-index " + << it->source_location.get_java_bytecode_index() + << " already instrumented." + << " Searching for alternative instruction" + << " to instrument." << messaget::eom; } } } @@ -1232,7 +1250,8 @@ void instrument_cover_goals( const namespacet ns(symbol_table); basic_blockst basic_blocks(goto_program); - basic_blocks.select_unique_java_bytecode_indices(goto_program); + basic_blocks.select_unique_java_bytecode_indices( + goto_program, message_handler); basic_blocks.report_block_anomalies(goto_program, message_handler); const irep_idt coverage_criterion=as_string(criterion); From b85624e290036079afa2a1e71e06debebdd90238 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Thu, 31 Aug 2017 17:07:43 +0100 Subject: [PATCH 21/65] Add missing function ids to instrumented instructions --- src/goto-instrument/cover.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index e1d50d4ac17..f6ae495dc73 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -1338,6 +1338,7 @@ void instrument_cover_goals( ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); i_it->source_location.set_function(function); + i_it->function=function; i_it++; } } @@ -1365,6 +1366,7 @@ void instrument_cover_goals( t->source_location.set(ID_coverage_criterion, coverage_criterion); t->source_location.set_property_class(property_class); t->source_location.set_function(i_it->function); + t->function=i_it->function; } if(i_it->is_goto() && !i_it->guard.is_true() && cover_curr_function && @@ -1378,8 +1380,9 @@ void instrument_cover_goals( "function "+id2string(i_it->function)+" block "+b+" branch false"; exprt guard=i_it->guard; + const irep_idt function=i_it->function; source_locationt source_location=i_it->source_location; - source_location.set_function(i_it->function); + source_location.set_function(function); goto_program.insert_before_swap(i_it); i_it->make_assertion(not_exprt(guard)); @@ -1387,6 +1390,7 @@ void instrument_cover_goals( i_it->source_location.set_comment(true_comment); i_it->source_location.set(ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); + i_it->function=function; goto_program.insert_before_swap(i_it); i_it->make_assertion(guard); @@ -1394,6 +1398,7 @@ void instrument_cover_goals( i_it->source_location.set_comment(false_comment); i_it->source_location.set(ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); + i_it->function=function; i_it++; i_it++; @@ -1424,6 +1429,7 @@ void instrument_cover_goals( i_it->source_location.set(ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); i_it->source_location.set_function(function); + i_it->function=function; const std::string comment_f="condition `"+c_string+"' false"; goto_program.insert_before_swap(i_it); @@ -1433,6 +1439,7 @@ void instrument_cover_goals( i_it->source_location.set(ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); i_it->source_location.set_function(function); + i_it->function=function; } for(std::size_t i=0; isource_location.set(ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); i_it->source_location.set_function(function); + i_it->function=function; const std::string comment_f="decision `"+d_string+"' false"; goto_program.insert_before_swap(i_it); @@ -1473,6 +1481,7 @@ void instrument_cover_goals( i_it->source_location.set(ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); i_it->source_location.set_function(function); + i_it->function=function; } for(std::size_t i=0; isource_location.set(ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); i_it->source_location.set_function(function); + i_it->function=function; std::string comment_f=description+" `"+p_string+"' false"; goto_program.insert_before_swap(i_it); @@ -1535,6 +1545,7 @@ void instrument_cover_goals( i_it->source_location.set(ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); i_it->source_location.set_function(function); + i_it->function=function; } std::set controlling; @@ -1561,6 +1572,7 @@ void instrument_cover_goals( i_it->source_location.set(ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); i_it->source_location.set_function(function); + i_it->function=function; } for(std::size_t i=0; imake_assertion(false_exprt()); if_it->source_location.set_comment(comment); if_it->source_location.set_property_class("reachability_constraint"); - if_it->source_location.set_function(if_it->function); + if_it->source_location.set_function(goto_functions.entry_point()); + if_it->function=goto_functions.entry_point(); } goto_functions.update(); From bbc99d9bef3d933c5d703890e07cf4f90861b300 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Thu, 31 Aug 2017 17:08:31 +0100 Subject: [PATCH 22/65] Remove redundant function name from goal descriptions --- src/cbmc/bmc_cover.cpp | 3 ++- src/goto-instrument/cover.cpp | 12 ++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/cbmc/bmc_cover.cpp b/src/cbmc/bmc_cover.cpp index 8485988b4a2..50695562bb0 100644 --- a/src/cbmc/bmc_cover.cpp +++ b/src/cbmc/bmc_cover.cpp @@ -161,7 +161,8 @@ void bmc_covert::satisfying_assignment() if(solver.l_get(cond).is_true()) { - status() << "Covered " << g.description << messaget::eom; + status() << "Covered function " << g.source_location.get_function() + << " " << g.description << messaget::eom; g.satisfied=true; test.covered_goals.push_back(goal_pair.first); break; diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index f6ae495dc73..258b790a887 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -1327,8 +1327,7 @@ void instrument_cover_goals( !source_location.is_built_in() && cover_curr_function) { - std::string comment= - "function "+id2string(i_it->function)+" block "+b; + std::string comment="block "+b; const irep_idt function=i_it->function; goto_program.insert_before_swap(i_it); i_it->make_assertion(false_exprt()); @@ -1354,8 +1353,7 @@ void instrument_cover_goals( { // we want branch coverage to imply 'entry point of function' // coverage - std::string comment= - "function "+id2string(i_it->function)+" entry point"; + std::string comment="entry point"; source_locationt source_location=i_it->source_location; @@ -1374,10 +1372,8 @@ void instrument_cover_goals( { std::string b= std::to_string(basic_blocks.block_of(i_it)+1); // start with 1 - std::string true_comment= - "function "+id2string(i_it->function)+" block "+b+" branch true"; - std::string false_comment= - "function "+id2string(i_it->function)+" block "+b+" branch false"; + std::string true_comment="block "+b+" branch true"; + std::string false_comment="block "+b+" branch false"; exprt guard=i_it->guard; const irep_idt function=i_it->function; From e54bc4765e79734b311272febcdebbc7b96711e2 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Thu, 31 Aug 2017 16:32:16 +0100 Subject: [PATCH 23/65] Tests for unique java bytecode instrumentation selection --- regression/cbmc-cover/unique-bytecode1/Test.class | Bin 0 -> 301 bytes regression/cbmc-cover/unique-bytecode1/Test.java | 6 ++++++ regression/cbmc-cover/unique-bytecode1/test.desc | 7 +++++++ regression/cbmc-cover/unique-bytecode2/Test.class | Bin 0 -> 262 bytes regression/cbmc-cover/unique-bytecode2/Test.java | 3 +++ regression/cbmc-cover/unique-bytecode2/test.desc | 8 ++++++++ regression/cbmc-cover/unique-bytecode3/Test.class | Bin 0 -> 292 bytes regression/cbmc-cover/unique-bytecode3/Test.java | 4 ++++ regression/cbmc-cover/unique-bytecode3/test.desc | 9 +++++++++ 9 files changed, 37 insertions(+) create mode 100644 regression/cbmc-cover/unique-bytecode1/Test.class create mode 100644 regression/cbmc-cover/unique-bytecode1/Test.java create mode 100644 regression/cbmc-cover/unique-bytecode1/test.desc create mode 100644 regression/cbmc-cover/unique-bytecode2/Test.class create mode 100644 regression/cbmc-cover/unique-bytecode2/Test.java create mode 100644 regression/cbmc-cover/unique-bytecode2/test.desc create mode 100644 regression/cbmc-cover/unique-bytecode3/Test.class create mode 100644 regression/cbmc-cover/unique-bytecode3/Test.java create mode 100644 regression/cbmc-cover/unique-bytecode3/test.desc diff --git a/regression/cbmc-cover/unique-bytecode1/Test.class b/regression/cbmc-cover/unique-bytecode1/Test.class new file mode 100644 index 0000000000000000000000000000000000000000..8fa774304fd6c9a88db55a668f645bad89ff2495 GIT binary patch literal 301 zcmYL_y-ve06ot=q(u9QmO)LnBu`tku1yQjeF%=k6u`oHos$5zZ1(zq_Nm!VfkQjIX zo(LfX90w#UUEk~D^Ic#0?d#uZ*BKw$7Zb z7Nw~tx|~yq7uq_(#^7>1(|39}*KRs2d~MzIFo2!H>+1Sc-~9RWV!5g-b7BLWP0X#| z3tSs9TI?1CLI1zic{wwc$2JtF3rjKR1xIAH#VpLN-Dk)X3qi^~X+%DNHO8;?fM|fb l(P%SyKz1+k`28Lj)i8N;%P(N_oN5O32_+vq2-X{0`v-w@HDCY$ literal 0 HcmV?d00001 diff --git a/regression/cbmc-cover/unique-bytecode1/Test.java b/regression/cbmc-cover/unique-bytecode1/Test.java new file mode 100644 index 00000000000..8ffd0be984f --- /dev/null +++ b/regression/cbmc-cover/unique-bytecode1/Test.java @@ -0,0 +1,6 @@ +class Test { + public static void main(String[] args) { + for (int i=0; i<3; i++) { + } + } +} diff --git a/regression/cbmc-cover/unique-bytecode1/test.desc b/regression/cbmc-cover/unique-bytecode1/test.desc new file mode 100644 index 00000000000..1ac356b5204 --- /dev/null +++ b/regression/cbmc-cover/unique-bytecode1/test.desc @@ -0,0 +1,7 @@ +CORE +Test.class +--cover location --show-properties --verbosity 10 +^EXIT=0$ +^SIGNAL=0$ +-- +^Ignoring block .* java::Test\.main diff --git a/regression/cbmc-cover/unique-bytecode2/Test.class b/regression/cbmc-cover/unique-bytecode2/Test.class new file mode 100644 index 0000000000000000000000000000000000000000..c949f8d85a47b363eb9074cd1767f0b7ef1e7878 GIT binary patch literal 262 zcmZ9GyAA:\(\)V block 2, location 4: bytecode-index 1 already instrumented +^Ignoring block 2 location .* file Test\.java line 2 function java::Test\.:\(\)V bytecode-index .* \(bytecode-index already instrumented\) +-- diff --git a/regression/cbmc-cover/unique-bytecode3/Test.class b/regression/cbmc-cover/unique-bytecode3/Test.class new file mode 100644 index 0000000000000000000000000000000000000000..7cd485fe136508e66742524c696d267ac2146d40 GIT binary patch literal 292 zcmYLD&1%A65S%stX{xC|N5M-$d#D$W(u*JnQV)vvBz{OFji9l#k0l<29{K=%DCvAb z^su|Lv$MPNclr4RFhI+Ph0ueEC!OjJ8V;HQ`C?2M-vWD>=4tUJFuJ{^z#MH?N>H1o zxq3f*#A>&Q;*5+tOtP!epKlMlM2%C;dkeKMUN_Na6u^TYz=jjRg~MBVBnb7epGEn) zKZ`diDbS%Aiw-N)QBLIQjgo=B0>J~jHmk5&FK5V+KoBt7B}q$oyh)!+j?2ag74rn+ QF8BFI|1x1vR4sAsA6o$@B>(^b literal 0 HcmV?d00001 diff --git a/regression/cbmc-cover/unique-bytecode3/Test.java b/regression/cbmc-cover/unique-bytecode3/Test.java new file mode 100644 index 00000000000..857bb865a7d --- /dev/null +++ b/regression/cbmc-cover/unique-bytecode3/Test.java @@ -0,0 +1,4 @@ +class Test { + static int x = 0; + static int y = 1; +} diff --git a/regression/cbmc-cover/unique-bytecode3/test.desc b/regression/cbmc-cover/unique-bytecode3/test.desc new file mode 100644 index 00000000000..ced64111931 --- /dev/null +++ b/regression/cbmc-cover/unique-bytecode3/test.desc @@ -0,0 +1,9 @@ +CORE +Test.class +--cover location --show-properties --verbosity 10 +^EXIT=0$ +^SIGNAL=0$ +^java::Test\.:\(\)V block 2, location 4: bytecode-index 1 already instrumented +^java::Test\.:\(\)V block 2: location 5, bytecode-index 3 selected for instrumentation +-- +^Ignoring block 2 location .* file Test\.java line 3 function java::Test\.:\(\)V bytecode-index .* \(bytecode-index already instrumented\) From b6ef688a41bd08b6096ddff80d3d9070ca5fb99a Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Thu, 31 Aug 2017 19:16:19 +0100 Subject: [PATCH 24/65] Fix and run cbmc-cover tests --- regression/Makefile | 1 + regression/cbmc-cover/assertion1/main.c | 1 + regression/cbmc-cover/assertion1/test.desc | 4 ++-- regression/cbmc-cover/branch1/test.desc | 14 +++++++------- regression/cbmc-cover/branch2/test.desc | 6 +++--- regression/cbmc-cover/branch3/main.c | 1 - regression/cbmc-cover/branch3/test.desc | 2 +- regression/cbmc-cover/built-ins2/test.desc | 2 +- regression/cbmc-cover/cover1/main.c | 1 + regression/cbmc-cover/inlining1/test.desc | 8 ++++---- regression/cbmc-cover/location11/main.c | 2 -- regression/cbmc-cover/location11/test.desc | 22 ++++++++++------------ regression/cbmc-cover/location12/main.c | 2 -- regression/cbmc-cover/location12/test.desc | 13 ++++++------- regression/cbmc-cover/location13/main.c | 2 -- regression/cbmc-cover/location13/test.desc | 16 ++++++++-------- regression/cbmc-cover/location14/main.c | 6 +++--- regression/cbmc-cover/location14/test.desc | 10 ++++------ regression/cbmc-cover/location15/main.c | 1 - regression/cbmc-cover/location15/test.desc | 16 ++++++---------- regression/cbmc-cover/location16/main.c | 5 ++--- regression/cbmc-cover/location16/test.desc | 18 ++++++++---------- 22 files changed, 68 insertions(+), 85 deletions(-) diff --git a/regression/Makefile b/regression/Makefile index c69d85febc2..3315fb90a6d 100644 --- a/regression/Makefile +++ b/regression/Makefile @@ -3,6 +3,7 @@ DIRS = ansi-c \ cpp \ cbmc-java \ cbmc-java-inheritance \ + cbmc-cover \ goto-analyzer \ goto-diff \ goto-instrument \ diff --git a/regression/cbmc-cover/assertion1/main.c b/regression/cbmc-cover/assertion1/main.c index ca0f7d96dd4..62bf3c24d94 100644 --- a/regression/cbmc-cover/assertion1/main.c +++ b/regression/cbmc-cover/assertion1/main.c @@ -5,6 +5,7 @@ int main() __CPROVER_input("input1", input1); __CPROVER_input("input2", input2); + // assert() is platform-dependent and changes set of coverage goals __CPROVER_assert(!input1, ""); if(input1) diff --git a/regression/cbmc-cover/assertion1/test.desc b/regression/cbmc-cover/assertion1/test.desc index 50ea8515480..0463c5e110c 100644 --- a/regression/cbmc-cover/assertion1/test.desc +++ b/regression/cbmc-cover/assertion1/test.desc @@ -3,7 +3,7 @@ main.c --cover assertion ^EXIT=0$ ^SIGNAL=0$ -^\[main.coverage.1\] file main.c line 8 function main: SATISFIED$ -^\[main.coverage.2\] file main.c line 12 function main: SATISFIED$ +^\[main.coverage.1\] file main.c line 9 function main: SATISFIED$ +^\[main.coverage.2\] file main.c line 13 function main: SATISFIED$ -- ^warning: ignoring diff --git a/regression/cbmc-cover/branch1/test.desc b/regression/cbmc-cover/branch1/test.desc index 04c09bbb7ab..d1a1dd77d56 100644 --- a/regression/cbmc-cover/branch1/test.desc +++ b/regression/cbmc-cover/branch1/test.desc @@ -3,12 +3,12 @@ main.c --cover branch ^EXIT=0$ ^SIGNAL=0$ -^\[main.coverage.1\] file main.c line 3 function main function main entry point: SATISFIED$ -^\[main.coverage.2\] file main.c line 8 function main function main block 1 branch false: SATISFIED$ -^\[main.coverage.3\] file main.c line 8 function main function main block 1 branch true: SATISFIED$ -^\[main.coverage.4\] file main.c line 10 function main function main block 2 branch false: FAILED$ -^\[main.coverage.5\] file main.c line 10 function main function main block 2 branch true: SATISFIED$ -^\[main.coverage.6\] file main.c line 16 function main function main block 4 branch false: SATISFIED$ -^\[main.coverage.7\] file main.c line 16 function main function main block 4 branch true: SATISFIED$ +^\[main.coverage.1\] file main.c line 3 function main entry point: SATISFIED$ +^\[main.coverage.2\] file main.c line 8 function main block 1 branch false: SATISFIED$ +^\[main.coverage.3\] file main.c line 8 function main block 1 branch true: SATISFIED$ +^\[main.coverage.4\] file main.c line 10 function main block 2 branch false: FAILED$ +^\[main.coverage.5\] file main.c line 10 function main block 2 branch true: SATISFIED$ +^\[main.coverage.6\] file main.c line 16 function main block 4 branch false: SATISFIED$ +^\[main.coverage.7\] file main.c line 16 function main block 4 branch true: SATISFIED$ -- ^warning: ignoring diff --git a/regression/cbmc-cover/branch2/test.desc b/regression/cbmc-cover/branch2/test.desc index 3dd40dec828..7dd6fad87e6 100644 --- a/regression/cbmc-cover/branch2/test.desc +++ b/regression/cbmc-cover/branch2/test.desc @@ -3,8 +3,8 @@ main.c --cover branch --unwind 2 ^EXIT=0$ ^SIGNAL=0$ -^\[main.coverage.1\] file main.c line 5 function main function main entry point: SATISFIED$ -^\[main.coverage.2\] file main.c line 6 function main function main block .* branch false: SATISFIED$ -^\[main.coverage.3\] file main.c line 6 function main function main block .* branch true: SATISFIED$ +^\[main.coverage.1\] file main.c line 5 function main entry point: SATISFIED$ +^\[main.coverage.2\] file main.c line 6 function main block .* branch false: SATISFIED$ +^\[main.coverage.3\] file main.c line 6 function main block .* branch true: SATISFIED$ -- ^warning: ignoring diff --git a/regression/cbmc-cover/branch3/main.c b/regression/cbmc-cover/branch3/main.c index c4446281161..de8af7752f0 100644 --- a/regression/cbmc-cover/branch3/main.c +++ b/regression/cbmc-cover/branch3/main.c @@ -1,4 +1,3 @@ -#include #include int main() diff --git a/regression/cbmc-cover/branch3/test.desc b/regression/cbmc-cover/branch3/test.desc index 5d9bce60ebe..057b9d56a31 100644 --- a/regression/cbmc-cover/branch3/test.desc +++ b/regression/cbmc-cover/branch3/test.desc @@ -3,6 +3,6 @@ main.c --cover branch --unwind 6 ^EXIT=0$ ^SIGNAL=0$ -^\*\* 23 of 23 covered \(100.0%\)$ +^\*\* .* of .* covered \(100.0%\)$ -- ^warning: ignoring diff --git a/regression/cbmc-cover/built-ins2/test.desc b/regression/cbmc-cover/built-ins2/test.desc index bd3fc9fdaa3..0f2ff4dd72e 100644 --- a/regression/cbmc-cover/built-ins2/test.desc +++ b/regression/cbmc-cover/built-ins2/test.desc @@ -3,7 +3,7 @@ main.c --cover location --unwind 10 ^EXIT=0$ ^SIGNAL=0$ -^\*\* 4 of 4 covered +^\*\* .* of .* covered \(100.0%\) -- ^warning: ignoring ^\[.* - int myfunc(int x, int y) { int z = x + y; diff --git a/regression/cbmc-cover/location11/test.desc b/regression/cbmc-cover/location11/test.desc index 498a0e96670..4f3ab61bc51 100644 --- a/regression/cbmc-cover/location11/test.desc +++ b/regression/cbmc-cover/location11/test.desc @@ -3,17 +3,15 @@ main.c --cover location ^EXIT=0$ ^SIGNAL=0$ -^\[main.coverage.1\] file main.c line 11 function main block 1: SATISFIED$ -^\[main.coverage.2\] file main.c line 13 function main block 2: FAILED$ -^\[main.coverage.3\] file main.c line 13 function main block 3: FAILED$ -^\[main.coverage.4\] file main.c line 15 function main block 4: SATISFIED$ -^\[main.coverage.5\] file main.c line 17 function main block 5: SATISFIED$ -^\[main.coverage.6\] file main.c line 18 function main block 6: SATISFIED$ -^\[main.coverage.7\] file main.c line 20 function main block 7: FAILED$ -^\[main.coverage.8\] file main.c line 22 function main block 8: SATISFIED$ -^\[main.coverage.9\] file main.c line 23 function main block 9: SATISFIED$ -^\[myfunc.coverage.1\] file main.c line 5 function myfunc block 1: FAILED$ -^\[myfunc.coverage.2\] file main.c line 7 function myfunc block 2: FAILED$ -^\*\* 6 of 11 covered \(54.5%\) +^\[main.coverage.1\] file main.c line 9 function main block 1: SATISFIED$ +^\[main.coverage.2\] file main.c line 11 function main block 2: FAILED$ +^\[main.coverage.3\] file main.c line 11 function main block 3: FAILED$ +^\[main.coverage.4\] file main.c line 13 function main block 4: SATISFIED$ +^\[main.coverage.5\] file main.c line 15 function main block 5: SATISFIED$ +^\[main.coverage.6\] file main.c line 16 function main block 6: SATISFIED$ +^\[main.coverage.7\] file main.c line 18 function main block 7: FAILED$ +^\[main.coverage.8\] file main.c line 20 function main block 8: SATISFIED$ +^\[myfunc.coverage.1\] file main.c line 3 function myfunc block 1: FAILED$ +^\*\* 5 of 9 covered \(55.6%\) -- ^warning: ignoring diff --git a/regression/cbmc-cover/location12/main.c b/regression/cbmc-cover/location12/main.c index 416664abab4..89fc1115803 100644 --- a/regression/cbmc-cover/location12/main.c +++ b/regression/cbmc-cover/location12/main.c @@ -1,5 +1,3 @@ -#include - int foo (int iX, int iY) { return iX + iY; diff --git a/regression/cbmc-cover/location12/test.desc b/regression/cbmc-cover/location12/test.desc index 8636a3ad831..1b3da668761 100644 --- a/regression/cbmc-cover/location12/test.desc +++ b/regression/cbmc-cover/location12/test.desc @@ -3,12 +3,11 @@ main.c --cover location ^EXIT=0$ ^SIGNAL=0$ -^\[main.coverage.1\] file main.c line 11 function main block 1: SATISFIED$ -^\[main.coverage.2\] file main.c line 12 function main block 2: SATISFIED$ -^\[foo.coverage.1\] file main.c line 5 function foo block 1: SATISFIED$ -^\[foo.coverage.2\] file main.c line 6 function foo block 2: FAILED$ -^\[foo.coverage.3\] file main.c line 7 function foo block 3: FAILED$ -^\[foo.coverage.4\] file main.c line 7 function foo block 4: SATISFIED$ -^\*\* 4 of 6 covered \(66.7%\) +^\[main.coverage.1\] file main.c line 9 function main block 1: SATISFIED$ +^\[main.coverage.2\] file main.c line 10 function main block 2: SATISFIED$ +^\[foo.coverage.1\] file main.c line 3 function foo block 1: SATISFIED$ +^\[foo.coverage.2\] file main.c line 4 function foo block 2: FAILED$ +^\[foo.coverage.3\] file main.c line 5 function foo block 3: SATISFIED$ +^\*\* 4 of 5 covered \(80.0%\) -- ^warning: ignoring diff --git a/regression/cbmc-cover/location13/main.c b/regression/cbmc-cover/location13/main.c index d589fb4aeac..c395eeaa4e7 100644 --- a/regression/cbmc-cover/location13/main.c +++ b/regression/cbmc-cover/location13/main.c @@ -1,5 +1,3 @@ -#include - int myfunc(int a, int b) { return a+b; diff --git a/regression/cbmc-cover/location13/test.desc b/regression/cbmc-cover/location13/test.desc index 2577349c99d..98c255d8bd1 100644 --- a/regression/cbmc-cover/location13/test.desc +++ b/regression/cbmc-cover/location13/test.desc @@ -3,13 +3,13 @@ main.c --cover location ^EXIT=0$ ^SIGNAL=0$ -^\[main.coverage.1\] file main.c line 16 function main block 1: SATISFIED$ -^\[main.coverage.2\] file main.c line 17 function main block 2: SATISFIED$ -^\[myfunc.coverage.1\] file main.c line 5 function myfunc block 1: FAILED$ -^\[myfunc.coverage.2\] file main.c line 6 function myfunc block 2: FAILED$ -^\[foo.coverage.1\] file main.c line 10 function foo block 1: SATISFIED$ -^\[foo.coverage.2\] file main.c line 11 function foo block 2: FAILED$ -^\[foo.coverage.3\] file main.c line 12 function foo block 3: FAILED$ -^\*\* 4 of 8 covered \(50.0%\) +^\[main.coverage.1\] file main.c line 14 function main block 1: SATISFIED$ +^\[main.coverage.2\] file main.c line 15 function main block 2: SATISFIED$ +^\[myfunc.coverage.1\] file main.c line 3 function myfunc block 1: FAILED$ +^\[foo.coverage.1\] file main.c line 8 function foo block 1: SATISFIED$ +^\[foo.coverage.2\] file main.c line 9 function foo block 2: FAILED$ +^\[foo.coverage.3\] file main.c line 10 function foo block 3: FAILED$ +^\[foo.coverage.4\] file main.c line 10 function foo block 4: SATISFIED$ +^\*\* 4 of 7 covered \(57.1%\) -- ^warning: ignoring diff --git a/regression/cbmc-cover/location14/main.c b/regression/cbmc-cover/location14/main.c index 5fbf0c498e7..04ea7490acb 100644 --- a/regression/cbmc-cover/location14/main.c +++ b/regression/cbmc-cover/location14/main.c @@ -1,5 +1,3 @@ -#include - int foo (int iX, int iY) { return iX + iY; @@ -9,5 +7,7 @@ int main(void) { int iN = 2 + 1; if (iN == 4) - assert(foo(5,3)==8); + + // assert() is platform-dependent and changes set of coverage goals + __CPROVER_assert(foo(5,3)==8, ""); } diff --git a/regression/cbmc-cover/location14/test.desc b/regression/cbmc-cover/location14/test.desc index 2683a0399dd..6fb93526b39 100644 --- a/regression/cbmc-cover/location14/test.desc +++ b/regression/cbmc-cover/location14/test.desc @@ -3,13 +3,11 @@ main.c --cover location ^EXIT=0$ ^SIGNAL=0$ -^\[main.coverage.1\] file main.c line 10 function main block 1: SATISFIED$ +^\[main.coverage.1\] file main.c line 8 function main block 1: SATISFIED$ ^\[main.coverage.2\] file main.c line 12 function main block 2: FAILED$ ^\[main.coverage.3\] file main.c line 12 function main block 3: FAILED$ -^\[main.coverage.4\] file main.c line 12 function main block 4: FAILED$ -^\[main.coverage.5\] file main.c line 13 function main block 6: SATISFIED$ -^\[foo.coverage.1\] file main.c line 5 function foo block 1: FAILED$ -^\[foo.coverage.2\] file main.c line 6 function foo block 2: FAILED$ -^\*\* 2 of 7 covered \(28.6%\) +^\[main.coverage.4\] file main.c line 13 function main block 4: SATISFIED$ +^\[foo.coverage.1\] file main.c line 3 function foo block 1: FAILED$ +^\*\* 2 of 5 covered \(40.0%\) -- ^warning: ignoring diff --git a/regression/cbmc-cover/location15/main.c b/regression/cbmc-cover/location15/main.c index fb872b31250..3f07259a77e 100644 --- a/regression/cbmc-cover/location15/main.c +++ b/regression/cbmc-cover/location15/main.c @@ -1,4 +1,3 @@ -#include #include int foo (int iX, int iY) diff --git a/regression/cbmc-cover/location15/test.desc b/regression/cbmc-cover/location15/test.desc index 9598d7d256a..6bb9591efe9 100644 --- a/regression/cbmc-cover/location15/test.desc +++ b/regression/cbmc-cover/location15/test.desc @@ -1,17 +1,13 @@ -KNOWNBUG +THOROUGH main.c --cover location ^EXIT=0$ ^SIGNAL=0$ -^\[main.coverage.1\] file main.c line 11 function main block 1: SATISFIED$ +^\[main.coverage.1\] file main.c line 10 function main block 1: SATISFIED$ ^\[main.coverage.2\] file main.c line 11 function main block 2: SATISFIED$ -^\[main.coverage.3\] file main.c line 14 function main block 3: FAILED$ -^\[main.coverage.4\] file main.c line 15 function main block 4: FAILED$ -^\[main.coverage.5\] file main.c line 15 function main block 5: FAILED$ -^\[main.coverage.6\] file main.c line 16 function main block 6: FAILED$ -^\[main.coverage.7\] file main.c line 17 function main block 7: SATISFIED$ -^\[foo.coverage.1\] file main.c line 6 function foo block 1: FAILED$ -^\[foo.coverage.2\] file main.c line 7 function foo block 2: FAILED$ -^\*\* 3 of 9 covered \(33.3%\) +^\[main.coverage.3\] file main.c line 13 function main block 3: FAILED$ +^\[main.coverage.4\] file main.c line 16 function main block 4: SATISFIED$ +^\[foo.coverage.1\] file main.c line 5 function foo block 1: FAILED$ +^\*\* 3 of 5 covered \(60.0%\) -- ^warning: ignoring diff --git a/regression/cbmc-cover/location16/main.c b/regression/cbmc-cover/location16/main.c index 6334e4c8e88..bd57c91fc8d 100644 --- a/regression/cbmc-cover/location16/main.c +++ b/regression/cbmc-cover/location16/main.c @@ -1,5 +1,3 @@ -#include - int func(int a) { int b = a*2; @@ -10,7 +8,8 @@ int func(int a) b += 10; } - assert(0); + // assert() is platform-dependent and changes set of coverage goals + __CPROVER_assert(0, ""); return b; } diff --git a/regression/cbmc-cover/location16/test.desc b/regression/cbmc-cover/location16/test.desc index acb02daaf1a..ea8414e88b7 100644 --- a/regression/cbmc-cover/location16/test.desc +++ b/regression/cbmc-cover/location16/test.desc @@ -3,15 +3,13 @@ main.c --cover location ^EXIT=0$ ^SIGNAL=0$ -^\[main.coverage.1\] file main.c line 20 function main block 1: SATISFIED$ -^\[main.coverage.2\] file main.c line 21 function main block 2: SATISFIED$ -^\[func.coverage.1\] file main.c line 5 function func block 1: SATISFIED$ -^\[func.coverage.2\] file main.c line 8 function func block 2: FAILED$ -^\[func.coverage.3\] file main.c line 10 function func block 3: FAILED$ -^\[func.coverage.4\] file main.c line 13 function func block 4: FAILED$ -^\[func.coverage.5\] file main.c line 13 function func block 5: FAILED$ -^\[func.coverage.6\] file main.c line 15 function func block 6: FAILED$ -^\[func.coverage.7\] file main.c line 16 function func block 7: SATISFIED$ -^\*\* 4 of 9 covered \(44.4%\) +^\[main.coverage.1\] file main.c line 19 function main block 1: SATISFIED$ +^\[main.coverage.2\] file main.c line 20 function main block 2: SATISFIED$ +^\[func.coverage.1\] file main.c line 3 function func block 1: SATISFIED$ +^\[func.coverage.2\] file main.c line 6 function func block 2: FAILED$ +^\[func.coverage.3\] file main.c line 8 function func block 3: FAILED$ +^\[func.coverage.4\] file main.c line 12 function func block 4: FAILED$ +^\[func.coverage.5\] file main.c line 15 function func block 5: SATISFIED$ +^\*\* 4 of 7 covered \(57.1%\) -- ^warning: ignoring From 4c94e7c8a0ef7c6ccd6531ae05136b2561b00737 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Wed, 12 Apr 2017 10:30:59 +0100 Subject: [PATCH 25/65] goto-instrument model-argc-argv: place environment in __CPROVER__start argc/argv modelling was previously placed in __CPROVER_initialize. To align with Java environment modelling, this is now moved to __CPROVER__start, just before the call to main(). --- src/goto-instrument/model_argc_argv.cpp | 89 +++++++++++++++---------- 1 file changed, 52 insertions(+), 37 deletions(-) diff --git a/src/goto-instrument/model_argc_argv.cpp b/src/goto-instrument/model_argc_argv.cpp index 319acf8674c..96cad896e6f 100644 --- a/src/goto-instrument/model_argc_argv.cpp +++ b/src/goto-instrument/model_argc_argv.cpp @@ -29,6 +29,12 @@ Date: April 2016 #include #include +/// Set up argv with up to max_argc pointers into an array of 4096 bytes. +/// \param symbol_table: Input program's symbol table +/// \param goto_functions: Input program's intermediate representation +/// \param max_argc: User-specified maximum number of arguments to be modelled +/// \param message_handler: message logging +/// \return True, if and only if modelling succeeded bool model_argc_argv( symbol_tablet &symbol_table, goto_functionst &goto_functions, @@ -38,37 +44,23 @@ bool model_argc_argv( messaget message(message_handler); const namespacet ns(symbol_table); - const symbolt *init_symbol=nullptr; - if(ns.lookup(CPROVER_PREFIX "initialize", init_symbol)) + if(!symbol_table.has_symbol(goto_functions.entry_point())) { message.error() << "Linking not done, missing " - << CPROVER_PREFIX "initialize" << messaget::eom; + << goto_functions.entry_point() << messaget::eom; return true; } - if(init_symbol->mode!=ID_C) + const symbolt &main_symbol= + ns.lookup(config.main.empty()?ID_main:config.main); + + if(main_symbol.mode!=ID_C) { message.error() << "argc/argv modelling is C specific" << messaget::eom; return true; } - goto_functionst::function_mapt::iterator init_entry= - goto_functions.function_map.find(CPROVER_PREFIX "initialize"); - assert( - init_entry!=goto_functions.function_map.end() && - init_entry->second.body_available()); - - goto_programt &init=init_entry->second.body; - goto_programt::targett init_end=init.instructions.end(); - --init_end; - assert(init_end->is_end_function()); - assert(init_end!=init.instructions.begin()); - --init_end; - - const symbolt &main_symbol= - ns.lookup(config.main.empty()?ID_main:config.main); - const code_typet::parameterst ¶meters= to_code_type(main_symbol.type).parameters(); if(parameters.size()!=2 && @@ -86,13 +78,14 @@ bool model_argc_argv( std::ostringstream oss; oss << "int ARGC;\n" << "char *ARGV[1];\n" - << "void " CPROVER_PREFIX "initialize()\n" + << "void " << goto_functions.entry_point() << "()\n" << "{\n" << " unsigned next=0u;\n" << " " CPROVER_PREFIX "assume(ARGC>=1);\n" << " " CPROVER_PREFIX "assume(ARGC<=" << max_argc << ");\n" - << " " CPROVER_PREFIX "thread_local static char arg_string[4096];\n" - << " for(unsigned i=0u; i"); - goto_programt tmp; + goto_programt init_instructions; exprt value=nil_exprt(); - // locate the body of the newly built initialize function as well - // as any additional declarations we might need; the body will then - // be converted and appended to the existing initialize function + // locate the body of the newly built start function as well as any + // additional declarations we might need; the body will then be + // converted and inserted into the start function forall_symbols(it, tmp_symbol_table.symbols) { // add __CPROVER_assume if necessary (it might exist already) - if(it->first==CPROVER_PREFIX "assume") + if(it->first==CPROVER_PREFIX "assume" || + it->first==CPROVER_PREFIX "input") symbol_table.add(it->second); - else if(it->first==CPROVER_PREFIX "initialize") + else if(it->first==goto_functions.entry_point()) { value=it->second.value; @@ -134,7 +128,7 @@ bool model_argc_argv( replace(value); } else if(has_prefix(id2string(it->first), - CPROVER_PREFIX "initialize::") && + id2string(goto_functions.entry_point())+"::") && symbol_table.add(it->second)) UNREACHABLE; } @@ -143,20 +137,41 @@ bool model_argc_argv( goto_convert( to_code(value), symbol_table, - tmp, + init_instructions, message_handler); - Forall_goto_program_instructions(it, tmp) + Forall_goto_program_instructions(it, init_instructions) { it->source_location.set_file(""); - it->function=CPROVER_PREFIX "initialize"; + it->function=goto_functions.entry_point(); } - init.insert_before_swap(init_end, tmp); + + goto_functionst::function_mapt::iterator start_entry= + goto_functions.function_map.find(goto_functions.entry_point()); + assert( + start_entry!=goto_functions.function_map.end() && + start_entry->second.body_available()); + + goto_programt &start=start_entry->second.body; + goto_programt::targett main_call=start.instructions.begin(); + for(goto_programt::targett end=start.instructions.end(); + main_call!=end; + ++main_call) + if(main_call->is_function_call()) + { + const exprt &func= + to_code_function_call(main_call->code).function(); + if(func.id()==ID_symbol && + to_symbol_expr(func).get_identifier()==main_symbol.name) + break; + } + + assert(main_call!=start.instructions.end()); + start.insert_before_swap(main_call, init_instructions); // update counters etc. - remove_skip(init); - init.compute_loop_numbers(); + remove_skip(start); + start.compute_loop_numbers(); goto_functions.update(); return false; } - From e8e16770a5a17ef4a701500b45a22fb6503df1bf Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Wed, 12 Apr 2017 10:35:54 +0100 Subject: [PATCH 26/65] dump-c: output a generated environment via --harness dump-c previously would not print __CPROVER__start code as this is deemed tool-internal. With increasing support for test-harness construction, the harness code may be of interest to users, who may wish to tweak and use re-use it. --- CHANGELOG | 1 + regression/goto-instrument/harness1/main.c | 8 ++ regression/goto-instrument/harness1/test.desc | 8 ++ src/clobber/clobber_parse_options.cpp | 2 +- src/goto-instrument/dump_c.cpp | 100 +++++++++++++++++- src/goto-instrument/dump_c.h | 2 + src/goto-instrument/dump_c_class.h | 6 +- .../goto_instrument_parse_options.cpp | 17 ++- .../goto_instrument_parse_options.h | 1 + 9 files changed, 136 insertions(+), 9 deletions(-) create mode 100644 regression/goto-instrument/harness1/main.c create mode 100644 regression/goto-instrument/harness1/test.desc diff --git a/CHANGELOG b/CHANGELOG index e497b1cadc2..35df4513382 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,7 @@ * GOTO-INSTRUMENT: New option --remove-function-body * GOTO-INSTRUMENT: New option --use-all-headers, changed --use-system-headers to --no-system-headers +* GOTO-INSTRUMENT: dump-c can output the generated environment via --harness 5.7 diff --git a/regression/goto-instrument/harness1/main.c b/regression/goto-instrument/harness1/main.c new file mode 100644 index 00000000000..0840c4d8365 --- /dev/null +++ b/regression/goto-instrument/harness1/main.c @@ -0,0 +1,8 @@ +#include + +int main(int argc, char* argv[]) +{ + assert(argc<2 || argv[1]!=0); + + return 0; +} diff --git a/regression/goto-instrument/harness1/test.desc b/regression/goto-instrument/harness1/test.desc new file mode 100644 index 00000000000..307044e9ed4 --- /dev/null +++ b/regression/goto-instrument/harness1/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--model-argc-argv 3 --dump-c --harness +^EXIT=0$ +^SIGNAL=0$ +Adding up to 3 command line arguments +-- +^warning: ignoring diff --git a/src/clobber/clobber_parse_options.cpp b/src/clobber/clobber_parse_options.cpp index 66fc8fb6896..b0859362be9 100644 --- a/src/clobber/clobber_parse_options.cpp +++ b/src/clobber/clobber_parse_options.cpp @@ -147,7 +147,7 @@ int clobber_parse_optionst::doit() if(!out) throw std::string("failed to create file simulator.c"); - dump_c(goto_functions, true, false, ns, out); + dump_c(goto_functions, true, false, false, ns, out); status() << "instrumentation complete; compile and execute simulator.c" << eom; diff --git a/src/goto-instrument/dump_c.cpp b/src/goto-instrument/dump_c.cpp index f3c156ac8ae..0b210d966d1 100644 --- a/src/goto-instrument/dump_c.cpp +++ b/src/goto-instrument/dump_c.cpp @@ -21,6 +21,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include +#include #include #include @@ -149,7 +150,8 @@ void dump_ct::operator()(std::ostream &os) // we don't want to dump in full all definitions; in particular // do not dump anonymous types that are defined in system headers if((!tag_added || symbol.is_type) && - system_symbols.is_symbol_internal_symbol(symbol, system_headers)) + system_symbols.is_symbol_internal_symbol(symbol, system_headers) && + symbol.name!=goto_functions.entry_point()) continue; bool inserted=symbols_sorted.insert(name_str).second; @@ -198,7 +200,8 @@ void dump_ct::operator()(std::ostream &os) goto_functionst::function_mapt::const_iterator func_entry= goto_functions.function_map.find(symbol.name); - if(func_entry!=goto_functions.function_map.end() && + if(!harness && + func_entry!=goto_functions.function_map.end() && func_entry->second.body_available() && (symbol.name==ID_main || (!config.main.empty() && symbol.name==config.main))) @@ -946,6 +949,63 @@ void dump_ct::convert_global_variable( } } +/// Replace CPROVER internal symbols in b by printable values and generate +/// necessary declarations. +/// \param b: Code block to be cleaned +void dump_ct::cleanup_harness(code_blockt &b) +{ + replace_symbolt replace; + code_blockt decls; + + const symbolt *argc_sym=nullptr; + if(!ns.lookup("argc'", argc_sym)) + { + symbol_exprt argc("argc", argc_sym->type); + replace.insert(argc_sym->name, argc); + code_declt d(argc); + decls.add(d); + } + const symbolt *argv_sym=nullptr; + if(!ns.lookup("argv'", argv_sym)) + { + symbol_exprt argv("argv", argv_sym->type); + replace.insert(argv_sym->name, argv); + code_declt d(argv); + decls.add(d); + } + const symbolt *return_sym=nullptr; + if(!ns.lookup("return'", return_sym)) + { + symbol_exprt return_value("return_value", return_sym->type); + replace.insert(return_sym->name, return_value); + code_declt d(return_value); + decls.add(d); + } + + Forall_operands(it, b) + { + codet &code=to_code(*it); + + if(code.get_statement()==ID_function_call) + { + exprt &func=to_code_function_call(code).function(); + if(func.id()==ID_symbol) + { + symbol_exprt &s=to_symbol_expr(func); + if(s.get_identifier()==ID_main) + s.set_identifier(CPROVER_PREFIX+id2string(ID_main)); + else if(s.get_identifier()==CPROVER_PREFIX "initialize") + continue; + } + } + + decls.add(code); + } + + b.swap(decls); + replace(b); +} + void dump_ct::convert_function_declaration( const symbolt &symbol, const bool skip_main, @@ -1001,9 +1061,20 @@ void dump_ct::convert_function_declaration( converted_enum.swap(converted_e_bak); converted_compound.swap(converted_c_bak); + if(harness && symbol.name==goto_functions.entry_point()) + cleanup_harness(b); + os_body << "// " << symbol.name << '\n'; os_body << "// " << symbol.location << '\n'; - os_body << make_decl(symbol.name, symbol.type) << '\n'; + if(symbol.name==goto_functions.entry_point()) + os_body << make_decl(ID_main, symbol.type) << '\n'; + else if(!harness || symbol.name!=ID_main) + os_body << make_decl(symbol.name, symbol.type) << '\n'; + else if(harness && symbol.name==ID_main) + { + os_body << make_decl(CPROVER_PREFIX+id2string(symbol.name), symbol.type) + << '\n'; + } os_body << expr_to_string(b); os_body << "\n\n"; @@ -1017,6 +1088,13 @@ void dump_ct::convert_function_declaration( os_decl << "// " << symbol.location << '\n'; os_decl << make_decl(symbol.name, symbol.type) << ";\n"; } + else if(harness && symbol.name==ID_main) + { + os_decl << "// " << symbol.name << '\n'; + os_decl << "// " << symbol.location << '\n'; + os_decl << make_decl(CPROVER_PREFIX+id2string(symbol.name), symbol.type) + << ";\n"; + } // make sure typedef names used in the function declaration are // available @@ -1368,11 +1446,17 @@ void dump_c( const goto_functionst &src, const bool use_system_headers, const bool use_all_headers, + const bool include_harness, const namespacet &ns, std::ostream &out) { dump_ct goto2c( - src, use_system_headers, use_all_headers, ns, new_ansi_c_language); + src, + use_system_headers, + use_all_headers, + include_harness, + ns, + new_ansi_c_language); out << goto2c; } @@ -1380,10 +1464,16 @@ void dump_cpp( const goto_functionst &src, const bool use_system_headers, const bool use_all_headers, + const bool include_harness, const namespacet &ns, std::ostream &out) { dump_ct goto2cpp( - src, use_system_headers, use_all_headers, ns, new_cpp_language); + src, + use_system_headers, + use_all_headers, + include_harness, + ns, + new_cpp_language); out << goto2cpp; } diff --git a/src/goto-instrument/dump_c.h b/src/goto-instrument/dump_c.h index afac58b9007..d0f15c60489 100644 --- a/src/goto-instrument/dump_c.h +++ b/src/goto-instrument/dump_c.h @@ -18,6 +18,7 @@ void dump_c( const goto_functionst &src, const bool use_system_headers, const bool use_all_headers, + const bool include_harness, const namespacet &ns, std::ostream &out); @@ -25,6 +26,7 @@ void dump_cpp( const goto_functionst &src, const bool use_system_headers, const bool use_all_headers, + const bool include_harness, const namespacet &ns, std::ostream &out); diff --git a/src/goto-instrument/dump_c_class.h b/src/goto-instrument/dump_c_class.h index 26a89242aa5..bddb1cdeda2 100644 --- a/src/goto-instrument/dump_c_class.h +++ b/src/goto-instrument/dump_c_class.h @@ -28,12 +28,14 @@ class dump_ct const goto_functionst &_goto_functions, const bool use_system_headers, const bool use_all_headers, + const bool include_harness, const namespacet &_ns, language_factoryt factory): goto_functions(_goto_functions), copied_symbol_table(_ns.get_symbol_table()), ns(copied_symbol_table), - language(factory()) + language(factory()), + harness(include_harness) { if(use_system_headers) system_symbols=system_library_symbolst(); @@ -49,6 +51,7 @@ class dump_ct symbol_tablet copied_symbol_table; const namespacet ns; std::unique_ptr language; + const bool harness; typedef std::unordered_set convertedt; convertedt converted_compound, converted_global, converted_enum; @@ -158,6 +161,7 @@ class dump_ct code_declt &decl, std::list &local_static, std::list &local_type_decls); + void cleanup_harness(code_blockt &b); }; #endif // CPROVER_GOTO_INSTRUMENT_DUMP_C_CLASS_H diff --git a/src/goto-instrument/goto_instrument_parse_options.cpp b/src/goto-instrument/goto_instrument_parse_options.cpp index 8991ab985d3..4c591b77f8e 100644 --- a/src/goto-instrument/goto_instrument_parse_options.cpp +++ b/src/goto-instrument/goto_instrument_parse_options.cpp @@ -624,6 +624,7 @@ int goto_instrument_parse_optionst::doit() const bool is_cpp=cmdline.isset("dump-cpp"); const bool h_libc=!cmdline.isset("no-system-headers"); const bool h_all=cmdline.isset("use-all-headers"); + const bool harness=cmdline.isset("harness"); namespacet ns(symbol_table); // restore RETURN instructions in case remove_returns had been @@ -642,11 +643,22 @@ int goto_instrument_parse_optionst::doit() error() << "failed to write to `" << cmdline.args[1] << "'"; return 10; } - (is_cpp ? dump_cpp : dump_c)(goto_functions, h_libc, h_all, ns, out); + (is_cpp ? dump_cpp : dump_c)( + goto_functions, + h_libc, + h_all, + harness, + ns, + out); } else (is_cpp ? dump_cpp : dump_c)( - goto_functions, h_libc, h_all, ns, std::cout); + goto_functions, + h_libc, + h_all, + harness, + ns, + std::cout); return 0; } @@ -1545,6 +1557,7 @@ void goto_instrument_parse_optionst::help() "Other options:\n" " --no-system-headers with --dump-c/--dump-cpp: generate C source expanding libc includes\n" // NOLINT(*) " --use-all-headers with --dump-c/--dump-cpp: generate C source with all includes\n" // NOLINT(*) + " --harness with --dump-c/--dump-cpp: include input generator in output\n" // NOLINT(*) " --version show version and exit\n" " --xml-ui use XML-formatted output\n" " --json-ui use JSON-formatted output\n" diff --git a/src/goto-instrument/goto_instrument_parse_options.h b/src/goto-instrument/goto_instrument_parse_options.h index e2c4bf4fbc0..25ed2ce4cee 100644 --- a/src/goto-instrument/goto_instrument_parse_options.h +++ b/src/goto-instrument/goto_instrument_parse_options.h @@ -27,6 +27,7 @@ Author: Daniel Kroening, kroening@kroening.com "(document-claims-latex)(document-claims-html)" \ "(document-properties-latex)(document-properties-html)" \ "(dump-c)(dump-cpp)(no-system-headers)(use-all-headers)(dot)(xml)" \ + "(harness)" \ OPT_GOTO_CHECK \ /* no-X-check are deprecated and ignored */ \ "(no-bounds-check)(no-pointer-check)(no-div-by-zero-check)" \ From a01eeb72c37a0425d7df690377e28ec08344c751 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Wed, 28 Jun 2017 15:38:40 +0100 Subject: [PATCH 27/65] Use invariant annotations instead of asserts --- src/goto-instrument/model_argc_argv.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/goto-instrument/model_argc_argv.cpp b/src/goto-instrument/model_argc_argv.cpp index 96cad896e6f..13d8de6c0b3 100644 --- a/src/goto-instrument/model_argc_argv.cpp +++ b/src/goto-instrument/model_argc_argv.cpp @@ -16,6 +16,7 @@ Date: April 2016 #include #include +#include #include #include #include @@ -132,8 +133,8 @@ bool model_argc_argv( symbol_table.add(it->second)) UNREACHABLE; } + POSTCONDITION(value.is_not_nil()); - assert(value.is_not_nil()); goto_convert( to_code(value), symbol_table, @@ -147,15 +148,17 @@ bool model_argc_argv( goto_functionst::function_mapt::iterator start_entry= goto_functions.function_map.find(goto_functions.entry_point()); - assert( + DATA_INVARIANT( start_entry!=goto_functions.function_map.end() && - start_entry->second.body_available()); + start_entry->second.body_available(), + "entry point expected to have a body"); goto_programt &start=start_entry->second.body; goto_programt::targett main_call=start.instructions.begin(); for(goto_programt::targett end=start.instructions.end(); main_call!=end; ++main_call) + { if(main_call->is_function_call()) { const exprt &func= @@ -164,8 +167,9 @@ bool model_argc_argv( to_symbol_expr(func).get_identifier()==main_symbol.name) break; } + } + POSTCONDITION(main_call!=start.instructions.end()); - assert(main_call!=start.instructions.end()); start.insert_before_swap(main_call, init_instructions); // update counters etc. From 4466408f20ca6ce1a96dc69e1f6a75715f9eed10 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Wed, 23 Aug 2017 15:24:32 +0100 Subject: [PATCH 28/65] Replace 3-valued char by enum --- src/goto-programs/interpreter.cpp | 11 +++++++---- src/goto-programs/interpreter_class.h | 10 ++++++++-- src/goto-programs/interpreter_evaluate.cpp | 15 ++++++++------- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/goto-programs/interpreter.cpp b/src/goto-programs/interpreter.cpp index e6161934ae2..ec0a245f67e 100644 --- a/src/goto-programs/interpreter.cpp +++ b/src/goto-programs/interpreter.cpp @@ -503,7 +503,9 @@ exprt interpretert::get_value( } return result; } - if(use_non_det && (memory[offset].initialized>=0)) + if(use_non_det && + memory[offset].initialized!= + memory_cellt::initializedt::WRITTEN_BEFORE_READ) return side_effect_expr_nondett(type); mp_vectort rhs; rhs.push_back(memory[offset].value); @@ -681,7 +683,8 @@ void interpretert::execute_assign() size_t size=get_size(code_assign.lhs().type()); for(size_t i=0; i memoryt; diff --git a/src/goto-programs/interpreter_evaluate.cpp b/src/goto-programs/interpreter_evaluate.cpp index 0efac402430..2fd4710d3d1 100644 --- a/src/goto-programs/interpreter_evaluate.cpp +++ b/src/goto-programs/interpreter_evaluate.cpp @@ -36,8 +36,8 @@ void interpretert::read( { const memory_cellt &cell=memory[integer2size_t(address+i)]; value=cell.value; - if(cell.initialized==0) - cell.initialized=-1; + if(cell.initialized==memory_cellt::initializedt::UNKNOWN) + cell.initialized=memory_cellt::initializedt::READ_BEFORE_WRITTEN; } else value=0; @@ -64,8 +64,8 @@ void interpretert::read_unbounded( { const memory_cellt &cell=memory[integer2size_t(address+i)]; value=cell.value; - if(cell.initialized==0) - cell.initialized=-1; + if(cell.initialized==memory_cellt::initializedt::UNKNOWN) + cell.initialized=memory_cellt::initializedt::READ_BEFORE_WRITTEN; } else value=0; @@ -86,7 +86,7 @@ void interpretert::allocate( { memory_cellt &cell=memory[integer2size_t(address+i)]; cell.value=0; - cell.initialized=0; + cell.initialized=memory_cellt::initializedt::UNKNOWN; } } } @@ -96,8 +96,9 @@ void interpretert::clear_input_flags() { for(auto &cell : memory) { - if(cell.second.initialized>0) - cell.second.initialized=0; + if(cell.second.initialized== + memory_cellt::initializedt::WRITTEN_BEFORE_READ) + cell.second.initialized=memory_cellt::initializedt::UNKNOWN; } } From 48845af9d906f193dafa395252e9ff9d8cd3f32e Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Wed, 23 Aug 2017 15:36:14 +0100 Subject: [PATCH 29/65] Interpreter: constify mp_integer typed address parameters --- src/goto-programs/interpreter.cpp | 2 +- src/goto-programs/interpreter_class.h | 12 ++++++------ src/goto-programs/interpreter_evaluate.cpp | 20 +++++++++++--------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/goto-programs/interpreter.cpp b/src/goto-programs/interpreter.cpp index ec0a245f67e..25d2be08cb8 100644 --- a/src/goto-programs/interpreter.cpp +++ b/src/goto-programs/interpreter.cpp @@ -692,7 +692,7 @@ void interpretert::execute_assign() /// sets the memory at address with the given rhs value (up to sizeof(rhs)) void interpretert::assign( - mp_integer address, + const mp_integer &address, const mp_vectort &rhs) { for(size_t i=0; ifirstsecond!=-1; ++offsets) { const auto &component_type=components[offsets->first].type(); @@ -278,13 +279,14 @@ bool interpretert::memory_offset_to_byte_offset( mp_integer elem_count; if(count_type_leaves(at.subtype(), elem_count)) return true; - mp_integer this_idx=cell_offset/elem_count; + mp_integer this_idx=full_cell_offset/elem_count; if(this_idx>=array_size_vec[0]) return true; mp_integer subtype_result; bool ret= - memory_offset_to_byte_offset(at.subtype(), - cell_offset%elem_count, + memory_offset_to_byte_offset( + at.subtype(), + full_cell_offset%elem_count, subtype_result); result=subtype_result+(elem_size*this_idx); return ret; @@ -293,7 +295,7 @@ bool interpretert::memory_offset_to_byte_offset( { // Primitive type. result=0; - return cell_offset!=0; + return full_cell_offset!=0; } } From 52d1e04d4a661b85ac111c5b51e7f2cbd85049c1 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Wed, 23 Aug 2017 14:42:32 +0100 Subject: [PATCH 30/65] Do not use default arguments for json(...) --- src/cbmc/bmc_cover.cpp | 3 ++- src/goto-programs/json_goto_trace.cpp | 2 +- src/symex/symex_cover.cpp | 3 ++- src/util/json_expr.h | 4 ++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/cbmc/bmc_cover.cpp b/src/cbmc/bmc_cover.cpp index 50695562bb0..c0ad5465c6a 100644 --- a/src/cbmc/bmc_cover.cpp +++ b/src/cbmc/bmc_cover.cpp @@ -394,7 +394,8 @@ bool bmc_covert::operator()() json_objectt json_input; json_input["id"]=json_stringt(id2string(step.io_id)); if(step.io_args.size()==1) - json_input["value"]=json(step.io_args.front(), bmc.ns); + json_input["value"]= + json(step.io_args.front(), bmc.ns, ID_unknown); json_test.push_back(json_input); } } diff --git a/src/goto-programs/json_goto_trace.cpp b/src/goto-programs/json_goto_trace.cpp index 4825fe5bea0..453d8e5c92c 100644 --- a/src/goto-programs/json_goto_trace.cpp +++ b/src/goto-programs/json_goto_trace.cpp @@ -192,7 +192,7 @@ void convert( DATA_INVARIANT( step.full_lhs_value.is_not_nil(), "full_lhs_value in assignment must not be nil"); - full_lhs_value=json(step.full_lhs_value, ns); + full_lhs_value=json(step.full_lhs_value, ns, ID_unknown); } json_assignment["value"]=full_lhs_value; diff --git a/src/symex/symex_cover.cpp b/src/symex/symex_cover.cpp index e7f101c0870..080425dd87f 100644 --- a/src/symex/symex_cover.cpp +++ b/src/symex/symex_cover.cpp @@ -164,7 +164,8 @@ void symex_parse_optionst::report_cover( json_objectt json_input; json_input["id"]=json_stringt(id2string(step.io_id)); if(step.io_args.size()==1) - json_input["value"]=json(step.io_args.front(), ns); + json_input["value"]= + json(step.io_args.front(), ns, ID_unknown); json_test.push_back(json_input); } } diff --git a/src/util/json_expr.h b/src/util/json_expr.h index 6b9a124680b..cc082020cdc 100644 --- a/src/util/json_expr.h +++ b/src/util/json_expr.h @@ -23,12 +23,12 @@ class namespacet; json_objectt json( const exprt &, const namespacet &, - const irep_idt &mode=ID_unknown); + const irep_idt &mode); json_objectt json( const typet &, const namespacet &, - const irep_idt &mode=ID_unknown); + const irep_idt &mode); json_objectt json(const source_locationt &); From 4d35274bd0a42deb5a8cb7a09fa495ca84d05fed Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Wed, 23 Aug 2017 14:43:44 +0100 Subject: [PATCH 31/65] Simplify pointer_offset(constant) --- src/util/simplify_expr_pointer.cpp | 37 +++++++++++++++++--- unit/Makefile | 7 ++-- unit/util/simplify_expr.cpp | 56 ++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 unit/util/simplify_expr.cpp diff --git a/src/util/simplify_expr_pointer.cpp b/src/util/simplify_expr_pointer.cpp index 1044d43dac4..938ce023d7e 100644 --- a/src/util/simplify_expr_pointer.cpp +++ b/src/util/simplify_expr_pointer.cpp @@ -375,14 +375,41 @@ bool simplify_exprt::simplify_pointer_offset(exprt &expr) return false; } - else if(ptr.id()==ID_constant && - ptr.get(ID_value)==ID_NULL) + else if(ptr.id()==ID_constant) { - expr=from_integer(0, expr.type()); + constant_exprt &c_ptr=to_constant_expr(ptr); - simplify_node(expr); + if(c_ptr.get_value()==ID_NULL || + c_ptr.value_is_zero_string()) + { + expr=from_integer(0, expr.type()); - return false; + simplify_node(expr); + + return false; + } + else + { + // this is a pointer, we can't use to_integer + mp_integer number=binary2integer(id2string(c_ptr.get_value()), false); + // a null pointer would have been caught above, return value 0 + // will indicate that conversion failed + if(number==0) + return true; + + // The constant address consists of OBJECT-ID || OFFSET. + mp_integer offset_bits= + pointer_offset_bits(ptr.type(), ns)-config.bv_encoding.object_bits; + number%=power(2, offset_bits); + + expr=from_integer(number, expr.type()); + + simplify_node(expr); + + return false; + } + + return true; } return true; diff --git a/unit/Makefile b/unit/Makefile index b24eeeab1ad..a47b3d6ec62 100644 --- a/unit/Makefile +++ b/unit/Makefile @@ -5,9 +5,6 @@ SRC = src/expr/require_expr.cpp \ src/ansi-c/c_to_expr.cpp \ unit_tests.cpp \ catch_example.cpp \ - util/expr_iterator.cpp \ - analyses/call_graph.cpp \ - java_bytecode/java_bytecode_convert_class/convert_abstract_class.cpp \ # Empty last line # Test source files @@ -23,8 +20,10 @@ SRC += unit_tests.cpp \ solvers/refinement/string_constraint_generator_valueof/get_numeric_value_from_character.cpp \ solvers/refinement/string_constraint_generator_valueof/is_digit_with_radix.cpp \ solvers/refinement/string_constraint_instantiation/instantiate_not_contains.cpp \ - solvers/refinement/string_refinement/substitute_array_list.cpp \ solvers/refinement/string_refinement/concretize_array.cpp \ + solvers/refinement/string_refinement/substitute_array_list.cpp \ + util/expr_iterator.cpp \ + util/simplify_expr.cpp \ catch_example.cpp \ # Empty last line diff --git a/unit/util/simplify_expr.cpp b/unit/util/simplify_expr.cpp new file mode 100644 index 00000000000..20d5816a8e9 --- /dev/null +++ b/unit/util/simplify_expr.cpp @@ -0,0 +1,56 @@ +/*******************************************************************\ + + Module: Unit tests of the expression simplifier + + Author: Michael Tautschnig + +\*******************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +TEST_CASE("Simplify pointer_offset(address of array index)") +{ + symbol_tablet symbol_table; + namespacet ns(symbol_table); + + array_typet array_type(char_type(), from_integer(2, size_type())); + symbol_exprt array("A", array_type); + index_exprt index(array, from_integer(1, index_type())); + address_of_exprt address_of(index); + + exprt p_o=pointer_offset(address_of); + + exprt simp=simplify_expr(p_o, ns); + + REQUIRE(simp.id()==ID_constant); + mp_integer offset_value; + REQUIRE(!to_integer(simp, offset_value)); + REQUIRE(offset_value==1); +} + +TEST_CASE("Simplify const pointer offset") +{ + symbol_tablet symbol_table; + namespacet ns(symbol_table); + + // build a numeric constant of some pointer type + constant_exprt number=from_integer(1234, size_type()); + number.type()=pointer_type(char_type()); + + exprt p_o=pointer_offset(number); + + exprt simp=simplify_expr(p_o, ns); + + REQUIRE(simp.id()==ID_constant); + mp_integer offset_value; + REQUIRE(!to_integer(simp, offset_value)); + REQUIRE(offset_value==1234); +} From 27fd210bb132efa598b4865a19ab00bbc2ba76ab Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Wed, 23 Aug 2017 14:44:17 +0100 Subject: [PATCH 32/65] Use generic simplify_expr instead of local simplification rules --- src/goto-programs/json_goto_trace.cpp | 80 +-------------------------- 1 file changed, 2 insertions(+), 78 deletions(-) diff --git a/src/goto-programs/json_goto_trace.cpp b/src/goto-programs/json_goto_trace.cpp index 453d8e5c92c..52c18d36e6b 100644 --- a/src/goto-programs/json_goto_trace.cpp +++ b/src/goto-programs/json_goto_trace.cpp @@ -21,82 +21,6 @@ Author: Daniel Kroening #include -/// Replaces in src, expressions of the form pointer_offset(constant) by that -/// constant. -/// \param src: an expression -void remove_pointer_offsets(exprt &src) -{ - if(src.id()==ID_pointer_offset && - src.op0().id()==ID_constant && - src.op0().type().id()==ID_pointer) - { - std::string binary_str=id2string(to_constant_expr(src.op0()).get_value()); - // The constant address consists of OBJECT-ID || OFFSET. - // Shift out the object-identifier bits, leaving only the offset: - mp_integer offset=binary2integer( - binary_str.substr(config.bv_encoding.object_bits), false); - src=from_integer(offset, src.type()); - } - else - for(auto &op : src.operands()) - remove_pointer_offsets(op); -} - -/// Replaces in src, expressions of the form pointer_offset(array_symbol) by a -/// constant value of 0. This is meant to simplify array expressions. -/// \param src: an expression -/// \param array_symbol: a symbol expression representing an array -void remove_pointer_offsets(exprt &src, const symbol_exprt &array_symbol) -{ - if(src.id()==ID_pointer_offset && - src.op0().id()==ID_constant && - src.op0().op0().id()==ID_address_of && - src.op0().op0().op0().id()==ID_index) - { - const index_exprt &idx=to_index_expr(src.op0().op0().op0()); - const irep_idt &array_id=to_symbol_expr(idx.array()).get_identifier(); - if(idx.array().id()==ID_symbol && - array_id==array_symbol.get_identifier() && - to_constant_expr(idx.index()).value_is_zero_string()) - src=from_integer(0, src.type()); - } - else - for(auto &op : src.operands()) - remove_pointer_offsets(op, array_symbol); -} - -/// Simplify an expression before putting it in the json format -/// \param src: an expression potentialy containing array accesses (index_expr) -/// \return an expression similar in meaning to src but where array accesses -/// have been simplified -exprt simplify_array_access(const exprt &src, const namespacet &ns) -{ - if(src.id()==ID_index && to_index_expr(src).array().id()==ID_symbol) - { - // Case where the array is a symbol. - const symbol_exprt &array_symbol=to_symbol_expr(to_index_expr(src).array()); - exprt simplified_index=to_index_expr(src).index(); - // We remove potential appearances of `pointer_offset(array_symbol)` - remove_pointer_offsets(simplified_index, array_symbol); - simplified_index=simplify_expr(simplified_index, ns); - return index_exprt(array_symbol, simplified_index); - } - else if(src.id()==ID_index && to_index_expr(src).array().id()==ID_array) - { - // Case where the array is given by an array of expressions - exprt index=to_index_expr(src).index(); - remove_pointer_offsets(index); - - // We look for an actual integer value for the index - index=simplify_expr(index, ns); - unsigned i; - if(index.id()==ID_constant && - !to_unsigned_integer(to_constant_expr(index), i)) - return to_index_expr(src).array().operands()[i]; - } - return src; -} - /// Produce a json representation of a trace. /// \param ns: a namespace /// \param goto_trace: a trace in a goto program @@ -169,7 +93,7 @@ void convert( DATA_INVARIANT( step.full_lhs.is_not_nil(), "full_lhs in assignment must not be nil"); - exprt simplified=simplify_array_access(step.full_lhs, ns); + exprt simplified=simplify_expr(step.full_lhs, ns); full_lhs_string=from_expr(ns, identifier, simplified); const symbolt *symbol; @@ -183,7 +107,7 @@ void convert( type_string=from_type(ns, identifier, symbol->type); json_assignment["mode"]=json_stringt(id2string(symbol->mode)); - exprt simplified=simplify_array_access(step.full_lhs_value, ns); + exprt simplified=simplify_expr(step.full_lhs_value, ns); full_lhs_value=json(simplified, ns, symbol->mode); } From 6c56f1981ec9328446cdcd2dce5072bcf11181e4 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Fri, 25 Aug 2017 13:51:20 +0100 Subject: [PATCH 33/65] Do not attempt to compute union sizes when not required Packed unions/structs without alignment specification may use fields of dynamic size. It is then unnecessary to compute their full size as it would never be used anyway. --- regression/ansi-c/Union_Padding2/main.c | 34 ++++++++++++++++++++++ regression/ansi-c/Union_Padding2/test.desc | 8 +++++ regression/cbmc/dynamic_sizeof1/main.c | 25 ++++++++++++++++ regression/cbmc/dynamic_sizeof1/test.desc | 8 +++++ src/ansi-c/padding.cpp | 28 ++++++++++-------- 5 files changed, 91 insertions(+), 12 deletions(-) create mode 100644 regression/ansi-c/Union_Padding2/main.c create mode 100644 regression/ansi-c/Union_Padding2/test.desc create mode 100644 regression/cbmc/dynamic_sizeof1/main.c create mode 100644 regression/cbmc/dynamic_sizeof1/test.desc diff --git a/regression/ansi-c/Union_Padding2/main.c b/regression/ansi-c/Union_Padding2/main.c new file mode 100644 index 00000000000..63850620415 --- /dev/null +++ b/regression/ansi-c/Union_Padding2/main.c @@ -0,0 +1,34 @@ +static unsigned bar() +{ + unsigned r; + return r; +} + +#ifdef _MSC_VER + +static void foo() +{ +} + +#else + +static void foo() +{ + unsigned len=bar(); + struct { + int a; + union { + int s; + unsigned char b[len]; + } __attribute__ (( packed )) S; + int c; + } __attribute__ (( packed )) *l; +} + +#endif + +int main() +{ + foo(); + return 0; +} diff --git a/regression/ansi-c/Union_Padding2/test.desc b/regression/ansi-c/Union_Padding2/test.desc new file mode 100644 index 00000000000..466da18b2b5 --- /dev/null +++ b/regression/ansi-c/Union_Padding2/test.desc @@ -0,0 +1,8 @@ +CORE +main.c + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +^CONVERSION ERROR$ diff --git a/regression/cbmc/dynamic_sizeof1/main.c b/regression/cbmc/dynamic_sizeof1/main.c new file mode 100644 index 00000000000..14082f936ce --- /dev/null +++ b/regression/cbmc/dynamic_sizeof1/main.c @@ -0,0 +1,25 @@ +#include +#include + +int main() +{ + unsigned x; + + if(x>=0 && x<=1000) + { + struct + { + int asd; + + union { + int i; + char array[x]; + }; + } *ptr; + + if(x<=sizeof(int)) + assert(sizeof(*ptr)==sizeof(int)*2); + else + assert(sizeof(*ptr)==sizeof(int)+x); + } +} diff --git a/regression/cbmc/dynamic_sizeof1/test.desc b/regression/cbmc/dynamic_sizeof1/test.desc new file mode 100644 index 00000000000..9efefbc7362 --- /dev/null +++ b/regression/cbmc/dynamic_sizeof1/test.desc @@ -0,0 +1,8 @@ +CORE +main.c + +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/src/ansi-c/padding.cpp b/src/ansi-c/padding.cpp index e7219fd615a..58e349ee0e6 100644 --- a/src/ansi-c/padding.cpp +++ b/src/ansi-c/padding.cpp @@ -303,36 +303,40 @@ void add_padding(struct_typet &type, const namespacet &ns) void add_padding(union_typet &type, const namespacet &ns) { - mp_integer max_alignment=alignment(type, ns)*8; - mp_integer size_bits=pointer_offset_bits(type, ns); + mp_integer max_alignment_bits=alignment(type, ns)*8; + mp_integer size_bits=0; - if(size_bits<0) - throw "type of unknown size:\n"+type.pretty(); - - union_typet::componentst &components=type.components(); + // check per component, and ignore those without fixed size + for(const auto &c : type.components()) + { + mp_integer s=pointer_offset_bits(c.type(), ns); + if(s>0) + size_bits=std::max(size_bits, s); + } // Is the union packed? if(type.get_bool(ID_C_packed)) { - // The size needs to be a multiple of 8 only. - max_alignment=8; + // The size needs to be a multiple of 8 bits only. + max_alignment_bits=8; } // The size must be a multiple of the alignment, or // we add a padding member to the union. - if(size_bits%max_alignment!=0) + if(size_bits%max_alignment_bits!=0) { - mp_integer padding=max_alignment-(size_bits%max_alignment); + mp_integer padding_bits= + max_alignment_bits-(size_bits%max_alignment_bits); unsignedbv_typet padding_type; - padding_type.set_width(integer2unsigned(size_bits+padding)); + padding_type.set_width(integer2size_t(size_bits+padding_bits)); struct_typet::componentt component; component.type()=padding_type; component.set_name("$pad"); component.set_is_padding(true); - components.push_back(component); + type.components().push_back(component); } } From 165ec479bc37943d18d38e000f1d121e1e78fa9d Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Fri, 25 Aug 2017 15:17:45 +0100 Subject: [PATCH 34/65] Test alignment of unions --- regression/ansi-c/Union_Padding1/main.c | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/regression/ansi-c/Union_Padding1/main.c b/regression/ansi-c/Union_Padding1/main.c index 1ed56e07bd6..4a5d22a562b 100644 --- a/regression/ansi-c/Union_Padding1/main.c +++ b/regression/ansi-c/Union_Padding1/main.c @@ -62,6 +62,33 @@ STATIC_ASSERT(sizeof(union some_union4)==3); #endif +#ifdef _MSC_VER + +union some_union5 +{ + int i; +}; + +STATIC_ASSERT(__alignof(union some_union5)==1); + +#else + +union some_union5 +{ + int i; +}; + +union some_union6 +{ + int i; +} __attribute__((__packed__)); + +// Packing may affect alignment +STATIC_ASSERT(_Alignof(union some_union5)==4); +STATIC_ASSERT(_Alignof(union some_union6)==1); + +#endif + int main() { } From 003482a7b710e3925952165fe9e453021f59370c Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Sat, 13 May 2017 19:34:00 +0100 Subject: [PATCH 35/65] MetaChar: use std::stringstream for incremental escaped-string construction This avoids the use of lower-level snprintf. --- src/ansi-c/c_misc.cpp | 49 ++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/src/ansi-c/c_misc.cpp b/src/ansi-c/c_misc.cpp index 5b1913bdf05..242bf616a4e 100644 --- a/src/ansi-c/c_misc.cpp +++ b/src/ansi-c/c_misc.cpp @@ -11,81 +11,72 @@ Author: Daniel Kroening, kroening@kroening.com #include "c_misc.h" -#include +#include -#ifdef _WIN32 -#ifndef __MINGW32__ -#define snprintf sprintf_s -#endif -#endif - -static void MetaChar(std::string &out, char c, bool inString) +static void MetaChar(std::ostringstream &out, char c, bool inString) { switch(c) { case '\'': if(inString) - out+="'"; + out << "'"; else - out+="\\'"; + out << "\\'"; break; case '"': if(inString) - out+="\\\""; + out << "\\\""; else - out+="\""; + out << "\""; break; case '\0': - out+="\\0"; + out << "\\0"; break; case '\\': - out+="\\\\"; + out << "\\\\"; break; case '\n': - out+="\\n"; + out << "\\n"; break; case '\t': - out+="\\t"; + out << "\\t"; break; case '\r': - out+="\\r"; + out << "\\r"; break; case '\f': - out+="\\f"; + out << "\\f"; break; case '\b': - out+="\\b"; + out << "\\b"; break; case '\v': - out+="\\v"; + out << "\\v"; break; case '\a': - out+="\\a"; + out << "\\a"; break; default: // Show low and certain high ascii as octal - if(((unsigned char)c < ' ') || (c == 127)) + if((static_cast(c)<' ') || (c==127)) { - char octbuf[8]; - snprintf(octbuf, sizeof(octbuf), "%03o", (unsigned char) c); - out+="\\"; - out+=octbuf; + out << "\\" << std::oct << static_cast(c); } else { // leave everything else to permit UTF-8 and 8-bit codepages - out+=c; + out << c; } break; @@ -103,10 +94,10 @@ static std::string MetaChar(char c) std::string MetaString(const std::string &in) { - std::string result; + std::ostringstream result; for(const auto &ch : in) MetaChar(result, ch, true); - return result; + return result.str(); } From 8555871e1d1e76448af1aa725ec507c476add812 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Sat, 13 May 2017 19:33:10 +0100 Subject: [PATCH 36/65] member_offset_bits: express member offset in bits instead of bytes --- src/analyses/goto_rw.cpp | 6 +++--- src/util/pointer_offset_size.cpp | 23 +++++++++++++++++++++++ src/util/pointer_offset_size.h | 5 +++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/analyses/goto_rw.cpp b/src/analyses/goto_rw.cpp index 571d8bd0ad1..110ed0b8f7c 100644 --- a/src/analyses/goto_rw.cpp +++ b/src/analyses/goto_rw.cpp @@ -221,12 +221,12 @@ void rw_range_sett::get_objects_member( const struct_typet &struct_type=to_struct_type(type); - // TODO - assumes members are byte-aligned range_spect offset= - to_range_spect(member_offset( + to_range_spect( + member_offset_bits( struct_type, expr.get_component_name(), - ns) * 8); + ns)); if(offset!=-1) offset+=range_start; diff --git a/src/util/pointer_offset_size.cpp b/src/util/pointer_offset_size.cpp index dee9aeff82d..798266792eb 100644 --- a/src/util/pointer_offset_size.cpp +++ b/src/util/pointer_offset_size.cpp @@ -80,6 +80,29 @@ mp_integer member_offset( return offsets->second; } +mp_integer member_offset_bits( + const struct_typet &type, + const irep_idt &member, + const namespacet &ns) +{ + mp_integer offset=0; + const struct_typet::componentst &components=type.components(); + + for(const auto &comp : components) + { + if(comp.get_name()==member) + break; + + mp_integer member_bits=pointer_offset_bits(comp.type(), ns); + if(member_bits==-1) + return member_bits; + + offset+=member_bits; + } + + return offset; +} + mp_integer pointer_offset_size( const typet &type, const namespacet &ns) diff --git a/src/util/pointer_offset_size.h b/src/util/pointer_offset_size.h index aeb62e03d74..0bdd67f85d3 100644 --- a/src/util/pointer_offset_size.h +++ b/src/util/pointer_offset_size.h @@ -45,6 +45,11 @@ mp_integer member_offset( const irep_idt &member, const namespacet &ns); +mp_integer member_offset_bits( + const struct_typet &type, + const irep_idt &member, + const namespacet &ns); + mp_integer pointer_offset_size( const typet &type, const namespacet &ns); From 4c1b3b3588a0e45e25ad78abdd3e3daaa6c063c3 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Sun, 3 Sep 2017 11:21:45 +0100 Subject: [PATCH 37/65] target name wrong for signed variant of goto-diff --- src/goto-diff/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/goto-diff/Makefile b/src/goto-diff/Makefile index 17b2d253561..986085eb307 100644 --- a/src/goto-diff/Makefile +++ b/src/goto-diff/Makefile @@ -51,5 +51,5 @@ goto-diff$(EXEEXT): $(OBJ) .PHONY: goto-diff-mac-signed -cbmc-mac-signed: goto-diff$(EXEEXT) +goto-diff-mac-signed: goto-diff$(EXEEXT) strip goto-diff$(EXEEXT) ; codesign -v -s $(OSX_IDENTITY) goto-diff$(EXEEXT) From 5bfe346eac339f9a0c9c3b7e0594a8f998e570e2 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Tue, 29 Aug 2017 22:06:58 +0100 Subject: [PATCH 38/65] use ranged for --- src/goto-programs/goto_inline_class.cpp | 61 ++++++++----------------- 1 file changed, 20 insertions(+), 41 deletions(-) diff --git a/src/goto-programs/goto_inline_class.cpp b/src/goto-programs/goto_inline_class.cpp index 355c25d6d21..e6ace7271c5 100644 --- a/src/goto-programs/goto_inline_class.cpp +++ b/src/goto-programs/goto_inline_class.cpp @@ -46,13 +46,8 @@ void goto_inlinet::parameter_assignments( code_type.parameters(); // iterates over the types of the parameters - for(code_typet::parameterst::const_iterator - it2=parameter_types.begin(); - it2!=parameter_types.end(); - it2++) + for(const auto ¶meter : parameter_types) { - const code_typet::parametert ¶meter=*it2; - // this is the type the n-th argument should be const typet &par_type=ns.follow(parameter.type()); @@ -174,13 +169,8 @@ void goto_inlinet::parameter_destruction( code_type.parameters(); // iterates over the types of the parameters - for(code_typet::parameterst::const_iterator - it=parameter_types.begin(); - it!=parameter_types.end(); - it++) + for(const auto ¶meter : parameter_types) { - const code_typet::parametert ¶meter=*it; - const irep_idt &identifier=parameter.get_identifier(); if(identifier.empty()) @@ -374,8 +364,8 @@ void goto_inlinet::insert_function_body( end.type=LOCATION; if(adjust_function) - Forall_goto_program_instructions(i_it, body) - i_it->function=target->function; + for(auto &instruction : body.instructions) + instruction.function=target->function; replace_return(body, lhs, constrain); @@ -737,10 +727,8 @@ void goto_inlinet::goto_inline_nontransitive( recursion_set.insert(identifier); - for(call_listt::const_iterator c_it=call_list.begin(); - c_it!=call_list.end(); c_it++) + for(const auto &call : call_list) { - const callt &call=*c_it; const bool transitive=call.second; const inline_mapt &new_inline_map= @@ -792,8 +780,7 @@ const goto_inlinet::goto_functiont &goto_inlinet::goto_inline_transitive( goto_programt::targetst call_list; - for(goto_programt::targett i_it=goto_program.instructions.begin(); - i_it!=goto_program.instructions.end(); i_it++) + Forall_goto_program_instructions(i_it, goto_program) { if(is_call(i_it)) call_list.push_back(i_it); @@ -804,15 +791,14 @@ const goto_inlinet::goto_functiont &goto_inlinet::goto_inline_transitive( recursion_set.insert(identifier); - for(goto_programt::targetst::iterator c_it=call_list.begin(); - c_it!=call_list.end(); c_it++) + for(const auto &call : call_list) { expand_function_call( goto_program, inline_mapt(), true, force_full, - *c_it); + call); } recursion_set.erase(identifier); @@ -855,17 +841,15 @@ bool goto_inlinet::check_inline_map( int ln=-1; - for(call_listt::const_iterator c_it=call_list.begin(); - c_it!=call_list.end(); c_it++) + for(const auto &call : call_list) { - const callt &call=*c_it; const goto_programt::const_targett target=call.first; -#if 0 + #if 0 // might not hold if call was previously inlined if(target->function!=identifier) return false; -#endif + #endif // location numbers increasing if(static_cast(target->location_number)<=ln) @@ -897,11 +881,10 @@ void goto_inlinet::output_inline_map( { assert(check_inline_map(inline_map)); - for(inline_mapt::const_iterator it=inline_map.begin(); - it!=inline_map.end(); it++) + for(const auto &it : inline_map) { - const irep_idt id=it->first; - const call_listt &call_list=it->second; + const irep_idt id=it.first; + const call_listt &call_list=it.second; out << "Function: " << id << "\n"; @@ -918,10 +901,8 @@ void goto_inlinet::output_inline_map( const goto_programt &goto_program=goto_function.body; - for(call_listt::const_iterator c_it=call_list.begin(); - c_it!=call_list.end(); c_it++) + for(const auto &call : call_list) { - const callt &call=*c_it; const goto_programt::const_targett target=call.first; bool transitive=call.second; @@ -959,10 +940,9 @@ void goto_inlinet::goto_inline_logt::cleanup( void goto_inlinet::goto_inline_logt::cleanup( const goto_functionst::function_mapt &function_map) { - for(goto_functionst::function_mapt::const_iterator it= - function_map.begin(); it!=function_map.end(); it++) + for(const auto &it : function_map) { - const goto_functiont &goto_function=it->second; + const goto_functiont &goto_function=it.second; if(!goto_function.body_available()) continue; @@ -1043,13 +1023,12 @@ jsont goto_inlinet::goto_inline_logt::output_inline_log_json() const json_objectt json_result; json_arrayt &json_inlined=json_result["inlined"].make_array(); - for(log_mapt::const_iterator it=log_map.begin(); - it!=log_map.end(); it++) + for(const auto &it : log_map) { json_objectt &object=json_inlined.push_back().make_object(); - goto_programt::const_targett start=it->first; - const goto_inline_log_infot &info=it->second; + goto_programt::const_targett start=it.first; + const goto_inline_log_infot &info=it.second; goto_programt::const_targett end=info.end; assert(start->location_number<=end->location_number); From 29f1e2a6da6b0ee6070a6e0a43245e71cf2ac721 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Tue, 29 Aug 2017 21:58:34 +0100 Subject: [PATCH 39/65] eliminate constrained BP calls --- src/goto-programs/goto_inline.cpp | 13 ++-- src/goto-programs/goto_inline_class.cpp | 97 ++++++------------------- src/goto-programs/goto_inline_class.h | 13 +--- 3 files changed, 30 insertions(+), 93 deletions(-) diff --git a/src/goto-programs/goto_inline.cpp b/src/goto-programs/goto_inline.cpp index 49aca830b3b..aa8c5a5852d 100644 --- a/src/goto-programs/goto_inline.cpp +++ b/src/goto-programs/goto_inline.cpp @@ -77,7 +77,7 @@ void goto_inline( Forall_goto_program_instructions(i_it, goto_program) { - if(!goto_inlinet::is_call(i_it)) + if(!i_it->is_function_call()) continue; call_list.push_back(goto_inlinet::callt(i_it, false)); @@ -164,14 +164,13 @@ void goto_partial_inline( Forall_goto_program_instructions(i_it, goto_program) { - if(!goto_inlinet::is_call(i_it)) + if(!i_it->is_function_call()) continue; exprt lhs; exprt function_expr; exprt::operandst arguments; - exprt constrain; - goto_inlinet::get_call(i_it, lhs, function_expr, arguments, constrain); + goto_inlinet::get_call(i_it, lhs, function_expr, arguments); if(function_expr.id()!=ID_symbol) // Can't handle pointers to functions @@ -199,7 +198,7 @@ void goto_partial_inline( if(goto_function.is_inlined() || goto_program.instructions.size()<=smallfunc_limit) { - assert(goto_inlinet::is_call(i_it)); + assert(i_it->is_function_call()); call_list.push_back(goto_inlinet::callt(i_it, false)); } } @@ -273,7 +272,7 @@ void goto_function_inline( Forall_goto_program_instructions(i_it, goto_program) { - if(!goto_inlinet::is_call(i_it)) + if(!i_it->is_function_call()) continue; call_list.push_back(goto_inlinet::callt(i_it, true)); @@ -318,7 +317,7 @@ jsont goto_function_inline_and_log( Forall_goto_program_instructions(i_it, goto_program) { - if(!goto_inlinet::is_call(i_it)) + if(!i_it->is_function_call()) continue; call_list.push_back(goto_inlinet::callt(i_it, true)); diff --git a/src/goto-programs/goto_inline_class.cpp b/src/goto-programs/goto_inline_class.cpp index e6ace7271c5..575722c1722 100644 --- a/src/goto-programs/goto_inline_class.cpp +++ b/src/goto-programs/goto_inline_class.cpp @@ -34,7 +34,7 @@ void goto_inlinet::parameter_assignments( const exprt::operandst &arguments, // arguments of call goto_programt &dest) { - assert(is_call(target)); + assert(target->is_function_call()); assert(dest.empty()); const source_locationt &source_location=target->source_location; @@ -160,7 +160,7 @@ void goto_inlinet::parameter_destruction( const code_typet &code_type, // type of called function goto_programt &dest) { - assert(is_call(target)); + assert(target->is_function_call()); assert(dest.empty()); const source_locationt &source_location=target->source_location; @@ -195,8 +195,7 @@ void goto_inlinet::parameter_destruction( void goto_inlinet::replace_return( goto_programt &dest, // inlining this - const exprt &lhs, // lhs in caller - const exprt &constrain) + const exprt &lhs) // lhs in caller { for(goto_programt::instructionst::iterator it=dest.instructions.begin(); @@ -231,14 +230,6 @@ void goto_inlinet::replace_return( assignment->source_location=it->source_location; assignment->function=it->function; - if(constrain.is_not_nil() && !constrain.is_true()) - { - codet constrain(ID_bp_constrain); - constrain.reserve_operands(2); - constrain.move_to_operands(assignment->code); - constrain.copy_to_operands(constrain); - } - dest.insert_before_swap(it, *assignment); it++; } @@ -276,20 +267,8 @@ void goto_inlinet::replace_return( code_assign.rhs().type()) code_assign.rhs().make_typecast(code_assign.lhs().type()); - if(constrain.is_not_nil() && !constrain.is_true()) - { - codet constrain(ID_bp_constrain); - constrain.reserve_operands(2); - constrain.move_to_operands(code_assign); - constrain.copy_to_operands(constrain); - it->code=constrain; - it->type=OTHER; - } - else - { - it->code=code_assign; - it->type=ASSIGN; - } + it->code=code_assign; + it->type=ASSIGN; it++; } @@ -346,10 +325,9 @@ void goto_inlinet::insert_function_body( goto_programt::targett target, const exprt &lhs, const symbol_exprt &function, - const exprt::operandst &arguments, - const exprt &constrain) + const exprt::operandst &arguments) { - assert(is_call(target)); + assert(target->is_function_call()); assert(!dest.empty()); assert(goto_function.body_available()); @@ -367,7 +345,7 @@ void goto_inlinet::insert_function_body( for(auto &instruction : body.instructions) instruction.function=target->function; - replace_return(body, lhs, constrain); + replace_return(body, lhs); goto_programt tmp1; parameter_assignments( @@ -448,7 +426,7 @@ void goto_inlinet::insert_function_nobody( const symbol_exprt &function, const exprt::operandst &arguments) { - assert(is_call(target)); + assert(target->is_function_call()); assert(!dest.empty()); const irep_idt identifier=function.get_identifier(); @@ -501,7 +479,7 @@ void goto_inlinet::expand_function_call( const bool force_full, goto_programt::targett target) { - assert(is_call(target)); + assert(target->is_function_call()); assert(!dest.empty()); assert(!transitive || inline_map.empty()); @@ -513,9 +491,8 @@ void goto_inlinet::expand_function_call( exprt lhs; exprt function_expr; exprt::operandst arguments; - exprt constrain; - get_call(target, lhs, function_expr, arguments, constrain); + get_call(target, lhs, function_expr, arguments); if(function_expr.id()!=ID_symbol) return; @@ -576,8 +553,7 @@ void goto_inlinet::expand_function_call( target, lhs, function, - arguments, - constrain); + arguments); progress() << "Inserting " << identifier << " into caller" << eom; progress() << "Number of instructions: " @@ -609,8 +585,7 @@ void goto_inlinet::expand_function_call( target, lhs, function, - arguments, - constrain); + arguments); } } else // no body available @@ -623,45 +598,15 @@ void goto_inlinet::get_call( goto_programt::const_targett it, exprt &lhs, exprt &function, - exprt::operandst &arguments, - exprt &constrain) + exprt::operandst &arguments) { - assert(is_call(it)); - - if(it->is_function_call()) - { - const code_function_callt &call=to_code_function_call(it->code); + assert(it->is_function_call()); - lhs=call.lhs(); - function=call.function(); - arguments=call.arguments(); - constrain=static_cast(get_nil_irep()); - } - else - { - assert(is_bp_call(it)); - - lhs=it->code.op0().op0(); - function=to_symbol_expr(it->code.op0().op1().op0()); - arguments=it->code.op0().op1().op1().operands(); - constrain=it->code.op1(); - } -} - -bool goto_inlinet::is_call(goto_programt::const_targett it) -{ - return it->is_function_call() || is_bp_call(it); -} - -bool goto_inlinet::is_bp_call(goto_programt::const_targett it) -{ - if(!it->is_other()) - return false; + const code_function_callt &call=to_code_function_call(it->code); - return it->code.get(ID_statement)==ID_bp_constrain && - it->code.operands().size()==2 && - it->code.op0().operands().size()==2 && - it->code.op0().op1().get(ID_statement)==ID_function_call; + lhs=call.lhs(); + function=call.function(); + arguments=call.arguments(); } void goto_inlinet::goto_inline( @@ -782,7 +727,7 @@ const goto_inlinet::goto_functiont &goto_inlinet::goto_inline_transitive( Forall_goto_program_instructions(i_it, goto_program) { - if(is_call(i_it)) + if(i_it->is_function_call()) call_list.push_back(i_it); } @@ -855,7 +800,7 @@ bool goto_inlinet::check_inline_map( if(static_cast(target->location_number)<=ln) return false; - if(!is_call(target)) + if(!target->is_function_call()) return false; ln=target->location_number; diff --git a/src/goto-programs/goto_inline_class.h b/src/goto-programs/goto_inline_class.h index c2356759e40..2dad1229191 100644 --- a/src/goto-programs/goto_inline_class.h +++ b/src/goto-programs/goto_inline_class.h @@ -76,17 +76,12 @@ class goto_inlinet:public messaget return inline_log.output_inline_log_json(); } - // is bp call - static bool is_bp_call(goto_programt::const_targett target); - // is normal or bp call - static bool is_call(goto_programt::const_targett target); // get call info of normal or bp call static void get_call( goto_programt::const_targett target, exprt &lhs, exprt &function, - exprt::operandst &arguments, - exprt &constrain); + exprt::operandst &arguments); class goto_inline_logt { @@ -175,8 +170,7 @@ class goto_inlinet:public messaget goto_programt::targett target, const exprt &lhs, const symbol_exprt &function, - const exprt::operandst &arguments, - const exprt &constrain); + const exprt::operandst &arguments); void insert_function_nobody( goto_programt &dest, @@ -187,8 +181,7 @@ class goto_inlinet:public messaget void replace_return( goto_programt &body, - const exprt &lhs, - const exprt &constrain); + const exprt &lhs); void parameter_assignments( const goto_programt::targett target, From 9e4350054a54e09efb73c1c6a9da959d05622a78 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Tue, 29 Aug 2017 22:18:35 +0100 Subject: [PATCH 40/65] remove assert() --- src/goto-programs/goto_inline.cpp | 52 +++++----- src/goto-programs/goto_inline_class.cpp | 123 +++++++++--------------- 2 files changed, 70 insertions(+), 105 deletions(-) diff --git a/src/goto-programs/goto_inline.cpp b/src/goto-programs/goto_inline.cpp index aa8c5a5852d..88ba69c26c0 100644 --- a/src/goto-programs/goto_inline.cpp +++ b/src/goto-programs/goto_inline.cpp @@ -49,40 +49,42 @@ void goto_inline( typedef goto_functionst::goto_functiont goto_functiont; - // find entry point - goto_functionst::function_mapt::iterator it= - goto_functions.function_map.find(goto_functionst::entry_point()); + // find entry point + goto_functionst::function_mapt::iterator it= + goto_functions.function_map.find(goto_functionst::entry_point()); - if(it==goto_functions.function_map.end()) - return; + if(it==goto_functions.function_map.end()) + return; - goto_functiont &goto_function=it->second; - assert(goto_function.body_available()); + goto_functiont &goto_function=it->second; + DATA_INVARIANT( + goto_function.body_available(), + "body of entry point function must be available"); - // gather all calls - // we use non-transitive inlining to avoid the goto program - // copying that goto_inlinet would do otherwise - goto_inlinet::inline_mapt inline_map; + // gather all calls + // we use non-transitive inlining to avoid the goto program + // copying that goto_inlinet would do otherwise + goto_inlinet::inline_mapt inline_map; - Forall_goto_functions(f_it, goto_functions) - { - goto_functiont &goto_function=f_it->second; + Forall_goto_functions(f_it, goto_functions) + { + goto_functiont &goto_function=f_it->second; - if(!goto_function.body_available()) - continue; + if(!goto_function.body_available()) + continue; - goto_inlinet::call_listt &call_list=inline_map[f_it->first]; + goto_inlinet::call_listt &call_list=inline_map[f_it->first]; - goto_programt &goto_program=goto_function.body; + goto_programt &goto_program=goto_function.body; - Forall_goto_program_instructions(i_it, goto_program) - { - if(!i_it->is_function_call()) - continue; + Forall_goto_program_instructions(i_it, goto_program) + { + if(!i_it->is_function_call()) + continue; - call_list.push_back(goto_inlinet::callt(i_it, false)); - } + call_list.push_back(goto_inlinet::callt(i_it, false)); } + } goto_inline.goto_inline( goto_functionst::entry_point(), goto_function, inline_map, true); @@ -198,7 +200,7 @@ void goto_partial_inline( if(goto_function.is_inlined() || goto_program.instructions.size()<=smallfunc_limit) { - assert(i_it->is_function_call()); + INVARIANT(i_it->is_function_call(), "is a call"); call_list.push_back(goto_inlinet::callt(i_it, false)); } } diff --git a/src/goto-programs/goto_inline_class.cpp b/src/goto-programs/goto_inline_class.cpp index 575722c1722..a21768f7732 100644 --- a/src/goto-programs/goto_inline_class.cpp +++ b/src/goto-programs/goto_inline_class.cpp @@ -17,12 +17,13 @@ Author: Daniel Kroening, kroening@kroening.com #include -#include -#include #include +#include +#include +#include +#include #include #include -#include #include "remove_skip.h" #include "goto_inline.h" @@ -34,8 +35,8 @@ void goto_inlinet::parameter_assignments( const exprt::operandst &arguments, // arguments of call goto_programt &dest) { - assert(target->is_function_call()); - assert(dest.empty()); + PRECONDITION(target->is_function_call()); + PRECONDITION(dest.empty()); const source_locationt &source_location=target->source_location; @@ -160,8 +161,8 @@ void goto_inlinet::parameter_destruction( const code_typet &code_type, // type of called function goto_programt &dest) { - assert(target->is_function_call()); - assert(dest.empty()); + PRECONDITION(target->is_function_call()); + PRECONDITION(dest.empty()); const source_locationt &source_location=target->source_location; @@ -204,51 +205,6 @@ void goto_inlinet::replace_return( { if(it->is_return()) { - #if 0 - if(lhs.is_not_nil()) - { - if(it->code.operands().size()!=1) - { - error().source_location=it->code.find_source_location(); - str << "return expects one operand!"; - warning_msg(); - continue; - } - - goto_programt tmp; - goto_programt::targett assignment=tmp.add_instruction(ASSIGN); - - code_assignt code_assign(lhs, it->code.op0()); - - // this may happen if the declared return type at the call site - // differs from the defined return type - if(code_assign.lhs().type()!= - code_assign.rhs().type()) - code_assign.rhs().make_typecast(code_assign.lhs().type()); - - assignment->code=code_assign; - assignment->source_location=it->source_location; - assignment->function=it->function; - - dest.insert_before_swap(it, *assignment); - it++; - } - else if(!it->code.operands().empty()) - { - goto_programt tmp; - goto_programt::targett expression=tmp.add_instruction(OTHER); - - expression->code=codet(ID_expression); - expression->code.move_to_operands(it->code.op0()); - expression->source_location=it->source_location; - expression->function=it->function; - - dest.insert_before_swap(it, *expression); - it++; - } - - it->make_goto(--dest.instructions.end()); - #else if(lhs.is_not_nil()) { if(it->code.operands().size()!=1) @@ -280,7 +236,6 @@ void goto_inlinet::replace_return( it->type=OTHER; it++; } - #endif } } } @@ -327,9 +282,9 @@ void goto_inlinet::insert_function_body( const symbol_exprt &function, const exprt::operandst &arguments) { - assert(target->is_function_call()); - assert(!dest.empty()); - assert(goto_function.body_available()); + PRECONDITION(target->is_function_call()); + PRECONDITION(!dest.empty()); + PRECONDITION(goto_function.body_available()); const irep_idt identifier=function.get_identifier(); @@ -338,7 +293,9 @@ void goto_inlinet::insert_function_body( inline_log.copy_from(goto_function.body, body); goto_programt::instructiont &end=body.instructions.back(); - assert(end.is_end_function()); + DATA_INVARIANT( + end.is_end_function(), + "final instruction of a function must be an END_FUNCTION"); end.type=LOCATION; if(adjust_function) @@ -367,7 +324,9 @@ void goto_inlinet::insert_function_body( t_it=goto_function.body.instructions.begin(); unsigned begin_location_number=t_it->location_number; t_it=--goto_function.body.instructions.end(); - assert(t_it->is_end_function()); + DATA_INVARIANT( + t_it->is_end_function(), + "final instruction of a function must be an END_FUNCTION"); unsigned end_location_number=t_it->location_number; unsigned call_location_number=target->location_number; @@ -426,8 +385,8 @@ void goto_inlinet::insert_function_nobody( const symbol_exprt &function, const exprt::operandst &arguments) { - assert(target->is_function_call()); - assert(!dest.empty()); + PRECONDITION(target->is_function_call()); + PRECONDITION(!dest.empty()); const irep_idt identifier=function.get_identifier(); @@ -479,9 +438,9 @@ void goto_inlinet::expand_function_call( const bool force_full, goto_programt::targett target) { - assert(target->is_function_call()); - assert(!dest.empty()); - assert(!transitive || inline_map.empty()); + PRECONDITION(target->is_function_call()); + PRECONDITION(!dest.empty()); + PRECONDITION(!transitive || inline_map.empty()); #ifdef DEBUG std::cout << "Expanding call:\n"; @@ -600,7 +559,7 @@ void goto_inlinet::get_call( exprt &function, exprt::operandst &arguments) { - assert(it->is_function_call()); + PRECONDITION(it->is_function_call()); const code_function_callt &call=to_code_function_call(it->code); @@ -613,12 +572,12 @@ void goto_inlinet::goto_inline( const inline_mapt &inline_map, const bool force_full) { - assert(check_inline_map(inline_map)); + PRECONDITION(check_inline_map(inline_map)); Forall_goto_functions(f_it, goto_functions) { const irep_idt identifier=f_it->first; - assert(!identifier.empty()); + DATA_INVARIANT(!identifier.empty(), "function name must not be empty"); goto_functiont &goto_function=f_it->second; if(!goto_function.body_available()) @@ -649,14 +608,14 @@ void goto_inlinet::goto_inline_nontransitive( const inline_mapt &inline_map, const bool force_full) { - assert(goto_function.body_available()); + PRECONDITION(goto_function.body_available()); finished_sett::const_iterator f_it=finished_set.find(identifier); if(f_it!=finished_set.end()) return; - assert(check_inline_map(identifier, inline_map)); + PRECONDITION(check_inline_map(identifier, inline_map)); goto_programt &goto_program=goto_function.body; @@ -700,19 +659,23 @@ const goto_inlinet::goto_functiont &goto_inlinet::goto_inline_transitive( const goto_functiont &goto_function, const bool force_full) { - assert(goto_function.body_available()); + PRECONDITION(goto_function.body_available()); cachet::const_iterator c_it=cache.find(identifier); if(c_it!=cache.end()) { const goto_functiont &cached=c_it->second; - assert(cached.body_available()); + DATA_INVARIANT( + cached.body_available(), + "body of cached functions must be available"); return cached; } goto_functiont &cached=cache[identifier]; - assert(cached.body.empty()); + INVARIANT( + cached.body.empty(), + "body of new function in cache must be empty"); progress() << "Creating copy of " << identifier << eom; progress() << "Number of instructions: " @@ -772,7 +735,7 @@ bool goto_inlinet::check_inline_map( goto_functionst::function_mapt::const_iterator f_it= goto_functions.function_map.find(identifier); - assert(f_it!=goto_functions.function_map.end()); + PRECONDITION(f_it!=goto_functions.function_map.end()); inline_mapt::const_iterator im_it=inline_map.find(identifier); @@ -824,11 +787,11 @@ void goto_inlinet::output_inline_map( std::ostream &out, const inline_mapt &inline_map) { - assert(check_inline_map(inline_map)); + PRECONDITION(check_inline_map(inline_map)); for(const auto &it : inline_map) { - const irep_idt id=it.first; + const irep_idt &id=it.first; const call_listt &call_list=it.second; out << "Function: " << id << "\n"; @@ -842,7 +805,7 @@ void goto_inlinet::output_inline_map( !call_list.empty()) { const goto_functiont &goto_function=f_it->second; - assert(goto_function.body_available()); + PRECONDITION(goto_function.body_available()); const goto_programt &goto_program=goto_function.body; @@ -903,12 +866,12 @@ void goto_inlinet::goto_inline_logt::add_segment( const unsigned call_location_number, const irep_idt function) { - assert(!goto_program.empty()); - assert(!function.empty()); - assert(end_location_number>=begin_location_number); + PRECONDITION(!goto_program.empty()); + PRECONDITION(!function.empty()); + PRECONDITION(end_location_number>=begin_location_number); goto_programt::const_targett start=goto_program.instructions.begin(); - assert(log_map.find(start)==log_map.end()); + PRECONDITION(log_map.find(start)==log_map.end()); goto_programt::const_targett end=goto_program.instructions.end(); end--; @@ -927,7 +890,7 @@ void goto_inlinet::goto_inline_logt::copy_from( const goto_programt &from, const goto_programt &to) { - assert(from.instructions.size()==to.instructions.size()); + PRECONDITION(from.instructions.size()==to.instructions.size()); goto_programt::const_targett it1=from.instructions.begin(); goto_programt::const_targett it2=to.instructions.begin(); From ede380f94a18596f224d70fe9c1d72049168c7c4 Mon Sep 17 00:00:00 2001 From: Kareem Khazem Date: Wed, 21 Jun 2017 16:12:29 +0100 Subject: [PATCH 41/65] goto-gcc removes CPROVER macros for native gcc Input programs containing __CPROVER_assume, __CPROVER_assert etc. can now be compiled with goto-gcc as well as goto-cc. Previously, the system compiler would complain about missing function bodies for all of these CPROVER macros. --- appveyor.yml | 1 + regression/Makefile | 10 +- regression/goto-gcc/Makefile | 27 +++++ .../goto-gcc/ignore_cprover_macros/main.c | 6 ++ .../goto-gcc/ignore_cprover_macros/test.desc | 13 +++ src/goto-cc/compile.cpp | 32 +++++- src/goto-cc/compile.h | 27 +++++ src/goto-cc/gcc_mode.cpp | 99 ++++++++++++------- src/goto-cc/gcc_mode.h | 10 +- 9 files changed, 182 insertions(+), 43 deletions(-) create mode 100644 regression/goto-gcc/Makefile create mode 100644 regression/goto-gcc/ignore_cprover_macros/main.c create mode 100644 regression/goto-gcc/ignore_cprover_macros/test.desc diff --git a/appveyor.yml b/appveyor.yml index 3a7c2d5c363..2efea4e75c2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -109,6 +109,7 @@ test_script: rmdir /s /q cbmc-java\classpath1 rmdir /s /q cbmc-java\jar-file3 rmdir /s /q cbmc-java\tableswitch2 + rmdir /s /q goto-gcc rmdir /s /q goto-instrument\slice08 make test diff --git a/regression/Makefile b/regression/Makefile index 3315fb90a6d..ff713b428e4 100644 --- a/regression/Makefile +++ b/regression/Makefile @@ -6,6 +6,7 @@ DIRS = ansi-c \ cbmc-cover \ goto-analyzer \ goto-diff \ + goto-gcc \ goto-instrument \ goto-instrument-typedef \ invariants \ @@ -14,9 +15,14 @@ DIRS = ansi-c \ test-script \ # Empty last line - +# Check for the existence of $dir. Tests under goto-gcc cannot be run on +# Windows, so appveyor.yml unlinks the entire directory under Windows. test: - $(foreach var,$(DIRS), $(MAKE) -C $(var) test || exit 1;) + @for dir in $(DIRS); do \ + if [ -d "$$dir" ]; then \ + $(MAKE) -C "$$dir" test || exit 1; \ + fi; \ + done; clean: @for dir in *; do \ diff --git a/regression/goto-gcc/Makefile b/regression/goto-gcc/Makefile new file mode 100644 index 00000000000..c845d7e2e2a --- /dev/null +++ b/regression/goto-gcc/Makefile @@ -0,0 +1,27 @@ +default: tests.log + +test: + -@ln -s goto-cc ../../src/goto-cc/goto-gcc + @if ! ../test.pl -c ../../../src/goto-cc/goto-gcc ; then \ + ../failed-tests-printer.pl ; \ + exit 1 ; \ + fi + +tests.log: ../test.pl + -@ln -s goto-cc ../../src/goto-cc/goto-gcc + @if ! ../test.pl -c ../../../src/goto-cc/goto-gcc ; then \ + ../failed-tests-printer.pl ; \ + exit 1 ; \ + fi + +show: + @for dir in *; do \ + if [ -d "$$dir" ]; then \ + vim -o "$$dir/*.c" "$$dir/*.out"; \ + fi; \ + done; + +clean: + find -name '*.out' -execdir $(RM) '{}' \; + find -name '*.gb' -execdir $(RM) '{}' \; + $(RM) tests.log diff --git a/regression/goto-gcc/ignore_cprover_macros/main.c b/regression/goto-gcc/ignore_cprover_macros/main.c new file mode 100644 index 00000000000..864f7dac484 --- /dev/null +++ b/regression/goto-gcc/ignore_cprover_macros/main.c @@ -0,0 +1,6 @@ +int main() +{ + unsigned x; + __CPROVER_assume(x); + __CPROVER_assert(x, ""); +} diff --git a/regression/goto-gcc/ignore_cprover_macros/test.desc b/regression/goto-gcc/ignore_cprover_macros/test.desc new file mode 100644 index 00000000000..c542c24273d --- /dev/null +++ b/regression/goto-gcc/ignore_cprover_macros/test.desc @@ -0,0 +1,13 @@ +CORE +main.c + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +^CONVERSION ERROR$ +-- +-- +goto-gcc must define out all CPROVER macros that are used in the +codebase. This test succeeds iff GCC doesn't see the CPROVER macros in +the test file. diff --git a/src/goto-cc/compile.cpp b/src/goto-cc/compile.cpp index c54b6b60f6b..71f0d81160e 100644 --- a/src/goto-cc/compile.cpp +++ b/src/goto-cc/compile.cpp @@ -379,7 +379,7 @@ bool compilet::link() output_file_executable, symbol_table, compiled_functions)) return true; - return false; + return add_written_cprover_symbols(symbol_table); } /// parses source files and writes object files, or keeps the symbols in the @@ -430,6 +430,9 @@ bool compilet::compile() if(write_object_file(cfn, symbol_table, compiled_functions)) return true; + if(add_written_cprover_symbols(symbol_table)) + return true; + symbol_table.clear(); // clean symbol table for next source file. compiled_functions.clear(); } @@ -616,6 +619,7 @@ bool compilet::write_bin_object_file( << "; " << cnt << " have a body." << eom; outfile.close(); + wrote_object=true; return false; } @@ -650,6 +654,7 @@ compilet::compilet(cmdlinet &_cmdline, ui_message_handlert &mh, bool Werror): { mode=COMPILE_LINK_EXECUTABLE; echo_file_name=false; + wrote_object=false; working_directory=get_current_working_directory(); } @@ -724,3 +729,28 @@ void compilet::convert_symbols(goto_functionst &dest) } } } + +bool compilet::add_written_cprover_symbols(const symbol_tablet &symbol_table) +{ + for(const auto &pair : symbol_table.symbols) + { + const irep_idt &name=pair.second.name; + const typet &new_type=pair.second.type; + if(!(has_prefix(id2string(name), CPROVER_PREFIX) && new_type.id()==ID_code)) + continue; + + bool inserted; + std::map::iterator old; + std::tie(old, inserted)=written_macros.insert({name, pair.second}); + + if(!inserted && old->second.type!=new_type) + { + error() << "Incompatible CPROVER macro symbol types:" << eom + << old->second.type.pretty() << "(at " << old->second.location + << ")" << eom << "and" << eom << new_type.pretty() + << "(at " << pair.second.location << ")" << eom; + return true; + } + } + return false; +} diff --git a/src/goto-cc/compile.h b/src/goto-cc/compile.h index d0a521769c1..b0c61d137a3 100644 --- a/src/goto-cc/compile.h +++ b/src/goto-cc/compile.h @@ -72,6 +72,23 @@ class compilet:public language_uit const symbol_tablet &, goto_functionst &); + /// \brief Has this compiler written any object files? + bool wrote_object_files() const { return wrote_object; } + + /// \brief `__CPROVER_...` macros written to object files and their arities + /// + /// \return A mapping from every `__CPROVER` macro that this compiler + /// wrote to one or more object files, to how many parameters that + /// `__CPROVER` macro has. + void cprover_macro_arities(std::map &cprover_macros) const + { + PRECONDITION(wrote_object); + for(const auto &pair : written_macros) + cprover_macros.insert({pair.first, + to_code_type(pair.second.type).parameters().size()}); + } + protected: cmdlinet &cmdline; bool warning_is_fatal; @@ -81,6 +98,16 @@ class compilet:public language_uit void add_compiler_specific_defines(class configt &config) const; void convert_symbols(goto_functionst &dest); + + bool add_written_cprover_symbols(const symbol_tablet &symbol_table); + std::map written_macros; + + // clients must only call add_written_cprover_symbols() if an object + // file has been written. The case where an object file was written + // but there were no __CPROVER symbols in the goto-program is distinct + // from the case where the user forgot to write an object file before + // calling add_written_cprover_symbols(). + bool wrote_object; }; #endif // CPROVER_GOTO_CC_COMPILE_H diff --git a/src/goto-cc/gcc_mode.cpp b/src/goto-cc/gcc_mode.cpp index db33ac5b194..231baff6eb5 100644 --- a/src/goto-cc/gcc_mode.cpp +++ b/src/goto-cc/gcc_mode.cpp @@ -19,10 +19,13 @@ Author: CM Wintersteiger, 2006 #include #endif +#include #include #include #include #include +#include +#include #include #include @@ -337,10 +340,16 @@ int gcc_modet::doit() std::cout << "gcc version 3.4.4 (goto-cc " CBMC_VERSION ")\n"; } + compilet compiler(cmdline, + gcc_message_handler, + cmdline.isset("Werror") && + cmdline.isset("Wextra") && + !cmdline.isset("Wno-error")); + if(cmdline.isset("version")) { if(produce_hybrid_binary) - return run_gcc(); + return run_gcc(compiler); std::cout << '\n' << "Copyright (C) 2006-2014 Daniel Kroening, Christoph Wintersteiger\n" << @@ -354,7 +363,7 @@ int gcc_modet::doit() if(cmdline.isset("dumpversion")) { if(produce_hybrid_binary) - return run_gcc(); + return run_gcc(compiler); std::cout << "3.4.4\n"; return EX_OK; @@ -390,6 +399,24 @@ int gcc_modet::doit() debug() << "GCC mode" << eom; } + // determine actions to be undertaken + if(act_as_ld) + compiler.mode=compilet::LINK_LIBRARY; + else if(cmdline.isset('S')) + compiler.mode=compilet::ASSEMBLE_ONLY; + else if(cmdline.isset('c')) + compiler.mode=compilet::COMPILE_ONLY; + else if(cmdline.isset('E')) + { + compiler.mode=compilet::PREPROCESS_ONLY; + UNREACHABLE; + } + else if(cmdline.isset("shared") || + cmdline.isset('r')) // really not well documented + compiler.mode=compilet::COMPILE_LINK; + else + compiler.mode=compilet::COMPILE_LINK_EXECUTABLE; + // In gcc mode, we have just pass on to gcc to handle the following: // * if -M or -MM is given, we do dependencies only // * preprocessing (-E) @@ -402,7 +429,7 @@ int gcc_modet::doit() cmdline.isset("MM") || cmdline.isset('E') || !cmdline.have_infile_arg()) - return run_gcc(); // exit! + return run_gcc(compiler); // exit! // get configuration config.set(cmdline); @@ -489,30 +516,6 @@ int gcc_modet::doit() if(cmdline.isset("fshort-double")) config.ansi_c.double_width=config.ansi_c.single_width; - // determine actions to be undertaken - compilet compiler(cmdline, - gcc_message_handler, - cmdline.isset("Werror") && - cmdline.isset("Wextra") && - !cmdline.isset("Wno-error")); - - if(act_as_ld) - compiler.mode=compilet::LINK_LIBRARY; - else if(cmdline.isset('S')) - compiler.mode=compilet::ASSEMBLE_ONLY; - else if(cmdline.isset('c')) - compiler.mode=compilet::COMPILE_ONLY; - else if(cmdline.isset('E')) - { - compiler.mode=compilet::PREPROCESS_ONLY; - UNREACHABLE; - } - else if(cmdline.isset("shared") || - cmdline.isset('r')) // really not well documented - compiler.mode=compilet::COMPILE_LINK; - else - compiler.mode=compilet::COMPILE_LINK_EXECUTABLE; - switch(compiler.mode) { case compilet::LINK_LIBRARY: @@ -695,10 +698,10 @@ int gcc_modet::doit() if(compiler.source_files.empty() && compiler.object_files.empty()) - return run_gcc(); // exit! + return run_gcc(compiler); // exit! if(compiler.mode==compilet::ASSEMBLE_ONLY) - return asm_output(act_as_bcc, compiler.source_files); + return asm_output(act_as_bcc, compiler.source_files, compiler); // do all the rest if(compiler.doit()) @@ -707,7 +710,7 @@ int gcc_modet::doit() // We can generate hybrid ELF and Mach-O binaries // containing both executable machine code and the goto-binary. if(produce_hybrid_binary && !act_as_bcc) - return gcc_hybrid_binary(); + return gcc_hybrid_binary(compiler); return EX_OK; } @@ -791,8 +794,7 @@ int gcc_modet::preprocess( return run(new_argv[0], new_argv, cmdline.stdin_file, stdout_file); } -/// run gcc or clang with original command line -int gcc_modet::run_gcc() +int gcc_modet::run_gcc(const compilet &compiler) { PRECONDITION(!cmdline.parsed_argv.empty()); @@ -802,6 +804,28 @@ int gcc_modet::run_gcc() for(const auto &a : cmdline.parsed_argv) new_argv.push_back(a.arg); + if(compiler.wrote_object_files()) + { + // Undefine all __CPROVER macros for the system compiler + std::map arities; + compiler.cprover_macro_arities(arities); + for(const auto &pair : arities) + { + std::ostringstream addition; + addition << "-D" << id2string(pair.first) << "("; + std::vector params(pair.second); + std::iota(params.begin(), params.end(), 'a'); + for(std::vector::iterator it=params.begin(); it!=params.end(); ++it) + { + addition << *it; + if(it+1!=params.end()) + addition << ","; + } + addition << ")= "; + new_argv.push_back(addition.str()); + } + } + // overwrite argv[0] new_argv[0]=native_tool_name; @@ -813,7 +837,7 @@ int gcc_modet::run_gcc() return run(new_argv[0], new_argv, cmdline.stdin_file, ""); } -int gcc_modet::gcc_hybrid_binary() +int gcc_modet::gcc_hybrid_binary(const compilet &compiler) { { bool have_files=false; @@ -861,7 +885,7 @@ int gcc_modet::gcc_hybrid_binary() if(output_files.empty() || (output_files.size()==1 && output_files.front()=="/dev/null")) - return run_gcc(); + return EX_OK; debug() << "Running " << native_tool_name << " to generate hybrid binary" << eom; @@ -893,7 +917,7 @@ int gcc_modet::gcc_hybrid_binary() } objcopy_cmd+="objcopy"; - int result=run_gcc(); + int result=run_gcc(compiler); // merge output from gcc with goto-binaries // using objcopy, or do cleanup if an earlier call failed @@ -975,7 +999,8 @@ int gcc_modet::gcc_hybrid_binary() int gcc_modet::asm_output( bool act_as_bcc, - const std::list &preprocessed_source_files) + const std::list &preprocessed_source_files, + const compilet &compiler) { { bool have_files=false; @@ -996,7 +1021,7 @@ int gcc_modet::asm_output( debug() << "Running " << native_tool_name << " to generate native asm output" << eom; - int result=run_gcc(); + int result=run_gcc(compiler); if(result!=0) // native tool failed return result; diff --git a/src/goto-cc/gcc_mode.h b/src/goto-cc/gcc_mode.h index cd4f1cb1a56..497546ff2a0 100644 --- a/src/goto-cc/gcc_mode.h +++ b/src/goto-cc/gcc_mode.h @@ -18,6 +18,8 @@ Date: June 2006 #include "goto_cc_mode.h" +class compilet; + class gcc_modet:public goto_cc_modet { public: @@ -45,13 +47,15 @@ class gcc_modet:public goto_cc_modet const std::string &dest, bool act_as_bcc); - int run_gcc(); // call gcc with original command line + /// \brief call gcc with original command line + int run_gcc(const compilet &compiler); - int gcc_hybrid_binary(); + int gcc_hybrid_binary(const compilet &compiler); int asm_output( bool act_as_bcc, - const std::list &preprocessed_source_files); + const std::list &preprocessed_source_files, + const compilet &compiler); static bool needs_preprocessing(const std::string &); }; From 1fd8b87a9db1959356bbf5c6419b19a40f4f357d Mon Sep 17 00:00:00 2001 From: Kareem Khazem Date: Fri, 14 Jul 2017 15:27:26 +0100 Subject: [PATCH 42/65] Add header for magic numbers All magic numbers throughout the codebase should eventually be added to this file. --- src/solvers/flattening/boolbv.cpp | 3 ++- src/util/magic.h | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 src/util/magic.h diff --git a/src/solvers/flattening/boolbv.cpp b/src/solvers/flattening/boolbv.cpp index 58b09b0d1bb..eb9612f76ea 100644 --- a/src/solvers/flattening/boolbv.cpp +++ b/src/solvers/flattening/boolbv.cpp @@ -15,6 +15,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include +#include #include #include #include @@ -688,7 +689,7 @@ bool boolbvt::is_unbounded_array(const typet &type) const return true; if(unbounded_array==unbounded_arrayt::U_AUTO) - if(s>1000) // magic number! + if(s>MAX_FLATTENED_ARRAY_SIZE) return true; return false; diff --git a/src/util/magic.h b/src/util/magic.h new file mode 100644 index 00000000000..b3525c2f199 --- /dev/null +++ b/src/util/magic.h @@ -0,0 +1,12 @@ +/// \file +/// \brief Magic numbers used throughout the codebase +/// \author Kareem Khazem + +#ifndef CPROVER_UTIL_MAGIC_H +#define CPROVER_UTIL_MAGIC_H + +#include + +const std::size_t MAX_FLATTENED_ARRAY_SIZE=1000; + +#endif From 85521b0263da63dde74bab2a16455d31043dda23 Mon Sep 17 00:00:00 2001 From: Kareem Khazem Date: Mon, 5 Jun 2017 13:43:53 +0100 Subject: [PATCH 43/65] goto-gcc reads definitions from linker scripts goto-gcc now runs the ls_parse.py script whenever the target codebase is being compiled with a custom linker script (specified with the -T option). goto-gcc then synthesizes the linker script definitions that ls_parse reported, and adds them to the goto-program as if those definitions were defined in the target C program rather than the linker script. This solves a problem where the values of some C variables are inaccessible from CBMC because those variables are defined in the linker script rather than the C codebase. It also solves the problem of CBMC not knowing what memory regions are accessible to the C program, again because the memory regions are declared to be valid in the linker script. This commit also introduces three tests for this functionality. This commit also fixes a small bug in ls_parse.py that made it reject some valid linker scripts. --- .../ansi-c/linker_script_start+end/main.c | 12 + .../ansi-c/linker_script_start+end/script.ld | 22 + .../ansi-c/linker_script_start+end/test.desc | 17 + .../ansi-c/linker_script_start+size/main.c | 12 + .../ansi-c/linker_script_start+size/script.ld | 25 + .../ansi-c/linker_script_start+size/test.desc | 19 + .../ansi-c/linker_script_symbol-only/main.c | 6 + .../linker_script_symbol-only/script.ld | 15 + .../linker_script_symbol-only/test.desc | 15 + scripts/ls_parse.py | 22 +- src/goto-cc/Makefile | 1 + src/goto-cc/gcc_mode.cpp | 35 +- src/goto-cc/gcc_mode.h | 6 +- src/goto-cc/linker_script_merge.cpp | 750 ++++++++++++++++++ src/goto-cc/linker_script_merge.h | 215 +++++ src/goto-programs/goto_program_template.h | 13 + 16 files changed, 1175 insertions(+), 10 deletions(-) create mode 100644 regression/ansi-c/linker_script_start+end/main.c create mode 100644 regression/ansi-c/linker_script_start+end/script.ld create mode 100644 regression/ansi-c/linker_script_start+end/test.desc create mode 100644 regression/ansi-c/linker_script_start+size/main.c create mode 100644 regression/ansi-c/linker_script_start+size/script.ld create mode 100644 regression/ansi-c/linker_script_start+size/test.desc create mode 100644 regression/ansi-c/linker_script_symbol-only/main.c create mode 100644 regression/ansi-c/linker_script_symbol-only/script.ld create mode 100644 regression/ansi-c/linker_script_symbol-only/test.desc create mode 100644 src/goto-cc/linker_script_merge.cpp create mode 100644 src/goto-cc/linker_script_merge.h diff --git a/regression/ansi-c/linker_script_start+end/main.c b/regression/ansi-c/linker_script_start+end/main.c new file mode 100644 index 00000000000..3a83adc35f2 --- /dev/null +++ b/regression/ansi-c/linker_script_start+end/main.c @@ -0,0 +1,12 @@ +extern char src_start[]; +extern char src_end[]; +extern char dst_start[]; + +void *memcpy(void *dest, void *src, unsigned n){ + return (void *)0; +} + +int main(){ + memcpy(dst_start, src_start, (unsigned)src_end - (unsigned)src_start); + return 0; +} diff --git a/regression/ansi-c/linker_script_start+end/script.ld b/regression/ansi-c/linker_script_start+end/script.ld new file mode 100644 index 00000000000..909b7bbd5cd --- /dev/null +++ b/regression/ansi-c/linker_script_start+end/script.ld @@ -0,0 +1,22 @@ +MEMORY { + RAM : ORIGIN = 0x0, LENGTH = 25M +} + +SECTIONS +{ + /* GCC insists on having these */ + .note.gnu.build-id : { } > RAM + .text : { } > RAM + + .src_section : { + src_start = .; + *(.text*) + src_end = .; + } > RAM + + .dst_section : { + dst_start = .; + *(.text*) + dst_end = .; + } > RAM +} diff --git a/regression/ansi-c/linker_script_start+end/test.desc b/regression/ansi-c/linker_script_start+end/test.desc new file mode 100644 index 00000000000..eb50eb8a5c4 --- /dev/null +++ b/regression/ansi-c/linker_script_start+end/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +-o out.gb -T script.ld -nostdlib +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +^CONVERSION ERROR$ +-- +Tesing the functionality of goto-cc's linker script parsing +functionality, ensuring that it can get the values of symbols that are +defined in linker scripts. + +This test ensures that goto-cc and ls-parse can: + +- get the value of a symbol whose value indicates the start of a section; +- get the value of a symbol whose value indicates the end of a section. diff --git a/regression/ansi-c/linker_script_start+size/main.c b/regression/ansi-c/linker_script_start+size/main.c new file mode 100644 index 00000000000..1dcd7e9df42 --- /dev/null +++ b/regression/ansi-c/linker_script_start+size/main.c @@ -0,0 +1,12 @@ +extern char src_start[]; +extern char src_size[]; +extern char dst_start[]; + +void *memcpy(void *dest, void *src, unsigned n){ + return (void *)0; +} + +int main(){ + memcpy(dst_start, src_start, (unsigned)src_size); + return 0; +} diff --git a/regression/ansi-c/linker_script_start+size/script.ld b/regression/ansi-c/linker_script_start+size/script.ld new file mode 100644 index 00000000000..57d0610a5f2 --- /dev/null +++ b/regression/ansi-c/linker_script_start+size/script.ld @@ -0,0 +1,25 @@ + +MEMORY { + RAM : ORIGIN = 0x0, LENGTH = 25M +} + +SECTIONS +{ + /* GCC insists on having these */ + .note.gnu.build-id : { } > RAM + .text : { } > RAM + + .src_section : { + src_start = .; + *(.text*) + src_end = .; + } > RAM + + src_size = src_end - src_start; + + .dst_section : { + dst_start = .; + *(.text*) + dst_end = .; + } > RAM +} diff --git a/regression/ansi-c/linker_script_start+size/test.desc b/regression/ansi-c/linker_script_start+size/test.desc new file mode 100644 index 00000000000..34b07f7bc8b --- /dev/null +++ b/regression/ansi-c/linker_script_start+size/test.desc @@ -0,0 +1,19 @@ +CORE +main.c +-o out.gb -T script.ld -nostdlib +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +^CONVERSION ERROR$ +-- +Tesing the functionality of goto-cc's linker script parsing +functionality, ensuring that it can get the values of symbols that are +defined in linker scripts. + +This test ensures that goto-cc and ls-parse can: + +- get the value of a symbol whose value indicates the start of a section; +- get the value of a symbol whose value indicates the size of a section, + and whose value has been generated through a basic arithmetic + expression in the linker script. diff --git a/regression/ansi-c/linker_script_symbol-only/main.c b/regression/ansi-c/linker_script_symbol-only/main.c new file mode 100644 index 00000000000..62fc32c179c --- /dev/null +++ b/regression/ansi-c/linker_script_symbol-only/main.c @@ -0,0 +1,6 @@ +extern char sym[]; + +int main(){ + int foo = (int)sym; + return 0; +} diff --git a/regression/ansi-c/linker_script_symbol-only/script.ld b/regression/ansi-c/linker_script_symbol-only/script.ld new file mode 100644 index 00000000000..168494d9c13 --- /dev/null +++ b/regression/ansi-c/linker_script_symbol-only/script.ld @@ -0,0 +1,15 @@ +MEMORY { + RAM : ORIGIN = 0x0, LENGTH = 25M +} + +SECTIONS +{ + /* GCC insists on having these */ + .note.gnu.build-id : { } > RAM + .text : { } > RAM + + .src_section : { + sym = .; + *(.text*) + } > RAM +} diff --git a/regression/ansi-c/linker_script_symbol-only/test.desc b/regression/ansi-c/linker_script_symbol-only/test.desc new file mode 100644 index 00000000000..f5d818e7cf6 --- /dev/null +++ b/regression/ansi-c/linker_script_symbol-only/test.desc @@ -0,0 +1,15 @@ +CORE +main.c +-o out.gb -T script.ld -nostdlib +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +^CONVERSION ERROR$ +-- +Tesing the functionality of goto-cc's linker script parsing +functionality, ensuring that it can get the values of symbols that are +defined in linker scripts. + +This test ensures that goto-cc and ls-parse can get the value of a +symbol whose value indicates the start of a section. diff --git a/scripts/ls_parse.py b/scripts/ls_parse.py index 556b55fa50d..5cbaee68319 100755 --- a/scripts/ls_parse.py +++ b/scripts/ls_parse.py @@ -77,7 +77,10 @@ def get_linker_script_data(script): # script is a whitespace. text = " %s" % text - close_brace = re.compile(r"\s}") + # Lex out comments + text = re.sub(r"/\*.*?\*/", " ", text) + + close_brace = re.compile(r"\s}(\s*>\s*\w+)?") memory_cmd = re.compile(r"\sMEMORY\s*{") sections_cmd = re.compile(r"\sSECTIONS\s*{") assign_current = re.compile(r"\s(?P\w+)\s*=\s*\.\s*;") @@ -256,6 +259,7 @@ def close_brace_fun(state, _, buf): sym = state["end-valid"].group("sym") info("'%s' marks the end of section '%s'", sym, sec) state["sections"][sec]["end"] = sym + state["end-valid"] = None else: # Linker script assigned end-of-section to a symbol, but not # the start. this is useless to us. @@ -388,7 +392,7 @@ def symbols_from(object_file): def match_up_addresses(script_data, symbol_table): ret = [] - for data in script_data["sections"].values(): + for name, data in script_data["sections"].items(): ok = False if "size" in data and "start" in data: ok = True @@ -404,6 +408,7 @@ def match_up_addresses(script_data, symbol_table): region["start"] = {"sym": sym, "val": value} if "end" in data and sym == data["end"]: region["end"] = {"sym": sym, "val": value} + region["section"] = name append = False if "size" in region and "start" in region: append = True @@ -424,6 +429,9 @@ def get_region_range(region): e_var = region["end"]["sym"] ret["start"] = start ret["size"] = size + ret["start-symbol"] = s_var + ret["end-symbol"] = e_var + ret["has-end-symbol"] = True ret["annot"] = "__CPROVER_allocated_memory(%s, %d);" % (hex(start), size) ret["commt"] = "from %s to %s" % (s_var, e_var) elif "size" in region: @@ -433,10 +441,14 @@ def get_region_range(region): z_var = region["size"]["sym"] ret["start"] = start ret["size"] = size + ret["start-symbol"] = s_var + ret["size-symbol"] = z_var + ret["has-end-symbol"] = False ret["annot"] = "__CPROVER_allocated_memory(%s, %d);" % (hex(start), size) ret["commt"] = "from %s for %s bytes" % (s_var, z_var) else: raise "Malformatted region\n%s" % str(region) + ret["section"] = region["section"] return ret @@ -502,9 +514,9 @@ def main(): regions = match_up_addresses(script_data, symbol_table) - info(json.dumps(symbol_table, indent=2)) - info(json.dumps(script_data, indent=2)) - info(json.dumps(regions, indent=2)) + info("symbol table %s" % json.dumps(symbol_table, indent=2)) + info("script data %s" % json.dumps(script_data, indent=2)) + info("regions %s" % json.dumps(regions, indent=2)) final = json.dumps(final_json_output(regions, symbol_table), indent=2) diff --git a/src/goto-cc/Makefile b/src/goto-cc/Makefile index 576a5e39505..374ed507b44 100644 --- a/src/goto-cc/Makefile +++ b/src/goto-cc/Makefile @@ -13,6 +13,7 @@ SRC = armcc_cmdline.cpp \ goto_cc_main.cpp \ goto_cc_mode.cpp \ ld_cmdline.cpp \ + linker_script_merge.cpp \ ms_cl_cmdline.cpp \ ms_cl_mode.cpp \ # Empty last line diff --git a/src/goto-cc/gcc_mode.cpp b/src/goto-cc/gcc_mode.cpp index 231baff6eb5..136b29d3489 100644 --- a/src/goto-cc/gcc_mode.cpp +++ b/src/goto-cc/gcc_mode.cpp @@ -19,26 +19,37 @@ Author: CM Wintersteiger, 2006 #include #endif +#include #include #include #include +#include #include #include #include #include +#include + +#include +#include +#include #include #include #include +#include #include #include #include #include #include +#include + +#include #include -#include "compile.h" +#include "linker_script_merge.h" static std::string compiler_name( const cmdlinet &cmdline, @@ -98,6 +109,7 @@ gcc_modet::gcc_modet( produce_hybrid_binary(_produce_hybrid_binary), act_as_ld(base_name=="ld" || base_name.find("goto-ld")!=std::string::npos), + goto_binary_tmp_suffix(".goto-cc-saved"), // Keys are architectures specified in configt::set_arch(). // Values are lists of GCC architectures that can be supplied as @@ -837,7 +849,7 @@ int gcc_modet::run_gcc(const compilet &compiler) return run(new_argv[0], new_argv, cmdline.stdin_file, ""); } -int gcc_modet::gcc_hybrid_binary(const compilet &compiler) +int gcc_modet::gcc_hybrid_binary(compilet &compiler) { { bool have_files=false; @@ -891,17 +903,20 @@ int gcc_modet::gcc_hybrid_binary(const compilet &compiler) << " to generate hybrid binary" << eom; // save the goto-cc output files + std::list goto_binaries; for(std::list::const_iterator it=output_files.begin(); it!=output_files.end(); it++) { - int result=rename(it->c_str(), (*it+".goto-cc-saved").c_str()); + std::string bin_name=*it+goto_binary_tmp_suffix; + int result=rename(it->c_str(), bin_name.c_str()); if(result!=0) { error() << "Rename failed: " << std::strerror(errno) << eom; return result; } + goto_binaries.push_back(bin_name); } std::string objcopy_cmd; @@ -919,6 +934,18 @@ int gcc_modet::gcc_hybrid_binary(const compilet &compiler) int result=run_gcc(compiler); + if(result==0) + { + linker_script_merget ls_merge( + compiler, output_files, goto_binaries, cmdline, gcc_message_handler); + const int fail=ls_merge.add_linker_script_definitions(); + if(fail!=0) + { + error() << "Unable to merge linker script symbols" << eom; + return fail; + } + } + // merge output from gcc with goto-binaries // using objcopy, or do cleanup if an earlier call failed for(std::list::const_iterator @@ -927,7 +954,7 @@ int gcc_modet::gcc_hybrid_binary(const compilet &compiler) it++) { debug() << "merging " << *it << eom; - std::string saved=*it+".goto-cc-saved"; + std::string saved=*it+goto_binary_tmp_suffix; #ifdef __linux__ if(result==0 && !cmdline.isset('c')) diff --git a/src/goto-cc/gcc_mode.h b/src/goto-cc/gcc_mode.h index 497546ff2a0..8d77ed29af1 100644 --- a/src/goto-cc/gcc_mode.h +++ b/src/goto-cc/gcc_mode.h @@ -16,6 +16,7 @@ Date: June 2006 #include +#include "compile.h" #include "goto_cc_mode.h" class compilet; @@ -39,6 +40,9 @@ class gcc_modet:public goto_cc_modet const bool act_as_ld; std::string native_tool_name; + const std::string goto_binary_tmp_suffix; + + /// \brief Associate CBMC architectures with processor names const std::map> arch_map; int preprocess( @@ -50,7 +54,7 @@ class gcc_modet:public goto_cc_modet /// \brief call gcc with original command line int run_gcc(const compilet &compiler); - int gcc_hybrid_binary(const compilet &compiler); + int gcc_hybrid_binary(compilet &compiler); int asm_output( bool act_as_bcc, diff --git a/src/goto-cc/linker_script_merge.cpp b/src/goto-cc/linker_script_merge.cpp new file mode 100644 index 00000000000..f7ee9e0b057 --- /dev/null +++ b/src/goto-cc/linker_script_merge.cpp @@ -0,0 +1,750 @@ +/*******************************************************************\ + +Module: Linker Script Merging + +Author: Kareem Khazem , 2017 + +\*******************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "compile.h" +#include "linker_script_merge.h" + +int linker_script_merget::add_linker_script_definitions() +{ + if(!cmdline.isset('T') || elf_binaries.size()!=1) + return 0; + const std::string &elf_file=*elf_binaries.begin(); + const std::string &goto_file=*goto_binaries.begin(); + + jsont data; + std::list linker_defined_symbols; + int fail=get_linker_script_data( + data, linker_defined_symbols, compiler.symbol_table, elf_file); + if(fail!=0) + return fail; + + fail=linker_data_is_malformed(data); + if(fail!=0) + { + error() << "Malformed linker-script JSON document" << eom; + data.output(error()); + return fail; + } + + symbol_tablet original_st; + goto_functionst original_gf; + fail=read_goto_binary(goto_file, original_st, original_gf, + get_message_handler()); + if(fail!=0) + { + error() << "Unable to read goto binary for linker script merging" << eom; + return fail; + } + + fail=1; + linker_valuest linker_values; + const auto &pair=original_gf.function_map.find(CPROVER_PREFIX "initialize"); + if(pair==original_gf.function_map.end()) + { + error() << "No " << CPROVER_PREFIX "initialize found in goto_functions" + << eom; + return fail; + } + fail=ls_data2instructions( + data, + cmdline.get_value('T'), + pair->second.body, + original_st, + linker_values); + if(fail!=0) + { + error() << "Could not add linkerscript defs to __CPROVER_initialize" << eom; + return fail; + } + + fail=goto_and_object_mismatch(linker_defined_symbols, linker_values); + if(fail!=0) + return fail; + + // The keys of linker_values are exactly the elements of + // linker_defined_symbols, so iterate over linker_values from now on. + + fail=pointerize_linker_defined_symbols(original_gf, original_st, + linker_values); + if(fail!=0) + { + error() << "Could not pointerize all linker-defined expressions" << eom; + return fail; + } + + fail=compiler.write_object_file(goto_file, original_st, original_gf); + if(fail!=0) + error() << "Could not write linkerscript-augmented binary" << eom; + return fail; +} + +linker_script_merget::linker_script_merget( + compilet &compiler, + std::list &elf_binaries, + std::list &goto_binaries, + cmdlinet &cmdline, + message_handlert &message_handler) : + messaget(message_handler), compiler(compiler), + elf_binaries(elf_binaries), goto_binaries(goto_binaries), + cmdline(cmdline), + replacement_predicates( + { + replacement_predicatet("address of array's first member", + [](const exprt expr){ return to_symbol_expr(expr.op0().op0()); }, + [](const exprt expr) + { + return expr.id()==ID_address_of && + expr.type().id()==ID_pointer && + + expr.op0().id()==ID_index && + expr.op0().type().id()==ID_unsignedbv && + + expr.op0().op0().id()==ID_symbol && + expr.op0().op0().type().id()==ID_array && + + expr.op0().op1().id()==ID_constant && + expr.op0().op1().type().id()==ID_signedbv; + }), + replacement_predicatet("address of array", + [](const exprt expr){ return to_symbol_expr(expr.op0()); }, + [](const exprt expr) + { + return expr.id()==ID_address_of && + expr.type().id()==ID_pointer && + + expr.op0().id()==ID_symbol && + expr.op0().type().id()==ID_array; + }), + replacement_predicatet("array variable", + [](const exprt expr){ return to_symbol_expr(expr); }, + [](const exprt expr) + { + return expr.id()==ID_symbol && + expr.type().id()==ID_array; + }), + replacement_predicatet("pointer (does not need pointerizing)", + [](const exprt expr){ return to_symbol_expr(expr); }, + [](const exprt expr) + { + return expr.id()==ID_symbol && + expr.type().id()==ID_pointer; + }) + }) +{} + +int linker_script_merget::pointerize_linker_defined_symbols( + goto_functionst &goto_functions, + symbol_tablet &symbol_table, + const linker_valuest &linker_values) +{ + int ret=0; + // First, pointerize the actual linker-defined symbols + for(const auto &pair : linker_values) + { + const auto &entry=symbol_table.symbols.find(pair.first); + if(entry==symbol_table.symbols.end()) + continue; + entry->second.type=pointer_type(char_type()); + entry->second.is_extern=false; + entry->second.value=pair.second.second; + } + + // Next, find all occurrences of linker-defined symbols that are _values_ + // of some symbol in the symbol table, and pointerize them too + for(auto &pair : symbol_table.symbols) + { + std::list to_pointerize; + symbols_to_pointerize(linker_values, pair.second.value, to_pointerize); + + if(to_pointerize.empty()) + continue; + debug() << "Pointerizing the symbol-table value of symbol " << pair.first + << eom; + int fail=pointerize_subexprs_of( + pair.second.value, to_pointerize, linker_values); + if(to_pointerize.empty() && fail==0) + continue; + ret=1; + for(const auto &sym : to_pointerize) + error() << " Could not pointerize '" << sym.get_identifier() + << "' in symbol table entry " << pair.first << ". Pretty:\n" + << sym.pretty() << "\n"; + error() << eom; + } + + // Finally, pointerize all occurrences of linker-defined symbols in the + // goto program + for(auto &gf : goto_functions.function_map) + { + goto_programt &program=gf.second.body; + Forall_goto_program_instructions(iit, program) + { + for(exprt *insts : std::list({&(iit->code), &(iit->guard)})) + { + std::list to_pointerize; + symbols_to_pointerize(linker_values, *insts, to_pointerize); + if(to_pointerize.empty()) + continue; + debug() << "Pointerizing a program expression..." << eom; + int fail=pointerize_subexprs_of(*insts, to_pointerize, linker_values); + if(to_pointerize.empty() && fail==0) + continue; + ret=1; + for(const auto &sym : to_pointerize) + { + error() << " Could not pointerize '" << sym.get_identifier() + << "' in function " << gf.first << ". Pretty:\n" + << sym.pretty() << "\n"; + error().source_location=iit->source_location; + } + error() << eom; + } + } + } + return ret; +} + +int linker_script_merget::replace_expr( + exprt &old_expr, + const linker_valuest &linker_values, + const symbol_exprt &old_symbol, + const irep_idt &ident, + const std::string &shape) +{ + auto it=linker_values.find(ident); + if(it==linker_values.end()) + { + error() << "Could not find a new expression for linker script-defined " + << "symbol '" << ident << "'" << eom; + return 1; + } + symbol_exprt new_expr=it->second.first; + new_expr.add_source_location()=old_symbol.source_location(); + debug() << "Pointerizing linker-defined symbol '" << ident << "' of shape <" + << shape << ">." << eom; + old_expr=new_expr; + return 0; +} + +int linker_script_merget::pointerize_subexprs_of( + exprt &expr, + std::list &to_pointerize, + const linker_valuest &linker_values) +{ + int fail=0, tmp=0; + for(auto const &pair : linker_values) + for(auto const &pattern : replacement_predicates) + { + if(!pattern.match(expr)) + continue; + const symbol_exprt &inner_symbol=pattern.inner_symbol(expr); + if(pair.first!=inner_symbol.get_identifier()) + continue; + tmp=replace_expr(expr, linker_values, inner_symbol, pair.first, + pattern.description()); + fail=tmp?tmp:fail; + auto result=std::find(to_pointerize.begin(), to_pointerize.end(), + inner_symbol); + if(result==to_pointerize.end()) + { + fail=1; + error() << "Too many removals of '" << inner_symbol.get_identifier() + << "'" << eom; + } + else + to_pointerize.erase(result); + // If we get here, we've just pointerized this expression. That expression + // will be a symbol possibly wrapped in some unary junk, but won't contain + // other symbols as subexpressions that might need to be pointerized. So + // it's safe to bail out here. + return fail; + } + + for(auto &op : expr.operands()) + { + tmp=pointerize_subexprs_of(op, to_pointerize, linker_values); + fail=tmp?tmp:fail; + } + return fail; +} + +void linker_script_merget::symbols_to_pointerize( + const linker_valuest &linker_values, + const exprt &expr, + std::list &to_pointerize) const +{ + for(const auto &op : expr.operands()) + { + if(op.id()!=ID_symbol) + continue; + const symbol_exprt &sym_exp=to_symbol_expr(op); + const auto &pair=linker_values.find(sym_exp.get_identifier()); + if(pair!=linker_values.end()) + to_pointerize.push_back(sym_exp); + } + for(const auto &op : expr.operands()) + symbols_to_pointerize(linker_values, op, to_pointerize); +} + +#if 0 +The current implementation of this function is less precise than the + commented-out version below. To understand the difference between these + implementations, consider the following example: + +Suppose we have a section in the linker script, 100 bytes long, where the +address of the symbol sec_start is the start of the section (value 4096) and the +address of sec_end is the end of that section (value 4196). + +The current implementation synthesizes the goto-version of the following C: + + char __sec_array[100]; + char *sec_start=(&__sec_array[0]); + char *sec_end=((&__sec_array[0])+100); + // Yes, it is 100 not 99. We're pointing to the end of the memory occupied + // by __sec_array, not the last element of __sec_array. + +This is imprecise for the following reason: the actual address of the array and +the pointers shall be some random CBMC-internal address, instead of being 4096 +and 4196. The linker script, on the other hand, would have specified the exact +position of the section, and we even know what the actual values of sec_start +and sec_end are from the object file (these values are in the `addresses` list +of the `data` argument to this function). If the correctness of the code depends +on these actual values, then CBMCs model of the code is too imprecise to verify +this. + +The commented-out version of this function below synthesizes the following: + + char *sec_start=4096; + char *sec_end=4196; + __CPROVER_allocated_memory(4096, 100); + +This code has both the actual addresses of the start and end of the section and +tells CBMC that the intermediate region is valid. However, the allocated_memory +macro does not currently allocate an actual object at the address 4096, so +symbolic execution can fail. In particular, the 'allocated memory' is part of +__CPROVER_memory, which does not have a bounded size; this means that (for +example) calls to memcpy or memset fail, because the first and third arguments +do not have know n size. The commented-out implementation should be reinstated +once this limitation of __CPROVER_allocated_memory has been fixed. + +In either case, no other changes to the rest of the code (outside this function) +should be necessary. The rest of this file converts expressions containing the +linker-defined symbol into pointer types if they were not already, and this is +the right behaviour for both implementations. +#endif +int linker_script_merget::ls_data2instructions( + jsont &data, + const std::string &linker_script, + goto_programt &gp, + symbol_tablet &symbol_table, + linker_valuest &linker_values) +#if 1 +{ + goto_programt::instructionst initialize_instructions=gp.instructions; + std::map truncated_symbols; + for(auto &d : data["regions"].array) + { + bool has_end=d["has-end-symbol"].is_true(); + + std::ostringstream array_name; + array_name << CPROVER_PREFIX << "linkerscript-array_" + << d["start-symbol"].value; + if(has_end) + array_name << "-" << d["end-symbol"].value; + + + // Array symbol_exprt + std::size_t array_size=integer2size_t(string2integer(d["size"].value)); + if(array_size > MAX_FLATTENED_ARRAY_SIZE) + { + warning() << "Object section '" << d["section"].value << "' of size " + << array_size << " is too large to model. Truncating to " + << MAX_FLATTENED_ARRAY_SIZE << " bytes" << eom; + array_size=MAX_FLATTENED_ARRAY_SIZE; + if(!has_end) + truncated_symbols[d["size-symbol"].value]=MAX_FLATTENED_ARRAY_SIZE; + } + + constant_exprt array_size_expr=from_integer(array_size, size_type()); + array_typet array_type(char_type(), array_size_expr); + symbol_exprt array_expr(array_name.str(), array_type); + source_locationt array_loc; + + array_loc.set_file(linker_script); + std::ostringstream array_comment; + array_comment << "Object section '" << d["section"].value << "' of size " + << integer2unsigned(array_size) << " bytes"; + array_loc.set_comment(array_comment.str()); + array_expr.add_source_location()=array_loc; + + // Array start address + index_exprt zero_idx(array_expr, from_integer(0, size_type())); + address_of_exprt array_start(zero_idx); + + // Linker-defined symbol_exprt pointing to start address + symbol_exprt start_sym(d["start-symbol"].value, pointer_type(char_type())); + linker_values[d["start-symbol"].value]=std::make_pair(start_sym, + array_start); + + // Since the value of the pointer will be a random CBMC address, write a + // note about the real address in the object file + auto it=std::find_if(data["addresses"].array.begin(), + data["addresses"].array.end(), + [&d](const jsont &add) + { return add["sym"].value==d["start-symbol"].value; }); + if(it==data["addresses"].array.end()) + { + error() << "Start: Could not find address corresponding to symbol '" + << d["start-symbol"].value << "' (start of section)" << eom; + return 1; + } + source_locationt start_loc; + start_loc.set_file(linker_script); + std::ostringstream start_comment; + start_comment << "Pointer to beginning of object section '" + << d["section"].value << "'. Original address in object file" + << " is " << (*it)["val"].value; + start_loc.set_comment(start_comment.str()); + start_sym.add_source_location()=start_loc; + + // Instruction for start-address pointer in __CPROVER_initialize + code_assignt start_assign(start_sym, array_start); + start_assign.add_source_location()=start_loc; + goto_programt::instructiont start_assign_i; + start_assign_i.make_assignment(start_assign); + start_assign_i.source_location=start_loc; + initialize_instructions.push_front(start_assign_i); + + if(has_end) // Same for pointer to end of array + { + plus_exprt array_end(array_start, array_size_expr); + + symbol_exprt end_sym(d["end-symbol"].value, pointer_type(char_type())); + linker_values[d["end-symbol"].value]=std::make_pair(end_sym, array_end); + + auto it=std::find_if(data["addresses"].array.begin(), + data["addresses"].array.end(), + [&d](const jsont &add) + { return add["sym"].value==d["end-symbol"].value; }); + if(it==data["addresses"].array.end()) + { + error() << "Could not find address corresponding to symbol '" + << d["end-symbol"].value << "' (end of section)" << eom; + return 1; + } + source_locationt end_loc; + end_loc.set_file(linker_script); + std::ostringstream end_comment; + end_comment << "Pointer to end of object section '" + << d["section"].value << "'. Original address in object file" + << " is " << (*it)["val"].value; + end_loc.set_comment(end_comment.str()); + end_sym.add_source_location()=end_loc; + + code_assignt end_assign(end_sym, array_end); + end_assign.add_source_location()=end_loc; + goto_programt::instructiont end_assign_i; + end_assign_i.make_assignment(end_assign); + end_assign_i.source_location=end_loc; + initialize_instructions.push_front(end_assign_i); + } + + // Add the array to the symbol table. We don't add the pointer(s) to the + // symbol table because they were already there, but declared as extern and + // probably with a different type. We change the externness and type in + // pointerize_linker_defined_symbols. + symbolt array_sym; + array_sym.name=array_name.str(); + array_sym.pretty_name=array_name.str(); + array_sym.is_lvalue=array_sym.is_static_lifetime=true; + array_sym.type=array_type; + array_sym.location=array_loc; + symbol_table.add(array_sym); + + // Push the array initialization to the front now, so that it happens before + // the initialization of the symbols that point to it. + namespacet ns(symbol_table); + exprt zi=zero_initializer(array_type, array_loc, ns, *message_handler); + code_assignt array_assign(array_expr, zi); + array_assign.add_source_location()=array_loc; + goto_programt::instructiont array_assign_i; + array_assign_i.make_assignment(array_assign); + array_assign_i.source_location=array_loc; + initialize_instructions.push_front(array_assign_i); + } + + // We've added every linker-defined symbol that marks the start or end of a + // region. But there might be other linker-defined symbols with some random + // address. These will have been declared extern too, so we need to give them + // a value also. Here, we give them the actual value that they have in the + // object file, since we're not assigning any object to them. + for(const auto &d : data["addresses"].array) + { + auto it=linker_values.find(irep_idt(d["sym"].value)); + if(it!=linker_values.end()) + // sym marks the start or end of a region; already dealt with. + continue; + + // Perhaps this is a size symbol for a section whose size we truncated + // earlier. + irep_idt symbol_value; + const auto &pair=truncated_symbols.find(d["sym"].value); + if(pair==truncated_symbols.end()) + symbol_value=d["val"].value; + else + { + debug() << "Truncating the value of symbol " << d["sym"].value << " from " + << d["val"].value << " to " << MAX_FLATTENED_ARRAY_SIZE + << " because it corresponds to the size of a too-large section." + << eom; + symbol_value=std::to_string(MAX_FLATTENED_ARRAY_SIZE); + } + + source_locationt loc; + loc.set_file(linker_script); + loc.set_comment("linker script-defined symbol: char *"+ + d["sym"].value+"="+"(char *)"+id2string(symbol_value)+"u;"); + + symbol_exprt lhs(d["sym"].value, pointer_type(char_type())); + + constant_exprt rhs; + rhs.set_value(integer2binary(string2integer(id2string(symbol_value)), + unsigned_int_type().get_width())); + rhs.type()=unsigned_int_type(); + + exprt rhs_tc(rhs); + rhs_tc.make_typecast(pointer_type(char_type())); + + linker_values[irep_idt(d["sym"].value)]=std::make_pair(lhs, rhs_tc); + + code_assignt assign(lhs, rhs_tc); + assign.add_source_location()=loc; + goto_programt::instructiont assign_i; + assign_i.make_assignment(assign); + assign_i.source_location=loc; + initialize_instructions.push_front(assign_i); + } + return 0; +} +#else +{ + goto_programt::instructionst initialize_instructions=gp.instructions; + for(const auto &d : data["regions"].array) + { + code_function_callt f; + code_typet void_t; + void_t.return_type()=empty_typet(); + f.function()=symbol_exprt(CPROVER_PREFIX "allocated_memory", void_t); + unsigned start=safe_string2unsigned(d["start"].value); + unsigned size=safe_string2unsigned(d["size"].value); + constant_exprt first=from_integer(start, size_type()); + constant_exprt second=from_integer(size, size_type()); + code_function_callt::argumentst args={first, second}; + f.arguments()=args; + + source_locationt loc; + loc.set_file(linker_script); + loc.set_comment("linker script-defined region:\n"+d["commt"].value+":\n"+ + d["annot"].value); + f.add_source_location()=loc; + + goto_programt::instructiont i; + i.make_function_call(f); + initialize_instructions.push_front(i); + } + + if(!symbol_table.has_symbol(CPROVER_PREFIX "allocated_memory")) + { + symbolt sym; + sym.name=CPROVER_PREFIX "allocated_memory"; + sym.pretty_name=CPROVER_PREFIX "allocated_memory"; + sym.is_lvalue=sym.is_static_lifetime=true; + code_typet void_t; + void_t.return_type()=empty_typet(); + sym.type=void_t; + symbol_table.add(sym); + } + + for(const auto &d : data["addresses"].array) + { + source_locationt loc; + loc.set_file(linker_script); + loc.set_comment("linker script-defined symbol: char *"+ + d["sym"].value+"="+"(char *)"+d["val"].value+"u;"); + + symbol_exprt lhs(d["sym"].value, pointer_type(char_type())); + + constant_exprt rhs; + rhs.set_value(integer2binary(string2integer(d["val"].value), + unsigned_int_type().get_width())); + rhs.type()=unsigned_int_type(); + + exprt rhs_tc(rhs); + rhs_tc.make_typecast(pointer_type(char_type())); + + linker_values[irep_idt(d["sym"].value)]=std::make_pair(lhs, rhs_tc); + + code_assignt assign(lhs, rhs_tc); + assign.add_source_location()=loc; + goto_programt::instructiont assign_i; + assign_i.make_assignment(assign); + initialize_instructions.push_front(assign_i); + } + return 0; +} +#endif + +int linker_script_merget::get_linker_script_data( + jsont &linker_data, + std::list &linker_defined_symbols, + const symbol_tablet &symbol_table, + const std::string &out_file) +{ + for(auto const &pair : symbol_table.symbols) + if(pair.second.is_extern && pair.second.value.is_nil() + && pair.second.name!="__CPROVER_memory") + linker_defined_symbols.push_back(pair.second.name); + + std::ostringstream linker_def_str; + std::copy(linker_defined_symbols.begin(), linker_defined_symbols.end(), + std::ostream_iterator(linker_def_str, "\n")); + debug() << "Linker-defined symbols: [" << linker_def_str.str() << "]\n" + << eom; + + temporary_filet linker_def_outfile("goto-cc-linker-info", ".json"); + temporary_filet linker_def_infile("goto-cc-linker-defs", ""); + std::ofstream linker_def_file(linker_def_infile()); + linker_def_file << linker_def_str.str(); + linker_def_file.close(); + + std::vector argv= + { + "ls_parse.py", + "--script", cmdline.get_value('T'), + "--object", out_file, + "--sym-file", linker_def_infile(), + "--out-file", linker_def_outfile() + }; + if(cmdline.isset("verbosity")) + { + unsigned verb=safe_string2unsigned(cmdline.get_value("verbosity")); + if(verb>9) + argv.push_back("--very-verbose"); + else if(verb>4) + argv.push_back("--verbose"); + } + + int rc=run(argv[0], argv, linker_def_infile(), linker_def_outfile()); + if(rc!=0) + { + error() << "Problem parsing linker script" << eom; + return rc; + } + + int fail=parse_json(linker_def_outfile(), get_message_handler(), + linker_data); + if(fail!=0) + error() << "Problem parsing linker script JSON data" << eom; + return fail; +} + +int linker_script_merget::goto_and_object_mismatch( + const std::list &linker_defined_symbols, + const linker_valuest &linker_values) +{ + int fail=0; + for(const auto &sym : linker_defined_symbols) + if(linker_values.find(sym)==linker_values.end()) + { + fail=1; + error() << "Variable '" << sym << "' was declared extern but never given " + << "a value, even in a linker script" << eom; + } + + for(const auto &pair : linker_values) + { + auto it=std::find(linker_defined_symbols.begin(), + linker_defined_symbols.end(), pair.first); + if(it==linker_defined_symbols.end()) + { + fail=1; + error() << "Linker script-defined symbol '" << pair.first << "' was " + << "either defined in the C source code, not declared extern in " + << "the C source code, or does not appear in the C source code" + << eom; + } + } + return fail; +} + +int linker_script_merget::linker_data_is_malformed(const jsont &data) const +{ + return (!(data.is_object() && + data.object.find("regions")!=data.object.end() && + data.object.find("addresses")!=data.object.end() && + data["regions"].is_array() && + data["addresses"].is_array() && + std::all_of(data["addresses"].array.begin(), + data["addresses"].array.end(), + [](jsont j) + { + return j.is_object() && + j.object.find("val")!=j.object.end() && + j.object.find("sym")!=j.object.end() && + j["val"].is_number() && + j["sym"].is_string(); + }) && + std::all_of(data["regions"].array.begin(), + data["regions"].array.end(), + [](jsont j) + { + return j.is_object() && + j.object.find("start")!=j.object.end() && + j.object.find("size")!=j.object.end() && + j.object.find("annot")!=j.object.end() && + j.object.find("commt")!=j.object.end() && + j.object.find("start-symbol")!=j.object.end() && + j.object.find("has-end-symbol")!=j.object.end() && + j.object.find("section")!=j.object.end() && + j["start"].is_number() && + j["size"].is_number() && + j["annot"].is_string() && + j["start-symbol"].is_string() && + j["section"].is_string() && + j["commt"].is_string() && + ( (j["has-end-symbol"].is_true() && + j.object.find("end-symbol")!=j.object.end() && + j["end-symbol"].is_string()) + ||(j["has-end-symbol"].is_false() && + j.object.find("size-symbol")!=j.object.end() && + j.object.find("end-symbol")==j.object.end() && + j["size-symbol"].is_string())); + }))); +} diff --git a/src/goto-cc/linker_script_merge.h b/src/goto-cc/linker_script_merge.h new file mode 100644 index 00000000000..fe45e37d6e6 --- /dev/null +++ b/src/goto-cc/linker_script_merge.h @@ -0,0 +1,215 @@ +/// \file linker_script_merge.h +/// \brief Merge linker script-defined symbols into a goto-program +/// \author Kareem Khazem + +#ifndef CPROVER_GOTO_CC_LINKER_SCRIPT_MERGE_H +#define CPROVER_GOTO_CC_LINKER_SCRIPT_MERGE_H + +#include + +#include +#include + +#include "compile.h" +#include "gcc_cmdline.h" + +/// \brief Patterns of expressions that should be replaced +/// +/// Each instance of this class describes an expression 'shape' that should be +/// replaced with a different expression. The intention is that if some +/// expression matches the pattern described by this replacement_predicatet +/// (i.e. replacement_predicatet::match() returns true), then that expression +/// should be replaced by a new expression. +class replacement_predicatet +{ +public: + replacement_predicatet( + const std::string &description, + const std::function inner_symbol, + const std::function match) + : _description(description), + _inner_symbol(inner_symbol), + _match(match) + {} + + /// \brief a textual description of the expression that we're trying to match + const std::string &description() const + { + return _description; + } + + /// \brief Return the underlying symbol of the matched expression + /// \pre replacement_predicatet::match() returned true + const symbol_exprt &inner_symbol(const exprt &expr) const + { + return _inner_symbol(expr); + } + + /// \brief Predicate: does the given expression match an interesting pattern? + /// + /// If this function returns true, the entire expression should be replaced by + /// a pointer whose underlying symbol is the symbol returned by + /// replacement_predicatet::inner_symbol(). + const bool match(const exprt &expr) const + { + return _match(expr); + }; + +private: + std::string _description; + std::function _inner_symbol; + std::function _match; +}; + +/// \brief Synthesise definitions of symbols that are defined in linker scripts +class linker_script_merget:public messaget +{ +public: + /// \brief Add values of linkerscript-defined symbols to the goto-binary + /// \pre There is a single output file in each of `elf_binaries` and + /// `goto_binaries`, and the codebase is being linked with a custom + /// linker script passed to the compiler with the `-T` option. + /// \post The `__CPROVER_initialize` function contains synthesized definitions + /// for all symbols that are declared in the C codebase and defined in + /// the linker script. + /// \post All uses of these symbols throughout the code base are re-typed to + /// match the type of the synthesized definitions. + /// \post The `__CPROVER_initialize` function contains one + /// `__CPROVER_allocated_memory` annotation for each object file section + /// that is specified in the linker script. + int add_linker_script_definitions(); + + typedef std::map> linker_valuest; + + linker_script_merget( + compilet &compiler, + std::list &elf_binaries, + std::list &goto_binaries, + cmdlinet &cmdline, + message_handlert &message_handler); + +protected: + compilet &compiler; + std::list &elf_binaries; + std::list &goto_binaries; + cmdlinet &cmdline; + + /// \brief The "shapes" of expressions to be replaced by a pointer + /// + /// Whenever this linker_script_merget encounters an expression `expr` in the + /// goto-program---if `rp.match(expr)` returns `true` for some `rp` in this + /// list, and the underlying symbol of `expr` is a linker-defined symbol, then + /// `expr` will be replaced by a pointer whose value is taken from the value + /// in the linker script. + std::list replacement_predicates; + + /// \brief Write linker script definitions to `linker_data`. + int get_linker_script_data( + jsont &linker_data, + std::list &linker_defined_symbols, + const symbol_tablet &symbol_table, + const std::string &out_file); + + /// \brief Write a list of definitions derived from `data` into gp's + /// `instructions` member. + /// \pre `data` is in the format verified by #linker_data_is_malformed. + /// \post For every memory region in `data`, a function call to + /// `__CPROVER_allocated_memory` is prepended to + /// `initialize_instructions`. + /// \post For every symbol in `data`, a declaration and initialization of that + /// symbol is prepended to `initialize_instructions`. + /// \post Every symbol in `data` shall be a key in `linker_values`; the value + /// shall be a constant expression with the actual value of the symbol + /// in the linker script. + int ls_data2instructions( + jsont &data, + const std::string &linker_script, + goto_programt &gp, + symbol_tablet &symbol_table, + linker_valuest &linker_values); + + /// \brief convert the type of linker script-defined symbols to `char*` + /// + /// #ls_data2instructions synthesizes definitions of linker script-defined + /// symbols, and types those definitions as `char*`. This means that if those + /// symbols were declared extern with a different type throughout the target + /// codebase, we need to change all expressions of those symbols to have type + /// `char*` within the goto functions---as well as in the symbol table. + /// + /// The 'canonical' way for linker script-defined symbols to be declared + /// within the codebase is as char[] variables, so we take care of converting + /// those into char*s. However, the frontend occasionally converts expressions + /// like &foo into &foo[0] (where foo is an array), so we have to convert + /// expressions like that even when they don't appear in the original + /// codebase. + /// + /// Note that in general, there is no limitation on what type a linker + /// script-defined symbol should be declared as in the C codebase, because we + /// should only ever be reading its address. So this function is incomplete in + /// that it assumes that linker script-defined symbols have been declared as + /// arrays in the C codebase. If a linker script-defined symbol is declared as + /// some other type, that would likely need some custom logic to be + /// implemented in this function. + /// + /// \post The types of linker-script defined symbols in the symbol table have + /// been converted to `char*`. + /// \post Expressions of the shape `&foo[0]`, `&foo`, and `foo`, where `foo` + /// is a linker-script defined symbol with type array, have been + /// converted to `foo` whose type is `char*`. + int pointerize_linker_defined_symbols( + goto_functionst &goto_functions, + symbol_tablet &symbol_table, + const linker_valuest &linker_values); + + /// \param expr an expr whose subexpressions may need to be pointerized + /// \param to_pointerize The symbols that are contained in the subexpressions + /// that we will pointerize. + /// \param linker_values the names of symbols defined in linker scripts. + /// + /// The subexpressions that we pointerize should be in one-to-one + /// correspondence with the symbols in `to_pointerize`. Every time we + /// pointerize an expression containing a symbol in `to_pointerize`, we remove + /// that symbol from `to_pointerize`. Therefore, when this function returns, + /// `to_pointerize` should be empty. If it is not, then the symbol is + /// contained in a subexpression whose shape is not recognised. + int pointerize_subexprs_of( + exprt &expr, + std::list &to_pointerize, + const linker_valuest &linker_values); + + /// \brief do the actual replacement of an expr with a new pointer expr + int replace_expr( + exprt &old_expr, + const linker_valuest &linker_values, + const symbol_exprt &old_symbol, + const irep_idt &ident, + const std::string &shape); + + /// \brief fill `to_pointerize` with names of linker symbols appearing in expr + void symbols_to_pointerize( + const linker_valuest &linker_values, + const exprt &expr, + std::list &to_pointerize) const; + + /// \brief one-to-one correspondence between extern & linker symbols + /// + /// Check that a string is in `linker_defined_symbols` iff it is a key in the + /// `linker_values` map. The error messages of this function describe what it + /// means for this constraint to be violated. + /// + /// \param linker_defined_symbols the list of symbols that were extern with no + /// value in the goto-program) + /// \param linker_values map from the names of linker-defined symbols from + /// the object file, to synthesized values for those + /// linker symbols. + /// \return `1` if there is some mismatch between the list and map, `0` + /// if everything is OK. + int goto_and_object_mismatch( + const std::list &linker_defined_symbols, + const linker_valuest &linker_values); + + /// \brief Validate output of the `scripts/ls_parse.py` tool + int linker_data_is_malformed(const jsont &data) const; +}; + +#endif // CPROVER_GOTO_CC_LINKER_SCRIPT_MERGE_H diff --git a/src/goto-programs/goto_program_template.h b/src/goto-programs/goto_program_template.h index aa863a5dd0f..846039341b4 100644 --- a/src/goto-programs/goto_program_template.h +++ b/src/goto-programs/goto_program_template.h @@ -239,6 +239,7 @@ class goto_program_templatet void make_dead() { clear(DEAD); } void make_atomic_begin() { clear(ATOMIC_BEGIN); } void make_atomic_end() { clear(ATOMIC_END); } + void make_end_function() { clear(END_FUNCTION); } void make_goto(targett _target) { @@ -252,6 +253,18 @@ class goto_program_templatet guard=g; } + void make_assignment(const codeT &_code) + { + clear(ASSIGN); + code=_code; + } + + void make_decl(const codeT &_code) + { + clear(DECL); + code=_code; + } + void make_function_call(const codeT &_code) { clear(FUNCTION_CALL); From 3947228301c4cc9f33569e55ec62bb680b85418f Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Mon, 4 Sep 2017 14:32:23 +0100 Subject: [PATCH 44/65] Do not overwrite non-zero return codes Failure in calling the native compiler must not be masked by a later successful call to "remove". Follow-up fix to 2655d9861. --- regression/goto-gcc/expect_fail/main.c | 6 ++++++ regression/goto-gcc/expect_fail/test.desc | 8 ++++++++ src/goto-cc/as_mode.cpp | 14 ++++++++------ src/goto-cc/gcc_mode.cpp | 14 ++++++++------ 4 files changed, 30 insertions(+), 12 deletions(-) create mode 100644 regression/goto-gcc/expect_fail/main.c create mode 100644 regression/goto-gcc/expect_fail/test.desc diff --git a/regression/goto-gcc/expect_fail/main.c b/regression/goto-gcc/expect_fail/main.c new file mode 100644 index 00000000000..dfaaeee2f8a --- /dev/null +++ b/regression/goto-gcc/expect_fail/main.c @@ -0,0 +1,6 @@ +int foo(); // this is not defined and should cause linker errors + +int main() +{ + return foo(); +} diff --git a/regression/goto-gcc/expect_fail/test.desc b/regression/goto-gcc/expect_fail/test.desc new file mode 100644 index 00000000000..3a1dab4b7f0 --- /dev/null +++ b/regression/goto-gcc/expect_fail/test.desc @@ -0,0 +1,8 @@ +CORE +main.c + +^EXIT=1$ +^SIGNAL=0$ +-- +^warning: ignoring +^CONVERSION ERROR$ diff --git a/src/goto-cc/as_mode.cpp b/src/goto-cc/as_mode.cpp index 8966c2159da..bf69e209eda 100644 --- a/src/goto-cc/as_mode.cpp +++ b/src/goto-cc/as_mode.cpp @@ -336,11 +336,12 @@ int as_modet::as_hybrid_binary() result=run(objcopy_argv[0], objcopy_argv, "", ""); } - result=remove(saved.c_str()); - if(result!=0) + int remove_result=remove(saved.c_str()); + if(remove_result!=0) { error() << "Remove failed: " << std::strerror(errno) << eom; - return result; + if(result==0) + result=remove_result; } #elif defined(__APPLE__) @@ -362,11 +363,12 @@ int as_modet::as_hybrid_binary() result=run(lipo_argv[0], lipo_argv, "", ""); } - result=remove(saved.c_str()); - if(result!=0) + int remove_result=remove(saved.c_str()); + if(remove_result!=0) { error() << "Remove failed: " << std::strerror(errno) << eom; - return result; + if(result==0) + result=remove_result; } #else diff --git a/src/goto-cc/gcc_mode.cpp b/src/goto-cc/gcc_mode.cpp index 136b29d3489..2c7dbfb3388 100644 --- a/src/goto-cc/gcc_mode.cpp +++ b/src/goto-cc/gcc_mode.cpp @@ -982,11 +982,12 @@ int gcc_modet::gcc_hybrid_binary(compilet &compiler) result=run(objcopy_argv[0], objcopy_argv, "", ""); } - result=remove(saved.c_str()); - if(result!=0) + int remove_result=remove(saved.c_str()); + if(remove_result!=0) { error() << "Remove failed: " << std::strerror(errno) << eom; - return result; + if(result==0) + result=remove_result; } #elif defined(__APPLE__) @@ -1008,11 +1009,12 @@ int gcc_modet::gcc_hybrid_binary(compilet &compiler) result=run(lipo_argv[0], lipo_argv, "", ""); } - result=remove(saved.c_str()); - if(result!=0) + int remove_result=remove(saved.c_str()); + if(remove_result!=0) { error() << "Remove failed: " << std::strerror(errno) << eom; - return result; + if(result==0) + result=remove_result; } #else From 433e139feac55bc42ce4b16dfc37d0e961e21754 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Thu, 24 Aug 2017 14:42:13 +0100 Subject: [PATCH 45/65] Fix verbosity in goto-gcc --- regression/goto-gcc/verbosity1/main.c | 4 ++++ regression/goto-gcc/verbosity1/test.desc | 9 +++++++++ regression/goto-gcc/verbosity2/main.c | 4 ++++ regression/goto-gcc/verbosity2/test.desc | 9 +++++++++ src/goto-cc/gcc_mode.cpp | 16 ++++++++-------- 5 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 regression/goto-gcc/verbosity1/main.c create mode 100644 regression/goto-gcc/verbosity1/test.desc create mode 100644 regression/goto-gcc/verbosity2/main.c create mode 100644 regression/goto-gcc/verbosity2/test.desc diff --git a/regression/goto-gcc/verbosity1/main.c b/regression/goto-gcc/verbosity1/main.c new file mode 100644 index 00000000000..f8b643afbf2 --- /dev/null +++ b/regression/goto-gcc/verbosity1/main.c @@ -0,0 +1,4 @@ +int main() +{ + return 0; +} diff --git a/regression/goto-gcc/verbosity1/test.desc b/regression/goto-gcc/verbosity1/test.desc new file mode 100644 index 00000000000..b2b3ebe5a69 --- /dev/null +++ b/regression/goto-gcc/verbosity1/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--version +^EXIT=0$ +^SIGNAL=0$ +-- +^RUN: .* --version +^warning: ignoring +^CONVERSION ERROR$ diff --git a/regression/goto-gcc/verbosity2/main.c b/regression/goto-gcc/verbosity2/main.c new file mode 100644 index 00000000000..f8b643afbf2 --- /dev/null +++ b/regression/goto-gcc/verbosity2/main.c @@ -0,0 +1,4 @@ +int main() +{ + return 0; +} diff --git a/regression/goto-gcc/verbosity2/test.desc b/regression/goto-gcc/verbosity2/test.desc new file mode 100644 index 00000000000..60419bf77cc --- /dev/null +++ b/regression/goto-gcc/verbosity2/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--version --verbosity 10 +^EXIT=0$ +^SIGNAL=0$ +^RUN: .* --version +-- +^warning: ignoring +^CONVERSION ERROR$ diff --git a/src/goto-cc/gcc_mode.cpp b/src/goto-cc/gcc_mode.cpp index 136b29d3489..77270c66b94 100644 --- a/src/goto-cc/gcc_mode.cpp +++ b/src/goto-cc/gcc_mode.cpp @@ -333,6 +333,14 @@ int gcc_modet::doit() unsigned int verbosity=1; + if(cmdline.isset("Wall") || cmdline.isset("Wextra")) + verbosity=2; + + if(cmdline.isset("verbosity")) + verbosity=unsafe_string2unsigned(cmdline.get_value("verbosity")); + + gcc_message_handler.set_verbosity(verbosity); + bool act_as_bcc= base_name=="bcc" || base_name.find("goto-bcc")!=std::string::npos; @@ -381,14 +389,6 @@ int gcc_modet::doit() return EX_OK; } - if(cmdline.isset("Wall") || cmdline.isset("Wextra")) - verbosity=2; - - if(cmdline.isset("verbosity")) - verbosity=unsafe_string2unsigned(cmdline.get_value("verbosity")); - - gcc_message_handler.set_verbosity(verbosity); - if(act_as_ld) { if(produce_hybrid_binary) From dd5adf788060520b690ff689bad38ccd944a51ca Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Mon, 4 Sep 2017 16:55:32 +0100 Subject: [PATCH 46/65] Properly prepare goto model for (reachability) slice 1. remove_returns must always be called after removing function pointers. 2. reachability_slice requires function pointer removal. --- .../goto-instrument/slice_function_ptr1/main.c | 13 +++++++++++++ .../goto-instrument/slice_function_ptr1/test.desc | 8 ++++++++ .../goto-instrument/slice_function_ptr2/main.c | 13 +++++++++++++ .../goto-instrument/slice_function_ptr2/test.desc | 8 ++++++++ .../goto_instrument_parse_options.cpp | 4 +++- 5 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 regression/goto-instrument/slice_function_ptr1/main.c create mode 100644 regression/goto-instrument/slice_function_ptr1/test.desc create mode 100644 regression/goto-instrument/slice_function_ptr2/main.c create mode 100644 regression/goto-instrument/slice_function_ptr2/test.desc diff --git a/regression/goto-instrument/slice_function_ptr1/main.c b/regression/goto-instrument/slice_function_ptr1/main.c new file mode 100644 index 00000000000..91ed2bf00e0 --- /dev/null +++ b/regression/goto-instrument/slice_function_ptr1/main.c @@ -0,0 +1,13 @@ +#include + +int foo() +{ + assert(0); + return 0; +} + +int main(void) +{ + int (*p)()=&foo; + return p(); +} diff --git a/regression/goto-instrument/slice_function_ptr1/test.desc b/regression/goto-instrument/slice_function_ptr1/test.desc new file mode 100644 index 00000000000..e647a84c958 --- /dev/null +++ b/regression/goto-instrument/slice_function_ptr1/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--full-slice +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/regression/goto-instrument/slice_function_ptr2/main.c b/regression/goto-instrument/slice_function_ptr2/main.c new file mode 100644 index 00000000000..91ed2bf00e0 --- /dev/null +++ b/regression/goto-instrument/slice_function_ptr2/main.c @@ -0,0 +1,13 @@ +#include + +int foo() +{ + assert(0); + return 0; +} + +int main(void) +{ + int (*p)()=&foo; + return p(); +} diff --git a/regression/goto-instrument/slice_function_ptr2/test.desc b/regression/goto-instrument/slice_function_ptr2/test.desc new file mode 100644 index 00000000000..423a2024fb2 --- /dev/null +++ b/regression/goto-instrument/slice_function_ptr2/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--reachability-slice +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/src/goto-instrument/goto_instrument_parse_options.cpp b/src/goto-instrument/goto_instrument_parse_options.cpp index 4c591b77f8e..f7aab087027 100644 --- a/src/goto-instrument/goto_instrument_parse_options.cpp +++ b/src/goto-instrument/goto_instrument_parse_options.cpp @@ -1426,6 +1426,8 @@ void goto_instrument_parse_optionst::instrument_goto_program() // reachability slice? if(cmdline.isset("reachability-slice")) { + do_indirect_call_and_rtti_removal(); + status() << "Performing a reachability slice" << eom; if(cmdline.isset("property")) reachability_slicer(goto_functions, cmdline.get_values("property")); @@ -1436,8 +1438,8 @@ void goto_instrument_parse_optionst::instrument_goto_program() // full slice? if(cmdline.isset("full-slice")) { - remove_returns(symbol_table, goto_functions); do_indirect_call_and_rtti_removal(); + do_remove_returns(); status() << "Performing a full slice" << eom; if(cmdline.isset("property")) From 2e04c176e115bbd85c56e15a158443af1eddbdf0 Mon Sep 17 00:00:00 2001 From: janmroczkowski Date: Fri, 1 Sep 2017 19:10:02 +0100 Subject: [PATCH 47/65] Replace syntactic_difft pointer by automatic variable --- src/goto-diff/goto_diff_parse_options.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/goto-diff/goto_diff_parse_options.cpp b/src/goto-diff/goto_diff_parse_options.cpp index 8fd0f19ca06..c0be3f06694 100644 --- a/src/goto-diff/goto_diff_parse_options.cpp +++ b/src/goto-diff/goto_diff_parse_options.cpp @@ -319,14 +319,10 @@ int goto_diff_parse_optionst::doit() return 0; } - std::unique_ptr goto_diff= - util_make_unique( - goto_model1, goto_model2, get_message_handler()); - goto_diff->set_ui(get_ui()); - - (*goto_diff)(); - - goto_diff->output_functions(std::cout); + syntactic_difft sd(goto_model1, goto_model2, get_message_handler()); + sd.set_ui(get_ui()); + sd(); + sd.output_functions(std::cout); return 0; } From dce6ae141ad11ce4a5c5bbd792f0a1a90adb65c0 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Tue, 5 Sep 2017 13:47:28 +0100 Subject: [PATCH 48/65] Improve filter_by_diff.py and friends * Attempts to cope with invalid UTF-8 (present in a few CBMC files) using iconv * Splits the filter-by-diff job into two stages (diff -> JSON description of interesting lines and JSON -> filtered output) This means that run_diff.sh CPPLINT is now practical, and produces a report of the linting problems in develop but not in master (around 150 lines as of the time of writing) in about 2 minutes. --- scripts/diff_to_added_lines.py | 46 ++++++++++++++++++++++++++++ scripts/filter_by_diff.py | 53 -------------------------------- scripts/filter_by_lines.py | 56 ++++++++++++++++++++++++++++++++++ scripts/run_diff.sh | 25 ++++++++++----- 4 files changed, 120 insertions(+), 60 deletions(-) create mode 100755 scripts/diff_to_added_lines.py delete mode 100755 scripts/filter_by_diff.py create mode 100755 scripts/filter_by_lines.py diff --git a/scripts/diff_to_added_lines.py b/scripts/diff_to_added_lines.py new file mode 100755 index 00000000000..09c7f89f547 --- /dev/null +++ b/scripts/diff_to_added_lines.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python + +from __future__ import print_function + +def diff_to_added_lines(diff_file, repository_root, out_stream): + + import unidiff + import os.path + import json + + # Create a set of all the files and the specific lines within that file that are in the diff + added_lines = dict() + + for file_in_diff in unidiff.PatchSet.from_filename(diff_file): + filename = file_in_diff.target_file + # Skip files deleted in the tip (b side of the diff): + if filename == "/dev/null": + continue + assert filename.startswith("b/") + filename = os.path.join(repository_root, filename[2:]) + if filename not in added_lines: + added_lines[filename] = [] + added_lines[filename].append(0) + for diff_hunk in file_in_diff: + for diff_line in diff_hunk: + if diff_line.line_type == "+": + if filename not in added_lines: + added_lines[filename] = [] + added_lines[filename].append(diff_line.target_line_no) + + json.dump(added_lines, out_stream) + +if __name__ == "__main__": + + import sys + + if len(sys.argv) != 3: + print("diff_to_added_lines.py: converts a unified-diff file into a JSON dictionary mapping filenames onto an array of added or modified line numbers", file=sys.stderr) + print("Usage: diff_to_added_lines.py diff.patch repository_root_directory", file=sys.stderr) + + sys.exit(1) + + diff_to_added_lines(sys.argv[1], sys.argv[2], sys.stdout) + +diff_file = sys.argv[1] +repository_root = sys.argv[2] diff --git a/scripts/filter_by_diff.py b/scripts/filter_by_diff.py deleted file mode 100755 index 3e7689ddf5b..00000000000 --- a/scripts/filter_by_diff.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python - -import sys -import unidiff -import os.path - -if len(sys.argv) != 4: - print >>sys.stderr, "Usage: filter_by_diff.py diffed_file diff.patch repository_root_directory < warnings.txt" - sys.exit(1) - -diffed_file = sys.argv[1] -diff_file = sys.argv[2] -repository_root = sys.argv[3] - -# Create a set of all the files and the specific lines within that file that are in the diff -added_lines = set() -for diff_file in unidiff.PatchSet.from_filename(diff_file): - filename = diff_file.target_file - # Skip files deleted in the tip (b side of the diff): - if filename == "/dev/null": - continue - assert filename.startswith("b/") - filename = os.path.join(repository_root, filename[2:]) - if filename != diffed_file: - continue - added_lines.add((filename, 0)) - for diff_hunk in diff_file: - for diff_line in diff_hunk: - if diff_line.line_type == "+": - added_lines.add((filename, diff_line.target_line_no)) - -# Print the lines that are in the set -found = False -for line in sys.stdin: - line_parts = line.split(":") - if len(line_parts) < 3: - if found: - # Print lines between a matching warning and the next warning - sys.stdout.write(line) - continue - try: - linenum = int(line_parts[1]) - found = False - filename = line_parts[0] - if not repository_root in filename: - filename = os.path.join(repository_root, line_parts[0]) - if (filename, linenum) in added_lines: - found = True - sys.stdout.write(line) - except ValueError: - if found: - sys.stdout.write(line) - continue diff --git a/scripts/filter_by_lines.py b/scripts/filter_by_lines.py new file mode 100755 index 00000000000..37c0cb41d83 --- /dev/null +++ b/scripts/filter_by_lines.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python + +from __future__ import print_function + +def filter_by_lines(diffed_file, added_lines_file, repository_root, in_stream, out_stream): + + import os.path + import json + + diffed_file = sys.argv[1] + added_lines_file = sys.argv[2] + repository_root = sys.argv[3] + + # Get a set of all the files and the specific lines within that file to keep: + with open(added_lines_file, "r") as f: + added_lines = json.load(f) + + # added_lines is a dict filename -> line_number list + # Make those into line_number sets instead: + + for k in added_lines: + added_lines[k] = set(added_lines[k]) + + # Print the lines that are in the set + found = False + for line in in_stream: + line_parts = line.split(":") + if len(line_parts) < 3: + if found: + # Print lines between a matching warning and the next warning + out_stream.write(line) + continue + try: + linenum = int(line_parts[1]) + found = False + filename = line_parts[0] + if not repository_root in filename: + filename = os.path.join(repository_root, line_parts[0]) + if filename in added_lines and linenum in added_lines[filename]: + found = True + out_stream.write(line) + except ValueError: + if found: + out_stream.write(line) + continue + +if __name__ == "__main__": + + import sys + + if len(sys.argv) != 4: + print("filter_by_lines.py: filters lines of the form filename:line_number:message, retaining those matching a particular filename and list of line numbers", file=sys.stderr) + print("Usage: filter_by_lines.py diffed_file added_lines.json repository_root_directory < warnings.txt", file=sys.stderr) + sys.exit(1) + + filter_by_lines(sys.argv[1], sys.argv[2], sys.argv[3], sys.stdin, sys.stdout) diff --git a/scripts/run_diff.sh b/scripts/run_diff.sh index 0e388537fb4..fee1f7daf24 100755 --- a/scripts/run_diff.sh +++ b/scripts/run_diff.sh @@ -16,15 +16,21 @@ then exit 1 fi -if ! [[ -e $script_folder/filter_by_diff.py ]] +if ! [[ -e $script_folder/filter_by_lines.py ]] then echo "Filter script could not be found in the $script_folder directory" - echo "Ensure filter_by_diff.py is inside the $script_folder directory then run again" + echo "Ensure filter_by_lines.py is inside the $script_folder directory then run again" exit 1 fi if [[ "$mode" == "CPPLINT" ]] then + if ! which iconv >/dev/null + then + echo "Couldn't find iconv in current path. Please install and try again" + exit 1 + fi + if ! [[ -e $script_folder/cpplint.py ]] then echo "Lint script could not be found in the $script_folder directory" @@ -76,17 +82,22 @@ git_start=`git merge-base $git_start $git_merge_base_end` cleanup() { - rm -f $diff_file + rm -f $diff_file $added_lines_file } trap cleanup EXIT diff_file=`mktemp` +added_lines_file=`mktemp` + +# Pass the output through iconv to remove any invalid UTF-8 (diff_to_added_lines.py will die otherwise) + +git diff $git_start $git_end | iconv -t utf-8 -c > $diff_file -git diff $git_start $git_end > $diff_file +# Get the list of files that have changed, that end with lintable extensions +diff_files=`git diff --name-only $git_start $git_end | grep "\.\(\(cpp\)\|\(hh\)\|\(cc\)\|h\)$" || true` -# Get the list of files that have changed -diff_files=`git diff --name-only $git_start $git_end` +$script_folder/diff_to_added_lines.py $diff_file $absolute_repository_root > $added_lines_file for file in $diff_files; do file=$absolute_repository_root/$file @@ -98,7 +109,7 @@ for file in $diff_files; do # Run the linting script and filter: # The errors from the linter go to STDERR so must be redirected to STDOUT - result=`eval $cmd | $script_folder/filter_by_diff.py $file $diff_file $absolute_repository_root` + result=`eval $cmd | $script_folder/filter_by_diff.py $file $added_lines_file $absolute_repository_root` # Providing some errors were relevant we print them out if [ "$result" ] From 389221ebee1e6a3dced6ca6aa8e7ef99155707f6 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 6 Sep 2017 11:06:28 +0100 Subject: [PATCH 49/65] run_diff.sh shellcheck fixes * Replace backticks with $() * Double-quote filenames that might conceivably contain troublesome special chars (*, space etc) --- scripts/run_diff.sh | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/scripts/run_diff.sh b/scripts/run_diff.sh index fee1f7daf24..aed0d24ddb0 100755 --- a/scripts/run_diff.sh +++ b/scripts/run_diff.sh @@ -2,8 +2,8 @@ set -e -script_folder=`dirname $0` -absolute_repository_root=`git rev-parse --show-toplevel` +script_folder=$(dirname "$0") +absolute_repository_root=$(git rev-parse --show-toplevel) mode=$1 modes="CPPLINT | DOXYGEN" @@ -16,7 +16,7 @@ then exit 1 fi -if ! [[ -e $script_folder/filter_by_lines.py ]] +if ! [[ -e ${script_folder}/filter_by_lines.py ]] then echo "Filter script could not be found in the $script_folder directory" echo "Ensure filter_by_lines.py is inside the $script_folder directory then run again" @@ -31,13 +31,13 @@ then exit 1 fi - if ! [[ -e $script_folder/cpplint.py ]] + if ! [[ -e "${script_folder}/cpplint.py" ]] then echo "Lint script could not be found in the $script_folder directory" echo "Ensure cpplint.py is inside the $script_folder directory then run again" exit 1 else - cmd='$script_folder/cpplint.py $file 2>&1 >/dev/null' + cmd='${script_folder}/cpplint.py $file 2>&1 >/dev/null' fi elif [[ "$mode" == "DOXYGEN" ]] then @@ -78,26 +78,26 @@ else git_merge_base_end="HEAD" fi -git_start=`git merge-base $git_start $git_merge_base_end` +git_start=$(git merge-base $git_start $git_merge_base_end) cleanup() { - rm -f $diff_file $added_lines_file + rm -f "$diff_file" "$added_lines_file" } trap cleanup EXIT -diff_file=`mktemp` -added_lines_file=`mktemp` +diff_file=$(mktemp) +added_lines_file=$(mktemp) # Pass the output through iconv to remove any invalid UTF-8 (diff_to_added_lines.py will die otherwise) -git diff $git_start $git_end | iconv -t utf-8 -c > $diff_file +git diff $git_start $git_end | iconv -t utf-8 -c > "$diff_file" # Get the list of files that have changed, that end with lintable extensions -diff_files=`git diff --name-only $git_start $git_end | grep "\.\(\(cpp\)\|\(hh\)\|\(cc\)\|h\)$" || true` +diff_files=$(git diff --name-only $git_start $git_end | grep "\.\(\(cpp\)\|\(hh\)\|\(cc\)\|h\)$" || true) -$script_folder/diff_to_added_lines.py $diff_file $absolute_repository_root > $added_lines_file +"${script_folder}/diff_to_added_lines.py" "$diff_file" "$absolute_repository_root" > "$added_lines_file" for file in $diff_files; do file=$absolute_repository_root/$file @@ -109,7 +109,7 @@ for file in $diff_files; do # Run the linting script and filter: # The errors from the linter go to STDERR so must be redirected to STDOUT - result=`eval $cmd | $script_folder/filter_by_diff.py $file $added_lines_file $absolute_repository_root` + result=$(eval $cmd | "${script_folder}/filter_by_lines.py" "$file" "$added_lines_file" "$absolute_repository_root") # Providing some errors were relevant we print them out if [ "$result" ] From b28e701228d960a1e3c26ce8422eac02f11de96c Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Mon, 4 Sep 2017 17:04:15 +0000 Subject: [PATCH 50/65] fixup! variants of service functions for goto_modelt --- src/goto-programs/replace_java_nondet.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/goto-programs/replace_java_nondet.cpp b/src/goto-programs/replace_java_nondet.cpp index 8261bb087ea..b030cbaa312 100644 --- a/src/goto-programs/replace_java_nondet.cpp +++ b/src/goto-programs/replace_java_nondet.cpp @@ -251,4 +251,3 @@ void replace_java_nondet(goto_modelt &goto_model) { replace_java_nondet(goto_model.goto_functions); } - From fd5692102c7bac0e654b58a709c59d0e6716c295 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Mon, 4 Sep 2017 17:37:17 +0000 Subject: [PATCH 51/65] fixup! Fix and run cbmc-cover tests --- regression/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/regression/Makefile b/regression/Makefile index ff713b428e4..d47df3994cc 100644 --- a/regression/Makefile +++ b/regression/Makefile @@ -1,9 +1,9 @@ DIRS = ansi-c \ cbmc \ - cpp \ + cbmc-cover \ cbmc-java \ cbmc-java-inheritance \ - cbmc-cover \ + cpp \ goto-analyzer \ goto-diff \ goto-gcc \ From 8054162c43705cdfbfb277be68bb766e366dca02 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Mon, 4 Sep 2017 17:52:34 +0000 Subject: [PATCH 52/65] fixup! Instrument string-refinement code such that null-pointer checks are detected --- src/java_bytecode/java_utils.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/java_bytecode/java_utils.h b/src/java_bytecode/java_utils.h index 59405c9f9c6..ed26fe1caf6 100644 --- a/src/java_bytecode/java_utils.h +++ b/src/java_bytecode/java_utils.h @@ -6,15 +6,12 @@ Author: Daniel Kroening, kroening@kroening.com \*******************************************************************/ -#include -#include -#include - -#include "java_bytecode_parse_tree.h" #ifndef CPROVER_JAVA_BYTECODE_JAVA_UTILS_H #define CPROVER_JAVA_BYTECODE_JAVA_UTILS_H -#include +#include +#include +#include bool java_is_array_type(const typet &type); From 7d261396dc2a1fc1a476ab2fa817571f681be0ee Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Mon, 4 Sep 2017 18:00:24 +0000 Subject: [PATCH 53/65] fixup! Replace BV_ADDR_BITS by config setting --- src/solvers/flattening/pointer_logic.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/solvers/flattening/pointer_logic.h b/src/solvers/flattening/pointer_logic.h index 2ce6dee37aa..d094dbd8523 100644 --- a/src/solvers/flattening/pointer_logic.h +++ b/src/solvers/flattening/pointer_logic.h @@ -18,8 +18,6 @@ Author: Daniel Kroening, kroening@kroening.com class namespacet; -class namespacet; - class pointer_logict { public: From d5db0bc0875b4247395bd29661f6f263aaf3b36f Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 5 Sep 2017 09:41:26 +0000 Subject: [PATCH 54/65] fixup! added a test case for combination use of forall/exists/not. --- regression/cbmc/Quantifiers-assertion/test.desc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regression/cbmc/Quantifiers-assertion/test.desc b/regression/cbmc/Quantifiers-assertion/test.desc index 555f7b0e61f..df26ad98dbe 100644 --- a/regression/cbmc/Quantifiers-assertion/test.desc +++ b/regression/cbmc/Quantifiers-assertion/test.desc @@ -9,4 +9,4 @@ main.c ^\[main.assertion.5\] NotForall-Forall: successful: SUCCESS$ ^\[main.assertion.6\] NotForall-NotForall: successful: SUCCESS$ ^\*\* 2 of 6 failed \(2 iterations\)$ -^\VERIFICATION FAILED$ +^VERIFICATION FAILED$ From 191f37198025013c4fd5388ff5b3764674e53fd4 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 5 Sep 2017 09:41:58 +0000 Subject: [PATCH 55/65] fixup! a right place to implement the quantifier handling. --- regression/cbmc/Quantifiers-assignment/test.desc | 2 +- regression/cbmc/Quantifiers-if/test.desc | 2 +- regression/cbmc/Quantifiers-not/test.desc | 2 +- regression/cbmc/Quantifiers-type/test.desc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/regression/cbmc/Quantifiers-assignment/test.desc b/regression/cbmc/Quantifiers-assignment/test.desc index 289e8a47efc..ca5f55d51a2 100644 --- a/regression/cbmc/Quantifiers-assignment/test.desc +++ b/regression/cbmc/Quantifiers-assignment/test.desc @@ -7,4 +7,4 @@ main.c ^\[main.assertion.3\] assertion z1: SUCCESS$ ^\[main.assertion.4\] assertion z2: SUCCESS$ ^\*\* 1 of 4 failed \(2 iterations\)$ -^\VERIFICATION FAILED$ +^VERIFICATION FAILED$ diff --git a/regression/cbmc/Quantifiers-if/test.desc b/regression/cbmc/Quantifiers-if/test.desc index be4945b25ef..7685cf4284a 100644 --- a/regression/cbmc/Quantifiers-if/test.desc +++ b/regression/cbmc/Quantifiers-if/test.desc @@ -8,4 +8,4 @@ main.c ^\[main.assertion.4\] failure 3: FAILURE$ ^\[main.assertion.5\] success 2: SUCCESS$ ^\*\* 3 of 5 failed \(2 iterations\)$ -^\VERIFICATION FAILED$ +^VERIFICATION FAILED$ diff --git a/regression/cbmc/Quantifiers-not/test.desc b/regression/cbmc/Quantifiers-not/test.desc index 2e862045758..b22b6666f14 100644 --- a/regression/cbmc/Quantifiers-not/test.desc +++ b/regression/cbmc/Quantifiers-not/test.desc @@ -8,4 +8,4 @@ main.c ^\[main.assertion.4\] success 3: SUCCESS$ ^\[main.assertion.5\] failure 2: FAILURE$ ^\*\* 2 of 5 failed \(2 iterations\)$ -^\VERIFICATION FAILED$ +^VERIFICATION FAILED$ diff --git a/regression/cbmc/Quantifiers-type/test.desc b/regression/cbmc/Quantifiers-type/test.desc index b0b25cc9903..a3939c6a78a 100644 --- a/regression/cbmc/Quantifiers-type/test.desc +++ b/regression/cbmc/Quantifiers-type/test.desc @@ -5,4 +5,4 @@ main.c ^\[main.assertion.1\] assertion tmp_if_expr\$1: FAILURE$ ^\[main.assertion.2\] assertion tmp_if_expr\$2: SUCCESS$ ^\*\* 1 of 2 failed \(2 iterations\)$ -^\VERIFICATION FAILED$ +^VERIFICATION FAILED$ From 24be89c7bb315a81800f3059f64889912a30e019 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 5 Sep 2017 09:43:09 +0000 Subject: [PATCH 56/65] fixup! simplify \'not exists\' to the form of \'forall not\' --- regression/cbmc/Quantifiers-not-exists/test.desc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regression/cbmc/Quantifiers-not-exists/test.desc b/regression/cbmc/Quantifiers-not-exists/test.desc index 630e54eb224..63ff98c10ad 100644 --- a/regression/cbmc/Quantifiers-not-exists/test.desc +++ b/regression/cbmc/Quantifiers-not-exists/test.desc @@ -9,4 +9,4 @@ main.c ^\[main.assertion.5\] assertion tmp_if_expr\$12: SUCCESS$ ^\[main.assertion.6\] assertion tmp_if_expr\$15: SUCCESS$ ^\*\* 0 of 6 failed \(1 iteration\)$ -^\VERIFICATION SUCCESSFUL$ +^VERIFICATION SUCCESSFUL$ From dfd00d3160c0af5e98b37f3d0ee999ccafef19b3 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 5 Sep 2017 11:21:22 +0000 Subject: [PATCH 57/65] fixup! Translate exprt to/from miniBDD --- src/solvers/prop/bdd_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/prop/bdd_expr.cpp b/src/solvers/prop/bdd_expr.cpp index 2a5b4ffa786..01dacc19048 100644 --- a/src/solvers/prop/bdd_expr.cpp +++ b/src/solvers/prop/bdd_expr.cpp @@ -122,7 +122,7 @@ exprt bdd_exprt::as_expr(const mini_bddt &r) const } else if(r.high().is_false()) { - if(r.high().is_true()) + if(r.low().is_true()) return not_exprt(n_expr); else return and_exprt(not_exprt(n_expr), as_expr(r.low())); From 66719a9f8d7971b66c5dfe7832898aa66313a641 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 5 Sep 2017 13:10:42 +0000 Subject: [PATCH 58/65] fixup! goto-instrument --print-path-lengths: statistics about control-flow graph paths --- src/goto-instrument/goto_instrument_parse_options.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/goto-instrument/goto_instrument_parse_options.cpp b/src/goto-instrument/goto_instrument_parse_options.cpp index f7aab087027..7d47a5a4771 100644 --- a/src/goto-instrument/goto_instrument_parse_options.cpp +++ b/src/goto-instrument/goto_instrument_parse_options.cpp @@ -1489,6 +1489,8 @@ void goto_instrument_parse_optionst::help() " --show-natural-loops show natural loop heads\n" // NOLINTNEXTLINE(whitespace/line_length) " --list-calls-args list all function calls with their arguments\n" + // NOLINTNEXTLINE(whitespace/line_length) + " --print-path-lengths print statistics about control-flow graph paths\n" "\n" "Safety checks:\n" " --no-assertions ignore user assertions\n" From f12c7909ee64cd637ff36a47c71309a25090a807 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 5 Sep 2017 13:39:30 +0000 Subject: [PATCH 59/65] fixup! fixup! Add --drop-unused-functions option --- src/goto-instrument/goto_instrument_parse_options.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/goto-instrument/goto_instrument_parse_options.cpp b/src/goto-instrument/goto_instrument_parse_options.cpp index 7d47a5a4771..be77888ad47 100644 --- a/src/goto-instrument/goto_instrument_parse_options.cpp +++ b/src/goto-instrument/goto_instrument_parse_options.cpp @@ -1482,6 +1482,7 @@ void goto_instrument_parse_optionst::help() " --show-symbol-table show symbol table\n" " --list-symbols list symbols with type information\n" HELP_SHOW_GOTO_FUNCTIONS + " --drop-unused-functions drop functions trivially unreachable from main function\n" // NOLINT(*) " --print-internal-representation\n" // NOLINTNEXTLINE(*) " show verbose internal representation of the program\n" " --list-undefined-functions list functions without body\n" From 82ab237b09b940d08cdc2674618d0c86c1fa5622 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 5 Sep 2017 13:54:10 +0000 Subject: [PATCH 60/65] fixup! Split java nondet pass in two --- src/goto-programs/convert_nondet.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/goto-programs/convert_nondet.cpp b/src/goto-programs/convert_nondet.cpp index d55afbe91a1..b329a41ddbc 100644 --- a/src/goto-programs/convert_nondet.cpp +++ b/src/goto-programs/convert_nondet.cpp @@ -67,7 +67,8 @@ static goto_programt::targett insert_nondet_init_code( } // Although, if the type is a ptr-to-void then we also want to bail - if(lhs.type().subtype().id()==ID_empty) + if(lhs.type().subtype().id()==ID_empty || + lhs.type().subtype().id()==ID_code) { return next_instr; } From 2060b34de7481cc9f058b374286d9f957b1070bf Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 5 Sep 2017 14:44:46 +0000 Subject: [PATCH 61/65] fixup! Added __CPROVER_array_replace to complement __CPROVER_array_set --- src/goto-programs/goto_convert_class.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/goto-programs/goto_convert_class.h b/src/goto-programs/goto_convert_class.h index 508fb4fda6d..fe227986a71 100644 --- a/src/goto-programs/goto_convert_class.h +++ b/src/goto-programs/goto_convert_class.h @@ -530,11 +530,6 @@ class goto_convertt:public messaget const exprt &rhs, const exprt::operandst &arguments, goto_programt &dest); - void do_array_set( - const exprt &lhs, - const exprt &rhs, - const exprt::operandst &arguments, - goto_programt &dest); void do_array_equal( const exprt &lhs, const exprt &rhs, @@ -543,7 +538,7 @@ class goto_convertt:public messaget void do_array_op( const irep_idt &id, const exprt &lhs, - const exprt &rhs, + const exprt &function, const exprt::operandst &arguments, goto_programt &dest); void do_printf( From 9d5d907ede97fb9d121cf39cea9819da4bd1c281 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 5 Sep 2017 17:04:40 +0100 Subject: [PATCH 62/65] fixup! Allow extra entry-points to be specified for CI lazy loading --- src/java_bytecode/java_utils.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/java_bytecode/java_utils.cpp b/src/java_bytecode/java_utils.cpp index 36b98dc0ccd..bf41076d84c 100644 --- a/src/java_bytecode/java_utils.cpp +++ b/src/java_bytecode/java_utils.cpp @@ -17,6 +17,8 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include + bool java_is_array_type(const typet &type) { if(type.id()!=ID_struct) From f72b7fce2f5ca02dc9fbf5b5e1649ce869393fd8 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Wed, 23 Aug 2017 11:15:04 +0100 Subject: [PATCH 63/65] pointer_typet now requires a width --- regression/invariants/driver.cpp | 4 +++- src/cpp/cpp_typecheck_constructor.cpp | 6 ++---- src/cpp/cpp_typecheck_conversions.cpp | 10 ++-------- src/cpp/parse.cpp | 2 +- src/goto-symex/symex_builtin_functions.cpp | 10 +++++----- src/goto-symex/symex_dead.cpp | 7 +------ src/goto-symex/symex_decl.cpp | 7 +------ src/java_bytecode/java_bytecode_instrument.cpp | 4 ++-- .../java_string_library_preprocess.cpp | 3 +-- src/java_bytecode/java_types.cpp | 9 ++++----- src/path-symex/path_symex.cpp | 10 +++++----- src/pointer-analysis/value_set.cpp | 5 ++--- src/util/simplify_expr_pointer.cpp | 6 ++++-- .../does_remove_const/does_expr_lose_const.cpp | 14 ++++++++------ .../does_type_preserve_const_correctness.cpp | 12 +++++++----- .../is_type_at_least_as_const_as.cpp | 12 +++++++----- 16 files changed, 55 insertions(+), 66 deletions(-) diff --git a/regression/invariants/driver.cpp b/regression/invariants/driver.cpp index c0627bbd341..4c2fbaf5f2b 100644 --- a/regression/invariants/driver.cpp +++ b/regression/invariants/driver.cpp @@ -11,9 +11,11 @@ Author: Chris Smowton, chris.smowton@diffblue.com #include #include + #include #include #include +#include /// An example of structured invariants-- this contains fields to /// describe the error to a catcher, and also produces a human-readable @@ -86,7 +88,7 @@ int main(int argc, char** argv) else if(arg=="data-invariant-string") DATA_INVARIANT(false, "Test invariant failure"); else if(arg=="irep") - INVARIANT_WITH_IREP(false, "error with irep", pointer_typet(void_typet())); + INVARIANT_WITH_IREP(false, "error with irep", pointer_type(void_typet())); else return 1; } diff --git a/src/cpp/cpp_typecheck_constructor.cpp b/src/cpp/cpp_typecheck_constructor.cpp index cfc645c5cb2..40b0fe18afd 100644 --- a/src/cpp/cpp_typecheck_constructor.cpp +++ b/src/cpp/cpp_typecheck_constructor.cpp @@ -223,8 +223,7 @@ void cpp_typecheckt::default_cpctor( cpp_declaratort parameter_tor; parameter_tor.add(ID_value).make_nil(); parameter_tor.set(ID_name, cpp_parameter); - parameter_tor.type()=reference_typet(); - parameter_tor.type().subtype().make_nil(); + parameter_tor.type()=reference_type(nil_typet()); parameter_tor.add_source_location()=source_location; // Parameter declaration @@ -388,9 +387,8 @@ void cpp_typecheckt::default_assignop( declarator_name.get_sub().push_back(irept("=")); declarator_type.id(ID_function_type); - declarator_type.subtype()=reference_typet(); + declarator_type.subtype()=reference_type(nil_typet()); declarator_type.subtype().add("#qualifier").make_nil(); - declarator_type.subtype().subtype().make_nil(); exprt &args=static_cast(declarator.type().add(ID_parameters)); args.add_source_location()=source_location; diff --git a/src/cpp/cpp_typecheck_conversions.cpp b/src/cpp/cpp_typecheck_conversions.cpp index e3d314f44aa..c0bb71e9f33 100644 --- a/src/cpp/cpp_typecheck_conversions.cpp +++ b/src/cpp/cpp_typecheck_conversions.cpp @@ -1280,11 +1280,8 @@ bool cpp_typecheckt::reference_binding( if(reference_compatible(expr, type, rank)) { { - address_of_exprt tmp; + address_of_exprt tmp(expr, reference_type(expr.type())); tmp.add_source_location()=expr.source_location(); - tmp.object()=expr; - tmp.type()=pointer_type(tmp.op0().type()); - tmp.type().set(ID_C_reference, true); new_expr.swap(tmp); } @@ -1411,10 +1408,7 @@ bool cpp_typecheckt::reference_binding( if(user_defined_conversion_sequence(arg_expr, type.subtype(), new_expr, rank)) { - address_of_exprt tmp; - tmp.type()=pointer_type(new_expr.type()); - tmp.object()=new_expr; - tmp.type().set(ID_C_reference, true); + address_of_exprt tmp(new_expr, reference_type(new_expr.type())); tmp.add_source_location()=new_expr.source_location(); new_expr.swap(tmp); return true; diff --git a/src/cpp/parse.cpp b/src/cpp/parse.cpp index bcdc444de36..ee399b8af8d 100644 --- a/src/cpp/parse.cpp +++ b/src/cpp/parse.cpp @@ -3015,7 +3015,7 @@ bool Parser::optPtrOperator(typet &ptrs) if(t=='*') { - pointer_typet op; + typet op(ID_pointer); cpp_tokent tk; lex.get_token(tk); set_location(op, tk); diff --git a/src/goto-symex/symex_builtin_functions.cpp b/src/goto-symex/symex_builtin_functions.cpp index 8b317f3cdc3..327c31c5247 100644 --- a/src/goto-symex/symex_builtin_functions.cpp +++ b/src/goto-symex/symex_builtin_functions.cpp @@ -165,20 +165,20 @@ void goto_symext::symex_malloc( new_symbol_table.add(value_symbol); - address_of_exprt rhs; + exprt rhs; if(object_type.id()==ID_array) { - rhs.type()=pointer_type(value_symbol.type.subtype()); index_exprt index_expr(value_symbol.type.subtype()); index_expr.array()=value_symbol.symbol_expr(); index_expr.index()=from_integer(0, index_type()); - rhs.op0()=index_expr; + rhs=address_of_exprt( + index_expr, pointer_type(value_symbol.type.subtype())); } else { - rhs.op0()=value_symbol.symbol_expr(); - rhs.type()=pointer_type(value_symbol.type); + rhs=address_of_exprt( + value_symbol.symbol_expr(), pointer_type(value_symbol.type)); } if(rhs.type()!=lhs.type()) diff --git a/src/goto-symex/symex_dead.cpp b/src/goto-symex/symex_dead.cpp index eacf6d247a8..a3a2a03e740 100644 --- a/src/goto-symex/symex_dead.cpp +++ b/src/goto-symex/symex_dead.cpp @@ -45,12 +45,7 @@ void goto_symext::symex_dead(statet &state) exprt rhs; if(failed.is_not_nil()) - { - address_of_exprt address_of_expr; - address_of_expr.object()=failed; - address_of_expr.type()=code.op0().type(); - rhs=address_of_expr; - } + rhs=address_of_exprt(failed, to_pointer_type(code.op0().type())); else rhs=exprt(ID_invalid); diff --git a/src/goto-symex/symex_decl.cpp b/src/goto-symex/symex_decl.cpp index eda7144f99b..3dbdc1e554c 100644 --- a/src/goto-symex/symex_decl.cpp +++ b/src/goto-symex/symex_decl.cpp @@ -60,12 +60,7 @@ void goto_symext::symex_decl(statet &state, const symbol_exprt &expr) exprt rhs; if(failed.is_not_nil()) - { - address_of_exprt address_of_expr; - address_of_expr.object()=failed; - address_of_expr.type()=expr.type(); - rhs=address_of_expr; - } + rhs=address_of_exprt(failed, to_pointer_type(expr.type())); else rhs=exprt(ID_invalid); diff --git a/src/java_bytecode/java_bytecode_instrument.cpp b/src/java_bytecode/java_bytecode_instrument.cpp index ea00b1ac58a..dd29b0b5ec5 100644 --- a/src/java_bytecode/java_bytecode_instrument.cpp +++ b/src/java_bytecode/java_bytecode_instrument.cpp @@ -103,8 +103,8 @@ codet java_bytecode_instrumentt::throw_exception( get_message_handler()); } - pointer_typet exc_ptr_type; - exc_ptr_type.subtype()=symbol_typet(exc_class_name); + pointer_typet exc_ptr_type= + pointer_type(symbol_typet(exc_class_name)); // Allocate and throw an instance of the exception class: diff --git a/src/java_bytecode/java_string_library_preprocess.cpp b/src/java_bytecode/java_string_library_preprocess.cpp index a0de9bfc3c1..8e7947d9636 100644 --- a/src/java_bytecode/java_string_library_preprocess.cpp +++ b/src/java_bytecode/java_string_library_preprocess.cpp @@ -1304,8 +1304,7 @@ exprt java_string_library_preprocesst::get_object_at_index( { dereference_exprt deref_objs(argv, argv.type().subtype()); pointer_typet empty_pointer=pointer_type(empty_typet()); - pointer_typet pointer_of_pointer; - pointer_of_pointer.copy_to_subtypes(empty_pointer); + pointer_typet pointer_of_pointer=pointer_type(empty_pointer); member_exprt data_member(deref_objs, "data", pointer_of_pointer); plus_exprt data_pointer_plus_index( data_member, from_integer(index, java_int_type()), data_member.type()); diff --git a/src/java_bytecode/java_types.cpp b/src/java_bytecode/java_types.cpp index 22d59cf95e0..c98616d06c0 100644 --- a/src/java_bytecode/java_types.cpp +++ b/src/java_bytecode/java_types.cpp @@ -67,7 +67,7 @@ typet java_boolean_type() reference_typet java_reference_type(const typet &subtype) { - return to_reference_type(reference_type(subtype)); + return reference_type(subtype); } reference_typet java_lang_object_type() @@ -246,11 +246,10 @@ typet java_type_from_string(const std::string &src) class_name[i]='.'; std::string identifier="java::"+class_name; + symbol_typet symbol_type(identifier); + symbol_type.set(ID_C_base_name, class_name); - reference_typet result; - result.subtype()=symbol_typet(identifier); - result.subtype().set(ID_C_base_name, class_name); - return result; + return java_reference_type(symbol_type); } default: diff --git a/src/path-symex/path_symex.cpp b/src/path-symex/path_symex.cpp index 0d8db5f979a..8f8f6f3707a 100644 --- a/src/path-symex/path_symex.cpp +++ b/src/path-symex/path_symex.cpp @@ -245,20 +245,20 @@ void path_symext::symex_malloc( value_symbol.type.set("#dynamic", true); value_symbol.mode=ID_C; - address_of_exprt rhs; + exprt rhs; if(object_type.id()==ID_array) { - rhs.type()=pointer_type(value_symbol.type.subtype()); index_exprt index_expr(value_symbol.type.subtype()); index_expr.array()=value_symbol.symbol_expr(); index_expr.index()=from_integer(0, index_type()); - rhs.op0()=index_expr; + rhs=address_of_exprt( + index_expr, pointer_type(value_symbol.type.subtype())); } else { - rhs.op0()=value_symbol.symbol_expr(); - rhs.type()=pointer_type(value_symbol.type); + rhs=address_of_exprt( + value_symbol.symbol_expr(), pointer_type(value_symbol.type)); } if(rhs.type()!=lhs.type()) diff --git a/src/pointer-analysis/value_set.cpp b/src/pointer-analysis/value_set.cpp index 5571b4ab8f5..70d2ccb7629 100644 --- a/src/pointer-analysis/value_set.cpp +++ b/src/pointer-analysis/value_set.cpp @@ -1523,9 +1523,8 @@ void value_sett::apply_code( if(failed.is_not_nil()) { - address_of_exprt address_of_expr; - address_of_expr.object()=failed; - address_of_expr.type()=lhs.type(); + address_of_exprt address_of_expr( + failed, to_pointer_type(lhs.type())); assign(lhs, address_of_expr, ns, false, false); } else diff --git a/src/util/simplify_expr_pointer.cpp b/src/util/simplify_expr_pointer.cpp index 938ce023d7e..8f862f7aead 100644 --- a/src/util/simplify_expr_pointer.cpp +++ b/src/util/simplify_expr_pointer.cpp @@ -78,7 +78,8 @@ bool simplify_exprt::simplify_address_of_arg(exprt &expr) if(!to_integer(expr.op1(), index) && step_size!=-1) { - pointer_typet pointer_type; + pointer_typet pointer_type= + to_pointer_type(to_dereference_expr(expr.op0()).pointer().type()); pointer_type.subtype()=expr.type(); typecast_exprt typecast_expr( from_integer(step_size*index+address, index_type()), pointer_type); @@ -114,7 +115,8 @@ bool simplify_exprt::simplify_address_of_arg(exprt &expr) mp_integer offset=member_offset(struct_type, member, ns); if(offset!=-1) { - pointer_typet pointer_type; + pointer_typet pointer_type= + to_pointer_type(to_dereference_expr(expr.op0()).pointer().type()); pointer_type.subtype()=expr.type(); typecast_exprt typecast_expr( from_integer(address+offset, index_type()), pointer_type); diff --git a/unit/analyses/does_remove_const/does_expr_lose_const.cpp b/unit/analyses/does_remove_const/does_expr_lose_const.cpp index 80e223c93be..d24cce126a3 100644 --- a/unit/analyses/does_remove_const/does_expr_lose_const.cpp +++ b/unit/analyses/does_remove_const/does_expr_lose_const.cpp @@ -10,15 +10,17 @@ /// Does Remove Const Unit Tests #include -#include + #include #include #include +#include + #include #include +#include #include - SCENARIO("does_expr_lose_const", "[core][analyses][does_remove_const][does_expr_remove_const]") { @@ -43,23 +45,23 @@ SCENARIO("does_expr_lose_const", // pointer (can be reassigned) // to int (value can be changed) // int * - typet pointer_to_int_type=pointer_typet(non_const_primitive_type); + typet pointer_to_int_type=pointer_type(non_const_primitive_type); // const pointer (can't be reassigned) // to int (value can be changed) // int * const - typet const_pointer_to_int_type=pointer_typet(non_const_primitive_type); + typet const_pointer_to_int_type=pointer_type(non_const_primitive_type); const_qualifier.write(const_pointer_to_int_type); // pointer (can be reassigned) // to const int (value can't be changed) // const int * - typet pointer_to_const_int_type=pointer_typet(const_primitive_type); + typet pointer_to_const_int_type=pointer_type(const_primitive_type); // constant pointer (can't be reassigned) // to const int (value can't be changed) // const int * const - typet const_pointer_to_const_int_type=pointer_typet(const_primitive_type); + typet const_pointer_to_const_int_type=pointer_type(const_primitive_type); const_qualifier.write(const_pointer_to_const_int_type); symbol_exprt const_primitive_symbol( diff --git a/unit/analyses/does_remove_const/does_type_preserve_const_correctness.cpp b/unit/analyses/does_remove_const/does_type_preserve_const_correctness.cpp index 0f10081c49b..9b678ff1089 100644 --- a/unit/analyses/does_remove_const/does_type_preserve_const_correctness.cpp +++ b/unit/analyses/does_remove_const/does_type_preserve_const_correctness.cpp @@ -11,8 +11,10 @@ #include -#include +#include #include +#include + #include #include #include @@ -42,23 +44,23 @@ SCENARIO("does_type_preserve_const_correctness", // pointer (can be reassigned) // to int (value can be changed) // int * - typet pointer_to_int_type=pointer_typet(non_const_primitive_type); + typet pointer_to_int_type=pointer_type(non_const_primitive_type); // const pointer (can't be reassigned) // to int (value can be changed) // int * const - typet const_pointer_to_int_type=pointer_typet(non_const_primitive_type); + typet const_pointer_to_int_type=pointer_type(non_const_primitive_type); const_qualifier.write(const_pointer_to_int_type); // pointer (can be reassigned) // to const int (value can't be changed) // const int * - typet pointer_to_const_int_type=pointer_typet(const_primitive_type); + typet pointer_to_const_int_type=pointer_type(const_primitive_type); // constant pointer (can't be reassigned) // to const int (value can't be changed) // const int * const - typet const_pointer_to_const_int_type=pointer_typet(const_primitive_type); + typet const_pointer_to_const_int_type=pointer_type(const_primitive_type); const_qualifier.write(const_pointer_to_const_int_type); WHEN("Comparing int to int") diff --git a/unit/analyses/does_remove_const/is_type_at_least_as_const_as.cpp b/unit/analyses/does_remove_const/is_type_at_least_as_const_as.cpp index cfb2c647536..a85819bf301 100644 --- a/unit/analyses/does_remove_const/is_type_at_least_as_const_as.cpp +++ b/unit/analyses/does_remove_const/is_type_at_least_as_const_as.cpp @@ -11,8 +11,10 @@ #include -#include +#include #include +#include + #include #include #include @@ -42,23 +44,23 @@ SCENARIO("is_type_at_least_as_const", // pointer (can be reassigned) // to int (value can be changed) // int * - typet pointer_to_int_type=pointer_typet(non_const_primitive_type); + typet pointer_to_int_type=pointer_type(non_const_primitive_type); // const pointer (can't be reassigned) // to int (value can be changed) // int * const - typet const_pointer_to_int_type=pointer_typet(non_const_primitive_type); + typet const_pointer_to_int_type=pointer_type(non_const_primitive_type); const_qualifier.write(const_pointer_to_int_type); // pointer (can be reassigned) // to const int (value can't be changed) // const int * - typet pointer_to_const_int_type=pointer_typet(const_primitive_type); + typet pointer_to_const_int_type=pointer_type(const_primitive_type); // constant pointer (can't be reassigned) // to const int (value can't be changed) // const int * const - typet const_pointer_to_const_int_type=pointer_typet(const_primitive_type); + typet const_pointer_to_const_int_type=pointer_type(const_primitive_type); const_qualifier.write(const_pointer_to_const_int_type); WHEN("Comparing int to int") From ce863191ba19a365f8d7fc0a38d77f0896600113 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Sun, 28 May 2017 19:32:05 +0100 Subject: [PATCH 64/65] pointer types now have width --- src/ansi-c/ansi_c_convert_type.cpp | 7 +++++++ src/ansi-c/c_typecheck_type.cpp | 3 +++ src/cpp/cpp_typecheck_type.cpp | 4 ++++ src/util/c_types.cpp | 4 ++-- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/ansi-c/ansi_c_convert_type.cpp b/src/ansi-c/ansi_c_convert_type.cpp index 1a67c80c4fa..8c2c9d62628 100644 --- a/src/ansi-c/ansi_c_convert_type.cpp +++ b/src/ansi-c/ansi_c_convert_type.cpp @@ -216,6 +216,13 @@ void ansi_c_convert_typet::read_rec(const typet &type) { c_storage_spec.alias=type.subtype().get(ID_value); } + else if(type.id()==ID_pointer) + { + // pointers have a width, much like integers + pointer_typet tmp=to_pointer_type(type); + tmp.set_width(config.ansi_c.pointer_width); + other.push_back(tmp); + } else other.push_back(type); } diff --git a/src/ansi-c/c_typecheck_type.cpp b/src/ansi-c/c_typecheck_type.cpp index 393be7dbf54..1a3998de19d 100644 --- a/src/ansi-c/c_typecheck_type.cpp +++ b/src/ansi-c/c_typecheck_type.cpp @@ -76,7 +76,10 @@ void c_typecheck_baset::typecheck_type(typet &type) else if(type.id()==ID_array) typecheck_array_type(to_array_type(type)); else if(type.id()==ID_pointer) + { typecheck_type(type.subtype()); + INVARIANT(!type.get(ID_width).empty(), "pointers must have width"); + } else if(type.id()==ID_struct || type.id()==ID_union) typecheck_compound_type(to_struct_union_type(type)); diff --git a/src/cpp/cpp_typecheck_type.cpp b/src/cpp/cpp_typecheck_type.cpp index 41fcd49b68c..5258633b16e 100644 --- a/src/cpp/cpp_typecheck_type.cpp +++ b/src/cpp/cpp_typecheck_type.cpp @@ -14,6 +14,7 @@ Author: Daniel Kroening, kroening@cs.cmu.edu #include #include #include +#include #include @@ -81,6 +82,9 @@ void cpp_typecheckt::typecheck_type(typet &type) // the pointer might have a qualifier, but do subtype first typecheck_type(type.subtype()); + // we add a width, much like with integers + to_pointer_type(type).set_width(config.ansi_c.pointer_width); + // Check if it is a pointer-to-member if(type.find("to-member").is_not_nil()) { diff --git a/src/util/c_types.cpp b/src/util/c_types.cpp index 6c553f5adbc..b02dfdec7e7 100644 --- a/src/util/c_types.cpp +++ b/src/util/c_types.cpp @@ -296,12 +296,12 @@ signedbv_typet pointer_diff_type() pointer_typet pointer_type(const typet &subtype) { - return pointer_typet(subtype); + return pointer_typet(subtype, config.ansi_c.pointer_width); } reference_typet reference_type(const typet &subtype) { - return reference_typet(subtype); + return reference_typet(subtype, config.ansi_c.pointer_width); } typet void_type() From d3c0b5796fc9560bf62e37116764a17872073bae Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Tue, 15 Aug 2017 17:37:53 +0100 Subject: [PATCH 65/65] remove legacy constructors --- src/util/std_expr.h | 5 ----- src/util/std_types.h | 22 ---------------------- 2 files changed, 27 deletions(-) diff --git a/src/util/std_expr.h b/src/util/std_expr.h index a0dfbbcb948..3396398e73b 100644 --- a/src/util/std_expr.h +++ b/src/util/std_expr.h @@ -2599,11 +2599,6 @@ class address_of_exprt:public unary_exprt { } - address_of_exprt(): - unary_exprt(ID_address_of, pointer_typet()) - { - } - exprt &object() { return op0(); diff --git a/src/util/std_types.h b/src/util/std_types.h index 5c244e6728e..4d4a0763ca8 100644 --- a/src/util/std_types.h +++ b/src/util/std_types.h @@ -1367,16 +1367,6 @@ inline c_bit_field_typet &to_c_bit_field_type(typet &type) class pointer_typet:public bitvector_typet { public: - pointer_typet():bitvector_typet(ID_pointer) - { - } - - // this one will go away; use the one with width - explicit pointer_typet(const typet &_subtype): - bitvector_typet(ID_pointer, _subtype) - { - } - pointer_typet(const typet &_subtype, std::size_t width): bitvector_typet(ID_pointer, _subtype, width) { @@ -1418,18 +1408,6 @@ inline pointer_typet &to_pointer_type(typet &type) class reference_typet:public pointer_typet { public: - reference_typet() - { - set(ID_C_reference, true); - } - - // this one will go away; use the one with width - explicit reference_typet(const typet &_subtype): - pointer_typet(_subtype) - { - set(ID_C_reference, true); - } - reference_typet(const typet &_subtype, std::size_t _width): pointer_typet(_subtype, _width) {