From c712cedd7df1c6df7c84d90c8357f809df87a838 Mon Sep 17 00:00:00 2001 From: Dario Cattaruzza Date: Tue, 25 Oct 2016 16:14:56 +0100 Subject: [PATCH 01/52] Get symbol of member expression --- src/util/std_expr.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/util/std_expr.h b/src/util/std_expr.h index e2ed2ad433d..c8a92a89b1f 100644 --- a/src/util/std_expr.h +++ b/src/util/std_expr.h @@ -3287,6 +3287,17 @@ class member_exprt:public exprt { return op0(); } + + // Retrieves the object(symbol) this member corresponds to + inline const symbol_exprt &symbol() const + { + const exprt &op=op0(); + if(op.id()==ID_member) + { + return static_cast(op).symbol(); + } + return to_symbol_expr(op); + } }; /*! \brief Cast a generic exprt to a \ref member_exprt From 9713c6a6bd80fa6dfa62c65e5f35a6427ca6da5e Mon Sep 17 00:00:00 2001 From: Dario Cattaruzza Date: Tue, 25 Oct 2016 16:16:43 +0100 Subject: [PATCH 02/52] Auxiliary function to check if the ssa has enough data to build an identifier --- src/util/ssa_expr.cpp | 13 +++++++++++++ src/util/ssa_expr.h | 6 +++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/util/ssa_expr.cpp b/src/util/ssa_expr.cpp index feb37fe84ca..77f2c43bbb5 100644 --- a/src/util/ssa_expr.cpp +++ b/src/util/ssa_expr.cpp @@ -67,6 +67,19 @@ static void build_ssa_identifier_rec( assert(false); } +/// Used to determine whether or not an identifier can be built +/// before trying and getting an exception +bool ssa_exprt::can_build_identifier(const exprt &expr) +{ + if(expr.id()==ID_symbol) + return true; + else if(expr.id()==ID_member || + expr.id()==ID_index) + return can_build_identifier(expr.op0()); + else + return false; +} + std::pair ssa_exprt::build_identifier( const exprt &expr, const irep_idt &l0, diff --git a/src/util/ssa_expr.h b/src/util/ssa_expr.h index 61cbc566ef1..63e6dfaf7d7 100644 --- a/src/util/ssa_expr.h +++ b/src/util/ssa_expr.h @@ -65,7 +65,7 @@ class ssa_exprt:public symbol_exprt const irep_idt get_l1_object_identifier() const { - #if 0 + #if 1 return get_l1_object().get_identifier(); #else // the above is the clean version, this is the fast one, using @@ -135,6 +135,10 @@ class ssa_exprt:public symbol_exprt const irep_idt &l0, const irep_idt &l1, const irep_idt &l2); + + /* Used to determine whether or not an identifier can be built + * before trying and getting an exception */ + static bool can_build_identifier(const exprt &src); }; /*! \brief Cast a generic exprt to an \ref ssa_exprt From c6f1acd5948dd2f1a12d19f19fc12dc971212bcf Mon Sep 17 00:00:00 2001 From: Dario Cattaruzza Date: Tue, 25 Oct 2016 16:17:06 +0100 Subject: [PATCH 03/52] Bitwise operators for mpinteger --- src/util/mp_arith.cpp | 263 ++++++++++++++++++++++++++++++++++++++++++ src/util/mp_arith.h | 23 ++++ 2 files changed, 286 insertions(+) diff --git a/src/util/mp_arith.cpp b/src/util/mp_arith.cpp index 980284ffcd8..986df2decee 100644 --- a/src/util/mp_arith.cpp +++ b/src/util/mp_arith.cpp @@ -18,6 +18,8 @@ Author: Daniel Kroening, kroening@kroening.com #include "mp_arith.h" #include "arith_tools.h" +typedef BigInt::ullong_t ullong_t; + mp_integer operator>>(const mp_integer &a, const mp_integer &b) { mp_integer power=::power(2, b); @@ -207,3 +209,264 @@ unsigned integer2unsigned(const mp_integer &n) assert(ull <= std::numeric_limits::max()); return (unsigned)ull; } + +/*******************************************************************\ + +Function: bitwise_or + + Inputs: + + Outputs: + + Purpose: bitwise or + bitwise operations only make sense on native objects, hence the + largest object size should be the largest available c++ integer + size (currently long long) + +\*******************************************************************/ + +mp_integer bitwise_or(const mp_integer &a, const mp_integer &b) +{ + ullong_t result=a.to_ulong()|b.to_ulong(); + return result; +} + +/*******************************************************************\ + +Function: bitwise_and + + Inputs: + + Outputs: + + Purpose: bitwise and + bitwise operations only make sense on native objects, hence the + largest object size should be the largest available c++ integer + size (currently long long) + +\*******************************************************************/ + +mp_integer bitwise_and(const mp_integer &a, const mp_integer &b) +{ + ullong_t result=a.to_ulong()&b.to_ulong(); + return result; +} + +/*******************************************************************\ + +Function: bitwise_xor + + Inputs: + + Outputs: + + Purpose: bitwise xor + bitwise operations only make sense on native objects, hence the + largest object size should be the largest available c++ integer + size (currently long long) + +\*******************************************************************/ + +mp_integer bitwise_xor(const mp_integer &a, const mp_integer &b) +{ + ullong_t result=a.to_ulong()^b.to_ulong(); + return result; +} + +/*******************************************************************\ + +Function: bitwise_neg + + Inputs: + + Outputs: + + Purpose: bitwise negation + bitwise operations only make sense on native objects, hence the + largest object size should be the largest available c++ integer + size (currently long long) + +\*******************************************************************/ + +mp_integer bitwise_neg(const mp_integer &a) +{ + ullong_t result=~a.to_ulong(); + return result; +} + +/*******************************************************************\ + +Function: arith_left_shift + + Inputs: + + Outputs: + + Purpose: arithmetic left shift + bitwise operations only make sense on native objects, hence the + largest object size should be the largest available c++ integer + size (currently long long) + +\*******************************************************************/ + +mp_integer arith_left_shift( + const mp_integer &a, + const mp_integer &b, + std::size_t true_size) +{ + ullong_t shift=b.to_ulong(); + if(shift>true_size && a!=mp_integer(0)) + throw "shift value out of range"; + + ullong_t result=a.to_ulong()<true_size) + throw "shift value out of range"; + + ullong_t sign=(1<<(true_size-1))&number; + ullong_t pad=(sign==0) ? 0 : ~((1<<(true_size-shift))-1); + ullong_t result=(number>>shift)|pad; + return result; +} + +/*******************************************************************\ + +Function: logic_left_shift + + Inputs: + + Outputs: + + Purpose: logic left shift + bitwise operations only make sense on native objects, hence the + largest object size should be the largest available c++ integer + size (currently long long) + +\*******************************************************************/ + +mp_integer logic_left_shift( + const mp_integer &a, + const mp_integer &b, + std::size_t true_size) +{ + ullong_t shift=b.to_ulong(); + if(shift>true_size && a!=mp_integer(0)) + throw "shift value out of range"; + + ullong_t result=a.to_ulong()<true_size) + throw "shift value out of range"; + + ullong_t result=a.to_ulong()>>shift; + return result; +} + +/*******************************************************************\ + +Function: rotate_right + + Inputs: + + Outputs: + + Purpose: rotates right (MSB=LSB) + bitwise operations only make sense on native objects, hence the + largest object size should be the largest available c++ integer + size (currently long long) + +\*******************************************************************/ + +mp_integer rotate_right( + const mp_integer &a, + const mp_integer &b, + std::size_t true_size) +{ + ullong_t number=a.to_ulong(); + ullong_t shift=b.to_ulong(); + if(shift>true_size) + throw "shift value out of range"; + + ullong_t revShift=true_size-shift; + ullong_t filter=1<<(true_size-1); + ullong_t result=(number>>shift)|((number<true_size) + throw "shift value out of range"; + + ullong_t revShift=true_size-shift; + ullong_t filter=1<<(true_size-1); + ullong_t result=((number<>revShift); + return result; +} diff --git a/src/util/mp_arith.h b/src/util/mp_arith.h index eede5855b75..7cc4dd7dfad 100644 --- a/src/util/mp_arith.h +++ b/src/util/mp_arith.h @@ -21,6 +21,28 @@ typedef BigInt mp_integer; std::ostream &operator<<(std::ostream &, const mp_integer &); mp_integer operator>>(const mp_integer &, const mp_integer &); mp_integer operator<<(const mp_integer &, const mp_integer &); +mp_integer bitwise_or(const mp_integer &, const mp_integer &); +mp_integer bitwise_and(const mp_integer &, const mp_integer &); +mp_integer bitwise_xor(const mp_integer &, const mp_integer &); +mp_integer bitwise_neg(const mp_integer &); + +mp_integer arith_left_shift( + const mp_integer &, const mp_integer &, std::size_t true_size); + +mp_integer arith_right_shift( + const mp_integer &, const mp_integer &, std::size_t true_size); + +mp_integer logic_left_shift( + const mp_integer &, const mp_integer &, std::size_t true_size); + +mp_integer logic_right_shift( + const mp_integer &, const mp_integer &, std::size_t true_size); + +mp_integer rotate_right( + const mp_integer &, const mp_integer &, std::size_t true_size); + +mp_integer rotate_left( + const mp_integer &, const mp_integer &, std::size_t true_size); const std::string integer2string(const mp_integer &, unsigned base=10); const mp_integer string2integer(const std::string &, unsigned base=10); @@ -29,5 +51,6 @@ const mp_integer binary2integer(const std::string &, bool is_signed); mp_integer::ullong_t integer2ulong(const mp_integer &); std::size_t integer2size_t(const mp_integer &); unsigned integer2unsigned(const mp_integer &); +const mp_integer mp_zero=string2integer("0"); #endif // CPROVER_UTIL_MP_ARITH_H From f4a468d5e85061a1c3a8441130dd6d494e42050c Mon Sep 17 00:00:00 2001 From: Dario Cattaruzza Date: Tue, 25 Oct 2016 16:18:08 +0100 Subject: [PATCH 04/52] Auxiliary function to retrieve tail of trace and added dead command to trace --- src/goto-programs/goto_trace.cpp | 7 ++++--- src/goto-programs/goto_trace.h | 7 +++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/goto-programs/goto_trace.cpp b/src/goto-programs/goto_trace.cpp index 4485aed5151..2e6921cb3de 100644 --- a/src/goto-programs/goto_trace.cpp +++ b/src/goto-programs/goto_trace.cpp @@ -51,9 +51,10 @@ void goto_trace_stept::output( case goto_trace_stept::typet::SHARED_READ: out << "SHARED_READ"; break; case goto_trace_stept::typet::SHARED_WRITE: out << "SHARED WRITE"; break; case goto_trace_stept::typet::FUNCTION_CALL: out << "FUNCTION CALL"; break; - case goto_trace_stept::typet::FUNCTION_RETURN: - out << "FUNCTION RETURN"; break; - default: assert(false); + case goto_trace_stept::typet::FUNCTION_RETURN: out << "FUNCTION RETURN"; break; + default: + out << "unknown type: " << type << std::endl; + assert(false); } if(type==typet::ASSERT || type==typet::ASSUME || type==typet::GOTO) diff --git a/src/goto-programs/goto_trace.h b/src/goto-programs/goto_trace.h index 4c8a3accc8a..16010145b61 100644 --- a/src/goto-programs/goto_trace.h +++ b/src/goto-programs/goto_trace.h @@ -174,6 +174,13 @@ class goto_tracet steps.push_back(step); } + // retrieves the final step in the trace for manipulation + // (used to fill a trace from code, hence non-const) + inline goto_trace_stept &get_last_step() + { + return steps.back(); + } + // delete all steps after (not including) s void trim_after(stepst::iterator s) { From 8d2615e4d8af1a4c8acf8a965369492a810d6173 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Fri, 13 Jan 2017 14:36:01 +0000 Subject: [PATCH 05/52] Fix arithmetic shift operators to_ulong() will negate a negative number, rather than returning its two's complement representation as an unsigned type as we might reasonably suppose. Instead use to_long() everywhere to preserve the bitwise representation and then use sign-bit filling to make sure the value is correctly re-encoded as mp_integer. --- src/util/mp_arith.cpp | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/util/mp_arith.cpp b/src/util/mp_arith.cpp index 986df2decee..e79d58f63e9 100644 --- a/src/util/mp_arith.cpp +++ b/src/util/mp_arith.cpp @@ -18,7 +18,8 @@ Author: Daniel Kroening, kroening@kroening.com #include "mp_arith.h" #include "arith_tools.h" -typedef BigInt::ullong_t ullong_t; +typedef BigInt::ullong_t ullong_t; // NOLINT(readability/identifiers) +typedef BigInt::llong_t llong_t; // NOLINT(readability/identifiers) mp_integer operator>>(const mp_integer &a, const mp_integer &b) { @@ -318,8 +319,12 @@ mp_integer arith_left_shift( if(shift>true_size && a!=mp_integer(0)) throw "shift value out of range"; - ullong_t result=a.to_ulong()<true_size) throw "shift value out of range"; - ullong_t sign=(1<<(true_size-1))&number; - ullong_t pad=(sign==0) ? 0 : ~((1<<(true_size-shift))-1); - ullong_t result=(number>>shift)|pad; + llong_t sign=(1<<(true_size-1))&number; + llong_t pad=(sign==0) ? 0 : ~((1<<(true_size-shift))-1); + llong_t result=(number >> shift)|pad; return result; } @@ -376,8 +381,17 @@ mp_integer logic_left_shift( ullong_t shift=b.to_ulong(); if(shift>true_size && a!=mp_integer(0)) throw "shift value out of range"; - - ullong_t result=a.to_ulong()<true_size) throw "shift value out of range"; - ullong_t result=a.to_ulong()>>shift; + ullong_t result=((ullong_t)a.to_long()) >> shift; return result; } @@ -436,7 +450,7 @@ mp_integer rotate_right( ullong_t revShift=true_size-shift; ullong_t filter=1<<(true_size-1); - ullong_t result=(number>>shift)|((number<> shift)|((number<>revShift); + ullong_t result=((number<> revShift); return result; } From 994e216e0723fd8e62bf0cf8b188b952ea51dd29 Mon Sep 17 00:00:00 2001 From: thk123 Date: Mon, 16 Jan 2017 14:58:46 +0000 Subject: [PATCH 06/52] Added a new class for handling the internals This code was originally in the `dump_ct` class but it is useful in other places (specifically when generating stubs we don't want to include any of these). --- src/goto-programs/Makefile | 1 + src/goto-programs/system_library_symbols.cpp | 298 +++++++++++++++++++ src/goto-programs/system_library_symbols.h | 37 +++ 3 files changed, 336 insertions(+) create mode 100644 src/goto-programs/system_library_symbols.cpp create mode 100644 src/goto-programs/system_library_symbols.h diff --git a/src/goto-programs/Makefile b/src/goto-programs/Makefile index a66b408a3c9..6e2bd969e57 100644 --- a/src/goto-programs/Makefile +++ b/src/goto-programs/Makefile @@ -57,6 +57,7 @@ SRC = basic_blocks.cpp \ slice_global_inits.cpp \ string_abstraction.cpp \ string_instrumentation.cpp \ + system_library_symbols.cpp \ vcd_goto_trace.cpp \ wp.cpp \ write_goto_binary.cpp \ diff --git a/src/goto-programs/system_library_symbols.cpp b/src/goto-programs/system_library_symbols.cpp new file mode 100644 index 00000000000..44bb1b1b2cd --- /dev/null +++ b/src/goto-programs/system_library_symbols.cpp @@ -0,0 +1,298 @@ +/*******************************************************************\ + +Module: Goto Programs + +Author: Thomas Kiley + +\*******************************************************************/ + +#include "system_library_symbols.h" +#include +#include +#include + +system_library_symbolst::system_library_symbolst() +{ + init_system_library_map(); +} + +/*******************************************************************\ + +Function: system_library_symbolst::init_system_library_map + +Inputs: + +Outputs: + +Purpose: To generate a map of header file names -> list of symbols + The symbol names are reserved as the header and source files + will be compiled in to the goto program. + +\*******************************************************************/ + +void system_library_symbolst::init_system_library_map() +{ + // ctype.h + std::list ctype_syms= + { + "isalnum", "isalpha", "isblank", "iscntrl", "isdigit", "isgraph", + "islower", "isprint", "ispunct", "isspace", "isupper", "isxdigit", + "tolower", "toupper" + }; + add_to_system_library("ctype.h", ctype_syms); + + // fcntl.h + std::list fcntl_syms= + { + "creat", "fcntl", "open" + }; + add_to_system_library("fcntl.h", fcntl_syms); + + // locale.h + std::list locale_syms= + { + "setlocale" + }; + add_to_system_library("locale.h", locale_syms); + + // math.h + std::list math_syms= + { + "acos", "acosh", "asin", "asinh", "atan", "atan2", "atanh", + "cbrt", "ceil", "copysign", "cos", "cosh", "erf", "erfc", "exp", + "exp2", "expm1", "fabs", "fdim", "floor", "fma", "fmax", "fmin", + "fmod", "fpclassify", "frexp", "hypot", "ilogb", "isfinite", + "isinf", "isnan", "isnormal", "j0", "j1", "jn", "ldexp", "lgamma", + "llrint", "llround", "log", "log10", "log1p", "log2", "logb", + "lrint", "lround", "modf", "nan", "nearbyint", "nextafter", "pow", + "remainder", "remquo", "rint", "round", "scalbln", "scalbn", + "signbit", "sin", "sinh", "sqrt", "tan", "tanh", "tgamma", + "trunc", "y0", "y1", "yn" + }; + add_to_system_library("math.h", math_syms); + + // pthread.h + std::list pthread_syms= + { + "pthread_cleanup_pop", "pthread_cleanup_push", + "pthread_cond_broadcast", "pthread_cond_destroy", + "pthread_cond_init", "pthread_cond_signal", + "pthread_cond_timedwait", "pthread_cond_wait", "pthread_create", + "pthread_detach", "pthread_equal", "pthread_exit", + "pthread_getspecific", "pthread_join", "pthread_key_delete", + "pthread_mutex_destroy", "pthread_mutex_init", + "pthread_mutex_lock", "pthread_mutex_trylock", + "pthread_mutex_unlock", "pthread_once", "pthread_rwlock_destroy", + "pthread_rwlock_init", "pthread_rwlock_rdlock", + "pthread_rwlock_unlock", "pthread_rwlock_wrlock", + "pthread_rwlockattr_destroy", "pthread_rwlockattr_getpshared", + "pthread_rwlockattr_init", "pthread_rwlockattr_setpshared", + "pthread_self", "pthread_setspecific" + }; + add_to_system_library("pthread.h", pthread_syms); + + // setjmp.h + std::list setjmp_syms= + { + "_longjmp", "_setjmp", "longjmp", "longjmperror", "setjmp", + "siglongjmp", "sigsetjmp" + }; + add_to_system_library("setjmp.h", setjmp_syms); + + // stdio.h + std::list stdio_syms= + { + "asprintf", "clearerr", "fclose", "fdopen", "feof", "ferror", + "fflush", "fgetc", "fgetln", "fgetpos", "fgets", "fgetwc", + "fgetws", "fileno", "fopen", "fprintf", "fpurge", "fputc", + "fputs", "fputwc", "fputws", "fread", "freopen", "fropen", + "fscanf", "fseek", "fsetpos", "ftell", "funopen", "fwide", + "fwopen", "fwprintf", "fwrite", "getc", "getchar", "getdelim", + "getline", "gets", "getw", "getwc", "getwchar", "mkdtemp", + "mkstemp", "mktemp", "perror", "printf", "putc", "putchar", + "puts", "putw", "putwc", "putwchar", "remove", "rewind", "scanf", + "setbuf", "setbuffer", "setlinebuf", "setvbuf", "snprintf", + "sprintf", "sscanf", "strerror", "swprintf", "sys_errlist", + "sys_nerr", "tempnam", "tmpfile", "tmpnam", "ungetc", "ungetwc", + "vasprintf", "vfprintf", "vfscanf", "vfwprintf", "vprintf", + "vscanf", "vsnprintf", "vsprintf", "vsscanf", "vswprintf", + "vwprintf", "wprintf", + /* non-public struct types */ + "tag-__sFILE", "tag-__sbuf", // OS X + "tag-_IO_FILE", "tag-_IO_marker", // Linux + }; + add_to_system_library("stdio.h", stdio_syms); + + // stdlib.h + std::list stdlib_syms= + { + "abort", "abs", "atexit", "atof", "atoi", "atol", "atoll", + "bsearch", "calloc", "div", "exit", "free", "getenv", "labs", + "ldiv", "llabs", "lldiv", "malloc", "mblen", "mbstowcs", "mbtowc", + "qsort", "rand", "realloc", "srand", "strtod", "strtof", "strtol", + "strtold", "strtoll", "strtoul", "strtoull", "system", "wcstombs", + "wctomb" + }; + add_to_system_library("stdlib.h", stdlib_syms); + + // string.h + std::list string_syms= + { + "strcat", "strncat", "strchr", "strrchr", "strcmp", "strncmp", + "strcpy", "strncpy", "strerror", "strlen", "strpbrk", "strspn", + "strcspn", "strstr", "strtok" + }; + add_to_system_library("string.h", string_syms); + + // time.h + std::list time_syms= + { + "asctime", "asctime_r", "ctime", "ctime_r", "difftime", "gmtime", + "gmtime_r", "localtime", "localtime_r", "mktime", + /* non-public struct types */ + "tag-timespec", "tag-timeval" + }; + add_to_system_library("time.h", time_syms); + + // unistd.h + std::list unistd_syms= + { + "_exit", "access", "alarm", "chdir", "chown", "close", "dup", + "dup2", "execl", "execle", "execlp", "execv", "execve", "execvp", + "fork", "fpathconf", "getcwd", "getegid", "geteuid", "getgid", + "getgroups", "getlogin", "getpgrp", "getpid", "getppid", "getuid", + "isatty", "link", "lseek", "pathconf", "pause", "pipe", "read", + "rmdir", "setgid", "setpgid", "setsid", "setuid", "sleep", + "sysconf", "tcgetpgrp", "tcsetpgrp", "ttyname", "ttyname_r", + "unlink", "write" + }; + add_to_system_library("unistd.h", unistd_syms); + + // sys/select.h + std::list sys_select_syms= + { + "select" + }; + add_to_system_library("sys/select.h", sys_select_syms); + + // sys/socket.h + std::list sys_socket_syms= + { + "accept", "bind", "connect" + }; + add_to_system_library("sys/socket.h", sys_socket_syms); + + // sys/stat.h + std::list sys_stat_syms= + { + "fstat", "lstat", "stat" + }; + add_to_system_library("sys/stat.h", sys_stat_syms); + +#if 0 + // sys/types.h + std::list sys_types_syms= + { + }; + add_to_system_library("sys/types.h", sys_types_syms); +#endif + + // sys/wait.h + std::list sys_wait_syms= + { + "wait", "waitpid" + }; + add_to_system_library("sys/wait.h", sys_wait_syms); +} + +/*******************************************************************\ + +Function: system_library_symbolst::add_to_system_library + +Inputs: + header_file - the name of the header file the symbol came from + symbols - a list of the names of the symbols in the header file + +Outputs: + +Purpose: To add the symbols from a specific header file to the + system library map. The symbol is used as the key so that + we can easily look up symbols. + +\*******************************************************************/ + +void system_library_symbolst::add_to_system_library( + irep_idt header_file, + std::list symbols) +{ + for(const irep_idt &symbol : symbols) + { + system_library_map[symbol]=header_file; + } +} + + +/*******************************************************************\ + +Function: system_library_symbolst::is_symbol_internal_symbol + +Inputs: + symbol - the symbol to check + +Outputs: True if the symbol is an internal symbol. If specific system + headers need to be included, the out_system_headers will contain + the headers. + +Purpose: To find out if a symbol is an internal symbol. + +\*******************************************************************/ + +bool system_library_symbolst::is_symbol_internal_symbol( + const symbolt &symbol, + std::set &out_system_headers) const +{ + const std::string &name_str=id2string(symbol.name); + + if(has_prefix(name_str, CPROVER_PREFIX) || + name_str=="__func__" || + name_str=="__FUNCTION__" || + name_str=="__PRETTY_FUNCTION__" || + name_str=="argc'" || + name_str=="argv'" || + name_str=="envp'" || + name_str=="envp_size'") + return true; + + const std::string &file_str=id2string(symbol.location.get_file()); + + // don't dump internal GCC builtins + if((file_str=="gcc_builtin_headers_alpha.h" || + file_str=="gcc_builtin_headers_arm.h" || + file_str=="gcc_builtin_headers_ia32.h" || + file_str=="gcc_builtin_headers_mips.h" || + file_str=="gcc_builtin_headers_power.h" || + file_str=="gcc_builtin_headers_generic.h") && + has_prefix(name_str, "__builtin_")) + return true; + + if(name_str=="__builtin_va_start" || + name_str=="__builtin_va_end" || + symbol.name==ID_gcc_builtin_va_arg) + { + out_system_headers.insert("stdarg.h"); + return true; + } + + if(name_str.find("$link")!=std::string::npos) + return false; + + const auto &it=system_library_map.find(symbol.name); + + if(it!=system_library_map.end()) + { + out_system_headers.insert(it->second); + return true; + } + + return false; +} diff --git a/src/goto-programs/system_library_symbols.h b/src/goto-programs/system_library_symbols.h new file mode 100644 index 00000000000..a253b903bd8 --- /dev/null +++ b/src/goto-programs/system_library_symbols.h @@ -0,0 +1,37 @@ +/*******************************************************************\ + +Module: Goto Programs + +Author: Thomas Kiley + +\*******************************************************************/ + +#ifndef CPROVER_GOTO_PROGRAMS_SYSTEM_LIBRARY_SYMBOLS_H +#define CPROVER_GOTO_PROGRAMS_SYSTEM_LIBRARY_SYMBOLS_H + +#include +#include +#include + +class symbolt; + +class system_library_symbolst +{ +public: + system_library_symbolst(); + + bool is_symbol_internal_symbol( + const symbolt &symbol, + std::set &out_system_headers) const; + +private: + void init_system_library_map(); + + void add_to_system_library( + irep_idt header_file, + std::list symbols); + + std::map system_library_map; +}; + +#endif // CPROVER_GOTO_PROGRAMS_SYSTEM_LIBRARY_SYMBOLS_H From b0dba3e356dde55c18e420980ca2162354f63017 Mon Sep 17 00:00:00 2001 From: thk123 Date: Mon, 16 Jan 2017 17:07:04 +0000 Subject: [PATCH 07/52] Adding more symbols that should be excluded The existing symbols were missing a few symbols from the files they were supposed to be symbols for. Further, for some reason the math functions were sometimes used with a double underscore prefix. Some included files were missed (fenv.h, errno.c, noop.c). There were some other prefixes that clearly have internal meaning (__VERIFIER, nondet_). Also asserts weren't being included. These problems were discovered by running the make and seeing which tests failed and what functions were being stubbed. It is therefore not necessarily exhaustive. Perhaps there is a better approach to this problem. --- src/goto-programs/system_library_symbols.cpp | 71 +++++++++++++++++--- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/src/goto-programs/system_library_symbols.cpp b/src/goto-programs/system_library_symbols.cpp index 44bb1b1b2cd..76023d0c455 100644 --- a/src/goto-programs/system_library_symbols.cpp +++ b/src/goto-programs/system_library_symbols.cpp @@ -10,6 +10,7 @@ Author: Thomas Kiley #include #include #include +#include system_library_symbolst::system_library_symbolst() { @@ -61,16 +62,28 @@ void system_library_symbolst::init_system_library_map() "acos", "acosh", "asin", "asinh", "atan", "atan2", "atanh", "cbrt", "ceil", "copysign", "cos", "cosh", "erf", "erfc", "exp", "exp2", "expm1", "fabs", "fdim", "floor", "fma", "fmax", "fmin", - "fmod", "fpclassify", "frexp", "hypot", "ilogb", "isfinite", - "isinf", "isnan", "isnormal", "j0", "j1", "jn", "ldexp", "lgamma", - "llrint", "llround", "log", "log10", "log1p", "log2", "logb", - "lrint", "lround", "modf", "nan", "nearbyint", "nextafter", "pow", - "remainder", "remquo", "rint", "round", "scalbln", "scalbn", - "signbit", "sin", "sinh", "sqrt", "tan", "tanh", "tgamma", - "trunc", "y0", "y1", "yn" + "fmod", "fpclassify", "fpclassifyl", "fpclassifyf", "frexp", + "hypot", "ilogb", "isfinite", "isinf", "isnan", "isnormal", + "j0", "j1", "jn", "ldexp", "lgamma", "llrint", "llround", "log", + "log10", "log1p", "log2", "logb", "lrint", "lround", "modf", "nan", + "nearbyint", "nextafter", "pow", "remainder", "remquo", "rint", + "round", "scalbln", "scalbn", "signbit", "sin", "sinh", "sqrt", + "tan", "tanh", "tgamma", "trunc", "y0", "y1", "yn", "isinff", + "isinfl", "isnanf", "isnanl" }; add_to_system_library("math.h", math_syms); + // for some reason the math functions can sometimes be prefixed with + // a double underscore + std::list underscore_math_syms; + for(const irep_idt &math_sym : math_syms) + { + std::ostringstream underscore_id; + underscore_id << "__" << math_sym; + underscore_math_syms.push_back(irep_idt(underscore_id.str())); + } + add_to_system_library("math.h", underscore_math_syms); + // pthread.h std::list pthread_syms= { @@ -140,7 +153,8 @@ void system_library_symbolst::init_system_library_map() { "strcat", "strncat", "strchr", "strrchr", "strcmp", "strncmp", "strcpy", "strncpy", "strerror", "strlen", "strpbrk", "strspn", - "strcspn", "strstr", "strtok" + "strcspn", "strstr", "strtok", "strcasecmp", "strncasecmp", "strdup", + "memset" }; add_to_system_library("string.h", string_syms); @@ -189,6 +203,27 @@ void system_library_symbolst::init_system_library_map() }; add_to_system_library("sys/stat.h", sys_stat_syms); + std::list fenv_syms= + { + "fenv_t", "fexcept_t", "feclearexcept", "fegetexceptflag", + "feraiseexcept", "fesetexceptflag", "fetestexcept", + "fegetround", "fesetround", "fegetenv", "feholdexcept", + "fesetenv", "feupdateenv" + }; + add_to_system_library("fenv.h", fenv_syms); + + std::list errno_syms= + { + "__error", "__errno_location", "__errno" + }; + add_to_system_library("errno.c", errno_syms); + + std::list noop_syms= + { + "__noop" + }; + add_to_system_library("noop.c", noop_syms); + #if 0 // sys/types.h std::list sys_types_syms= @@ -263,6 +298,17 @@ bool system_library_symbolst::is_symbol_internal_symbol( name_str=="envp_size'") return true; + // exclude nondet instructions + if(has_prefix(name_str, "nondet_")) + { + return true; + } + + if(has_prefix(name_str, "__VERIFIER")) + { + return true; + } + const std::string &file_str=id2string(symbol.location.get_file()); // don't dump internal GCC builtins @@ -283,6 +329,15 @@ bool system_library_symbolst::is_symbol_internal_symbol( return true; } + // don't dump asserts + else if(name_str=="__assert_fail" || + name_str=="_assert" || + name_str=="__assert_c99" || + name_str=="_wassert") + { + return true; + } + if(name_str.find("$link")!=std::string::npos) return false; From 3f8242ea5dfac12a039c16ccf0e09c2df2bd044d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Forejt?= Date: Fri, 20 Jan 2017 21:51:10 +0000 Subject: [PATCH 08/52] Autocomplete script for bash See documentation in scripts/bash-autocomplete/Readme.md --- scripts/bash-autocomplete/.gitignore | 1 + scripts/bash-autocomplete/Readme.md | 31 ++++++++++++ scripts/bash-autocomplete/cbmc.sh.template | 43 +++++++++++++++++ scripts/bash-autocomplete/extract_switches.sh | 48 +++++++++++++++++++ .../switch_extractor_helper.c | 3 ++ 5 files changed, 126 insertions(+) create mode 100644 scripts/bash-autocomplete/.gitignore create mode 100644 scripts/bash-autocomplete/Readme.md create mode 100644 scripts/bash-autocomplete/cbmc.sh.template create mode 100755 scripts/bash-autocomplete/extract_switches.sh create mode 100644 scripts/bash-autocomplete/switch_extractor_helper.c diff --git a/scripts/bash-autocomplete/.gitignore b/scripts/bash-autocomplete/.gitignore new file mode 100644 index 00000000000..1e0acedc4f2 --- /dev/null +++ b/scripts/bash-autocomplete/.gitignore @@ -0,0 +1 @@ +cbmc.sh diff --git a/scripts/bash-autocomplete/Readme.md b/scripts/bash-autocomplete/Readme.md new file mode 100644 index 00000000000..00101d99159 --- /dev/null +++ b/scripts/bash-autocomplete/Readme.md @@ -0,0 +1,31 @@ +# CBMC Autocomplete Scripts for Bash +This directory contains an autocomplete script for bash. +## Installation +1. Compile cbmc and + +2. `cd scripts/bash-autocomplete` + +3. `./extract-switches.sh` + +4. Put the following at the end of you in your `~/.bashrc`, with the directories adapted to your directory structure: + ```bash + cbmcautocomplete=~/diffblue/cbmc/scripts/bash-autocomplete/cbmc.sh + if [ -f $cbmcautocomplete ]; then + . $cbmcautocomplete + fi + ``` +## Usage +As with the usual autocomplete in bash, start typing a switch to complete it, for example: +``` +cbmc --clas +``` +will complete to +``` +cbmc --classpath +``` + +## Features implemented + +* Completing all switches +* Completing values for `--cover`, `--mm` and `--arch` +* When completing a name of a file to analyze, only files with supported extensions are shown. diff --git a/scripts/bash-autocomplete/cbmc.sh.template b/scripts/bash-autocomplete/cbmc.sh.template new file mode 100644 index 00000000000..cbd64762b2d --- /dev/null +++ b/scripts/bash-autocomplete/cbmc.sh.template @@ -0,0 +1,43 @@ +#!/bin/bash +_cbmc_autocomplete() +{ + #list of all switches cbmc has. IMPORTANT: in the template file, this variable must be defined on line 5. + local switches="" + #word on which the cursor is + local cur=${COMP_WORDS[COMP_CWORD]} + #previous word (in case it is a switch with a parameter) + local prev=${COMP_WORDS[COMP_CWORD-1]} + + #check if the command before cursor is a switch that takes parameters, if yes, + #offer a choice of parameters + case "$prev" in + --cover) #for coverage we list the options explicitly + COMPREPLY=( $( compgen -W "assertion path branch location decision condition mcdc cover" -- $cur ) ) + return 0 + ;; + --mm) #for memory models we list the options explicitly + COMPREPLY=( $( compgen -W "sc tso pso" -- $cur ) ) + return 0 + ;; + --arch) #for architecture we list the options explicitly + COMPREPLY=( $( compgen -W "i386 x86_64" -- $cur ) ) + return 0 + ;; + -I|--classpath|-cp|--outfile|--existing-coverage|--graphml-cex) + #a switch that takes a file parameter of which we don't know an extension + #TODO probably we can do more for -I, --classpath, -cp + _filedir + return 0 + ;; + esac + + #complete a switch from a standard list, if the parameter under cursor starts with a hyphen + if [[ "$cur" == -* ]]; then + COMPREPLY=( $( compgen -W "$switches" -- $cur ) ) + return 0 + fi + + #if none of the above applies, offer directories and files that we can analyze + _filedir "@(class|jar|cpp|cc|c\+\+|ii|cxx|c|i|gb)" +} +complete -F _cbmc_autocomplete cbmc diff --git a/scripts/bash-autocomplete/extract_switches.sh b/scripts/bash-autocomplete/extract_switches.sh new file mode 100755 index 00000000000..e000b469bea --- /dev/null +++ b/scripts/bash-autocomplete/extract_switches.sh @@ -0,0 +1,48 @@ +#!/bin/bash +echo "Compiling the helper file to extract the raw list of parameters from cbmc" +g++ -c -MMD -MP -std=c++11 -Wall -I ../../src/ -ftrack-macro-expansion=0 -fno-diagnostics-show-caret switch_extractor_helper.c -o tmp.o 2> pragma.txt + +retval=$? + +#clean up compiled files, we don't need them. +rm tmp.o 2> /dev/null +rm tmp.d 2> /dev/null + +#check if compilation went fine +if [ $retval -ne 0 ]; then + echo "Problem compiling the helper file, parameter list not extracted." + exit 1; +fi + +echo "Converting the raw parameter list to the format required by autocomplete scripts" +rawstring=`sed "s/^.*pragma message: \(.*\)/\1/" pragma.txt` +#delete pragma file, we won't need it +rm pragma.txt 2> /dev/null + +#now the main bit, convert from raw format to a proper list of switches +cleanstring=`( + #extract 2-hyphen switches, such as --foo + #grep for '(foo)' expressions, and then use sed to remove parantheses and put '--' at the start + (echo $rawstring | grep -o "([^)]*)" | sed "s/^.\(.*\).$/--\1/") ; + #extract 1-hyphen switches, such as -F + #use sed to remove all (foo) expressions, then you're left with switches and ':', so grep the colons out and then use sed to include the '-' + (echo $rawstring | sed "s/([^)]*)//g" | grep -o "[a-zA-Z0-9]" | sed "s/\(.*\)/-\1/") + ) | tr '\n' ' '` + +#sanity check that there is only one line of output +if [ `echo $cleanstring | wc -l | awk '{print $1}'` -ne 1 ]; then + echo "Problem converting the parameter list to the correct format, I was expecting one line but either got 0 or >2. This is likely to be an error in this conversion script." + exit 1; +fi + +#sanity check that there are no dangerous characters +echo $cleanstring | grep -q "[^a-zA-Z0-9 -]" +if [ $? -eq 0 ]; then + echo "Problem converting the parameter list to the correct format, illegal characters detected. This is likely to be an error in this conversion script." + exit 1; +fi + +echo "Injecting the parameter list to the autocomplete file." +sed "5 s/.*/ local switches=\"$cleanstring\"/" cbmc.sh.template > cbmc.sh + +rm pragma.txt 2> /dev/null diff --git a/scripts/bash-autocomplete/switch_extractor_helper.c b/scripts/bash-autocomplete/switch_extractor_helper.c new file mode 100644 index 00000000000..4d9cc2e56fe --- /dev/null +++ b/scripts/bash-autocomplete/switch_extractor_helper.c @@ -0,0 +1,3 @@ +#include "cbmc/cbmc_parse_options.h" + +#pragma message CBMC_OPTIONS From b28c4187c484c5ac21815771839340d0bba4736f Mon Sep 17 00:00:00 2001 From: Cristina Date: Thu, 9 Feb 2017 15:36:36 +0000 Subject: [PATCH 09/52] Support for Java assume --- src/Makefile | 10 +++++++++- .../java_bytecode_convert_method.cpp | 19 +++++++++++++++++++ .../library/src/org/cprover/CProver.java | 11 +++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/java_bytecode/library/src/org/cprover/CProver.java diff --git a/src/Makefile b/src/Makefile index cc2a5831d8e..6d2c3f0a8fd 100644 --- a/src/Makefile +++ b/src/Makefile @@ -84,4 +84,12 @@ glucose-download: @(cd ../glucose-syrup; patch -p1 < ../scripts/glucose-syrup-patch) @rm glucose-syrup.tgz -.PHONY: minisat2-download glucose-download +cprover-jar-build: + @echo "Building org.cprover.jar" + @(cd java_bytecode/library/; \ + mkdir -p target; \ + javac -d target/ `find src/ -name "*.java"`; \ + cd target; jar cf org.cprover.jar `find . -name "*.class"`; \ + mv org.cprover.jar ../../../) + +.PHONY: minisat2-download glucose-download cprover-jar-build diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index b0b296c9cfd..6da2bad7129 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -1070,6 +1070,25 @@ codet java_bytecode_convert_methodt::convert_instructions( get_message_handler()); } } + // replace calls to CProver.assume + else if(statement=="invokestatic" && + id2string(arg0.get(ID_identifier))== + "java::org.cprover.CProver.assume:(Z)V") + { + const code_typet &code_type=to_code_type(arg0.type()); + // sanity check: function has the right number of args + assert(code_type.parameters().size()==1); + + exprt operand = pop(1)[0]; + // we may need to adjust the type of the argument + if(operand.type()!=bool_typet()) + operand.make_typecast(bool_typet()); + + c=code_assumet(operand); + source_locationt loc=i_it->source_location; + loc.set_function(method_id); + c.add_source_location()=loc; + } else if(statement=="invokeinterface" || statement=="invokespecial" || statement=="invokevirtual" || diff --git a/src/java_bytecode/library/src/org/cprover/CProver.java b/src/java_bytecode/library/src/org/cprover/CProver.java new file mode 100644 index 00000000000..72c3eeb1d70 --- /dev/null +++ b/src/java_bytecode/library/src/org/cprover/CProver.java @@ -0,0 +1,11 @@ +package org.cprover; + +public final class CProver +{ + public static boolean enableAssume=true; + public static void assume(boolean condition) + { + if(enableAssume) + throw new RuntimeException("Cannot execute program with CProver.assume()"); + } +} From c5c017fefb8992d8019db00b12f56bc1f69a844e Mon Sep 17 00:00:00 2001 From: Cristina Date: Thu, 9 Feb 2017 19:16:01 +0000 Subject: [PATCH 10/52] Regression tests for Java assume --- regression/cbmc-java/assume1/Assume1.class | Bin 0 -> 660 bytes regression/cbmc-java/assume1/Assume1.java | 10 ++++++++++ regression/cbmc-java/assume1/test.desc | 8 ++++++++ regression/cbmc-java/assume2/Assume2.class | Bin 0 -> 661 bytes regression/cbmc-java/assume2/Assume2.java | 10 ++++++++++ regression/cbmc-java/assume2/test.desc | 8 ++++++++ regression/cbmc-java/assume3/Assume3.class | Bin 0 -> 684 bytes regression/cbmc-java/assume3/Assume3.java | 10 ++++++++++ regression/cbmc-java/assume3/test.desc | 8 ++++++++ 9 files changed, 54 insertions(+) create mode 100644 regression/cbmc-java/assume1/Assume1.class create mode 100644 regression/cbmc-java/assume1/Assume1.java create mode 100644 regression/cbmc-java/assume1/test.desc create mode 100644 regression/cbmc-java/assume2/Assume2.class create mode 100644 regression/cbmc-java/assume2/Assume2.java create mode 100644 regression/cbmc-java/assume2/test.desc create mode 100644 regression/cbmc-java/assume3/Assume3.class create mode 100644 regression/cbmc-java/assume3/Assume3.java create mode 100644 regression/cbmc-java/assume3/test.desc diff --git a/regression/cbmc-java/assume1/Assume1.class b/regression/cbmc-java/assume1/Assume1.class new file mode 100644 index 0000000000000000000000000000000000000000..b9a49bc9971d81889935e4cefba60fffd292840c GIT binary patch literal 660 zcmZWmO>fgc5PcIn-o!OcnwAp6M*}U8a==3BjS3Y7kSc`_sZ}L%K-xIlvc=6-Yp3G3 zRN{uj8IULf3GVzT#H_KJ1Bda<&b)c^X8ill_n!bZupXj@PKYbGT1S9u0@p+M=m@NY z=;DUJO~T@u%ra$jZ6?`coyk$E#snG?f=xZq`9p%&Ti+x2eKS^s#z0Th^Xbt@*7KOOz00JZztI_?K6sR6(<62N0n_Xo!!*5Z$42kiwh0$@a+$n+CXdU$+GdiL zW5XRYwTXJF-H@o{xpyc}WP~|H0;>_$a4SL`A))OGaVjSVF+=|?^u$_Y38L&3xE_MCyTXUjp+<#ekzJV;{JJ~}gyD@9*r(7c}k5#6v8lMm4h4LvE z_-aGGa=`xppk~|2fJNYCk`r@=WkFXJv2CWPzIoh1@<+xu*ezL z{F>3O*6jozApDQ;y>F;|hIfia=RM|rz<+gy>MzIZ6}3); + assert x>0; + } +} diff --git a/regression/cbmc-java/assume1/test.desc b/regression/cbmc-java/assume1/test.desc new file mode 100644 index 00000000000..1f80a1c1e86 --- /dev/null +++ b/regression/cbmc-java/assume1/test.desc @@ -0,0 +1,8 @@ +CORE +Assume1.class +--function Assume1.foo +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/assume2/Assume2.class b/regression/cbmc-java/assume2/Assume2.class new file mode 100644 index 0000000000000000000000000000000000000000..36e09875d7d72406f27d2512b116cd7a586871d6 GIT binary patch literal 661 zcmZWmO>fgc5PcIn-qzUno^WK~BuixK(09eCnga*11F5qH_0G9+VNAS@VxDw$i zdIHx7iz_nEl`XWH<_~o)$C;WCXhaCs^;8%430{A7hu{y)L=l=pJylO<`(tId9hlG_ znp9>x(rS0F9{u9A&I#f0L7va{)!lnc^U4^e>2EqVddp{%aAvEJ>6<6=pz3R^r&%Q% zZJC)()nn~M;)>_ao;;K><`4^9kFkOqF+xOyjw>XYobDzJ{X5VjYmFs{s#oAy0JN~cv4J)g`NcKA zWVEaGy1{!0{{wvQD{7zM9ii0~?=bfr{)=POe>!5XB%Uwz1-CcYTlkMa4`;E&xMe;8 pyl{h-7<2B#=~^iTEVP3!5J#2XXL$d+b`*8g;te-jhc7jp{{vk5b}Ik? literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/assume2/Assume2.java b/regression/cbmc-java/assume2/Assume2.java new file mode 100644 index 00000000000..6991167bfb8 --- /dev/null +++ b/regression/cbmc-java/assume2/Assume2.java @@ -0,0 +1,10 @@ +import org.cprover.CProver; + +class Assume2 +{ + static void foo(int x) + { + CProver.assume(x>3); + assert x>4; + } +} diff --git a/regression/cbmc-java/assume2/test.desc b/regression/cbmc-java/assume2/test.desc new file mode 100644 index 00000000000..35a954116f8 --- /dev/null +++ b/regression/cbmc-java/assume2/test.desc @@ -0,0 +1,8 @@ +CORE +Assume2.class +--function Assume2.foo +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/assume3/Assume3.class b/regression/cbmc-java/assume3/Assume3.class new file mode 100644 index 0000000000000000000000000000000000000000..916ad4065fb77e04ba492a6f7499799ea22c85f7 GIT binary patch literal 684 zcmZuvO>fgc5PcIn-qjFF61OtQv!_%-mcDc`H0~3xAqC{AfGBid#E$Dx0p|qd2PXj?l4be zx-X5k>w42I-|B+k51$mpVy+(UaD%zj8DYKuW_T!%Wt_@v7LQ7!v)N8HK$;m-qW_c$ z=SHPW-o21Vb^q3GlGgHqQNA#VdakXQu%7q8jtH@WP~dimP236LBOvsavl;rw_%ma2 zLl8Ar;BJU}=o30i@XN`eN=lZOn^~M3nfzFpc<`!!rOU4pOeM?WroX zQPZ=bY^YptflqhLx8dVCzK834g7dFP%Wt9)KDJhRylCLkZyo7^Z2$lO literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/assume3/Assume3.java b/regression/cbmc-java/assume3/Assume3.java new file mode 100644 index 00000000000..895deee9ca0 --- /dev/null +++ b/regression/cbmc-java/assume3/Assume3.java @@ -0,0 +1,10 @@ +import org.cprover.CProver; + +class Assume3 +{ + public static void main(String[] args) + { + CProver.assume(false); + assert false; + } +} diff --git a/regression/cbmc-java/assume3/test.desc b/regression/cbmc-java/assume3/test.desc new file mode 100644 index 00000000000..0ad8c00399f --- /dev/null +++ b/regression/cbmc-java/assume3/test.desc @@ -0,0 +1,8 @@ +CORE +Assume3.class + +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring From 6385921c3eed014466090ad71ced56134af7126c Mon Sep 17 00:00:00 2001 From: Cristina Date: Tue, 20 Sep 2016 14:47:20 +0100 Subject: [PATCH 11/52] Remove assume as coverage target --- src/goto-instrument/cover.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index f2d17617ccd..60409dd265d 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -39,7 +39,12 @@ class basic_blockst source_location_map[block_count]=it->source_location; next_is_target= +#if 0 + // Disabled for being too messy it->is_goto() || it->is_function_call() || it->is_assume(); +#else + it->is_goto() || it->is_function_call(); +#endif } } From 6a192f04ad06cc781e5535e5a6c85d8c540937d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20G=C3=BCdemann?= Date: Wed, 1 Feb 2017 16:05:54 +0100 Subject: [PATCH 12/52] output covered lines as CSV in show_properties --- src/goto-instrument/cover.cpp | 56 ++++++++++++++++++++++----- src/goto-programs/show_properties.cpp | 3 ++ src/util/irep_ids.def | 1 + src/util/source_location.h | 10 +++++ 4 files changed, 61 insertions(+), 9 deletions(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index 60409dd265d..9c80bb2a788 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -13,9 +13,11 @@ Date: May 2016 #include #include +#include #include #include +#include #include "cover.h" @@ -32,6 +34,11 @@ class basic_blockst if(next_is_target || it->is_target()) block_count++; + const irep_idt &line=it->source_location.get_line(); + if(!line.empty()) + block_line_cover_map[block_count] + .insert(unsafe_string2unsigned(id2string(line))); + block_map[it]=block_count; if(!it->source_location.is_nil() && @@ -46,6 +53,24 @@ class basic_blockst it->is_goto() || it->is_function_call(); #endif } + + // create list of covered lines as CSV string and set as property of source + // location of basic block + for(const auto &cover_set : block_line_cover_map) + { + std::string covered_lines; + bool first=true; + for(const auto &line_number : cover_set.second) + { + if(first) + first=false; + else + covered_lines+=","; + covered_lines+=std::to_string(line_number); + } + source_location_map[cover_set.first] + .set_basic_block_covered_lines(covered_lines); + } } // map program locations to block numbers @@ -56,6 +81,11 @@ class basic_blockst typedef std::map source_location_mapt; source_location_mapt source_location_map; + // map block numbers to set of line numbers + typedef std::map > + block_line_cover_mapt; + block_line_cover_mapt block_line_cover_map; + inline unsigned operator[](goto_programt::const_targett t) { return block_map[t]; @@ -304,7 +334,7 @@ std::set collect_mcdc_controlling_nested( const std::set &decisions) { // To obtain the 1st-level controlling conditions - std::set controlling = collect_mcdc_controlling(decisions); + std::set controlling=collect_mcdc_controlling(decisions); std::set result; // For each controlling condition, to check if it contains @@ -495,7 +525,7 @@ void remove_repetition(std::set &exprs) **/ for(auto &y : new_exprs) { - bool iden = true; + bool iden=true; for(auto &c : conditions) { std::set signs1=sign_of_expr(c, x); @@ -537,7 +567,7 @@ void remove_repetition(std::set &exprs) } // update the original ''exprs'' - exprs = new_exprs; + exprs=new_exprs; } /// To evaluate the value of expr ''src'', according to the atomic expr values @@ -672,7 +702,8 @@ bool is_mcdc_pair( if(diff_count==1) return true; - else return false; + else + return false; } /// To check if we can find the mcdc pair of the input ''expr_set'' regarding @@ -774,7 +805,8 @@ void minimize_mcdc_controlling( { controlling=new_controlling; } - else break; + else + break; } } @@ -1062,9 +1094,12 @@ void instrument_cover_goals( const std::set decisions=collect_decisions(i_it); std::set both; - std::set_union(conditions.begin(), conditions.end(), - decisions.begin(), decisions.end(), - inserter(both, both.end())); + std::set_union( + conditions.begin(), + conditions.end(), + decisions.begin(), + decisions.end(), + inserter(both, both.end())); const source_locationt source_location=i_it->source_location; @@ -1151,7 +1186,10 @@ void instrument_cover_goals( f_it->second.is_hidden()) continue; - instrument_cover_goals(symbol_table, f_it->second.body, criterion); + instrument_cover_goals( + symbol_table, + f_it->second.body, + criterion); } } diff --git a/src/goto-programs/show_properties.cpp b/src/goto-programs/show_properties.cpp index a052a8aaecb..51c8eb81d34 100644 --- a/src/goto-programs/show_properties.cpp +++ b/src/goto-programs/show_properties.cpp @@ -109,6 +109,9 @@ void show_properties_json( json_properties.push_back(jsont()).make_object(); json_property["name"]=json_stringt(id2string(property_id)); json_property["class"]=json_stringt(id2string(property_class)); + if(!source_location.get_basic_block_covered_lines().empty()) + json_property["covered_lines"]= + json_stringt(id2string(source_location.get_basic_block_covered_lines())); json_property["sourceLocation"]=json(source_location); json_property["description"]=json_stringt(id2string(description)); json_property["expression"]= diff --git a/src/util/irep_ids.def b/src/util/irep_ids.def index e31eceb1e98..77568e3d5d6 100644 --- a/src/util/irep_ids.def +++ b/src/util/irep_ids.def @@ -810,6 +810,7 @@ IREP_ID_ONE(cprover_string_to_upper_case_func) IREP_ID_ONE(cprover_string_trim_func) IREP_ID_ONE(cprover_string_value_of_func) IREP_ID_ONE(array_replace) +IREP_ID_ONE(basic_block_covered_lines) #undef IREP_ID_ONE #undef IREP_ID_TWO diff --git a/src/util/source_location.h b/src/util/source_location.h index 4186f3e35e2..95bef820ae9 100644 --- a/src/util/source_location.h +++ b/src/util/source_location.h @@ -75,6 +75,11 @@ class source_locationt:public irept return get(ID_java_bytecode_index); } + const irep_idt &get_basic_block_covered_lines() const + { + return get(ID_basic_block_covered_lines); + } + void set_file(const irep_idt &file) { set(ID_file, file); @@ -130,6 +135,11 @@ class source_locationt:public irept set(ID_java_bytecode_index, index); } + void set_basic_block_covered_lines(const irep_idt &covered_lines) + { + return set(ID_basic_block_covered_lines, covered_lines); + } + void set_hide() { set(ID_hide, true); From 2ae6b606e9fa4b02783ab23866bcfa24a3c45e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20G=C3=BCdemann?= Date: Mon, 13 Feb 2017 15:59:29 +0100 Subject: [PATCH 13/52] compress list of lines into line ranges --- src/goto-instrument/cover.cpp | 19 ++--- src/goto-programs/show_properties.cpp | 5 +- src/util/Makefile | 1 + src/util/format_number_range.cpp | 114 ++++++++++++++++++++++++++ src/util/format_number_range.h | 21 +++++ 5 files changed, 147 insertions(+), 13 deletions(-) create mode 100644 src/util/format_number_range.cpp create mode 100644 src/util/format_number_range.h diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index 9c80bb2a788..ef64691b4a3 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -15,6 +15,7 @@ Date: May 2016 #include #include +#include #include #include #include @@ -55,19 +56,15 @@ class basic_blockst } // create list of covered lines as CSV string and set as property of source - // location of basic block + // location of basic block, compress to ranges if applicable + format_number_ranget format_lines; for(const auto &cover_set : block_line_cover_map) { - std::string covered_lines; - bool first=true; - for(const auto &line_number : cover_set.second) - { - if(first) - first=false; - else - covered_lines+=","; - covered_lines+=std::to_string(line_number); - } + assert(!cover_set.second.empty()); + std::vector + line_list{cover_set.second.begin(), cover_set.second.end()}; + + std::string covered_lines=format_lines(line_list); source_location_map[cover_set.first] .set_basic_block_covered_lines(covered_lines); } diff --git a/src/goto-programs/show_properties.cpp b/src/goto-programs/show_properties.cpp index 51c8eb81d34..9afa3f99eba 100644 --- a/src/goto-programs/show_properties.cpp +++ b/src/goto-programs/show_properties.cpp @@ -110,8 +110,9 @@ void show_properties_json( json_property["name"]=json_stringt(id2string(property_id)); json_property["class"]=json_stringt(id2string(property_class)); if(!source_location.get_basic_block_covered_lines().empty()) - json_property["covered_lines"]= - json_stringt(id2string(source_location.get_basic_block_covered_lines())); + json_property["coveredLines"]= + json_stringt( + id2string(source_location.get_basic_block_covered_lines())); json_property["sourceLocation"]=json(source_location); json_property["description"]=json_stringt(id2string(description)); json_property["expression"]= diff --git a/src/util/Makefile b/src/util/Makefile index d5030ef2a48..cff6340e044 100644 --- a/src/util/Makefile +++ b/src/util/Makefile @@ -17,6 +17,7 @@ SRC = arith_tools.cpp \ find_symbols.cpp \ fixedbv.cpp \ format_constant.cpp \ + format_number_range.cpp \ fresh_symbol.cpp \ get_base_name.cpp \ get_module.cpp \ diff --git a/src/util/format_number_range.cpp b/src/util/format_number_range.cpp new file mode 100644 index 00000000000..146808118ce --- /dev/null +++ b/src/util/format_number_range.cpp @@ -0,0 +1,114 @@ +/*******************************************************************\ + +Module: Format vector of numbers into a compressed range + +Author: Daniel Kroening, kroening@kroening.com + +\*******************************************************************/ + +#include +#include + +#include "format_number_range.h" + +/*******************************************************************\ + +Function: format_number_range::operator() + + Inputs: vector of numbers + + Outputs: string of compressed number range representation + + Purpose: create shorter representation for output + +\*******************************************************************/ + +std::string format_number_ranget::operator()(std::vector &numbers) +{ + std::string number_range; + std::sort(numbers.begin(), numbers.end()); + unsigned end_number=numbers.back(); + if(numbers.front()==end_number) + number_range=std::to_string(end_number); // only single number + else + { + bool next=true; + bool first=true; + bool range=false; + unsigned start_number=numbers.front(); + unsigned last_number=start_number; + + for(const auto &number : numbers) + { + if(next) + { + next=false; + start_number=number; + last_number=number; + } + // advance one forward + else + { + if(number==last_number+1 && !(number==end_number)) + { + last_number++; + if(last_number>start_number+1) + range=true; + } + // end this block range + else + { + if(first) + first=false; + else + number_range+=","; + if(last_number>start_number) + { + if(range) + { + if(number==end_number && number==last_number+1) + number_range+= + std::to_string(start_number)+"-"+std::to_string(end_number); + else if(number==end_number) + number_range+= + std::to_string(start_number)+"-"+std::to_string(last_number)+ + ","+std::to_string(end_number); + else + number_range+= + std::to_string(start_number)+"-"+std::to_string(last_number); + } + else + { + if(number!=end_number) + number_range+= + std::to_string(start_number)+","+std::to_string(last_number); + else + number_range+= + std::to_string(start_number)+","+std::to_string(last_number)+ + std::to_string(end_number); + } + start_number=number; + last_number=number; + range=false; + continue; + } + else + { + if(number!=end_number) + number_range+=std::to_string(start_number); + else + number_range+=std::to_string(start_number)+","+ + std::to_string(end_number); + start_number=number; + last_number=number; + range=false; + continue; // already set next start number + } + next=true; + } + } + } + } + assert(!number_range.empty()); + return number_range; +} diff --git a/src/util/format_number_range.h b/src/util/format_number_range.h new file mode 100644 index 00000000000..7ff016e9c4d --- /dev/null +++ b/src/util/format_number_range.h @@ -0,0 +1,21 @@ +/*******************************************************************\ + +Module: Format vector of numbers into a compressed range + +Author: Daniel Kroening, kroening@kroening.com + +\*******************************************************************/ + +#ifndef CPROVER_UTIL_FORMAT_NUMBER_RANGE_H +#define CPROVER_UTIL_FORMAT_NUMBER_RANGE_H + +#include +#include + +class format_number_ranget +{ +public: + std::string operator()(std::vector &); +}; + +#endif // CPROVER_UTIL_FORMAT_NUMBER_RANGE_H From 242c6095f10cffdb04ecb0f15491291b28562a5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20G=C3=BCdemann?= Date: Wed, 15 Feb 2017 23:53:28 +0100 Subject: [PATCH 14/52] add regression test for coverage lines --- regression/cbmc-java/covered1/covered1.class | Bin 0 -> 750 bytes regression/cbmc-java/covered1/covered1.java | 37 +++++++++++++++++++ regression/cbmc-java/covered1/test.desc | 19 ++++++++++ 3 files changed, 56 insertions(+) create mode 100644 regression/cbmc-java/covered1/covered1.class create mode 100644 regression/cbmc-java/covered1/covered1.java create mode 100644 regression/cbmc-java/covered1/test.desc diff --git a/regression/cbmc-java/covered1/covered1.class b/regression/cbmc-java/covered1/covered1.class new file mode 100644 index 0000000000000000000000000000000000000000..7cb91496b7df5bc0b1e7f8b6db0aa9a4992bd947 GIT binary patch literal 750 zcmYk4TWb?h6ouEBOJ*jSCQa%+wf9SU)TC(>1*uXHiUBVVl?py}G8x*`n3Rwf?N9N^ zw?5lA2nzlHf0VlRp`r}?+xwiuIcx3B{QULp2Y?11WKlpRKptxXEx04NE4U}93TlFN zL0zyR*c3E8G(Fr`Q12Nn#s|ikf_1jeB4V@^>_Ml)>WysI1sj4*K||0~$ZU1{-O*zO zx6*2@?I}1<2AxEq@T}WUUYxvZC&O1!yT_f0-BA?3eI6Z~HT4zzt+;o2-LA;x?C#)X z7$-Yjb0Hp_Cc~stuO3CGQHU8VhnPe$L`g6uxGA_LC<|^2t_rRRt_ZHw`A%h|$M8{-GG5hkKSyRDeikN*$m^Iy)OhYEqlR2ll zS<@b~#hAe?6y{ichs_Uot-nHPCxxZm6t>Q!aHMjj%4jczr~MSZE>9n(2$=R$Wc3#W z Date: Fri, 17 Feb 2017 11:12:48 +0100 Subject: [PATCH 15/52] fix problem with missing comma / range fix for reaching end --- src/util/format_number_range.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/util/format_number_range.cpp b/src/util/format_number_range.cpp index 146808118ce..cca3bbf154c 100644 --- a/src/util/format_number_range.cpp +++ b/src/util/format_number_range.cpp @@ -8,6 +8,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include "format_number_range.h" @@ -83,9 +84,16 @@ std::string format_number_ranget::operator()(std::vector &numbers) number_range+= std::to_string(start_number)+","+std::to_string(last_number); else - number_range+= - std::to_string(start_number)+","+std::to_string(last_number)+ - std::to_string(end_number); + { + if(start_number+1==last_number && last_number+1==number) + number_range+= + std::to_string(start_number)+"-"+std::to_string(end_number); + else + number_range+= + std::to_string(start_number)+ + ","+std::to_string(last_number)+ + ","+std::to_string(end_number); + } } start_number=number; last_number=number; From 1cdbff41dc3f71dbcba1d0c19c1383c390482244 Mon Sep 17 00:00:00 2001 From: thk123 Date: Mon, 16 Jan 2017 15:11:43 +0000 Subject: [PATCH 16/52] Updated dump-C to use the new class --- src/goto-instrument/dump_c.cpp | 265 +------------------ src/goto-instrument/dump_c_class.h | 8 +- src/goto-programs/system_library_symbols.cpp | 81 +++--- src/goto-programs/system_library_symbols.h | 3 +- 4 files changed, 55 insertions(+), 302 deletions(-) diff --git a/src/goto-instrument/dump_c.cpp b/src/goto-instrument/dump_c.cpp index fa9ebf63359..7e67a6bf5b1 100644 --- a/src/goto-instrument/dump_c.cpp +++ b/src/goto-instrument/dump_c.cpp @@ -148,7 +148,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) && ignore(symbol)) + if((!tag_added || symbol.is_type) && + system_symbols.is_symbol_internal_symbol(symbol, system_headers)) continue; bool inserted=symbols_sorted.insert(name_str).second; @@ -317,7 +318,7 @@ void dump_ct::convert_compound( ns.lookup(to_symbol_type(type).get_identifier()); DATA_INVARIANT(symbol.is_type, "symbol expected to be type symbol"); - if(!ignore(symbol)) + if(!system_symbols.is_symbol_internal_symbol(symbol, system_headers)) convert_compound(symbol.type, unresolved, recursive, os); } else if(type.id()==ID_c_enum_tag) @@ -326,7 +327,7 @@ void dump_ct::convert_compound( ns.lookup(to_c_enum_tag_type(type).get_identifier()); DATA_INVARIANT(symbol.is_type, "symbol expected to be type symbol"); - if(!ignore(symbol)) + if(!system_symbols.is_symbol_internal_symbol(symbol, system_headers)) convert_compound(symbol.type, unresolved, recursive, os); } else if(type.id()==ID_array || type.id()==ID_pointer) @@ -581,195 +582,6 @@ void dump_ct::convert_compound_enum( os << ";\n\n"; } -#define ADD_TO_SYSTEM_LIBRARY(v, header) \ - for(size_t i=0; isecond); - return true; - } - - if(use_all_headers && - has_prefix(file_str, "/usr/include/")) - { - if(file_str.find("/bits/")==std::string::npos) - { - // Do not include transitive includes of system headers! - std::string::size_type prefix_len=std::string("/usr/include/").size(); - system_headers.insert(file_str.substr(prefix_len)); - } - - return true; - } - - return false; -} - void dump_ct::cleanup_decl( code_declt &decl, std::list &local_static, diff --git a/src/goto-instrument/dump_c_class.h b/src/goto-instrument/dump_c_class.h index 255cb88677e..3c6fab3e652 100644 --- a/src/goto-instrument/dump_c_class.h +++ b/src/goto-instrument/dump_c_class.h @@ -18,6 +18,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include class dump_ct { @@ -35,7 +36,7 @@ class dump_ct use_all_headers(use_all_headers) { if(use_system_headers) - init_system_library_map(); + system_symbols=system_library_symbolst(); } virtual ~dump_ct() @@ -57,9 +58,7 @@ class dump_ct std::set system_headers; - typedef std::unordered_map - system_library_mapt; - system_library_mapt system_library_map; + system_library_symbolst system_symbols; typedef std::unordered_map declared_enum_constants_mapt; @@ -89,7 +88,6 @@ class dump_ct std::string type_to_string(const typet &type); std::string expr_to_string(const exprt &expr); - bool ignore(const symbolt &symbol); bool ignore(const typet &type); static std::string indent(const unsigned n) diff --git a/src/goto-programs/system_library_symbols.cpp b/src/goto-programs/system_library_symbols.cpp index 76023d0c455..7e885a8f150 100644 --- a/src/goto-programs/system_library_symbols.cpp +++ b/src/goto-programs/system_library_symbols.cpp @@ -63,13 +63,13 @@ void system_library_symbolst::init_system_library_map() "cbrt", "ceil", "copysign", "cos", "cosh", "erf", "erfc", "exp", "exp2", "expm1", "fabs", "fdim", "floor", "fma", "fmax", "fmin", "fmod", "fpclassify", "fpclassifyl", "fpclassifyf", "frexp", - "hypot", "ilogb", "isfinite", "isinf", "isnan", "isnormal", - "j0", "j1", "jn", "ldexp", "lgamma", "llrint", "llround", "log", - "log10", "log1p", "log2", "logb", "lrint", "lround", "modf", "nan", - "nearbyint", "nextafter", "pow", "remainder", "remquo", "rint", - "round", "scalbln", "scalbn", "signbit", "sin", "sinh", "sqrt", - "tan", "tanh", "tgamma", "trunc", "y0", "y1", "yn", "isinff", - "isinfl", "isnanf", "isnanl" + "hypot", "ilogb", "isfinite", "isinf", "isinff", "isinfl", + "isnan", "isnanf", "isnanl", "isnormal", "j0", "j1", "jn", + "ldexp", "lgamma", "llrint", "llround", "log", "log10", "log1p", + "log2", "logb", "lrint", "lround", "modf", "nan", "nearbyint", + "nextafter", "pow", "remainder", "remquo", "rint", "round", + "scalbln", "scalbn", "signbit", "sin", "sinh", "sqrt", "tan", + "tanh", "tgamma", "trunc", "y0", "y1", "yn" }; add_to_system_library("math.h", math_syms); @@ -100,7 +100,10 @@ void system_library_symbolst::init_system_library_map() "pthread_rwlock_unlock", "pthread_rwlock_wrlock", "pthread_rwlockattr_destroy", "pthread_rwlockattr_getpshared", "pthread_rwlockattr_init", "pthread_rwlockattr_setpshared", - "pthread_self", "pthread_setspecific" + "pthread_self", "pthread_setspecific", + /* non-public struct types */ + "tag-__pthread_internal_list", "tag-__pthread_mutex_s", + "pthread_mutex_t" }; add_to_system_library("pthread.h", pthread_syms); @@ -125,7 +128,7 @@ void system_library_symbolst::init_system_library_map() "mkstemp", "mktemp", "perror", "printf", "putc", "putchar", "puts", "putw", "putwc", "putwchar", "remove", "rewind", "scanf", "setbuf", "setbuffer", "setlinebuf", "setvbuf", "snprintf", - "sprintf", "sscanf", "strerror", "swprintf", "sys_errlist", + "sprintf", "sscanf", "swprintf", "sys_errlist", "sys_nerr", "tempnam", "tmpfile", "tmpnam", "ungetc", "ungetwc", "vasprintf", "vfprintf", "vfscanf", "vfwprintf", "vprintf", "vscanf", "vsnprintf", "vsprintf", "vsscanf", "vswprintf", @@ -151,10 +154,10 @@ void system_library_symbolst::init_system_library_map() // string.h std::list string_syms= { - "strcat", "strncat", "strchr", "strrchr", "strcmp", "strncmp", - "strcpy", "strncpy", "strerror", "strlen", "strpbrk", "strspn", - "strcspn", "strstr", "strtok", "strcasecmp", "strncasecmp", "strdup", - "memset" + "memset", "strcasecmp", "strcat", "strchr", "strcmp", "strcpy", + "strcspn", "strdup", "strerror", "strlen", "strncasecmp", + "strncat", "strncmp", "strncpy", "strpbrk", "strrchr", "strspn", + "strstr", "strtok" }; add_to_system_library("string.h", string_syms); @@ -162,9 +165,9 @@ void system_library_symbolst::init_system_library_map() std::list time_syms= { "asctime", "asctime_r", "ctime", "ctime_r", "difftime", "gmtime", - "gmtime_r", "localtime", "localtime_r", "mktime", + "gmtime_r", "localtime", "localtime_r", "mktime", "strftime", /* non-public struct types */ - "tag-timespec", "tag-timeval" + "tag-timespec", "tag-timeval", "tag-tm" }; add_to_system_library("time.h", time_syms); @@ -185,21 +188,27 @@ void system_library_symbolst::init_system_library_map() // sys/select.h std::list sys_select_syms= { - "select" + "select", + /* non-public struct types */ + "fd_set" }; add_to_system_library("sys/select.h", sys_select_syms); // sys/socket.h std::list sys_socket_syms= { - "accept", "bind", "connect" + "accept", "bind", "connect", + /* non-public struct types */ + "tag-sockaddr" }; add_to_system_library("sys/socket.h", sys_socket_syms); // sys/stat.h std::list sys_stat_syms= { - "fstat", "lstat", "stat" + "fstat", "lstat", "stat", + /* non-public struct types */ + "tag-stat" }; add_to_system_library("sys/stat.h", sys_stat_syms); @@ -284,7 +293,7 @@ Purpose: To find out if a symbol is an internal symbol. bool system_library_symbolst::is_symbol_internal_symbol( const symbolt &symbol, - std::set &out_system_headers) const + std::set &out_system_headers) const { const std::string &name_str=id2string(symbol.name); @@ -300,24 +309,18 @@ bool system_library_symbolst::is_symbol_internal_symbol( // exclude nondet instructions if(has_prefix(name_str, "nondet_")) - { return true; - } if(has_prefix(name_str, "__VERIFIER")) - { return true; - } + + if(has_suffix(name_str, "$object")) + return true; const std::string &file_str=id2string(symbol.location.get_file()); // don't dump internal GCC builtins - if((file_str=="gcc_builtin_headers_alpha.h" || - file_str=="gcc_builtin_headers_arm.h" || - file_str=="gcc_builtin_headers_ia32.h" || - file_str=="gcc_builtin_headers_mips.h" || - file_str=="gcc_builtin_headers_power.h" || - file_str=="gcc_builtin_headers_generic.h") && + if(has_prefix(file_str, "gcc_builtin_headers_") && has_prefix(name_str, "__builtin_")) return true; @@ -334,18 +337,26 @@ bool system_library_symbolst::is_symbol_internal_symbol( name_str=="_assert" || name_str=="__assert_c99" || name_str=="_wassert") - { return true; - } - - if(name_str.find("$link")!=std::string::npos) - return false; const auto &it=system_library_map.find(symbol.name); if(it!=system_library_map.end()) { - out_system_headers.insert(it->second); + out_system_headers.insert(id2string(it->second)); + return true; + } + + if(use_all_headers && + has_prefix(file_str, "/usr/include/")) + { + if(file_str.find("/bits/")==std::string::npos) + { + // Do not include transitive includes of system headers! + std::string::size_type prefix_len=std::string("/usr/include/").size(); + out_system_headers.insert(file_str.substr(prefix_len)); + } + return true; } diff --git a/src/goto-programs/system_library_symbols.h b/src/goto-programs/system_library_symbols.h index a253b903bd8..9438e052a76 100644 --- a/src/goto-programs/system_library_symbols.h +++ b/src/goto-programs/system_library_symbols.h @@ -11,6 +11,7 @@ Author: Thomas Kiley #include #include +#include #include class symbolt; @@ -22,7 +23,7 @@ class system_library_symbolst bool is_symbol_internal_symbol( const symbolt &symbol, - std::set &out_system_headers) const; + std::set &out_system_headers) const; private: void init_system_library_map(); From b1348d00f49446a6922a5a89b3f7520a2b63c9f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20G=C3=BCdemann?= Date: Thu, 2 Mar 2017 15:10:22 +0100 Subject: [PATCH 17/52] update interpreter --- .../goto_instrument_parse_options.cpp | 2 +- src/goto-programs/interpreter.cpp | 852 ++++++++++++++++-- src/goto-programs/interpreter.h | 5 +- src/goto-programs/interpreter_class.h | 157 +++- src/goto-programs/interpreter_evaluate.cpp | 795 ++++++++++++++-- 5 files changed, 1647 insertions(+), 164 deletions(-) diff --git a/src/goto-instrument/goto_instrument_parse_options.cpp b/src/goto-instrument/goto_instrument_parse_options.cpp index b807b21dc9a..92995c74252 100644 --- a/src/goto-instrument/goto_instrument_parse_options.cpp +++ b/src/goto-instrument/goto_instrument_parse_options.cpp @@ -539,7 +539,7 @@ int goto_instrument_parse_optionst::doit() if(cmdline.isset("interpreter")) { status() << "Starting interpreter" << eom; - interpreter(symbol_table, goto_functions); + interpreter(symbol_table, goto_functions, get_message_handler()); return 0; } diff --git a/src/goto-programs/interpreter.cpp b/src/goto-programs/interpreter.cpp index 8a5c23f1a62..1f9e22f485a 100644 --- a/src/goto-programs/interpreter.cpp +++ b/src/goto-programs/interpreter.cpp @@ -12,18 +12,65 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include +#include #include +#include #include #include +#include +#include +#include +#include +#include #include "interpreter.h" #include "interpreter_class.h" +#include "remove_returns.h" + +const size_t interpretert::npos=std::numeric_limits::max(); void interpretert::operator()() +{ + status() << "0- Initialize:" << eom; + initialize(true); + try + { + status() << "Type h for help\n" << eom; + + while(!done) + command(); + + status() << total_steps << "- Program End.\n" << eom; + } + catch (const char *e) + { + error() << e << "\n" << eom; + } + + while(!done) + command(); +} + +/*******************************************************************\ + +Function: interpretert::initialize + + Inputs: + + Outputs: + + Purpose: Initializes the memory map of the interpreter and + [optionally] runs up to the entry point (thus doing + the cprover initialization) + +\*******************************************************************/ + +void interpretert::initialize(bool init) { build_memory_map(); + total_steps=0; const goto_functionst::function_mapt::const_iterator main_it=goto_functions.function_map.find(goto_functionst::entry_point()); @@ -35,36 +82,54 @@ void interpretert::operator()() if(!goto_function.body_available()) throw "main has no body"; - PC=goto_function.body.instructions.begin(); + pc=goto_function.body.instructions.begin(); function=main_it; done=false; - - while(!done) + if(init) { + stack_depth=call_stack.size()+1; show_state(); - command(); - if(!done) + step(); + while(!done && (stack_depth<=call_stack.size()) && (stack_depth!=npos)) + { + show_state(); step(); + } + while(!done && (call_stack.size()==0)) + { + show_state(); + step(); + } + clear_input_flags(); + input_vars.clear(); } } +/// displays the current position of the pc and corresponding code void interpretert::show_state() { - std::cout << "\n----------------------------------------------------\n"; + if(!show) + return; + status() << "\n" + << total_steps+1 + << " ----------------------------------------------------\n"; - if(PC==function->second.body.instructions.end()) + if(pc==function->second.body.instructions.end()) { - std::cout << "End of function `" - << function->first << "'\n"; + status() << "End of function `" << function->first << "'\n"; } else function->second.body.output_instruction( - ns, function->first, std::cout, PC); + ns, + function->first, + status(), + pc); - std::cout << '\n'; + status() << eom; } +/// reads a user command and executes it. void interpretert::command() { #define BUFSIZE 100 @@ -76,42 +141,140 @@ void interpretert::command() } char ch=tolower(command[0]); - if(ch=='q') done=true; + else if(ch=='h') + { + status() + << "Interpreter help\n" + << "h: display this menu\n" + << "j: output json trace\n" + << "m: output memory dump\n" + << "o: output goto trace\n" + << "q: quit\n" + << "r: run until completion\n" + << "s#: step a number of instructions\n" + << "sa: step across a function\n" + << "so: step out of a function\n" + << eom; + } + else if(ch=='j') + { + jsont json_steps; + convert(ns, steps, json_steps); + ch=tolower(command[1]); + if(ch==' ') + { + std::ofstream file; + file.open(command+2); + if(file.is_open()) + { + json_steps.output(file); + file.close(); + return; + } + } + json_steps.output(result()); + } + else if(ch=='m') + { + ch=tolower(command[1]); + print_memory(ch=='i'); + } + else if(ch=='o') + { + ch=tolower(command[1]); + if(ch==' ') + { + std::ofstream file; + file.open(command+2); + if(file.is_open()) + { + steps.output(ns, file); + file.close(); + return; + } + } + steps.output(ns, result()); + } + else if(ch=='r') + { + ch=tolower(command[1]); + initialize(ch!='0'); + } + else if((ch=='s') || (ch==0)) + { + num_steps=1; + stack_depth=npos; + ch=tolower(command[1]); + if(ch=='e') + num_steps=npos; + else if(ch=='o') + stack_depth=call_stack.size(); + else if(ch=='a') + stack_depth=call_stack.size()+1; + else + { + num_steps=atoi(command+1); + if(num_steps==0) + num_steps=1; + } + while(!done && ((num_steps==npos) || ((num_steps--)>0))) + { + step(); + show_state(); + } + while(!done && (stack_depth<=call_stack.size()) && (stack_depth!=npos)) + { + step(); + show_state(); + } + return; + } + show_state(); } +/// executes a single step and updates the program counter void interpretert::step() { - if(PC==function->second.body.instructions.end()) + total_steps++; + if(pc==function->second.body.instructions.end()) { if(call_stack.empty()) done=true; else { - PC=call_stack.top().return_PC; + pc=call_stack.top().return_pc; function=call_stack.top().return_function; - stack_pointer=call_stack.top().old_stack_pointer; + // TODO: this increases memory size quite quickly. + // Should check alternatives call_stack.pop(); } return; } - next_PC=PC; - next_PC++; + next_pc=pc; + next_pc++; - switch(PC->type) + steps.add_step(goto_trace_stept()); + goto_trace_stept &trace_step=steps.get_last_step(); + trace_step.thread_nr=thread_id; + trace_step.pc=pc; + switch(pc->type) { case GOTO: + trace_step.type=goto_trace_stept::GOTO; execute_goto(); break; case ASSUME: + trace_step.type=goto_trace_stept::ASSUME; execute_assume(); break; case ASSERT: + trace_step.type=goto_trace_stept::ASSERT; execute_assert(); break; @@ -120,38 +283,46 @@ void interpretert::step() break; case DECL: + trace_step.type=goto_trace_stept::DECL; execute_decl(); break; case SKIP: case LOCATION: + trace_step.type=goto_trace_stept::LOCATION; + break; case END_FUNCTION: + trace_step.type=goto_trace_stept::FUNCTION_RETURN; break; case RETURN: + trace_step.type=goto_trace_stept::FUNCTION_RETURN; if(call_stack.empty()) throw "RETURN without call"; // NOLINT(readability/throw) - if(PC->code.operands().size()==1 && + if(pc->code.operands().size()==1 && call_stack.top().return_value_address!=0) { - std::vector rhs; - evaluate(PC->code.op0(), rhs); + mp_vectort rhs; + evaluate(pc->code.op0(), rhs); assign(call_stack.top().return_value_address, rhs); } - next_PC=function->second.body.instructions.end(); + next_pc=function->second.body.instructions.end(); break; case ASSIGN: + trace_step.type=goto_trace_stept::ASSIGNMENT; execute_assign(); break; case FUNCTION_CALL: + trace_step.type=goto_trace_stept::FUNCTION_CALL; execute_function_call(); break; case START_THREAD: + trace_step.type=goto_trace_stept::SPAWN; throw "START_THREAD not yet implemented"; // NOLINT(readability/throw) case END_THREAD: @@ -159,44 +330,89 @@ void interpretert::step() break; case ATOMIC_BEGIN: + trace_step.type=goto_trace_stept::ATOMIC_BEGIN; throw "ATOMIC_BEGIN not yet implemented"; // NOLINT(readability/throw) case ATOMIC_END: + trace_step.type=goto_trace_stept::ATOMIC_END; throw "ATOMIC_END not yet implemented"; // NOLINT(readability/throw) case DEAD: - throw "DEAD not yet implemented"; // NOLINT(readability/throw) - + trace_step.type=goto_trace_stept::DEAD; + break; + case THROW: + trace_step.type=goto_trace_stept::GOTO; + while(!done && (pc->type!=CATCH)) + { + if(pc==function->second.body.instructions.end()) + { + if(call_stack.empty()) + done=true; + else + { + pc=call_stack.top().return_pc; + function=call_stack.top().return_function; + call_stack.pop(); + } + } + else + { + next_pc=pc; + next_pc++; + } + } + break; + case CATCH: + break; default: throw "encountered instruction with undefined instruction type"; } - - PC=next_PC; + pc=next_pc; } +/// executes a goto instruction void interpretert::execute_goto() { - if(evaluate_boolean(PC->guard)) + if(evaluate_boolean(pc->guard)) { - if(PC->targets.empty()) + if(pc->targets.empty()) throw "taken goto without target"; - if(PC->targets.size()>=2) + if(pc->targets.size()>=2) throw "non-deterministic goto encountered"; - next_PC=PC->targets.front(); + next_pc=pc->targets.front(); } } +/// executes side effects of 'other' instructions void interpretert::execute_other() { - const irep_idt &statement=PC->code.get_statement(); - + const irep_idt &statement=pc->code.get_statement(); if(statement==ID_expression) { - assert(PC->code.operands().size()==1); - std::vector rhs; - evaluate(PC->code.op0(), rhs); + assert(pc->code.operands().size()==1); + mp_vectort rhs; + evaluate(pc->code.op0(), rhs); + } + else if(statement==ID_array_set) + { + mp_vectort tmp, rhs; + evaluate(pc->code.op1(), tmp); + mp_integer address=evaluate_address(pc->code.op0()); + size_t size=get_size(pc->code.op0().type()); + while(rhs.size()code.get_statement()==ID_decl); + assert(pc->code.get_statement()==ID_decl); +} + +/*******************************************************************\ + +Function: interpretert::get_component_id + + Inputs: an object and a memory offset + + Outputs: + + Purpose: retrieves the member at offset + +\*******************************************************************/ + +irep_idt interpretert::get_component_id( + const irep_idt &object, + unsigned offset) +{ + const symbolt &symbol=ns.lookup(object); + const typet real_type=ns.follow(symbol.type); + if(real_type.id()!=ID_struct) + throw "request for member of non-struct"; + + const struct_typet &struct_type=to_struct_type(real_type); + const struct_typet::componentst &components=struct_type.components(); + for(struct_typet::componentst::const_iterator it=components.begin(); + it!=components.end(); it++) + { + if(offset<=0) + return it->id(); + size_t size=get_size(it->type()); + offset-=size; + } + return object; +} + +/*******************************************************************\ + +Function: interpretert::get_type + + Inputs: + + Outputs: + + Purpose: returns the type object corresponding to id + +\*******************************************************************/ + +typet interpretert::get_type(const irep_idt &id) const +{ + dynamic_typest::const_iterator it=dynamic_types.find(id); + if(it==dynamic_types.end()) + return symbol_table.lookup(id).type; + return it->second; +} + +/*******************************************************************\ + +Function: interpretert::get_value + + Inputs: + + Outputs: + + Purpose: retrives the constant value at memory location offset + as an object of type type + +\*******************************************************************/ + +exprt interpretert::get_value( + const typet &type, + std::size_t offset, + bool use_non_det) +{ + const typet real_type=ns.follow(type); + if(real_type.id()==ID_struct) + { + exprt result=struct_exprt(real_type); + const struct_typet &struct_type=to_struct_type(real_type); + const struct_typet::componentst &components=struct_type.components(); + + // Retrieve the values for the individual members + result.reserve_operands(components.size()); + for(struct_typet::componentst::const_iterator it=components.begin(); + it!=components.end(); it++) + { + size_t size=get_size(it->type()); + const exprt operand=get_value(it->type(), offset); + offset+=size; + result.copy_to_operands(operand); + } + return result; + } + else if(real_type.id()==ID_array) + { + // Get size of array + exprt result=array_exprt(to_array_type(real_type)); + const exprt &size_expr=static_cast(type.find(ID_size)); + size_t subtype_size=get_size(type.subtype()); + mp_integer mp_count; + to_integer(size_expr, mp_count); + unsigned count=integer2unsigned(mp_count); + + // Retrieve the value for each member in the array + result.reserve_operands(count); + for(unsigned i=0; i=0)) + return side_effect_expr_nondett(type); + mp_vectort rhs; + rhs.push_back(memory[offset].value); + return get_value(type, rhs); } +/*******************************************************************\ + + Function: interpretert::get_value + + Inputs: + + Outputs: + + Purpose: returns the value at offset in the form of type given a + memory buffer rhs which is typically a structured type + +\*******************************************************************/ + +exprt interpretert::get_value( + const typet &type, + mp_vectort &rhs, + std::size_t offset) +{ + const typet real_type=ns.follow(type); + assert(!rhs.empty()); + + if(real_type.id()==ID_struct) + { + exprt result=struct_exprt(real_type); + const struct_typet &struct_type=to_struct_type(real_type); + const struct_typet::componentst &components=struct_type.components(); + + // Retrieve the values for the individual members + result.reserve_operands(components.size()); + for(const struct_union_typet::componentt &expr : components) + { + size_t size=get_size(expr.type()); + const exprt operand=get_value(expr.type(), rhs, offset); + offset+=size; + result.copy_to_operands(operand); + } + return result; + } + else if(real_type.id()==ID_array) + { + exprt result(ID_constant, type); + const exprt &size_expr=static_cast(type.find(ID_size)); + + // Get size of array + size_t subtype_size=get_size(type.subtype()); + mp_integer mp_count; + to_integer(size_expr, mp_count); + unsigned count=integer2unsigned(mp_count); + + // Retrieve the value for each member in the array + result.reserve_operands(count); + for(unsigned i=0; i object count " << memory.size() << eom; + throw "interpreter: reading from invalid pointer"; + } + else if(real_type.id()==ID_string) + { + // Strings are currently encoded by their irep_idt ID. + return constant_exprt( + irep_idt(rhs[offset].to_long(), 0), + type); + } + // Retrieve value of basic data type + return from_integer(rhs[offset], type); +} + +/// executes the assign statement at the current pc value void interpretert::execute_assign() { const code_assignt &code_assign= - to_code_assign(PC->code); + to_code_assign(pc->code); - std::vector rhs; + mp_vectort rhs; evaluate(code_assign.rhs(), rhs); if(!rhs.empty()) { mp_integer address=evaluate_address(code_assign.lhs()); - unsigned size=get_size(code_assign.lhs().type()); + size_t size=get_size(code_assign.lhs().type()); if(size!=rhs.size()) - std::cout << "!! failed to obtain rhs (" - << rhs.size() << " vs. " - << size << ")\n"; + error() << "!! failed to obtain rhs (" + << rhs.size() << " vs. " + << size << ")\n" + << eom; else + { + goto_trace_stept &trace_step=steps.get_last_step(); assign(address, rhs); + trace_step.full_lhs=code_assign.lhs(); + + // TODO: need to look at other cases on ssa_exprt + // (dereference should be handled on ssa) + if(ssa_exprt::can_build_identifier(trace_step.full_lhs)) + { + trace_step.lhs_object=ssa_exprt(trace_step.full_lhs); + } + trace_step.full_lhs_value=get_value(trace_step.full_lhs.type(), rhs); + trace_step.lhs_object_value=trace_step.full_lhs_value; + } + } + else if(code_assign.rhs().id()==ID_side_effect) + { + side_effect_exprt side_effect=to_side_effect_expr(code_assign.rhs()); + if(side_effect.get_statement()==ID_nondet) + { + unsigned address=integer2unsigned(evaluate_address(code_assign.lhs())); + size_t size=get_size(code_assign.lhs().type()); + for(size_t i=0; i &rhs) + const mp_vectort &rhs) { - for(unsigned i=0; iguard)) + if(!evaluate_boolean(pc->guard)) throw "assumption failed"; } void interpretert::execute_assert() { - if(!evaluate_boolean(PC->guard)) - throw "assertion failed"; + if(!evaluate_boolean(pc->guard)) + { + if((target_assert==pc) || stop_on_assertion) + throw "program assertion reached"; + else if(show) + error() << "assertion failed at " << pc->location_number + << "\n" << eom; + } } void interpretert::execute_function_call() { const code_function_callt &function_call= - to_code_function_call(PC->code); + to_code_function_call(pc->code); // function to be called mp_integer a=evaluate_address(function_call.function()); @@ -270,8 +774,12 @@ void interpretert::execute_function_call() else if(a>=memory.size()) throw "out-of-range function call"; + // Retrieve the empty last trace step struct we pushed for this step + // of the interpreter run to fill it with the corresponding data + goto_trace_stept &trace_step=steps.get_last_step(); const memory_cellt &cell=memory[integer2size_t(a)]; const irep_idt &identifier=cell.identifier; + trace_step.identifier=identifier; const goto_functionst::function_mapt::const_iterator f_it= goto_functions.function_map.find(identifier); @@ -289,7 +797,7 @@ void interpretert::execute_function_call() return_value_address=0; // values of the arguments - std::vector > argument_values; + std::vector argument_values; argument_values.resize(function_call.arguments().size()); @@ -303,7 +811,7 @@ void interpretert::execute_function_call() call_stack.push(stack_framet()); stack_framet &frame=call_stack.top(); - frame.return_PC=next_PC; + frame.return_pc=next_pc; frame.return_function=function; frame.old_stack_pointer=stack_pointer; frame.return_value_address=return_value_address; @@ -315,24 +823,7 @@ void interpretert::execute_function_call() for(const auto &id : locals) { const symbolt &symbol=ns.lookup(id); - unsigned size=get_size(symbol.type); - - if(size!=0) - { - frame.local_map[id]=stack_pointer; - - for(unsigned i=0; i=memory.size()) - memory.resize(address+1); - memory[address].value=0; - memory[address].identifier=id; - memory[address].offset=i; - } - - stack_pointer+=size; - } + frame.local_map[id]=integer2unsigned(build_memory_map(id, symbol.type)); } // assign the arguments @@ -342,7 +833,7 @@ void interpretert::execute_function_call() if(argument_values.size()second.body.instructions.begin(); + next_pc=f_it->second.body.instructions.begin(); } else - throw "no body for "+id2string(identifier); + { + list_input_varst::iterator it= + function_input_vars.find(function_call.function().get(ID_identifier)); + if(it!=function_input_vars.end()) + { + mp_vectort value; + assert(!it->second.empty()); + assert(!it->second.front().return_assignments.empty()); + evaluate(it->second.front().return_assignments.back().value, value); + if(return_value_address>0) + { + assign(return_value_address, value); + } + it->second.pop_front(); + return; + } + if(show) + error() << "no body for "+id2string(identifier) << eom; + } } +/// Creates a memory map of all static symbols in the program void interpretert::build_memory_map() { // put in a dummy for NULL memory.resize(1); memory[0].offset=0; memory[0].identifier="NULL-OBJECT"; + memory[0].initialized=0; + + num_dynamic_objects=0; + dynamic_types.clear(); // now do regular static symbols for(const auto &s : symbol_table.symbols) @@ -376,7 +890,7 @@ void interpretert::build_memory_map() void interpretert::build_memory_map(const symbolt &symbol) { - unsigned size=0; + size_t size=0; if(symbol.type.id()==ID_code) { @@ -393,17 +907,110 @@ void interpretert::build_memory_map(const symbolt &symbol) memory.resize(address+size); memory_map[symbol.name]=address; - for(unsigned i=0; i(type.find(ID_size)); + mp_vectort computed_size; + evaluate(size_expr, computed_size); + if(computed_size.size()==1 && + computed_size[0]>=0) + { + result() << "Concretized array with size " << computed_size[0] + << eom; + return array_typet(type.subtype(), + constant_exprt::integer_constant(computed_size[0].to_ulong())); + } + else + { + error() << "Failed to concretize variable array" + << eom; + } + } + return type; +} + +/*******************************************************************\ + +Function: interpretert::build_memory_map + + Inputs: + + Outputs: Updtaes the memory map to include variable id if it does + not exist + + Purpose: Populates dynamic entries of the memory map + +\*******************************************************************/ + +mp_integer interpretert::build_memory_map( + const irep_idt &id, + const typet &type) +{ + typet alloc_type=concretize_type(type); + size_t size=get_size(alloc_type); + auto it=dynamic_types.find(id); + + if(it!=dynamic_types.end()) + { + unsigned offset=1; + unsigned address=memory_map[id]; + while(memory[address+offset].offset>0) offset++; + + // current size <= size already recorded + if(size<=offset) + return memory_map[id]; + } + + // The current size is bigger then the one previously recorded + // in the memory map + + if(size==0) + size=1; // This is a hack to create existence + + unsigned address=memory.size(); + memory.resize(address+size); + memory_map[id]=address; + dynamic_types.insert(std::pair(id, alloc_type)); + + for(size_t i=0; i>>>>>> fef1fed6b... update interpreter { if(type.id()==ID_struct) { @@ -427,7 +1034,7 @@ unsigned interpretert::get_size(const typet &type) const const union_typet::componentst &components= to_union_type(type).components(); - unsigned max_size=0; + size_t max_size=0; for(const auto &comp : components) { @@ -443,26 +1050,93 @@ unsigned interpretert::get_size(const typet &type) const { const exprt &size_expr=static_cast(type.find(ID_size)); - unsigned subtype_size=get_size(type.subtype()); + size_t subtype_size=get_size(type.subtype()); - mp_integer i; - if(!to_integer(size_expr, i)) - return subtype_size*integer2unsigned(i); - else - return subtype_size; + mp_vectort i; + evaluate(size_expr, i); + if(i.size()==1) + { + // Go via the binary representation to reproduce any + // overflow behaviour. + exprt size_const=from_integer(i[0], size_expr.type()); + mp_integer size_mp; + assert(!to_integer(size_const, size_mp)); + return subtype_size*integer2unsigned(size_mp); + } + return subtype_size; } else if(type.id()==ID_symbol) { return get_size(ns.follow(type)); } + return 1; +} + +/******************************************************************* \ + +Function: interpretert::get_value + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt interpretert::get_value(const irep_idt &id) +{ + // The dynamic type and the static symbol type may differ for VLAs, + // where the symbol carries a size expression and the dynamic type + // registry contains its actual length. + auto findit=dynamic_types.find(id); + typet get_type; + if(findit!=dynamic_types.end()) + get_type=findit->second; else - return 1; + get_type=symbol_table.lookup(id).type; + + symbol_exprt symbol_expr(id, get_type); + mp_integer whole_lhs_object_address=evaluate_address(symbol_expr); + + return get_value(get_type, integer2unsigned(whole_lhs_object_address)); } void interpreter( const symbol_tablet &symbol_table, - const goto_functionst &goto_functions) + const goto_functionst &goto_functions, + message_handlert &message_handler) { - interpretert interpreter(symbol_table, goto_functions); + interpretert interpreter( + symbol_table, + goto_functions, + message_handler); interpreter(); } + +/*******************************************************************\ + +Function: interpretert::print_memory + + Inputs: + + Outputs: + + Purpose: Prints the current state of the memory map + Since messaget mdofifies class members, print functions are nonconst + +\*******************************************************************/ + +void interpretert::print_memory(bool input_flags) +{ + for(size_t i=0; i(cell.initialized) << ")" + << eom; + debug() << eom; + } +} diff --git a/src/goto-programs/interpreter.h b/src/goto-programs/interpreter.h index 20113a54fc6..8d598852b1a 100644 --- a/src/goto-programs/interpreter.h +++ b/src/goto-programs/interpreter.h @@ -12,10 +12,13 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_GOTO_PROGRAMS_INTERPRETER_H #define CPROVER_GOTO_PROGRAMS_INTERPRETER_H +#include + #include "goto_functions.h" void interpreter( const symbol_tablet &symbol_table, - const goto_functionst &goto_functions); + const goto_functionst &goto_functions, + message_handlert &message_handler); #endif // CPROVER_GOTO_PROGRAMS_INTERPRETER_H diff --git a/src/goto-programs/interpreter_class.h b/src/goto-programs/interpreter_class.h index 9938862bb92..562df8d6d1e 100644 --- a/src/goto-programs/interpreter_class.h +++ b/src/goto-programs/interpreter_class.h @@ -17,24 +17,93 @@ Author: Daniel Kroening, kroening@kroening.com #include #include "goto_functions.h" +#include "goto_trace.h" +#include "json_goto_trace.h" +#include "util/message.h" -class interpretert +class interpretert:public messaget { public: interpretert( const symbol_tablet &_symbol_table, - const goto_functionst &_goto_functions): + const goto_functionst &_goto_functions, + message_handlert &_message_handler): + messaget(_message_handler), symbol_table(_symbol_table), ns(_symbol_table), - goto_functions(_goto_functions) + goto_functions(_goto_functions), + stop_on_assertion(false) { + show=true; } void operator()(); + void print_memory(bool input_flags); + + // An assertion that identifier 'id' carries value in some particular context. + // Used to record parameter (id) assignment (value) lists for function calls. + struct function_assignmentt + { + irep_idt id; + exprt value; + }; + + // A list of such assignments. + typedef std::vector function_assignmentst; + + typedef std::vector mp_vectort; + + // Maps an assignment id to the name of the parameter being assigned + typedef std::pair assignment_idt; + + // Identifies an expression before and after some change; + typedef std::pair diff_pairt; + + // Records a diff between an assignment pre and post conditions + typedef std::map side_effects_differencet; + + // A entry in the input_valuest map + typedef std::pair input_entryt; + + // List of the input variables with their corresponding initial values + typedef std::map input_valuest; + + // List of dynamically allocated symbols that are not in the symbol table + typedef std::map dynamic_typest; + + // An assignment list annotated with the calling context. + struct function_assignments_contextt + { + irep_idt calling_function; + function_assignmentst return_assignments; + function_assignmentst param_assignments; + }; + + // list_input_varst maps function identifiers onto a vector of [name = value] + // assignments per call to that function. + typedef std::list + function_assignments_contextst; + typedef std::map > + list_input_varst; + + const dynamic_typest &get_dynamic_types() { return dynamic_types; } protected: + struct trace_stack_entryt + { + irep_idt func_name; + mp_integer this_address; + irep_idt capture_symbol; + bool is_super_call; + std::vector param_values; + }; + typedef std::vector trace_stackt; + const symbol_tablet &symbol_table; + + // This is a cache so that we don't have to create it when a call needs it const namespacet ns; + const goto_functionst &goto_functions; typedef std::unordered_map memory_mapt; @@ -46,16 +115,40 @@ class interpretert irep_idt identifier; unsigned offset; mp_integer value; + // Initialized is annotated even during reads + // Set to 1 when written-before-read, -1 when read-before-written + mutable char initialized; }; typedef std::vector memoryt; - memoryt memory; + typedef std::map parameter_sett; + // mapping -> value + typedef std::pair struct_member_idt; + typedef std::map struct_valuest; + + + // The memory is being annotated/reshaped even during reads + // (ie to find a read-before-write location) thus memory + // properties need to be mutable to avoid making all calls nonconst + mutable memoryt memory; std::size_t stack_pointer; void build_memory_map(); void build_memory_map(const symbolt &symbol); - unsigned get_size(const typet &type) const; + mp_integer build_memory_map(const irep_idt &id, const typet &type); + typet concretize_type(const typet &type); + size_t get_size(const typet &type); + + irep_idt get_component_id(const irep_idt &object, unsigned offset); + typet get_type(const irep_idt &id) const; + exprt get_value( + const typet &type, + std::size_t offset=0, + bool use_non_det=false); + exprt get_value(const typet &type, mp_vectort &rhs, std::size_t offset=0); + exprt get_value(const irep_idt &id); + void step(); void execute_assert(); @@ -65,21 +158,26 @@ class interpretert void execute_function_call(); void execute_other(); void execute_decl(); + void clear_input_flags(); + + void allocate( + mp_integer address, + size_t size); void assign( mp_integer address, - const std::vector &rhs); + const mp_vectort &rhs); void read( mp_integer address, - std::vector &dest) const; + mp_vectort &dest) const; - void command(); + virtual void command(); class stack_framet { public: - goto_programt::const_targett return_PC; + goto_programt::const_targett return_pc; goto_functionst::function_mapt::const_iterator return_function; mp_integer return_value_address; memory_mapt local_map; @@ -87,27 +185,56 @@ class interpretert }; typedef std::stack call_stackt; + call_stackt call_stack; + input_valuest input_vars; + list_input_varst function_input_vars; goto_functionst::function_mapt::const_iterator function; - goto_programt::const_targett PC, next_PC; + goto_programt::const_targett pc, next_pc, target_assert; + goto_tracet steps; bool done; - - bool evaluate_boolean(const exprt &expr) const + bool show; + bool stop_on_assertion; + static const size_t npos; + size_t num_steps; + size_t total_steps; + + dynamic_typest dynamic_types; + int num_dynamic_objects; + size_t stack_depth; + int thread_id; + + bool evaluate_boolean(const exprt &expr) { - std::vector v; + mp_vectort v; evaluate(expr, v); if(v.size()!=1) throw "invalid boolean value"; return v.front()!=0; } + bool count_type_leaves( + const typet &source_type, + mp_integer &result); + + bool byte_offset_to_memory_offset( + const typet &source_type, + mp_integer byte_offset, + mp_integer &result); + + bool memory_offset_to_byte_offset( + const typet &source_type, + mp_integer cell_offset, + mp_integer &result); + void evaluate( const exprt &expr, - std::vector &dest) const; + mp_vectort &dest); - mp_integer evaluate_address(const exprt &expr) const; + mp_integer evaluate_address(const exprt &expr, bool fail_quietly=false); + void initialize(bool init); void show_state(); }; diff --git a/src/goto-programs/interpreter_evaluate.cpp b/src/goto-programs/interpreter_evaluate.cpp index 43a072cfaf4..a8da762a7ea 100644 --- a/src/goto-programs/interpreter_evaluate.cpp +++ b/src/goto-programs/interpreter_evaluate.cpp @@ -11,41 +11,366 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include #include #include +#include +#include #include "interpreter_class.h" +/// reads a memory address and loads it into the dest variable +/// marks cell as read before written if cell has never been written void interpretert::read( mp_integer address, - std::vector &dest) const + mp_vectort &dest) const { // copy memory region - for(auto &d : dest) + for(size_t i=0; i0) + cell.initialized=0; + } +} + +/*******************************************************************\ + +Function: interpretert::count_type_leaves + + Inputs: Type + + Outputs: Number of leaf primitive types; returns true on error + + Purpose: + +\*******************************************************************/ + +bool interpretert::count_type_leaves(const typet &ty, mp_integer &result) +{ + if(ty.id()==ID_struct) + { + result=0; + mp_integer subtype_count; + for(const auto &component : to_struct_type(ty).components()) + { + if(count_type_leaves(component.type(), subtype_count)) + return true; + result+=subtype_count; + } + return false; + } + else if(ty.id()==ID_array) + { + const auto &at=to_array_type(ty); + mp_vectort array_size_vec; + evaluate(at.size(), array_size_vec); + if(array_size_vec.size()!=1) + return true; + mp_integer subtype_count; + if(count_type_leaves(at.subtype(), subtype_count)) + return true; + result=array_size_vec[0]*subtype_count; + return false; + } + else + { + result=1; + return false; + } +} + +/*******************************************************************\ + +Function: interpretert::byte_offset_to_memory_offset + + Inputs: 'source_type', 'offset' (unit: bytes), + + Outputs: Offset into a vector of interpreter values; returns true on error + + Purpose: Supposing the caller has an mp_vector representing + a value with type 'source_type', this yields the offset into that + vector at which to find a value at *byte* address 'offset'. + We need this because the interpreter's memory map uses unlabelled + variable-width values -- for example, a C value { { 1, 2 }, 3, 4 } + of type struct { int x[2]; char y; unsigned long z; } + would be represented [1,2,3,4], with the source type needed alongside + to figure out which member is targeted by a byte-extract operation. + +\*******************************************************************/ + +bool interpretert::byte_offset_to_memory_offset( + const typet &source_type, + mp_integer offset, + mp_integer &result) +{ + if(source_type.id()==ID_struct) + { + const auto &st=to_struct_type(source_type); + const struct_typet::componentst &components=st.components(); + member_offset_iterator component_offsets(st, ns); + mp_integer previous_member_offsets=0; + for(; component_offsets->firstsecond!=-1 && + component_offsets->second<=offset; + ++component_offsets) + { + const auto &component_type=components[component_offsets->first].type(); + mp_integer component_byte_size=pointer_offset_size(component_type, ns); + if(component_byte_size<0) + return true; + if((component_offsets->second+component_byte_size)>offset) + { + mp_integer subtype_result; + bool ret=byte_offset_to_memory_offset( + component_type, + offset-(component_offsets->second), + subtype_result); + result=previous_member_offsets+subtype_result; + return ret; + } + else + { + mp_integer component_count; + if(count_type_leaves(component_type, component_count)) + return true; + previous_member_offsets+=component_count; + } + } + // Ran out of struct members, or struct contained a variable-length field. + return true; + } + else if(source_type.id()==ID_array) + { + const auto &at=to_array_type(source_type); + mp_vectort array_size_vec; + evaluate(at.size(), array_size_vec); + if(array_size_vec.size()!=1) + return true; + mp_integer array_size=array_size_vec[0]; + mp_integer elem_size_bytes=pointer_offset_size(at.subtype(), ns); + if(elem_size_bytes<=0) + return true; + mp_integer elem_size_leaves; + if(count_type_leaves(at.subtype(), elem_size_leaves)) + return true; + mp_integer this_idx=offset/elem_size_bytes; + if(this_idx>=array_size_vec[0]) + return true; + mp_integer subtype_result; + bool ret=byte_offset_to_memory_offset( + at.subtype(), + offset%elem_size_bytes, + subtype_result); + result=subtype_result+(elem_size_leaves*this_idx); + return ret; + } + else + { + result=0; + // Can't currently subdivide a primitive. + return offset!=0; + } +} + +/*******************************************************************\ + +Function: interpretert::memory_offset_to_byte_offset + + Inputs: An interpreter memory offset and the type to interpret that memory + + Outputs: The corresponding byte offset. Returns true on error + + Purpose: Similarly to the above, the interpreter's memory objects contain + mp_integers that represent variable-sized struct members. This + counts the size of type leaves to determine the byte offset + corresponding to a memory offset. + +\*******************************************************************/ + +bool interpretert::memory_offset_to_byte_offset( + const typet &source_type, + mp_integer cell_offset, + mp_integer &result) +{ + if(source_type.id()==ID_struct) + { + const auto &st=to_struct_type(source_type); + const struct_typet::componentst &components=st.components(); + member_offset_iterator offsets(st, ns); + mp_integer previous_member_sizes; + for(; offsets->firstsecond!=-1; ++offsets) + { + const auto &component_type=components[offsets->first].type(); + mp_integer component_count; + if(count_type_leaves(component_type, component_count)) + return true; + if(component_count>cell_offset) + { + mp_integer subtype_result; + bool ret=memory_offset_to_byte_offset( + component_type, + cell_offset, + subtype_result); + result=previous_member_sizes+subtype_result; + return ret; + } + else + { + cell_offset-=component_count; + mp_integer component_size=pointer_offset_size(component_type, ns); + if(component_size<0) + return true; + previous_member_sizes+=component_size; + } + } + // Ran out of members, or member of indefinite size + return true; + } + else if(source_type.id()==ID_array) + { + const auto &at=to_array_type(source_type); + mp_vectort array_size_vec; + evaluate(at.size(), array_size_vec); + if(array_size_vec.size()!=1) + return true; + mp_integer elem_size=pointer_offset_size(at.subtype(), ns); + if(elem_size==-1) + return true; + mp_integer elem_count; + if(count_type_leaves(at.subtype(), elem_count)) + return true; + mp_integer this_idx=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, + subtype_result); + result=subtype_result+(elem_size*this_idx); + return ret; + } + else + { + // Primitive type. + result=0; + return cell_offset!=0; } } void interpretert::evaluate( const exprt &expr, - std::vector &dest) const + mp_vectort &dest) { if(expr.id()==ID_constant) { if(expr.type().id()==ID_struct) { + dest.reserve(get_size(expr.type())); + bool error=false; + + forall_operands(it, expr) + { + if(it->type().id()==ID_code) + continue; + + size_t sub_size=get_size(it->type()); + if(sub_size==0) + continue; + + mp_vectort tmp; + evaluate(*it, tmp); + + if(tmp.size()==sub_size) + { + for(size_t i=0; itype().id()==ID_code) continue; - unsigned sub_size=get_size(it->type()); + size_t sub_size=get_size(it->type()); if(sub_size==0) continue; - std::vector tmp; + mp_vectort tmp; evaluate(*it, tmp); if(tmp.size()==sub_size) { - for(unsigned i=0; i tmp0, tmp1; + mp_vectort tmp0, tmp1; evaluate(expr.op0(), tmp0); evaluate(expr.op1(), tmp1); @@ -151,7 +671,7 @@ void interpretert::evaluate( forall_operands(it, expr) { - std::vector tmp; + mp_vectort tmp; evaluate(*it, tmp); if(tmp.size()==1 && tmp.front()!=0) @@ -170,20 +690,20 @@ void interpretert::evaluate( if(expr.operands().size()!=3) throw "if expects three operands"; - std::vector tmp0, tmp1, tmp2; + mp_vectort tmp0, tmp1; evaluate(expr.op0(), tmp0); - evaluate(expr.op1(), tmp1); - evaluate(expr.op2(), tmp2); - if(tmp0.size()==1 && tmp1.size()==1 && tmp2.size()==1) + if(tmp0.size()==1) { - const mp_integer &op0=tmp0.front(); - const mp_integer &op1=tmp1.front(); - const mp_integer &op2=tmp2.front(); - - dest.push_back(op0!=0?op1:op2); + if(tmp0.front()!=0) + evaluate(expr.op1(), tmp1); + else + evaluate(expr.op2(), tmp1); } + if(tmp1.size()==1) + dest.push_back(tmp1.front()); + return; } else if(expr.id()==ID_and) @@ -195,7 +715,7 @@ void interpretert::evaluate( forall_operands(it, expr) { - std::vector tmp; + mp_vectort tmp; evaluate(*it, tmp); if(tmp.size()==1 && tmp.front()==0) @@ -214,7 +734,7 @@ void interpretert::evaluate( if(expr.operands().size()!=1) throw id2string(expr.id())+" expects one operand"; - std::vector tmp; + mp_vectort tmp; evaluate(expr.op0(), tmp); if(tmp.size()==1) @@ -228,7 +748,7 @@ void interpretert::evaluate( forall_operands(it, expr) { - std::vector tmp; + mp_vectort tmp; evaluate(*it, tmp); if(tmp.size()==1) result+=tmp.front(); @@ -260,7 +780,7 @@ void interpretert::evaluate( forall_operands(it, expr) { - std::vector tmp; + mp_vectort tmp; evaluate(*it, tmp); if(tmp.size()==1) { @@ -296,7 +816,7 @@ void interpretert::evaluate( if(expr.operands().size()!=2) throw "- expects two operands"; - std::vector tmp0, tmp1; + mp_vectort tmp0, tmp1; evaluate(expr.op0(), tmp0); evaluate(expr.op1(), tmp1); @@ -309,7 +829,7 @@ void interpretert::evaluate( if(expr.operands().size()!=2) throw "/ expects two operands"; - std::vector tmp0, tmp1; + mp_vectort tmp0, tmp1; evaluate(expr.op0(), tmp0); evaluate(expr.op1(), tmp1); @@ -322,7 +842,7 @@ void interpretert::evaluate( if(expr.operands().size()!=1) throw "unary- expects one operand"; - std::vector tmp0; + mp_vectort tmp0; evaluate(expr.op0(), tmp0); if(tmp0.size()==1) @@ -337,22 +857,130 @@ void interpretert::evaluate( dest.push_back(evaluate_address(expr.op0())); return; } + else if(expr.id()==ID_pointer_offset) + { + if(expr.operands().size()!=1) + throw "pointer_offset expects one operand"; + if(expr.op0().type().id()!=ID_pointer) + throw "pointer_offset expects a pointer operand"; + mp_vectort result; + evaluate(expr.op0(), result); + if(result.size()==1) + { + // Return the distance, in bytes, between the address returned + // and the beginning of the underlying object. + mp_integer address=result[0]; + if(address>0 && address0) + { + dest.insert(dest.end(), + extract_from.begin()+memory_offset.to_long(), + extract_from.begin()+(memory_offset+target_type_leaves).to_long()); + return; + } + } + } + } else if(expr.id()==ID_dereference || expr.id()==ID_index || expr.id()==ID_symbol || expr.id()==ID_member) { - mp_integer a=evaluate_address(expr); - dest.resize(get_size(expr.type())); - read(a, dest); - return; + mp_integer address=evaluate_address( + expr, + true); // fail quietly + if(address.is_zero() && expr.id()==ID_index) + { + // Try reading from a constant array: + mp_vectort idx; + evaluate(expr.op1(), idx); + if(idx.size()==1) + { + mp_integer read_from_index=idx[0]; + if(expr.op0().id()==ID_array) + { + const auto &ops=expr.op0().operands(); + assert(read_from_index.is_long()); + if(read_from_index>=0 && read_from_index tmp; + mp_vectort tmp; evaluate(expr.op0(), tmp); if(tmp.size()==1) @@ -378,38 +1006,50 @@ void interpretert::evaluate( dest.push_back(binary2integer(s, false)); return; } - else if(expr.type().id()==ID_bool) + else if((expr.type().id()==ID_bool) || (expr.type().id()==ID_c_bool)) { dest.push_back(value!=0); return; } } } - else if(expr.id()==ID_ashr) + else if((expr.id()==ID_array) || (expr.id()==ID_array_of)) { - if(expr.operands().size()!=2) - throw "ashr expects two operands"; - - std::vector tmp0, tmp1; - evaluate(expr.op0(), tmp0); - evaluate(expr.op1(), tmp1); - - if(tmp0.size()==1 && tmp1.size()==1) - dest.push_back(tmp0.front()/power(2, tmp1.front())); - + forall_operands(it, expr) + { + evaluate(*it, dest); + } return; } - - std::cout << "!! failed to evaluate expression: " - << from_expr(ns, function->first, expr) - << '\n'; + else if(expr.id()==ID_nil) + { + dest.push_back(0); + return; + } + else if(expr.id()==ID_infinity) + { + if(expr.type().id()==ID_signedbv) + { + error() << "Infinite size arrays not supported" << eom; + return; + } + } + error() << "!! failed to evaluate expression: " + << from_expr(ns, function->first, expr) << "\n" + << expr.id() << "[" << expr.type().id() << "]" + << eom; } -mp_integer interpretert::evaluate_address(const exprt &expr) const +mp_integer interpretert::evaluate_address( + const exprt &expr, + bool fail_quietly) { if(expr.id()==ID_symbol) { - const irep_idt &identifier=expr.get(ID_identifier); + const irep_idt &identifier= + is_ssa_expr(expr) ? + to_ssa_expr(expr).get_original_name() : + expr.get(ID_identifier); interpretert::memory_mapt::const_iterator m_it1= memory_map.find(identifier); @@ -425,13 +1065,16 @@ mp_integer interpretert::evaluate_address(const exprt &expr) const if(m_it2!=call_stack.top().local_map.end()) return m_it2->second; } + mp_integer address=memory.size(); + build_memory_map(to_symbol_expr(expr).get_identifier(), expr.type()); + return address; } else if(expr.id()==ID_dereference) { if(expr.operands().size()!=1) throw "dereference expects one operand"; - std::vector tmp0; + mp_vectort tmp0; evaluate(expr.op0(), tmp0); if(tmp0.size()==1) @@ -442,11 +1085,15 @@ mp_integer interpretert::evaluate_address(const exprt &expr) const if(expr.operands().size()!=2) throw "index expects two operands"; - std::vector tmp1; + mp_vectort tmp1; evaluate(expr.op1(), tmp1); if(tmp1.size()==1) - return evaluate_address(expr.op0())+tmp1.front(); + { + auto base=evaluate_address(expr.op0(), fail_quietly); + if(!base.is_zero()) + return base+tmp1.front(); + } } else if(expr.id()==ID_member) { @@ -469,12 +1116,44 @@ mp_integer interpretert::evaluate_address(const exprt &expr) const offset+=get_size(comp.type()); } - return evaluate_address(expr.op0())+offset; + auto base=evaluate_address(expr.op0(), fail_quietly); + if(!base.is_zero()) + return base+offset; } - - std::cout << "!! failed to evaluate address: " + else if(expr.id()==ID_byte_extract_little_endian || + expr.id()==ID_byte_extract_big_endian) + { + if(expr.operands().size()!=2) + throw "byte_extract should have two operands"; + mp_vectort extract_offset; + evaluate(expr.op1(), extract_offset); + mp_vectort extract_from; + evaluate(expr.op0(), extract_from); + if(extract_offset.size()==1 && !extract_from.empty()) + { + mp_integer memory_offset; + if(!byte_offset_to_memory_offset(expr.op0().type(), + extract_offset[0], memory_offset)) + return evaluate_address(expr.op0(), fail_quietly)+memory_offset; + } + } + else if(expr.id()==ID_if) + { + mp_vectort result; + if_exprt address_cond( + expr.op0(), + address_of_exprt(expr.op1()), + address_of_exprt(expr.op2())); + evaluate(address_cond, result); + if(result.size()==1) + return result[0]; + } + if(!fail_quietly) + { + error() << "!! failed to evaluate address: " << from_expr(ns, function->first, expr) - << '\n'; + << eom; + } return 0; } From aa3a90f2ce8cda1ceed5c2a934dfd459fc274791 Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Sat, 31 Dec 2016 15:27:04 +0300 Subject: [PATCH 18/52] Preprocessing of goto programs for string refinement --- .../string_refine_preprocess.cpp | 1289 +++++++++++++++++ src/goto-programs/string_refine_preprocess.h | 215 +++ src/util/std_expr.h | 13 + 3 files changed, 1517 insertions(+) create mode 100644 src/goto-programs/string_refine_preprocess.cpp create mode 100644 src/goto-programs/string_refine_preprocess.h diff --git a/src/goto-programs/string_refine_preprocess.cpp b/src/goto-programs/string_refine_preprocess.cpp new file mode 100644 index 00000000000..c4dc1a92960 --- /dev/null +++ b/src/goto-programs/string_refine_preprocess.cpp @@ -0,0 +1,1289 @@ +/*******************************************************************\ + +Module: Preprocess a goto-programs so that calls to the java String + library are recognized by the string solver + +Author: Romain Brenguier + +Date: September 2016 + +\*******************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +// TODO: refined_string_type should be moved to util +#include +#include + +#include "string_refine_preprocess.h" + +/******************************************************************* \ + +Function: string_refine_preprocesst::fresh_array + + Inputs: + type - an array type + location - a location in the program + + Outputs: a new symbol + + Purpose: add a symbol with static lifetime and name containing + `cprover_string_array` and given type + +\*******************************************************************/ + +symbol_exprt string_refine_preprocesst::fresh_array( + const typet &type, const source_locationt &location) +{ + symbolt array_symbol=get_fresh_aux_symbol( + type, + "cprover_string_array", + "cprover_string_array", + location, + ID_java, + symbol_table); + array_symbol.is_static_lifetime=true; + return array_symbol.symbol_expr(); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::fresh_string + + Inputs: + type - a type for refined strings + location - a location in the program + + Outputs: a new symbol + + Purpose: add a symbol with static lifetime and name containing + `cprover_string` and given type + +\*******************************************************************/ + +symbol_exprt string_refine_preprocesst::fresh_string( + const typet &type, const source_locationt &location) +{ + symbolt array_symbol=get_fresh_aux_symbol( + type, "cprover_string", "cprover_string", location, ID_java, symbol_table); + array_symbol.is_static_lifetime=true; + return array_symbol.symbol_expr(); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::declare_function + + Inputs: a name and a type + + Purpose: declare a function with the given name and type + +\*******************************************************************/ + +void string_refine_preprocesst::declare_function( + irep_idt function_name, const typet &type) +{ + auxiliary_symbolt func_symbol; + func_symbol.base_name=function_name; + func_symbol.is_static_lifetime=false; + func_symbol.mode=ID_java; + func_symbol.name=function_name; + func_symbol.type=type; + symbol_table.add(func_symbol); + goto_functions.function_map[function_name]; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::get_data_and_length_type_of_string + + Inputs: an expression, a reference to a data type and a reference to a + length type + + Purpose: assuming the expression is a java string, figure out what + the types for length and data are and put them into the references + given as argument + +\*******************************************************************/ + +void string_refine_preprocesst::get_data_and_length_type_of_string( + const exprt &expr, typet &data_type, typet &length_type) +{ + assert(refined_string_typet::is_java_string_type(expr.type()) || + refined_string_typet::is_java_string_builder_type(expr.type())); + typet object_type=ns.follow(expr.type()); + const struct_typet &struct_type=to_struct_type(object_type); + for(const auto &component : struct_type.components()) + if(component.get_name()=="length") + length_type=component.type(); + else if(component.get_name()=="data") + data_type=component.type(); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::make_cprover_string_assign + + Inputs: a goto_program, a position in this program, an expression and a + location + + Outputs: an expression + + Purpose: Introduce a temporary variable for cprover strings; + returns the cprover_string corresponding to rhs if it is a string + pointer and the original rhs otherwise. + +\*******************************************************************/ + +exprt string_refine_preprocesst::make_cprover_string_assign( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &rhs, + const source_locationt &location) +{ + if(refined_string_typet::is_java_string_pointer_type(rhs.type())) + { + auto pair=java_to_cprover_strings.insert( + std::pair(rhs, nil_exprt())); + + if(pair.second) + { + // We do the following assignments: + // cprover_string_array = *(rhs->data) + // cprover_string = { rhs->length; cprover_string_array } + + dereference_exprt deref(rhs, rhs.type().subtype()); + + typet data_type, length_type; + get_data_and_length_type_of_string(deref, data_type, length_type); + member_exprt length(deref, "length", length_type); + symbol_exprt array_lhs=fresh_array(data_type.subtype(), location); + + // string expression for the rhs of the second assignment + string_exprt new_rhs( + length, array_lhs, refined_string_typet(length_type, data_type)); + + member_exprt data(deref, "data", data_type); + dereference_exprt deref_data(data, data_type.subtype()); + symbol_exprt lhs=fresh_string(new_rhs.type(), location); + + std::list assignments; + assignments.emplace_back(array_lhs, deref_data); + assignments.emplace_back(lhs, new_rhs); + insert_assignments( + goto_program, target, target->function, location, assignments); + target=goto_program.insert_after(target); + pair.first->second=lhs; + } + return pair.first->second; + } + else if(rhs.id()==ID_typecast && + refined_string_typet::is_java_string_pointer_type(rhs.op0().type())) + { + exprt new_rhs=make_cprover_string_assign( + goto_program, target, rhs.op0(), location); + return typecast_exprt(new_rhs, rhs.type()); + } + else + return rhs; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::make_normal_assign + + Inputs: a goto_program, a position in this program, an expression lhs, + a function type, a function name, a vector of arguments, a location + and a signature + + Purpose: replace the current instruction by: + > lhs=function_name(arguments) : return_type @ location + If given, signature can force String conversion of given arguments. + The convention for signature is one character by argument + and 'S' denotes string. + +\*******************************************************************/ + +void string_refine_preprocesst::make_normal_assign( + goto_programt &goto_program, + goto_programt::targett target, + const exprt &lhs, + const code_typet &function_type, + const irep_idt &function_name, + const exprt::operandst &arguments, + const source_locationt &location, + const std::string &signature) +{ + if(function_name==ID_cprover_string_copy_func) + { + assert(!arguments.empty()); + make_string_copy(goto_program, target, lhs, arguments[0], location); + } + else + { + function_application_exprt rhs( + symbol_exprt(function_name), function_type.return_type()); + rhs.add_source_location()=location; + declare_function(function_name, function_type); + + exprt::operandst processed_arguments=process_arguments( + goto_program, target, arguments, location, signature); + rhs.arguments()=processed_arguments; + + code_assignt assignment(lhs, rhs); + assignment.add_source_location()=location; + target->make_assignment(); + target->code=assignment; + } +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::insert_assignments + + Inputs: a goto_program, a position in this program, a list of assignments + + Purpose: add the assignments to the program in the order they are given + +\*******************************************************************/ + +void string_refine_preprocesst::insert_assignments( + goto_programt &goto_program, + goto_programt::targett &target, + irep_idt function, + source_locationt location, + const std::list &va) +{ + if(va.empty()) + return; + + auto i=va.begin(); + target->make_assignment(); + target->code=*i; + target->function=function; + target->source_location=location; + for(i++; i!=va.end(); i++) + { + target=goto_program.insert_after(target); + target->make_assignment(); + target->code=*i; + target->function=function; + target->source_location=location; + } +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::make_string_assign + + Inputs: a goto_program, a position in this program, an expression lhs, + a function type, a function name, a vector of arguments, a location + and a signature + + Purpose: replace the current instruction by: + > lhs=malloc(String *) + > lhs->length=function_name_length(arguments) + > tmp_data=function_name_data(arguments) + > lhs->data=&tmp_data + +\*******************************************************************/ + +void string_refine_preprocesst::make_string_assign( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &lhs, + const code_typet &function_type, + const irep_idt &function_name, + const exprt::operandst &arguments, + const source_locationt &location, + const std::string &signature) +{ + assert(refined_string_typet::is_java_string_pointer_type( + function_type.return_type())); + dereference_exprt deref(lhs, lhs.type().subtype()); + typet object_type=ns.follow(deref.type()); + exprt object_size=size_of_expr(object_type, ns); + typet length_type, data_type; + get_data_and_length_type_of_string(deref, data_type, length_type); + + std::string fnamel=id2string(function_name)+"_length"; + std::string fnamed=id2string(function_name)+"_data"; + declare_function(fnamel, length_type); + declare_function(fnamed, data_type); + function_application_exprt rhs_length(symbol_exprt(fnamel), length_type); + function_application_exprt rhs_data( + symbol_exprt(fnamed), data_type.subtype()); + + exprt::operandst processed_arguments=process_arguments( + goto_program, target, arguments, location, signature); + rhs_length.arguments()=processed_arguments; + rhs_data.arguments()=processed_arguments; + + symbolt sym_length=get_fresh_aux_symbol( + length_type, "length", "length", location, ID_java, symbol_table); + symbol_exprt tmp_length=sym_length.symbol_expr(); + symbol_exprt tmp_array=fresh_array(data_type.subtype(), location); + member_exprt lhs_length(deref, "length", length_type); + member_exprt lhs_data(deref, "data", tmp_array.type()); + + // lhs=malloc(String *) + assert(object_size.is_not_nil()); // got nil object_size + side_effect_exprt malloc_expr(ID_malloc); + malloc_expr.copy_to_operands(object_size); + malloc_expr.type()=pointer_typet(object_type); + malloc_expr.add_source_location()=location; + + std::list assigns; + assigns.emplace_back(lhs, malloc_expr); + assigns.emplace_back(tmp_length, rhs_length); + assigns.emplace_back(lhs_length, tmp_length); + assigns.emplace_back(tmp_array, rhs_data); + assigns.emplace_back(lhs_data, address_of_exprt(tmp_array)); + insert_assignments(goto_program, target, target->function, location, assigns); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::make_assign + + Inputs: a goto_program, a position in this program, an expression lhs, + a function type, a function name, a vector of arguments, a location + and a signature + + Purpose: assign the result of the function application to lhs, + in case the function type is string, it does a special assignment + using `make_string_assign` + +\*******************************************************************/ + +void string_refine_preprocesst::make_assign( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &lhs, + const code_typet &function_type, + const irep_idt &function_name, + const exprt::operandst &arg, + const source_locationt &loc, + const std::string &sig) +{ + if(refined_string_typet::is_java_string_pointer_type( + function_type.return_type())) + make_string_assign( + goto_program, target, lhs, function_type, function_name, arg, loc, sig); + else + make_normal_assign( + goto_program, target, lhs, function_type, function_name, arg, loc, sig); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::make_string_copy + + Inputs: a goto_program, a position in this program, a lhs expression, + an argument expression and a location + + Outputs: an expression + + Purpose: replace the current instruction by: + > lhs->length=argument->length + > tmp_data=*(argument->data) + > lhs->data=&tmp_data + +\*******************************************************************/ + +void string_refine_preprocesst::make_string_copy( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &lhs, + const exprt &argument, + const source_locationt &location) +{ + // TODO : treat CharSequence and StringBuffer + assert(refined_string_typet::is_java_string_pointer_type(lhs.type()) || + refined_string_typet::is_java_string_builder_pointer_type(lhs.type())); + exprt deref=dereference_exprt(lhs, lhs.type().subtype()); + + typet length_type, data_type; + get_data_and_length_type_of_string(deref, data_type, length_type); + + dereference_exprt deref_arg(argument, argument.type().subtype()); + std::list assignments; + + exprt lhs_length=get_length(deref, length_type); + exprt rhs_length=get_length(deref_arg, length_type); + assignments.emplace_back(lhs_length, rhs_length); + + symbol_exprt tmp_data=fresh_array(data_type.subtype(), location); + exprt rhs_data=get_data(deref_arg, data_type); + exprt lhs_data=get_data(deref, data_type); + assignments.emplace_back( + tmp_data, dereference_exprt(rhs_data, data_type.subtype())); + assignments.emplace_back(lhs_data, address_of_exprt(tmp_data)); + + insert_assignments( + goto_program, target, target->function, location, assignments); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::make_string_function + + Inputs: a position in a goto program, a function name, an expression lhs, + a function type, name, arguments, a location and a signature string + + Purpose: at the current position replace `lhs=s.some_function(x,...)` + by `lhs=function_name(s,x,...)`; + +\*******************************************************************/ + +void string_refine_preprocesst::make_string_function( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &lhs, + const code_typet &function_type, + const irep_idt &function_name, + const exprt::operandst &arguments, + const source_locationt &location, + const std::string &signature) +{ + if(refined_string_typet::is_java_string_pointer_type( + function_type.return_type())) + make_string_assign( + goto_program, + target, + lhs, + function_type, + function_name, + arguments, + location, + signature); + else + make_normal_assign( + goto_program, + target, + lhs, + function_type, + function_name, + arguments, + location, + signature); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::make_string_function + + Inputs: a position in a goto program, a function name and two Boolean options + + Purpose: at the current position replace `lhs=s.some_function(x,...)` + by `lhs=function_name(s,x,...)`; + option `assign_first_arg` uses `s` instead of `lhs` in the resulting + expression; + option `skip_first_arg`, removes `s` from the arguments, ie `x` is + the first one + +\*******************************************************************/ + +void string_refine_preprocesst::make_string_function( + goto_programt &goto_program, + goto_programt::targett &target, + const irep_idt &function_name, + const std::string &signature, + bool assign_first_arg, + bool skip_first_arg) +{ + code_function_callt &function_call=to_code_function_call(target->code); + code_typet function_type=to_code_type(function_call.function().type()); + code_typet new_type; + const source_locationt &loc=function_call.source_location(); + declare_function(function_name, function_type); + function_application_exprt rhs; + std::vector args; + if(assign_first_arg) + { + assert(!function_call.arguments().empty()); + rhs.type()=function_call.arguments()[0].type(); + } + else + rhs.type()=function_type.return_type(); + rhs.add_source_location()=function_call.source_location(); + rhs.function()=symbol_exprt(function_name); + + std::size_t start_index=skip_first_arg?1:0; + for(std::size_t i=start_index; icode); + assert(!function_call.arguments().empty()); + string_builders[function_call.lhs()]=function_call.arguments()[0]; + make_string_function( + goto_program, target, function_name, signature, true, false); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::build_function_application + + Inputs: a function name, a type, a location and a vector of arguments + + Outputs: a function application expression + + Purpose: declare a function and construct an function application expression + with the given function name, type, location and arguments + +\*******************************************************************/ + +function_application_exprt + string_refine_preprocesst::build_function_application( + const irep_idt &function_name, + const typet &type, + const source_locationt &location, + const exprt::operandst &arguments) +{ + declare_function(function_name, type); + function_application_exprt function_app(symbol_exprt(function_name), type); + function_app.add_source_location()=location; + for(const auto &arg : arguments) + function_app.arguments().push_back(arg); + + return function_app; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::make_to_char_array_function + + Inputs: a goto program and a position in that goto program + + Purpose: at the given position replace `return_tmp0=s.toCharArray()` with: + > return_tmp0->data=&((s->data)[0]) + > return_tmp0->length=s->length + +\*******************************************************************/ + +void string_refine_preprocesst::make_to_char_array_function( + goto_programt &goto_program, goto_programt::targett &target) +{ + const code_function_callt &function_call=to_code_function_call(target->code); + + assert(!function_call.arguments().empty()); + const exprt &string_argument=function_call.arguments()[0]; + assert(refined_string_typet::is_java_string_pointer_type( + string_argument.type())); + + dereference_exprt deref(string_argument, string_argument.type().subtype()); + typet length_type, data_type; + get_data_and_length_type_of_string(deref, data_type, length_type); + std::list assignments; + + // &((s->data)[0]) + exprt rhs_data=get_data(deref, data_type); + dereference_exprt rhs_array(rhs_data, data_type.subtype()); + exprt first_index=from_integer(0, java_int_type()); + index_exprt first_element(rhs_array, first_index, java_char_type()); + address_of_exprt rhs_pointer(first_element); + + // return_tmp0->data=&((s->data)[0]) + typet deref_type=function_call.lhs().type().subtype(); + dereference_exprt deref_lhs(function_call.lhs(), deref_type); + exprt lhs_data=get_data(deref_lhs, data_type); + assignments.emplace_back(lhs_data, rhs_pointer); + + // return_tmp0->length=s->length + exprt rhs_length=get_length(deref, length_type); + exprt lhs_length=get_length(deref_lhs, length_type); + assignments.emplace_back(lhs_length, rhs_length); + source_locationt location=target->source_location; + insert_assignments( + goto_program, target, target->function, location, assignments); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::make_cprover_char_array_assign + + Inputs: a goto_program, a position in this program, an expression and a + location + + Outputs: a char array expression (not a pointer) + + Purpose: Introduce a temporary variable for cprover strings; + returns the cprover_string corresponding to rhs + +\*******************************************************************/ + +exprt string_refine_preprocesst::make_cprover_char_array_assign( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &rhs, + const source_locationt &location) +{ + // TODO : add an assertion on the type of rhs + + // We do the following assignments: + // cprover_string_array = rhs.data + // cprover_string = { rhs.length; cprover_string_array } + + // string expression for the rhs of the second assignment + string_exprt new_rhs(java_char_type()); + + typet data_type=new_rhs.content().type(); + typet length_type=java_int_type(); + + symbol_exprt array_lhs=fresh_array(data_type, location); + exprt array_rhs=get_data(rhs, new_rhs.content().type()); + symbol_exprt lhs=fresh_string(new_rhs.type(), location); + new_rhs.length()=get_length(rhs, length_type); + new_rhs.content()=array_lhs; + + std::list assignments; + assignments.emplace_back(array_lhs, array_rhs); + assignments.emplace_back(lhs, new_rhs); + insert_assignments( + goto_program, target, target->function, location, assignments); + target=goto_program.insert_after(target); + return lhs; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::make_char_array_function + + Inputs: a position in a goto program, a function name, two Boolean options, + and the index of the char array argument in the function + + Purpose: at the given position replace + `lhs=s.some_function(...,char_array,...)` by + > cprover_string = { char_array->length, *char_array } + > tmp_string=function_name(s, cprover_string, ...) + option `assign_first_arg` uses `s` instead of `lhs` in the second + assignment; + option `skip_first_arg`, removes `s` from the arguments, ie `x` is + the first one; + argument index gives the index of the argument containing char_array + +\*******************************************************************/ + +void string_refine_preprocesst::make_char_array_function( + goto_programt &goto_program, + goto_programt::targett &target, + const irep_idt &function_name, + const std::string &signature, + std::size_t index, + bool assign_first_arg, + bool skip_first_arg) +{ + code_function_callt &function_call=to_code_function_call(target->code); + code_typet function_type=to_code_type(function_call.function().type()); + code_typet new_function_type; + const source_locationt &location=function_call.source_location(); + assert(!function_call.arguments().size()>index); + const std::vector &args=function_call.arguments(); + std::vector new_args; + + exprt lhs; + if(assign_first_arg) + { + assert(!function_call.arguments().empty()); + lhs=function_call.arguments()[0]; + else + lhs=function_call.lhs(); + + if(lhs.id()==ID_typecast) + lhs=to_typecast_expr(lhs).op(); + + exprt char_array=dereference_exprt( + function_call.arguments()[index], + function_call.arguments()[index].type().subtype()); + exprt string=make_cprover_char_array_assign( + goto_program, target, char_array, location); + + std::size_t start_index=skip_first_arg?1:0; + for(std::size_t i=start_index; icode); + assert(!function_call.arguments().empty()); + string_builders[function_call.lhs()]=function_call.arguments()[0]; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::process_arguments + + Inputs: a goto program, a position, a list of expressions, a location and a + signature + + Outputs: a list of expressions + + Purpose: for each expression that is a string or that is at a position with + an 'S' character in the signature, we declare a new `cprover_string` + whose contents is deduced from the expression and replace the + expression by this cprover_string in the output list; + in the other case the expression is kept as is for the output list. + +\*******************************************************************/ + +exprt::operandst string_refine_preprocesst::process_arguments( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt::operandst &arguments, + const source_locationt &location, + const std::string &signature) +{ + exprt::operandst new_arguments; + + for(std::size_t i=0; isecond); + else + { + if(isecond; + else + return ""; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::replace_string_calls + + Inputs: a function in a goto_program + + Purpose: goes through the instructions, replace function calls to string + function by equivalent instructions using functions defined + for the string solver, replace string literals by string + expressions of the type used by the string solver + TODO: the current implementation is only for java functions, + we should add support for other languages + +\*******************************************************************/ + +void string_refine_preprocesst::replace_string_calls( + goto_functionst::function_mapt::iterator f_it) +{ + goto_programt &goto_program=f_it->second.body; + + Forall_goto_program_instructions(target, goto_program) + { + if(target->is_function_call()) + { + code_function_callt &function_call=to_code_function_call(target->code); + for(auto &arg : function_call.arguments()) + { + auto sb_it=string_builders.find(arg); + if(sb_it!=string_builders.end()) + arg=sb_it->second; + } + + if(function_call.function().id()==ID_symbol) + { + const irep_idt &function_id= + to_symbol_expr(function_call.function()).get_identifier(); + std::string signature=function_signature(function_id); + + auto it=string_functions.find(function_id); + if(it!=string_functions.end()) + make_string_function( + goto_program, target, it->second, signature, false, false); + + it=side_effect_functions.find(function_id); + if(it!=side_effect_functions.end()) + make_string_function_side_effect( + goto_program, target, it->second, signature); + + it=string_function_calls.find(function_id); + if(it!=string_function_calls.end()) + make_string_function_call( + goto_program, target, it->second, signature); + + it=string_of_char_array_functions.find(function_id); + if(it!=string_of_char_array_functions.end()) + make_char_array_function( + goto_program, target, it->second, signature, 0); + + it=string_of_char_array_function_calls.find(function_id); + if(it!=string_of_char_array_function_calls.end()) + make_char_array_function_call( + goto_program, target, it->second, signature); + + it=side_effect_char_array_functions.find(function_id); + if(it!=side_effect_char_array_functions.end()) + make_char_array_side_effect( + goto_program, target, it->second, signature); + + if(function_id==irep_idt("java::java.lang.String.toCharArray:()[C")) + make_to_char_array_function(goto_program, target); + } + } + else + { + if(target->is_assign()) + { + // In assignments we replace string literals and C string functions + code_assignt assignment=to_code_assign(target->code); + + exprt new_rhs=assignment.rhs(); + code_assignt new_assignment(assignment.lhs(), new_rhs); + + if(new_rhs.id()==ID_function_application) + { + function_application_exprt f=to_function_application_expr(new_rhs); + const exprt &name=f.function(); + assert(name.id()==ID_symbol); + const irep_idt &id=to_symbol_expr(name).get_identifier(); + auto it=c_string_functions.find(id); + if(it!=c_string_functions.end()) + { + declare_function(it->second, f.type()); + f.function()=symbol_exprt(it->second); + new_assignment=code_assignt(assignment.lhs(), f); + } + } + + new_assignment.add_source_location()=assignment.source_location(); + target->make_assignment(); + target->code=new_assignment; + } + } + } + return; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::initialize_string_function_table + + Purpose: fill maps with correspondance from java method names to cprover + functions + +\*******************************************************************/ + +void string_refine_preprocesst::initialize_string_function_table() +{ + string_functions["java::java.lang.String.codePointAt:(I)I"]= + ID_cprover_string_code_point_at_func; + string_functions["java::java.lang.String.codePointBefore:(I)I"]= + ID_cprover_string_code_point_before_func; + string_functions["java::java.lang.String.codePointCount:(II)I"]= + ID_cprover_string_code_point_count_func; + string_functions["java::java.lang.String.offsetByCodePoints:(II)I"]= + ID_cprover_string_offset_by_code_point_func; + string_functions["java::java.lang.String.hashCode:()I"]= + ID_cprover_string_hash_code_func; + string_functions["java::java.lang.String.indexOf:(I)I"]= + ID_cprover_string_index_of_func; + string_functions["java::java.lang.String.indexOf:(II)I"]= + ID_cprover_string_index_of_func; + string_functions["java::java.lang.String.indexOf:(Ljava/lang/String;)I"]= + ID_cprover_string_index_of_func; + string_functions["java::java.lang.String.indexOf:(Ljava/lang/String;I)I"]= + ID_cprover_string_index_of_func; + string_functions["java::java.lang.String.lastIndexOf:(I)I"]= + ID_cprover_string_last_index_of_func; + string_functions["java::java.lang.String.lastIndexOf:(II)I"]= + ID_cprover_string_last_index_of_func; + string_functions + ["java::java.lang.String.lastIndexOf:(Ljava/lang/String;)I"]= + ID_cprover_string_last_index_of_func; + string_functions + ["java::java.lang.String.lastIndexOf:(Ljava/lang/String;I)I"]= + ID_cprover_string_last_index_of_func; + string_functions + ["java::java.lang.String.concat:(Ljava/lang/String;)Ljava/lang/String;"]= + ID_cprover_string_concat_func; + string_functions["java::java.lang.String.length:()I"]= + ID_cprover_string_length_func; + string_functions["java::java.lang.StringBuilder.length:()I"]= + ID_cprover_string_length_func; + string_functions["java::java.lang.String.equals:(Ljava/lang/Object;)Z"]= + ID_cprover_string_equal_func; + string_functions + ["java::java.lang.String.equalsIgnoreCase:(Ljava/lang/String;)Z"]= + ID_cprover_string_equals_ignore_case_func; + string_functions["java::java.lang.String.startsWith:(Ljava/lang/String;)Z"]= + ID_cprover_string_startswith_func; + string_functions + ["java::java.lang.String.startsWith:(Ljava/lang/String;I)Z"]= + ID_cprover_string_startswith_func; + string_functions["java::java.lang.String.endsWith:(Ljava/lang/String;)Z"]= + ID_cprover_string_endswith_func; + string_functions["java::java.lang.String.substring:(II)Ljava/lang/String;"]= + ID_cprover_string_substring_func; + string_functions["java::java.lang.String.substring:(II)Ljava/lang/String;"]= + ID_cprover_string_substring_func; + string_functions["java::java.lang.String.substring:(I)Ljava/lang/String;"]= + ID_cprover_string_substring_func; + string_functions + ["java::java.lang.StringBuilder.substring:(II)Ljava/lang/String;"]= + ID_cprover_string_substring_func; + string_functions + ["java::java.lang.StringBuilder.substring:(I)Ljava/lang/String;"]= + ID_cprover_string_substring_func; + string_functions + ["java::java.lang.String.subSequence:(II)Ljava/lang/CharSequence;"]= + ID_cprover_string_substring_func; + string_functions["java::java.lang.String.trim:()Ljava/lang/String;"]= + ID_cprover_string_trim_func; + string_functions["java::java.lang.String.toLowerCase:()Ljava/lang/String;"]= + ID_cprover_string_to_lower_case_func; + string_functions["java::java.lang.String.toUpperCase:()Ljava/lang/String;"]= + ID_cprover_string_to_upper_case_func; + string_functions["java::java.lang.String.replace:(CC)Ljava/lang/String;"]= + ID_cprover_string_replace_func; + string_functions + ["java::java.lang.String.contains:(Ljava/lang/CharSequence;)Z"]= + ID_cprover_string_contains_func; + string_functions["java::java.lang.String.compareTo:(Ljava/lang/String;)I"]= + ID_cprover_string_compare_to_func; + string_functions["java::java.lang.String.intern:()Ljava/lang/String;"]= + ID_cprover_string_intern_func; + string_functions["java::java.lang.String.isEmpty:()Z"]= + ID_cprover_string_is_empty_func; + string_functions["java::java.lang.String.charAt:(I)C"]= + ID_cprover_string_char_at_func; + string_functions["java::java.lang.StringBuilder.charAt:(I)C"]= + ID_cprover_string_char_at_func; + string_functions["java::java.lang.CharSequence.charAt:(I)C"]= + ID_cprover_string_char_at_func; + string_functions + ["java::java.lang.StringBuilder.toString:()Ljava/lang/String;"]= + ID_cprover_string_copy_func; + + string_functions["java::java.lang.String.valueOf:(F)Ljava/lang/String;"]= + ID_cprover_string_of_float_func; + string_functions["java::java.lang.Float.toString:(F)Ljava/lang/String;"]= + ID_cprover_string_of_float_func; + string_functions["java::java.lang.Integer.toString:(I)Ljava/lang/String;"]= + ID_cprover_string_of_int_func; + string_functions["java::java.lang.String.valueOf:(I)Ljava/lang/String;"]= + ID_cprover_string_of_int_func; + string_functions["java::java.lang.Integer.toHexString:(I)Ljava/lang/String;"]= + ID_cprover_string_of_int_hex_func; + string_functions["java::java.lang.String.valueOf:(L)Ljava/lang/String;"]= + ID_cprover_string_of_long_func; + string_functions["java::java.lang.String.valueOf:(D)Ljava/lang/String;"]= + ID_cprover_string_of_double_func; + string_functions["java::java.lang.String.valueOf:(Z)Ljava/lang/String;"]= + ID_cprover_string_of_bool_func; + string_functions["java::java.lang.String.valueOf:(C)Ljava/lang/String;"]= + ID_cprover_string_of_char_func; + string_functions["java::java.lang.Integer.parseInt:(Ljava/lang/String;)I"]= + ID_cprover_string_parse_int_func; + + side_effect_functions + ["java::java.lang.StringBuilder.append:(Ljava/lang/String;)" + "Ljava/lang/StringBuilder;"]= + ID_cprover_string_concat_func; + side_effect_functions["java::java.lang.StringBuilder.setCharAt:(IC)V"]= + ID_cprover_string_char_set_func; + side_effect_functions + ["java::java.lang.StringBuilder.append:(I)Ljava/lang/StringBuilder;"]= + ID_cprover_string_concat_int_func; + side_effect_functions + ["java::java.lang.StringBuilder.append:(J)Ljava/lang/StringBuilder;"]= + ID_cprover_string_concat_long_func; + side_effect_functions + ["java::java.lang.StringBuilder.append:(Z)Ljava/lang/StringBuilder;"]= + ID_cprover_string_concat_bool_func; + side_effect_functions + ["java::java.lang.StringBuilder.append:(C)Ljava/lang/StringBuilder;"]= + ID_cprover_string_concat_char_func; + side_effect_functions + ["java::java.lang.StringBuilder.append:(D)Ljava/lang/StringBuilder;"]= + ID_cprover_string_concat_double_func; + side_effect_functions + ["java::java.lang.StringBuilder.append:(F)Ljava/lang/StringBuilder;"]= + ID_cprover_string_concat_float_func; + side_effect_functions + ["java::java.lang.StringBuilder.appendCodePoint:(I)" + "Ljava/lang/StringBuilder;"]= + ID_cprover_string_concat_code_point_func; + side_effect_functions + ["java::java.lang.StringBuilder.delete:(II)Ljava/lang/StringBuilder;"]= + ID_cprover_string_delete_func; + side_effect_functions + ["java::java.lang.StringBuilder.deleteCharAt:(I)Ljava/lang/StringBuilder;"]= + ID_cprover_string_delete_char_at_func; + side_effect_functions + ["java::java.lang.StringBuilder.insert:(ILjava/lang/String;)" + "Ljava/lang/StringBuilder;"]= + ID_cprover_string_insert_func; + side_effect_functions + ["java::java.lang.StringBuilder.insert:(II)Ljava/lang/StringBuilder;"]= + ID_cprover_string_insert_int_func; + side_effect_functions + ["java::java.lang.StringBuilder.insert:(IJ)Ljava/lang/StringBuilder;"]= + ID_cprover_string_insert_long_func; + side_effect_functions + ["java::java.lang.StringBuilder.insert:(IC)Ljava/lang/StringBuilder;"]= + ID_cprover_string_insert_char_func; + side_effect_functions + ["java::java.lang.StringBuilder.insert:(IZ)Ljava/lang/StringBuilder;"]= + ID_cprover_string_insert_bool_func; + side_effect_functions + ["java::java.lang.StringBuilder.setLength:(I)V"]= + ID_cprover_string_set_length_func; + + + side_effect_char_array_functions + ["java::java.lang.StringBuilder.insert:(I[CII)Ljava/lang/StringBuilder;"]= + ID_cprover_string_insert_char_array_func; + side_effect_char_array_functions + ["java::java.lang.StringBuilder.insert:(I[C)Ljava/lang/StringBuilder;"]= + ID_cprover_string_insert_char_array_func; + + string_function_calls + ["java::java.lang.String.:(Ljava/lang/String;)V"]= + ID_cprover_string_copy_func; + string_function_calls + ["java::java.lang.String.:(Ljava/lang/StringBuilder;)V"]= + ID_cprover_string_copy_func; + string_function_calls + ["java::java.lang.StringBuilder.:(Ljava/lang/String;)V"]= + ID_cprover_string_copy_func; + string_function_calls["java::java.lang.String.:()V"]= + ID_cprover_string_empty_string_func; + string_function_calls["java::java.lang.StringBuilder.:()V"]= + ID_cprover_string_empty_string_func; + + string_of_char_array_function_calls["java::java.lang.String.:([C)V"]= + ID_cprover_string_of_char_array_func; + string_of_char_array_function_calls["java::java.lang.String.:([CII)V"]= + ID_cprover_string_of_char_array_func; + + string_of_char_array_functions + ["java::java.lang.String.valueOf:([CII)Ljava/lang/String;"]= + ID_cprover_string_of_char_array_func; + string_of_char_array_functions + ["java::java.lang.String.valueOf:([C)Ljava/lang/String;"]= + ID_cprover_string_of_char_array_func; + string_of_char_array_functions + ["java::java.lang.String.copyValueOf:([CII)Ljava/lang/String;"]= + ID_cprover_string_of_char_array_func; + string_of_char_array_functions + ["java::java.lang.String.copyValueOf:([C)Ljava/lang/String;"]= + ID_cprover_string_of_char_array_func; + + c_string_functions["__CPROVER_uninterpreted_string_literal_func"]= + ID_cprover_string_literal_func; + c_string_functions["__CPROVER_uninterpreted_string_char_at_func"]= + ID_cprover_string_char_at_func; + c_string_functions["__CPROVER_uninterpreted_string_equal_func"]= + ID_cprover_string_equal_func; + c_string_functions["__CPROVER_uninterpreted_string_concat_func"]= + ID_cprover_string_concat_func; + c_string_functions["__CPROVER_uninterpreted_string_length_func"]= + ID_cprover_string_length_func; + c_string_functions["__CPROVER_uninterpreted_string_substring_func"]= + ID_cprover_string_substring_func; + c_string_functions["__CPROVER_uninterpreted_string_is_prefix_func"]= + ID_cprover_string_is_prefix_func; + c_string_functions["__CPROVER_uninterpreted_string_is_suffix_func"]= + ID_cprover_string_is_suffix_func; + c_string_functions["__CPROVER_uninterpreted_string_contains_func"]= + ID_cprover_string_contains_func; + c_string_functions["__CPROVER_uninterpreted_string_index_of_func"]= + ID_cprover_string_index_of_func; + c_string_functions["__CPROVER_uninterpreted_string_last_index_of_func"]= + ID_cprover_string_last_index_of_func; + c_string_functions["__CPROVER_uninterpreted_string_char_set_func"]= + ID_cprover_string_char_set_func; + c_string_functions["__CPROVER_uninterpreted_string_copy_func"]= + ID_cprover_string_copy_func; + c_string_functions["__CPROVER_uninterpreted_string_parse_int_func"]= + ID_cprover_string_parse_int_func; + c_string_functions["__CPROVER_uninterpreted_string_of_int_func"]= + ID_cprover_string_of_int_func; + + signatures["java::java.lang.String.equals:(Ljava/lang/Object;)Z"]="SSZ"; + signatures + ["java::java.lang.String.contains:(Ljava/lang/CharSequence;)Z"]= + "SSZ"; +} + +/*******************************************************************\ + +Constructor: string_refine_preprocesst::string_refine_preprocesst + + Inputs: a symbol table, goto functions, a message handler + + Purpose: process the goto function by replacing calls to string functions + +\*******************************************************************/ + +string_refine_preprocesst::string_refine_preprocesst( + symbol_tablet &_symbol_table, + goto_functionst &_goto_functions, + message_handlert &_message_handler): + messaget(_message_handler), + ns(_symbol_table), + symbol_table(_symbol_table), + goto_functions(_goto_functions), + next_symbol_id(0), + jls_ptr(symbol_typet("java::java.lang.String")) +{ + initialize_string_function_table(); + Forall_goto_functions(it, goto_functions) + replace_string_calls(it); +} diff --git a/src/goto-programs/string_refine_preprocess.h b/src/goto-programs/string_refine_preprocess.h new file mode 100644 index 00000000000..37e178f799a --- /dev/null +++ b/src/goto-programs/string_refine_preprocess.h @@ -0,0 +1,215 @@ +/*******************************************************************\ + +Module: Preprocess a goto-programs so that calls to the java String + library are recognized by the PASS algorithm + +Author: Romain Brenguier + +Date: September 2016 + +\*******************************************************************/ + +#ifndef CPROVER_GOTO_PROGRAMS_STRING_REFINE_PREPROCESS_H +#define CPROVER_GOTO_PROGRAMS_STRING_REFINE_PREPROCESS_H + +#include +#include + +class string_refine_preprocesst:public messaget +{ + public: + string_refine_preprocesst( + symbol_tablet &, goto_functionst &, message_handlert &); + + private: + namespacet ns; + symbol_tablet & symbol_table; + goto_functionst & goto_functions; + + typedef std::unordered_map id_mapt; + typedef std::unordered_map expr_mapt; + + // String builders maps the different names of a same StringBuilder object + // to a unique expression. + expr_mapt string_builders; + + // Map name of Java string functions to there equivalent in the solver + id_mapt side_effect_functions; + id_mapt string_functions; + id_mapt c_string_functions; + id_mapt string_function_calls; + id_mapt string_of_char_array_functions; + id_mapt string_of_char_array_function_calls; + id_mapt side_effect_char_array_functions; + + std::unordered_map signatures; + expr_mapt hidden_strings; + expr_mapt java_to_cprover_strings; + + // unique id for each newly created symbols + int next_symbol_id; + + void initialize_string_function_table(); + + symbol_exprt fresh_array( + const typet &type, const source_locationt &location); + symbol_exprt fresh_string( + const typet &type, const source_locationt &location); + + // get the data member of a java string + static exprt get_data(const exprt &string, const typet &data_type) + { + return member_exprt(string, "data", data_type); + } + + // get the length member of a java string + exprt get_length(const exprt &string, const typet &length_type) + { + return member_exprt(string, "length", length_type); + } + + // type of pointers to string + pointer_typet jls_ptr; + exprt replace_string(const exprt &in); + exprt replace_string_in_assign(const exprt &in); + + void insert_assignments( + goto_programt &goto_program, + goto_programt::targett &target, + irep_idt function, + source_locationt location, + const std::list &va); + + exprt replace_string_pointer(const exprt &in); + + // Replace string builders by expression of the mapping and make + // assignments for strings as string_exprt + exprt::operandst process_arguments( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt::operandst &arguments, + const source_locationt &location, + const std::string &signature=""); + + // Signature of the named function if it is defined in the signature map, + // empty string otherwise + std::string function_signature(const irep_idt &function_id); + + void declare_function(irep_idt function_name, const typet &type); + + void get_data_and_length_type_of_string( + const exprt &expr, typet &data_type, typet &length_type); + + function_application_exprt build_function_application( + const irep_idt &function_name, + const typet &type, + const source_locationt &location, + const exprt::operandst &arguments); + + void make_normal_assign( + goto_programt &goto_program, + goto_programt::targett target, + const exprt &lhs, + const code_typet &function_type, + const irep_idt &function_name, + const exprt::operandst &arguments, + const source_locationt &location, + const std::string &signature=""); + + void make_string_assign( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &lhs, + const code_typet &function_type, + const irep_idt &function_name, + const exprt::operandst &arguments, + const source_locationt &location, + const std::string &signature); + + void make_assign( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &lhs, + const code_typet &function_type, + const irep_idt &function_name, + const exprt::operandst &arg, + const source_locationt &loc, + const std::string &sig); + + exprt make_cprover_string_assign( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &rhs, + const source_locationt &location); + + void make_string_copy( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &lhs, + const exprt &argument, + const source_locationt &location); + + void make_string_function( + goto_programt &goto_program, + goto_programt::targett &target, + const irep_idt &function_name, + const std::string &signature, + bool assign_first_arg=false, + bool skip_first_arg=false); + + void make_string_function( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &lhs, + const code_typet &function_type, + const irep_idt &function_name, + const exprt::operandst &arguments, + const source_locationt &location, + const std::string &signature); + + void make_string_function_call( + goto_programt &goto_program, + goto_programt::targett &target, + const irep_idt &function_name, + const std::string &signature); + + void make_string_function_side_effect( + goto_programt &goto_program, + goto_programt::targett &target, + const irep_idt &function_name, + const std::string &signature); + + void make_to_char_array_function( + goto_programt &goto_program, goto_programt::targett &); + + exprt make_cprover_char_array_assign( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &rhs, + const source_locationt &location); + + void make_char_array_function( + goto_programt &goto_program, + goto_programt::targett &target, + const irep_idt &function_name, + const std::string &signature, + std::size_t index, + bool assign_first_arg=false, + bool skip_first_arg=false); + + void make_char_array_function_call( + goto_programt &goto_program, + goto_programt::targett &target, + const irep_idt &function_name, + const std::string &signature); + + void make_char_array_side_effect( + goto_programt &goto_program, + goto_programt::targett &target, + const irep_idt &function_name, + const std::string &signature); + + void replace_string_calls(goto_functionst::function_mapt::iterator f_it); +}; + +#endif diff --git a/src/util/std_expr.h b/src/util/std_expr.h index c8a92a89b1f..69a03bdfa9c 100644 --- a/src/util/std_expr.h +++ b/src/util/std_expr.h @@ -3803,6 +3803,19 @@ class function_application_exprt:public exprt operands().resize(2); } + explicit function_application_exprt(const typet &_type): + exprt(ID_function_application, _type) + { + operands().resize(2); + } + + function_application_exprt( + const symbol_exprt &_function, const typet &_type): + function_application_exprt(_type) // NOLINT(runtime/explicit) + { + function()=_function; + } + exprt &function() { return op0(); From 0b41e8aad40b09888d0d9c28dc362996158db312 Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Fri, 17 Feb 2017 13:10:40 +0000 Subject: [PATCH 19/52] Moving is_java_string_type functions to string_preprocess This avoid dependencies between goto-programs and solver. We also removed function is_unrefined_string_type which should not be needed in the string solver. Removed also mention of java string types and unrefined types in the solver. These mentions should not be necessary, since we are not supposed to do anything java specific. The solver should only have to deal with refined string types and possibly char arrays. --- .../string_refine_preprocess.cpp | 146 ++++++++++++++++-- src/goto-programs/string_refine_preprocess.h | 10 ++ .../refinement/refined_string_type.cpp | 64 -------- src/solvers/refinement/refined_string_type.h | 36 +---- .../string_constraint_generator_constants.cpp | 2 +- .../string_constraint_generator_indexof.cpp | 20 ++- .../string_constraint_generator_main.cpp | 4 +- src/solvers/refinement/string_refinement.cpp | 6 +- 8 files changed, 166 insertions(+), 122 deletions(-) diff --git a/src/goto-programs/string_refine_preprocess.cpp b/src/goto-programs/string_refine_preprocess.cpp index c4dc1a92960..b14153c26c1 100644 --- a/src/goto-programs/string_refine_preprocess.cpp +++ b/src/goto-programs/string_refine_preprocess.cpp @@ -22,7 +22,125 @@ Date: September 2016 #include "string_refine_preprocess.h" -/******************************************************************* \ +/*******************************************************************\ + +Function: string_refine_preprocesst::is_java_string_pointer_type + + Inputs: a type + + Outputs: Boolean telling whether the type is that of java string pointers + +\*******************************************************************/ + +bool string_refine_preprocesst::is_java_string_pointer_type(const typet &type) +{ + if(type.id()==ID_pointer) + { + const pointer_typet &pt=to_pointer_type(type); + const typet &subtype=pt.subtype(); + return is_java_string_type(subtype); + } + return false; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::is_java_string_type + + Inputs: a type + + Outputs: Boolean telling whether the type is that of java string + +\*******************************************************************/ + +bool string_refine_preprocesst::is_java_string_type(const typet &type) +{ + if(type.id()==ID_symbol) + { + const irep_idt &tag=to_symbol_type(type).get_identifier(); + return tag=="java::java.lang.String"; + } + else if(type.id()==ID_struct) + { + const irep_idt &tag=to_struct_type(type).get_tag(); + return tag=="java.lang.String"; + } + return false; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::is_java_string_builder_type + + Inputs: a type + + Outputs: Boolean telling whether the type is that of java string builder + +\*******************************************************************/ + +bool string_refine_preprocesst::is_java_string_builder_type(const typet &type) +{ + if(type.id()==ID_pointer) + { + const pointer_typet &pt=to_pointer_type(type); + const typet &subtype=pt.subtype(); + if(subtype.id()==ID_struct) + { + const irep_idt &tag=to_struct_type(subtype).get_tag(); + return tag=="java.lang.StringBuilder"; + } + } + return false; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::is_java_string_builder_pointer_type + + Inputs: a type + + Outputs: Boolean telling whether the type is that of java StringBuilder + pointers + +\*******************************************************************/ + +bool string_refine_preprocesst::is_java_string_builder_pointer_type( + const typet &type) +{ + if(type.id()==ID_pointer) + { + const pointer_typet &pt=to_pointer_type(type); + const typet &subtype=pt.subtype(); + return is_java_string_builder_type(subtype); + } + return false; +} +/*******************************************************************\ + +Function: string_refine_preprocesst::is_java_char_sequence_type + + Inputs: a type + + Outputs: Boolean telling whether the type is that of java char sequence + +\*******************************************************************/ + +bool string_refine_preprocesst::is_java_char_sequence_type(const typet &type) +{ + if(type.id()==ID_pointer) + { + const pointer_typet &pt=to_pointer_type(type); + const typet &subtype=pt.subtype(); + if(subtype.id()==ID_struct) + { + const irep_idt &tag=to_struct_type(subtype).get_tag(); + return tag=="java.lang.CharSequence"; + } + } + return false; +} + +/*******************************************************************\ Function: string_refine_preprocesst::fresh_array @@ -114,8 +232,8 @@ Function: string_refine_preprocesst::get_data_and_length_type_of_string void string_refine_preprocesst::get_data_and_length_type_of_string( const exprt &expr, typet &data_type, typet &length_type) { - assert(refined_string_typet::is_java_string_type(expr.type()) || - refined_string_typet::is_java_string_builder_type(expr.type())); + assert(is_java_string_type(expr.type()) || + is_java_string_builder_type(expr.type())); typet object_type=ns.follow(expr.type()); const struct_typet &struct_type=to_struct_type(object_type); for(const auto &component : struct_type.components()) @@ -146,7 +264,7 @@ exprt string_refine_preprocesst::make_cprover_string_assign( const exprt &rhs, const source_locationt &location) { - if(refined_string_typet::is_java_string_pointer_type(rhs.type())) + if(is_java_string_pointer_type(rhs.type())) { auto pair=java_to_cprover_strings.insert( std::pair(rhs, nil_exprt())); @@ -183,7 +301,7 @@ exprt string_refine_preprocesst::make_cprover_string_assign( return pair.first->second; } else if(rhs.id()==ID_typecast && - refined_string_typet::is_java_string_pointer_type(rhs.op0().type())) + is_java_string_pointer_type(rhs.op0().type())) { exprt new_rhs=make_cprover_string_assign( goto_program, target, rhs.op0(), location); @@ -303,8 +421,7 @@ void string_refine_preprocesst::make_string_assign( const source_locationt &location, const std::string &signature) { - assert(refined_string_typet::is_java_string_pointer_type( - function_type.return_type())); + assert(is_java_string_pointer_type(function_type.return_type())); dereference_exprt deref(lhs, lhs.type().subtype()); typet object_type=ns.follow(deref.type()); exprt object_size=size_of_expr(object_type, ns); @@ -371,8 +488,7 @@ void string_refine_preprocesst::make_assign( const source_locationt &loc, const std::string &sig) { - if(refined_string_typet::is_java_string_pointer_type( - function_type.return_type())) + if(is_java_string_pointer_type(function_type.return_type())) make_string_assign( goto_program, target, lhs, function_type, function_name, arg, loc, sig); else @@ -404,8 +520,8 @@ void string_refine_preprocesst::make_string_copy( const source_locationt &location) { // TODO : treat CharSequence and StringBuffer - assert(refined_string_typet::is_java_string_pointer_type(lhs.type()) || - refined_string_typet::is_java_string_builder_pointer_type(lhs.type())); + assert(is_java_string_pointer_type(lhs.type()) || + is_java_string_builder_pointer_type(lhs.type())); exprt deref=dereference_exprt(lhs, lhs.type().subtype()); typet length_type, data_type; @@ -451,8 +567,7 @@ void string_refine_preprocesst::make_string_function( const source_locationt &location, const std::string &signature) { - if(refined_string_typet::is_java_string_pointer_type( - function_type.return_type())) + if(is_java_string_pointer_type(function_type.return_type())) make_string_assign( goto_program, target, @@ -633,8 +748,7 @@ void string_refine_preprocesst::make_to_char_array_function( assert(!function_call.arguments().empty()); const exprt &string_argument=function_call.arguments()[0]; - assert(refined_string_typet::is_java_string_pointer_type( - string_argument.type())); + assert(is_java_string_pointer_type(string_argument.type())); dereference_exprt deref(string_argument, string_argument.type().subtype()); typet length_type, data_type; @@ -870,7 +984,7 @@ exprt::operandst string_refine_preprocesst::process_arguments( { while(arg.id()==ID_typecast) arg=arg.op0(); - if(!refined_string_typet::is_java_string_type(arg.type())) + if(!is_java_string_type(arg.type())) arg=typecast_exprt(arg, jls_ptr); } exprt arg2=make_cprover_string_assign( diff --git a/src/goto-programs/string_refine_preprocess.h b/src/goto-programs/string_refine_preprocess.h index 37e178f799a..613d0161926 100644 --- a/src/goto-programs/string_refine_preprocess.h +++ b/src/goto-programs/string_refine_preprocess.h @@ -51,6 +51,16 @@ class string_refine_preprocesst:public messaget void initialize_string_function_table(); + static bool is_java_string_pointer_type(const typet &type); + + static bool is_java_string_type(const typet &type); + + static bool is_java_string_builder_type(const typet &type); + + static bool is_java_string_builder_pointer_type(const typet &type); + + static bool is_java_char_sequence_type(const typet &type); + symbol_exprt fresh_array( const typet &type, const source_locationt &location); symbol_exprt fresh_string( diff --git a/src/solvers/refinement/refined_string_type.cpp b/src/solvers/refinement/refined_string_type.cpp index dd91489e8fd..55529c5f2d5 100644 --- a/src/solvers/refinement/refined_string_type.cpp +++ b/src/solvers/refinement/refined_string_type.cpp @@ -37,67 +37,3 @@ bool refined_string_typet::is_c_string_type(const typet &type) type.id()==ID_struct && to_struct_type(type).get_tag()==CPROVER_PREFIX"string"; } - -/// \par parameters: a type -/// \return Boolean telling whether the type is that of java string pointers -bool refined_string_typet::is_java_string_pointer_type(const typet &type) -{ - if(type.id()==ID_pointer) - { - const pointer_typet &pt=to_pointer_type(type); - const typet &subtype=pt.subtype(); - return is_java_string_type(subtype); - } - return false; -} - -/// \par parameters: a type -/// \return Boolean telling whether the type is that of java string -bool refined_string_typet::is_java_string_type(const typet &type) -{ - if(type.id()==ID_symbol) - { - irep_idt tag=to_symbol_type(type).get_identifier(); - return tag=="java::java.lang.String"; - } - else if(type.id()==ID_struct) - { - irep_idt tag=to_struct_type(type).get_tag(); - return tag=="java.lang.String"; - } - return false; -} - -/// \par parameters: a type -/// \return Boolean telling whether the type is that of java string builder -bool refined_string_typet::is_java_string_builder_type(const typet &type) -{ - if(type.id()==ID_pointer) - { - const pointer_typet &pt=to_pointer_type(type); - const typet &subtype=pt.subtype(); - if(subtype.id()==ID_struct) - { - irep_idt tag=to_struct_type(subtype).get_tag(); - return tag=="java.lang.StringBuilder"; - } - } - return false; -} - -/// \par parameters: a type -/// \return Boolean telling whether the type is that of java char sequence -bool refined_string_typet::is_java_char_sequence_type(const typet &type) -{ - if(type.id()==ID_pointer) - { - const pointer_typet &pt=to_pointer_type(type); - const typet &subtype=pt.subtype(); - if(subtype.id()==ID_struct) - { - const irep_idt &tag=to_struct_type(subtype).get_tag(); - return tag=="java.lang.CharSequence"; - } - } - return false; -} diff --git a/src/solvers/refinement/refined_string_type.h b/src/solvers/refinement/refined_string_type.h index 4d5e11afa84..46a6b93cac7 100644 --- a/src/solvers/refinement/refined_string_type.h +++ b/src/solvers/refinement/refined_string_type.h @@ -39,41 +39,20 @@ class refined_string_typet: public struct_typet const typet &get_char_type() const { - assert(components().size()==2); - return components()[0].type(); + return get_content_type().subtype(); } const typet &get_index_type() const { - return get_content_type().size().type(); + assert(components().size()==2); + return components()[0].type(); } - // For C the unrefined string type is __CPROVER_string, for java it is a - // pointer to a struct with tag java.lang.String + // For C the unrefined string type is __CPROVER_string static bool is_c_string_type(const typet &type); - static bool is_java_string_pointer_type(const typet &type); - - static bool is_java_string_type(const typet &type); - - static bool is_java_string_builder_type(const typet &type); - - static bool is_java_char_sequence_type(const typet &type); - - static bool is_unrefined_string_type(const typet &type) - { - return ( - is_c_string_type(type) || - is_java_string_pointer_type(type) || - is_java_string_builder_type(type) || - is_java_char_sequence_type(type)); - } - - static bool is_unrefined_string(const exprt &expr) - { - return (is_unrefined_string_type(expr.type())); - } + static bool is_refined_string_type(const typet &type); constant_exprt index_of_int(int i) const { @@ -81,9 +60,10 @@ class refined_string_typet: public struct_typet } }; -const refined_string_typet &to_refined_string_type(const typet &type) +extern inline const refined_string_typet &to_refined_string_type( + const typet &type) { - assert(type.id()==ID_struct); + assert(refined_string_typet::is_refined_string_type(type)); return static_cast(type); } diff --git a/src/solvers/refinement/string_constraint_generator_constants.cpp b/src/solvers/refinement/string_constraint_generator_constants.cpp index 3c05aaf5440..8ee5d8c3427 100644 --- a/src/solvers/refinement/string_constraint_generator_constants.cpp +++ b/src/solvers/refinement/string_constraint_generator_constants.cpp @@ -100,7 +100,7 @@ string_exprt string_constraint_generatort::add_axioms_from_literal( else { // Java string constant - assert(refined_string_typet::is_unrefined_string_type(arg.type())); + assert(arg.id()==ID_symbol); const exprt &s=arg.op0(); // It seems the value of the string is lost, diff --git a/src/solvers/refinement/string_constraint_generator_indexof.cpp b/src/solvers/refinement/string_constraint_generator_indexof.cpp index d32be2e3570..67ee7ad7b1c 100644 --- a/src/solvers/refinement/string_constraint_generator_indexof.cpp +++ b/src/solvers/refinement/string_constraint_generator_indexof.cpp @@ -163,14 +163,16 @@ exprt string_constraint_generatort::add_axioms_for_index_of( else assert(false); - if(refined_string_typet::is_java_string_pointer_type(c.type())) + if(c.type().id()==ID_unsignedbv) + { + return add_axioms_for_index_of( + str, typecast_exprt(c, ref_type.get_char_type()), from_index); + } + else { string_exprt sub=add_axioms_for_string_expr(c); return add_axioms_for_index_of_string(str, sub, from_index); } - else - return add_axioms_for_index_of( - str, typecast_exprt(c, ref_type.get_char_type()), from_index); } exprt string_constraint_generatort::add_axioms_for_last_index_of( @@ -248,12 +250,14 @@ exprt string_constraint_generatort::add_axioms_for_last_index_of( else assert(false); - if(refined_string_typet::is_java_string_pointer_type(c.type())) + if(c.type().id()==ID_unsignedbv) + { + return add_axioms_for_last_index_of( + str, typecast_exprt(c, ref_type.get_char_type()), from_index); + } + else { string_exprt sub=add_axioms_for_string_expr(c); return add_axioms_for_last_index_of_string(str, sub, from_index); } - else - return add_axioms_for_last_index_of( - str, typecast_exprt(c, ref_type.get_char_type()), from_index); } diff --git a/src/solvers/refinement/string_constraint_generator_main.cpp b/src/solvers/refinement/string_constraint_generator_main.cpp index b0b48df18bd..bcb0ef13302 100644 --- a/src/solvers/refinement/string_constraint_generator_main.cpp +++ b/src/solvers/refinement/string_constraint_generator_main.cpp @@ -149,10 +149,10 @@ string_exprt string_constraint_generatort::add_axioms_for_if( const if_exprt &expr) { assert( - refined_string_typet::is_unrefined_string_type(expr.true_case().type())); + refined_string_typet::is_c_string_type(expr.true_case().type())); string_exprt t=add_axioms_for_string_expr(expr.true_case()); assert( - refined_string_typet::is_unrefined_string_type(expr.false_case().type())); + refined_string_typet::is_c_string_type(expr.false_case().type())); string_exprt f=add_axioms_for_string_expr(expr.false_case()); const refined_string_typet &ref_type=to_refined_string_type(t.type()); const typet &index_type=ref_type.get_index_type(); diff --git a/src/solvers/refinement/string_refinement.cpp b/src/solvers/refinement/string_refinement.cpp index 36f619b8add..0f31a6add0f 100644 --- a/src/solvers/refinement/string_refinement.cpp +++ b/src/solvers/refinement/string_refinement.cpp @@ -114,7 +114,7 @@ bvt string_refinementt::convert_symbol(const exprt &expr) const irep_idt &identifier=expr.get(ID_identifier); assert(!identifier.empty()); - if(refined_string_typet::is_unrefined_string_type(type)) + if(refined_string_typet::is_refined_string_type(type)) { string_exprt str= generator.find_or_add_string_of_symbol(to_symbol_expr(expr)); @@ -165,7 +165,7 @@ bool string_refinementt::boolbv_set_equality_to_true(const equal_exprt &expr) if(expr.rhs().id()==ID_typecast) { exprt uncast=to_typecast_expr(expr.rhs()).op(); - if(refined_string_typet::is_unrefined_string_type(uncast.type())) + if(refined_string_typet::is_refined_string_type(uncast.type())) { debug() << "(sr) detected casted string" << eom; symbol_exprt sym=to_symbol_expr(expr.lhs()); @@ -174,7 +174,7 @@ bool string_refinementt::boolbv_set_equality_to_true(const equal_exprt &expr) } } - if(refined_string_typet::is_unrefined_string_type(type)) + if(refined_string_typet::is_refined_string_type(type)) { symbol_exprt sym=to_symbol_expr(expr.lhs()); generator.set_string_symbol_equal_to_expr(sym, expr.rhs()); From 95f0b6c4373088ca0568c2192658301ae88c452d Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Fri, 24 Feb 2017 11:02:55 +0000 Subject: [PATCH 20/52] Moving refined_string_type to util This is a more appropriate location for this module since it's used both in the preprocessing of goto-programs and the string solver. --- src/goto-programs/string_refine_preprocess.cpp | 3 +-- src/solvers/refinement/string_constraint.h | 2 +- src/solvers/refinement/string_constraint_generator.h | 2 +- src/{solvers/refinement => util}/refined_string_type.cpp | 0 src/{solvers/refinement => util}/refined_string_type.h | 4 ++-- 5 files changed, 5 insertions(+), 6 deletions(-) rename src/{solvers/refinement => util}/refined_string_type.cpp (100%) rename src/{solvers/refinement => util}/refined_string_type.h (94%) diff --git a/src/goto-programs/string_refine_preprocess.cpp b/src/goto-programs/string_refine_preprocess.cpp index b14153c26c1..ec02988d577 100644 --- a/src/goto-programs/string_refine_preprocess.cpp +++ b/src/goto-programs/string_refine_preprocess.cpp @@ -14,10 +14,9 @@ Date: September 2016 #include #include #include +#include #include #include -// TODO: refined_string_type should be moved to util -#include #include #include "string_refine_preprocess.h" diff --git a/src/solvers/refinement/string_constraint.h b/src/solvers/refinement/string_constraint.h index 27a6a87a5a8..aa5e50ba018 100644 --- a/src/solvers/refinement/string_constraint.h +++ b/src/solvers/refinement/string_constraint.h @@ -22,7 +22,7 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com #include #include -#include +#include class string_constraintt: public exprt { diff --git a/src/solvers/refinement/string_constraint_generator.h b/src/solvers/refinement/string_constraint_generator.h index 84732931d70..4f2f72039b9 100644 --- a/src/solvers/refinement/string_constraint_generator.h +++ b/src/solvers/refinement/string_constraint_generator.h @@ -21,7 +21,7 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com #define CPROVER_SOLVERS_REFINEMENT_STRING_CONSTRAINT_GENERATOR_H #include -#include +#include #include class string_constraint_generatort diff --git a/src/solvers/refinement/refined_string_type.cpp b/src/util/refined_string_type.cpp similarity index 100% rename from src/solvers/refinement/refined_string_type.cpp rename to src/util/refined_string_type.cpp diff --git a/src/solvers/refinement/refined_string_type.h b/src/util/refined_string_type.h similarity index 94% rename from src/solvers/refinement/refined_string_type.h rename to src/util/refined_string_type.h index 46a6b93cac7..4c494a767ec 100644 --- a/src/solvers/refinement/refined_string_type.h +++ b/src/util/refined_string_type.h @@ -16,8 +16,8 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com /// `content` of type `content_type`. This module also defines functions to /// recognise the C and java string types. -#ifndef CPROVER_SOLVERS_REFINEMENT_REFINED_STRING_TYPE_H -#define CPROVER_SOLVERS_REFINEMENT_REFINED_STRING_TYPE_H +#ifndef CPROVER_UTIL_REFINED_STRING_TYPE_H +#define CPROVER_UTIL_REFINED_STRING_TYPE_H #include #include From d1d325157e98a8ebe6df3b85c1399bb75a77005e Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Mon, 27 Feb 2017 11:14:11 +0000 Subject: [PATCH 21/52] Removed distinction between c string type and refined string type --- src/util/refined_string_type.cpp | 7 ++++--- src/util/refined_string_type.h | 4 ---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/util/refined_string_type.cpp b/src/util/refined_string_type.cpp index 55529c5f2d5..84b628c4918 100644 --- a/src/util/refined_string_type.cpp +++ b/src/util/refined_string_type.cpp @@ -27,13 +27,14 @@ refined_string_typet::refined_string_typet( array_typet char_array(char_type, infinite_index); components().emplace_back("length", index_type); components().emplace_back("content", char_array); + set_tag(CPROVER_PREFIX"refined_string_type"); } /// \par parameters: a type -/// \return Boolean telling whether the type is that of C strings -bool refined_string_typet::is_c_string_type(const typet &type) +/// \return Boolean telling whether the input is a refined string type +bool refined_string_typet::is_refined_string_type(const typet &type) { return type.id()==ID_struct && - to_struct_type(type).get_tag()==CPROVER_PREFIX"string"; + to_struct_type(type).get_tag()==CPROVER_PREFIX"refined_string_type"; } diff --git a/src/util/refined_string_type.h b/src/util/refined_string_type.h index 4c494a767ec..efa8a0987ec 100644 --- a/src/util/refined_string_type.h +++ b/src/util/refined_string_type.h @@ -48,10 +48,6 @@ class refined_string_typet: public struct_typet return components()[0].type(); } - // For C the unrefined string type is __CPROVER_string - - static bool is_c_string_type(const typet &type); - static bool is_refined_string_type(const typet &type); constant_exprt index_of_int(int i) const From 6278614f9511a79cdf69d4ddf0eb7eb0b11159ff Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Mon, 27 Feb 2017 11:14:21 +0000 Subject: [PATCH 22/52] Removed mention of c string type Refined string type should be used instead as we are trying to be language independent. --- src/solvers/refinement/string_constraint_generator_main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/solvers/refinement/string_constraint_generator_main.cpp b/src/solvers/refinement/string_constraint_generator_main.cpp index bcb0ef13302..13390ee877c 100644 --- a/src/solvers/refinement/string_constraint_generator_main.cpp +++ b/src/solvers/refinement/string_constraint_generator_main.cpp @@ -149,10 +149,10 @@ string_exprt string_constraint_generatort::add_axioms_for_if( const if_exprt &expr) { assert( - refined_string_typet::is_c_string_type(expr.true_case().type())); + refined_string_typet::is_refined_string_type(expr.true_case().type())); string_exprt t=add_axioms_for_string_expr(expr.true_case()); assert( - refined_string_typet::is_c_string_type(expr.false_case().type())); + refined_string_typet::is_refined_string_type(expr.false_case().type())); string_exprt f=add_axioms_for_string_expr(expr.false_case()); const refined_string_typet &ref_type=to_refined_string_type(t.type()); const typet &index_type=ref_type.get_index_type(); From 0adc109761e9a9649b30d87caa5dc8d59196eebe Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Tue, 7 Feb 2017 11:11:47 +0000 Subject: [PATCH 23/52] Making add_string_type more generic The class_name is now passed as argument so that we can reuse this function for StringBuilder and other "String-like" classes. --- .../java_bytecode_convert_class.cpp | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/java_bytecode/java_bytecode_convert_class.cpp b/src/java_bytecode/java_bytecode_convert_class.cpp index 05b4e44e47b..34f7082ea25 100644 --- a/src/java_bytecode/java_bytecode_convert_class.cpp +++ b/src/java_bytecode/java_bytecode_convert_class.cpp @@ -53,7 +53,16 @@ class java_bytecode_convert_classt:public messaget convert(parse_tree.parsed_class); else if(string_refinement_enabled && parse_tree.parsed_class.name=="java.lang.String") - add_string_type(); + add_string_type("java.lang.String"); + else if(string_refinement_enabled && + parse_tree.parsed_class.name=="java.lang.StringBuilder") + add_string_type("java.lang.StringBuilder"); + else if(string_refinement_enabled && + parse_tree.parsed_class.name=="java.lang.CharSequence") + add_string_type("java.lang.CharSequence"); + else if(string_refinement_enabled && + parse_tree.parsed_class.name=="java.lang.StringBuffer") + add_string_type("java.lang.StringBuffer"); else generate_class_stub(parse_tree.parsed_class.name); } @@ -75,7 +84,7 @@ class java_bytecode_convert_classt:public messaget void generate_class_stub(const irep_idt &class_name); void add_array_types(); - void add_string_type(); + void add_string_type(const irep_idt &class_name); }; void java_bytecode_convert_classt::convert(const classt &c) @@ -349,10 +358,11 @@ bool java_bytecode_convert_class( /// Implements the java.lang.String type in the case that we provide an internal /// implementation. -void java_bytecode_convert_classt::add_string_type() +/// \param class_name: a name for the class such as "java.lang.String" +void java_bytecode_convert_classt::add_string_type(const irep_idt &class_name) { class_typet string_type; - string_type.set_tag("java.lang.String"); + string_type.set_tag(class_name); string_type.components().resize(3); string_type.components()[0].set_name("@java.lang.Object"); string_type.components()[0].set_pretty_name("@java.lang.Object"); @@ -370,8 +380,8 @@ void java_bytecode_convert_classt::add_string_type() string_type.add_base(symbol_typet("java::java.lang.Object")); symbolt string_symbol; - string_symbol.name="java::java.lang.String"; - string_symbol.base_name="java.lang.String"; + string_symbol.name="java::"+id2string(class_name); + string_symbol.base_name=id2string(class_name); string_symbol.type=string_type; string_symbol.is_type=true; @@ -383,8 +393,8 @@ void java_bytecode_convert_classt::add_string_type() symbolt string_equals_symbol; string_equals_symbol.name= "java::java.lang.String.equals:(Ljava/lang/Object;)Z"; - string_equals_symbol.base_name="java.lang.String.equals"; - string_equals_symbol.pretty_name="java.lang.String.equals"; + string_equals_symbol.base_name=id2string(class_name)+".equals"; + string_equals_symbol.pretty_name=id2string(class_name)+".equals"; string_equals_symbol.mode=ID_java; code_typet string_equals_type; From 846abf4b97dc15fdafef8a518c6ac7a96037fd79 Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Thu, 9 Mar 2017 15:02:08 +0000 Subject: [PATCH 24/52] new identifier for converting char pointer to array --- src/util/irep_ids.def | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/irep_ids.def b/src/util/irep_ids.def index 77568e3d5d6..70bca4bff5f 100644 --- a/src/util/irep_ids.def +++ b/src/util/irep_ids.def @@ -811,6 +811,7 @@ IREP_ID_ONE(cprover_string_trim_func) IREP_ID_ONE(cprover_string_value_of_func) IREP_ID_ONE(array_replace) IREP_ID_ONE(basic_block_covered_lines) +IREP_ID_ONE(cprover_string_array_of_char_pointer_func) #undef IREP_ID_ONE #undef IREP_ID_TWO From fbd797ca9879565a14ddde6675b7d21535ba6ea2 Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Fri, 17 Feb 2017 13:18:54 +0000 Subject: [PATCH 25/52] Many corrections in preprocessing of strings Better signatures and string detection Better detection of string-like types and handling of char arrays Changing the way we deal with string initialisation from array Factorized part of type recognition and added StringBuilder and CharSequence to the list of java classes that should be considered as string. Changed the way we deal with StringBuilders: instead of having a map we add an assignment to the instructions. We also detect char arrays and handle them better. We now use substring and copy functions for initialisation from char array since the argument are always transformed into refined strings. For each string returned by a string function we also add into the java_string_to_cprover_string map a string_exprt. Corrected detection of typecast in make_cprover_string_assign Ensuring refined_string arguments of function applications are string_exprt Correct string_refine_preprocesst constructor. Order of initialisation is now the same as the order of declaration. This was picked up by g++ and clang. Added signatures for some StringBuilder functions. Removed map java_to_cprover_string and adapt signature for side effects. The usage of a map is not correct since strings can be modified by side effects. Signature is necessary for StringBuilders to be assigned in the right way with methods with side effects. Assign all string_exprt to refined string symbols in preprocessing. This makes it then easier to debug and to find witnesses for counter examples in the solver. Make signatures take priority over actual type and add signature for intern. Linting corrections Adding malloc for char arrays for String.toCharArray Fixing preprocessing of string function with side effect This fixes problems we were getting with some StringBuilder functions. The return value should contain a pointer to the original StringBuilder and the fields of the StringBuilder should be filled with the result of the function call. Corrected mistake in preprocessing of string functions with side effects char array assignements returns a string_exprt This is to be uniform with other preprocessing functions also returning string_exprt Preprocessing for StringBuilder.append on char array Corrected update of signature and commented out some unused code Corrected the initialization from char array We cannot use the substring function because the meaning of the third argument is different between `String.([CII)` and `String.substring(SII)` Using new id for conversion between char pointer and array Cleaning of preprocessing for strings Removed useless functions and merged some maps Make a copy of the function call to be modified Removed redeclaration of location --- .../string_refine_preprocess.cpp | 797 +++++++++--------- src/goto-programs/string_refine_preprocess.h | 71 +- 2 files changed, 416 insertions(+), 452 deletions(-) diff --git a/src/goto-programs/string_refine_preprocess.cpp b/src/goto-programs/string_refine_preprocess.cpp index ec02988d577..8403d4bf044 100644 --- a/src/goto-programs/string_refine_preprocess.cpp +++ b/src/goto-programs/string_refine_preprocess.cpp @@ -23,6 +23,32 @@ Date: September 2016 /*******************************************************************\ +Function: string_refine_preprocesst::check_java_type + + Inputs: a type and a string + + Outputs: Boolean telling whether the type is a struct with the given + tag or a symbolic type with the tag prefixed by "java::" + +\*******************************************************************/ + +bool string_refine_preprocesst::check_java_type( + const typet &type, const std::string &tag) +{ + if(type.id()==ID_symbol) + { + irep_idt tag_id=to_symbol_type(type).get_identifier(); + return tag_id=="java::"+tag; + } + else if(type.id()==ID_struct) + { + irep_idt tag_id=to_struct_type(type).get_tag(); + return tag_id==tag; + } + return false; +} +/*******************************************************************\ + Function: string_refine_preprocesst::is_java_string_pointer_type Inputs: a type @@ -54,17 +80,7 @@ Function: string_refine_preprocesst::is_java_string_type bool string_refine_preprocesst::is_java_string_type(const typet &type) { - if(type.id()==ID_symbol) - { - const irep_idt &tag=to_symbol_type(type).get_identifier(); - return tag=="java::java.lang.String"; - } - else if(type.id()==ID_struct) - { - const irep_idt &tag=to_struct_type(type).get_tag(); - return tag=="java.lang.String"; - } - return false; + return check_java_type(type, "java.lang.String"); } /*******************************************************************\ @@ -79,17 +95,7 @@ Function: string_refine_preprocesst::is_java_string_builder_type bool string_refine_preprocesst::is_java_string_builder_type(const typet &type) { - if(type.id()==ID_pointer) - { - const pointer_typet &pt=to_pointer_type(type); - const typet &subtype=pt.subtype(); - if(subtype.id()==ID_struct) - { - const irep_idt &tag=to_struct_type(subtype).get_tag(); - return tag=="java.lang.StringBuilder"; - } - } - return false; + return check_java_type(type, "java.lang.StringBuilder"); } /*******************************************************************\ @@ -114,6 +120,7 @@ bool string_refine_preprocesst::is_java_string_builder_pointer_type( } return false; } + /*******************************************************************\ Function: string_refine_preprocesst::is_java_char_sequence_type @@ -125,16 +132,67 @@ Function: string_refine_preprocesst::is_java_char_sequence_type \*******************************************************************/ bool string_refine_preprocesst::is_java_char_sequence_type(const typet &type) +{ + return check_java_type(type, "java.lang.CharSequence"); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::is_java_char_sequence_pointer_type + + Inputs: a type + + Outputs: Boolean telling whether the type is that of a pointer + to a java char sequence + +\*******************************************************************/ + +bool string_refine_preprocesst::is_java_char_sequence_pointer_type( + const typet &type) { if(type.id()==ID_pointer) { const pointer_typet &pt=to_pointer_type(type); const typet &subtype=pt.subtype(); - if(subtype.id()==ID_struct) - { - const irep_idt &tag=to_struct_type(subtype).get_tag(); - return tag=="java.lang.CharSequence"; - } + return is_java_char_sequence_type(subtype); + } + return false; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::is_java_char_array_type + + Inputs: a type + + Outputs: Boolean telling whether the type is that of java char array + +\*******************************************************************/ + +bool string_refine_preprocesst::is_java_char_array_type(const typet &type) +{ + return check_java_type(type, "array[char]"); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::is_java_char_array_pointer_type + + Inputs: a type + + Outputs: Boolean telling whether the type is that of a pointer + to a java char array + +\*******************************************************************/ + +bool string_refine_preprocesst::is_java_char_array_pointer_type( + const typet &type) +{ + if(type.id()==ID_pointer) + { + const pointer_typet &pt=to_pointer_type(type); + const typet &subtype=pt.subtype(); + return is_java_char_array_type(subtype); } return false; } @@ -217,6 +275,32 @@ void string_refine_preprocesst::declare_function( /*******************************************************************\ +Function: string_refine_preprocesst::get_data_and_length_type_of_char_array + + Inputs: an expression, a reference to a data type and a reference to a + length type + + Purpose: assuming the expression is a char array, figure out what + the types for length and data are and put them into the references + given as argument + +\*******************************************************************/ + +void string_refine_preprocesst::get_data_and_length_type_of_char_array( + const exprt &expr, typet &data_type, typet &length_type) +{ + typet object_type=ns.follow(expr.type()); + assert(object_type.id()==ID_struct); + const struct_typet &struct_type=to_struct_type(object_type); + for(auto component : struct_type.components()) + if(component.get_name()=="length") + length_type=component.type(); + else if(component.get_name()=="data") + data_type=component.type(); +} + +/*******************************************************************\ + Function: string_refine_preprocesst::get_data_and_length_type_of_string Inputs: an expression, a reference to a data type and a reference to a @@ -232,7 +316,8 @@ void string_refine_preprocesst::get_data_and_length_type_of_string( const exprt &expr, typet &data_type, typet &length_type) { assert(is_java_string_type(expr.type()) || - is_java_string_builder_type(expr.type())); + is_java_string_builder_type(expr.type()) || + is_java_char_sequence_type(expr.type())); typet object_type=ns.follow(expr.type()); const struct_typet &struct_type=to_struct_type(object_type); for(const auto &component : struct_type.components()) @@ -263,44 +348,43 @@ exprt string_refine_preprocesst::make_cprover_string_assign( const exprt &rhs, const source_locationt &location) { - if(is_java_string_pointer_type(rhs.type())) + if(implements_java_char_sequence(rhs.type())) { - auto pair=java_to_cprover_strings.insert( - std::pair(rhs, nil_exprt())); - - if(pair.second) - { - // We do the following assignments: - // cprover_string_array = *(rhs->data) - // cprover_string = { rhs->length; cprover_string_array } - - dereference_exprt deref(rhs, rhs.type().subtype()); - - typet data_type, length_type; - get_data_and_length_type_of_string(deref, data_type, length_type); - member_exprt length(deref, "length", length_type); - symbol_exprt array_lhs=fresh_array(data_type.subtype(), location); - - // string expression for the rhs of the second assignment - string_exprt new_rhs( - length, array_lhs, refined_string_typet(length_type, data_type)); - - member_exprt data(deref, "data", data_type); - dereference_exprt deref_data(data, data_type.subtype()); - symbol_exprt lhs=fresh_string(new_rhs.type(), location); - - std::list assignments; - assignments.emplace_back(array_lhs, deref_data); - assignments.emplace_back(lhs, new_rhs); - insert_assignments( - goto_program, target, target->function, location, assignments); - target=goto_program.insert_after(target); - pair.first->second=lhs; - } - return pair.first->second; + // We do the following assignments: + // 1 length= *(rhs->length) + // 2 cprover_string_array = *(rhs->data) + // 3 cprover_string = { length; cprover_string_array } + + dereference_exprt deref(rhs, rhs.type().subtype()); + typet data_type, length_type; + get_data_and_length_type_of_string(deref, data_type, length_type); + std::list assignments; + + // 1) cprover_string_length= *(rhs->length) + member_exprt length(deref, "length", length_type); + + // 2) cprover_string_array = *(rhs->data) + symbol_exprt array_lhs=fresh_array(data_type.subtype(), location); + member_exprt data(deref, "data", data_type); + dereference_exprt deref_data(data, data_type.subtype()); + assignments.emplace_back(array_lhs, deref_data); + + // 3) cprover_string = { cprover_string_length; cprover_string_array } + // This assignment is useful for finding witnessing strings for counter + // examples + refined_string_typet ref_type(length_type, java_char_type()); + string_exprt new_rhs(length, array_lhs, ref_type); + + symbol_exprt lhs=fresh_string(new_rhs.type(), location); + assignments.emplace_back(lhs, new_rhs); + + insert_assignments( + goto_program, target, target->function, location, assignments); + target=goto_program.insert_after(target); + return new_rhs; } else if(rhs.id()==ID_typecast && - is_java_string_pointer_type(rhs.op0().type())) + implements_java_char_sequence(rhs.op0().type())) { exprt new_rhs=make_cprover_string_assign( goto_program, target, rhs.op0(), location); @@ -312,6 +396,75 @@ exprt string_refine_preprocesst::make_cprover_string_assign( /*******************************************************************\ +Function: string_refine_preprocesst::make_cprover_char_array_assign + + Inputs: a goto_program, a position in this program, an expression of + type char array pointer and a location + + Outputs: a string expression + + Purpose: Introduce a temporary variable for cprover strings; + returns the cprover_string corresponding to rhs + +\*******************************************************************/ + +string_exprt string_refine_preprocesst::make_cprover_char_array_assign( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &rhs, + const source_locationt &location) +{ + assert(is_java_char_array_pointer_type(rhs.type())); + + // We do the following assignments: + // deref=*(rhs->data) + // array= typecast(&deref); + // string={ rhs->length; array } + + dereference_exprt deref(rhs, rhs.type().subtype()); + typet length_type, data_type; + get_data_and_length_type_of_char_array(deref, data_type, length_type); + assert(data_type.id()==ID_pointer); + typet char_type=to_pointer_type(data_type).subtype(); + + refined_string_typet ref_type(length_type, java_char_type()); + typet content_type=ref_type.get_content_type(); + std::list assignments; + + // deref=*(rhs->data) + member_exprt array_rhs(deref, "data", data_type); + dereference_exprt deref_array(array_rhs, data_type.subtype()); + symbolt sym_lhs_deref=get_fresh_aux_symbol( + data_type.subtype(), + "char_array_assign$deref", + "char_array_assign$deref", + location, + ID_java, + symbol_table); + symbol_exprt lhs_deref=sym_lhs_deref.symbol_expr(); + assignments.emplace_back(lhs_deref, deref_array); + + // array=convert_pointer_to_char_array(*rhs->data) + declare_function(ID_cprover_string_array_of_char_pointer_func, content_type); + function_application_exprt fun_app(symbol_exprt( + ID_cprover_string_array_of_char_pointer_func), content_type); + fun_app.arguments().push_back(deref_array); + symbol_exprt array=fresh_array(content_type, location); + assignments.emplace_back(array, fun_app); + + // string={ rhs->length; string_array } + string_exprt new_rhs(get_length(deref, length_type), array, ref_type); + symbol_exprt lhs=fresh_string(ref_type, location); + assignments.emplace_back(lhs, new_rhs); + + insert_assignments( + goto_program, target, target->function, location, assignments); + target=goto_program.insert_after(target); + return new_rhs; +} + +/*******************************************************************\ + Function: string_refine_preprocesst::make_normal_assign Inputs: a goto_program, a position in this program, an expression lhs, @@ -336,27 +489,19 @@ void string_refine_preprocesst::make_normal_assign( const source_locationt &location, const std::string &signature) { - if(function_name==ID_cprover_string_copy_func) - { - assert(!arguments.empty()); - make_string_copy(goto_program, target, lhs, arguments[0], location); - } - else - { - function_application_exprt rhs( - symbol_exprt(function_name), function_type.return_type()); - rhs.add_source_location()=location; - declare_function(function_name, function_type); + function_application_exprt rhs( + symbol_exprt(function_name), function_type.return_type()); + rhs.add_source_location()=location; + declare_function(function_name, function_type); - exprt::operandst processed_arguments=process_arguments( - goto_program, target, arguments, location, signature); - rhs.arguments()=processed_arguments; + exprt::operandst processed_arguments=process_arguments( + goto_program, target, arguments, location, signature); + rhs.arguments()=processed_arguments; - code_assignt assignment(lhs, rhs); - assignment.add_source_location()=location; - target->make_assignment(); - target->code=assignment; - } + code_assignt assignment(lhs, rhs); + assignment.add_source_location()=location; + target->make_assignment(); + target->code=assignment; } /*******************************************************************\ @@ -420,7 +565,7 @@ void string_refine_preprocesst::make_string_assign( const source_locationt &location, const std::string &signature) { - assert(is_java_string_pointer_type(function_type.return_type())); + assert(implements_java_char_sequence(function_type.return_type())); dereference_exprt deref(lhs, lhs.type().subtype()); typet object_type=ns.follow(deref.type()); exprt object_size=size_of_expr(object_type, ns); @@ -454,98 +599,22 @@ void string_refine_preprocesst::make_string_assign( malloc_expr.type()=pointer_typet(object_type); malloc_expr.add_source_location()=location; + refined_string_typet ref_type(length_type, data_type.subtype().subtype()); + string_exprt str(tmp_length, tmp_array, ref_type); + symbol_exprt cprover_string_sym=fresh_string(ref_type, location); + std::list assigns; assigns.emplace_back(lhs, malloc_expr); assigns.emplace_back(tmp_length, rhs_length); assigns.emplace_back(lhs_length, tmp_length); assigns.emplace_back(tmp_array, rhs_data); + assigns.emplace_back(cprover_string_sym, str); assigns.emplace_back(lhs_data, address_of_exprt(tmp_array)); insert_assignments(goto_program, target, target->function, location, assigns); } /*******************************************************************\ -Function: string_refine_preprocesst::make_assign - - Inputs: a goto_program, a position in this program, an expression lhs, - a function type, a function name, a vector of arguments, a location - and a signature - - Purpose: assign the result of the function application to lhs, - in case the function type is string, it does a special assignment - using `make_string_assign` - -\*******************************************************************/ - -void string_refine_preprocesst::make_assign( - goto_programt &goto_program, - goto_programt::targett &target, - const exprt &lhs, - const code_typet &function_type, - const irep_idt &function_name, - const exprt::operandst &arg, - const source_locationt &loc, - const std::string &sig) -{ - if(is_java_string_pointer_type(function_type.return_type())) - make_string_assign( - goto_program, target, lhs, function_type, function_name, arg, loc, sig); - else - make_normal_assign( - goto_program, target, lhs, function_type, function_name, arg, loc, sig); -} - -/*******************************************************************\ - -Function: string_refine_preprocesst::make_string_copy - - Inputs: a goto_program, a position in this program, a lhs expression, - an argument expression and a location - - Outputs: an expression - - Purpose: replace the current instruction by: - > lhs->length=argument->length - > tmp_data=*(argument->data) - > lhs->data=&tmp_data - -\*******************************************************************/ - -void string_refine_preprocesst::make_string_copy( - goto_programt &goto_program, - goto_programt::targett &target, - const exprt &lhs, - const exprt &argument, - const source_locationt &location) -{ - // TODO : treat CharSequence and StringBuffer - assert(is_java_string_pointer_type(lhs.type()) || - is_java_string_builder_pointer_type(lhs.type())); - exprt deref=dereference_exprt(lhs, lhs.type().subtype()); - - typet length_type, data_type; - get_data_and_length_type_of_string(deref, data_type, length_type); - - dereference_exprt deref_arg(argument, argument.type().subtype()); - std::list assignments; - - exprt lhs_length=get_length(deref, length_type); - exprt rhs_length=get_length(deref_arg, length_type); - assignments.emplace_back(lhs_length, rhs_length); - - symbol_exprt tmp_data=fresh_array(data_type.subtype(), location); - exprt rhs_data=get_data(deref_arg, data_type); - exprt lhs_data=get_data(deref, data_type); - assignments.emplace_back( - tmp_data, dereference_exprt(rhs_data, data_type.subtype())); - assignments.emplace_back(lhs_data, address_of_exprt(tmp_data)); - - insert_assignments( - goto_program, target, target->function, location, assignments); -} - -/*******************************************************************\ - Function: string_refine_preprocesst::make_string_function Inputs: a position in a goto program, a function name, an expression lhs, @@ -566,7 +635,36 @@ void string_refine_preprocesst::make_string_function( const source_locationt &location, const std::string &signature) { - if(is_java_string_pointer_type(function_type.return_type())) + if(signature.length()>0) + { + if(signature.back()=='S') + { + code_typet ft=function_type; + ft.return_type()=jls_ptr; + typecast_exprt lhs2(lhs, jls_ptr); + + make_string_assign( + goto_program, + target, + lhs2, + ft, + function_name, + arguments, + location, + signature); + } + else + make_normal_assign( + goto_program, + target, + lhs, + function_type, + function_name, + arguments, + location, + signature); + } + else if(implements_java_char_sequence(function_type.return_type())) make_string_assign( goto_program, target, @@ -597,9 +695,11 @@ Function: string_refine_preprocesst::make_string_function Purpose: at the current position replace `lhs=s.some_function(x,...)` by `lhs=function_name(s,x,...)`; option `assign_first_arg` uses `s` instead of `lhs` in the resulting - expression; + expression, Warning : it assumes that `s` is string-like option `skip_first_arg`, removes `s` from the arguments, ie `x` is - the first one + the first one; + arguments that are string (TODO: and char array) are replaced + by string_exprt \*******************************************************************/ @@ -635,11 +735,17 @@ void string_refine_preprocesst::make_string_function( new_type.parameters().push_back(function_type.parameters()[i]); } + std::string new_sig=signature; exprt lhs; if(assign_first_arg) { assert(!function_call.arguments().empty()); lhs=function_call.arguments()[0]; + std::size_t size=function_call.arguments().size(); + if(signature.length()<=size) + new_sig.resize(size+1, '_'); + + new_sig.replace(size, 1, "S"); } else lhs=function_call.lhs(); @@ -650,7 +756,7 @@ void string_refine_preprocesst::make_string_function( new_type.return_type()=lhs.type(); make_string_function( - goto_program, target, lhs, new_type, function_name, args, loc, signature); + goto_program, target, lhs, new_type, function_name, args, loc, new_sig); } /*******************************************************************\ @@ -680,9 +786,11 @@ Function: string_refine_preprocesst::make_string_function_side_effect Inputs: a position in a goto program and a function name - Purpose: at the current position, replace `r=s.some_function(x,...)` - by `s=function_name(s,x,...)` and add a correspondance from r - to s in the `string_builders` map + Purpose: at the current position, replace `r=s.some_function(x,...)` by + > tmp=function_name(x,...) + > s->data=tmp.data + > s->length=tmp.length + > r=s \*******************************************************************/ @@ -692,11 +800,48 @@ void string_refine_preprocesst::make_string_function_side_effect( const irep_idt &function_name, const std::string &signature) { - const code_function_callt function_call=to_code_function_call(target->code); - assert(!function_call.arguments().empty()); - string_builders[function_call.lhs()]=function_call.arguments()[0]; - make_string_function( - goto_program, target, function_name, signature, true, false); + code_function_callt function_call=to_code_function_call(target->code); + source_locationt loc=function_call.source_location(); + std::list assignments; + exprt lhs=function_call.lhs(); + exprt s=function_call.arguments()[0]; + code_typet function_type=to_code_type(function_call.type()); + + function_type.return_type()=s.type(); + + if(lhs.is_not_nil()) + { + symbol_exprt tmp_string=fresh_string(lhs.type(), loc); + + make_string_assign( + goto_program, + target, + tmp_string, + function_type, + function_name, + function_call.arguments(), + loc, + signature); + dereference_exprt deref_lhs(s, s.type().subtype()); + typet data_type, length_type; + get_data_and_length_type_of_string(deref_lhs, data_type, length_type); + member_exprt lhs_data(deref_lhs, "data", data_type); + member_exprt lhs_length(deref_lhs, "length", length_type); + dereference_exprt deref_rhs(tmp_string, s.type().subtype()); + member_exprt rhs_data(deref_rhs, "data", data_type); + member_exprt rhs_length(deref_rhs, "length", length_type); + assignments.emplace_back(lhs_length, rhs_length); + assignments.emplace_back(lhs_data, rhs_data); + assignments.emplace_back(lhs, s); + target=goto_program.insert_after(target); + insert_assignments( + goto_program, target, target->function, loc, assignments); + } + else + { + make_string_function( + goto_program, target, function_name, signature, true, false); + } } /*******************************************************************\ @@ -735,6 +880,7 @@ Function: string_refine_preprocesst::make_to_char_array_function Inputs: a goto program and a position in that goto program Purpose: at the given position replace `return_tmp0=s.toCharArray()` with: + > return_tmp0 = malloc(array[char]); > return_tmp0->data=&((s->data)[0]) > return_tmp0->length=s->length @@ -744,16 +890,36 @@ void string_refine_preprocesst::make_to_char_array_function( goto_programt &goto_program, goto_programt::targett &target) { const code_function_callt &function_call=to_code_function_call(target->code); + source_locationt location=function_call.source_location(); - assert(!function_call.arguments().empty()); + assert(function_call.arguments().size()>=1); const exprt &string_argument=function_call.arguments()[0]; assert(is_java_string_pointer_type(string_argument.type())); + typet deref_type=function_call.lhs().type().subtype(); + const exprt &lhs=function_call.lhs(); + dereference_exprt deref_lhs(lhs, deref_type); + dereference_exprt deref(string_argument, string_argument.type().subtype()); typet length_type, data_type; get_data_and_length_type_of_string(deref, data_type, length_type); std::list assignments; + // lhs=malloc(array[char]) + typet object_type=ns.follow(deref_type); + exprt object_size=size_of_expr(object_type, ns); + + if(object_size.is_nil()) + debug() << "string_refine_preprocesst::make_to_char_array_function " + << "got nil object_size" << eom; + + side_effect_exprt malloc_expr(ID_malloc); + malloc_expr.copy_to_operands(object_size); + malloc_expr.type()=pointer_typet(object_type); + malloc_expr.add_source_location()=location; + assignments.emplace_back(lhs, malloc_expr); + + // &((s->data)[0]) exprt rhs_data=get_data(deref, data_type); dereference_exprt rhs_array(rhs_data, data_type.subtype()); @@ -762,8 +928,6 @@ void string_refine_preprocesst::make_to_char_array_function( address_of_exprt rhs_pointer(first_element); // return_tmp0->data=&((s->data)[0]) - typet deref_type=function_call.lhs().type().subtype(); - dereference_exprt deref_lhs(function_call.lhs(), deref_type); exprt lhs_data=get_data(deref_lhs, data_type); assignments.emplace_back(lhs_data, rhs_pointer); @@ -771,178 +935,8 @@ void string_refine_preprocesst::make_to_char_array_function( exprt rhs_length=get_length(deref, length_type); exprt lhs_length=get_length(deref_lhs, length_type); assignments.emplace_back(lhs_length, rhs_length); - source_locationt location=target->source_location; - insert_assignments( - goto_program, target, target->function, location, assignments); -} - -/*******************************************************************\ - -Function: string_refine_preprocesst::make_cprover_char_array_assign - - Inputs: a goto_program, a position in this program, an expression and a - location - - Outputs: a char array expression (not a pointer) - - Purpose: Introduce a temporary variable for cprover strings; - returns the cprover_string corresponding to rhs - -\*******************************************************************/ - -exprt string_refine_preprocesst::make_cprover_char_array_assign( - goto_programt &goto_program, - goto_programt::targett &target, - const exprt &rhs, - const source_locationt &location) -{ - // TODO : add an assertion on the type of rhs - - // We do the following assignments: - // cprover_string_array = rhs.data - // cprover_string = { rhs.length; cprover_string_array } - - // string expression for the rhs of the second assignment - string_exprt new_rhs(java_char_type()); - - typet data_type=new_rhs.content().type(); - typet length_type=java_int_type(); - - symbol_exprt array_lhs=fresh_array(data_type, location); - exprt array_rhs=get_data(rhs, new_rhs.content().type()); - symbol_exprt lhs=fresh_string(new_rhs.type(), location); - new_rhs.length()=get_length(rhs, length_type); - new_rhs.content()=array_lhs; - - std::list assignments; - assignments.emplace_back(array_lhs, array_rhs); - assignments.emplace_back(lhs, new_rhs); insert_assignments( goto_program, target, target->function, location, assignments); - target=goto_program.insert_after(target); - return lhs; -} - -/*******************************************************************\ - -Function: string_refine_preprocesst::make_char_array_function - - Inputs: a position in a goto program, a function name, two Boolean options, - and the index of the char array argument in the function - - Purpose: at the given position replace - `lhs=s.some_function(...,char_array,...)` by - > cprover_string = { char_array->length, *char_array } - > tmp_string=function_name(s, cprover_string, ...) - option `assign_first_arg` uses `s` instead of `lhs` in the second - assignment; - option `skip_first_arg`, removes `s` from the arguments, ie `x` is - the first one; - argument index gives the index of the argument containing char_array - -\*******************************************************************/ - -void string_refine_preprocesst::make_char_array_function( - goto_programt &goto_program, - goto_programt::targett &target, - const irep_idt &function_name, - const std::string &signature, - std::size_t index, - bool assign_first_arg, - bool skip_first_arg) -{ - code_function_callt &function_call=to_code_function_call(target->code); - code_typet function_type=to_code_type(function_call.function().type()); - code_typet new_function_type; - const source_locationt &location=function_call.source_location(); - assert(!function_call.arguments().size()>index); - const std::vector &args=function_call.arguments(); - std::vector new_args; - - exprt lhs; - if(assign_first_arg) - { - assert(!function_call.arguments().empty()); - lhs=function_call.arguments()[0]; - else - lhs=function_call.lhs(); - - if(lhs.id()==ID_typecast) - lhs=to_typecast_expr(lhs).op(); - - exprt char_array=dereference_exprt( - function_call.arguments()[index], - function_call.arguments()[index].type().subtype()); - exprt string=make_cprover_char_array_assign( - goto_program, target, char_array, location); - - std::size_t start_index=skip_first_arg?1:0; - for(std::size_t i=start_index; icode); - assert(!function_call.arguments().empty()); - string_builders[function_call.lhs()]=function_call.arguments()[0]; } /*******************************************************************\ @@ -974,22 +968,20 @@ exprt::operandst string_refine_preprocesst::process_arguments( for(std::size_t i=0; isecond); - else + if(iis_function_call()) { code_function_callt &function_call=to_code_function_call(target->code); - for(auto &arg : function_call.arguments()) - { - auto sb_it=string_builders.find(arg); - if(sb_it!=string_builders.end()) - arg=sb_it->second; - } if(function_call.function().id()==ID_symbol) { @@ -1070,21 +1056,6 @@ void string_refine_preprocesst::replace_string_calls( make_string_function_call( goto_program, target, it->second, signature); - it=string_of_char_array_functions.find(function_id); - if(it!=string_of_char_array_functions.end()) - make_char_array_function( - goto_program, target, it->second, signature, 0); - - it=string_of_char_array_function_calls.find(function_id); - if(it!=string_of_char_array_function_calls.end()) - make_char_array_function_call( - goto_program, target, it->second, signature); - - it=side_effect_char_array_functions.find(function_id); - if(it!=side_effect_char_array_functions.end()) - make_char_array_side_effect( - goto_program, target, it->second, signature); - if(function_id==irep_idt("java::java.lang.String.toCharArray:()[C")) make_to_char_array_function(goto_program, target); } @@ -1299,12 +1270,18 @@ void string_refine_preprocesst::initialize_string_function_table() ID_cprover_string_set_length_func; - side_effect_char_array_functions + + side_effect_functions + ["java::java.lang.StringBuilder.append:([C)" + "Ljava/lang/StringBuilder;"]= + ID_cprover_string_concat_func; + side_effect_functions ["java::java.lang.StringBuilder.insert:(I[CII)Ljava/lang/StringBuilder;"]= - ID_cprover_string_insert_char_array_func; - side_effect_char_array_functions + ID_cprover_string_insert_func; + side_effect_functions ["java::java.lang.StringBuilder.insert:(I[C)Ljava/lang/StringBuilder;"]= - ID_cprover_string_insert_char_array_func; + ID_cprover_string_insert_func; + // TODO clean irep ids from insert_char_array etc... string_function_calls ["java::java.lang.String.:(Ljava/lang/String;)V"]= @@ -1320,23 +1297,23 @@ void string_refine_preprocesst::initialize_string_function_table() string_function_calls["java::java.lang.StringBuilder.:()V"]= ID_cprover_string_empty_string_func; - string_of_char_array_function_calls["java::java.lang.String.:([C)V"]= - ID_cprover_string_of_char_array_func; - string_of_char_array_function_calls["java::java.lang.String.:([CII)V"]= - ID_cprover_string_of_char_array_func; + string_function_calls["java::java.lang.String.:([C)V"]= + ID_cprover_string_copy_func; + string_function_calls["java::java.lang.String.:([CII)V"]= + ID_cprover_string_copy_func; - string_of_char_array_functions + string_functions ["java::java.lang.String.valueOf:([CII)Ljava/lang/String;"]= - ID_cprover_string_of_char_array_func; - string_of_char_array_functions + ID_cprover_string_copy_func; + string_functions ["java::java.lang.String.valueOf:([C)Ljava/lang/String;"]= - ID_cprover_string_of_char_array_func; - string_of_char_array_functions + ID_cprover_string_copy_func; + string_functions ["java::java.lang.String.copyValueOf:([CII)Ljava/lang/String;"]= - ID_cprover_string_of_char_array_func; - string_of_char_array_functions + ID_cprover_string_copy_func; + string_functions ["java::java.lang.String.copyValueOf:([C)Ljava/lang/String;"]= - ID_cprover_string_of_char_array_func; + ID_cprover_string_copy_func; c_string_functions["__CPROVER_uninterpreted_string_literal_func"]= ID_cprover_string_literal_func; @@ -1370,9 +1347,23 @@ void string_refine_preprocesst::initialize_string_function_table() ID_cprover_string_of_int_func; signatures["java::java.lang.String.equals:(Ljava/lang/Object;)Z"]="SSZ"; - signatures - ["java::java.lang.String.contains:(Ljava/lang/CharSequence;)Z"]= - "SSZ"; + signatures["java::java.lang.String.contains:(Ljava/lang/CharSequence;)Z"]= + "SSZ"; + signatures["java::java.lang.StringBuilder.insert:(IZ)" + "Ljava/lang/StringBuilder;"]="SIZS"; + signatures["java::java.lang.StringBuilder.insert:(IJ)" + "Ljava/lang/StringBuilder;"]="SIJS"; + signatures["java::java.lang.StringBuilder.insert:(II)" + "Ljava/lang/StringBuilder;"]="SIIS"; + signatures["java::java.lang.StringBuilder.insert:(IC)" + "Ljava/lang/StringBuilder;"]="SICS"; + signatures["java::java.lang.StringBuilder.insert:(ILjava/lang/String;)" + "Ljava/lang/StringBuilder;"]="SISS"; + signatures["java::java.lang.StringBuilder.insert:(ILjava/lang/String;)" + "Ljava/lang/StringBuilder;"]="SISS"; + signatures["java::java.lang.StringBuilder.insert:(I[C)" + "Ljava/lang/StringBuilder;"]="SI[S"; + signatures["java::java.lang.String.intern:()Ljava/lang/String;"]="SV"; } /*******************************************************************\ diff --git a/src/goto-programs/string_refine_preprocess.h b/src/goto-programs/string_refine_preprocess.h index 613d0161926..5ae398b757a 100644 --- a/src/goto-programs/string_refine_preprocess.h +++ b/src/goto-programs/string_refine_preprocess.h @@ -14,6 +14,7 @@ Date: September 2016 #include #include +#include class string_refine_preprocesst:public messaget { @@ -29,28 +30,21 @@ class string_refine_preprocesst:public messaget typedef std::unordered_map id_mapt; typedef std::unordered_map expr_mapt; - // String builders maps the different names of a same StringBuilder object - // to a unique expression. - expr_mapt string_builders; - // Map name of Java string functions to there equivalent in the solver id_mapt side_effect_functions; id_mapt string_functions; id_mapt c_string_functions; id_mapt string_function_calls; - id_mapt string_of_char_array_functions; - id_mapt string_of_char_array_function_calls; - id_mapt side_effect_char_array_functions; std::unordered_map signatures; - expr_mapt hidden_strings; - expr_mapt java_to_cprover_strings; // unique id for each newly created symbols int next_symbol_id; void initialize_string_function_table(); + static bool check_java_type(const typet &type, const std::string &tag); + static bool is_java_string_pointer_type(const typet &type); static bool is_java_string_type(const typet &type); @@ -61,6 +55,20 @@ class string_refine_preprocesst:public messaget static bool is_java_char_sequence_type(const typet &type); + static bool is_java_char_sequence_pointer_type(const typet &type); + + static bool is_java_char_array_type(const typet &type); + + static bool is_java_char_array_pointer_type(const typet &type); + + static bool implements_java_char_sequence(const typet &type) + { + return + is_java_char_sequence_pointer_type(type) || + is_java_string_builder_pointer_type(type) || + is_java_string_pointer_type(type); + } + symbol_exprt fresh_array( const typet &type, const source_locationt &location); symbol_exprt fresh_string( @@ -110,6 +118,9 @@ class string_refine_preprocesst:public messaget void get_data_and_length_type_of_string( const exprt &expr, typet &data_type, typet &length_type); + void get_data_and_length_type_of_char_array( + const exprt &expr, typet &data_type, typet &length_type); + function_application_exprt build_function_application( const irep_idt &function_name, const typet &type, @@ -136,27 +147,16 @@ class string_refine_preprocesst:public messaget const source_locationt &location, const std::string &signature); - void make_assign( - goto_programt &goto_program, - goto_programt::targett &target, - const exprt &lhs, - const code_typet &function_type, - const irep_idt &function_name, - const exprt::operandst &arg, - const source_locationt &loc, - const std::string &sig); - exprt make_cprover_string_assign( goto_programt &goto_program, goto_programt::targett &target, const exprt &rhs, const source_locationt &location); - void make_string_copy( + string_exprt make_cprover_char_array_assign( goto_programt &goto_program, goto_programt::targett &target, - const exprt &lhs, - const exprt &argument, + const exprt &rhs, const source_locationt &location); void make_string_function( @@ -192,33 +192,6 @@ class string_refine_preprocesst:public messaget void make_to_char_array_function( goto_programt &goto_program, goto_programt::targett &); - exprt make_cprover_char_array_assign( - goto_programt &goto_program, - goto_programt::targett &target, - const exprt &rhs, - const source_locationt &location); - - void make_char_array_function( - goto_programt &goto_program, - goto_programt::targett &target, - const irep_idt &function_name, - const std::string &signature, - std::size_t index, - bool assign_first_arg=false, - bool skip_first_arg=false); - - void make_char_array_function_call( - goto_programt &goto_program, - goto_programt::targett &target, - const irep_idt &function_name, - const std::string &signature); - - void make_char_array_side_effect( - goto_programt &goto_program, - goto_programt::targett &target, - const irep_idt &function_name, - const std::string &signature); - void replace_string_calls(goto_functionst::function_mapt::iterator f_it); }; From 433daf40ad429ac1776f22ee5830bbc395a4cdec Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Tue, 28 Feb 2017 13:50:25 +0000 Subject: [PATCH 26/52] Many corrections in string refinement Overhaul of string solver contributions The code adding lemmas to the solver for each equality has been completely remastered. It has been simplified and should now cover all foreseable cases. Add overflow constraints on sums for string solver When creating sum expressions during string refinement, e.g. when adding string lengths, we shall add axioms to prevent the solver from finding values that actually come from an integer overflow. Therefore, we introduce a new method plus_exprt_with_overflow_check() that wraps around plus_exprt and generates the relevant axioms. Cache function applications Cache converted function applications to avoid re-generating the axioms if it has already been done for a given function application. This seems to happen for function applications that are in an assertion, and thus are treated separately by convert_bitvector. Remove string_refinement::convert_symbol: the behaviour of this function was to convert java strings to strings of symbols. In hindsight, this was not a good idea, as we still refer to the actual java string fields in some cases, e.g. to read its length. Replace add_axioms_for_string_expr In all add_axioms_... methods, we replace all calls to add_axioms_for_string_expr by the newly created function get_string_expr, which simply returns a string_exprt when we give it an refined expr (such as a string_exprt or a symbol). Update doc in add_axioms_for_index_string Simplify constraint for is_prefix: apply distribution law and update (and refactor) documentation. Remove set_string_symbol_equal_to_expr() Removed mentions of java string type in the string solver Removing mentions of is_c_string_type To use the string solver in C, we should use a struct type with tag __CPROVER_refined_string_type Keep non-string axioms in a list Instead of giving axioms to super::boolbv_set_equality_to_true, which may contain un-substituted symbols, we keep them in a list and substitute them in dec_solve() before giving them to the function. Cleaning the add_axioms_for_string_expr method and renamed it to add_axioms_for_refined_string to signify that it should only be called on expression of type refined string. An assertion was added at the beginning to ensure that. Better get_array and string_of_array functions. Cleaned the implementation of get_array and factorized part of it. Made string_of_array directly take a array_exprt, which can be obtained from get_array. Improved string_of_array for non printable characters Resolve symbol to char arrays in non-string axioms. We introduce a mapping that expresses the maximal traversal of symbols of char array type. We use that map to, either obtain a char array from a symbol, either get a unique symbol the aliases equivalence class. This map is used to replace all symbols of char array type in the axioms that are added using the parent method: supert::boolbv_set_equality_to_true. Defining several intermediary functions for check_axioms and cleaning. Check axioms is quite complicated so we splitted it in several parts. Avoid using same universal variable name in string comparison function. Corrected test in index_of as characters could be signed Corrected return type retrieval in from_float functions. The return type should be given as argument of the helper function add_axioms_from_float. Fixed type of contains in constraint generation Introduce string_refinementt::set_to. We now override the set_to() method instead of set_equality_to_true(). This solves a problem where many lemmas were being dropped. Handle array_of in set_char_array_equality. Java assignments such as char[] str=new char[10] involves assigning the char array to 0, which is done using the array_of operator. This operator is now handled when found on the rhs of a char array assignment. Optimized string hash code and intern functions to only look at seen strings. We only compare the argument to the strings on which hash_code (resp. intern) was already called. Add missing override keyword in declarations Integrate strings into symbol resolution. We now use for strings the mechanism that was made for resolving symbols to char arrays. As a result, the symbol_to_string map has been removed. We introduce an unresolved_symbol map to associate symbols to string expressions that were introduced during constraint generation. Preventing return of nil exprt in sum_over_map Enforce -1 for witnesses when strings are unequal. This makes it easier to see when models for string have different length. Correct array index in get_array Correct a bad array access that caused a segmentation fault on the java_delete test. Adding option to concretize result and get method in string solver The option to concretize makes sure that the model that we get in the end is correct. Overiding the get method is necessary to get the actual valuation of string gotten by the solver. This two additions makes the trace generation for program with strings more likely to be actual traces of the program. Avoid adding axioms for copy Corrected `get` to not replace strings Simplifying lemmas before handing them to the solver This seems to improve performances Ignoring char array that are not symbol or constants Avoid creating new length variable for concat Adding constraint on positive length for refined strings Using get method of the parent class for the size Add function to fill the found_length map Signature for get_array should be constant Corrected overflow problem when integer get to the max size Removing overflow check in universal constraint Enforcing witness -1 when length is not sufficient in suffix Corrected index variable which should be universally quantified Factorizing addition to index set and more debug information Avoiding generating a fresh string for the empty string Enabling string solver to treat more cases and more debug infos Conversion from char pointer to array in the solver Raise a warning if found length is negative Ensure the arguments of parseInt are of the right format For now we add axioms asking for the argument to have the right format but ultimately we should raise an exception when it is not the case (which is not done right now). Corrects the specification of int to string conversion Some problems where encountered for strings with the maximal size possible for an int, which could cause an overflow. Disallow + sign in string from int Java will not add the sign for positive numbers Use get instead of current_model in check_axioms Streamline code of check_axioms() by calling get() insteand of relying on the 'current_model' variable. get() has been adapted to convert array-lists into with expressions, the former not being handled by the string solver. --- src/solvers/refinement/string_constraint.h | 1 - .../refinement/string_constraint_generator.h | 45 +- ...tring_constraint_generator_code_points.cpp | 18 +- ...string_constraint_generator_comparison.cpp | 104 +- .../string_constraint_generator_concat.cpp | 31 +- .../string_constraint_generator_constants.cpp | 9 +- .../string_constraint_generator_indexof.cpp | 27 +- .../string_constraint_generator_insert.cpp | 24 +- .../string_constraint_generator_main.cpp | 428 +++++--- .../string_constraint_generator_testing.cpp | 46 +- ...ng_constraint_generator_transformation.cpp | 39 +- .../string_constraint_generator_valueof.cpp | 106 +- src/solvers/refinement/string_refinement.cpp | 992 ++++++++++++++---- src/solvers/refinement/string_refinement.h | 66 +- 14 files changed, 1413 insertions(+), 523 deletions(-) diff --git a/src/solvers/refinement/string_constraint.h b/src/solvers/refinement/string_constraint.h index aa5e50ba018..c83d63cc69a 100644 --- a/src/solvers/refinement/string_constraint.h +++ b/src/solvers/refinement/string_constraint.h @@ -55,7 +55,6 @@ class string_constraintt: public exprt return operands()[4]; } - private: string_constraintt(); diff --git a/src/solvers/refinement/string_constraint_generator.h b/src/solvers/refinement/string_constraint_generator.h index 4f2f72039b9..85758ba3864 100644 --- a/src/solvers/refinement/string_constraint_generator.h +++ b/src/solvers/refinement/string_constraint_generator.h @@ -21,6 +21,7 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com #define CPROVER_SOLVERS_REFINEMENT_STRING_CONSTRAINT_GENERATOR_H #include +#include #include #include @@ -72,21 +73,20 @@ class string_constraint_generatort symbol_exprt fresh_univ_index(const irep_idt &prefix, const typet &type); symbol_exprt fresh_boolean(const irep_idt &prefix); string_exprt fresh_string(const refined_string_typet &type); + string_exprt get_string_expr(const exprt &expr); + string_exprt convert_java_string_to_string_exprt( + const exprt &underlying); + plus_exprt plus_exprt_with_overflow_check(const exprt &op1, const exprt &op2); - // We maintain a map from symbols to strings. - std::map symbol_to_string; + // Maps unresolved symbols to the string_exprt that was created for them + std::map unresolved_symbols; - string_exprt find_or_add_string_of_symbol(const symbol_exprt &sym); - void assign_to_symbol( - const symbol_exprt &sym, const string_exprt &expr) - { - symbol_to_string[sym.get_identifier()]=expr; - } + string_exprt find_or_add_string_of_symbol( + const symbol_exprt &sym, + const refined_string_typet &ref_type); - string_exprt add_axioms_for_string_expr(const exprt &expr); - void set_string_symbol_equal_to_expr( - const symbol_exprt &sym, const exprt &str); + string_exprt add_axioms_for_refined_string(const exprt &expr); exprt add_axioms_for_function_application( const function_application_exprt &expr); @@ -103,6 +103,8 @@ class string_constraint_generatort const std::size_t MAX_FLOAT_LENGTH=15; const std::size_t MAX_DOUBLE_LENGTH=30; + std::map function_application_cache; + static irep_idt extract_java_string(const symbol_exprt &s); exprt axiom_for_is_positive_index(const exprt &x); @@ -124,6 +126,9 @@ class string_constraint_generatort // The specification is partial: the actual value is not actually computed // but we ensure that hash codes of equal strings are equal. exprt add_axioms_for_hash_code(const function_application_exprt &f); + // To each string on which hash_code was called we associate a symbol + // representing the return value of the hash_code function. + std::map hash_code_of_string; exprt add_axioms_for_is_empty(const function_application_exprt &f); exprt add_axioms_for_is_prefix( @@ -231,7 +236,9 @@ class string_constraint_generatort // the start for negative number string_exprt add_axioms_from_float(const function_application_exprt &f); string_exprt add_axioms_from_float( - const exprt &f, bool double_precision=false); + const exprt &f, + const refined_string_typet &ref_type, + bool double_precision); // Add axioms corresponding to the String.valueOf(D) java function // TODO: the specifications is only partial @@ -260,6 +267,7 @@ class string_constraint_generatort string_exprt add_axioms_for_code_point( const exprt &code_point, const refined_string_typet &ref_type); string_exprt add_axioms_for_java_char_array(const exprt &char_array); + exprt add_axioms_for_char_pointer(const function_application_exprt &fun); string_exprt add_axioms_for_if(const if_exprt &expr); exprt add_axioms_for_char_literal(const function_application_exprt &f); @@ -277,6 +285,8 @@ class string_constraint_generatort const function_application_exprt &f); exprt add_axioms_for_parse_int(const function_application_exprt &f); + exprt add_axioms_for_correct_number_format( + const string_exprt &str, std::size_t max_size=10); exprt add_axioms_for_to_char_array(const function_application_exprt &f); exprt add_axioms_for_compare_to(const function_application_exprt &f); @@ -285,6 +295,9 @@ class string_constraint_generatort // string pointers symbol_exprt add_axioms_for_intern(const function_application_exprt &f); + // Pool used for the intern method + std::map intern_of_string; + // Tells which language is used. C and Java are supported irep_idt mode; @@ -300,14 +313,8 @@ class string_constraint_generatort exprt int_of_hex_char(const exprt &chr) const; exprt is_high_surrogate(const exprt &chr) const; exprt is_low_surrogate(const exprt &chr) const; - static exprt character_equals_ignore_case( + exprt character_equals_ignore_case( exprt char1, exprt char2, exprt char_a, exprt char_A, exprt char_Z); - - // Pool used for the intern method - std::map pool; - - // Used to determine whether hashcode should be equal - std::map hash; }; #endif diff --git a/src/solvers/refinement/string_constraint_generator_code_points.cpp b/src/solvers/refinement/string_constraint_generator_code_points.cpp index 6bf8e035ad5..ad44469d51e 100644 --- a/src/solvers/refinement/string_constraint_generator_code_points.cpp +++ b/src/solvers/refinement/string_constraint_generator_code_points.cpp @@ -127,17 +127,18 @@ exprt string_constraint_generatort::add_axioms_for_code_point_at( { typet return_type=f.type(); assert(return_type.id()==ID_signedbv); - string_exprt str=add_axioms_for_string_expr(args(f, 2)[0]); + string_exprt str=get_string_expr(args(f, 2)[0]); const exprt &pos=args(f, 2)[1]; symbol_exprt result=fresh_symbol("char", return_type); exprt index1=from_integer(1, str.length().type()); const exprt &char1=str[pos]; - const exprt &char2=str[plus_exprt(pos, index1)]; + const exprt &char2=str[plus_exprt_with_overflow_check(pos, index1)]; exprt char1_as_int=typecast_exprt(char1, return_type); exprt char2_as_int=typecast_exprt(char2, return_type); exprt pair=pair_value(char1_as_int, char2_as_int, return_type); - exprt is_low=is_low_surrogate(str[plus_exprt(pos, index1)]); + exprt is_low=is_low_surrogate( + str[plus_exprt_with_overflow_check(pos, index1)]); exprt return_pair=and_exprt(is_high_surrogate(str[pos]), is_low); axioms.push_back(implies_exprt(return_pair, equal_exprt(result, pair))); @@ -158,7 +159,7 @@ exprt string_constraint_generatort::add_axioms_for_code_point_before( typet return_type=f.type(); assert(return_type.id()==ID_signedbv); symbol_exprt result=fresh_symbol("char", return_type); - string_exprt str=add_axioms_for_string_expr(args[0]); + string_exprt str=get_string_expr(args[0]); const exprt &char1= str[minus_exprt(args[1], from_integer(2, str.length().type()))]; @@ -185,7 +186,7 @@ exprt string_constraint_generatort::add_axioms_for_code_point_before( exprt string_constraint_generatort::add_axioms_for_code_point_count( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 3)[0]); + string_exprt str=get_string_expr(args(f, 3)[0]); const exprt &begin=args(f, 3)[1]; const exprt &end=args(f, 3)[2]; const typet &return_type=f.type(); @@ -207,14 +208,15 @@ exprt string_constraint_generatort::add_axioms_for_code_point_count( exprt string_constraint_generatort::add_axioms_for_offset_by_code_point( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 3)[0]); + string_exprt str=get_string_expr(args(f, 3)[0]); const exprt &index=args(f, 3)[1]; const exprt &offset=args(f, 3)[2]; const typet &return_type=f.type(); symbol_exprt result=fresh_symbol("offset_by_code_point", return_type); - exprt minimum=plus_exprt(index, offset); - exprt maximum=plus_exprt(index, plus_exprt(offset, offset)); + exprt minimum=plus_exprt_with_overflow_check(index, offset); + exprt maximum=plus_exprt_with_overflow_check( + index, plus_exprt_with_overflow_check(offset, offset)); axioms.push_back(binary_relation_exprt(result, ID_le, maximum)); axioms.push_back(binary_relation_exprt(result, ID_ge, minimum)); diff --git a/src/solvers/refinement/string_constraint_generator_comparison.cpp b/src/solvers/refinement/string_constraint_generator_comparison.cpp index fbb64c55d68..c6ec1f20d79 100644 --- a/src/solvers/refinement/string_constraint_generator_comparison.cpp +++ b/src/solvers/refinement/string_constraint_generator_comparison.cpp @@ -13,8 +13,10 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com #include -/// add axioms stating that the result is true exactly when the strings -/// represented by the arguments are equal +/// Add axioms stating that the result is true exactly when the strings +/// represented by the arguments are equal. the variable ending in +/// `witness_unequal` is -1 if the length differs or an index at +/// which the strings are different /// \par parameters: function application with two string arguments /// \return a expression of Boolean type exprt string_constraint_generatort::add_axioms_for_equals( @@ -24,8 +26,8 @@ exprt string_constraint_generatort::add_axioms_for_equals( symbol_exprt eq=fresh_boolean("equal"); typecast_exprt tc_eq(eq, f.type()); - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); - string_exprt s2=add_axioms_for_string_expr(args(f, 2)[1]); + string_exprt s1=get_string_expr(args(f, 2)[0]); + string_exprt s2=get_string_expr(args(f, 2)[1]); typet index_type=s1.length().type(); // We want to write: @@ -49,9 +51,10 @@ exprt string_constraint_generatort::add_axioms_for_equals( binary_relation_exprt(witness, ID_lt, s1.length()), binary_relation_exprt(witness, ID_ge, zero)); and_exprt witnessing(bound_witness, notequal_exprt(s1[witness], s2[witness])); - implies_exprt a3( - not_exprt(eq), - or_exprt(notequal_exprt(s1.length(), s2.length()), witnessing)); + and_exprt diff_length( + notequal_exprt(s1.length(), s2.length()), + equal_exprt(witness, from_integer(-1, index_type))); + implies_exprt a3(not_exprt(eq), or_exprt(diff_length, witnessing)); axioms.push_back(a3); return tc_eq; @@ -79,8 +82,13 @@ exprt string_constraint_generatort::character_equals_ignore_case( // p3 : (is_up2&&'a'-'A'+char2=char1) equal_exprt p1(char1, char2); minus_exprt diff=minus_exprt(char_a, char_A); - and_exprt p2(is_upper_case_1, equal_exprt(plus_exprt(diff, char1), char2)); - and_exprt p3(is_upper_case_2, equal_exprt(plus_exprt(diff, char2), char1)); + + // Overflow is not a problem here because is_upper_case conditions + // ensure that we are within a safe range. + and_exprt p2(is_upper_case_1, + equal_exprt(plus_exprt(diff, char1), char2)); + and_exprt p3(is_upper_case_2, + equal_exprt(plus_exprt(diff, char2), char1)); return or_exprt(or_exprt(p1, p2), p3); } @@ -94,8 +102,8 @@ exprt string_constraint_generatort::add_axioms_for_equals_ignore_case( symbol_exprt eq=fresh_boolean("equal_ignore_case"); typecast_exprt tc_eq(eq, f.type()); - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); - string_exprt s2=add_axioms_for_string_expr(args(f, 2)[1]); + string_exprt s1=get_string_expr(args(f, 2)[0]); + string_exprt s2=get_string_expr(args(f, 2)[1]); typet char_type=to_refined_string_type(s1.type()).get_char_type(); exprt char_a=constant_char('a', char_type); exprt char_A=constant_char('A', char_type); @@ -143,37 +151,35 @@ exprt string_constraint_generatort::add_axioms_for_equals_ignore_case( exprt string_constraint_generatort::add_axioms_for_hash_code( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 1)[0]); + string_exprt str=get_string_expr(args(f, 1)[0]); typet return_type=f.type(); typet index_type=str.length().type(); - // initialisation of the missing pool variable - std::map::iterator it; - for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++) - if(hash.find(it->second)==hash.end()) - hash[it->second]=fresh_symbol("hash", return_type); + auto pair=hash_code_of_string.insert( + std::make_pair(str, fresh_symbol("hash", return_type))); + exprt hash=pair.first->second; // for each string s. either: // c1: hash(str)=hash(s) // c2: |str|!=|s| - // c3: (|str|==|s| &&exists i<|s|. s[i]!=str[i]) + // c3: (|str|==|s| && exists i<|s|. s[i]!=str[i]) // WARNING: the specification may be incomplete - for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++) + for(auto it : hash_code_of_string) { symbol_exprt i=fresh_exist_index("index_hash", index_type); - equal_exprt c1(hash[it->second], hash[str]); - not_exprt c2(equal_exprt(it->second.length(), str.length())); + equal_exprt c1(it.second, hash); + not_exprt c2(equal_exprt(it.first.length(), str.length())); and_exprt c3( - equal_exprt(it->second.length(), str.length()), + equal_exprt(it.first.length(), str.length()), and_exprt( - not_exprt(equal_exprt(str[i], it->second[i])), + not_exprt(equal_exprt(str[i], it.first[i])), and_exprt( str.axiom_for_is_strictly_longer_than(i), axiom_for_is_positive_index(i)))); axioms.push_back(or_exprt(c1, or_exprt(c2, c3))); } - return hash[str]; + return hash; } /// add axioms corresponding to the String.compareTo java function @@ -182,8 +188,8 @@ exprt string_constraint_generatort::add_axioms_for_hash_code( exprt string_constraint_generatort::add_axioms_for_compare_to( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); - string_exprt s2=add_axioms_for_string_expr(args(f, 2)[1]); + string_exprt s1=get_string_expr(args(f, 2)[0]); + string_exprt s2=get_string_expr(args(f, 2)[1]); const typet &return_type=f.type(); symbol_exprt res=fresh_symbol("compare_to", return_type); typet index_type=s1.length().type(); @@ -194,12 +200,12 @@ exprt string_constraint_generatort::add_axioms_for_compare_to( // a1 : res==0 => |s1|=|s2| // a2 : forall i<|s1|. s1[i]==s2[i] // a3 : exists x. - // res!=0 ==> x> 0 && - // ((|s1| <= |s2| &&x<|s1|) || (|s1| >= |s2| &&x<|s2|) - // &&res=s1[x]-s2[x] ) - // || cond2: - // (|s1|<|s2| &&x=|s1|) || (|s1| > |s2| &&x=|s2|) &&res=|s1|-|s2|) - // a4 : forall i s1[i]=s2[i] + // res!=0 ==> x > 0 + // && ((|s1| <= |s2| && x<|s1|) || (|s1| >= |s2| &&x<|s2|) + // && res=s1[x]-s2[x] ) + // || cond2: + // (|s1|<|s2| &&x=|s1|) || (|s1| > |s2| &&x=|s2|) &&res=|s1|-|s2|) + // a4 : forall i' s1[i]=s2[i] assert(return_type.id()==ID_signedbv); @@ -242,7 +248,9 @@ exprt string_constraint_generatort::add_axioms_for_compare_to( or_exprt(cond1, cond2))); axioms.push_back(a3); - string_constraintt a4(i, x, not_exprt(res_null), equal_exprt(s1[i], s2[i])); + symbol_exprt i2=fresh_univ_index("QA_compare_to", index_type); + string_constraintt a4( + i2, x, not_exprt(res_null), equal_exprt(s1[i2], s2[i2])); axioms.push_back(a4); return res; @@ -255,15 +263,15 @@ exprt string_constraint_generatort::add_axioms_for_compare_to( symbol_exprt string_constraint_generatort::add_axioms_for_intern( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 1)[0]); + string_exprt str=get_string_expr(args(f, 1)[0]); + // For now we only enforce content equality and not pointer equality const typet &return_type=f.type(); + typet index_type=str.length().type(); - // initialisation of the missing pool variable - std::map::iterator it; - for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++) - if(pool.find(it->second)==pool.end()) - pool[it->second]=fresh_symbol("pool", return_type); + auto pair=intern_of_string.insert( + std::make_pair(str, fresh_symbol("pool", return_type))); + symbol_exprt intern=pair.first->second; // intern(str)=s_0 || s_1 || ... // for each string s. @@ -271,30 +279,30 @@ symbol_exprt string_constraint_generatort::add_axioms_for_intern( // || (|str|==|s| &&exists i<|s|. s[i]!=str[i]) exprt disj=false_exprt(); - for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++) + for(auto it : intern_of_string) disj=or_exprt( - disj, equal_exprt(pool[str], symbol_exprt(it->first, return_type))); + disj, equal_exprt(intern, it.second)); axioms.push_back(disj); // WARNING: the specification may be incomplete or incorrect - for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++) - if(it->second!=str) + for(auto it : intern_of_string) + if(it.second!=str) { symbol_exprt i=fresh_exist_index("index_intern", index_type); axioms.push_back( or_exprt( - equal_exprt(pool[it->second], pool[str]), + equal_exprt(it.second, intern), or_exprt( - not_exprt(str.axiom_for_has_same_length_as(it->second)), + not_exprt(str.axiom_for_has_same_length_as(it.first)), and_exprt( - str.axiom_for_has_same_length_as(it->second), + str.axiom_for_has_same_length_as(it.first), and_exprt( - not_exprt(equal_exprt(str[i], it->second[i])), + not_exprt(equal_exprt(str[i], it.first[i])), and_exprt(str.axiom_for_is_strictly_longer_than(i), axiom_for_is_positive_index(i))))))); } - return pool[str]; + return intern; } diff --git a/src/solvers/refinement/string_constraint_generator_concat.cpp b/src/solvers/refinement/string_constraint_generator_concat.cpp index 4d0a5b47151..b4d33f1ba57 100644 --- a/src/solvers/refinement/string_constraint_generator_concat.cpp +++ b/src/solvers/refinement/string_constraint_generator_concat.cpp @@ -30,9 +30,7 @@ string_exprt string_constraint_generatort::add_axioms_for_concat( // a4 : forall i<|s1|. res[i]=s1[i] // a5 : forall i<|s2|. res[i+|s1|]=s2[i] - exprt a1=res.axiom_for_has_length( - plus_exprt(s1.length(), s2.length())); - axioms.push_back(a1); + res.length()=plus_exprt_with_overflow_check(s1.length(), s2.length()); axioms.push_back(s1.axiom_for_is_shorter_than(res)); axioms.push_back(s2.axiom_for_is_shorter_than(res)); @@ -58,8 +56,8 @@ string_exprt string_constraint_generatort::add_axioms_for_concat( const function_application_exprt::argumentst &args=f.arguments(); assert(args.size()==2); - string_exprt s1=add_axioms_for_string_expr(args[0]); - string_exprt s2=add_axioms_for_string_expr(args[1]); + string_exprt s1=get_string_expr(args[0]); + string_exprt s2=get_string_expr(args[1]); return add_axioms_for_concat(s1, s2); } @@ -72,7 +70,7 @@ string_exprt string_constraint_generatort::add_axioms_for_concat_int( const function_application_exprt &f) { const refined_string_typet &ref_type=to_refined_string_type(f.type()); - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); + string_exprt s1=get_string_expr(args(f, 2)[0]); string_exprt s2=add_axioms_from_int( args(f, 2)[1], MAX_INTEGER_LENGTH, ref_type); return add_axioms_for_concat(s1, s2); @@ -86,7 +84,7 @@ string_exprt string_constraint_generatort::add_axioms_for_concat_long( const function_application_exprt &f) { const refined_string_typet &ref_type=to_refined_string_type(f.type()); - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); + string_exprt s1=get_string_expr(args(f, 2)[0]); string_exprt s2=add_axioms_from_int(args(f, 2)[1], MAX_LONG_LENGTH, ref_type); return add_axioms_for_concat(s1, s2); } @@ -97,7 +95,7 @@ string_exprt string_constraint_generatort::add_axioms_for_concat_long( string_exprt string_constraint_generatort::add_axioms_for_concat_bool( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); + string_exprt s1=get_string_expr(args(f, 2)[0]); const refined_string_typet &ref_type=to_refined_string_type(s1.type()); string_exprt s2=add_axioms_from_bool(args(f, 2)[1], ref_type); return add_axioms_for_concat(s1, s2); @@ -110,7 +108,7 @@ string_exprt string_constraint_generatort::add_axioms_for_concat_bool( string_exprt string_constraint_generatort::add_axioms_for_concat_char( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); + string_exprt s1=get_string_expr(args(f, 2)[0]); const refined_string_typet &ref_type=to_refined_string_type(s1.type()); string_exprt s2=add_axioms_from_char(args(f, 2)[1], ref_type); return add_axioms_for_concat(s1, s2); @@ -123,9 +121,10 @@ string_exprt string_constraint_generatort::add_axioms_for_concat_char( string_exprt string_constraint_generatort::add_axioms_for_concat_double( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); - string_exprt s2=add_axioms_from_float( - args(f, 2)[1], MAX_DOUBLE_LENGTH); + string_exprt s1=get_string_expr(args(f, 2)[0]); + assert(refined_string_typet::is_refined_string_type(f.type())); + refined_string_typet ref_type=to_refined_string_type(f.type()); + string_exprt s2=add_axioms_from_float(args(f, 2)[1], ref_type, true); return add_axioms_for_concat(s1, s2); } @@ -136,8 +135,10 @@ string_exprt string_constraint_generatort::add_axioms_for_concat_double( string_exprt string_constraint_generatort::add_axioms_for_concat_float( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); - string_exprt s2=add_axioms_from_float(args(f, 2)[1], MAX_FLOAT_LENGTH); + string_exprt s1=get_string_expr(args(f, 2)[0]); + assert(refined_string_typet::is_refined_string_type(f.type())); + refined_string_typet ref_type=to_refined_string_type(f.type()); + string_exprt s2=add_axioms_from_float(args(f, 2)[1], ref_type, false); return add_axioms_for_concat(s1, s2); } @@ -148,7 +149,7 @@ string_exprt string_constraint_generatort::add_axioms_for_concat_float( string_exprt string_constraint_generatort::add_axioms_for_concat_code_point( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); + string_exprt s1=get_string_expr(args(f, 2)[0]); const refined_string_typet &ref_type=to_refined_string_type(s1.type()); string_exprt s2=add_axioms_for_code_point(args(f, 2)[1], ref_type); return add_axioms_for_concat(s1, s2); diff --git a/src/solvers/refinement/string_constraint_generator_constants.cpp b/src/solvers/refinement/string_constraint_generator_constants.cpp index 8ee5d8c3427..c5fb56658fb 100644 --- a/src/solvers/refinement/string_constraint_generator_constants.cpp +++ b/src/solvers/refinement/string_constraint_generator_constants.cpp @@ -69,9 +69,13 @@ string_exprt string_constraint_generatort::add_axioms_for_empty_string( const function_application_exprt &f) { assert(f.arguments().empty()); + assert(refined_string_typet::is_refined_string_type(f.type())); const refined_string_typet &ref_type=to_refined_string_type(f.type()); - string_exprt res=fresh_string(ref_type); - axioms.push_back(res.axiom_for_has_length(0)); + exprt size=from_integer(0, ref_type.get_index_type()); + const array_typet &content_type=ref_type.get_content_type(); + array_of_exprt empty_array( + from_integer(0, ref_type.get_content_type().subtype()), content_type); + string_exprt res(size, empty_array, ref_type); return res; } @@ -100,6 +104,7 @@ string_exprt string_constraint_generatort::add_axioms_from_literal( else { // Java string constant + assert(false); // TODO: Check if used. On the contrary, discard else. assert(arg.id()==ID_symbol); const exprt &s=arg.op0(); diff --git a/src/solvers/refinement/string_constraint_generator_indexof.cpp b/src/solvers/refinement/string_constraint_generator_indexof.cpp index 67ee7ad7b1c..59b7395188d 100644 --- a/src/solvers/refinement/string_constraint_generator_indexof.cpp +++ b/src/solvers/refinement/string_constraint_generator_indexof.cpp @@ -79,15 +79,16 @@ exprt string_constraint_generatort::add_axioms_for_index_of_string( symbol_exprt contains=fresh_boolean("contains_substring"); // We add axioms: - // a1 : contains => |substring|>=offset>=from_index + // a1 : contains => |str|-|substring|>=offset>=from_index // a2 : !contains => offset=-1 - // a3 : forall 0 <= witness str[witness+offset]=substring[witness] + // a3 : forall 0<=witness<|substring|. + // contains => str[witness+offset]=substring[witness] implies_exprt a1( contains, and_exprt( - str.axiom_for_is_longer_than(plus_exprt(substring.length(), offset)), + str.axiom_for_is_longer_than(plus_exprt_with_overflow_check( + substring.length(), offset)), binary_relation_exprt(offset, ID_ge, from_index))); axioms.push_back(a1); @@ -125,7 +126,8 @@ exprt string_constraint_generatort::add_axioms_for_last_index_of_string( implies_exprt a1( contains, and_exprt( - str.axiom_for_is_longer_than(plus_exprt(substring.length(), offset)), + str.axiom_for_is_longer_than( + plus_exprt_with_overflow_check(substring.length(), offset)), binary_relation_exprt(offset, ID_le, from_index))); axioms.push_back(a1); @@ -150,7 +152,7 @@ exprt string_constraint_generatort::add_axioms_for_index_of( const function_application_exprt &f) { const function_application_exprt::argumentst &args=f.arguments(); - string_exprt str=add_axioms_for_string_expr(args[0]); + string_exprt str=get_string_expr(args[0]); const exprt &c=args[1]; const refined_string_typet &ref_type=to_refined_string_type(str.type()); assert(f.type()==ref_type.get_index_type()); @@ -163,14 +165,15 @@ exprt string_constraint_generatort::add_axioms_for_index_of( else assert(false); - if(c.type().id()==ID_unsignedbv) + if(c.type().id()==ID_unsignedbv || c.type().id()==ID_signedbv) { return add_axioms_for_index_of( str, typecast_exprt(c, ref_type.get_char_type()), from_index); } else { - string_exprt sub=add_axioms_for_string_expr(c); + assert(refined_string_typet::is_refined_string_type(c.type())); + string_exprt sub=get_string_expr(c); return add_axioms_for_index_of_string(str, sub, from_index); } } @@ -192,7 +195,7 @@ exprt string_constraint_generatort::add_axioms_for_last_index_of( exprt index1=from_integer(1, index_type); exprt minus1=from_integer(-1, index_type); - exprt from_index_plus_one=plus_exprt(from_index, index1); + exprt from_index_plus_one=plus_exprt_with_overflow_check(from_index, index1); and_exprt a1( binary_relation_exprt(index, ID_ge, minus1), binary_relation_exprt(index, ID_lt, from_index_plus_one)); @@ -237,7 +240,7 @@ exprt string_constraint_generatort::add_axioms_for_last_index_of( const function_application_exprt &f) { const function_application_exprt::argumentst &args=f.arguments(); - string_exprt str=add_axioms_for_string_expr(args[0]); + string_exprt str=get_string_expr(args[0]); exprt c=args[1]; const refined_string_typet &ref_type=to_refined_string_type(str.type()); exprt from_index; @@ -250,14 +253,14 @@ exprt string_constraint_generatort::add_axioms_for_last_index_of( else assert(false); - if(c.type().id()==ID_unsignedbv) + if(c.type().id()==ID_unsignedbv || c.type().id()==ID_signedbv) { return add_axioms_for_last_index_of( str, typecast_exprt(c, ref_type.get_char_type()), from_index); } else { - string_exprt sub=add_axioms_for_string_expr(c); + string_exprt sub=get_string_expr(c); return add_axioms_for_last_index_of_string(str, sub, from_index); } } diff --git a/src/solvers/refinement/string_constraint_generator_insert.cpp b/src/solvers/refinement/string_constraint_generator_insert.cpp index f757317121e..89045e52d8f 100644 --- a/src/solvers/refinement/string_constraint_generator_insert.cpp +++ b/src/solvers/refinement/string_constraint_generator_insert.cpp @@ -33,8 +33,8 @@ string_exprt string_constraint_generatort::add_axioms_for_insert( string_exprt string_constraint_generatort::add_axioms_for_insert( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 3)[0]); - string_exprt s2=add_axioms_for_string_expr(args(f, 3)[2]); + string_exprt s1=get_string_expr(args(f, 3)[0]); + string_exprt s2=get_string_expr(args(f, 3)[2]); return add_axioms_for_insert(s1, s2, args(f, 3)[1]); } @@ -47,7 +47,7 @@ string_exprt string_constraint_generatort::add_axioms_for_insert_int( const function_application_exprt &f) { const refined_string_typet &ref_type=to_refined_string_type(f.type()); - string_exprt s1=add_axioms_for_string_expr(args(f, 3)[0]); + string_exprt s1=get_string_expr(args(f, 3)[0]); string_exprt s2=add_axioms_from_int( args(f, 3)[2], MAX_INTEGER_LENGTH, ref_type); return add_axioms_for_insert(s1, s2, args(f, 3)[1]); @@ -62,7 +62,7 @@ string_exprt string_constraint_generatort::add_axioms_for_insert_long( const function_application_exprt &f) { const refined_string_typet &ref_type=to_refined_string_type(f.type()); - string_exprt s1=add_axioms_for_string_expr(args(f, 3)[0]); + string_exprt s1=get_string_expr(args(f, 3)[0]); string_exprt s2=add_axioms_from_int(args(f, 3)[2], MAX_LONG_LENGTH, ref_type); return add_axioms_for_insert(s1, s2, args(f, 3)[1]); } @@ -76,7 +76,7 @@ string_exprt string_constraint_generatort::add_axioms_for_insert_bool( const function_application_exprt &f) { const refined_string_typet &ref_type=to_refined_string_type(f.type()); - string_exprt s1=add_axioms_for_string_expr(args(f, 3)[0]); + string_exprt s1=get_string_expr(args(f, 3)[0]); string_exprt s2=add_axioms_from_bool(args(f, 3)[2], ref_type); return add_axioms_for_insert(s1, s2, args(f, 3)[1]); } @@ -89,7 +89,7 @@ string_exprt string_constraint_generatort::add_axioms_for_insert_bool( string_exprt string_constraint_generatort::add_axioms_for_insert_char( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 3)[0]); + string_exprt s1=get_string_expr(args(f, 3)[0]); const refined_string_typet &ref_type=to_refined_string_type(s1.type()); string_exprt s2=add_axioms_from_char(args(f, 3)[2], ref_type); return add_axioms_for_insert(s1, s2, args(f, 3)[1]); @@ -103,8 +103,9 @@ string_exprt string_constraint_generatort::add_axioms_for_insert_char( string_exprt string_constraint_generatort::add_axioms_for_insert_double( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 3)[0]); - string_exprt s2=add_axioms_from_float(args(f, 3)[2]); + string_exprt s1=get_string_expr(args(f, 3)[0]); + const refined_string_typet &ref_type=to_refined_string_type(s1.type()); + string_exprt s2=add_axioms_from_float(args(f, 3)[2], ref_type, true); return add_axioms_for_insert(s1, s2, args(f, 3)[1]); } @@ -116,8 +117,9 @@ string_exprt string_constraint_generatort::add_axioms_for_insert_double( string_exprt string_constraint_generatort::add_axioms_for_insert_float( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 3)[0]); - string_exprt s2=add_axioms_from_float(args(f, 3)[2]); + string_exprt s1=get_string_expr(args(f, 3)[0]); + const refined_string_typet &ref_type=to_refined_string_type(s1.type()); + string_exprt s2=add_axioms_from_float(args(f, 3)[2], ref_type, false); return add_axioms_for_insert(s1, s2, args(f, 3)[1]); } @@ -145,7 +147,7 @@ string_exprt string_constraint_generatort::add_axioms_for_insert_char_array( offset=from_integer(0, count.type()); } - string_exprt str=add_axioms_for_string_expr(f.arguments()[0]); + string_exprt str=get_string_expr(f.arguments()[0]); const exprt &length=f.arguments()[2]; const exprt &data=f.arguments()[3]; string_exprt arr=add_axioms_from_char_array( diff --git a/src/solvers/refinement/string_constraint_generator_main.cpp b/src/solvers/refinement/string_constraint_generator_main.cpp index 13390ee877c..0b87b9471a1 100644 --- a/src/solvers/refinement/string_constraint_generator_main.cpp +++ b/src/solvers/refinement/string_constraint_generator_main.cpp @@ -23,6 +23,7 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com #include #include #include +#include unsigned string_constraint_generatort::next_symbol_id=1; @@ -82,9 +83,47 @@ symbol_exprt string_constraint_generatort::fresh_boolean( return b; } -/// construct a string expression whose length and content are new variables -/// \par parameters: a type for string -/// \return a string expression +/// Create a plus expression while adding extra constraints to +/// axioms in order to prevent overflows. +/// \par op1: First term of the sum +/// \par op2: Second term of the sum +/// \return A plus expression representing the sum of the arguments +plus_exprt string_constraint_generatort::plus_exprt_with_overflow_check( + const exprt &op1, const exprt &op2) +{ + plus_exprt sum(plus_exprt(op1, op2)); + + exprt zero=from_integer(0, op1.type()); + + binary_relation_exprt neg1(op1, ID_lt, zero); + binary_relation_exprt neg2(op2, ID_lt, zero); + binary_relation_exprt neg_sum(sum, ID_lt, zero); + + // We prevent overflows by adding the following constraint: + // If the signs of the two operands are the same, then the sign of the sum + // should also be the same. + implies_exprt no_overflow(equal_exprt(neg1, neg2), + equal_exprt(neg1, neg_sum)); + + axioms.push_back(no_overflow); + + return sum; +} + +/*******************************************************************\ + +Function: string_constraint_generatort::fresh_string + + Inputs: a type for string + + Outputs: a string expression + + Purpose: construct a string expression whose length and content are new + variables + +\*******************************************************************/ + +>>>>>>> bdbeaf586... Many corrections in string refinement string_exprt string_constraint_generatort::fresh_string( const refined_string_typet &type) { @@ -94,52 +133,107 @@ string_exprt string_constraint_generatort::fresh_string( return string_exprt(length, content, type); } -/// obtain a refined string expression corresponding to string variable of -/// string function call -/// \par parameters: an expression of type string -/// \return a string expression that is linked to the argument through axioms -/// that are added to the list -string_exprt string_constraint_generatort::add_axioms_for_string_expr( - const exprt &unrefined_string) +/// casts an expression to a string expression, or fetches the actual +/// string_exprt in the case of a symbol. +/// \par parameters: an expression of refined string type +/// \return a string expression +string_exprt string_constraint_generatort::get_string_expr(const exprt &expr) { - string_exprt s; + assert(refined_string_typet::is_refined_string_type(expr.type())); + + if(expr.id()==ID_symbol) + { + return find_or_add_string_of_symbol( + to_symbol_expr(expr), + to_refined_string_type(expr.type())); + } + else + { + return to_string_expr(expr); + } +} - if(unrefined_string.id()==ID_function_application) +string_exprt string_constraint_generatort::convert_java_string_to_string_exprt( + const exprt &jls) +{ + assert(get_mode()==ID_java); + assert(jls.id()==ID_struct); + + exprt length(to_struct_expr(jls).op1()); + // TODO: Add assertion on the type. + // assert(length.type()==refined_string_typet::index_type()); + exprt java_content(to_struct_expr(jls).op2()); + if(java_content.id()==ID_address_of) { - exprt res=add_axioms_for_function_application( - to_function_application_expr(unrefined_string)); - s=to_string_expr(res); + java_content=to_address_of_expr(java_content).object(); } - else if(unrefined_string.id()==ID_symbol) - s=find_or_add_string_of_symbol(to_symbol_expr(unrefined_string)); - else if(unrefined_string.id()==ID_address_of) + else { - assert(unrefined_string.op0().id()==ID_symbol); - s=find_or_add_string_of_symbol(to_symbol_expr(unrefined_string.op0())); + java_content=dereference_exprt(java_content, java_content.type()); } - else if(unrefined_string.id()==ID_if) - s=add_axioms_for_if(to_if_expr(unrefined_string)); - else if(unrefined_string.id()==ID_nondet_symbol || - unrefined_string.id()==ID_struct) + + refined_string_typet type(java_int_type(), java_char_type()); + + return string_exprt(length, java_content, type); +} + +/*******************************************************************\ + +Function: string_constraint_generatort::add_axioms_for_refined_string + + Inputs: an expression of refined string type + + Outputs: a string expression that is linked to the argument through + axioms that are added to the list + + Purpose: obtain a refined string expression corresponding to a expression + of type string + +\*******************************************************************/ + + +string_exprt string_constraint_generatort::add_axioms_for_refined_string( + const exprt &string) +>>>>>>> bdbeaf586... Many corrections in string refinement +{ + assert(refined_string_typet::is_refined_string_type(string.type())); + refined_string_typet type=to_refined_string_type(string.type()); + + // Function applications should have been removed before + assert(string.id()!=ID_function_application); + + if(string.id()==ID_symbol) { - // TODO: for now we ignore non deterministic symbols and struct + const symbol_exprt &sym=to_symbol_expr(string); + string_exprt s=find_or_add_string_of_symbol(sym, type); + axioms.push_back( + s.axiom_for_is_longer_than(from_integer(0, s.length().type()))); + return s; } - else if(unrefined_string.id()==ID_typecast) + else if(string.id()==ID_nondet_symbol) { - exprt arg=to_typecast_expr(unrefined_string).op(); - exprt res=add_axioms_for_string_expr(arg); - s=to_string_expr(res); + string_exprt s=fresh_string(type); + axioms.push_back( + s.axiom_for_is_longer_than(from_integer(0, s.length().type()))); + return s; + } + else if(string.id()==ID_if) + { + return add_axioms_for_if(to_if_expr(string)); + } + else if(string.id()==ID_struct) + { + const string_exprt &s=to_string_expr(string); + axioms.push_back( + s.axiom_for_is_longer_than(from_integer(0, s.length().type()))); + return s; } else { - throw "add_axioms_for_string_expr:\n"+unrefined_string.pretty()+ + throw "add_axioms_for_refined_string:\n"+string.pretty()+ "\nwhich is not a function application, "+ - "a symbol or an if expression"; + "a symbol, a struct or an if expression"; } - - axioms.push_back( - s.axiom_for_is_longer_than(from_integer(0, s.length().type()))); - return s; } /// add axioms for an if expression which should return a string @@ -150,10 +244,10 @@ string_exprt string_constraint_generatort::add_axioms_for_if( { assert( refined_string_typet::is_refined_string_type(expr.true_case().type())); - string_exprt t=add_axioms_for_string_expr(expr.true_case()); + string_exprt t=get_string_expr(expr.true_case()); assert( refined_string_typet::is_refined_string_type(expr.false_case().type())); - string_exprt f=add_axioms_for_string_expr(expr.false_case()); + string_exprt f=get_string_expr(expr.false_case()); const refined_string_typet &ref_type=to_refined_string_type(t.type()); const typet &index_type=ref_type.get_index_type(); string_exprt res=fresh_string(ref_type); @@ -179,12 +273,11 @@ string_exprt string_constraint_generatort::add_axioms_for_if( /// \par parameters: a symbol expression /// \return a string expression string_exprt string_constraint_generatort::find_or_add_string_of_symbol( - const symbol_exprt &sym) + const symbol_exprt &sym, const refined_string_typet &ref_type) { irep_idt id=sym.get_identifier(); - const refined_string_typet &ref_type=to_refined_string_type(sym.type()); string_exprt str=fresh_string(ref_type); - auto entry=symbol_to_string.insert(std::make_pair(id, str)); + auto entry=unresolved_symbols.insert(std::make_pair(id, str)); return entry.first->second; } @@ -202,125 +295,180 @@ exprt string_constraint_generatort::add_axioms_for_function_application( const irep_idt &id=is_ssa_expr(name)?to_ssa_expr(name).get_object_name(): to_symbol_expr(name).get_identifier(); + std::string str_id(id.c_str()); + + size_t pos=str_id.find("func_length"); + if(pos!=std::string::npos) + { + function_application_exprt new_expr(expr); + // TODO: This part needs some improvement. + // Stripping the symbol name is not a very robust process. + new_expr.function() = symbol_exprt(str_id.substr(0, pos+4)); + assert(get_mode()==ID_java); + new_expr.type() = refined_string_typet(java_int_type(), java_char_type()); + + auto res_it=function_application_cache.insert(std::make_pair(new_expr, + nil_exprt())); + if(res_it.second) + { + string_exprt res=to_string_expr( + add_axioms_for_function_application(new_expr)); + res_it.first->second=res; + return res.length(); + } + else + return to_string_expr(res_it.first->second).length(); + } + + pos = str_id.find("func_data"); + if(pos!=std::string::npos) + { + function_application_exprt new_expr(expr); + new_expr.function() = symbol_exprt(str_id.substr(0, pos+4)); + new_expr.type() = refined_string_typet(java_int_type(), java_char_type()); + + auto res_it=function_application_cache.insert(std::make_pair(new_expr, + nil_exprt())); + if(res_it.second) + { + string_exprt res=to_string_expr( + add_axioms_for_function_application(new_expr)); + res_it.first->second=res; + return res.content(); + } + else + return to_string_expr(res_it.first->second).content(); + } + // TODO: improve efficiency of this test by either ordering test by frequency // or using a map + auto res_it=function_application_cache.find(expr); + if(res_it!=function_application_cache.end() && res_it->second!=nil_exprt()) + return res_it->second; + + exprt res; + if(id==ID_cprover_char_literal_func) - return add_axioms_for_char_literal(expr); + res=add_axioms_for_char_literal(expr); else if(id==ID_cprover_string_length_func) - return add_axioms_for_length(expr); + res=add_axioms_for_length(expr); else if(id==ID_cprover_string_equal_func) - return add_axioms_for_equals(expr); + res=add_axioms_for_equals(expr); else if(id==ID_cprover_string_equals_ignore_case_func) - return add_axioms_for_equals_ignore_case(expr); + res=add_axioms_for_equals_ignore_case(expr); else if(id==ID_cprover_string_is_empty_func) - return add_axioms_for_is_empty(expr); + res=add_axioms_for_is_empty(expr); else if(id==ID_cprover_string_char_at_func) - return add_axioms_for_char_at(expr); + res=add_axioms_for_char_at(expr); else if(id==ID_cprover_string_is_prefix_func) - return add_axioms_for_is_prefix(expr); + res=add_axioms_for_is_prefix(expr); else if(id==ID_cprover_string_is_suffix_func) - return add_axioms_for_is_suffix(expr); + res=add_axioms_for_is_suffix(expr); else if(id==ID_cprover_string_startswith_func) - return add_axioms_for_is_prefix(expr, true); + res=add_axioms_for_is_prefix(expr, true); else if(id==ID_cprover_string_endswith_func) - return add_axioms_for_is_suffix(expr, true); + res=add_axioms_for_is_suffix(expr, true); else if(id==ID_cprover_string_contains_func) - return add_axioms_for_contains(expr); + res=add_axioms_for_contains(expr); else if(id==ID_cprover_string_hash_code_func) - return add_axioms_for_hash_code(expr); + res=add_axioms_for_hash_code(expr); else if(id==ID_cprover_string_index_of_func) - return add_axioms_for_index_of(expr); + res=add_axioms_for_index_of(expr); else if(id==ID_cprover_string_last_index_of_func) - return add_axioms_for_last_index_of(expr); + res=add_axioms_for_last_index_of(expr); else if(id==ID_cprover_string_parse_int_func) - return add_axioms_for_parse_int(expr); + res=add_axioms_for_parse_int(expr); else if(id==ID_cprover_string_to_char_array_func) - return add_axioms_for_to_char_array(expr); + res=add_axioms_for_to_char_array(expr); else if(id==ID_cprover_string_code_point_at_func) - return add_axioms_for_code_point_at(expr); + res=add_axioms_for_code_point_at(expr); else if(id==ID_cprover_string_code_point_before_func) - return add_axioms_for_code_point_before(expr); + res=add_axioms_for_code_point_before(expr); else if(id==ID_cprover_string_code_point_count_func) - return add_axioms_for_code_point_count(expr); + res=add_axioms_for_code_point_count(expr); else if(id==ID_cprover_string_offset_by_code_point_func) - return add_axioms_for_offset_by_code_point(expr); + res=add_axioms_for_offset_by_code_point(expr); else if(id==ID_cprover_string_compare_to_func) - return add_axioms_for_compare_to(expr); + res=add_axioms_for_compare_to(expr); else if(id==ID_cprover_string_literal_func) - return add_axioms_from_literal(expr); + res=add_axioms_from_literal(expr); else if(id==ID_cprover_string_concat_func) - return add_axioms_for_concat(expr); + res=add_axioms_for_concat(expr); else if(id==ID_cprover_string_concat_int_func) - return add_axioms_for_concat_int(expr); + res=add_axioms_for_concat_int(expr); else if(id==ID_cprover_string_concat_long_func) - return add_axioms_for_concat_long(expr); + res=add_axioms_for_concat_long(expr); else if(id==ID_cprover_string_concat_bool_func) - return add_axioms_for_concat_bool(expr); + res=add_axioms_for_concat_bool(expr); else if(id==ID_cprover_string_concat_char_func) - return add_axioms_for_concat_char(expr); + res=add_axioms_for_concat_char(expr); else if(id==ID_cprover_string_concat_double_func) - return add_axioms_for_concat_double(expr); + res=add_axioms_for_concat_double(expr); else if(id==ID_cprover_string_concat_float_func) - return add_axioms_for_concat_float(expr); + res=add_axioms_for_concat_float(expr); else if(id==ID_cprover_string_concat_code_point_func) - return add_axioms_for_concat_code_point(expr); + res=add_axioms_for_concat_code_point(expr); else if(id==ID_cprover_string_insert_func) - return add_axioms_for_insert(expr); + res=add_axioms_for_insert(expr); else if(id==ID_cprover_string_insert_int_func) - return add_axioms_for_insert_int(expr); + res=add_axioms_for_insert_int(expr); else if(id==ID_cprover_string_insert_long_func) - return add_axioms_for_insert_long(expr); + res=add_axioms_for_insert_long(expr); else if(id==ID_cprover_string_insert_bool_func) - return add_axioms_for_insert_bool(expr); + res=add_axioms_for_insert_bool(expr); else if(id==ID_cprover_string_insert_char_func) - return add_axioms_for_insert_char(expr); + res=add_axioms_for_insert_char(expr); else if(id==ID_cprover_string_insert_double_func) - return add_axioms_for_insert_double(expr); + res=add_axioms_for_insert_double(expr); else if(id==ID_cprover_string_insert_float_func) - return add_axioms_for_insert_float(expr); + res=add_axioms_for_insert_float(expr); +#if 0 else if(id==ID_cprover_string_insert_char_array_func) - return add_axioms_for_insert_char_array(expr); + res=add_axioms_for_insert_char_array(expr); +#endif else if(id==ID_cprover_string_substring_func) - return add_axioms_for_substring(expr); + res=add_axioms_for_substring(expr); else if(id==ID_cprover_string_trim_func) - return add_axioms_for_trim(expr); + res=add_axioms_for_trim(expr); else if(id==ID_cprover_string_to_lower_case_func) - return add_axioms_for_to_lower_case(expr); + res=add_axioms_for_to_lower_case(expr); else if(id==ID_cprover_string_to_upper_case_func) - return add_axioms_for_to_upper_case(expr); + res=add_axioms_for_to_upper_case(expr); else if(id==ID_cprover_string_char_set_func) - return add_axioms_for_char_set(expr); + res=add_axioms_for_char_set(expr); else if(id==ID_cprover_string_value_of_func) - return add_axioms_for_value_of(expr); + res=add_axioms_for_value_of(expr); else if(id==ID_cprover_string_empty_string_func) - return add_axioms_for_empty_string(expr); + res=add_axioms_for_empty_string(expr); else if(id==ID_cprover_string_copy_func) - return add_axioms_for_copy(expr); + res=add_axioms_for_copy(expr); else if(id==ID_cprover_string_of_int_func) - return add_axioms_from_int(expr); + res=add_axioms_from_int(expr); else if(id==ID_cprover_string_of_int_hex_func) - return add_axioms_from_int_hex(expr); + res=add_axioms_from_int_hex(expr); else if(id==ID_cprover_string_of_float_func) - return add_axioms_from_float(expr); + res=add_axioms_from_float(expr); else if(id==ID_cprover_string_of_double_func) - return add_axioms_from_double(expr); + res=add_axioms_from_double(expr); else if(id==ID_cprover_string_of_long_func) - return add_axioms_from_long(expr); + res=add_axioms_from_long(expr); else if(id==ID_cprover_string_of_bool_func) - return add_axioms_from_bool(expr); + res=add_axioms_from_bool(expr); else if(id==ID_cprover_string_of_char_func) - return add_axioms_from_char(expr); - else if(id==ID_cprover_string_of_char_array_func) - return add_axioms_from_char_array(expr); + res=add_axioms_from_char(expr); else if(id==ID_cprover_string_set_length_func) - return add_axioms_for_set_length(expr); + res=add_axioms_for_set_length(expr); else if(id==ID_cprover_string_delete_func) - return add_axioms_for_delete(expr); + res=add_axioms_for_delete(expr); else if(id==ID_cprover_string_delete_char_at_func) - return add_axioms_for_delete_char_at(expr); + res=add_axioms_for_delete_char_at(expr); else if(id==ID_cprover_string_replace_func) - return add_axioms_for_replace(expr); + res=add_axioms_for_replace(expr); + else if(id==ID_cprover_string_intern_func) + res=add_axioms_for_intern(expr); + else if(id==ID_cprover_string_array_of_char_pointer_func) + res=add_axioms_for_char_pointer(expr); else { std::string msg( @@ -328,29 +476,32 @@ exprt string_constraint_generatort::add_axioms_for_function_application( msg+=id2string(id); throw msg; } + function_application_cache[expr]=res; + return res; } /// add axioms to say that the returned string expression is equal to the /// argument of the function application /// \par parameters: function application with one argument, which is a string +/// or three arguments: string, integer offset and count /// \return a new string expression string_exprt string_constraint_generatort::add_axioms_for_copy( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 1)[0]); - const refined_string_typet &ref_type=to_refined_string_type(s1.type()); - string_exprt res=fresh_string(ref_type); - - // We add axioms: - // a1 : |res|=|s1| - // a2 : forall i<|s1|. s1[i]=res[i] - - axioms.push_back(res.axiom_for_has_same_length_as(s1)); - - symbol_exprt idx=fresh_univ_index("QA_index_copy", ref_type.get_index_type()); - string_constraintt a2(idx, s1.length(), equal_exprt(s1[idx], res[idx])); - axioms.push_back(a2); - return res; + const auto &args=f.arguments(); + if(args.size()==1) + { + string_exprt s1=get_string_expr(args[0]); + return s1; + } + else + { + assert(args.size()==3); + string_exprt s1=get_string_expr(args[0]); + exprt offset=args[1]; + exprt count=args[2]; + return add_axioms_for_substring(s1, offset, plus_exprt(offset, count)); + } } /// add axioms corresponding to the String.valueOf([C) java function @@ -370,13 +521,36 @@ string_exprt string_constraint_generatort::add_axioms_for_java_char_array( return res; } -/// add axioms corresponding to the String.length java function -/// \par parameters: function application with one string argument -/// \return a string expression of index type +/// for an expression of the form `array[0]` returns `array` +/// \par parameters: an expression of type char +/// \return an array expression +exprt string_constraint_generatort::add_axioms_for_char_pointer( + const function_application_exprt &fun) +{ + exprt char_pointer=args(fun, 1)[0]; + if(char_pointer.id()==ID_index) + return char_pointer.op0(); + // TODO: we do not know what to do in the other cases + assert(false); +} + +/*******************************************************************\ + +Function: string_constraint_generatort::add_axioms_for_length + + Inputs: function application with one string argument + + Outputs: a string expression of index type + + Purpose: add axioms corresponding to the String.length java function + +\*******************************************************************/ + +>>>>>>> bdbeaf586... Many corrections in string refinement exprt string_constraint_generatort::add_axioms_for_length( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 1)[0]); + string_exprt str=get_string_expr(args(f, 1)[0]); return str.length(); } @@ -393,6 +567,7 @@ string_exprt string_constraint_generatort::add_axioms_from_char_array( const exprt &offset, const exprt &count) { + assert(false); // deprecated, we should use add_axioms_for_substring instead const typet &char_type=to_array_type(data.type()).subtype(); const typet &index_type=length.type(); refined_string_typet ref_type(index_type, char_type); @@ -405,7 +580,7 @@ string_exprt string_constraint_generatort::add_axioms_from_char_array( symbol_exprt qvar=fresh_univ_index("QA_string_of_char_array", index_type); exprt char_in_tab=data; assert(char_in_tab.id()==ID_index); - char_in_tab.op1()=plus_exprt(qvar, offset); + char_in_tab.op1()=plus_exprt_with_overflow_check(qvar, offset); string_constraintt a1(qvar, count, equal_exprt(str[qvar], char_in_tab)); axioms.push_back(a1); @@ -422,6 +597,7 @@ string_exprt string_constraint_generatort::add_axioms_from_char_array( string_exprt string_constraint_generatort::add_axioms_from_char_array( const function_application_exprt &f) { + assert(false); // deprecated, we should use add_axioms_for_substring instead exprt offset; exprt count; if(f.arguments().size()==4) @@ -485,7 +661,7 @@ exprt string_constraint_generatort::add_axioms_for_char_literal( exprt string_constraint_generatort::add_axioms_for_char_at( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 2)[0]); + string_exprt str=get_string_expr(args(f, 2)[0]); const refined_string_typet &ref_type=to_refined_string_type(str.type()); symbol_exprt char_sym=fresh_symbol("char", ref_type.get_char_type()); axioms.push_back(equal_exprt(char_sym, str[args(f, 2)[1]])); @@ -498,18 +674,6 @@ exprt string_constraint_generatort::add_axioms_for_char_at( exprt string_constraint_generatort::add_axioms_for_to_char_array( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 1)[0]); + string_exprt str=get_string_expr(args(f, 1)[0]); return str.content(); } - -/// add a correspondence to make sure the symbol points to the same string as -/// the second argument -/// \par parameters: a symbol and a string -void string_constraint_generatort::set_string_symbol_equal_to_expr( - const symbol_exprt &sym, const exprt &str) -{ - if(str.id()==ID_symbol) - assign_to_symbol(sym, find_or_add_string_of_symbol(to_symbol_expr(str))); - else - assign_to_symbol(sym, add_axioms_for_string_expr(str)); -} diff --git a/src/solvers/refinement/string_constraint_generator_testing.cpp b/src/solvers/refinement/string_constraint_generator_testing.cpp index dc28a5198e9..16a9d4b3ea0 100644 --- a/src/solvers/refinement/string_constraint_generator_testing.cpp +++ b/src/solvers/refinement/string_constraint_generator_testing.cpp @@ -24,15 +24,15 @@ exprt string_constraint_generatort::add_axioms_for_is_prefix( // We add axioms: // a1 : isprefix => |str| >= |prefix|+offset - // a2 : forall 0<=qvar - // s0[witness+offset]=s2[witness] - // a3 : !isprefix => |str| < |prefix|+offset - // || (|str| >= |prefix|+offset &&0<=witness<|prefix| - // &&str[witness+ofsset]!=prefix[witness]) + // a2 : forall 0<=qvar<|prefix|. isprefix => s0[witness+offset]=s2[witness] + // a3 : !isprefix => + // |str|<|prefix|+offset || + // (0<=witness<|prefix| && str[witness+offset]!=prefix[witness]) implies_exprt a1( isprefix, - str.axiom_for_is_longer_than(plus_exprt(prefix.length(), offset))); + str.axiom_for_is_longer_than(plus_exprt_with_overflow_check( + prefix.length(), offset))); axioms.push_back(a1); symbol_exprt qvar=fresh_univ_index("QA_isprefix", index_type); @@ -40,7 +40,8 @@ exprt string_constraint_generatort::add_axioms_for_is_prefix( qvar, prefix.length(), isprefix, - equal_exprt(str[plus_exprt(qvar, offset)], prefix[qvar])); + equal_exprt(str[plus_exprt_with_overflow_check(qvar, offset)], + prefix[qvar])); axioms.push_back(a2); symbol_exprt witness=fresh_exist_index("witness_not_isprefix", index_type); @@ -48,14 +49,13 @@ exprt string_constraint_generatort::add_axioms_for_is_prefix( axiom_for_is_positive_index(witness), and_exprt( prefix.axiom_for_is_strictly_longer_than(witness), - notequal_exprt(str[plus_exprt(witness, offset)], prefix[witness]))); + notequal_exprt(str[plus_exprt_with_overflow_check(witness, offset)], + prefix[witness]))); or_exprt s0_notpref_s1( not_exprt( - str.axiom_for_is_longer_than(plus_exprt(prefix.length(), offset))), - and_exprt( - witness_diff, str.axiom_for_is_longer_than( - plus_exprt(prefix.length(), offset)))); + plus_exprt_with_overflow_check(prefix.length(), offset))), + witness_diff); implies_exprt a3(not_exprt(isprefix), s0_notpref_s1); axioms.push_back(a3); @@ -73,8 +73,8 @@ exprt string_constraint_generatort::add_axioms_for_is_prefix( { const function_application_exprt::argumentst &args=f.arguments(); assert(f.type()==bool_typet() || f.type().id()==ID_c_bool); - string_exprt s0=add_axioms_for_string_expr(args[swap_arguments?1:0]); - string_exprt s1=add_axioms_for_string_expr(args[swap_arguments?0:1]); + string_exprt s0=get_string_expr(args[swap_arguments?1:0]); + string_exprt s1=get_string_expr(args[swap_arguments?0:1]); exprt offset; if(args.size()==2) offset=from_integer(0, s0.length().type()); @@ -97,7 +97,7 @@ exprt string_constraint_generatort::add_axioms_for_is_empty( // a2 : s0 => is_empty symbol_exprt is_empty=fresh_boolean("is_empty"); - string_exprt s0=add_axioms_for_string_expr(args(f, 1)[0]); + string_exprt s0=get_string_expr(args(f, 1)[0]); axioms.push_back(implies_exprt(is_empty, s0.axiom_for_has_length(0))); axioms.push_back(implies_exprt(s0.axiom_for_has_length(0), is_empty)); return typecast_exprt(is_empty, f.type()); @@ -118,8 +118,8 @@ exprt string_constraint_generatort::add_axioms_for_is_suffix( symbol_exprt issuffix=fresh_boolean("issuffix"); typecast_exprt tc_issuffix(issuffix, f.type()); - string_exprt s0=add_axioms_for_string_expr(args[swap_arguments?1:0]); - string_exprt s1=add_axioms_for_string_expr(args[swap_arguments?0:1]); + string_exprt s0=get_string_expr(args[swap_arguments?1:0]); + string_exprt s1=get_string_expr(args[swap_arguments?0:1]); const typet &index_type=s0.length().type(); // We add axioms: @@ -127,7 +127,7 @@ exprt string_constraint_generatort::add_axioms_for_is_suffix( // a2 : forall witness s1[witness]=s0[witness + s0.length-s1.length] // a3 : !issuffix => - // s1.length > s0.length + // (s1.length > s0.length && witness=-1) // || (s1.length > witness>=0 // &&s1[witness]!=s0[witness + s0.length-s1.length] @@ -145,7 +145,8 @@ exprt string_constraint_generatort::add_axioms_for_is_suffix( exprt shifted=plus_exprt( witness, minus_exprt(s1.length(), s0.length())); or_exprt constr3( - s0.axiom_for_is_strictly_longer_than(s1), + and_exprt(s0.axiom_for_is_strictly_longer_than(s1), + equal_exprt(witness, from_integer(-1, index_type))), and_exprt( notequal_exprt(s0[witness], s1[shifted]), and_exprt( @@ -166,9 +167,10 @@ exprt string_constraint_generatort::add_axioms_for_contains( assert(f.type()==bool_typet() || f.type().id()==ID_c_bool); symbol_exprt contains=fresh_boolean("contains"); typecast_exprt tc_contains(contains, f.type()); - string_exprt s0=add_axioms_for_string_expr(args(f, 2)[0]); - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[1]); - const typet &index_type=s0.type(); + string_exprt s0=get_string_expr(args(f, 2)[0]); + string_exprt s1=get_string_expr(args(f, 2)[1]); + const refined_string_typet ref_type=to_refined_string_type(s0.type()); + const typet &index_type=ref_type.get_index_type(); // We add axioms: // a1 : contains => s0.length >= s1.length diff --git a/src/solvers/refinement/string_constraint_generator_transformation.cpp b/src/solvers/refinement/string_constraint_generator_transformation.cpp index 01395b25cc1..6db591e8cf4 100644 --- a/src/solvers/refinement/string_constraint_generator_transformation.cpp +++ b/src/solvers/refinement/string_constraint_generator_transformation.cpp @@ -24,7 +24,7 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com string_exprt string_constraint_generatort::add_axioms_for_set_length( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); + string_exprt s1=get_string_expr(args(f, 2)[0]); exprt k=args(f, 2)[1]; const refined_string_typet &ref_type=to_refined_string_type(s1.type()); string_exprt res=fresh_string(ref_type); @@ -63,7 +63,7 @@ string_exprt string_constraint_generatort::add_axioms_for_substring( { const function_application_exprt::argumentst &args=f.arguments(); assert(args.size()>=2); - string_exprt str=add_axioms_for_string_expr(args[0]); + string_exprt str=get_string_expr(args[0]); exprt i(args[1]); exprt j; if(args.size()==3) @@ -89,7 +89,6 @@ string_exprt string_constraint_generatort::add_axioms_for_substring( { const refined_string_typet &ref_type=to_refined_string_type(str.type()); const typet &index_type=ref_type.get_index_type(); - symbol_exprt idx=fresh_exist_index("index_substring", index_type); assert(start.type()==index_type); assert(end.type()==index_type); string_exprt res=fresh_string(ref_type); @@ -112,8 +111,11 @@ string_exprt string_constraint_generatort::add_axioms_for_substring( // Warning: check what to do if the string is not long enough axioms.push_back(str.axiom_for_is_longer_than(end)); - string_constraintt a4( - idx, res.length(), equal_exprt(res[idx], str[plus_exprt(start, idx)])); + symbol_exprt idx=fresh_univ_index("QA_index_substring", index_type); + string_constraintt a4(idx, + res.length(), + equal_exprt(res[idx], + str[plus_exprt_with_overflow_check(start, idx)])); axioms.push_back(a4); return res; } @@ -124,7 +126,7 @@ string_exprt string_constraint_generatort::add_axioms_for_substring( string_exprt string_constraint_generatort::add_axioms_for_trim( const function_application_exprt &expr) { - string_exprt str=add_axioms_for_string_expr(args(expr, 1)[0]); + string_exprt str=get_string_expr(args(expr, 1)[0]); const refined_string_typet &ref_type=to_refined_string_type(str.type()); const typet &index_type=ref_type.get_index_type(); string_exprt res=fresh_string(ref_type); @@ -143,7 +145,8 @@ string_exprt string_constraint_generatort::add_axioms_for_trim( // a8 : forall n<|s1|, s[idx+n]=s1[n] // a9 : (s[m]>' ' &&s[m+|s1|-1]>' ') || m=|s| - exprt a1=str.axiom_for_is_longer_than(plus_exprt(idx, res.length())); + exprt a1=str.axiom_for_is_longer_than( + plus_exprt_with_overflow_check(idx, res.length())); axioms.push_back(a1); binary_relation_exprt a2(idx, ID_ge, from_integer(0, index_type)); @@ -165,7 +168,8 @@ string_exprt string_constraint_generatort::add_axioms_for_trim( axioms.push_back(a6); symbol_exprt n2=fresh_univ_index("QA_index_trim2", index_type); - minus_exprt bound(str.length(), plus_exprt(idx, res.length())); + minus_exprt bound(str.length(), plus_exprt_with_overflow_check(idx, + res.length())); binary_relation_exprt eqn2( str[plus_exprt(idx, plus_exprt(res.length(), n2))], ID_le, @@ -180,7 +184,8 @@ string_exprt string_constraint_generatort::add_axioms_for_trim( axioms.push_back(a8); minus_exprt index_before( - plus_exprt(idx, res.length()), from_integer(1, index_type)); + plus_exprt_with_overflow_check(idx, res.length()), + from_integer(1, index_type)); binary_relation_exprt no_space_before(str[index_before], ID_gt, space_char); or_exprt a9( equal_exprt(idx, str.length()), @@ -197,7 +202,7 @@ string_exprt string_constraint_generatort::add_axioms_for_trim( string_exprt string_constraint_generatort::add_axioms_for_to_lower_case( const function_application_exprt &expr) { - string_exprt str=add_axioms_for_string_expr(args(expr, 1)[0]); + string_exprt str=get_string_expr(args(expr, 1)[0]); const refined_string_typet &ref_type=to_refined_string_type(str.type()); const typet &char_type=ref_type.get_char_type(); const typet &index_type=ref_type.get_index_type(); @@ -241,7 +246,7 @@ string_exprt string_constraint_generatort::add_axioms_for_to_lower_case( string_exprt string_constraint_generatort::add_axioms_for_to_upper_case( const function_application_exprt &expr) { - string_exprt str=add_axioms_for_string_expr(args(expr, 1)[0]); + string_exprt str=get_string_expr(args(expr, 1)[0]); const refined_string_typet &ref_type=to_refined_string_type(str.type()); const typet &char_type=ref_type.get_char_type(); const typet &index_type=ref_type.get_index_type(); @@ -288,7 +293,7 @@ string_exprt string_constraint_generatort::add_axioms_for_to_upper_case( string_exprt string_constraint_generatort::add_axioms_for_char_set( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 3)[0]); + string_exprt str=get_string_expr(args(f, 3)[0]); const refined_string_typet &ref_type=to_refined_string_type(str.type()); string_exprt res=fresh_string(ref_type); with_exprt sarrnew(str.content(), args(f, 3)[1], args(f, 3)[2]); @@ -313,7 +318,7 @@ string_exprt string_constraint_generatort::add_axioms_for_char_set( string_exprt string_constraint_generatort::add_axioms_for_replace( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 3)[0]); + string_exprt str=get_string_expr(args(f, 3)[0]); const refined_string_typet &ref_type=to_refined_string_type(str.type()); const exprt &old_char=args(f, 3)[1]; const exprt &new_char=args(f, 3)[2]; @@ -347,10 +352,12 @@ string_exprt string_constraint_generatort::add_axioms_for_replace( string_exprt string_constraint_generatort::add_axioms_for_delete_char_at( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 2)[0]); + string_exprt str=get_string_expr(args(f, 2)[0]); exprt index_one=from_integer(1, str.length().type()); return add_axioms_for_delete( - str, args(f, 2)[1], plus_exprt(args(f, 2)[1], index_one)); + str, + args(f, 2)[1], + plus_exprt_with_overflow_check(args(f, 2)[1], index_one)); } /// add axioms stating that the returned string corresponds to the input one @@ -376,6 +383,6 @@ string_exprt string_constraint_generatort::add_axioms_for_delete( string_exprt string_constraint_generatort::add_axioms_for_delete( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 3)[0]); + string_exprt str=get_string_expr(args(f, 3)[0]); return add_axioms_for_delete(str, args(f, 3)[1], args(f, 3)[2]); } diff --git a/src/solvers/refinement/string_constraint_generator_valueof.cpp b/src/solvers/refinement/string_constraint_generator_valueof.cpp index 6fe11ca6c18..5d9900264d6 100644 --- a/src/solvers/refinement/string_constraint_generator_valueof.cpp +++ b/src/solvers/refinement/string_constraint_generator_valueof.cpp @@ -40,7 +40,8 @@ string_exprt string_constraint_generatort::add_axioms_from_long( string_exprt string_constraint_generatort::add_axioms_from_float( const function_application_exprt &f) { - return add_axioms_from_float(args(f, 1)[0], false); + const refined_string_typet &ref_type=to_refined_string_type(f.type()); + return add_axioms_from_float(args(f, 1)[0], ref_type, false); } /// add axioms corresponding to the String.valueOf(D) java function @@ -49,7 +50,8 @@ string_exprt string_constraint_generatort::add_axioms_from_float( string_exprt string_constraint_generatort::add_axioms_from_double( const function_application_exprt &f) { - return add_axioms_from_float(args(f, 1)[0], true); + const refined_string_typet &ref_type=to_refined_string_type(f.type()); + return add_axioms_from_float(args(f, 1)[0], ref_type, true); } /// add axioms corresponding to the String.valueOf(F) java function Warning: we @@ -59,13 +61,12 @@ string_exprt string_constraint_generatort::add_axioms_from_double( /// double precision /// \return a new string expression string_exprt string_constraint_generatort::add_axioms_from_float( - const exprt &f, bool double_precision) + const exprt &f, const refined_string_typet &ref_type, bool double_precision) { - const refined_string_typet &ref_type=to_refined_string_type(f.type()); + string_exprt res=fresh_string(ref_type); const typet &index_type=ref_type.get_index_type(); const typet &char_type=ref_type.get_char_type(); - string_exprt res=fresh_string(ref_type); - const exprt &index24=from_integer(24, ref_type.get_index_type()); + const exprt &index24=from_integer(24, index_type); axioms.push_back(res.axiom_for_is_shorter_than(index24)); string_exprt magnitude=fresh_string(ref_type); @@ -247,13 +248,22 @@ string_exprt string_constraint_generatort::add_axioms_from_int( axioms.push_back(a1); exprt chr=res[0]; - exprt starts_with_minus=equal_exprt(chr, minus_char); - exprt starts_with_digit=and_exprt( + equal_exprt starts_with_minus(chr, minus_char); + and_exprt starts_with_digit( binary_relation_exprt(chr, ID_ge, zero_char), binary_relation_exprt(chr, ID_le, nine_char)); or_exprt a2(starts_with_digit, starts_with_minus); axioms.push_back(a2); + // These are constraints to detect number that requiere the maximum number + // of digits + exprt smallest_with_max_digits= + from_integer(smallest_by_digit(max_size-1), type); + binary_relation_exprt big_negative( + i, ID_le, unary_minus_exprt(smallest_with_max_digits)); + binary_relation_exprt big_positive(i, ID_ge, smallest_with_max_digits); + or_exprt requieres_max_digits(big_negative, big_positive); + for(size_t size=1; size<=max_size; size++) { // For each possible size, we add axioms: @@ -311,13 +321,18 @@ string_exprt string_constraint_generatort::add_axioms_from_int( axioms.push_back(a6); } - // we have to be careful when exceeding the maximal size of integers + // when the size is close to the maximum, either the number is very big + // or it is negative + if(size==max_size-1) + { + implies_exprt a7(premise, or_exprt(requieres_max_digits, + starts_with_minus)); + axioms.push_back(a7); + } + // when we reach the maximal size the number is very big in the negative if(size==max_size) { - exprt smallest_with_10_digits=from_integer( - smallest_by_digit(max_size), type); - binary_relation_exprt big(i, ID_ge, smallest_with_10_digits); - implies_exprt a7(premise, big); + implies_exprt a7(premise, and_exprt(starts_with_minus, big_negative)); axioms.push_back(a7); } } @@ -466,13 +481,68 @@ string_exprt string_constraint_generatort::add_axioms_for_value_of( } } -/// add axioms corresponding to the Integer.parseInt java function +/// add axioms making the return value true if the given string is +/// a correct number /// \par parameters: function application with one string expression -/// \return an integer expression +/// \return an boolean expression +exprt string_constraint_generatort::add_axioms_for_correct_number_format( + const string_exprt &str, std::size_t max_size) +{ + symbol_exprt correct=fresh_boolean("correct_number_format"); + const refined_string_typet &ref_type=to_refined_string_type(str.type()); + const typet &char_type=ref_type.get_char_type(); + const typet &index_type=ref_type.get_index_type(); + exprt zero_char=constant_char('0', char_type); + exprt nine_char=constant_char('9', char_type); + exprt minus_char=constant_char('-', char_type); + exprt plus_char=constant_char('+', char_type); + + exprt chr=str[0]; + equal_exprt starts_with_minus(chr, minus_char); + equal_exprt starts_with_plus(chr, plus_char); + and_exprt starts_with_digit( + binary_relation_exprt(chr, ID_ge, zero_char), + binary_relation_exprt(chr, ID_le, nine_char)); + + or_exprt correct_first( + or_exprt(starts_with_minus, starts_with_plus), starts_with_digit); + exprt has_first=str.axiom_for_is_longer_than(from_integer(1, index_type)); + implies_exprt a1(correct, and_exprt(has_first, correct_first)); + axioms.push_back(a1); + + exprt not_too_long=str.axiom_for_is_shorter_than(max_size); + axioms.push_back(not_too_long); + + symbol_exprt qvar=fresh_univ_index("number_format", index_type); + + and_exprt is_digit( + binary_relation_exprt(str[qvar], ID_ge, zero_char), + binary_relation_exprt(str[qvar], ID_le, nine_char)); + + string_constraintt a2( + qvar, from_integer(1, index_type), str.length(), correct, is_digit); + + axioms.push_back(a2); + return correct; +} + +/*******************************************************************\ + +Function: string_constraint_generatort::add_axioms_for_parse_int + + Inputs: function application with one string expression + + Outputs: an integer expression + + Purpose: add axioms corresponding to the Integer.parseInt java function + +\*******************************************************************/ + +>>>>>>> bdbeaf586... Many corrections in string refinement exprt string_constraint_generatort::add_axioms_for_parse_int( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 1)[0]); + string_exprt str=get_string_expr(args(f, 1)[0]); const typet &type=f.type(); symbol_exprt i=fresh_symbol("parsed_int", type); const refined_string_typet &ref_type=to_refined_string_type(str.type()); @@ -488,6 +558,10 @@ exprt string_constraint_generatort::add_axioms_for_parse_int( exprt starts_with_plus=equal_exprt(chr, plus_char); exprt starts_with_digit=binary_relation_exprt(chr, ID_ge, zero_char); + // TODO: we should throw an exception when this does not hold: + exprt correct=add_axioms_for_correct_number_format(str); + axioms.push_back(correct); + for(unsigned size=1; size<=10; size++) { exprt sum=from_integer(0, type); diff --git a/src/solvers/refinement/string_refinement.cpp b/src/solvers/refinement/string_refinement.cpp index 0f31a6add0f..93c6d612f1e 100644 --- a/src/solvers/refinement/string_refinement.cpp +++ b/src/solvers/refinement/string_refinement.cpp @@ -18,17 +18,38 @@ Author: Alberto Griggio, alberto.griggio@gmail.com /// Ghosh. #include +#include #include #include #include +#include +#include #include #include #include +#include + +/*******************************************************************\ + +Constructor: string_refinementt + + Inputs: a namespace, a decision procedure, a bound on the number + of refinements and a boolean flag `concretize_result` + + Purpose: refinement_bound is a bound on the number of refinement allowed. + if `concretize_result` is set to true, at the end of the decision + procedure, the solver try to find a concrete value for each + character + +\*******************************************************************/ string_refinementt::string_refinementt( - const namespacet &_ns, propt &_prop, unsigned refinement_bound): + const namespacet &_ns, + propt &_prop, + unsigned refinement_bound): supert(_ns, _prop), use_counter_example(false), + do_concretizing(false), initial_loop_bound(refinement_bound) { } @@ -45,15 +66,27 @@ void string_refinementt::set_mode() /// display the current index set, for debugging void string_refinementt::display_index_set() { + std::size_t count=0; + std::size_t count_current=0; for(const auto &i : index_set) { const exprt &s=i.first; - debug() << "IS(" << from_expr(s) << ")=={"; + debug() << "IS(" << from_expr(s) << ")=={" << eom; for(auto j : i.second) - debug() << from_expr(j) << "; "; + { + if(current_index_set[i.first].find(j)!=current_index_set[i.first].end()) + { + count_current++; + debug() << "**"; + } + debug() << " " << from_expr(j) << ";" << eom; + count++; + } debug() << "}" << eom; } + debug() << count << " elements in index set (" << count_current + << " newly added)" << eom; } /// compute the index set for all formulas, instantiate the formulas with the @@ -86,115 +119,304 @@ void string_refinementt::add_instantiations() /// if the expression is a function application, we convert it using our own /// convert_function_application method -/// \par parameters: an expression -/// \return a literal -literalt string_refinementt::convert_rest(const exprt &expr) +/// keeps a map of symbols to expressions, such as none of the mapped +/// values exist as a key +/// \par parameters: a symbol and the expression to map it to +void string_refinementt::add_symbol_to_symbol_map +(const exprt &lhs, const exprt &rhs) { - if(expr.id()==ID_function_application) + assert(lhs.id()==ID_symbol); + + // We insert the mapped value of the rhs, if it exists. + auto it=symbol_resolve.find(rhs); + const exprt &new_rhs=it!=symbol_resolve.end()?it->second:rhs; + + symbol_resolve[lhs]=new_rhs; + reverse_symbol_resolve[new_rhs].push_back(lhs); + + std::list symbols_to_update_with_new_rhs(reverse_symbol_resolve[rhs]); + for(exprt item : symbols_to_update_with_new_rhs) { - // can occur in __CPROVER_assume - bvt bv=convert_function_application(to_function_application_expr(expr)); - assert(bv.size()==1); - return bv[0]; + symbol_resolve[item]=new_rhs; + reverse_symbol_resolve[new_rhs].push_back(item); } - else +} + +/*******************************************************************\ + +Function: string_refinementt::set_char_array_equality() + + Inputs: the rhs and lhs of an equality over character arrays + + Purpose: add axioms if the rhs is a character array + +\*******************************************************************/ + +void string_refinementt::set_char_array_equality( + const exprt &lhs, const exprt &rhs) +{ + assert(lhs.id()==ID_symbol); + + if(rhs.id()==ID_array && rhs.type().id()==ID_array) { - return supert::convert_rest(expr); + const typet &index_type=to_array_type(rhs.type()).size().type(); + for(size_t i=0, ilim=rhs.operands().size(); i!=ilim; ++i) + { + // Introduce axioms to map symbolic rhs to its char array. + index_exprt arraycell(rhs, from_integer(i, index_type)); + equal_exprt arrayeq(arraycell, rhs.operands()[i]); + add_lemma(arrayeq, false); +#if 0 + generator.axioms.push_back(arrayeq); +#endif + } } + // At least for Java (as it is currently pre-processed), we need not consider + // other cases, because all character arrays find themselves on the rhs of an + // equality. Note that this might not be the case for other languages. } -/// if the expression as string type, look up for the string in the list of -/// string symbols that we maintain, and convert it; otherwise use the method of -/// the parent class -/// \par parameters: an expression -/// \return a bitvector -bvt string_refinementt::convert_symbol(const exprt &expr) +/// remove functions applications and create the necessary axioms +/// \par parameters: an expression containing function applications +/// \return an epression containing no function application +exprt string_refinementt::substitute_function_applications(exprt expr) { - const typet &type=expr.type(); - const irep_idt &identifier=expr.get(ID_identifier); - assert(!identifier.empty()); + for(size_t i=0; iMAX_CONCRETE_STRING_SIZE? + MAX_CONCRETE_STRING_SIZE:concretize_limit; + exprt content_expr=str.content(); + replace_expr(current_model, content_expr); + for(size_t i=0; i &pair : non_string_axioms) + { + replace_expr(symbol_resolve, pair.first); + debug() << "super::set_to " << from_expr(pair.first) << eom; + supert::set_to(pair.first, pair.second); + } + + for(exprt &axiom : generator.axioms) + { + replace_expr(symbol_resolve, axiom); if(axiom.id()==ID_string_constraint) { string_constraintt c=to_string_constraint(axiom); @@ -223,6 +456,7 @@ decision_proceduret::resultt string_refinementt::dec_solve() { add_lemma(axiom); } + } initial_index_set(universal_axioms); update_index_set(cur); @@ -243,6 +477,7 @@ decision_proceduret::resultt string_refinementt::dec_solve() else { debug() << "check_SAT: the model is correct" << eom; + concretize_lengths(); return D_SATISFIABLE; } @@ -259,7 +494,13 @@ decision_proceduret::resultt string_refinementt::dec_solve() if(current_index_set.empty()) { debug() << "current index set is empty" << eom; - return D_SATISFIABLE; + if(do_concretizing) + { + concretize_results(); + do_concretizing=false; + } + else + return D_SATISFIABLE; } display_index_set(); @@ -294,147 +535,355 @@ bvt string_refinementt::convert_bool_bv(const exprt &boole, const exprt &orig) return ret; } -/// add the given lemma to the solver -/// \par parameters: a lemma -void string_refinementt::add_lemma(const exprt &lemma, bool add_to_index_set) +/*******************************************************************\ + +Function: string_refinementt::add_lemma + + Inputs: a lemma and Boolean value stating whether the lemma should + be added to the index set. + + Purpose: add the given lemma to the solver + +\*******************************************************************/ + +void string_refinementt::add_lemma( + const exprt &lemma, bool _simplify, bool add_to_index_set) { if(!seen_instances.insert(lemma).second) return; - if(lemma.is_true()) + if(add_to_index_set) + cur.push_back(lemma); + + exprt simple_lemma=lemma; + if(_simplify) + simplify(simple_lemma, ns); + + if(simple_lemma.is_true()) { +#if 0 debug() << "string_refinementt::add_lemma : tautology" << eom; +#endif return; } - debug() << "adding lemma " << from_expr(lemma) << eom; + debug() << "adding lemma " << from_expr(simple_lemma) << eom; - prop.l_set_to_true(convert(lemma)); - if(add_to_index_set) - cur.push_back(lemma); + prop.l_set_to_true(convert(simple_lemma)); } -/// convert the content of a string to a more readable representation. This -/// should only be used for debbuging. -/// \par parameters: a constant array expression and a integer expression -/// \return a string -std::string string_refinementt::string_of_array( - const exprt &arr, const exprt &size) const +/*******************************************************************\ + +Function: string_refinementt::get_array + + Inputs: an expression representing an array and an expression + representing an integer + + Outputs: an array expression or an array_of_exprt + + Purpose: get a model of an array and put it in a certain form. + If the size cannot be obtained or if it is too big, return an + empty array. + +\*******************************************************************/ + +exprt string_refinementt::get_array(const exprt &arr, const exprt &size) const { - if(size.id()!=ID_constant) - return "string of unknown size"; + exprt arr_val=get_array(arr); + exprt size_val=supert::get(size); + size_val=simplify_expr(size_val, ns); + typet char_type=arr.type().subtype(); + typet index_type=size.type(); + array_typet empty_ret_type(char_type, from_integer(0, index_type)); + array_of_exprt empty_ret(from_integer(0, char_type), empty_ret_type); + + if(size_val.id()!=ID_constant) + { +#if 0 + debug() << "(sr::get_array) string of unknown size: " + << from_expr(size_val) << eom; +#endif + return empty_ret; + } + unsigned n; - if(to_unsigned_integer(to_constant_expr(size), n)) - n=0; + if(to_unsigned_integer(to_constant_expr(size_val), n)) + { +#if 0 + debug() << "(sr::get_array) size is not valid" << eom; +#endif + return empty_ret; + } + + array_typet ret_type(char_type, from_integer(n, index_type)); + array_exprt ret(ret_type); if(n>MAX_CONCRETE_STRING_SIZE) - return "very long string"; + { +#if 0 + debug() << "(sr::get_array) long string (size=" << n << ")" << eom; +#endif + return empty_ret; + } + if(n==0) - return "\"\""; + { +#if 0 + debug() << "(sr::get_array) empty string" << eom; +#endif + return empty_ret; + } - std::ostringstream buf; - buf << "\""; - exprt val=get(arr); + std::vector concrete_array(n); - if(val.id()=="array-list") + if(arr_val.id()=="array-list") { - for(size_t i=0; i(c); + exprt value=arr_val.operands()[i*2+1]; + to_unsigned_integer(to_constant_expr(value), concrete_array[idx]); } } } } + else if(arr_val.id()==ID_array) + { + for(size_t i=0; i=32) + result << (unsigned char) c; + else + { + result << "\\u" << std::hex << std::setw(4) << std::setfill('0') + << (unsigned int) c; + } + } + + return result.str(); +} + +/*******************************************************************\ - exprt len=get(elength); - exprt arr=get_array(econtent, len); +Function: string_refinementt::fill_model + + Purpose: Fill in `current_model` by mapping the variables created by + the solver to constant expressions given by the current model + +\*******************************************************************/ - fmodel[elength]=len; - fmodel[econtent]=arr; - debug() << it.first << "=" << from_expr(it.second) - << " of length " << from_expr(len) <<" := " << eom - << from_expr(get(econtent)) << eom - << string_of_array(econtent, len) << eom; +void string_refinementt::fill_model() +{ + for(auto it : symbol_resolve) + { + if(refined_string_typet::is_refined_string_type(it.second.type())) + { + string_exprt refined=to_string_expr(it.second); + // TODO: check whith this is necessary: + replace_expr(symbol_resolve, refined); + const exprt &econtent=refined.content(); + const exprt &elength=refined.length(); + + exprt len=supert::get(elength); + len=simplify_expr(len, ns); + exprt arr=get_array(econtent, len); + + current_model[elength]=len; + current_model[econtent]=arr; + debug() << from_expr(to_symbol_expr(it.first)) << "=" + << from_expr(refined); + + if(arr.id()==ID_array) + debug() << " = \"" << string_of_array(to_array_expr(arr)) + << "\" (size:" << from_expr(len) << ")"<< eom; + else + debug() << " = " << from_expr(arr) << " (size:" << from_expr(len) + << ")" << eom; + } + else + { + assert(is_char_array(it.second.type())); + exprt arr=it.second; + replace_expr(symbol_resolve, arr); + replace_expr(current_model, arr); + exprt arr_model=get_array(arr); + current_model[it.first]=arr_model; + + debug() << from_expr(to_symbol_expr(it.first)) << "=" + << from_expr(arr) << " = " << from_expr(arr_model) << "" << eom; + } } for(auto it : generator.boolean_symbols) { - debug() << "" << it.get_identifier() << " := " - << from_expr(get(it)) << eom; - fmodel[it]=get(it); + debug() << "" << it.get_identifier() << " := " + << from_expr(supert::get(it)) << eom; + current_model[it]=supert::get(it); } for(auto it : generator.index_symbols) { - debug() << "" << it.get_identifier() << " := " - << from_expr(get(it)) << eom; - fmodel[it]=get(it); + debug() << "" << it.get_identifier() << " := " + << from_expr(supert::get(it)) << eom; + current_model[it]=supert::get(it); } +} + +/*******************************************************************\ + +Function: string_refinementt::add_negation_of_constraint_to_solver + + Inputs: a string constraint and a solver for non string expressions + + Purpose: negates the constraint and add it to the solver. + the intended usage is to find an assignement of the universal + variable that would violate the axiom, + to avoid false positives the symbols other than the universal + variable should have been replaced by there valuation in the + current model + +\*******************************************************************/ + +void string_refinementt::add_negation_of_constraint_to_solver( + const string_constraintt &axiom, supert &solver) +{ + exprt lb=axiom.lower_bound(); + exprt ub=axiom.upper_bound(); + if(lb.id()==ID_constant && ub.id()==ID_constant) + { + mp_integer lb_int, ub_int; + to_integer(to_constant_expr(lb), lb_int); + to_integer(to_constant_expr(ub), ub_int); + if(ub_int<=lb_int) + { + debug() << "empty constraint with current model" << eom; + solver << false_exprt(); + return; + } + } + + if(axiom.premise()==false_exprt()) + { + debug() << "(string_refinement::check_axioms) adding false" << eom; + solver << false_exprt(); + return; + } + + and_exprt premise(axiom.premise(), axiom.univ_within_bounds()); + and_exprt negaxiom(premise, not_exprt(axiom.body())); + + debug() << "(sr::check_axioms) negated axiom: " << from_expr(negaxiom) << eom; + solver << negaxiom; +} + +/*******************************************************************\ + +Function: string_refinementt::check_axioms + + Outputs: a Boolean + + Purpose: return true if the current model satisfies all the axioms + +\*******************************************************************/ + +bool string_refinementt::check_axioms() +{ + debug() << "string_refinementt::check_axioms: ===============" + << "===========================================" << eom; + debug() << "string_refinementt::check_axioms: build the" + << " interpretation from the model of the prop_solver" << eom; + fill_model(); // Maps from indexes of violated universal axiom to a witness of violation std::map violated; @@ -444,21 +893,27 @@ bool string_refinementt::check_axioms() for(size_t i=0; i string_refinementt::map_representation_of_sum( /// times given by the corresponding integer in the map. For a map x -> 2, y /// -> -1 would give an expression $x + x - y$. exprt string_refinementt::sum_over_map( - std::map &m, bool negated) const + std::map &m, const typet &type, bool negated) const { exprt sum=nil_exprt(); mp_integer constants=0; typet index_type; if(m.empty()) - return nil_exprt(); + return from_integer(0, type); else index_type=m.begin()->first.type(); @@ -604,12 +1057,20 @@ exprt string_refinementt::sum_over_map( default: if(second>1) { - for(int i=0; isecond; i--) + if(sum.is_nil()) + sum=unary_minus_exprt(t); + else + sum=minus_exprt(sum, t); + for(int i=-1; i>second; i--) sum=minus_exprt(sum, t); } } @@ -628,7 +1089,7 @@ exprt string_refinementt::sum_over_map( exprt string_refinementt::simplify_sum(const exprt &f) const { std::map map=map_representation_of_sum(f); - return sum_over_map(map); + return sum_over_map(map, f.type()); } /// \par parameters: a symbol qvar, an expression val, an expression f @@ -665,7 +1126,7 @@ exprt string_refinementt::compute_inverse_function( } elems.erase(it); - return sum_over_map(elems, neg); + return sum_over_map(elems, f.type(), neg); } @@ -687,9 +1148,18 @@ class find_qvar_visitort: public const_expr_visitort } }; -/// looks for the symbol and return true if it is found -/// \par parameters: an index expression and a symbol qvar -/// \return a Boolean +/*******************************************************************\ + +Function: find_qvar + + Inputs: an index expression and a symbol qvar + + Outputs: a Boolean + + Purpose: look for the symbol and return true if it is found + +\*******************************************************************/ + static bool find_qvar(const exprt index, const symbol_exprt &qvar) { find_qvar_visitort v2(qvar); @@ -715,9 +1185,37 @@ void string_refinementt::update_index_set(const std::vector &cur) update_index_set(axiom); } -/// add to the index set all the indices that appear in the formula and the -/// upper bound minus one -/// \par parameters: a string constraint +/*******************************************************************\ + +Function: string_refinementt::initial_index_set + + Inputs: a string constraint + + Purpose: add to the index set all the indices that appear in the formula + and the upper bound minus one + +\*******************************************************************/ +void string_refinementt::add_to_index_set(const exprt &s, exprt i) +{ + simplify(i, ns); + if(i.id()==ID_constant) + { + mp_integer mpi; + to_integer(i, mpi); + if(mpi<0) + { + debug() << "add_to_index_set : ignoring negative number " << mpi << eom; + return; + } + } + if(index_set[s].insert(i).second) + { + debug() << "adding to index set of " << from_expr(s) + << ": " << from_expr(i) << eom; + current_index_set[s].insert(i); + } +} + void string_refinementt::initial_index_set(const string_constraintt &axiom) { symbol_exprt qvar=axiom.univ_var(); @@ -738,8 +1236,7 @@ void string_refinementt::initial_index_set(const string_constraintt &axiom) // if cur is of the form s[i] and no quantified variable appears in i if(!has_quant_var) { - current_index_set[s].insert(i); - index_set[s].insert(i); + add_to_index_set(s, i); } else { @@ -749,8 +1246,7 @@ void string_refinementt::initial_index_set(const string_constraintt &axiom) axiom.upper_bound(), from_integer(1, axiom.upper_bound().type())); replace_expr(qvar, kminus1, e); - current_index_set[s].insert(e); - index_set[s].insert(e); + add_to_index_set(s, e); } } else @@ -776,12 +1272,7 @@ void string_refinementt::update_index_set(const exprt &formula) const exprt &i=cur.op1(); assert(s.type().id()==ID_array); exprt simplified=simplify_sum(i); - if(index_set[s].insert(simplified).second) - { - debug() << "adding to index set of " << from_expr(s) - << ": " << from_expr(simplified) << eom; - current_index_set[s].insert(simplified); - } + add_to_index_set(s, simplified); } else { @@ -828,14 +1319,21 @@ exprt find_index(const exprt &expr, const exprt &str) catch (exprt i) { return i; } } +/*******************************************************************\ + +Function: string_refinementt::instantiate + + Inputs: a universally quantified formula `axiom`, an array of char + variable `str`, and an index expression `val`. + + Outputs: substitute `qvar` the universally quantified variable of `axiom`, by + an index `val`, in `axiom`, so that the index used for `str` equals + `val`. For instance, if `axiom` corresponds to + $\forall q. s[q+x]='a' && t[q]='b'$, `instantiate(axom,s,v)` + would return an expression for $s[v]='a' && t[v-x]='b'$. + +\*******************************************************************/ -/// \par parameters: an universaly quantified formula `axiom`, an array of char -/// variable `str`, and an index expression `val`. -/// \return substitute `qvar` the universaly quantified variable of `axiom`, by -/// an index `val`, in `axiom`, so that the index used for `str` equals `val`. -/// For instance, if `axiom` corresponds to $\forall q. s[q+x]='a' && -/// t[q]='b'$, `instantiate(axom,s,v)` would return an expression for -/// $s[v]='a' && t[v-x]='b'$. exprt string_refinementt::instantiate( const string_constraintt &axiom, const exprt &str, const exprt &val) { @@ -857,6 +1355,17 @@ exprt string_refinementt::instantiate( return implies_exprt(bounds, instance); } +/*******************************************************************\ + +Function: string_refinementt::instantiate_not_contains + + Inputs: a quantified formula representing `not_contains`, and a + list to which to add the created lemmas to + + Purpose: instantiate a quantified formula representing `not_contains` + by substituting the quantifiers and generating axioms + +\*******************************************************************/ void string_refinementt::instantiate_not_contains( const string_not_contains_constraintt &axiom, std::list &new_lemmas) @@ -908,3 +1417,76 @@ void string_refinementt::instantiate_not_contains( new_lemmas.push_back(witness_bounds); } } + +/*******************************************************************\ + +Function: string_refinementt::substitute_array_lists() + + Inputs: an expression containing array-list expressions + + Outputs: an epression containing no array-list + + Purpose: replace array-lists by 'with' expressions + +\*******************************************************************/ + +exprt string_refinementt::substitute_array_lists(exprt expr) const +{ + for(size_t i=0; i=2); + typet &char_type=expr.operands()[1].type(); + array_typet arr_type(char_type, infinity_exprt(char_type)); + array_of_exprt new_arr(from_integer(0, char_type), + arr_type); + + with_exprt ret_expr(new_arr, + expr.operands()[0], + expr.operands()[1]); + + for(size_t i=2; isecond); + } + + ecopy=supert::get(ecopy); + + return substitute_array_lists(ecopy); +} diff --git a/src/solvers/refinement/string_refinement.h b/src/solvers/refinement/string_refinement.h index aa28f8a0c96..134154af09b 100644 --- a/src/solvers/refinement/string_refinement.h +++ b/src/solvers/refinement/string_refinement.h @@ -21,6 +21,7 @@ Author: Alberto Griggio, alberto.griggio@gmail.com #define CPROVER_SOLVERS_REFINEMENT_STRING_REFINEMENT_H #include +#include #include #include @@ -34,30 +35,32 @@ Author: Alberto Griggio, alberto.griggio@gmail.com class string_refinementt: public bv_refinementt { public: - // refinement_bound is a bound on the number of refinement allowed string_refinementt( - const namespacet &_ns, propt &_prop, unsigned refinement_bound); + const namespacet &_ns, + propt &_prop, + unsigned refinement_bound); void set_mode(); // Should we use counter examples at each iteration? bool use_counter_example; - virtual std::string decision_procedure_text() const + bool do_concretizing; + + virtual std::string decision_procedure_text() const override { return "string refinement loop with "+prop.solver_text(); } static exprt is_positive(const exprt &x); + exprt get(const exprt &expr) const override; + protected: typedef std::set expr_sett; + typedef std::list exprt_listt; - virtual bvt convert_symbol(const exprt &expr); - virtual bvt convert_function_application( - const function_application_exprt &expr); - - decision_proceduret::resultt dec_solve(); + decision_proceduret::resultt dec_solve() override; bvt convert_bool_bv(const exprt &boole, const exprt &orig); @@ -67,6 +70,9 @@ class string_refinementt: public bv_refinementt unsigned initial_loop_bound; + // Is the current model correct + bool concrete_model; + string_constraint_generatort generator; // Simple constraints that have been given to the solver @@ -83,23 +89,42 @@ class string_refinementt: public bv_refinementt // Warning: this is indexed by array_expressions and not string expressions std::map current_index_set; std::map index_set; + replace_mapt symbol_resolve; + std::map reverse_symbol_resolve; + std::list> non_string_axioms; - void display_index_set(); + // Valuation in the current model of the symbols that have been created + // by the solver + replace_mapt current_model; - void add_lemma(const exprt &lemma, bool add_to_index_set=true); + void add_equivalence(const irep_idt & lhs, const exprt & rhs); - bool boolbv_set_equality_to_true(const equal_exprt &expr); + void display_index_set(); - literalt convert_rest(const exprt &expr); + void add_lemma(const exprt &lemma, + bool simplify=true, + bool add_to_index_set=true); - void add_instantiations(); + exprt substitute_function_applications(exprt expr); + typet substitute_java_string_types(typet type); + exprt substitute_java_strings(exprt expr); + void add_symbol_to_symbol_map(const exprt &lhs, const exprt &rhs); + bool is_char_array(const typet &type) const; + bool add_axioms_for_string_assigns(const exprt &lhs, const exprt &rhs); + void set_to(const exprt &expr, bool value) override; + void add_instantiations(); + void add_negation_of_constraint_to_solver( + const string_constraintt &axiom, supert &solver); + void fill_model(); bool check_axioms(); + void set_char_array_equality(const exprt &lhs, const exprt &rhs); void update_index_set(const exprt &formula); void update_index_set(const std::vector &cur); void initial_index_set(const string_constraintt &axiom); void initial_index_set(const std::vector &string_axioms); + void add_to_index_set(const exprt &s, exprt i); exprt instantiate( const string_constraintt &axiom, const exprt &str, const exprt &val); @@ -108,17 +133,26 @@ class string_refinementt: public bv_refinementt const string_not_contains_constraintt &axiom, std::list &new_lemmas); + exprt substitute_array_lists(exprt) const; + exprt compute_inverse_function( const exprt &qvar, const exprt &val, const exprt &f); std::map map_representation_of_sum(const exprt &f) const; - exprt sum_over_map(std::map &m, bool negated=false) const; + exprt sum_over_map( + std::map &m, const typet &type, bool negated=false) const; exprt simplify_sum(const exprt &f) const; - exprt get_array(const exprt &arr, const exprt &size); + void concretize_results(); + void concretize_lengths(); + // Length of char arrays found during concretization + std::map found_length; + + exprt get_array(const exprt &arr, const exprt &size) const; + exprt get_array(const exprt &arr) const; - std::string string_of_array(const exprt &arr, const exprt &size) const; + std::string string_of_array(const array_exprt &arr); }; #endif From a31a4eb17eca788fe24ebc45158895fb6fecb005 Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Wed, 22 Mar 2017 15:05:40 +0000 Subject: [PATCH 27/52] Need to assign length before calls since it can be overwritten by functions with side-effect --- src/goto-programs/string_refine_preprocess.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/goto-programs/string_refine_preprocess.cpp b/src/goto-programs/string_refine_preprocess.cpp index 8403d4bf044..7243f66049a 100644 --- a/src/goto-programs/string_refine_preprocess.cpp +++ b/src/goto-programs/string_refine_preprocess.cpp @@ -361,7 +361,16 @@ exprt string_refine_preprocesst::make_cprover_string_assign( std::list assignments; // 1) cprover_string_length= *(rhs->length) + symbolt sym_length=get_fresh_aux_symbol( + length_type, + "cprover_string_length", + "cprover_string_length", + location, + ID_java, + symbol_table); + symbol_exprt cprover_length=sym_length.symbol_expr(); member_exprt length(deref, "length", length_type); + assignments.emplace_back(cprover_length, length); // 2) cprover_string_array = *(rhs->data) symbol_exprt array_lhs=fresh_array(data_type.subtype(), location); @@ -373,7 +382,7 @@ exprt string_refine_preprocesst::make_cprover_string_assign( // This assignment is useful for finding witnessing strings for counter // examples refined_string_typet ref_type(length_type, java_char_type()); - string_exprt new_rhs(length, array_lhs, ref_type); + string_exprt new_rhs(cprover_length, array_lhs, ref_type); symbol_exprt lhs=fresh_string(new_rhs.type(), location); assignments.emplace_back(lhs, new_rhs); From fa35841810d0d156c7a454912b75570f43e157d0 Mon Sep 17 00:00:00 2001 From: Joel Allred Date: Thu, 23 Mar 2017 15:05:27 +0000 Subject: [PATCH 28/52] const refs and clean up Corrections on PR 675 requested by Peter Schrammel --- src/goto-programs/string_refine_preprocess.cpp | 10 ++++++---- .../refinement/string_constraint_generator_main.cpp | 12 ++++++++++++ src/solvers/refinement/string_refinement.h | 3 --- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/goto-programs/string_refine_preprocess.cpp b/src/goto-programs/string_refine_preprocess.cpp index 7243f66049a..8b491bab0ab 100644 --- a/src/goto-programs/string_refine_preprocess.cpp +++ b/src/goto-programs/string_refine_preprocess.cpp @@ -809,11 +809,13 @@ void string_refine_preprocesst::make_string_function_side_effect( const irep_idt &function_name, const std::string &signature) { + // Cannot use const & here code_function_callt function_call=to_code_function_call(target->code); source_locationt loc=function_call.source_location(); std::list assignments; - exprt lhs=function_call.lhs(); - exprt s=function_call.arguments()[0]; + const exprt &lhs=function_call.lhs(); + assert(!function_call.arguments().empty()); + const exprt &s=function_call.arguments()[0]; code_typet function_type=to_code_type(function_call.type()); function_type.return_type()=s.type(); @@ -901,7 +903,7 @@ void string_refine_preprocesst::make_to_char_array_function( const code_function_callt &function_call=to_code_function_call(target->code); source_locationt location=function_call.source_location(); - assert(function_call.arguments().size()>=1); + assert(!function_call.arguments().empty()); const exprt &string_argument=function_call.arguments()[0]; assert(is_java_string_pointer_type(string_argument.type())); @@ -985,7 +987,7 @@ exprt::operandst string_refine_preprocesst::process_arguments( arg=typecast_exprt(arg, jls_ptr); } arg=make_cprover_string_assign(goto_program, target, arg, location); - typet type=ns.follow(arg.type()); + const typet &type=ns.follow(arg.type()); if(is_java_char_array_pointer_type(type)) { arg=make_cprover_char_array_assign(goto_program, target, arg, location); diff --git a/src/solvers/refinement/string_constraint_generator_main.cpp b/src/solvers/refinement/string_constraint_generator_main.cpp index 0b87b9471a1..5c7f1b7647c 100644 --- a/src/solvers/refinement/string_constraint_generator_main.cpp +++ b/src/solvers/refinement/string_constraint_generator_main.cpp @@ -153,6 +153,18 @@ string_exprt string_constraint_generatort::get_string_expr(const exprt &expr) } } +/*******************************************************************\ + +Function: string_constraint_generatort::convert_java_string_to_string_exprt + + Inputs: a java string + + Outputs: a string expression + + Purpose: create a new string_exprt as a conversion of a java string + +\*******************************************************************/ + string_exprt string_constraint_generatort::convert_java_string_to_string_exprt( const exprt &jls) { diff --git a/src/solvers/refinement/string_refinement.h b/src/solvers/refinement/string_refinement.h index 134154af09b..fe77cda6010 100644 --- a/src/solvers/refinement/string_refinement.h +++ b/src/solvers/refinement/string_refinement.h @@ -70,9 +70,6 @@ class string_refinementt: public bv_refinementt unsigned initial_loop_bound; - // Is the current model correct - bool concrete_model; - string_constraint_generatort generator; // Simple constraints that have been given to the solver From 201e79ec2877b17f3b96dcf6c15e56308045c39b Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Mon, 27 Feb 2017 10:40:20 +0000 Subject: [PATCH 29/52] Adding refined_string_type to util Makefile --- src/util/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util/Makefile b/src/util/Makefile index cff6340e044..6a94cabdb88 100644 --- a/src/util/Makefile +++ b/src/util/Makefile @@ -43,6 +43,7 @@ SRC = arith_tools.cpp \ message.cpp \ mp_arith.cpp \ namespace.cpp \ + nondet_ifthenelse.cpp \ options.cpp \ parse_options.cpp \ parser.cpp \ @@ -52,6 +53,7 @@ SRC = arith_tools.cpp \ rational.cpp \ rational_tools.cpp \ ref_expr_set.cpp \ + refined_string_type.cpp \ rename.cpp \ rename_symbol.cpp \ replace_expr.cpp \ From f954a86d0baa3fd8186d4f6b7d817510153106cd Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Tue, 10 Jan 2017 13:42:48 +0000 Subject: [PATCH 30/52] Adding string preprocessing of goto-programs to Makefile --- src/goto-programs/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/goto-programs/Makefile b/src/goto-programs/Makefile index 6e2bd969e57..d93c93d5b7d 100644 --- a/src/goto-programs/Makefile +++ b/src/goto-programs/Makefile @@ -57,6 +57,7 @@ SRC = basic_blocks.cpp \ slice_global_inits.cpp \ string_abstraction.cpp \ string_instrumentation.cpp \ + string_refine_preprocess.cpp \ system_library_symbols.cpp \ vcd_goto_trace.cpp \ wp.cpp \ From 1eee9092a75ed15c4ff2928d3e76fed5e1c27b9b Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Tue, 10 Jan 2017 13:43:30 +0000 Subject: [PATCH 31/52] Adding string solver cpp files to Makefile --- src/solvers/Makefile | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/solvers/Makefile b/src/solvers/Makefile index 108718ccb75..3f3465277a3 100644 --- a/src/solvers/Makefile +++ b/src/solvers/Makefile @@ -158,6 +158,17 @@ SRC = $(BOOLEFORCE_SRC) \ refinement/bv_refinement_loop.cpp \ refinement/refine_arithmetic.cpp \ refinement/refine_arrays.cpp \ + refinement/string_refinement.cpp \ + refinement/string_constraint_generator_code_points.cpp \ + refinement/string_constraint_generator_comparison.cpp \ + refinement/string_constraint_generator_concat.cpp \ + refinement/string_constraint_generator_constants.cpp \ + refinement/string_constraint_generator_indexof.cpp \ + refinement/string_constraint_generator_insert.cpp \ + refinement/string_constraint_generator_main.cpp \ + refinement/string_constraint_generator_testing.cpp \ + refinement/string_constraint_generator_transformation.cpp \ + refinement/string_constraint_generator_valueof.cpp \ sat/cnf.cpp \ sat/cnf_clause_list.cpp \ sat/dimacs_cnf.cpp \ From 2b34b4e7143d04ab10ec68dec13717ad20e4474a Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Tue, 10 Jan 2017 13:36:33 +0000 Subject: [PATCH 32/52] Adding the string refinement option to the CBMC solvers We add the option `--string-refine` which can be used to activate the string solver, in order to deal precisely with string functions. --- src/cbmc/cbmc_parse_options.cpp | 15 +++++++++++++++ src/cbmc/cbmc_parse_options.h | 1 + src/cbmc/cbmc_solvers.cpp | 1 + src/cbmc/cbmc_solvers.h | 13 ++++++++----- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/cbmc/cbmc_parse_options.cpp b/src/cbmc/cbmc_parse_options.cpp index d2f1c178d8e..01d811d86c1 100644 --- a/src/cbmc/cbmc_parse_options.cpp +++ b/src/cbmc/cbmc_parse_options.cpp @@ -24,6 +24,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include #include #include @@ -288,6 +289,11 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options) options.set_option("refine-arithmetic", true); } + if(cmdline.isset("string-refine")) + { + options.set_option("string-refine", true); + } + if(cmdline.isset("max-node-refinement")) options.set_option( "max-node-refinement", @@ -811,6 +817,14 @@ bool cbmc_parse_optionst::process_goto_program( status() << "Partial Inlining" << eom; goto_partial_inline(goto_functions, ns, ui_message_handler); + + if(cmdline.isset("string-refine")) + { + status() << "Preprocessing for string refinement" << eom; + string_refine_preprocesst( + symbol_table, goto_functions, ui_message_handler); + } + // remove returns, gcc vectors, complex remove_returns(symbol_table, goto_functions); remove_vector(symbol_table, goto_functions); @@ -1070,6 +1084,7 @@ void cbmc_parse_optionst::help() " --yices use Yices\n" " --z3 use Z3\n" " --refine use refinement procedure (experimental)\n" + " --string-refine use string refinement (experimental)\n" " --outfile filename output formula to given file\n" " --arrays-uf-never never turn arrays into uninterpreted functions\n" // NOLINT(*) " --arrays-uf-always always turn arrays into uninterpreted functions\n" // NOLINT(*) diff --git a/src/cbmc/cbmc_parse_options.h b/src/cbmc/cbmc_parse_options.h index d95e60eb25b..53e7d0aa3c6 100644 --- a/src/cbmc/cbmc_parse_options.h +++ b/src/cbmc/cbmc_parse_options.h @@ -41,6 +41,7 @@ class optionst; "(no-sat-preprocessor)" \ "(no-pretty-names)(beautify)" \ "(dimacs)(refine)(max-node-refinement):(refine-arrays)(refine-arithmetic)"\ + "(string-refine)" \ "(aig)(16)(32)(64)(LP64)(ILP64)(LLP64)(ILP32)(LP32)" \ "(little-endian)(big-endian)" \ "(show-goto-functions)(show-loops)" \ diff --git a/src/cbmc/cbmc_solvers.cpp b/src/cbmc/cbmc_solvers.cpp index 2fb47bf2396..5111d21b346 100644 --- a/src/cbmc/cbmc_solvers.cpp +++ b/src/cbmc/cbmc_solvers.cpp @@ -17,6 +17,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include #include #include diff --git a/src/cbmc/cbmc_solvers.h b/src/cbmc/cbmc_solvers.h index 9bc51021039..a391ed0c1cc 100644 --- a/src/cbmc/cbmc_solvers.h +++ b/src/cbmc/cbmc_solvers.h @@ -108,15 +108,17 @@ class cbmc_solverst:public messaget solvert *solver; if(options.get_bool_option("dimacs")) - solver = get_dimacs(); + solver=get_dimacs(); else if(options.get_bool_option("refine")) - solver = get_bv_refinement(); + solver=get_bv_refinement(); + else if(options.get_bool_option("string-refine")) + solver=get_string_refinement(); else if(options.get_bool_option("smt1")) - solver = get_smt1(get_smt1_solver_type()); + solver=get_smt1(get_smt1_solver_type()); else if(options.get_bool_option("smt2")) - solver = get_smt2(get_smt2_solver_type()); + solver=get_smt2(get_smt2_solver_type()); else - solver = get_default(); + solver=get_default(); return std::unique_ptr(solver); } @@ -138,6 +140,7 @@ class cbmc_solverst:public messaget solvert *get_default(); solvert *get_dimacs(); solvert *get_bv_refinement(); + solvert *get_string_refinement(); solvert *get_smt1(smt1_dect::solvert solver); solvert *get_smt2(smt2_dect::solvert solver); From 7ecb16fb5704d30fafaa67c57baee88aabb44422 Mon Sep 17 00:00:00 2001 From: Joel Allred Date: Thu, 23 Mar 2017 18:18:14 +0000 Subject: [PATCH 33/52] Change option name to --refine-strings --- src/cbmc/cbmc_parse_options.cpp | 8 ++++---- src/cbmc/cbmc_parse_options.h | 2 +- src/cbmc/cbmc_solvers.h | 2 +- src/java_bytecode/java_bytecode_language.cpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cbmc/cbmc_parse_options.cpp b/src/cbmc/cbmc_parse_options.cpp index 01d811d86c1..bda681dd730 100644 --- a/src/cbmc/cbmc_parse_options.cpp +++ b/src/cbmc/cbmc_parse_options.cpp @@ -289,9 +289,9 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options) options.set_option("refine-arithmetic", true); } - if(cmdline.isset("string-refine")) + if(cmdline.isset("refine-strings")) { - options.set_option("string-refine", true); + options.set_option("refine-strings", true); } if(cmdline.isset("max-node-refinement")) @@ -818,7 +818,7 @@ bool cbmc_parse_optionst::process_goto_program( goto_partial_inline(goto_functions, ns, ui_message_handler); - if(cmdline.isset("string-refine")) + if(cmdline.isset("refine-strings")) { status() << "Preprocessing for string refinement" << eom; string_refine_preprocesst( @@ -1084,7 +1084,7 @@ void cbmc_parse_optionst::help() " --yices use Yices\n" " --z3 use Z3\n" " --refine use refinement procedure (experimental)\n" - " --string-refine use string refinement (experimental)\n" + " --refine-strings use string refinement (experimental)\n" " --outfile filename output formula to given file\n" " --arrays-uf-never never turn arrays into uninterpreted functions\n" // NOLINT(*) " --arrays-uf-always always turn arrays into uninterpreted functions\n" // NOLINT(*) diff --git a/src/cbmc/cbmc_parse_options.h b/src/cbmc/cbmc_parse_options.h index 53e7d0aa3c6..c713b2ca470 100644 --- a/src/cbmc/cbmc_parse_options.h +++ b/src/cbmc/cbmc_parse_options.h @@ -41,7 +41,7 @@ class optionst; "(no-sat-preprocessor)" \ "(no-pretty-names)(beautify)" \ "(dimacs)(refine)(max-node-refinement):(refine-arrays)(refine-arithmetic)"\ - "(string-refine)" \ + "(refine-strings)" \ "(aig)(16)(32)(64)(LP64)(ILP64)(LLP64)(ILP32)(LP32)" \ "(little-endian)(big-endian)" \ "(show-goto-functions)(show-loops)" \ diff --git a/src/cbmc/cbmc_solvers.h b/src/cbmc/cbmc_solvers.h index a391ed0c1cc..f17f9b663bf 100644 --- a/src/cbmc/cbmc_solvers.h +++ b/src/cbmc/cbmc_solvers.h @@ -111,7 +111,7 @@ class cbmc_solverst:public messaget solver=get_dimacs(); else if(options.get_bool_option("refine")) solver=get_bv_refinement(); - else if(options.get_bool_option("string-refine")) + else if(options.get_bool_option("refine-strings")) solver=get_string_refinement(); else if(options.get_bool_option("smt1")) solver=get_smt1(get_smt1_solver_type()); diff --git a/src/java_bytecode/java_bytecode_language.cpp b/src/java_bytecode/java_bytecode_language.cpp index 85205c7525d..b7b97f32b14 100644 --- a/src/java_bytecode/java_bytecode_language.cpp +++ b/src/java_bytecode/java_bytecode_language.cpp @@ -35,7 +35,7 @@ Author: Daniel Kroening, kroening@kroening.com void java_bytecode_languaget::get_language_options(const cmdlinet &cmd) { assume_inputs_non_null=cmd.isset("java-assume-inputs-non-null"); - string_refinement_enabled=cmd.isset("string-refine"); + string_refinement_enabled=cmd.isset("refine-strings"); if(cmd.isset("java-max-input-array-length")) max_nondet_array_length= std::stoi(cmd.get_value("java-max-input-array-length")); From 591a8db43bd15a96fcb6a6a5c8df4fd0fbac9eb6 Mon Sep 17 00:00:00 2001 From: Joel Allred Date: Fri, 24 Feb 2017 17:36:40 +0000 Subject: [PATCH 34/52] Restructuration of tests on strings Add test java_intern Adapt test.desc to new output format Make more robust java tests. Add test for parseint. Correction in the hacks to use refined strings in C programs Add smoke tests for java string support Quick set of tests. Created by modifying the existing development tests. Longer tests are run when using 'make testall'. Format of java files was adapted. No change to the validation tests (written by Lucas Cordeiro). Update smoke tests Add a series of performance tests that check that the negation of the assertions found in the smoke tests indeed fail. Update java_char_array_init/test_init.class Add first fixed_bugs test For bug #95 Update test description with new option name String refinement option name has changed to --refine-strings Formatting in cprover-string-hack.h Move smoke tests to regression folder. Move fixed bugs tests to strings folder Move string perfomance tests to strings directory These are not really performance tests, only tests that are longer than the smoke tests. Adapt Makefile for new location of smoke tests --- regression/strings-smoke-tests/Makefile | 9 ++ .../java_append_char/test.desc | 7 ++ .../java_append_char/test_append_char.class | Bin 0 -> 999 bytes .../java_append_char/test_append_char.java | 17 ++++ .../java_append_int/test.desc | 7 ++ .../java_append_int/test_append_int.class | Bin 0 -> 842 bytes .../java_append_int/test_append_int.java | 11 +++ .../java_append_object/test.desc | 7 ++ .../test_append_object.class | Bin 0 -> 992 bytes .../test_append_object.java | 17 ++++ .../java_append_string/test.desc | 7 ++ .../test_append_string.class | Bin 0 -> 1032 bytes .../test_append_string.java | 14 +++ .../strings-smoke-tests/java_case/test.desc | 7 ++ .../java_case/test_case.class | Bin 0 -> 865 bytes .../java_case/test_case.java | 12 +++ .../java_char_array/test.desc | 7 ++ .../java_char_array/test_char_array.class | Bin 0 -> 714 bytes .../java_char_array/test_char_array.java | 13 +++ .../java_char_array_init/test.desc | 7 ++ .../java_char_array_init/test_init.class | Bin 0 -> 1046 bytes .../java_char_array_init/test_init.java | 21 ++++ .../java_char_at/test.desc | 7 ++ .../java_char_at/test_char_at.class | Bin 0 -> 628 bytes .../java_char_at/test_char_at.java | 7 ++ .../java_code_point/test.desc | 7 ++ .../java_code_point/test_code_point.class | Bin 0 -> 999 bytes .../java_code_point/test_code_point.java | 14 +++ .../java_compare/test.desc | 7 ++ .../java_compare/test_compare.class | Bin 0 -> 623 bytes .../java_compare/test_compare.java | 9 ++ .../strings-smoke-tests/java_concat/test.desc | 8 ++ .../java_concat/test_concat.class | Bin 0 -> 798 bytes .../java_concat/test_concat.java | 13 +++ .../java_contains/test.desc | 8 ++ .../java_contains/test_contains.class | Bin 0 -> 716 bytes .../java_contains/test_contains.java | 11 +++ .../strings-smoke-tests/java_delete/test.desc | 7 ++ .../java_delete/test_delete.class | Bin 0 -> 943 bytes .../java_delete/test_delete.java | 10 ++ .../java_delete_char_at/test.desc | 7 ++ .../test_delete_char_at.class | Bin 0 -> 867 bytes .../test_delete_char_at.java | 11 +++ .../strings-smoke-tests/java_empty/test.desc | 7 ++ .../java_empty/test_empty.class | Bin 0 -> 571 bytes .../java_empty/test_empty.java | 8 ++ .../java_endswith/test.desc | 8 ++ .../java_endswith/test_endswith.class | Bin 0 -> 711 bytes .../java_endswith/test_endswith.java | 12 +++ .../strings-smoke-tests/java_equal/test.desc | 8 ++ .../java_equal/test_equal.class | Bin 0 -> 725 bytes .../java_equal/test_equal.java | 11 +++ .../strings-smoke-tests/java_float/test.desc | 7 ++ .../java_float/test_float.class | Bin 0 -> 965 bytes .../java_float/test_float.java | 15 +++ .../java_hash_code/test.desc | 8 ++ .../java_hash_code/test_hash_code.class | Bin 0 -> 650 bytes .../java_hash_code/test_hash_code.java | 11 +++ .../java_index_of/test.desc | 7 ++ .../java_index_of/test_index_of.class | Bin 0 -> 631 bytes .../java_index_of/test_index_of.java | 10 ++ .../java_index_of_char/test.desc | 7 ++ .../test_index_of_char.class | Bin 0 -> 614 bytes .../test_index_of_char.java | 10 ++ .../java_insert_char/test.desc | 7 ++ .../java_insert_char/test_insert_char.class | Bin 0 -> 811 bytes .../java_insert_char/test_insert_char.java | 10 ++ .../java_insert_char_array/test.desc | 7 ++ .../test_insert_char_array.class | Bin 0 -> 979 bytes .../test_insert_char_array.java | 14 +++ .../java_insert_int/test.desc | 7 ++ .../java_insert_int/test_insert_int.class | Bin 0 -> 810 bytes .../java_insert_int/test_insert_int.java | 10 ++ .../.test_insert.java.swp | Bin 0 -> 12288 bytes .../java_insert_multiple/test.desc | 7 ++ .../test_insert_multiple.class | Bin 0 -> 898 bytes .../test_insert_multiple.java | 11 +++ .../java_insert_string/test.desc | 7 ++ .../test_insert_string.class | Bin 0 -> 841 bytes .../test_insert_string.java | 10 ++ .../java_int_to_string/test.desc | 7 ++ .../java_int_to_string/test_int.class | Bin 0 -> 859 bytes .../java_int_to_string/test_int.java | 11 +++ .../strings-smoke-tests/java_intern/test.desc | 7 ++ .../java_intern/test_intern.class | Bin 0 -> 634 bytes .../java_intern/test_intern.java | 11 +++ .../java_last_index_of/test.desc | 7 ++ .../test_last_index_of.class | Bin 0 -> 647 bytes .../test_last_index_of.java | 10 ++ .../java_last_index_of_char/test.desc | 7 ++ .../test_last_index_of_char.class | Bin 0 -> 623 bytes .../test_last_index_of_char.java | 9 ++ .../strings-smoke-tests/java_length/test.desc | 7 ++ .../java_length/test_length.class | Bin 0 -> 630 bytes .../java_length/test_length.java | 9 ++ .../java_parseint/test.desc | 8 ++ .../java_parseint/test_parseint.class | Bin 0 -> 727 bytes .../java_parseint/test_parseint.java | 10 ++ .../java_replace/test.desc | 7 ++ .../java_replace/test_replace.class | Bin 0 -> 980 bytes .../java_replace/test_replace.java | 13 +++ .../java_replace_char/test.desc | 7 ++ .../java_replace_char/test_replace_char.class | Bin 0 -> 730 bytes .../java_replace_char/test_replace_char.java | 9 ++ .../java_set_char_at/test.desc | 7 ++ .../java_set_char_at/test_set_char_at.class | Bin 0 -> 874 bytes .../java_set_char_at/test_set_char_at.java | 13 +++ .../java_set_length/test.desc | 9 ++ .../java_set_length/test_set_length.class | Bin 0 -> 861 bytes .../java_set_length/test_set_length.java | 12 +++ .../java_starts_with/test.desc | 8 ++ .../java_starts_with/test_starts_with.class | Bin 0 -> 719 bytes .../java_starts_with/test_starts_with.java | 11 +++ .../java_string_builder_length/test.desc | 7 ++ .../test_sb_length.class | Bin 0 -> 722 bytes .../test_sb_length.java | 9 ++ .../java_subsequence/test.desc | 7 ++ .../java_subsequence/test_subsequence.class | Bin 0 -> 789 bytes .../java_subsequence/test_subsequence.java | 14 +++ .../java_substring/test.desc | 7 ++ .../java_substring/test_substring.class | Bin 0 -> 740 bytes .../java_substring/test_substring.java | 14 +++ .../strings-smoke-tests/java_trim/test.desc | 8 ++ .../java_trim/test_trim.class | Bin 0 -> 641 bytes .../java_trim/test_trim.java | 9 ++ regression/strings/RegexMatches01/test.desc | 2 +- regression/strings/RegexMatches02/test.desc | 2 +- .../strings/RegexSubstitution01/test.desc | 2 +- .../strings/RegexSubstitution02/test.desc | 2 +- .../strings/RegexSubstitution03/test.desc | 2 +- .../strings/StaticCharMethods01/test.desc | 2 +- .../strings/StaticCharMethods02/test.desc | 2 +- .../strings/StaticCharMethods03/test.desc | 2 +- .../strings/StaticCharMethods04/test.desc | 2 +- .../strings/StaticCharMethods05/test.desc | 2 +- .../strings/StaticCharMethods06/test.desc | 2 +- .../strings/StringBuilderAppend01/test.desc | 2 +- .../strings/StringBuilderAppend02/test.desc | 2 +- .../strings/StringBuilderCapLen01/test.desc | 2 +- .../strings/StringBuilderCapLen02/test.desc | 2 +- .../strings/StringBuilderCapLen03/test.desc | 2 +- .../strings/StringBuilderCapLen04/test.desc | 2 +- .../strings/StringBuilderChars01/test.desc | 2 +- .../strings/StringBuilderChars02/test.desc | 2 +- .../strings/StringBuilderChars03/test.desc | 2 +- .../strings/StringBuilderChars04/test.desc | 2 +- .../strings/StringBuilderChars05/test.desc | 2 +- .../strings/StringBuilderChars06/test.desc | 2 +- .../StringBuilderConstructors01/test.desc | 2 +- .../StringBuilderConstructors02/test.desc | 2 +- .../StringBuilderInsertDelete01/test.desc | 2 +- .../StringBuilderInsertDelete02/test.desc | 2 +- .../StringBuilderInsertDelete03/test.desc | 2 +- regression/strings/StringCompare01/test.desc | 2 +- regression/strings/StringCompare02/test.desc | 2 +- regression/strings/StringCompare03/test.desc | 2 +- regression/strings/StringCompare04/test.desc | 2 +- regression/strings/StringCompare05/test.desc | 2 +- .../strings/StringConcatenation01/test.desc | 2 +- .../strings/StringConcatenation02/test.desc | 2 +- .../strings/StringConcatenation03/test.desc | 2 +- .../strings/StringConcatenation04/test.desc | 2 +- .../strings/StringConstructors01/test.desc | 2 +- .../strings/StringConstructors02/test.desc | 2 +- .../strings/StringConstructors03/test.desc | 2 +- .../strings/StringConstructors04/test.desc | 2 +- .../strings/StringConstructors05/test.desc | 2 +- .../strings/StringIndexMethods01/test.desc | 2 +- .../strings/StringIndexMethods02/test.desc | 2 +- .../strings/StringIndexMethods03/test.desc | 2 +- .../strings/StringIndexMethods04/test.desc | 2 +- .../strings/StringIndexMethods05/test.desc | 2 +- .../strings/StringMiscellaneous01/test.desc | 2 +- .../strings/StringMiscellaneous02/test.desc | 2 +- .../strings/StringMiscellaneous03/test.desc | 2 +- .../strings/StringMiscellaneous04/test.desc | 2 +- regression/strings/StringStartEnd01/test.desc | 2 +- regression/strings/StringStartEnd02/test.desc | 2 +- regression/strings/StringStartEnd03/test.desc | 2 +- regression/strings/StringValueOf01/test.desc | 2 +- regression/strings/StringValueOf02/test.desc | 2 +- regression/strings/StringValueOf03/test.desc | 2 +- regression/strings/StringValueOf04/test.desc | 2 +- regression/strings/StringValueOf05/test.desc | 2 +- regression/strings/StringValueOf06/test.desc | 2 +- regression/strings/StringValueOf07/test.desc | 2 +- regression/strings/StringValueOf08/test.desc | 2 +- regression/strings/StringValueOf09/test.desc | 2 +- regression/strings/StringValueOf10/test.desc | 2 +- regression/strings/SubString01/test.desc | 2 +- regression/strings/SubString02/test.desc | 2 +- regression/strings/SubString03/test.desc | 2 +- regression/strings/TokenTest01/test.desc | 2 +- regression/strings/TokenTest02/test.desc | 2 +- regression/strings/Validate01/test.desc | 2 +- regression/strings/Validate02/test.desc | 2 +- .../strings/bug-test-gen-095/test.class | Bin 0 -> 822 bytes regression/strings/bug-test-gen-095/test.desc | 7 ++ regression/strings/bug-test-gen-095/test.java | 10 ++ regression/strings/cprover-string-hack.h | 90 ++++++++++++------ regression/strings/java_append_char/test.desc | 7 ++ .../java_append_char/test_append_char.class | Bin 0 -> 999 bytes .../java_append_char/test_append_char.java | 17 ++++ regression/strings/java_append_int/test.desc | 7 ++ .../java_append_int/test_append_int.class | Bin 0 -> 842 bytes .../java_append_int/test_append_int.java | 11 +++ .../strings/java_append_object/test.desc | 7 ++ .../test_append_object.class | Bin 0 -> 992 bytes .../test_append_object.java | 17 ++++ .../strings/java_append_string/test.desc | 7 ++ .../test_append_string.class | Bin 0 -> 1032 bytes .../test_append_string.java | 14 +++ regression/strings/java_case/test.desc | 7 +- regression/strings/java_case/test_case.class | Bin 1073 -> 839 bytes regression/strings/java_case/test_case.java | 26 +++-- regression/strings/java_char_array/test.desc | 6 +- .../java_char_array/test_char_array.class | Bin 820 -> 676 bytes .../java_char_array/test_char_array.java | 26 +++-- .../strings/java_char_array_init/test.desc | 8 +- .../java_char_array_init/test_init.class | Bin 1209 -> 836 bytes .../java_char_array_init/test_init.java | 33 +++---- regression/strings/java_char_at/test.desc | 6 +- .../strings/java_char_at/test_char_at.class | Bin 951 -> 628 bytes .../strings/java_char_at/test_char_at.java | 18 +--- regression/strings/java_code_point/test.desc | 10 +- .../java_code_point/test_code_point.class | Bin 1025 -> 941 bytes .../java_code_point/test_code_point.java | 25 ++--- regression/strings/java_compare/test.desc | 7 +- .../strings/java_compare/test_compare.class | Bin 780 -> 623 bytes .../strings/java_compare/test_compare.java | 25 ++--- regression/strings/java_concat/test.desc | 6 +- .../strings/java_concat/test_concat.class | Bin 854 -> 798 bytes .../strings/java_concat/test_concat.java | 23 ++--- regression/strings/java_contains/test.desc | 5 +- .../strings/java_contains/test_contains.class | Bin 753 -> 671 bytes .../strings/java_contains/test_contains.java | 17 ++-- regression/strings/java_delete/test.desc | 5 +- .../strings/java_delete/test_delete.class | Bin 1126 -> 800 bytes .../strings/java_delete/test_delete.java | 23 ++--- .../strings/java_delete_char_at/test.desc | 7 ++ .../test_delete_char_at.class | Bin 0 -> 867 bytes .../test_delete_char_at.java | 11 +++ .../strings/java_easychair/easychair.class | Bin 1164 -> 1163 bytes .../strings/java_easychair/easychair.java | 62 ++++++------ regression/strings/java_easychair/test.desc | 6 +- regression/strings/java_empty/test.desc | 5 +- .../strings/java_empty/test_empty.class | Bin 669 -> 571 bytes regression/strings/java_empty/test_empty.java | 13 +-- regression/strings/java_endswith/test.desc | 7 ++ .../strings/java_endswith/test_endswith.class | Bin 0 -> 666 bytes .../strings/java_endswith/test_endswith.java | 9 ++ regression/strings/java_equal/test.desc | 5 +- .../strings/java_equal/test_equal.class | Bin 726 -> 725 bytes regression/strings/java_equal/test_equal.java | 17 ++-- regression/strings/java_float/test.desc | 7 +- .../strings/java_float/test_float.class | Bin 1095 -> 1015 bytes regression/strings/java_float/test_float.java | 35 ++++--- regression/strings/java_hash_code/test.desc | 7 ++ .../java_hash_code/test_hash_code.class | Bin 0 -> 602 bytes .../java_hash_code/test_hash_code.java | 9 ++ regression/strings/java_index_of/test.desc | 13 +-- .../strings/java_index_of/test_index_of.class | Bin 1108 -> 631 bytes .../strings/java_index_of/test_index_of.java | 40 ++------ .../strings/java_index_of_char/test.desc | 7 ++ .../test_index_of_char.class | Bin 0 -> 614 bytes .../test_index_of_char.java | 10 ++ .../strings/java_insert/test_insert.class | Bin 1318 -> 0 bytes .../strings/java_insert/test_insert.java | 19 ---- .../strings/java_insert/test_insert1.class | Bin 1035 -> 0 bytes .../strings/java_insert/test_insert1.java | 23 ----- regression/strings/java_insert_char/test.desc | 7 ++ .../java_insert_char/test_insert_char.class | Bin 0 -> 811 bytes .../java_insert_char/test_insert_char.java | 10 ++ .../strings/java_insert_char_array/test.desc | 7 ++ .../test_insert_char_array.class | Bin 0 -> 979 bytes .../test_insert_char_array.java | 14 +++ regression/strings/java_insert_int/test.desc | 7 ++ .../java_insert_int/test_insert_int.class | Bin 0 -> 810 bytes .../java_insert_int/test_insert_int.java | 10 ++ .../strings/java_insert_multiple/test.desc | 7 ++ .../test_insert_multiple.class | Bin 0 -> 898 bytes .../test_insert_multiple.java | 11 +++ .../strings/java_insert_string/test.desc | 7 ++ .../test_insert_string.class | Bin 0 -> 841 bytes .../test_insert_string.java | 10 ++ regression/strings/java_int/test.desc | 13 --- regression/strings/java_int/test_int.class | Bin 1140 -> 0 bytes regression/strings/java_int/test_int.java | 25 ----- regression/strings/java_prefix/test.desc | 10 -- .../strings/java_prefix/test_prefix.class | Bin 933 -> 0 bytes .../strings/java_prefix/test_prefix.java | 23 ----- regression/strings/java_replace/test.desc | 8 -- .../strings/java_replace/test_replace.class | Bin 904 -> 0 bytes .../strings/java_replace/test_replace.java | 10 -- regression/strings/java_set_length/test.desc | 9 -- .../java_set_length/test_set_length.class | Bin 887 -> 0 bytes .../java_set_length/test_set_length.java | 12 --- .../strings/java_string_builder/test.desc | 9 -- .../test_string_builder.class | Bin 1003 -> 0 bytes .../test_string_builder.java | 16 ---- .../java_string_builder_insert/test.desc | 8 -- .../test_insert.class | Bin 1049 -> 0 bytes .../test_insert.java | 20 ---- .../java_string_builder_length/test.desc | 8 -- .../test_sb_length.class | Bin 791 -> 0 bytes .../test_sb_length.java | 11 --- regression/strings/java_strlen/test.desc | 8 -- .../strings/java_strlen/test_length.class | Bin 864 -> 0 bytes .../strings/java_strlen/test_length.java | 14 --- regression/strings/java_substring/test.desc | 10 -- .../java_substring/test_substring.class | Bin 1051 -> 0 bytes .../java_substring/test_substring.java | 27 ------ regression/strings/java_suffix/test.desc | 8 -- .../strings/java_suffix/test_suffix.class | Bin 811 -> 0 bytes .../strings/java_suffix/test_suffix.java | 15 --- regression/strings/java_trim/test.desc | 8 -- regression/strings/java_trim/test_trim.class | Bin 730 -> 0 bytes regression/strings/java_trim/test_trim.java | 8 -- regression/strings/test1/test.desc | 2 +- regression/strings/test2/test.desc | 2 +- regression/strings/test3.1/test.desc | 2 +- regression/strings/test3.2/test.desc | 2 +- regression/strings/test3.3/test.desc | 2 +- regression/strings/test3.4/test.desc | 8 +- regression/strings/test3/test.desc | 2 +- regression/strings/test4/test.desc | 2 +- regression/strings/test5/test.desc | 2 +- regression/strings/test_char_set/test.desc | 6 +- regression/strings/test_concat/test.desc | 2 +- regression/strings/test_contains/test.desc | 2 +- regression/strings/test_equal/test.desc | 6 +- regression/strings/test_index_of/test.desc | 2 +- regression/strings/test_int/test.desc | 2 +- regression/strings/test_pass1/test.desc | 2 +- regression/strings/test_pass_pc3/test.desc | 2 +- regression/strings/test_prefix/test.desc | 2 +- regression/strings/test_strlen/test.desc | 2 +- regression/strings/test_substring/test.desc | 10 +- regression/strings/test_suffix/test.desc | 2 +- 339 files changed, 1402 insertions(+), 738 deletions(-) create mode 100644 regression/strings-smoke-tests/Makefile create mode 100644 regression/strings-smoke-tests/java_append_char/test.desc create mode 100644 regression/strings-smoke-tests/java_append_char/test_append_char.class create mode 100644 regression/strings-smoke-tests/java_append_char/test_append_char.java create mode 100644 regression/strings-smoke-tests/java_append_int/test.desc create mode 100644 regression/strings-smoke-tests/java_append_int/test_append_int.class create mode 100644 regression/strings-smoke-tests/java_append_int/test_append_int.java create mode 100644 regression/strings-smoke-tests/java_append_object/test.desc create mode 100644 regression/strings-smoke-tests/java_append_object/test_append_object.class create mode 100644 regression/strings-smoke-tests/java_append_object/test_append_object.java create mode 100644 regression/strings-smoke-tests/java_append_string/test.desc create mode 100644 regression/strings-smoke-tests/java_append_string/test_append_string.class create mode 100644 regression/strings-smoke-tests/java_append_string/test_append_string.java create mode 100644 regression/strings-smoke-tests/java_case/test.desc create mode 100644 regression/strings-smoke-tests/java_case/test_case.class create mode 100644 regression/strings-smoke-tests/java_case/test_case.java create mode 100644 regression/strings-smoke-tests/java_char_array/test.desc create mode 100644 regression/strings-smoke-tests/java_char_array/test_char_array.class create mode 100644 regression/strings-smoke-tests/java_char_array/test_char_array.java create mode 100644 regression/strings-smoke-tests/java_char_array_init/test.desc create mode 100644 regression/strings-smoke-tests/java_char_array_init/test_init.class create mode 100644 regression/strings-smoke-tests/java_char_array_init/test_init.java create mode 100644 regression/strings-smoke-tests/java_char_at/test.desc create mode 100644 regression/strings-smoke-tests/java_char_at/test_char_at.class create mode 100644 regression/strings-smoke-tests/java_char_at/test_char_at.java create mode 100644 regression/strings-smoke-tests/java_code_point/test.desc create mode 100644 regression/strings-smoke-tests/java_code_point/test_code_point.class create mode 100644 regression/strings-smoke-tests/java_code_point/test_code_point.java create mode 100644 regression/strings-smoke-tests/java_compare/test.desc create mode 100644 regression/strings-smoke-tests/java_compare/test_compare.class create mode 100644 regression/strings-smoke-tests/java_compare/test_compare.java create mode 100644 regression/strings-smoke-tests/java_concat/test.desc create mode 100644 regression/strings-smoke-tests/java_concat/test_concat.class create mode 100644 regression/strings-smoke-tests/java_concat/test_concat.java create mode 100644 regression/strings-smoke-tests/java_contains/test.desc create mode 100644 regression/strings-smoke-tests/java_contains/test_contains.class create mode 100644 regression/strings-smoke-tests/java_contains/test_contains.java create mode 100644 regression/strings-smoke-tests/java_delete/test.desc create mode 100644 regression/strings-smoke-tests/java_delete/test_delete.class create mode 100644 regression/strings-smoke-tests/java_delete/test_delete.java create mode 100644 regression/strings-smoke-tests/java_delete_char_at/test.desc create mode 100644 regression/strings-smoke-tests/java_delete_char_at/test_delete_char_at.class create mode 100644 regression/strings-smoke-tests/java_delete_char_at/test_delete_char_at.java create mode 100644 regression/strings-smoke-tests/java_empty/test.desc create mode 100644 regression/strings-smoke-tests/java_empty/test_empty.class create mode 100644 regression/strings-smoke-tests/java_empty/test_empty.java create mode 100644 regression/strings-smoke-tests/java_endswith/test.desc create mode 100644 regression/strings-smoke-tests/java_endswith/test_endswith.class create mode 100644 regression/strings-smoke-tests/java_endswith/test_endswith.java create mode 100644 regression/strings-smoke-tests/java_equal/test.desc create mode 100644 regression/strings-smoke-tests/java_equal/test_equal.class create mode 100644 regression/strings-smoke-tests/java_equal/test_equal.java create mode 100644 regression/strings-smoke-tests/java_float/test.desc create mode 100644 regression/strings-smoke-tests/java_float/test_float.class create mode 100644 regression/strings-smoke-tests/java_float/test_float.java create mode 100644 regression/strings-smoke-tests/java_hash_code/test.desc create mode 100644 regression/strings-smoke-tests/java_hash_code/test_hash_code.class create mode 100644 regression/strings-smoke-tests/java_hash_code/test_hash_code.java create mode 100644 regression/strings-smoke-tests/java_index_of/test.desc create mode 100644 regression/strings-smoke-tests/java_index_of/test_index_of.class create mode 100644 regression/strings-smoke-tests/java_index_of/test_index_of.java create mode 100644 regression/strings-smoke-tests/java_index_of_char/test.desc create mode 100644 regression/strings-smoke-tests/java_index_of_char/test_index_of_char.class create mode 100644 regression/strings-smoke-tests/java_index_of_char/test_index_of_char.java create mode 100644 regression/strings-smoke-tests/java_insert_char/test.desc create mode 100644 regression/strings-smoke-tests/java_insert_char/test_insert_char.class create mode 100644 regression/strings-smoke-tests/java_insert_char/test_insert_char.java create mode 100644 regression/strings-smoke-tests/java_insert_char_array/test.desc create mode 100644 regression/strings-smoke-tests/java_insert_char_array/test_insert_char_array.class create mode 100644 regression/strings-smoke-tests/java_insert_char_array/test_insert_char_array.java create mode 100644 regression/strings-smoke-tests/java_insert_int/test.desc create mode 100644 regression/strings-smoke-tests/java_insert_int/test_insert_int.class create mode 100644 regression/strings-smoke-tests/java_insert_int/test_insert_int.java create mode 100644 regression/strings-smoke-tests/java_insert_multiple/.test_insert.java.swp create mode 100644 regression/strings-smoke-tests/java_insert_multiple/test.desc create mode 100644 regression/strings-smoke-tests/java_insert_multiple/test_insert_multiple.class create mode 100644 regression/strings-smoke-tests/java_insert_multiple/test_insert_multiple.java create mode 100644 regression/strings-smoke-tests/java_insert_string/test.desc create mode 100644 regression/strings-smoke-tests/java_insert_string/test_insert_string.class create mode 100644 regression/strings-smoke-tests/java_insert_string/test_insert_string.java create mode 100644 regression/strings-smoke-tests/java_int_to_string/test.desc create mode 100644 regression/strings-smoke-tests/java_int_to_string/test_int.class create mode 100644 regression/strings-smoke-tests/java_int_to_string/test_int.java create mode 100644 regression/strings-smoke-tests/java_intern/test.desc create mode 100644 regression/strings-smoke-tests/java_intern/test_intern.class create mode 100644 regression/strings-smoke-tests/java_intern/test_intern.java create mode 100644 regression/strings-smoke-tests/java_last_index_of/test.desc create mode 100644 regression/strings-smoke-tests/java_last_index_of/test_last_index_of.class create mode 100644 regression/strings-smoke-tests/java_last_index_of/test_last_index_of.java create mode 100644 regression/strings-smoke-tests/java_last_index_of_char/test.desc create mode 100644 regression/strings-smoke-tests/java_last_index_of_char/test_last_index_of_char.class create mode 100644 regression/strings-smoke-tests/java_last_index_of_char/test_last_index_of_char.java create mode 100644 regression/strings-smoke-tests/java_length/test.desc create mode 100644 regression/strings-smoke-tests/java_length/test_length.class create mode 100644 regression/strings-smoke-tests/java_length/test_length.java create mode 100644 regression/strings-smoke-tests/java_parseint/test.desc create mode 100644 regression/strings-smoke-tests/java_parseint/test_parseint.class create mode 100644 regression/strings-smoke-tests/java_parseint/test_parseint.java create mode 100644 regression/strings-smoke-tests/java_replace/test.desc create mode 100644 regression/strings-smoke-tests/java_replace/test_replace.class create mode 100644 regression/strings-smoke-tests/java_replace/test_replace.java create mode 100644 regression/strings-smoke-tests/java_replace_char/test.desc create mode 100644 regression/strings-smoke-tests/java_replace_char/test_replace_char.class create mode 100644 regression/strings-smoke-tests/java_replace_char/test_replace_char.java create mode 100644 regression/strings-smoke-tests/java_set_char_at/test.desc create mode 100644 regression/strings-smoke-tests/java_set_char_at/test_set_char_at.class create mode 100644 regression/strings-smoke-tests/java_set_char_at/test_set_char_at.java create mode 100644 regression/strings-smoke-tests/java_set_length/test.desc create mode 100644 regression/strings-smoke-tests/java_set_length/test_set_length.class create mode 100644 regression/strings-smoke-tests/java_set_length/test_set_length.java create mode 100644 regression/strings-smoke-tests/java_starts_with/test.desc create mode 100644 regression/strings-smoke-tests/java_starts_with/test_starts_with.class create mode 100644 regression/strings-smoke-tests/java_starts_with/test_starts_with.java create mode 100644 regression/strings-smoke-tests/java_string_builder_length/test.desc create mode 100644 regression/strings-smoke-tests/java_string_builder_length/test_sb_length.class create mode 100644 regression/strings-smoke-tests/java_string_builder_length/test_sb_length.java create mode 100644 regression/strings-smoke-tests/java_subsequence/test.desc create mode 100644 regression/strings-smoke-tests/java_subsequence/test_subsequence.class create mode 100644 regression/strings-smoke-tests/java_subsequence/test_subsequence.java create mode 100644 regression/strings-smoke-tests/java_substring/test.desc create mode 100644 regression/strings-smoke-tests/java_substring/test_substring.class create mode 100644 regression/strings-smoke-tests/java_substring/test_substring.java create mode 100644 regression/strings-smoke-tests/java_trim/test.desc create mode 100644 regression/strings-smoke-tests/java_trim/test_trim.class create mode 100644 regression/strings-smoke-tests/java_trim/test_trim.java create mode 100644 regression/strings/bug-test-gen-095/test.class create mode 100644 regression/strings/bug-test-gen-095/test.desc create mode 100644 regression/strings/bug-test-gen-095/test.java create mode 100644 regression/strings/java_append_char/test.desc create mode 100644 regression/strings/java_append_char/test_append_char.class create mode 100644 regression/strings/java_append_char/test_append_char.java create mode 100644 regression/strings/java_append_int/test.desc create mode 100644 regression/strings/java_append_int/test_append_int.class create mode 100644 regression/strings/java_append_int/test_append_int.java create mode 100644 regression/strings/java_append_object/test.desc create mode 100644 regression/strings/java_append_object/test_append_object.class create mode 100644 regression/strings/java_append_object/test_append_object.java create mode 100644 regression/strings/java_append_string/test.desc create mode 100644 regression/strings/java_append_string/test_append_string.class create mode 100644 regression/strings/java_append_string/test_append_string.java create mode 100644 regression/strings/java_delete_char_at/test.desc create mode 100644 regression/strings/java_delete_char_at/test_delete_char_at.class create mode 100644 regression/strings/java_delete_char_at/test_delete_char_at.java create mode 100644 regression/strings/java_endswith/test.desc create mode 100644 regression/strings/java_endswith/test_endswith.class create mode 100644 regression/strings/java_endswith/test_endswith.java create mode 100644 regression/strings/java_hash_code/test.desc create mode 100644 regression/strings/java_hash_code/test_hash_code.class create mode 100644 regression/strings/java_hash_code/test_hash_code.java create mode 100644 regression/strings/java_index_of_char/test.desc create mode 100644 regression/strings/java_index_of_char/test_index_of_char.class create mode 100644 regression/strings/java_index_of_char/test_index_of_char.java delete mode 100644 regression/strings/java_insert/test_insert.class delete mode 100644 regression/strings/java_insert/test_insert.java delete mode 100644 regression/strings/java_insert/test_insert1.class delete mode 100644 regression/strings/java_insert/test_insert1.java create mode 100644 regression/strings/java_insert_char/test.desc create mode 100644 regression/strings/java_insert_char/test_insert_char.class create mode 100644 regression/strings/java_insert_char/test_insert_char.java create mode 100644 regression/strings/java_insert_char_array/test.desc create mode 100644 regression/strings/java_insert_char_array/test_insert_char_array.class create mode 100644 regression/strings/java_insert_char_array/test_insert_char_array.java create mode 100644 regression/strings/java_insert_int/test.desc create mode 100644 regression/strings/java_insert_int/test_insert_int.class create mode 100644 regression/strings/java_insert_int/test_insert_int.java create mode 100644 regression/strings/java_insert_multiple/test.desc create mode 100644 regression/strings/java_insert_multiple/test_insert_multiple.class create mode 100644 regression/strings/java_insert_multiple/test_insert_multiple.java create mode 100644 regression/strings/java_insert_string/test.desc create mode 100644 regression/strings/java_insert_string/test_insert_string.class create mode 100644 regression/strings/java_insert_string/test_insert_string.java delete mode 100644 regression/strings/java_int/test.desc delete mode 100644 regression/strings/java_int/test_int.class delete mode 100644 regression/strings/java_int/test_int.java delete mode 100644 regression/strings/java_prefix/test.desc delete mode 100644 regression/strings/java_prefix/test_prefix.class delete mode 100644 regression/strings/java_prefix/test_prefix.java delete mode 100644 regression/strings/java_replace/test.desc delete mode 100644 regression/strings/java_replace/test_replace.class delete mode 100644 regression/strings/java_replace/test_replace.java delete mode 100644 regression/strings/java_set_length/test.desc delete mode 100644 regression/strings/java_set_length/test_set_length.class delete mode 100644 regression/strings/java_set_length/test_set_length.java delete mode 100644 regression/strings/java_string_builder/test.desc delete mode 100644 regression/strings/java_string_builder/test_string_builder.class delete mode 100644 regression/strings/java_string_builder/test_string_builder.java delete mode 100644 regression/strings/java_string_builder_insert/test.desc delete mode 100644 regression/strings/java_string_builder_insert/test_insert.class delete mode 100644 regression/strings/java_string_builder_insert/test_insert.java delete mode 100644 regression/strings/java_string_builder_length/test.desc delete mode 100644 regression/strings/java_string_builder_length/test_sb_length.class delete mode 100644 regression/strings/java_string_builder_length/test_sb_length.java delete mode 100644 regression/strings/java_strlen/test.desc delete mode 100644 regression/strings/java_strlen/test_length.class delete mode 100644 regression/strings/java_strlen/test_length.java delete mode 100644 regression/strings/java_substring/test.desc delete mode 100644 regression/strings/java_substring/test_substring.class delete mode 100644 regression/strings/java_substring/test_substring.java delete mode 100644 regression/strings/java_suffix/test.desc delete mode 100644 regression/strings/java_suffix/test_suffix.class delete mode 100644 regression/strings/java_suffix/test_suffix.java delete mode 100644 regression/strings/java_trim/test.desc delete mode 100644 regression/strings/java_trim/test_trim.class delete mode 100644 regression/strings/java_trim/test_trim.java diff --git a/regression/strings-smoke-tests/Makefile b/regression/strings-smoke-tests/Makefile new file mode 100644 index 00000000000..c41ab1c5be8 --- /dev/null +++ b/regression/strings-smoke-tests/Makefile @@ -0,0 +1,9 @@ + +test: + @../test.pl -c ../../../src/cbmc/cbmc + +testfuture: + @../test.pl -c ../../../src/cbmc/cbmc -CF + +testall: + @../test.pl -c ../../../src/cbmc/cbmc -CFTK diff --git a/regression/strings-smoke-tests/java_append_char/test.desc b/regression/strings-smoke-tests/java_append_char/test.desc new file mode 100644 index 00000000000..0f1b3ae243f --- /dev/null +++ b/regression/strings-smoke-tests/java_append_char/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_append_char.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_append_char/test_append_char.class b/regression/strings-smoke-tests/java_append_char/test_append_char.class new file mode 100644 index 0000000000000000000000000000000000000000..00c40aef6f6514f718dc1137889e4124d8bd7230 GIT binary patch literal 999 zcmZWnYf}Wo2Pz(&a;H%@8%{2WMdqwzlljUYhBz_y_u& z&ES+xeeXwA?}3!mVR?7YbKcAIyzl$#_qQJa7O0Ha)#&34?)cGDMe5+w_+i!nyow z2BqW}f+4wP+F~PU)`a^?I@3i{H*JQ#vai?Qt?R80%uyg-9PEZyEIlzrEP5Y% z?TWh35ZWr8z`M+-Q(X}Z+1yqszt#&pLA^-ieCH@;ICs{OJpQX%{^3CdNX=QrVhY9OGl*1Mmr!w z93#iBU!l+sXz=fmYB*(7s!GbNR3oWIr5Yvkyo=W)Zb>|lxTvfhB2+y*hO46R8 z9~&f4khoFuN`w8OgTj&NJm)yh6CA^ZV;Kt_X~4i>UmN{<;L0Z`;V+2wDjunq86ya3 ME3!uy=@3HpFJ~^+h5!Hn literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_append_char/test_append_char.java b/regression/strings-smoke-tests/java_append_char/test_append_char.java new file mode 100644 index 00000000000..3eec4f30abe --- /dev/null +++ b/regression/strings-smoke-tests/java_append_char/test_append_char.java @@ -0,0 +1,17 @@ +public class test_append_char +{ + public static void main(/*String[] args*/) + { + char[] diff = {'d', 'i', 'f', 'f'}; + char[] blue = {'b', 'l', 'u', 'e'}; + + StringBuilder buffer = new StringBuilder(); + + buffer.append(diff) + .append(blue); + + String tmp=buffer.toString(); + System.out.println(tmp); + assert tmp.equals("diffblue"); + } +} diff --git a/regression/strings-smoke-tests/java_append_int/test.desc b/regression/strings-smoke-tests/java_append_int/test.desc new file mode 100644 index 00000000000..e1455859470 --- /dev/null +++ b/regression/strings-smoke-tests/java_append_int/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_append_int.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_append_int/test_append_int.class b/regression/strings-smoke-tests/java_append_int/test_append_int.class new file mode 100644 index 0000000000000000000000000000000000000000..16948397e03dc279cdae32b41c8692bcfbb44978 GIT binary patch literal 842 zcmaJfgc5Pjo(*l`@3rfC~W0~87*DQ!pza7cxK0upKphaf6?shoIKxwv+)9ezyy z0B1l-B`U$4{{&*zX&Rssmzmx9c<=4Z{`mFv8-OMr=rB=Maao6gvW6?tUzKKAnrj*4 za9zWSjvKhC;+BrAEU)OOqNZY%FuP)fp$H06*g4eQ`6GxWg5ptc#>b={s`f->gsklwhHhb= zJ{tlrC>n5r_qm5<{uw6!A%$q`b!HFbpaZfyj${TbR2#nnP)1bv9?39?*he3!UNjJwFlOa_g; z36*0S7MZ019SfYvf_|c*qNL(toSNut#)5#ELT-c$L#WA*NG85On_^EiOPmxGo@H<&=ME&u=k literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_append_int/test_append_int.java b/regression/strings-smoke-tests/java_append_int/test_append_int.java new file mode 100644 index 00000000000..963f3d7c063 --- /dev/null +++ b/regression/strings-smoke-tests/java_append_int/test_append_int.java @@ -0,0 +1,11 @@ +public class test_append_int +{ + public static void main(/*String[] args*/) + { + StringBuilder diffblue = new StringBuilder(); + diffblue.append("d"); + diffblue.append(4); + String s = diffblue.toString(); + assert s.equals("d4"); + } +} diff --git a/regression/strings-smoke-tests/java_append_object/test.desc b/regression/strings-smoke-tests/java_append_object/test.desc new file mode 100644 index 00000000000..5db2ac1db73 --- /dev/null +++ b/regression/strings-smoke-tests/java_append_object/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_append_object.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_append_object/test_append_object.class b/regression/strings-smoke-tests/java_append_object/test_append_object.class new file mode 100644 index 0000000000000000000000000000000000000000..ed6942a1fa6ddb20c36b528444d598e867e347f5 GIT binary patch literal 992 zcmZWn*>2N76g`t|9M@^mbPIb6p(Jh7u#`2SEAT>Ekb*$;rE=nF<>J`E3ld+!dwzgt zij+!Jf_FX&xZ{wfX=VG4=gygP&s~21`SBCLGB#C=VMf8Mg6kYNRKzeNOy5|YkHyzu1W_o(V5(Wd?VMtU>+w@l$ zqJ`pHhS;WK2!?dcw8eJNY6$m@1k*uFH*JPg-PfBRw)A%BCT`NjagRZ%Hm(0mYTXIk zrg&k>d(*z~{9V1>7PhhLG!8`5Upmk~=^7?5NwkK!w?|9E3M5#blr7!fFV}t7wD&gx z(=vpsQ8Dgocz}l-k2E~S6OM|8DxPY{Vw|E&8p%OgG^}8iAvfS!@8|y9bsd)>dtMXA znuc|3Fk}YzUWIapTs>J-wq8aIr9$oOg-Y?1YbcKjDfOK`$3)>gkPxQ?)IWQ^Xi;yR zz-O53(V9;AHPyx^8lku7!gwfP*v-J(5@b=&CQnQ31+U0nC&b4R*arn|^=z++z#i++bXh}h3bGR6_n)@0^aX%oS3C;sZb6 zvzWArB>L`05%-x=nuO#a7V$IhB!u~xT_+U z#5g82Rt39^(lGmdgsB>X^rZf@eAwv7}=eD^i=&(T@S*Y>9GN$12tsvh8v!tx;@v zp6f9fmsu)U*Rg@k4vw!6j(90x=+AApi#3VQ%h@HGjWSIAE8tSjc|Y?V7{$+iz$>&3 zwq1gq5#mx#O^o97HW(K7ygKXMT2g4@qkf9p5twCpU3$v|8snFx&xNnE=K{X(fx^1V1kWY>r`5PNxw_-+GtBn zT|1;t)}fyub&SlU(OpN+F}hBXrnKH)5-$?sjS&)&fJVp$6v9+-lWb#T$)gK1(6NOS zu2WPu*crAI3@NxlGK_4sGaK>-dJUtFzGEn{uZTszBh`j#wI)l&5z&|B0B+Gw1jBy- DqWB3A~sECS)t!#oa~!3s1iJ ztR|4yMBn{Ujc0ZRv^JTXnK|b>=ljl?`E~sL2Y@ObsYoF&vG34ZOeUXx<+Tfdkn125ZyK{(|gPy z6^d^d!gagH84?ZC;x9&r9qzmmUrp2(-^o;JiePigmNf?8&-5va?p*HQ2)8)@i zk+JM?*L&MFT)uf=d@wYmkzq)Rb7f#y{YukwOsmfj+Uba3MZ-9{$7mvU9+@9z&+kSdEEkp53rN za;HwR8PbK~|1cl)dN`bcqWt~H7`P{D21Hv$8gViJ?Dj3&;X&b3=?R)xh^i0h$r!Rd z?wSto&D*92@J1A%_iAH}K0%6p3QOk1$mk@2WFtd1OSe_p8SRnM6zq!t;tbiS@1$WN zH-~@)+r|u1pXcBYp(6HAVbq;NH-+)7&L}X@cdy z(1JhY^XDPcIYK`+N)5;)SV5W8)X3999A_z-gmjFujB~-tW(jkCuD0rT0HpN91j#Yv a@MnajZ;%%xvnEBc2twKuF^UVmhSlFL=B-Bn literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_case/test_case.java b/regression/strings-smoke-tests/java_case/test_case.java new file mode 100644 index 00000000000..b3437a6f83e --- /dev/null +++ b/regression/strings-smoke-tests/java_case/test_case.java @@ -0,0 +1,12 @@ +public class test_case +{ + public static void main(/*String[] argv*/) + { + String s = new String("Ab"); + String l = s.toLowerCase(); + String u = s.toUpperCase(); + assert(l.equals("ab")); + assert(u.equals("AB")); + assert(s.equalsIgnoreCase("aB")); + } +} diff --git a/regression/strings-smoke-tests/java_char_array/test.desc b/regression/strings-smoke-tests/java_char_array/test.desc new file mode 100644 index 00000000000..ecce56c1ab8 --- /dev/null +++ b/regression/strings-smoke-tests/java_char_array/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_char_array.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_char_array/test_char_array.class b/regression/strings-smoke-tests/java_char_array/test_char_array.class new file mode 100644 index 0000000000000000000000000000000000000000..0d2056042ca2ef3063d717972cfe8bf0f7b0d053 GIT binary patch literal 714 zcmZXR%Wl&^6o&t?9gpL zsgPK*2BcI1sqA?u;EbUOm(7`(|J=TF=G*trX8=05?ZQRP!6g@$aYdV@A{^8?uDY;M zAm|?D;iSXr9@hX=&Zg8wJI2+;UcNw>zj8!NfMLKCAlWBGkz7Xm_C?($9 zITEjhhdInsKQRa?-@{F;dANm!hY~!7nvPi?iTH56d(Qk&sYDUgKjk=@9$IKK__L&) z!I2EJzodSqqWF-(*zYlvvZO~qUCl#dHJVzqHDi~utj6Oez00$Dy%DXBVR0zaNXg-p zi58KK$w7PD!!m8&rEg(=O;15L6SOSMlP%M$PA8+Y&^iVCpabEPwR4f7h{`ndEeu%X z+o>8)S`(OC?Ly~X%bdX4{D{H{D(y4-9ZFwd@1BBx{iW4?@t?Njhkt0gsgXBbAyy(G zLYr=!XdP4uVT~rZOZ3~MR4F2W`GZ7@Bj8wIgdYSHdSOc1$?1Vg)tR7p0&cyBWqv|o U*6VygU9SMcyRX-9GGO8l5EOL`WQzE66TtyO1T~q{01u{YH(2aiY&)ZWg+BA* zqt9ZpC1Uj5KgdVoxt)xWm^SB}d(U^y{m$3h--q9S0+_)g4JnLpjB1GBf;1Ns7{etQ zUDj{~nFI`sb7VCnFd}y*;+T}_t8q+8pX0cu;X0-{ZZPzXnZ7T)z;Ydb!Sc;5TT~g? z21Bf1IaV;s5Y3FgU{H!~RWKx1Ek``5*S3WBT!JZ4GcAXqyA+s}H*4l@xXm#`BpKp` ziv6#RR&wiJMJ!pes3#D9@JeQ;cFcFCjsc_@3>oKa)7j3I0?%@`<^D}+ZgJe!aR+yG z+(VwDpyNJfb@ZX1Veq(Y{%Dv*&vQKqdcY77wvIW>GpNhLwp|?$QDjK8IdClKSj5r^ z22ZzkL?xi=O~R^~&7xF+lV4epQ76|AejsWjlv^kKz-maxa&ymUgn$MSW-U*8+QQim zUWa!(`wftN?slx6L0IL?bC6cfEMTcIDJ0N4@@ucUt03W z6QGu~At-sQT+ybBz>uyA-||GYEhK%`piT+81sfQp%ax*w$c#ZLJw;JaccjUlqSX+2 zMqbS}!M;i$2Fb?4O;Q}E+t5EysTlZVXg}1)*{HEx&MJl|XH~;4XJgWE!z~{mvQEvS zt6`w1O(<*oP$wFQHNf`~-$TD#7}{ra9U!sZg!Zci=pr}S067VoOz91D?{$L0+Eh;i z$&PKwIuf#;MUrBbo)|Q6TE%H(IfI5_bkVP+V;VguP^Lt}Y@in=$@8A1`AEn!RBa%7 zh!V$Hj&t;mrK!hITZ5TU7oay~G|;;Tu6%(K{f784i6iM`GZhhiP6|96ayK%)14Q&n}mKmr$g#`EUAH{(D5ZteiAqV6M)iiek3O!-J*I)@xy*=WYYtPjr? zU;CKDyoV}bd{M-))JAoq_=Ac?t0UV4IwEA&Riw-YAziC~Avle0TN1|hR3tz3E?QC_ zSTGkZgo+3wO(VkdkK$|c%mxVA^|156;WxWI9m;KGJBmie<~TeR`dFBEXX2X(Fp4ok z!Nw~c5uL0wjaJbKi;Grhs|x`Fj09N35}`80Z9cl+(z>e&!BcJzZvwnU?HTju)|m_q zpNZec+K=+eYVBr?2!&15rXZIJ}OO%)0Yh()H zcjRy39rls^ZHZC|(I__o4t%(%GVM5LSul S?9r7aaghq%TkjKz*5rTZxpr0n literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_char_at/test_char_at.java b/regression/strings-smoke-tests/java_char_at/test_char_at.java new file mode 100644 index 00000000000..3b8663d62ae --- /dev/null +++ b/regression/strings-smoke-tests/java_char_at/test_char_at.java @@ -0,0 +1,7 @@ +public class test_char_at { + + public static void main(/*String[] argv*/) { + String s = new String("abc"); + assert(s.charAt(2)=='c'); + } +} diff --git a/regression/strings-smoke-tests/java_code_point/test.desc b/regression/strings-smoke-tests/java_code_point/test.desc new file mode 100644 index 00000000000..012c7c3501b --- /dev/null +++ b/regression/strings-smoke-tests/java_code_point/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_code_point.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_code_point/test_code_point.class b/regression/strings-smoke-tests/java_code_point/test_code_point.class new file mode 100644 index 0000000000000000000000000000000000000000..1d5d2269325d6c4baed8f6c6f44326db9fc57985 GIT binary patch literal 999 zcmZuw+fEZv6kVsCOFJE)43|~`0Yz-7f+BbW2~ag@sF$QhBQIo_9&n({G&55ZUya5G zqaVPF#uuNxq$HB)yZ_)P@CU@W&q!NPU-rzbv-aA1?S1CQudm+#OkqxgfuR_N<4EG9 zhEo`cg2h!8r!^=T63D0sXGF-T$ZALkIDs*NPp=-qSeeMOe>-aZp z-(0QmG6P#?P-bn%4(1r5nd}1wDesm!Lr2ke_?_C;D);USG97H0w!_d?3QTMBwpk5f z73ZlsLu}Tn9LQ)Tx8_;=mMxOH1MUYa7D=vDUE2x9H_Rudjvn+f3=Z$Td$#xGWf-4_ z@ztUDLPr<6seq0Pm}E$c)QO7etWPX7tlacG*VAzklRAxUTE`_!Go)I~QsCLn`eMzl zlsOSE^x}tK2C!A%=buF18vvVrPbSXFWE(Mgw^g zXi@VOS~x>*nftcK%gvF|`hprA(6*N`O!v#6E60*)F>HFHdnUF+F-2bk^knpu$9BLz z3L?@Jl@Mfz<5-jWlTsse_Qr@TeL{2_J!4WGk|DoEVi(Gz9jMCVKkM3@B) zoAkSQ(D52=I8Lli$ouG1(U(f4_K{W5Pvn87)v3@v(Trpro!d~Q50Ijt5p7j#Oh~B7 Oi0JcTjwixq27d!;VcgOH literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_code_point/test_code_point.java b/regression/strings-smoke-tests/java_code_point/test_code_point.java new file mode 100644 index 00000000000..faf9a2051d5 --- /dev/null +++ b/regression/strings-smoke-tests/java_code_point/test_code_point.java @@ -0,0 +1,14 @@ +public class test_code_point +{ + public static void main(/*String[] argv*/) + { + String s = "!𐤇𐤄𐤋𐤋𐤅"; + assert(s.codePointAt(1) == 67847); + assert(s.codePointBefore(3) == 67847); + assert(s.codePointCount(1,5) >= 2); + assert(s.offsetByCodePoints(1,2) >= 3); + StringBuilder sb = new StringBuilder(); + sb.appendCodePoint(0x10907); + assert(s.charAt(1) == sb.charAt(0)); + } +} diff --git a/regression/strings-smoke-tests/java_compare/test.desc b/regression/strings-smoke-tests/java_compare/test.desc new file mode 100644 index 00000000000..38aa025f416 --- /dev/null +++ b/regression/strings-smoke-tests/java_compare/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_compare.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_compare/test_compare.class b/regression/strings-smoke-tests/java_compare/test_compare.class new file mode 100644 index 0000000000000000000000000000000000000000..3a807f4d203aecb2c12a4dab57637aeb3ded9359 GIT binary patch literal 623 zcmY*WO;6iE5Pjn~w&NH`%vTBxA1!SINaex}RJEcYA=37c2njCL##y1IiH+7ye+(Cn zoM|PHiqziuPgI?CA!)U%+1)oYZ{Ez_{r>S2z$O|#e9U^Nd3aKShdCefcB%mEjtS1TidFW8P-v_k66~F%D+v=#70Zu|@LS11M{-Y@jA|y+>~oa#&xDq*PsLXeU<~5~ zOLUCkXBh!g1bB`WLd}G1^hA8J@$OOVuGWbr1piXGcoE*OFyLUkD0g2fA12(5##(EJAb98+uS*C^T-DBr?4 zx`F%4a9BA<2%GOkF6i*$-)1QxBW2J%>MkaEGc+|Uu$dPHs-bs{(m7oF5_aJ`>=Eaq RF2hrV6}&a-r}L6Ce*kI)bz}el literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_compare/test_compare.java b/regression/strings-smoke-tests/java_compare/test_compare.java new file mode 100644 index 00000000000..c052ed429bd --- /dev/null +++ b/regression/strings-smoke-tests/java_compare/test_compare.java @@ -0,0 +1,9 @@ +public class test_compare +{ + public static void main(/*String[] argv*/) + { + String s1 = "ab"; + String s2 = "aa"; + assert(s1.compareTo(s2) == 1); + } +} diff --git a/regression/strings-smoke-tests/java_concat/test.desc b/regression/strings-smoke-tests/java_concat/test.desc new file mode 100644 index 00000000000..fb784efd723 --- /dev/null +++ b/regression/strings-smoke-tests/java_concat/test.desc @@ -0,0 +1,8 @@ +FUTURE +test_concat.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 10.* SUCCESS$ +^\[.*assertion.2\].* line 11.* FAILURE$ +-- diff --git a/regression/strings-smoke-tests/java_concat/test_concat.class b/regression/strings-smoke-tests/java_concat/test_concat.class new file mode 100644 index 0000000000000000000000000000000000000000..e4143c157737bffffa1af323a7918a12ba9a88e1 GIT binary patch literal 798 zcmZuvT~E_s6n;+Eu3cAP42MHR1aWQ?m>N(KXzlg$}NALZ(`KO;B4wR}iLl zTwm<TqMg{z+g&?M!_0 zwirRJZr56TzcEb9#GCkdu#Ip7!TCX z$eo~AQVZdGq3I-Q~5>`oJmtnB2@n4o@wmRn6Ut|&$j%*^27rf0ZSCpXq z;((^(GVv!Bcz}WOi0wwY0We*(2ADX3u6~4?`GVXS?R-f&QG;SVlBbwU$z1sjB)pi= literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_concat/test_concat.java b/regression/strings-smoke-tests/java_concat/test_concat.java new file mode 100644 index 00000000000..b9909c723d4 --- /dev/null +++ b/regression/strings-smoke-tests/java_concat/test_concat.java @@ -0,0 +1,13 @@ +public class test_concat +{ + public static void main(/*String[] argv*/) + { + String s = new String("pi"); + int i = s.length(); + String t = new String("ppo"); + String u = s.concat(t); + char c = u.charAt(i); + assert(c == 'p'); + assert(c == 'o'); + } +} diff --git a/regression/strings-smoke-tests/java_contains/test.desc b/regression/strings-smoke-tests/java_contains/test.desc new file mode 100644 index 00000000000..2b96346d718 --- /dev/null +++ b/regression/strings-smoke-tests/java_contains/test.desc @@ -0,0 +1,8 @@ +FUTURE +test_contains.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 8.* SUCCESS$ +^\[.*assertion.2\].* line 9.* FAILURE$ +-- diff --git a/regression/strings-smoke-tests/java_contains/test_contains.class b/regression/strings-smoke-tests/java_contains/test_contains.class new file mode 100644 index 0000000000000000000000000000000000000000..adf0ece000a23e9f4fd98803c8c74cbbf0aec72e GIT binary patch literal 716 zcmY*W!EVz)5Pf4OvEw)-aYzX*1qvli(n2r2H6W@07g9K+s?=W4+F2F1sSUQnkq^la za0aACq7vNssES#)Nr<$X-JLfx@6F8Lt6#qX?BJ<|B9;xTn7C&_!>WnrBm+|Wt&T##9O>Q z3;oKeI%Cf-p&dE;1ev!^w&&#bf4~@{+TOf?IY!|U`J)M}KR4d3MX#dJQi^3JVP05# z7h$j_6AdQpu&2gI3ECAJ29~Z*jo~{pEjy_`pyCuRV2@#Bz9FOkgfXu_Z9&z_LbG40 JM(Zj4-GA+{itGRY literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_contains/test_contains.java b/regression/strings-smoke-tests/java_contains/test_contains.java new file mode 100644 index 00000000000..5112c344c09 --- /dev/null +++ b/regression/strings-smoke-tests/java_contains/test_contains.java @@ -0,0 +1,11 @@ +public class test_contains +{ + public static void main(/*String[] argv*/) + { + String s = new String("Abc"); + String u = "bc"; + String t = "ab"; + assert(s.contains(u)); + assert(s.contains(t)); + } +} diff --git a/regression/strings-smoke-tests/java_delete/test.desc b/regression/strings-smoke-tests/java_delete/test.desc new file mode 100644 index 00000000000..27a1406cdb7 --- /dev/null +++ b/regression/strings-smoke-tests/java_delete/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_delete.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_delete/test_delete.class b/regression/strings-smoke-tests/java_delete/test_delete.class new file mode 100644 index 0000000000000000000000000000000000000000..f18891851b1e69aae1bc9416dd3316dab6c8e3b1 GIT binary patch literal 943 zcmZuv+iuf95IvjQ#*W+O+J-`aLV=_S4VRQ#0yHfkRZ0OV2-Na`9D7x{IB~HZBz`47 zz%xZkBr3r>{{&(-X_{Vm*|BHNoIP`Pe*gXP6F>!PD&n}raXE?w6#-n4$5nYOD!7L0 zDsCXJU>b!emQ)l`;<%|olRe8S%DBaGn<2HRd!BH8%jtN}EKhIQ!en6E43V1EvHT|t z!F=H@LulPG1;b3k>WG)!c1yT#B$x_q-RdyR=HEAV_0M|Q);l}prteyvovLh{YWlkI zaZ}$L;z=;a9foMlun+mwrqgu|@xqd9abI};2UFO>7t4}QLkekzxzpThUCTCwOY-V1 zLxS#VK*K{k;;3q<$w~rAhCtn*yEQxpO_iMx*2fM!cU^}VW5+abJk_v@ zIw_kpylU+V!#|N44a|_q|KEkkXe5SQeq*C>26H$~m5lM7F;_Z&7D$L=LYiMZU$n^s zr%Q4&BU;NTzb5y6q7izV8d5{$C({gkPl9ZEx`_DH)ot&T_|cHn0jU4ZyxhAZF=|43i8B z=8&at33aJ8NO9!=fvse4fKa0t3ilCySL`FQxes3IBf1Zzhjb~a_7UqLb^vW_fT>@S zIxwW3Cvv(ED#Zji<)WlQp^Z^-jw&&*Kd5lbbDXErg(Inzp(Y@aobF?$2Oj#0Q1CmH U3HMmGcd;12=iei~s-t literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_delete/test_delete.java b/regression/strings-smoke-tests/java_delete/test_delete.java new file mode 100644 index 00000000000..13bd09cd075 --- /dev/null +++ b/regression/strings-smoke-tests/java_delete/test_delete.java @@ -0,0 +1,10 @@ +public class test_delete +{ + public static void main(/*String[] argv*/) + { + StringBuilder s = new StringBuilder("Abc"); + s.delete(1,2); + String str = s.toString(); + assert(str.equals("Ac")); + } +} diff --git a/regression/strings-smoke-tests/java_delete_char_at/test.desc b/regression/strings-smoke-tests/java_delete_char_at/test.desc new file mode 100644 index 00000000000..94ba56a2c54 --- /dev/null +++ b/regression/strings-smoke-tests/java_delete_char_at/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_delete_char_at.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_delete_char_at/test_delete_char_at.class b/regression/strings-smoke-tests/java_delete_char_at/test_delete_char_at.class new file mode 100644 index 0000000000000000000000000000000000000000..cfd8561e5960688dd28ec9e722c7353b57d35ec8 GIT binary patch literal 867 zcmaJ*MY z8C=z{s^c22tGJ;fE#Va%Rn%0hF%(vL5C}iCJvVr42fXhHi-GMjB)4qW4j(YYD%Cd( z@omo%4B3wDikHKKzVKg5FeMJS?J{J#AvfQ@;Dabkl2qJe(6&tHm`3kjF9Of95wn;S&+(wfM%m~`k2A}x8M+}Ak)K+oFz+K#9$ju(U>hB9P{3kRKL&M>N zfpBS3>y^&z!6e(No(dhSZ!s8?p0}yxHc>BEo}Go(LT_5JSUC+OzNGjtZ4Bn4QVnc4*fO3zi6MUsxw|q0NOuO3UeZx0cBUdzYFNbJqp$pz%ZUDiQAzF;g*US&?OKL zd+gmsZGkyLYNJ~J)v(LWR#27u$}rMehWbi2?)1a@jd$-ka44(72yaLue( z_x$VP_MgYSAZP{zyRRUy=wQjx=4N)dMu(3^A^_Rn1ss?Mz~6WzTgUEIUDVXmLf@DBr7^d cwISkEV8K4z{bqS3qCAUGc(nlKcs)a zwVKcb65acwi1!W9rVEpocfapB_ujwfr@sMg;<1e~76oouxNXD0l7%}K?iNwPJ#8-w z+_zEGDGzL{;GsZ^P+#$qM8>HaM#&46c>X|!1UeuTx++rXGlJP(eMiXc3`0q%^i(9@ zjE;R7ztzbcIQCRTDECt@__XVN&fH9cV0DARWe>YQ9L0frrF4ax$|U_DqcHiZ(vMG$ zyf2=EDr$tP);9)Tbhyz^V-+28`)xl6b@&m%2$-AU2M(^G;-HOHLUUHKeKpC;I3C7K zX%0uA<6sTzb0~ZMkqlBoqurbJxq#l%Q(KzlduI8c6y8&1R=6|ZWfB%bnW$KXQ$DNhSmIrj7n z#=dJ#kbCXsdv0O(C&U=_&e{pAF-m7B?oVLx= z;+}l3G?kyqB>f~m4@B@UA9;WfY!zHDhgGcI;r`G)k-d~qsr`QtD{CydmoTo{tnGEuSY-?qZLNCyn? zP7krfPvh~!QL(BgU@r$|L6OfHzAdmNw)xc&=(|otiBBsF5(+5eA^SS@E0>yVcP?QZ zlyW1O?aa%ww_D2Z{eU$@d985)dx)t^I0qvX{*0rI=G~}PGBTxk)?#^X(_$qXbNu@> zS+~WJ3L`#@D>QA)j=u`SbGO}ZWNiX7CHDeTL)hjwn7N;@Cj2*(Xs$dA?~R_fn#n)9 E2H7QzvH$=8 literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_equal/test_equal.java b/regression/strings-smoke-tests/java_equal/test_equal.java new file mode 100644 index 00000000000..a3acb0ebda5 --- /dev/null +++ b/regression/strings-smoke-tests/java_equal/test_equal.java @@ -0,0 +1,11 @@ +public class test_equal +{ + public static void main(String[] argv) + { + String s = new String("pi"); + String t = new String("po"); + String u = "po"; + assert(s.equals(t)); + assert(t.equals(u)); + } +} diff --git a/regression/strings-smoke-tests/java_float/test.desc b/regression/strings-smoke-tests/java_float/test.desc new file mode 100644 index 00000000000..427d1fca836 --- /dev/null +++ b/regression/strings-smoke-tests/java_float/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_float.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_float/test_float.class b/regression/strings-smoke-tests/java_float/test_float.class new file mode 100644 index 0000000000000000000000000000000000000000..e4448d415584df7b1d4015eaf7189dcde13f9c81 GIT binary patch literal 965 zcmZuwZBNrs6n<{k?RKSOqpH2 z{(zsw1dJx?CqMY3#B)1gpr*~ax6ggfInO!g_UEt9UjfYEfsO%8s5|cf^-!9f?|_bT zIG@A?OzN0IK8Z9gYPh81G720;9etS4FsYetQ@SjOC9keamWk@wbtNHqgwH3h}*BG?< zrt>F;-tanpQ`Btfkq$)=zFc=aD=cqXZ!H5u$Z}jaa053vW(?fIZH_wz?xJeI#2|^N zTXhO*U>0)>BhsznSnfvU(UJTm-}ih<`q*8UNw*o2rQTle<>Z(*a1T^jrWfYv+NNlR zr=UjY+wKO*?XhZ7Gvx@qqr+^WR$T58x-cm`5xTJ*grZF)cpdW1cG0gjXRb(dJRyID&jV|oa z0Zn?9Zcv)87r-(jvh}o!fyoJx&C%C5t&G*}(0flhDHkAc4 zwrHwLlb;Z;Pm!5b^U}umkSOhg??Kx|b~J7#_o45i?+f}~9KiS%;X@@e^&dDps+#?$ zaVbZMpofzz4gF+?=tmhtDyp)I3|6StS5)UHv4;^mL=_1|Q8>oBFOVB1 q*E7d8%|vwq17><3nO$)8J=EAoXuaG=t&lO}P>hGNVP_+0C#+nD+1t&jn^YIG7T6 z;b9hY0`r8*qD&GMr@9viSJ zDQ4hI>WDDjOl5ewE6=mEK%L+=!tQ?#ui5Lzq57yzM0=y4 zf+gD~@O2D6llWM`BB5qVHoG!9+I;tD_d^`_VnT70Okl~!GFAxXVb9n0i3-z^R5Oir zbi^Kwjfc^A&QCnxux-1`yCGCND$%j(43v4&w9f!Hv@p;6^?2)4t{Kn#mjiDDMUExD z&G1Ql=GX5)-%KIO9GxslC}3hxdI^i0fkt3`4y>IZxBDIT6{_pE$Zzm>jj>;F4(=fS z41t%UfKjkAg=yAcS!Q(j5v=5*&ha(d4HzlGx<_50^6=Ieo*Y=&%IpCXfqRR>6@+~Q YJNEgj507B+?5dZ)H literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_hash_code/test_hash_code.java b/regression/strings-smoke-tests/java_hash_code/test_hash_code.java new file mode 100644 index 00000000000..d9f42b7ff9d --- /dev/null +++ b/regression/strings-smoke-tests/java_hash_code/test_hash_code.java @@ -0,0 +1,11 @@ +public class test_hash_code +{ + public static void main(/*String[] argv*/) + { + String s1 = "ab"; + String s2 = "ab"; + String s3 = "aa"; + assert(s1.hashCode() == s2.hashCode()); + assert(s1.hashCode() == s3.hashCode()); + } +} diff --git a/regression/strings-smoke-tests/java_index_of/test.desc b/regression/strings-smoke-tests/java_index_of/test.desc new file mode 100644 index 00000000000..f2fa825597d --- /dev/null +++ b/regression/strings-smoke-tests/java_index_of/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_index_of.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_index_of/test_index_of.class b/regression/strings-smoke-tests/java_index_of/test_index_of.class new file mode 100644 index 0000000000000000000000000000000000000000..1acb3335d57d4664c88fb229efaf15666076d900 GIT binary patch literal 631 zcmY*WOHbQC5dOxoy^b-Em=aRTD=oAEq;la_Kt<3>RZ} zXQ%`cNc7$xg&4af5%OwxJu}~9cK$xx-UC=g(}s-+3v~-GZA{`-85X7lrfry*5SXzs zi#dS?VQk(@Q<-Ecj?!(FdVW`i1nLmXH5I9BgHUQNekbT#aVQC+EfvX~-ia@hy}Xzc zC!UH3!|luqj=y<7i?G0Jg0&WO|8v;wxR(U-v&s=}Cev(RMWOt)A0NCw@=iSm!x&+y zO+O%Le!zGKZ!qs*2o9m1*Q|8C=x}B8$?m5li4)d+MkcV};4R(}Dg(%_eQ zDmo;H!o}_ZVZ7NIApWI4EPmmJ2hpuAzZIbt%2XvX>^tGkvmPh-p*m>rQ`Au zd@F%nVubfm{+s5L_%xPoK$m$TD!iLTkWfaoU)q7jU|`PGzPhE>((*O*^(z=>s7&eS z7`lV`;|AhS&Y~48H5hz17-jM&Sl;4Em*H~M0X<+=V2l^f1~2+LtA#dDb**cZ&mi;* Y=%wE<2E82|tP literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_index_of/test_index_of.java b/regression/strings-smoke-tests/java_index_of/test_index_of.java new file mode 100644 index 00000000000..270267196c5 --- /dev/null +++ b/regression/strings-smoke-tests/java_index_of/test_index_of.java @@ -0,0 +1,10 @@ +public class test_index_of +{ + public static void main(/*String[] argv*/) + { + String s = "Abc"; + String bc = "bc"; + int i = s.indexOf(bc); + assert(i == 1); + } +} diff --git a/regression/strings-smoke-tests/java_index_of_char/test.desc b/regression/strings-smoke-tests/java_index_of_char/test.desc new file mode 100644 index 00000000000..63382a455f3 --- /dev/null +++ b/regression/strings-smoke-tests/java_index_of_char/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_index_of_char.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_index_of_char/test_index_of_char.class b/regression/strings-smoke-tests/java_index_of_char/test_index_of_char.class new file mode 100644 index 0000000000000000000000000000000000000000..f87a10266837a4d7315b07e7dbb86aad5cd9ca03 GIT binary patch literal 614 zcmZWmO;6iE5Pg%_*kOZP&1R^$!B?%hXrN{9`a z#Cn_Uknuj|@Y;umK|;-@S35F3THSnZ_k%HsAyob+6L{le9&ZUjAGg~+R$=x}sF@iZ z9}z^}%I+b1S=?FLVUvB>R)^<9s75N)Mnye!cAIrM!NWP=Mg>nBprB^^krnVA(S2%sIkQ5A=k(K!x}>FxpdD%awtVinv4h62iHLQ~Uv^Py5`Q PrEyX4H>`!RTy^{pEv0g( literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_index_of_char/test_index_of_char.java b/regression/strings-smoke-tests/java_index_of_char/test_index_of_char.java new file mode 100644 index 00000000000..6a5d3d60bd6 --- /dev/null +++ b/regression/strings-smoke-tests/java_index_of_char/test_index_of_char.java @@ -0,0 +1,10 @@ +public class test_index_of_char +{ + public static void main(/*String[] argv*/) + { + String s = "Abc"; + char c = 'c'; + int i = s.indexOf(c); + assert(i == 2); + } +} diff --git a/regression/strings-smoke-tests/java_insert_char/test.desc b/regression/strings-smoke-tests/java_insert_char/test.desc new file mode 100644 index 00000000000..77d3ce2ebd9 --- /dev/null +++ b/regression/strings-smoke-tests/java_insert_char/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_insert_char.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_insert_char/test_insert_char.class b/regression/strings-smoke-tests/java_insert_char/test_insert_char.class new file mode 100644 index 0000000000000000000000000000000000000000..481304a9f6deb435deed6561f574cf664acb1da3 GIT binary patch literal 811 zcmZWnU2hUW6g{)R?y_tPrIg|aYPBj*1wX1UG)Bdm7*QWEn)am`b|>xB?XK>JKZZZx zvzkC+6MgqTX}kjkV*7G;_S`e)o_p{7{`=!6fK5EKu!xHWswOU3&~RCWD=MsIVdJWa zYZlgV-M|eCmSWztP($57gJF4{N0A6)8TipN8S%a+Tn4twpl?ZE#*Y|MwfZ}TbSH2H zL%u70@j5x`i}0-?Q{sqApJAaFbLYb={&5VG8v`2*=9c4~$XLA~2_5lVs!J=eh~hoz ztI~VU0S}vp{4=+)gd)SLI=4LT@3(q!DEX2=potT5UhB?z6R@r3qfeS) zsMcO|>Ss77EwpJQaWK^?)y@)$p^Hxm_o7p^CZ5`LT1|fLpySd07|O1QWGLKOyR?ls zp#&{&7i;tk7U`|9LPd>>PAM=oYl_SCSEVnbZ>BK<`>Kd2QPjsELl!GD>H%HVDAziM zwo^=vkbc=n7y3hF-ZzHOyWe08P}(S(Lu3cY9mCogA@@s(YGctdGIY++L)1ysz$#2M zsYIF39M~T;2{TY3_}r}O=GY0aRJ4a!7{Ew>K|1vv#$0!5R_SD**^gCA=f`C)`~&hw Br?3D3 literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_insert_char/test_insert_char.java b/regression/strings-smoke-tests/java_insert_char/test_insert_char.java new file mode 100644 index 00000000000..ac6beb4ffcf --- /dev/null +++ b/regression/strings-smoke-tests/java_insert_char/test_insert_char.java @@ -0,0 +1,10 @@ +public class test_insert_char +{ + public static void main(/*String[] argv*/) + { + StringBuilder sb = new StringBuilder("ac"); + sb.insert(1, 'b'); + String s = sb.toString(); + assert(s.equals("abc")); + } +} diff --git a/regression/strings-smoke-tests/java_insert_char_array/test.desc b/regression/strings-smoke-tests/java_insert_char_array/test.desc new file mode 100644 index 00000000000..d48c601b61b --- /dev/null +++ b/regression/strings-smoke-tests/java_insert_char_array/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_insert_char_array.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_insert_char_array/test_insert_char_array.class b/regression/strings-smoke-tests/java_insert_char_array/test_insert_char_array.class new file mode 100644 index 0000000000000000000000000000000000000000..3c0b53292301c003d9745154f7ecba9ccf1a4695 GIT binary patch literal 979 zcmZuwTTc^F5dKbYr(G5(ZMi4{qKLg9^@7(TmsU-Tpe7X!@IX#?PjGR&i@RGBeueM+ z0iVUBBx3a4A4QzgLM!6SoU`A2GxN=y+26ZGH!Rzf9z#f& ziZiFE%-lyd0*dN`JJ zEThbj?8d&T?MNda8Jm?ecv~gIV0NWTZi6K?#8|sshVkt4%}VYZ>7>6BO)YRwlV!5! ziNyFzPIb=@WSw5hZIGzJc3R6VzNVQ4ltzj=1*BV&&cY0QSCMRb!I=Em5Vrr1`gW_O z9Bo8@x2K9tYeO?LrEhuC?97suAZU<-c4h;Uw0%ihR+b!5k3qLENCq-w2kC2!PDW=m ze+c$f5ivwI)&dz4817I%Q)rlcl_P}KQ{h8IUPOOHR|?@|ZLJVV8f*DTp^50bd=s(N z1Mrz9;s;3VBQulIn&{a_&k^+XL-hVqg+i@D(^P`0L!**?;G`^$5yB=2nL-c!GdjxX zB@EH DG=!i}#;CO>ji?V8P5WYoWm2bZ7u{X_G5i6a z)dUio=)3<(;~gjv+m|~tXU?2^?!EK-?~k7V8hBu15f?3#lDK5Uz-1k-=&+W8gR4ng zv$2lr7H-(EHS?y8GAb6TgynS+hBAm$&kvufP;@-mCD1;>+)}=Z9ui{Z${Rv_yVsS3 zOiTIlW&fxngV&nO7e_+*goSn_+z&6r$1%)qENl>xTdsE^W4C+#z?ILGew2@77`;=z zPR&bHI~1RVgC*n$t9oDegnv+PM}hJWp7fR1l>xyJuIAiwa2quTb=+}~L6$v;#-_^& z9o)qxp*UA~Jgsgg2zo4$IhEMLJ%@XEpOBqDdeu3UZuB2CaY9%rx8}SF*wpPYC$$ht z<=x%N8O})wP3}n4n`-6DXNk-(<)^;z!c(~>o|+Y&OlIz2+vD*O3SAkhKz3)<@-U)4 zU-0bqvBtk(k-rLMi@IIBi-B~nIWF_5#4GWdsE$BiH4%A^<`^WTuri~*=cfkW)sJE9 zJW*y9L&}?SOerYa>*f51Eh~(?~RcDrA3XgXaNb{C-@(lENWpDNz^z+ zfzdSR4{D5AC^CF*mbEc<0xad6Ar=O(;$IMteTOyIoto7;2^h{JUDEk++6(^xKTD?D literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_insert_int/test_insert_int.java b/regression/strings-smoke-tests/java_insert_int/test_insert_int.java new file mode 100644 index 00000000000..b787141e51a --- /dev/null +++ b/regression/strings-smoke-tests/java_insert_int/test_insert_int.java @@ -0,0 +1,10 @@ +public class test_insert_int +{ + public static void main(/*String[] argv*/) + { + StringBuilder sb = new StringBuilder("ac"); + sb.insert(1, 42); + String s = sb.toString(); + assert(s.equals("a42c")); + } +} diff --git a/regression/strings-smoke-tests/java_insert_multiple/.test_insert.java.swp b/regression/strings-smoke-tests/java_insert_multiple/.test_insert.java.swp new file mode 100644 index 0000000000000000000000000000000000000000..5596a2c906d7e2a9c8e731f9ddba55e45b991bea GIT binary patch literal 12288 zcmeI&%Sr<=6b9hbx)QvgxNsN8MW@AfynzLATC${#p{Bqz5Ix+oKWuCczsmupLm${1sJH}`uN#jWDQAY;dg zjBNK$#pYEvQyD0&lDN8)oXNDhxU?|WH}TRYdV${xyi_(*scpKaO{(Ii_O@HeiQJLe zXzy5b#G#6{OwC~{i;QYV(la!ach+n|-{NRO00Q3&Wag+^A7+aS^WC52j5EzA#&^HZ z#|Q)<009U<00Izz00bcL?*vS{z^>?41NqH{^19Gh=S@@)fB*y_009U<00Izz00bZa z0SNp-0TD9xIKtS(C>@@@|G)qLf2Q^m#Vy4(MNHA4s8dW)Oj6i6uQd0C0tEsPfB*y_ z009U<00Izz00bcL+XOCbVVv6#+P*S(bxodTBGRrS{P&?R2ZK;LC<9snTkT0(t5OLEYI>i@@_gE?QS=3XMUst pu8lBMbrKcwmQbU}I;AbG)>^GPPz5iQsx(GLO&U=jFgEQ=Gt8VcQ-`6>#gE|! zd{z@kY@+Y}lg53ZKosN4-skMg+G}5a{QCM0z!qv6a=4&iO~pkG64r&dq~fyB8$w)3 zV-{CcT+?8psGy`l7a5xxuH%M+GQ<3a6^1;B+>ReUbwjJ=afg8&Fr;=|-;EwJB+TMl z2D#pGI77DK`utVgZt>ua2qs6{a(#xGW@Op#URoyuGqF-oVNiE$?+iw3cH+S1&s~wU z9PuzZbbV3!upN7md*bo(vGu{yF^@dMl6Y4<%Rj0#qrml#p2V)_@PI+G91(L<$1U6@ zsx9%jqtig{>X?H;jI5UJP%lP>)BwJ_~{lVdeitL%}^A_wj%sH_3e6I_7rt zhiS-*VZm%n;)ceWm{@Aq9>c1+TQ5$5_7Eb}UyAL#9^(bUnzET%g}7 zX+}C(>Vtg}fmkG&8W{$lq!*L`xMf?k?2EyQId0Z56QifY@~Wn_DVgdjn7DT zk>5159x`2IPNDDjG4ox3O9Su~f~ShmNE=YF0u^gis!Emuc`{%>QB|-!be$VB*cz|` h=8V}MvRx?hN63jUNKddw#05?glKx1vcYaWM^*86Xz$pL# literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_insert_multiple/test_insert_multiple.java b/regression/strings-smoke-tests/java_insert_multiple/test_insert_multiple.java new file mode 100644 index 00000000000..cce6881ca7d --- /dev/null +++ b/regression/strings-smoke-tests/java_insert_multiple/test_insert_multiple.java @@ -0,0 +1,11 @@ +public class test_insert_multiple +{ + public static void main(/*String[] argv*/) + { + StringBuilder sb = new StringBuilder("ad"); + sb.insert(1, 'c'); + sb.insert(1, "b"); + String s = sb.toString(); + assert(s.equals("abcd")); + } +} diff --git a/regression/strings-smoke-tests/java_insert_string/test.desc b/regression/strings-smoke-tests/java_insert_string/test.desc new file mode 100644 index 00000000000..b438d32d6d9 --- /dev/null +++ b/regression/strings-smoke-tests/java_insert_string/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_insert_string.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_insert_string/test_insert_string.class b/regression/strings-smoke-tests/java_insert_string/test_insert_string.class new file mode 100644 index 0000000000000000000000000000000000000000..39cc969a902e163ccfdfe821e6b8ae8b9f30aa07 GIT binary patch literal 841 zcmZuv+iuf95IyT$>^KfdoiquT0)+xe3JI5Rky0U`fP@I}5Cm#ps*SxWTU-ZhhmXk* z@C-Tej5 zn*&!cA1#VY&hPbjM*Cu14lfS>QN;U zVYDNCReC3k0_pEI_xLAn!A6nNDsFk)-);5cPLvgNQ;j{?uGvqpPKB{X>0j~rA?1k%TRVj zC;Mt7<)0sEqeSf(=_gA5sz z=hS!fRHIz$0NR$Fm>~JQk+f4|q~A8i(7Rt@j8Iy)Gh>(|WDk(tn!x(0M73D7j1O|Xx0PO J(&@PDnZGzkv2FkW literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_insert_string/test_insert_string.java b/regression/strings-smoke-tests/java_insert_string/test_insert_string.java new file mode 100644 index 00000000000..7c161205131 --- /dev/null +++ b/regression/strings-smoke-tests/java_insert_string/test_insert_string.java @@ -0,0 +1,10 @@ +public class test_insert_string +{ + public static void main(/*String[] argv*/) + { + StringBuilder sb = new StringBuilder("ad"); + sb.insert(1, "bc"); + String s = sb.toString(); + assert(s.equals("abcd")); + } +} diff --git a/regression/strings-smoke-tests/java_int_to_string/test.desc b/regression/strings-smoke-tests/java_int_to_string/test.desc new file mode 100644 index 00000000000..a615a10f538 --- /dev/null +++ b/regression/strings-smoke-tests/java_int_to_string/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_int.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_int_to_string/test_int.class b/regression/strings-smoke-tests/java_int_to_string/test_int.class new file mode 100644 index 0000000000000000000000000000000000000000..eff0e5a422e2df360086c15be326751bd69c8115 GIT binary patch literal 859 zcmY*X+iuf96r6P~n>bE$Yf1fGGfQwPYP>A4?ip#jd zv8*DDd=ytvRI!3<5nSiEp`wH`M};A?qPwneq+wg`W5dP+Vac@v{iCiSi4@084Xaqwuz&=EvR)?z4K>_i$a$=qsaw6;_9W{Q$FUubbq#fF za5OaB#vO{fTHhewi9W|&4fk-LAvx1{***{*IoE1Q$FO<~sTpg}lA4M%jRlcQsj0|Mw&_pwZuB~CYpC3D{3=`8?? zixkx~eHCbBw1z6jU|&5VGE~EUlOc-5DfKfHdVrmz_8rQzBLs$6tfYe@gocRyMELD7 z`0wOj0-HyOR7Z%8In}f}&+&W|-zQH_WKK0qQ8e#zKa$sk{z9hCAX6 zl|TZiz4u2I#sQL6w#J@$GjHC^pTBp%0IcFeh&;*x#zIu^IuC(yfr$`Vlm*^|n8aIw zcZA`pOjBj7ZYSxcPGzH|nglu^>5j8Asuk8W7tJt0_+ThAO}z1=af+Sab3XjN(tbz+rCJ|4?686m;|H5Ic-cHG@E!-fpyU1qm8vZ$oOUoB1+#~z_7P;S!$?GzW zGZ)iy+Z-Rk5(4JTV}|7nF)|8zV8<6I^)8144EGwZcEtcgC2@n`9KyeZpZN*D-{nQG QW6Z*fKD((#*zqv>2xe1s)c^nh literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_intern/test_intern.java b/regression/strings-smoke-tests/java_intern/test_intern.java new file mode 100644 index 00000000000..7f9d5283597 --- /dev/null +++ b/regression/strings-smoke-tests/java_intern/test_intern.java @@ -0,0 +1,11 @@ +public class test_intern +{ + public static void main(/*String[] argv*/) + { + String s1 = "abc"; + String s3 = "abc"; + String x = s1.intern(); + String y = s3.intern(); + assert(x == y); + } +} diff --git a/regression/strings-smoke-tests/java_last_index_of/test.desc b/regression/strings-smoke-tests/java_last_index_of/test.desc new file mode 100644 index 00000000000..77bc5b7f18f --- /dev/null +++ b/regression/strings-smoke-tests/java_last_index_of/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_last_index_of.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_last_index_of/test_last_index_of.class b/regression/strings-smoke-tests/java_last_index_of/test_last_index_of.class new file mode 100644 index 0000000000000000000000000000000000000000..4455da4d17990ad4ba7072f2330d39bebd49531c GIT binary patch literal 647 zcmZWmK~K~`6#ia!+v#=-EJb!#1px(JAb|@v(P&T;;wpzFChmny+kp%$t!cZ2-@?VC zXElLD6TSPRh;ORw#+XjtOuzZQ@4b2N*Y&p_0JhNa;GyNB?c%nFJGfhei#dUL4-Q%a z_dG0MQDBKMvn=ymWra?Y{DsbCI8ZTx`UGcNC%Sk_sB~7}5vn_BtO!$Gov63N(@FAfHhgHB>~evlq+9LqE5 zV*--|TZWMg36>1m#>WFJ`>4Ywv<+)>Ad{ob=QmZq%(65i1pj*qtoV3{M})>$w-+9( zsQ3r!6`4+s2z67@t|@5mkTBcnj#Ymsk5_lO0b_KB1v#M^t6XO)9+kwMD29B&jq78H zTkr8ysL?i$;8O+MElhHp;=g&`iFbSL3iR0!(ctKmAfblo5w#DC#lT` zpL~IRfySKk5%uqI-d{odG%i-@(uB=tn^g{fg44S^`5FR7eb6-)1ZH^gtZ-|TXRFK& hOb6~IY8MdIPpDSD!X6vnlxK`=SpGBfh}kl4^EYGRe8vC( literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_last_index_of/test_last_index_of.java b/regression/strings-smoke-tests/java_last_index_of/test_last_index_of.java new file mode 100644 index 00000000000..8b3a0904d5b --- /dev/null +++ b/regression/strings-smoke-tests/java_last_index_of/test_last_index_of.java @@ -0,0 +1,10 @@ +public class test_last_index_of +{ + public static void main(/*String[] argv*/) + { + String s = "abcab"; + String ab = "ab"; + int i = s.lastIndexOf(ab); + assert(i == 3); + } +} diff --git a/regression/strings-smoke-tests/java_last_index_of_char/test.desc b/regression/strings-smoke-tests/java_last_index_of_char/test.desc new file mode 100644 index 00000000000..3e9a3d4b547 --- /dev/null +++ b/regression/strings-smoke-tests/java_last_index_of_char/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_last_index_of_char.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_last_index_of_char/test_last_index_of_char.class b/regression/strings-smoke-tests/java_last_index_of_char/test_last_index_of_char.class new file mode 100644 index 0000000000000000000000000000000000000000..388717f4261b0458687f8c13e6e1a6735e6419c8 GIT binary patch literal 623 zcmZ`$&rcIU6#ibjyVGtLS&Eh_6#Rh(ILL)#V>GBqgFr}$30#`l-2n#5u9@8${}wJD zJ*x>Mn&{pCN#mOhwDDjjdGqG|_`dJG`Ss`94*(l@;-ijM4Rb!)xLb$7J%M>2E?NQ$ zJ~~(wSR%|W%RE=6&{>+l)VYj?Dk0Dz!RzW&7taXQmDRTdXERF_Vfu|u)z0WVQfA*4 zbK+d;lrYsVWPG+Q-<4s3`-ECI9$sVk{cL1n^;+AGg+k@UU?|z>G*KT0+0h_Ak>=^C zd@ln8m?F3`ie!szsv(6F+4R@Lqi&$iNA?eWl))=kdmgjS+*ZB#Or!P6HbPVll0S+U^l0~EHc zaQ3PoI~Utq{Oa&ce7kE`pwG4t(`>ymNZcBZOZQOW11vTxTWg`bM78?`&IQ7G?;{%D z;T~MU`)M&MB}Nkt`z{lDOf8tIh8d33LBG)vX!5sUb_~B!QUWtgaf#Xmg!2hb^(&kS T;*Bbc;-V5fx7u%)gm?Y|i7a^3 literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_last_index_of_char/test_last_index_of_char.java b/regression/strings-smoke-tests/java_last_index_of_char/test_last_index_of_char.java new file mode 100644 index 00000000000..029d59c9d68 --- /dev/null +++ b/regression/strings-smoke-tests/java_last_index_of_char/test_last_index_of_char.java @@ -0,0 +1,9 @@ +public class test_last_index_of_char +{ + public static void main(/*String[] argv*/) + { + String s = "abcab"; + int n = s.lastIndexOf('a'); + assert(n == 3); + } +} diff --git a/regression/strings-smoke-tests/java_length/test.desc b/regression/strings-smoke-tests/java_length/test.desc new file mode 100644 index 00000000000..913afbf13c7 --- /dev/null +++ b/regression/strings-smoke-tests/java_length/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_length.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_length/test_length.class b/regression/strings-smoke-tests/java_length/test_length.class new file mode 100644 index 0000000000000000000000000000000000000000..9273d09869b9f51a7d8c54ecac00703acfcf3186 GIT binary patch literal 630 zcmY*WOHUI~6#mY1I@3-E`#_*td6kE47qVezLnK8LW7S0s32ex8dQ)y0re@~WAH&9_ zYc-*XB(Uc{VK{dxEpE;|_dLGueCOQ${c{aq7j*|Ylx;lA;JE_>6>VN*k;Sr&6$iFX zt~yx5x{WGfe$$I%5h*zg;{zFc-9YpRbWE_CGL&kMkgC-W31(~96NG$QhT_xcyepzF zx|kE^o(u_d9p(9FAHA%8b3AA$;HJu7=D zkXFaGz`tdFiQjZ%4Em`HQDkc+LE`4pwDgc$4bE*`!8j_V#xOrLE|G5jf^~sH#rlri z73`xiGB+B?NPtQ(*-yh^$UGmriVWsCk_FwNYU3$i1q)M--Gmn?ma>;{E?}EKV5WY< Unjt=nrcu%`+&5alVnVod4-^}9hyVZp literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_length/test_length.java b/regression/strings-smoke-tests/java_length/test_length.java new file mode 100644 index 00000000000..4222414fa80 --- /dev/null +++ b/regression/strings-smoke-tests/java_length/test_length.java @@ -0,0 +1,9 @@ +public class test_length +{ + public static void main(/*String[] argv*/) + { + String s = new String("Abc"); + int l = s.length(); + assert(l == 3); + } +} diff --git a/regression/strings-smoke-tests/java_parseint/test.desc b/regression/strings-smoke-tests/java_parseint/test.desc new file mode 100644 index 00000000000..9cb70f5a957 --- /dev/null +++ b/regression/strings-smoke-tests/java_parseint/test.desc @@ -0,0 +1,8 @@ +FUTURE +test_parseint.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 7.* SUCCESS$ +^\[.*assertion.2\].* line 8.* FAILURE$ +-- diff --git a/regression/strings-smoke-tests/java_parseint/test_parseint.class b/regression/strings-smoke-tests/java_parseint/test_parseint.class new file mode 100644 index 0000000000000000000000000000000000000000..e1ffe0c72107860cfe03ac1f697018740f58a884 GIT binary patch literal 727 zcmZ`%U279T6g_u0o84@-=F7%dTeY@o+KNRfC|HY96$+_7M185W>NHhy`3Mpnyw0 zE{E`KaxugeEcsX_)Rsk(NNv1Ob6d=bL!n|qz4@|rAl``efr$I-ZKGA(zh@g~+D3F=?}|}c&&&wHW_R!hJZulg zx+|Y33sp5TF|S5KCsM`criF`e1|>rIZ)k#Z>$Xi^^>Ho2bu=SHm?1Q>%7-VLJ=S`t znaL@5A1e`7v33glS?54@4PmzV?`0|(`c7klRu!X4bnNNen%~jOcx1}R) zb=lrMhO<|7C&;zdzQDWx5&0uj=F8Dr6p!KWO%Qya#@=Nyi|(Z8b$IN12zgG4KhhEc z+~HYgIm%z{r~Og0RO4uUN^~P-1XQYp&j^p;=iVddenLKjJt1vjJUGz_XbmxW3hJyprYdsx4{^ zY?mRjZaJ2}!4OPmUNeM>jhbK>FI$dy-mF)J`$~$*QRkM!Fjn!o`F@)pbj(D^pst&C zH-=VeG+k3Xwd9F}FFgOPD-LXKilu%2k?S~*6hmC@b2fMOauwgToIRr8Rg+h1Qm{%~ zlI=*x13Xl)rX!Da1&?%WU{%K?rh0mkY+{QcH3(SfmHEVV8!khDS1HyZ@gJIpM-2Kf zl!Ahe$0&{NJZ+Qxcr1tw!!8b;+j#g4gpj%nsM6nYa$5$fg-Z2!q?+efgc5Pj=7vEw+zaoQ3-3KaU04`?pEwL+i(7XloDklIUG+pFT%cFNk}$K(%i z2Bbuy65RPuAZFb*5mZ{u&d$7f^JezfpYJ~a?4W0%ikk**nYe91!>TfO%BbM3iF@j? zX5hYsvI0G@u#OD_n+%P0o~A-(;V4O;g(>$U5iqa=hSFY`gxO<;LaY6bLGOiK5?)lsc6ky9n3vCIBW(ZE?~QjX{ET6_HCS++i`Z2=FfKIH2(5m^PniPf;9vMQMViu4_zTPEa{Rd4C4$ zry|sHLKiyuMOZ}LfI%xau}qN)*l%NV=I4?yi Po+32+i5jJux4iKe)@YJ< literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_replace_char/test_replace_char.java b/regression/strings-smoke-tests/java_replace_char/test_replace_char.java new file mode 100644 index 00000000000..82a023924e2 --- /dev/null +++ b/regression/strings-smoke-tests/java_replace_char/test_replace_char.java @@ -0,0 +1,9 @@ +public class test_replace_char +{ + public static void main(/*String[] argv*/) + { + String s = new String("abcabd"); + String t = s.replace('b','m'); + assert(t.equals("amcamd")); + } +} diff --git a/regression/strings-smoke-tests/java_set_char_at/test.desc b/regression/strings-smoke-tests/java_set_char_at/test.desc new file mode 100644 index 00000000000..650e7712278 --- /dev/null +++ b/regression/strings-smoke-tests/java_set_char_at/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_set_char_at.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_set_char_at/test_set_char_at.class b/regression/strings-smoke-tests/java_set_char_at/test_set_char_at.class new file mode 100644 index 0000000000000000000000000000000000000000..6e843afbe2a4b7cfb6c15ccbbbc95c7bc11bcbd0 GIT binary patch literal 874 zcmZWnOK%cU6#gy@Gs7^*K%wBH+SXP9vG}M@h!IhfrmZfhCUirF;igWV4mvZ~|3XY$ zx>gfNB+N86dCJ6 zT#F)s>nifXT~JWe5Erl;8cMjSV1r>{&Gdcl1$Nip? zErV3=b~r;~$9DOv-cg%-dm@+|N2cvE#2bNWz27xIjLk%i*f6M7%Q;JxsI@KOE$g_2+YH(HkY_#H z>2OcS9o*GvLico}upofP1iX(247nMmHtG3==XE`*I8R5xLmiLs_#ZN_+lSl=hgMQMOYbp*LdaAmh78OH;tr2(Sb-=X!9E~a7w z=zYXSh&P8g_j_#46eEN)tS>XWC>BR*-Ucw~;V3i2cDl~-GkS9{^t$4Stw)k z877r7a1GZP@(b>RSznJmZ{QiYff~s_QJ3SUfm^uEU@n+1ItQXF|AMAM7_x=NB5w-b zRnv)6D~+HN8c1PRK`}X)u`-3?zcdEjmzF2}*S6gM&&z5J(*Xr**rf&*I>O< z>U*MwDAqngsFl(t2tO^E`k1I=L>r&MN63^@+8D7B5=V%)CeXhh!(${&{lf`3T_!mC z2de6ag8CcaB5|jKaVyKXsIw372kfUf4+D}wCRyp!Hm2heeJ6cxo%3d##_RAYnsVv&a$4ZM*1vBAZ1C3{E|nO>$!n4LL7ztqY>y$=7O_w-8O-L&M~2MSAmR+A zu88^j;ZeZl2OUhnkuPF~Vo&+umu>$zb(0JRyB+qgYB;^YP=@@i&>1zw6SbcxU#evP zn^2#hANpT?7iCl!%KE+D_v3^0o{}OyAcjs5MjBpbFggL5AarpHB^OPsFw|!$o$F@a zNI8&H?O!SjEf=d;yFs)Q9P&_+ux58wYQny$dv_*UKate`1kt=ov(&9V4V7Uo;)#$v znu?+ksUZP0(LF5EVv4jmR<7$_=w*Ubp+eT9-vZr??rdue_EQIA znuNVLg|X|IV`ScW*{+w{{sn7{H@%v|NGaxtgm~f5U4%uN zY&3|lO`aMdB^Z}zSeTof8o_s_S~gOBK*cMZz#YNL{6NP14Qp2ax&>V;3&VY-8?C4G GcmD#%SB#4Q literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_starts_with/test_starts_with.java b/regression/strings-smoke-tests/java_starts_with/test_starts_with.java new file mode 100644 index 00000000000..aba79d846c0 --- /dev/null +++ b/regression/strings-smoke-tests/java_starts_with/test_starts_with.java @@ -0,0 +1,11 @@ +public class test_starts_with +{ + public static void main(/*String[] argv*/) + { + String s = new String("Abcd"); + String pref = "Ab"; + String bad_pref = "bc"; + assert(s.startsWith(pref)); + assert(s.startsWith(bad_pref)); + } +} diff --git a/regression/strings-smoke-tests/java_string_builder_length/test.desc b/regression/strings-smoke-tests/java_string_builder_length/test.desc new file mode 100644 index 00000000000..ba9187109ed --- /dev/null +++ b/regression/strings-smoke-tests/java_string_builder_length/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_sb_length.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_string_builder_length/test_sb_length.class b/regression/strings-smoke-tests/java_string_builder_length/test_sb_length.class new file mode 100644 index 0000000000000000000000000000000000000000..cfc35874d26f44f91fc0291fbf4cc2eb1c058bfd GIT binary patch literal 722 zcmZuuO>fgc5Pjn~vEw*x;?OpH6zB&e4YaxR)(QayBt$8PAW(Cu*7hp6xK3m{{Fq)i zat5SCq7vNsO$agTwy_Xgc4lYiy?OKY=kIUd0c@jdp^9q;uA8`FLBq0%n=0Naqk`Ki zTQRU|p{$zLEUe>>fxCppx=0ckr@=5vo&Ra8mxTHK zAd&~;6IaHsRWm=Fh#(?Vd#Ui=zZ9da%t8p}t`}Z#SiRvm_T;lbAsVSn(xb#Z3S~4% z-)$X>55h(bb;6R$yP=2%-Ci08(ctko2z?o|3gLRHsYTFyX`_t|8*`Yq(ZM}JGY3Ap zTW4;eZ4_c#OhZERwTP|Go|++*pbgoXBgUOZQ@qqZ-J(MU$@%;x_Z{=rPSo$;7>|;9S2e!SB75=>{e=yaWYFW+-VBx6q>F{ltBXKNt zrl8NN5e+^|S&{g+ugqHe85C%rK|6E`Q|K=`PH}?L+b=Lq(dbNInjcX)L-}wD>xW{~ zGByXg8Uc%W>oCxQi3P5hpkHViSmbPJHfKAV4b+{=1okNm{S)-UR~R|rr94Gagl0cf KOEj~2SN{Od36Tu| literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_string_builder_length/test_sb_length.java b/regression/strings-smoke-tests/java_string_builder_length/test_sb_length.java new file mode 100644 index 00000000000..b616749ffb4 --- /dev/null +++ b/regression/strings-smoke-tests/java_string_builder_length/test_sb_length.java @@ -0,0 +1,9 @@ +public class test_sb_length +{ + public static void main(/*String[] argv*/) + { + StringBuilder x = new StringBuilder("abc"); + x.append("de"); + assert(x.length() == 5); + } +} diff --git a/regression/strings-smoke-tests/java_subsequence/test.desc b/regression/strings-smoke-tests/java_subsequence/test.desc new file mode 100644 index 00000000000..34585a7900d --- /dev/null +++ b/regression/strings-smoke-tests/java_subsequence/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_subsequence.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_subsequence/test_subsequence.class b/regression/strings-smoke-tests/java_subsequence/test_subsequence.class new file mode 100644 index 0000000000000000000000000000000000000000..0f8410939e1af315893c149dafa8190916146c35 GIT binary patch literal 789 zcmZuuO>fgc5PchetmC+?<0K`Ngs+y851^L{4wQ;00V!$6B&5& z)}DALEX-k^CU;z~Ctp$z3#+(JjVv_Kv`~P>P)(U@V-f7Gbxx!|2*XLpV4v;E(X!CS z4NA?b9=m(ei~oU!ap(uT42v^X_mv2T$Kn_YBz5+xHTwPL;Q!paq~D|34oy%S{brYT zc8WQsb<>=YjQmiJrUqzvaY6~&^$z`wK|csEyP8_2n*v%e=ILCZSDhlGsI`v3KBh$2 zbm|$%kVkP!J)}~Na>B`NwKU^1ltEkh0yT$wZ8eLVZ7qwp)lbk4P^{VBdlbGwe|7}^ z<1bdXduK7HqT2Eln99gyGFC|dX`{h9x!`cf%@SeD^twZSw#d;7a^n!I4COb08b^tv u%ow>Um5E=O8d%Rv0Y!(z=MTWu4^WjuXtRMQzSD*pa@PHHJByi~bAJGKN17A> literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_subsequence/test_subsequence.java b/regression/strings-smoke-tests/java_subsequence/test_subsequence.java new file mode 100644 index 00000000000..4d8d79cb381 --- /dev/null +++ b/regression/strings-smoke-tests/java_subsequence/test_subsequence.java @@ -0,0 +1,14 @@ +public class test_subsequence +{ + public static void main(/*String[] argv*/) + { + String abcdef = "AbcDef"; + CharSequence cde = abcdef.subSequence(2,5); + char c = cde.charAt(0); + char d = cde.charAt(1); + char e = cde.charAt(2); + assert(c == 'c'); + assert(d == 'D'); + assert(e == 'e'); + } +} diff --git a/regression/strings-smoke-tests/java_substring/test.desc b/regression/strings-smoke-tests/java_substring/test.desc new file mode 100644 index 00000000000..8a29460f529 --- /dev/null +++ b/regression/strings-smoke-tests/java_substring/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_substring.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_substring/test_substring.class b/regression/strings-smoke-tests/java_substring/test_substring.class new file mode 100644 index 0000000000000000000000000000000000000000..3ba0b60e7f2f7faf54110943d367cc5063d9aaf7 GIT binary patch literal 740 zcmZ8eO>fgs5S$m=vE#a_^U*Xw0~AWhheU-`aiLU1Ns%G~9D$3LLChO zdtUR*J(OO20UD&^1#&Yf0+o8N*XYm7&N%m}%zN#GZ8lKry+((Nm~%Q~?vSM;8Tp|c z&D3!t@stTJaELWNfyws~b~W+CKLy+x@{CKo)p!b?TJsd*Q$mEzm`y=yL}5n#$Wo2D z{bJ^EQ!`GW^jpda)CVn7z(i8Om>hnvN1bA?T-6CciwBzLnYm3PsA! d9Ya??Kvlj#n-4s9oHW#su^uLSSx)s-{s3YPjAQ@+ literal 0 HcmV?d00001 diff --git a/regression/strings-smoke-tests/java_substring/test_substring.java b/regression/strings-smoke-tests/java_substring/test_substring.java new file mode 100644 index 00000000000..03a33fdbebd --- /dev/null +++ b/regression/strings-smoke-tests/java_substring/test_substring.java @@ -0,0 +1,14 @@ +public class test_substring +{ + public static void main(/*String[] argv*/) + { + String abcdef = "AbcDef"; + String cde = abcdef.substring(2,5); + char c = cde.charAt(0); + char d = cde.charAt(1); + char e = cde.charAt(2); + assert(c == 'c'); + assert(d == 'D'); + assert(e == 'e'); + } +} diff --git a/regression/strings-smoke-tests/java_trim/test.desc b/regression/strings-smoke-tests/java_trim/test.desc new file mode 100644 index 00000000000..c7a307c37ed --- /dev/null +++ b/regression/strings-smoke-tests/java_trim/test.desc @@ -0,0 +1,8 @@ +FUTURE +test_trim.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 6.* SUCCESS$ +^\[.*assertion.2\].* line 7.* FAILURE$ +-- diff --git a/regression/strings-smoke-tests/java_trim/test_trim.class b/regression/strings-smoke-tests/java_trim/test_trim.class new file mode 100644 index 0000000000000000000000000000000000000000..33b34714ae2a5b39608f6624183a4d26028930b0 GIT binary patch literal 641 zcmY*W(M}UV6g_u$yVEX9Tb2UVinf5#@*tYOVgY&q5!wD6&nx zUiUErpWpge#hQ<&ct)ri&So!+k2c@lMcqx3K|&}@gap=oG!4BxrGM%i%dY+pYO`y6 z#G#Elq0(&aP5FN>UlD{#cl)RMTh=>|qBP~~^mtx`#Ym%%$h5f(PaaK^}uF!KxU zmrIE23=bH;4;oo3lMUb)FV5hi27woxE?}ep>jpJ}`3eJ-iQ`u02h0WeF$yCH=Q|wx V0`^q#E~rt-!Sdgjb`~+`K5Ph@2&a!L*Aq4OvYBVYz322O7NLgx(C!z-|t;Ev+BTn2bxF7x){(xt- z3aU(%-u+Kn_K*eK?%1$3@~({%${ZDj#Z?gm(hpVN3!bY$v|ZU{VEYW_mhx2im?2gwzhQ`P_q&oI z-Bg}@86CEz|5}47a43|=kT1P!9*EDP?h3D0Z-u_{dJUa8*9t}F#b6*k8r%9sfO9z~ z4K!#7VSmbA;tE5GAWuSc7J#CrhA4U|QJ?>+L ze#AU|8{VhL zW5k-(YmarE7fQuk?v3QW_ToOSkPt-bfJ-`{=!n8%8WBt|(dsR&_In#5!RgB|W z96gwb;kt?}avYN?5;9;)#WZF(W*G*?b=}Z?5-Lx5cO1@ruyRJ9eFh`zvam+Eq7HihOOlrvq+?se| z%DA*IJbznnHid0$*WT#v?5_S^*U*mvhGF@gw{&|aU-Dhk-dPPy%Mh-H8@Q?A7Unr_ zYq*2E919xm;l73x`ly;=*6UR(5L8=30gDWoZmx$%S|7Wv<1(a9bKrQOVF}B0)s1>y z-4!*TA+%LIfp?fur#d1SMzUMQ+*&vA1oZ-u^PQuZ!R%Q_^7yZ6>4WEs2DRS_sCK%O z)^zeOs2x6~5qg6H2HMq5!VJ7Aoh%wlI(vpsL5?#j-UYhlopR_XE#zqY$*zo|MLWVU zWC+i6g>l?Onz$d(1ue)X#%R@&w3aNDk&~dWFqj-B*+Dvu(3{aaGI;>@Svn$3HrfUm z;ut!1{R)MCK%IY&RKh8vTv1YHxe`g$%atgZXC1sMaZBQX#6@}S5TVKe!t2wMEhtm; ze?8qoWMd!EnHKmyVtW{z>5sRdenjFB33AqcN-m)`mkDA)1d$nIw%~O_H&NoJi#$sIF>QrmIn0o_q5Qv2d;dA68?f%x8jj{nK6Qp Nwjz6Ukq#k@`~_x<)`b87 literal 0 HcmV?d00001 diff --git a/regression/strings/java_append_char/test_append_char.java b/regression/strings/java_append_char/test_append_char.java new file mode 100644 index 00000000000..90e9ab089a2 --- /dev/null +++ b/regression/strings/java_append_char/test_append_char.java @@ -0,0 +1,17 @@ +public class test_append_char +{ + public static void main(/*String[] args*/) + { + char[] diff = {'d', 'i', 'f', 'f'}; + char[] blue = {'b', 'l', 'u', 'e'}; + + StringBuilder buffer = new StringBuilder(); + + buffer.append(diff) + .append(blue); + + String tmp=buffer.toString(); + System.out.println(tmp); + assert(!tmp.equals("diffblue")); + } +} diff --git a/regression/strings/java_append_int/test.desc b/regression/strings/java_append_int/test.desc new file mode 100644 index 00000000000..d65eecf13f5 --- /dev/null +++ b/regression/strings/java_append_int/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_append_int.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 9.* FAILURE$ +-- diff --git a/regression/strings/java_append_int/test_append_int.class b/regression/strings/java_append_int/test_append_int.class new file mode 100644 index 0000000000000000000000000000000000000000..d9ee5046e7d68f976c15ed958ecd8f1ee7d75712 GIT binary patch literal 842 zcmaJ#j z4c`_7v+a0ddvMql!7EwJi9^fr2)RyV_1pk}rM(_B8peLR=vZ)w} zFxs>Fec{=Aju)*SSnn+Z1xyp>WZ<~A2w0YFU1Fpo^rF8)BN;rBkzm3~r9EjF zWn0yAp;O&0!b0Ww|I%9Ik12|k^MwqM7Vid@8xm&zWFARvRe4+HM9+rHD<#a@B6I>_ zpACT*6b(4R``pDM{|uA=5amm9hI~qZ{GR4&?i}l8Mf&-NXTIJtkmb9 zrf_cU1j?IZBwo}C$stlZHFb#ePHhOa{TbR3ipzz}5c&sXPmtw8>vdID(q|h-Bgmv2N76g`uq8OL#!Cf(Rm2qkHohNY|tr3>&vTabc4^rdp*Y31VB!3z>!!882< zo+(l)Q3>ApDBzAmnx>WQJDxjd&OLYe{pZI|0E<{tF^YnMX$4m~uBnKjAWc!4>j})@ zhKdr(31l#NCw1mOHwix1d(>DDj zhG?n$h9S1*7=j_QZrWlqXg7uXT7v1It(!JOs^ROc_ZxaAbQ3q};<&@0)LYhnCbi)N zZc98j<-JK?c>cED=?L4{cA9&l~bRJLA543*OQ=?k^;3D-~_HB#z3eU7oxSs)=!2xxrre9@-f zIDyYF-lH|0>MN>^Pc%Yr(}jE}VA##TI}&73&&E$m>;?42+wqdaa>Uv2S1<#nw~98(;SY{zFW{8`@lAJg_3er$XR+8eSNK_g{5?(_V=Lkh&|I#MLaXx%6 ua9kv}Lco3=i=kj(G?(cjyAK}widghJ)Ir34PLgp15p7v!ewj8AT=@rV@YR?A literal 0 HcmV?d00001 diff --git a/regression/strings/java_append_object/test_append_object.java b/regression/strings/java_append_object/test_append_object.java new file mode 100644 index 00000000000..e139a01679a --- /dev/null +++ b/regression/strings/java_append_object/test_append_object.java @@ -0,0 +1,17 @@ +public class test_append_object +{ + public static void main(/*String[] args*/) + { + Object diff = "diff"; + Object blue = "blue"; + + StringBuilder buffer = new StringBuilder(); + + buffer.append(diff) + .append(blue); + + String tmp=buffer.toString(); + System.out.println(tmp); + assert(!tmp.equals("diffblue")); + } +} diff --git a/regression/strings/java_append_string/test.desc b/regression/strings/java_append_string/test.desc new file mode 100644 index 00000000000..7b6ea8ccae7 --- /dev/null +++ b/regression/strings/java_append_string/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_append_string.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 12.* FAILURE$ +-- diff --git a/regression/strings/java_append_string/test_append_string.class b/regression/strings/java_append_string/test_append_string.class new file mode 100644 index 0000000000000000000000000000000000000000..f2cb5cf8bea64858805fef9f4a7b85663a237736 GIT binary patch literal 1032 zcmZ`%YfsZq7=F%f?Meru444;G5OFYIiYO|G+zkq9GNXYnq^xJ;VAsyJGx3j@$RF^t zm~4q8`rRKzd{4(%Ci>O#pr zE299GN#|l;%vh8xqtx>Fd zp6f9f7g;J;)3J_?4vw$(4|yqI=+AAni#3VQ%h@HGjWSIAE8s%TSwHg~7{yP1z$>&3 zwrr8CA#mx#O^o97HW(K7ygKXMT2g4@qkf9p5twCpU;};lF3$v|8tnFx&xNnAM({YtBn zUE8Ej)}bFGb%e~M(OpN+7j&Hs}a7Bd1)Xd1>N=N(y z#z@+PgrUU1pCr~kf@J60-+F!DS~u2nc;)5o{t+lLZIh(aq|2h)#^9%hjE0^Fae6KK zbda^^xA>*$ZxbAK4Z;Rr^Yko0Bqav~Aop^

fY~HnML@r4WxVBGHxl=b!$VK{U8rN9v6#k~S-EOzEw58w$5kzgd)f);Hk+Oxvq##Mv1pHyP+ex$7cI)m|;}hsB zzzg_WOiCh&{`VDp7vh;+p@JlvnKNg;^UZfI`|J4o4*>VEt{{zZ2@^7ICUj4CzVTak%Z8R@*6?j$Ui> zIs@Bbh%A|H(_Ll==JKx?LYh_Q42g=_=9}GCjoU8-m@Znn*=ES*URQSY_j;kJw;P43 zYn$yxQ3S@Tu5P^D&^sQUv@^&{M)NPZQnk9a!PiYeHQ;i`ePiejpA%FnvKVGao~I>k zrJAAD*9739ibq(Gu&ClOiV~JoJQ2=iEU3s}h`@TyFzQ^zQ>-wI^w~-$nXlQlWee6- zO)IZ?hGCQ`qJ&k3=&33Rnu;)9q_4b~ zr)DR8z_Ui%vbnGH!h8st=oe6H((q90>)bJIUO%lTb=>XJ1x?Nl#%UbWG`%c2BKkpA z5EO%9T1V(KN;{)HJaq{6RRD2`)`;h%>f;pvik(o&;J;e4AJA%4>i1<(6J)0W1$UU7(^pHG{9`#A~knzLz`fNgN zz*9Q~h3qh`5hNf{dQnoXU;;5L(*L)GI2sthC%U~#$U%gTu_$5G|FYRJ$hdY|lX)+B jAeF{o52<}fp)UvpzaiRx@}xk5E{s5YMU-*OQ*`|gWS!(_ diff --git a/regression/strings/java_case/test_case.java b/regression/strings/java_case/test_case.java index ce3a51814c8..309abfc07b9 100644 --- a/regression/strings/java_case/test_case.java +++ b/regression/strings/java_case/test_case.java @@ -1,16 +1,12 @@ -public class test_case { - - public static void main(String[] argv) { - - String s = new String("AbcCdE"); - String l = s.toLowerCase(); - System.out.println(l); - - String u = s.toUpperCase(); - System.out.println(u); - assert(l.equals("abccde")); - assert(u.equals("ABCCDE")); - assert(s.equalsIgnoreCase("ABccDe")); - assert(!l.equals("abccde") || !u.equals("ABCCDE")); - } +public class test_case +{ + public static void main(/*String[] argv*/) + { + String s = new String("Ab"); + String l = s.toLowerCase(); + String u = s.toUpperCase(); + assert(!l.equals("ab") || + !u.equals("AB") || + !s.equalsIgnoreCase("aB")); + } } diff --git a/regression/strings/java_char_array/test.desc b/regression/strings/java_char_array/test.desc index 8282b808b84..62cc45997ba 100644 --- a/regression/strings/java_char_array/test.desc +++ b/regression/strings/java_char_array/test.desc @@ -1,9 +1,7 @@ FUTURE test_char_array.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_char_array.java line 11: SUCCESS$ -^\[assertion.2\] assertion at file test_char_array.java line 12: SUCCESS$ -^\[assertion.3\] assertion at file test_char_array.java line 13: FAILURE$ +^\[.*assertion.1\].* line 9.* FAILURE$ -- diff --git a/regression/strings/java_char_array/test_char_array.class b/regression/strings/java_char_array/test_char_array.class index 836942da1346e6bee0164979a451b7eec1a18c9b..38a7ecf41eddf662574382383851643fa631b055 100644 GIT binary patch delta 310 zcmXwzy-osA5QV?HuzO)yby-n<1QGEUOh|M~HTGyMv@x-{5MqMFSP&WupMlUAD+*sg zVldGJd*8@L915p6GiPQ_^1V4PcKH4KF#$sMTwF3SvMxDRW|EH+qo7%JamZ+jE^CxD z>;15vn!D(l=Ixoezch_bOHzg{I~;fv;k6l@~WV`x0lfH?ay1#(HEredO+MNLX6NXy3({}7?T%qkfSrdBC6 Pi`ZD+iIV-Y7>o2D@ft1Q delta 474 zcmZvY&rTXq6vlsdhM5ZkSR5ED#XpF)D$r8vlo;DY6IVv43yq0kH4ROw}s8!C_Ep1p7OswdTRc{hfEy8;bZ^GpK*624B{L zt;V+Ig=SJSrI~KE-$y57IO-kcw1~gBV+!Um8;vE!Sce1w 'z' ); - } +public class test_char_array +{ + public static void main(/*String[] argv*/) + { + String s = "abc"; + char [] str = s.toCharArray(); + char c = str[2]; + char a = s.charAt(0); + assert(str.length != 3 || + a != 'a' || + c != 'c'); + } } diff --git a/regression/strings/java_char_array_init/test.desc b/regression/strings/java_char_array_init/test.desc index fe5ffae7238..24437881467 100644 --- a/regression/strings/java_char_array_init/test.desc +++ b/regression/strings/java_char_array_init/test.desc @@ -1,11 +1,7 @@ FUTURE test_init.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_init.java line 16: SUCCESS$ -^\[assertion.2\] assertion at file test_init.java line 17: SUCCESS$ -^\[assertion.3\] assertion at file test_init.java line 18: SUCCESS$ -^\[assertion.4\] assertion at file test_init.java line 20: SUCCESS$ -^\[assertion.5\] assertion at file test_init.java line 21: FAILURE$ +^\[.*assertion.1\].* line 14.* FAILURE$ -- diff --git a/regression/strings/java_char_array_init/test_init.class b/regression/strings/java_char_array_init/test_init.class index be3baee56bd4f0a276d7b18454f832685f146dce..ff9c64510dad8e9bdd4cffcca053a0ed768259a6 100644 GIT binary patch delta 528 zcmYL_OK;Oa6otR>BNIDzaNPjq5nd&wbpnAB3KBvBiAAdtu?SgIMWO~-Az&p4EVlfH z;#Iq12U|c&fFjti;ur91DrPKEq|rHdM(3V;?tFEAmDYamfBOM+xZ!e$y5y9L!D$U= z9DL5|>Rg$5&F9NBG%rXlxKy-!(PfE9(%jx!ulc*=_%6-U*o% z1kd8vaXXDigLW@_IUEfYaT0H&)7nj!ZEn_~vWi;{+#_}6qZ3H5i)Ap(|5o+43!kW6( z6${07G(~*WLJlh|6^{akBL~ti*s2*G2JUxzJu-vUeq;qnKeB_gAC)x7VBFus*idHX zy`r#g+Ec9VC+uAoniEQa`;K}mloQH3)S96)!QG*pwVA HOg{M+MhHx` literal 1209 zcmZuxOH&g;5dJ2~W|C!rB_TXiPy{6qAPS=LP{9C#@~{e{1stp;jJUYT!tRDD|A9xZ zaPg>Du_{<%>D{CL9gDJO!&@q;?w;;%db+>v+F$$MegNphtcqH+ama{6Zx@}Mm@s9wDo?oHOBv~r*)-In zfk8i;S^5X17~&Y#a1Zx69%vZBsD_8gNNY?(0(A_^q_8Yo!#E}w8jcf<9`-%%IJUzO z5SE5VnA9+Z$8@x8hUif>98WY%W9C#XbIWTY=Mi=(L+>P)GO}MzdTL5qC#!zzdLmC; z+C{=A%1oJd`YF-m5m~~>5799E>Q1{U;kpD_#Bm~dKE+{66jr_0{-~yCB1!*w)%6U= zb6=P;a_&_*WwB8-EcXnc+}KbD0r;k26~){u;;!7-|0U2?9MhVyXrX8wR)lLhV&#Zs z+5)dg0otZTw9uZ`(qc2cK@N$mAebCA$woRgk!GZo&Rww25{L^V!@iTof{VCBHbL1W z6#4;wboIM3oeJuc*;Ggu*_5JN*;H5xuG`r?1Qt@e2+sIMNZCbbb_YsV3E{HhB}8@* z-9~L!Of8{e8x?!d7Isnj^T1sK*VPYa-QBUO5~@$2Q(@&R^udsSE72H=)trv|{&xQn zy4GC2zlB5O*6{1Zv2ZjfSCuqZ$$7FG>WcXhsEn2{iPg3Ii0$K*u8CH;ChR zh~qsWKM~8niRUKDQV(SxiyX}ym+4gyeBYKyW^6i?BbGe zS!QK;Ac|S9d*!t{$Lg}BJjtrd8tcPbu{+!_wr^rO5{Ohj@MvWsG-5*6l%5K@3*GIC zk9Z6gN$VO3AB9ez`CB~+Hb4?Vq>^_LHMcg*z^wq)HCA% literal 951 zcmZuvT~pIQ6g}IfO-NIkwtTc&v><5OTJQ_MTIHkS$V|nDIy%J%CbT;k3=JfyKZX~4 z^I4r~XJiJSeDOyy-YorZ;5kp=mAddfN0n?)sL~@t#?pxoPt@16yZ^R;`ZZ zKV=9Tg*OaR&1rLnMBVD}weHR)cV7!IC3Z}!!!TyNt8beh%{klbY|S-%*XnFl#Km~S zH(MWGn!5u$X(pKrO0{L5@~aJ}>$doFORyzo71D66DR$SL{1M+e}{s0dt z_NO=*k2E|+y?7*j!uVIH`&iED&H<{2h&B7reiV-)LB`1Gy9byGG6VETDHZQw zcptGKEM$cSvS#VEgG8u^Kqrw|$jC#%3`I(mTY!cY#L=X#cL{Nc(8CBHV?oAcCL@;} rBlN^s_w$1`fm9la9`t?4(q~BFZ&1%`2382J2tx5iVc3;{q^rLH7FffW diff --git a/regression/strings/java_char_at/test_char_at.java b/regression/strings/java_char_at/test_char_at.java index 337c6524099..9ae02733fb8 100644 --- a/regression/strings/java_char_at/test_char_at.java +++ b/regression/strings/java_char_at/test_char_at.java @@ -1,17 +1,7 @@ public class test_char_at { - public static void main(String[] argv) { - String s = new String("Hello World!"); - char c = s.charAt(4); - StringBuilder sb = new StringBuilder(s); - sb.setCharAt(5,'-'); - s = sb.toString(); - - if(argv.length==1) - assert(c == 'o'); - else if(argv.length==2) - assert(c == 'p'); - else - assert(s.equals("Hello-World!")); - } + public static void main(/*String[] argv*/) { + String s = new String("abc"); + assert(s.charAt(2)!='c'); + } } diff --git a/regression/strings/java_code_point/test.desc b/regression/strings/java_code_point/test.desc index 35ca0cd6f4b..2b94f1fa0c0 100644 --- a/regression/strings/java_code_point/test.desc +++ b/regression/strings/java_code_point/test.desc @@ -1,11 +1,7 @@ FUTURE test_code_point.class ---string-refine -^EXIT=0$ +--refine-strings +^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_code_point.java line 5: SUCCESS$ -^\[assertion.2\] assertion at file test_code_point.java line 6: SUCCESS$ -^\[assertion.3\] assertion at file test_code_point.java line 7: SUCCESS$ -^\[assertion.4\] assertion at file test_code_point.java line 8: SUCCESS$ -^\[assertion.5\] assertion at file test_code_point.java line 11: SUCCESS$ +^\[.*assertion.1\].* line 8.* FAILURE$ -- diff --git a/regression/strings/java_code_point/test_code_point.class b/regression/strings/java_code_point/test_code_point.class index c257f0633ec65db2643a2b314c4f01928dc14660..f2f5fbad63a60c992bb2f3c9ef2d15fb99700de0 100644 GIT binary patch delta 482 zcmYL_%}*0S7{-6IU$fnA`B;fIh*%L7w`c_`il9LgPnDAv1D9sS#-OAn?Z(8DG5!T) zZzLoT51u@z$(lfdCodfRe>A>BVw}To-aPZn^S(3h{m**s_|L%+Q0IO?M8)TVW+K3* zVxtP$R2K^jF&S`)%LZ2rrVOqc#Ksb9ssRI3G}8gsxUQ*fuQf(WPts)l^>VWHG{Z!4YVSRXa8pRoTA$Pui0*=6c(k#q6i`sDOM=O5B$0V@qj{v16fK#5K;(kyb_~VNyy%~ zkZ|#$2Q^uvBzpIM;6EY8nTA9Xok@N(^UOQ%*L;+({l#CuzyAQLJPHWu^Xbpf&b5F6 zuG@%=lne%V^cgZ_q-11Raw8yXaF!86%4S!Vj0W7KBDuA{I6c}`TAFzgy^1QEQFE;_ z7w@b$*QSQ&1-ZF6s&C9j+fSpF&4y%5``iCEpHp;lK_3<4RFfy7m{&|tRn(YN+-5S# zi=O^F+*RCTN|28mFXQF<)@oyUduzQJOYSQk@GyBRO38_MmV6Ln$+-1q_Y#7FF7yOj zPuL5sna|hS&c= 2); - assert(s.offsetByCodePoints(1,2) >= 3); - StringBuilder sb = new StringBuilder(); - sb.appendCodePoint(0x10907); - assert(s.charAt(1) == sb.charAt(0)); - } +public class test_code_point +{ + public static void main(/*String[] argv*/) + { + String s = "!𐤇𐤄𐤋𐤋𐤅"; + StringBuilder sb = new StringBuilder(); + sb.appendCodePoint(0x10907); + assert(s.codePointAt(1) != 67847 || + s.codePointBefore(3) != 67847 || + s.codePointCount(1,5) < 2 || + s.offsetByCodePoints(1,2) < 3 || + s.charAt(1) != sb.charAt(0)); + } } diff --git a/regression/strings/java_compare/test.desc b/regression/strings/java_compare/test.desc index 517b208c3e4..e7444831e77 100644 --- a/regression/strings/java_compare/test.desc +++ b/regression/strings/java_compare/test.desc @@ -1,10 +1,7 @@ FUTURE test_compare.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_compare.java line 6: SUCCESS$ -^\[assertion.2\] assertion at file test_compare.java line 8: FAILURE$ -^\[assertion.3\] assertion at file test_compare.java line 11: SUCCESS$ -^\[assertion.4\] assertion at file test_compare.java line 12: FAILURE$ +^\[.*assertion.1\].* line 7.* FAILURE$ -- diff --git a/regression/strings/java_compare/test_compare.class b/regression/strings/java_compare/test_compare.class index 5616013c523bf345c4c9743a55ef57608353b3f9..67f18914ea60035f71b5a2b6d3fbf28050aa44c4 100644 GIT binary patch delta 399 zcmYL_J5K^p5QV?HEW69HsH~{?!1pT{H8Cc(T3CSEcLV9qVGXY_r&U+{z~yQW&}zg7%2x$-rZYWktH8ul06S*Uq*N z8jW($Jg?UdgPNgcJl7rO(h6K#|M$V7qpD{b6vKw8Z<~{K@tdk!0N62CHIebj1 zD^XFjB;*is6kl3#)HfNMQF+oz4HS0!s*v=ZF0l@_`G6UD!TcxvGZykhF}(fI{#ajg F{1*XBGvU54k$*G_MUsscg}ae@7y21zkCC58!HwHm^N|6#7rJ}T(wZgH3PF2 zbWF>`bpvx2=5fQo0z+ki$FYbKFAUaxpL*M4I4!wv9W}k47KdaM`u2sL{S*o zXkeMazQ|~xX`_WULpf`E-rE;$@>gmso*{p#WIJS-YW&CDGqSSBEr#eMOG1oi+`ydN3L93o7 zNh2IoXfI1YQ>#YNca)B!ZhnMzgvnNWgq(Ja!dK|8PGEdb)75rUy+wfXE(088YmBXo zV7BQ0r%3`tcM*_^lvL3?OxkOtAxG+T5^mxyEZie|FUZ;fRZUVw1==sv4NTEj`-vGD qsI+?S_)cmKa4N`;U>(8G-a}JALCY>Xvo8sAP>K)bkS?cMYJUJ&teKbq diff --git a/regression/strings/java_compare/test_compare.java b/regression/strings/java_compare/test_compare.java index 8c1d4b71a0c..0a535fd0bf3 100644 --- a/regression/strings/java_compare/test_compare.java +++ b/regression/strings/java_compare/test_compare.java @@ -1,18 +1,9 @@ -public class test_compare { - - public static void main(String[] argv) { - String s1 = "abc"; - String s2 = "aac"; - assert(s1.compareTo(s2) == 1); - - assert(s2.compareTo(argv[0]) != -1); - - String s3 = "abc"; - assert(s3.hashCode() == s1.hashCode()); - assert(s3.hashCode() == s2.hashCode()); - - /*String x = s1.intern(); - String y = s3.intern(); - assert(x == y);*/ - } +public class test_compare +{ + public static void main(/*String[] argv*/) + { + String s1 = "ab"; + String s2 = "aa"; + assert(s1.compareTo(s2) != 1); + } } diff --git a/regression/strings/java_concat/test.desc b/regression/strings/java_concat/test.desc index 8ef2898e0d7..fb784efd723 100644 --- a/regression/strings/java_concat/test.desc +++ b/regression/strings/java_concat/test.desc @@ -1,8 +1,8 @@ FUTURE test_concat.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_concat.java line 9: SUCCESS$ -^\[assertion.2\] assertion at file test_concat.java line 10: FAILURE$ +^\[.*assertion.1\].* line 10.* SUCCESS$ +^\[.*assertion.2\].* line 11.* FAILURE$ -- diff --git a/regression/strings/java_concat/test_concat.class b/regression/strings/java_concat/test_concat.class index a6d4008aa268b84833bf1df2c7b8519a5ef4090a..a69c05921f673cc68295af7dbb43ccd41e10f1a8 100644 GIT binary patch delta 373 zcmYL^yG{aO6okKBSaw-f1q2jP5WFJ@DzVW*6FS68w4q!GF+rjf#LoB(gw8^F1uY;E zqrDGc>7%G;O$>kX&txX&OwN3I9z4a5@0T~Az_!UaF`Ze1ITMw*0||q9hm#JZyjU#g zESi|k|#4Vkt0o*0yVxWxI85SDST->AW6B)-2MjE4W&%Yl{q7iw$z!xRQ_N zEjHOw@HgxmJJ+rK@=wCtR5~j;nN{%CFmO9E~WcudwY(20sZNZ^%jCcF4J uk=79z38Vgqq3KL1@*P4F45s-%w;*RbFA(e|UCEHMrJ-8;iuh3xDl@-B(>Emm delta 390 zcmYLEy-vbV7(Ms)=ay2G6s&-#;4g|;6k*ViIIw||SQo-n2q7YY#t>&;fpl{a7hk{u z5=nIT0UX_Z3H8<({gUrHIp_Poli%dh>*v!mfE)@cX0XVxq+nSEMZyb71uGt|dST56 z4eJaWDpap>Q$-3}4BNv}Suj#{w@Qp~z#7=i%M;r~M0C|F7$G*1BuH9>!)kde)91w)+m4DG1TwV0qM{b$C*9`C^zxx3K zWRBJpw5AIah?VphQt^k%oSvpLW3WRpD#pi93eqEdx6tRLpfiGh3bi(Y|K(5YkK7v? zvqb)&gjqg03Wfv}{-_T{uAaeb$_QH0hLH=gk&LGbch{(A{=_b`X~K;PxF`<-ia2mG`pGp0sjOq3jhEB delta 457 zcmY*VOG^S#7(I91&Wt&Z`N*=ghnbIDM4L!*8I)}dLRw8FQVkj+EpyvegcfdEwyr=S zq4xco7Hy^PPEiDx?{&{T=Y02G{*X)Wlb2Tj8(7!j$E=Du4GA3r<~1y6NcvzP#rs7S zOFDcUvaDkTX%(xztvxZ4IqvVUNYG#HIH#8t=jzZoaqGm>yDOG01R1Og=h`W{PP0+0 zcG~C727|dZ5-o}dm8 z%H@a91~A6()ke_Yex}{R|1sAPJdHT1fEabiWKkhgD$>xfO{x*P2|$?eAB%pUFkQud neQ$aO0Xqa^2y*~cdVnN8L;Vx*mWUFNv&j(rWxnf-XCVFs=fgcY diff --git a/regression/strings/java_contains/test_contains.java b/regression/strings/java_contains/test_contains.java index fce2ee63047..6f4c60a1a2e 100644 --- a/regression/strings/java_contains/test_contains.java +++ b/regression/strings/java_contains/test_contains.java @@ -1,10 +1,9 @@ -public class test_contains { - - public static void main(String[] argv) { - String s = new String("Hello World!"); - String u = "o W"; - String t = "W o"; - assert(s.contains(u)); - assert(s.contains(t)); - } +public class test_contains +{ + public static void main(/*String[] argv*/) + { + String s = new String("Abc"); + String u = "bc"; + assert(!s.contains(u)); + } } diff --git a/regression/strings/java_delete/test.desc b/regression/strings/java_delete/test.desc index c6c608c0955..ff41e78b3df 100644 --- a/regression/strings/java_delete/test.desc +++ b/regression/strings/java_delete/test.desc @@ -1,8 +1,7 @@ FUTURE test_delete.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_delete.java line 11: SUCCESS$ -^\[assertion.2\] assertion at file test_delete.java line 12: FAILURE$ +^\[.*assertion.1\].* line 8.* FAILURE$ -- diff --git a/regression/strings/java_delete/test_delete.class b/regression/strings/java_delete/test_delete.class index 6d30024f108aeca8a2d4587aec50ce79b2f35ddf..7036ce13c9036943ef66368d595e31b8ed88ca47 100644 GIT binary patch delta 431 zcmYL_J1<006otQY?%aFs+&P%J#``_qGsc^mM29FyP>u--3Wb{Az%7JIr$#c9kdP=< zYCph#P!Ri0f@ZCA_E~%FwaudY3TCl4$$<(&>KTv5=+jfKVX1C z!%#pFD~AI{7&YY2wwAMX>&KjD0*;~=c5T2{fL1%HNY{@WYDKc)E zVA9e+TA>%qBDG909qp-tH)AEtTy&vEq8Hs3eG0GXT=cHjPpu>bm2QnY<>a8mG8Al- zTbHmBcJo!#Z7d`!=+%mfBu#(PeQDM5HvWj-4xK8A<$S`e;BMwCcq@09E3$>quaLYX z^+>Q?CG~s~o9dcrGp?Ln`3FxD7@F~AucR=fP+t@cErwPpxBX3>ttEj>Xe-oRVG=ha WoO{f_?{C=H$3@$Pc%}B**p46foiwBX literal 1126 zcmaJ=T~8BH5IwhF+iowkwop((DI#tuP!;j3s6YWB0X3f{&;I%M^A~_Atf)vKt6*3~0NE(6$#X=8>oSbW za3cl{ITd5b$B@K$6cZ{YQBZJGMYpWJrQ$ZG6x?A*kLaE!T;FtTZ^88R4NDjdY@H!8 zW7?+wm?5a;UNMA9jv*KltEMfUHEJ8eeJR28p{AQQLq>bMx}|^83zlwg7RtVB+M7jL z*j4uR>W4MG-og`g1=9@CnX0wlUoATgwLMwa6)?s4451CEC%a?Ie7g2xa10qtCL)OQZ3^=PNt(%>U|l|OsFsF4kv26gUjlQ5ma z3%X&S+6cWy1?iR$$I}c-U4ksKNAFpilRF~fV?(#R6M(js#T?l%(NVZ$kypuShVV>R z7>74R2J;*AfsDG2ELlE9{|Za?%X_A$AgDVs6#M9HkWNNtcx)H!y9A=2Vx*NMSKuNp z(X)hprP3gsulEpmvy0$rJ{4*rT*)iRNE4Atp5By7zKQ7C4r1d?s5^*nqh~zDo9Nm` zd=K4Jm-u}&{iTzZ(*v#Pqcj%?A&M{(#H9}k5shIODsqTp7917&cP|r)Bk)(6d4M1p rs0nRUDU3kZtW@J_i^$M_f=T@R diff --git a/regression/strings/java_delete/test_delete.java b/regression/strings/java_delete/test_delete.java index c91b16c5b89..ea846cd215a 100644 --- a/regression/strings/java_delete/test_delete.java +++ b/regression/strings/java_delete/test_delete.java @@ -1,15 +1,10 @@ -public class test_delete { - - public static void main(String[] argv) { - StringBuilder s = new StringBuilder(); - s.append("Hello World!"); - s.delete(4,6); - s.deleteCharAt(1); - - String str = s.toString(); - System.out.println(str); - assert(str.equals("HllWorld!")); - assert(!str.equals("HllWorld!")); - - } +public class test_delete +{ + public static void main(/*String[] argv*/) + { + StringBuilder s = new StringBuilder("Abc"); + s.delete(1,2); + String str = s.toString(); + assert(!str.equals("Ac")); + } } diff --git a/regression/strings/java_delete_char_at/test.desc b/regression/strings/java_delete_char_at/test.desc new file mode 100644 index 00000000000..0314c606e56 --- /dev/null +++ b/regression/strings/java_delete_char_at/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_delete_char_at.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 9.* FAILURE$ +-- diff --git a/regression/strings/java_delete_char_at/test_delete_char_at.class b/regression/strings/java_delete_char_at/test_delete_char_at.class new file mode 100644 index 0000000000000000000000000000000000000000..ed3148e2f7e60738b9863b1e47c0d50650b289cc GIT binary patch literal 867 zcmaJjF9Of95wn;S&+(eTK%m~`k1|RvpM+}93)K+oJz-`=N$ju(U80-l%{3|pOL&M?2 zp>SzZ>y_^8!6e(No(dhSZ!s8?o;%cXo2Zv7PyUD2LT_5JSUC+OzNC0J;!eOY|EG|N z@>Z4Bn4QV%IJ9eq1xp0BFRYWf(B{GsC1}w*SfMYIrO(B3B{^0)#lYlJ$QJ2VCeO$x zYKLH-BoOmtlTnZ%g@qHSM_*8(+~yIK*N2Ebt>xomB(`g0liRg1)b3|!2Pm%PQ)B2K zkUm11fW~*pt3TE`WfVq5Tj57yN a;~x=^eStRPo@$mn2`I*W+1a_M^zv`0>bRr; literal 0 HcmV?d00001 diff --git a/regression/strings/java_delete_char_at/test_delete_char_at.java b/regression/strings/java_delete_char_at/test_delete_char_at.java new file mode 100644 index 00000000000..5f2c995b56b --- /dev/null +++ b/regression/strings/java_delete_char_at/test_delete_char_at.java @@ -0,0 +1,11 @@ +public class test_delete_char_at +{ + public static void main(/*String[] argv*/) + { + StringBuilder s = new StringBuilder(); + s.append("Abc"); + s.deleteCharAt(1); + String str = s.toString(); + assert(!str.equals("Ac")); + } +} diff --git a/regression/strings/java_easychair/easychair.class b/regression/strings/java_easychair/easychair.class index e47900cc0b20ba70177dddd97c472c178867b054..e6c5f66c42df9f28db774c6eb3ab463dd03b134c 100644 GIT binary patch delta 108 zcmeC-?B?V+^>5cc1_lO`jU3mREm;}Z7}yyE88{fE7`Pb}8F(1f82A|U7z7wB7=##{ z7(^LD7{nOj7{nQ}7^E5M7-Sgg8RQsx85Ac=u$XX}Ffam5Vqg#ynjFre!OP>o2oz8P J3NSG!0|3Hx4oCn1 delta 109 zcmeC??BV1%^>5cc1_lP>jU3mREm;`Y7+4tufus}zCxapb7lRrD4}%^9AA<#h0D}{Q zFhdA~2tyo$C_@%dMID1QLp_5mLob8EWC<1%Zc_$Eph*l2Lc$D_!&o$Uc^w#mB1%9J HCI)2y$e#`} diff --git a/regression/strings/java_easychair/easychair.java b/regression/strings/java_easychair/easychair.java index 55ca2a31bb3..caed962fb46 100644 --- a/regression/strings/java_easychair/easychair.java +++ b/regression/strings/java_easychair/easychair.java @@ -1,34 +1,34 @@ -public class easychair { +public class easychair +{ + public static void main(String[] argv) + { + if(argv.length > 1) + { + String str = new String(argv[1]); + if(str.length() < 40) + { + // containing "/" and containing "EasyChair" + int lastSlash = str.lastIndexOf('/'); + if(lastSlash < 0) return ; - public static void main(String[] argv) { - if(argv.length > 1){ - String str = new String(argv[1]); - if(str.length() < 40){ - - // containing "/" and containing "EasyChair" - int lastSlash = str.lastIndexOf('/'); - if(lastSlash < 0) return ; - - String rest = str.substring(lastSlash + 1); - // warning: removed this because contains is not efficient at the moment - if(! rest.contains("EasyChair")) return ; - // (2) Check that str starts with "http://" - if(! str.startsWith("http://")) return ; - // (3) Take the string between "http://" and the last "/". - // if it starts with "www." strip the "www." off - String t = str.substring("http://".length(),lastSlash - "http://".length()); - if(t.startsWith("www.")) - t = t.substring("www.".length()); - - // - //(4) Check that after stripping we have either "live.com" - // or "google.com" - if(!t.equals("live.com") && !t.equals("google.com")) - return ; - // s survived all checks - assert(false); //return true; - } - } - } + String rest = str.substring(lastSlash + 1); + // warning: removed this because contains is not efficient at the moment + if(! rest.contains("EasyChair")) return ; + // (2) Check that str starts with "http://" + if(! str.startsWith("http://")) return ; + // (3) Take the string between "http://" and the last "/". + // if it starts with "www." strip the "www." off + String t = str.substring("http://".length(),lastSlash - "http://".length()); + if(t.startsWith("www.")) + t = t.substring("www.".length()); + //(4) Check that after stripping we have either "live.com" + // or "google.com" + if(!t.equals("live.com") && !t.equals("google.com")) + return ; + // s survived all checks + assert(false); //return true; + } + } + } } diff --git a/regression/strings/java_easychair/test.desc b/regression/strings/java_easychair/test.desc index 8680af72c5a..14418a7798e 100644 --- a/regression/strings/java_easychair/test.desc +++ b/regression/strings/java_easychair/test.desc @@ -1,7 +1,7 @@ -FUTURE +THOROUGH easychair.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file easychair.java line 29: FAILURE$ +^\[.*assertion.1\].* line 30.* FAILURE$ -- diff --git a/regression/strings/java_empty/test.desc b/regression/strings/java_empty/test.desc index cab514b80b5..44e8e1346a9 100644 --- a/regression/strings/java_empty/test.desc +++ b/regression/strings/java_empty/test.desc @@ -1,8 +1,7 @@ FUTURE test_empty.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_empty.java line 4: SUCCESS$ -^\[assertion.2\] assertion at file test_empty.java line 5: FAILURE$ +^\[.*assertion.1\].* line 6.* FAILURE$ -- diff --git a/regression/strings/java_empty/test_empty.class b/regression/strings/java_empty/test_empty.class index f0ced290ee36f38aa83f6b0d1a25161f3594a364..147a2b628fe75ae1487deed1d827639b1d4b3295 100644 GIT binary patch delta 337 zcmYL^Jxjw-6o#LhubZYxZBnhNTCG(Ea?p(M1ObcYj0ZWWiY+RcOJ2 z?*1BofQTm-tjl}Pd3it1eQ>AF?&r_jJCL&#P^0a$SVNNrbXd|X2e`B~D*;_rHEU%) zh@+$1;{58cxH&G)t}isb@@c0P5-A7?s0$OaPQU!hyp51e`oo^u9$u=wJ1rfcnrWqz z$wrAM5^TuUl~+P=vkB_C5;7;~8B&S0Ig=h>8Mc#HgBR=(NjAp0r#{6!nc#g?cFWis z(ju9H-YKbkE|%3teUoYunOd{d++;$W=rR5X?L6Yxuh{=-f5%iIE>^f-ojh;K7JdP7 CE+hE> delta 433 zcmZXQOG^TA6vcn@a&#Qc#z&S~(_1aDs8&I=&sIhdt)>T3nM6pdpbyYW+6k>&SD=tk zdp}Y{bY~!2#D#m$|8P0y{BK`>G}Z^-Z|}ewWebaJnDGcCD6Ur3OKSQ3{$BCmo> zMW#{ip*;JGB&3G|QX#@9j$nWF1XT)F9ku#`)*-#rMekyCi1rB`^e{gH-VuIC-U{pM zs)4S9E?AS&rw*REFfi+2t^gPF`tsby z3m1-#FSvM#MH@9jr52>ANR;fw={uPQovw%obU?5+Wh~VjLax5DPcXN8ksy?sG8P~E z#~qRE>0}NZ2Qns%wNwy(+YP>FZq`6>HpA{6hTH1(lTf^uy24i?RbNCLr9Y+mx^@)& z2t1TfCX}_k-VNfz^_EIxe8})yoiNhjR|G>_V;J|agk?f?l)ZJ|#7>g*5?1qo!baW0 z3K|axK6Q>ns0fqw<_PCM>ucSxqXm9ufsdr{h)Scv?Jm!eFcpbZCL$W@;i;%T2Y84F zSm3wt_@$^^)orkq1EZkK`vl+S_#{5_jRELfC&K65%AAA(D#O$^ml_lBs7>J{u06tCg52Ppj3NJfU_!(=fW-g+ literal 0 HcmV?d00001 diff --git a/regression/strings/java_endswith/test_endswith.java b/regression/strings/java_endswith/test_endswith.java new file mode 100644 index 00000000000..fabf6f8dde0 --- /dev/null +++ b/regression/strings/java_endswith/test_endswith.java @@ -0,0 +1,9 @@ +public class test_endswith +{ + public static void main(/*String[] argv*/) + { + String s = new String("Abcd"); + String suff = "cd"; + assert(!s.endsWith(suff)); + } +} diff --git a/regression/strings/java_equal/test.desc b/regression/strings/java_equal/test.desc index d66c30b26fe..bb61dcea8ed 100644 --- a/regression/strings/java_equal/test.desc +++ b/regression/strings/java_equal/test.desc @@ -1,8 +1,7 @@ FUTURE test_equal.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_equal.java line 7: FAILURE$ -^\[assertion.2\] assertion at file test_equal.java line 8: SUCCESS$ +^\[.*assertion.1\].* line 8.* FAILURE$ -- diff --git a/regression/strings/java_equal/test_equal.class b/regression/strings/java_equal/test_equal.class index 26ee19e6cb16d81855e5204569a842332489e8e1..e0fc6db8aaf91eb799f5e02cfdd3194a232479f1 100644 GIT binary patch delta 72 zcmcb{dX<&q)W2Q(7#J8#HgbeBiLx?qF|aX+Ft9U-GjK5IGH^0DGjL5VVN&8UVPFKR ZVqg#yn!J!ngO|sF5hx%56kuYI1ON?o3Zwu4 delta 73 zcmcc0dX1Ii)W2Q(7#J9gH*$nCiLx+oF|aa-Ft9O*Gq5x0GH@_BGjL8WVN&8YWncuV aVqg#wW|+KyNrRWyfe|Po0Tf|kkOTk~K?Sac*Pan#mw9$s)uJ zW{FC&3h{th+`AcgBeyf~?cWI0z{DU9B+YW4FZBflZ99`czGNcfdX2x1|YiVq;xf{-SajacLbY(lEL7l>^P zL{QLDu=N3a0&6>UBoUkJE;GZ-|9`vtX-{d#x;Is>~C8Zr-`4a>HrJve$F9;h_7 z$GwYguX}l=sI>p;$*H4v|(Q-S8 diff --git a/regression/strings/java_float/test_float.java b/regression/strings/java_float/test_float.java index e59c631d91e..312f1aeaf10 100644 --- a/regression/strings/java_float/test_float.java +++ b/regression/strings/java_float/test_float.java @@ -1,20 +1,17 @@ -public class test_float { - - public static void main(String[] arg) { - float inf = 100.0f / 0.0f; - float minus_inf = -100.0f / 0.0f; - float nan = 0.0f / 0.0f; - String inf_string = Float.toString(inf); - String mininf_string = Float.toString(minus_inf); - String nan_string = Float.toString(nan); - //String arg1 = arg[0]; - System.out.println(nan_string); - System.out.println(inf_string); - System.out.println(mininf_string); - assert(nan_string.equals("NaN")); - assert(inf_string.equals("Infinity")); - assert(mininf_string.equals("-Infinity")); - assert(!nan_string.equals("NaN") || !inf_string.equals("Infinity") - || !mininf_string.equals("-Infinity")); - } +public class test_float +{ + public static void main(/*String[] arg*/) + { + float inf = 100.0f / 0.0f; + float minus_inf = -100.0f / 0.0f; + float nan = 0.0f / 0.0f; + String inf_string = Float.toString(inf); + String mininf_string = Float.toString(minus_inf); + String nan_string = Float.toString(nan); + System.out.println(nan_string); + System.out.println(inf_string); + System.out.println(mininf_string); + assert(!nan_string.equals("NaN") || !inf_string.equals("Infinity") + || !mininf_string.equals("-Infinity")); + } } diff --git a/regression/strings/java_hash_code/test.desc b/regression/strings/java_hash_code/test.desc new file mode 100644 index 00000000000..4f786d42f80 --- /dev/null +++ b/regression/strings/java_hash_code/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_hash_code.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 7.* FAILURE$ +-- diff --git a/regression/strings/java_hash_code/test_hash_code.class b/regression/strings/java_hash_code/test_hash_code.class new file mode 100644 index 0000000000000000000000000000000000000000..d9b3e2b2f3de9b4d49d84348b75a7e50690e3cc1 GIT binary patch literal 602 zcmY*W%TC)s6g}6EOmGYY2SR8|c_SVYY*?ZS#6v=*Wf5AbY|z9R!9Z}3?eHoK)T@a{v7{V8UuO3{K1-^M0#&>}c zLTOSaiHcL*jFNSo$XY|y3A9JZE$c|9KM3~B>|cVj)~qW+@3xNA@7768#k;1M6DLwf zgzjo8!{cA_Gz$xi67tJoi zm&l`!BL&biMg#)>I8wz$6N!Z6BbOxO3I6bp;9q zwP+Ev?z^;;&IlRza?ZVf{*QCM?H^K7!gTHjg3J? zob-fxh9+XDcv{2L52~93jGZUUKB=N{PvVu>=@9EZa?!>v8BDIlTVydgmgL*Aa2!u4 uE^0*CVn(hKe0CC4ABRKQvj@ccSjGc}{*3wW{5M}@WTLsd(H3*#;LI=X>@Jr8 literal 1108 zcmZuwOHUI~6#i~IGj}>|X=y2s+6pLYAH1|sUr02lu?ffmqY)EvXa^h|I%Z}tCjJTC z7{kWyTtshJ`=DAK_0>&mAb0z%0(W_q*RY_nhzC`T6I|Hh>Z?Xo%ssihd0P z7!>A&Feil>QgKT7)54qyA&MMFUPBniISLwz80HvZNDk?)YdD^1*WK%;t1nwdje#vP zC{t$L^rjhtx%^!QX~wP@46#|WZrt8jUpAaOf=mbNx>;xF&OMl2)1T>MmR?^STkssS zzIs^%Mi)H2`eaUj>hn29ImQ^&sj9V?Ut6#@oT_ot6xkA<;d)DEy=FXLvR6h$#t0Hf zGDL0}mSqpzvmL88NI4=H$Jq$Z2{Vq8Sd|z8mMyjuVoN5DPKMrgUDsO8-f$e-q2dl) z$1xc}8Rr?|?U4E9HKXd0Qb+W6fVkT;1NW<+Um*p5 zf(SSXs3Jr14MD>&{bv(|UZUB|p#zU-GAlHj7c`fb#C%Oz-jnd((Tg4Q;TO{QjSLGQ z%ev7|D9CDmDLBN@$B|~cACO3QrMvo)$s}EOY=6j;{xs<{iD(lYo8ZzrNWst0+C{e} RE|SX#M6Zf>k@0)V{sT&*+!Fu* diff --git a/regression/strings/java_index_of/test_index_of.java b/regression/strings/java_index_of/test_index_of.java index bbe06d279ec..b607ba79570 100644 --- a/regression/strings/java_index_of/test_index_of.java +++ b/regression/strings/java_index_of/test_index_of.java @@ -1,32 +1,10 @@ -public class test_index_of { - - public static void main(String[] argv) { - String s = "Hello World!"; - char c = 'o'; - int i = s.indexOf(c); - int j = s.lastIndexOf('o'); - int k = s.indexOf(c,5); - int l = s.lastIndexOf(c,5); - int m = s.indexOf("lo"); - int n = s.lastIndexOf("lo"); - if(argv.length == 1){ - assert(i == 4); - assert(i != 4); - } - else if(argv.length == 2){ - assert(j == 7); - assert(j != 7); - } - else if(argv.length == 3){ - assert(k == 7); - assert(k != 7); - } - else if(argv.length == 4){ - assert(l == 4); - assert(l != 4); - } else { - assert(m != 2); - assert(n != 2); - } - } +public class test_index_of +{ + public static void main(/*String[] argv*/) + { + String s = "Abc"; + String bc = "bc"; + int i = s.indexOf(bc); + assert(i != 1); + } } diff --git a/regression/strings/java_index_of_char/test.desc b/regression/strings/java_index_of_char/test.desc new file mode 100644 index 00000000000..30d179cbaaa --- /dev/null +++ b/regression/strings/java_index_of_char/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_index_of_char.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 8.* FAILURE$ +-- diff --git a/regression/strings/java_index_of_char/test_index_of_char.class b/regression/strings/java_index_of_char/test_index_of_char.class new file mode 100644 index 0000000000000000000000000000000000000000..bf4fa6e946eca6e5f9872d09a06a2f839b17d288 GIT binary patch literal 614 zcmZWmO;6iE5Pg%_*kOZP&1R^$!B?%hXrN{9`a z#Cn_Uknuj|@Y;umK|;-@S35F3THSnZ_k%HsAyob+6L{le9&ZUjAGg~+R$=x}sF@iZ z9}z^}%I+b1S=?FLVUvB>R)^<9s75N)Mnye!cAIrM!NWP=Mg>nBprB^^krnVA(S2%sIkQ5A=k(K!x}>FxpdD%awtVinv4h62iHLQ~Uv^Py5`Q PrEyX4H>`!RTy^{pE-iAY literal 0 HcmV?d00001 diff --git a/regression/strings/java_index_of_char/test_index_of_char.java b/regression/strings/java_index_of_char/test_index_of_char.java new file mode 100644 index 00000000000..92d75b3b07d --- /dev/null +++ b/regression/strings/java_index_of_char/test_index_of_char.java @@ -0,0 +1,10 @@ +public class test_index_of_char +{ + public static void main(/*String[] argv*/) + { + String s = "Abc"; + char c = 'c'; + int i = s.indexOf(c); + assert(i != 2); + } +} diff --git a/regression/strings/java_insert/test_insert.class b/regression/strings/java_insert/test_insert.class deleted file mode 100644 index 5fa0f4250618e78cf024e8037a9213b4fe087127..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1318 zcmah|TTc^F5dKct?J3I^N=t!?C@4ycN(BU!R^+bbt|c1q!7S|wENolcZcPl2`X}TM z_$($%B8k5HZ~O!5oE9jzNR!UY&U|w@-Gvy^0&hg^&zG~L5~!7 zq_``^Jt=y9h)aE6ioRO(V?e_L4AvryAs-%Uc!b9s!x}>9=16Er;t9tHL#WFr7KQDY zg?w?+EE;Q;$TF~125-{Ln+`#0qOn&D%0wY67#ilxyjUpZ)`Yz*!4$|DW}cxr`ets^ zcyGilBflO`JGPl$Psl`n+A%U)^Tu`=&+(Lw!ZFI=OJ=OY7FxPcvNK}Zlm!EhC^~P= zyd0}nmeg?tZ451E%a4~#D=TaUbwgNILBhs#jAKHINhzkJn5H8bYZ+-i)A1ZBju{=Z znB$n&u^@9=5g{rz1i>7;B>MUX;`FDQG^mb6EHSiJyN?|)Hf7rdYF~F^V2&3$ULsA$ zs3t6~ZHkOT9WJ2g6tF@YLpXXdm);614DHcWDs~QYNJyd_pSUDGb4h&lfAQXE>Rk84 z{}Oyo;plKp(epqW`2=6-4@F1h=-LV;Vl7_@vR{qPFZ%U1-t>*16EhaN!^3d#I0a7Y%y|>>?cD!A2Ls zUDO>Qw6c$;pQrqvtA07Dr#$Hh8pu}YSSmQpT}QH>=8VwnozT!jo_^>^z>i6a%o0A0 z0JhMGj|ifJvRmN!OAgM_$rQ#oZgAX`ZXddinHnrp0t7<{yJ+48SH3{0`G!Dsm?PR` QQ57Els3i9meRy#D9{|H4+W-In diff --git a/regression/strings/java_insert/test_insert.java b/regression/strings/java_insert/test_insert.java deleted file mode 100644 index 6871a51716c..00000000000 --- a/regression/strings/java_insert/test_insert.java +++ /dev/null @@ -1,19 +0,0 @@ -public class test_insert { - - public static void main(String[] argv) { - int i = 123; - long j = 123; - char c = '/'; - boolean b = true; - StringBuilder sb = new StringBuilder("hello"); - sb.insert(2,i); - sb.insert(2,c); - sb.insert(2,j); - sb.insert(2,b); - sb.insert(2,"abc"); - String s = sb.toString(); - System.out.println(s); - assert(s.equals("heabctrue123/123llo")); - assert(!s.equals("heabctrue123/123llo")); - } -} diff --git a/regression/strings/java_insert/test_insert1.class b/regression/strings/java_insert/test_insert1.class deleted file mode 100644 index 80091936cea37ba88b8d3f67bddf5ea8683f7b2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1035 zcmZuw+fEZv6kVsx%xR}n=!F6mQ9;xem2wf(wsMC^f|sO513s9cJ%PdL49-kV41dC# zPdbd2DB1aUkF9GfkY zgTOuE>dsyU65@=!@)ti4HF`z2P9oDSTFcG9rUwd$Mwm6akZSrlzsr9lAgI#;_0t9hsWX$*!7SbAcJc(m(Z_tHB94be6Q4v(0n{Uttiv#5tQ|$dI+tc zWi++F0sbzdH4rZF14J^s0sR2ceWWuyX*3YqNAw7t>xbz2Ez^aX=|-T_T%iOiI3V diff --git a/regression/strings/java_insert/test_insert1.java b/regression/strings/java_insert/test_insert1.java deleted file mode 100644 index 54e754302c5..00000000000 --- a/regression/strings/java_insert/test_insert1.java +++ /dev/null @@ -1,23 +0,0 @@ -public class test_insert1 { - - public static void main(String[] argv) { - int i = 123; - long j = 123; - char c = '/'; - boolean b = true; - StringBuilder sb = new StringBuilder("hello"); - sb.insert(2,i); - - /* - sb.insert(2,c); - sb.insert(2,j); - sb.insert(2,b); - sb.insert(2,"abc"); - */ - String s = sb.toString(); - System.out.println(s); - assert(s.equals("he123llo")); - //assert(s.equals("heabctrue123/123llo")); - //assert(!s.equals("heabctrue123/123llo")); - } -} diff --git a/regression/strings/java_insert_char/test.desc b/regression/strings/java_insert_char/test.desc new file mode 100644 index 00000000000..f5727a3a4ab --- /dev/null +++ b/regression/strings/java_insert_char/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_insert_char.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 8.* FAILURE$ +-- diff --git a/regression/strings/java_insert_char/test_insert_char.class b/regression/strings/java_insert_char/test_insert_char.class new file mode 100644 index 0000000000000000000000000000000000000000..fbf4a82070b0507614103af7be1f1d5846d7a754 GIT binary patch literal 811 zcmZWnU2hUW6g{&nyRd8vrIg|aYPIS@75u2a&=?gpG1B^g(X=nkuuR&i+eP=o|6>1u z&uRjRP4wOWr11_EHnuN!XU{!z?z#8Q@4r8O0$9gG3-h>WqME@a3mPt~a7BfcENooO z;F^V1TsLvUf~A-@EjXx|s530C@-P%ZBnN)@OoqJYi9Q3{VK6qNFQZ2cDW~?9L2nQG zf+63LzSxQndm?zF$dowb(r1|KM%;bB$v=!?a${nRA+zCnCo)!d5C^V!A=Ra&NQBX@ z^i}Cycb^B11OAEISU{0sS)H36_xGCJD3Jc%(^z_a5in@nRh(NkZlhtNi90s(D3C|q zbE%+>yST?tNd%ruyL%o415zlQE^OkyO+$P@spQt{-hptV|DcHza_)2z-UMu^`52RC z7^=?8cI^!3q=goZBpOV$O3qm#F%0oB=3aQJ*2Gh*Mytsu4%!~=kD=Tbp$tTS)-G)$ ziYY}3sl6HIcLB5X6BnYv%e3&{{%3Hs)i&cIWERAr6Gh%%3M|^lfV^B zYq*MR0)5EEk=Ibb497JMx{8_AP{ehP8w`UP;rr4HEZ6ZLTfV5<(qv$346(B1Siw9) zIGcOJ5UIMRWawYA9QmTzs7vp)B9o&bEQg`D76{}0ve<6Jq>JMw$1R3<*|3i?X*IX$ z8S<&6;>H5$2OE~7s&5$Ygts9)PwdQYiH}0ZAkqvY>Rz;kvstVKp5<&-nwD)!k0B&X z#hKG_8+UZv#XXMuIv$|JQP%NLc?OUob)s&Vq(jF%9x;q|GcF$Y{lxQJN;&+0Jsb-< z7ExhHc4J@Gx1d%yrYs~D7(}pcfgVwVyx3H!$kJkdNp^3bktvorWUxz$*os7@{T`Gi=^_4;-X{_WUg%+Z3^DV@d z_rPabi0>h>i}XxNYoX^edJdqk?xXjYDimrLnx+y|9U7JF11Dv1j1o3UNCrLh&*-S2 zmoSi@9iqZ!i}#;8@3Mr|Y9%njwM=pi9iuDmA1H+x-4 z$h4F%xBG`38NAYDzBm-hC(N}Y;l6(?V_}Vu+;F`U8N1!<2d;ds^rL(v!|1K@ zb!uLs+JX2a94sJ5Sl0WxC;a_-I|`J)|D>Eu@k~lxi#aB!KQAHIj)6J zDsOF7&TvjjXmUrQ-b5>3K1*bVDL?jw7oN&B_SCHKWHK`cn;wskQ0U4~1+qJ>mWL7b z`GRM+hZX(>^ZZpPTh#61T@0jq&2f=WC0>cwM0E)Is)@*RG)EvIg{3L=9X~bru6_(- zHy0Zs{-PSsRtHGD;b6AD!8$^IEtec1^%?17*t&9g zixCf_eb*PI_dBr{xknza99r)!9ka+YEQoj2v;2cyf4wctY!v;fP47GLE>(e0U5?20SG!)#^aUTyDa^uWb?L%%y zf0%~680O68IBsaHi;1O%?J*S1?M7)L=Cq+YL&e;l@YesAphn%Z;(2p2kRVh1U2J*b zU*v{O)JwG8?3i-HqZ445cX;Rq+!@V?78=Fmp#AS*g)S*aXUB2{F=TorK-Ysj$vOHJ zNi)*Pav$uI2*fv^Rk??dr0n-Wh2#tvQzFsZGJ}j z82L3r>ml<2nG@){eN259;L-qmiQuUsG|~nXEJ4LGm8y}YK%NZPPt+7F4qfL)4Auv% ifEi=DhwL#F`6J}S7o^A7XT$|g5|aK%w0C|`y7(LCDZnTI literal 0 HcmV?d00001 diff --git a/regression/strings/java_insert_multiple/test_insert_multiple.java b/regression/strings/java_insert_multiple/test_insert_multiple.java new file mode 100644 index 00000000000..c976ddd807f --- /dev/null +++ b/regression/strings/java_insert_multiple/test_insert_multiple.java @@ -0,0 +1,11 @@ +public class test_insert_multiple +{ + public static void main(/*String[] argv*/) + { + StringBuilder sb = new StringBuilder("ad"); + sb.insert(1, 'c'); + sb.insert(1, "b"); + String s = sb.toString(); + assert(!s.equals("abcd")); + } +} diff --git a/regression/strings/java_insert_string/test.desc b/regression/strings/java_insert_string/test.desc new file mode 100644 index 00000000000..91e13cefab1 --- /dev/null +++ b/regression/strings/java_insert_string/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_insert_string.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 8.* FAILURE$ +-- diff --git a/regression/strings/java_insert_string/test_insert_string.class b/regression/strings/java_insert_string/test_insert_string.class new file mode 100644 index 0000000000000000000000000000000000000000..be8f7ad0f79126964af9df57d0e5500d86d69cdd GIT binary patch literal 841 zcmZuv+iuf95IyT$>^KfdoiquT0)+xe3JI5Rky0U`fP@I}5Cm#ps*SxWTU-Zhhkv0z zz%w8v5|!Yce*!VIU*?2gZzJ#%KpKYxGw4xo)YCh}O(aoWHc6B^DMSXK8qb)3&2 zhcyEiOkBhz9W@hKMXsA@U|q*$hT<9zLlH!B;D--o$ormf8Q3;MdPDj$y33HL)n73r zHwUg@$akeLo)7o?B6z9Dl-TFeXUO#;?!0}*-^DN)(s6~s*l@ff8M8MS299_v)uT!z z!e~eOs`O461=8Pb?(q-Yf{h}jRowEpzuW4?$p=H}xgucDxT`o#iu#U)7Oq;jhU*pz zSRyaH@3>Uh!VR<;s&kq9(=Hzc!GLt^MFTo+TDXPV42Ai-7yUiqM1MgOM-0og?wmIP zJ8DwtNm~rf+LQk<7NDcvIy9|lFcmM=>I+0-q{aIo_riaQPfT{|w6*-)(xykNWhlEM zl!0((6QD&!LrTzIx3NlpNS^*AR;a2GQj`Eq2Sqwd^tD1aqdV0YgMC&+EYq2eL52*< zGwK_9s!^_W2yM$wjFEiWNZP3p(ytpM=-n?c4p3URGb5NEkv&9qYYgj$64heSGEx+$ zV3NEI9Tga8Qi%$oS+HMd>Zs~CPVk9Y)pqOzSh8~?96NxX{DfrUD~!4B)U47;L9_0u KmQKcHPyGQmzOiip literal 0 HcmV?d00001 diff --git a/regression/strings/java_insert_string/test_insert_string.java b/regression/strings/java_insert_string/test_insert_string.java new file mode 100644 index 00000000000..028a348122b --- /dev/null +++ b/regression/strings/java_insert_string/test_insert_string.java @@ -0,0 +1,10 @@ +public class test_insert_string +{ + public static void main(/*String[] argv*/) + { + StringBuilder sb = new StringBuilder("ad"); + sb.insert(1, "bc"); + String s = sb.toString(); + assert(!s.equals("abcd")); + } +} diff --git a/regression/strings/java_int/test.desc b/regression/strings/java_int/test.desc deleted file mode 100644 index ae60dd78af0..00000000000 --- a/regression/strings/java_int/test.desc +++ /dev/null @@ -1,13 +0,0 @@ -FUTURE -test_int.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_int.java line 8: SUCCESS$ -^\[assertion.2\] assertion at file test_int.java line 9: SUCCESS$ -^\[assertion.3\] assertion at file test_int.java line 12: SUCCESS$ -^\[assertion.4\] assertion at file test_int.java line 15: SUCCESS$ -^\[assertion.5\] assertion at file test_int.java line 18: SUCCESS$ -^\[assertion.6\] assertion at file test_int.java line 21: SUCCESS$ -^\[assertion.7\] assertion at file test_int.java line 23: FAILURE$ --- diff --git a/regression/strings/java_int/test_int.class b/regression/strings/java_int/test_int.class deleted file mode 100644 index 643d7eca09cb890b7b49705679a2c8406c96efa8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1140 zcmZuwOHUJF6g^)%ueMV7Zru1Y+~J0(cczq9bo0ILJ?Gwg&dirz?>_;^;F2E-y8Y-uuOFvz z#)lU4i8$*Ak8TO)oXB|z2`}*at8+<8=yx(xA};tbfI$&M4ADN-vNY4yD~5GNx72)D zD>ATU24Pw^bbFS;n@HYa;1()HjUlwC8`{n4T3$16JINGSQ+0!(EpcygRehuml~toO zv}BvQQJQjq!6jQQJh-8*yZIu9MT{^=(}nUOzkjJxH4EA`-C+ybnq{x(hCS$z$%vv= zL|UeSvxJi|iZK~sL>Sr|)#mCWTs6&#NiB_}Gg%qqxX8c{WYZY}P9RGGHD4&on8Xxy zP_HCnTE+}$Ql&w8E5E80Y|`gHQ~i}#o0K8kz~&5FD{0h+WLN6pSR$AFS07Tja9=g& zs1Qd93j|qLO-myNhFIcXKr+V=uq)TK$8};sdstP=*0Jmp-g6zRYlFx zO|5t&8#!cGDL_syqnAD;g+4K+v^zr6$qUi}t+dAI7N?!j&iC(vy>SxJMyudHGWc); z?R2J8wgC^_fuCVtau1%x6t@HKOp2#E{fRR8cyegoHto zXC49MAY+AeFCl~{r213R{W&TAl4Sfyg6@-~9mJM^_?tjHp+%fxjC_b5ppzY-hwimg u7o8@EyYtAgQP&zE5=F}nLYok|SKz$wz%@Fo+vil_;R#-LOpdz)bo~Lq)9aJ~ diff --git a/regression/strings/java_int/test_int.java b/regression/strings/java_int/test_int.java deleted file mode 100644 index 620ae638dce..00000000000 --- a/regression/strings/java_int/test_int.java +++ /dev/null @@ -1,25 +0,0 @@ -public class test_int { - - public static void main(String[] argv) { - String s = Integer.toString(2345); - char c = s.charAt(1); - char d = s.charAt(2); - char e = s.charAt(3); - assert(c == '3'); - assert(d == '4'); - - int i = Integer.parseInt("1234"); - assert(i == 1234); - - String t = Integer.toString(-2345); - assert(t.charAt(0) == '-'); - - int j = Integer.parseInt("-4231"); - assert(j == -4231); - - String u = Integer.toHexString(43981); - assert(u.equals("abcd")); - - assert(e == '2' || i < 1234 || t.charAt(0) != '-' || j != -4231 || !u.equals("abcd")); - } -} diff --git a/regression/strings/java_prefix/test.desc b/regression/strings/java_prefix/test.desc deleted file mode 100644 index 175f934ca1d..00000000000 --- a/regression/strings/java_prefix/test.desc +++ /dev/null @@ -1,10 +0,0 @@ -FUTURE -test_prefix.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_prefix.java line 14: SUCCESS$ -^\[assertion.2\] assertion at file test_prefix.java line 16: FAILURE$ -^\[assertion.3\] assertion at file test_prefix.java line 18: SUCCESS$ -^\[assertion.4\] assertion at file test_prefix.java line 20: FAILURE$ --- diff --git a/regression/strings/java_prefix/test_prefix.class b/regression/strings/java_prefix/test_prefix.class deleted file mode 100644 index 6f5f4025932b51a8fdcec8d94d4d5032d883ee5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 933 zcmZ`%%Wl&^6g`vJvEw*RaBwh`LIVNvC=IW60il8x5J)L30*#t3kdv6=;@Xw%ApQV; zfvmb?4M>edrLgC7_yFLJMH)asvgY2IbMBpc&iLDpFCzfgv7{h_GZN0qm{$-(LB=^5 z=XqL`ae>E+Nu+T}LP8>W+~A%am>tLJF|am6qHeo(xWW)G zl{XlKHLqteWE!?>J?`&zEdMDd6R>OAEELDw`wTRlY0^7HGN8^*lVV?kc zsx}Jr*ctjYSk~ZzDT{+~7im3CyE%%CqF5P%edI*wv?iiMh9vShK{=;>r_uz)cZY~= zYVje2h9<68wZs9WmFfbm%R*I?X`5UYD?0ov-S` z0JkSVVhogZae(3kkj6k(7vCc_2KcnGXxf{YpyCRAPFBJ#6Lrs UOfvS3cNGy!-{J0_js~6k1sUzW1ONa4 diff --git a/regression/strings/java_prefix/test_prefix.java b/regression/strings/java_prefix/test_prefix.java deleted file mode 100644 index c9b5fa72fcf..00000000000 --- a/regression/strings/java_prefix/test_prefix.java +++ /dev/null @@ -1,23 +0,0 @@ -public class test_prefix { - - public static void main(String[] argv) { - String s = new String("Hello World!"); - //String t = new String("Hello"); - //String u = new String("Wello"); - String u = "Wello"; - boolean b = s.startsWith("Hello"); - //boolean c = s.startsWith("Wello"); - //boolean b = s.startsWith(t); - boolean c = s.startsWith(u); - boolean d = s.startsWith("lo",3); - if(argv.length == 1){ - assert(b); - } else if(argv.length == 2){ - assert(c); - } else if(argv.length == 3){ - assert(d); - } else if(argv.length == 4){ - assert(!d); - } - } -} diff --git a/regression/strings/java_replace/test.desc b/regression/strings/java_replace/test.desc deleted file mode 100644 index 1e89ebe37b4..00000000000 --- a/regression/strings/java_replace/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -FUTURE -test_replace.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_replace.java line 6: SUCCESS$ -^\[assertion.2\] assertion at file test_replace.java line 8: FAILURE$ --- diff --git a/regression/strings/java_replace/test_replace.class b/regression/strings/java_replace/test_replace.class deleted file mode 100644 index c795826dc15e95c6e64931bc9afb74e3617f8687..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 904 zcmZuvYi|-k6g|UhV7mx~wqg|ptqK&uTI-9(*r28+R8258tsl$+lV~aL$K@!l z$iouHRRu9*W4MOv3JNH4loTwZ%yEMuy`(vguwC6UoyWSPwG7c=V7m;Fb=}n6hYZ0& z@ijxJZgm7hqM@7Oxz}w8`;|HadBk zR#8#KO%+MZj-y^~+Z#n!aEl=`0ogd}`H5{?Hpi-p+gRhcqv9?q^n98K$2}GI@!$lF z7p;BKb{Xai|L>ZQyO6@v>&1VQNMP~a(+uYn#t67pBnPIu{^+=(OI}!>EINYIt?EmX z*(I@s)~%75eupQo8F)`78RSu7qCnjs--%pDIJzx5$AXYqu15hfeHVH9ND2CAESZtA z(k=)l9ie%SPFY$Rt>MxT?5j+~Jk1gRlF_eQz**YM)KBy@Nb9ph1a?xvAwrGiq?Pmr z2yY!A(#Kpm#RrJ?F>{F6&JfDa1I&~MP^Y7xCsA20;FnvZfHR zP((%GH%c7mXk_Vr@tFUbPZUU{5g*`8A3XF0q2M<}Cg?}aNTe_V@kg@d^M3IQe*s01 Bzfk}H diff --git a/regression/strings/java_replace/test_replace.java b/regression/strings/java_replace/test_replace.java deleted file mode 100644 index 342bf9afddc..00000000000 --- a/regression/strings/java_replace/test_replace.java +++ /dev/null @@ -1,10 +0,0 @@ -public class test_replace { - - public static void main(String[] argv) { - String s = new String("Hello World!"); - String t = s.replace('o','u'); - assert(t.equals("Hellu Wurld!")); - System.out.println(t); - assert(!t.equals("Hellu Wurld!")); - } -} diff --git a/regression/strings/java_set_length/test.desc b/regression/strings/java_set_length/test.desc deleted file mode 100644 index 43f82a648fd..00000000000 --- a/regression/strings/java_set_length/test.desc +++ /dev/null @@ -1,9 +0,0 @@ -FUTURE -test_set_length.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_set_length.java line 8: SUCCESS$ -^\[assertion.2\] assertion at file test_set_length.java line 9: SUCCESS$ -^\[assertion.3\] assertion at file test_set_length.java line 10: FAILURE$ --- diff --git a/regression/strings/java_set_length/test_set_length.class b/regression/strings/java_set_length/test_set_length.class deleted file mode 100644 index 8836640967a8736f8ecdfc31c509c8f67e5cdc31..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 887 zcmZ`%TW=CU6#j+<29~8=xfL%|t5uhRMXmJ`8>6BoO{hL#G~h$Cz=UqyE@pS|$22iM z`m839*hJs`Pa4l`OHtI9GiSazm+w1gzW@C46~G$q=$J!^V=;lVIwCly%#t$alQ3{W z$1*N*T+)$5NnI{;SUSpB;ixcVm+c@BzH|m&@W=`5jw^Z$tj!SLa6CueW6-Sf3x;TY z&=U;v4aXBthkG62KUcx@uxC3SL&190*tOrd)}2NS`MeShE^xPf)jHPe^lrh!|y&0tP5pLKRcSN;JV z3T4P!|5l$QDUDDGP0HF-14+oiBr9i?|4w7j18Ms*c9pG^`lrCE1r zr?iot2pnJZj`h+a;$8!v2fk; z7RD>SReQH)H3K~9Rx!t*E!65K{CcI)a%=pVkZd`hd;X>uly6pBqHc3{O7a>QLY5)> ze~-t<7zVZJ@-6W`Z{QB@QiJ@iuqNr$Qiwx@_P{l(7i&$bvcBx)ecX-V|lR9>VthJg=B4(H@^ziIl>SRRH zp!tmsN2X9b2PA~<`IhT@>%xD_FxZQpu2!SwCy+!}@JgMY0$rrdJ>hcu)C#&kzeOMD z9c*BP9#@*)Axq|@m$XwrHOSJMqth@&MloU@fPIlbT%a`?BpG73h)cAW&|g%lQ2b~f zMLuEg5TVxxP|D+}a2t{JaWgy}#8i}m8IgyS8f4ng*1jUPkIY0$Z=-J?eTOipIR2xP z?r$T}Bb_{pmij`0J`+0a719|-KO!_(ltxieqWmoSuuA_>6>)q(0+$Jyfbs{cDuz{D v8Tw80Yq)yq!CWvbkV<2qjnqEW@MnaTZ-{jpb_|hZ5rpE)(zZMuLKyi6M=96L diff --git a/regression/strings/java_string_builder/test_string_builder.java b/regression/strings/java_string_builder/test_string_builder.java deleted file mode 100644 index 1d76b34e9f8..00000000000 --- a/regression/strings/java_string_builder/test_string_builder.java +++ /dev/null @@ -1,16 +0,0 @@ -public class test_string_builder { - public static void main(String[] argv) { - if(argv.length > 2) { - StringBuilder tmp = new StringBuilder(); - tmp.append("prefix "); - tmp.append(argv[1]); - tmp.append(" middle ").append(argv[2]).append(" end"); - //StringBuilder tmp1 = tmp.append(argv[2]); - //tmp1.append(" end"); - String r = tmp.toString(); - assert(r.startsWith("pref")); - assert(r.endsWith("end")); - assert(r.startsWith("pr3f")); - } - } -} diff --git a/regression/strings/java_string_builder_insert/test.desc b/regression/strings/java_string_builder_insert/test.desc deleted file mode 100644 index 2655f846da1..00000000000 --- a/regression/strings/java_string_builder_insert/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -FUTURE -test_insert.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_insert.java line 17: SUCCESS$ -^\[assertion.2\] assertion at file test_insert.java line 18: FAILURE$ --- diff --git a/regression/strings/java_string_builder_insert/test_insert.class b/regression/strings/java_string_builder_insert/test_insert.class deleted file mode 100644 index 69a32d7f93fa8cbebd4e1f6c84f79c41463bb3b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1049 zcmZuwT~8B16g|_Aop!sWYg<1206|e&3RFcJe$32GBpy7GK^-ah27EI6Bv_zGGturXorfvE& z48ctHHAATAR0Ts~$+X2vy|yXbR}xGIHN&(Sx-uI}+r~#DZyEMhzT~^6y;YEf@se*; z-Y*+FO+3dqY38`k5Sgx6M^~sNr|wq7GgA`kzVQ6FrY&WSNlFbVq#3%;)6dsUt14WQ z+W*OMt*XRLXqdzU4G-~%V@g8-(;SaA%*c~VNHWA0g=IOd3eutB31%63+T?S`4SDLi z4zb5h>EW2uFpnasY!|%P+!hs|A+T{a-)aIwXXgK%QCc1u`ZCWqirEXGBYy>ImG2yr zr85_Sgg7Oq^x5-8jo!_vlc>%Xt?A@n(v$c^Ba9jqq?-EArWyE-1X=W+iuh1BEbpB9 zmeoR*<|EN=K+&Qhq7kSH&vZrgq=EGEew_|zg4QuWv#8VPGQCGW1nq(#8Awy?q_19D z8Li>reXws5h%SmsGszG|H+pCFMctXt)rA_Lc*@&N*C z$>2Uh%Ok;D1K~F#4Ja#n;G+#h_7L4gdNipv5ZguU0NUC<;=fO)zqHd*PM|4g5^>sx z>3W4Eaq<))4^fh)l7l#gC^Lox{h&Ig$mc3KeMgAPRFy#B5UU(lIIePB>!Q-$6Z;cQ kpFlE&js_CD;GwSw1-~QOzWlfsk}Qlsd{%a>uc__&KWVw%^#A|> diff --git a/regression/strings/java_string_builder_insert/test_insert.java b/regression/strings/java_string_builder_insert/test_insert.java deleted file mode 100644 index 1fac897c5ed..00000000000 --- a/regression/strings/java_string_builder_insert/test_insert.java +++ /dev/null @@ -1,20 +0,0 @@ -public class test_insert { - - public static void main(String[] argv) - { - char [] str = new char[5]; - str[0] = 'H'; - str[1] = 'e'; - str[2] = 'l'; - str[3] = 'l'; - str[4] = 'o'; - - - StringBuilder sb = new StringBuilder(" world"); - sb.insert(0,str); - String s = sb.toString(); - System.out.println(s); - assert(s.equals("Hello world")); - assert(!s.equals("Hello world")); - } -} diff --git a/regression/strings/java_string_builder_length/test.desc b/regression/strings/java_string_builder_length/test.desc deleted file mode 100644 index c4720992571..00000000000 --- a/regression/strings/java_string_builder_length/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -FUTURE -test_sb_length.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -\[assertion.1\] assertion at file test_sb_length.java line 6: SUCCESS$ -\[assertion.2\] assertion at file test_sb_length.java line 8: FAILURE$ --- diff --git a/regression/strings/java_string_builder_length/test_sb_length.class b/regression/strings/java_string_builder_length/test_sb_length.class deleted file mode 100644 index 586e8f71935b9b16a50d4a4a6ad14c4069667c5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 791 zcmZuv&rcIk5dPkFyT7`H((4HUL5zx!m=rzKNWcSm?LOV z9Ojj`VB)$1TY(lG+`vr}w-`!`JdQ<_$Zi-vmN9Py!e?N+491!aWpbY(<1M{l(AT@Z zU>I-6P(1A)v_$k=fhlpoWymn?y=?6Bx4a(kuv2d)kqkSlsxaS7c>B#3@1=NB$Y8Ct zgOlb?v)hl_VpFPCr9{NZUfkLXMA%7Quc&@53YcJ+`M39@z6^X3kXegw9BMV3A)KH=IOL~x;`tE)v)Ac zK*BLWZ;`&{$TG6o>JaR+0-{8(kp>z43X_;3UqRnfsYZ752-;3DGlbr#6|(~v+h1TF zVzM@XRj@xGcLaN92s!bMJ{(&0yQp#NU4b&{7CjbBd diff --git a/regression/strings/java_string_builder_length/test_sb_length.java b/regression/strings/java_string_builder_length/test_sb_length.java deleted file mode 100644 index 652b72cdc90..00000000000 --- a/regression/strings/java_string_builder_length/test_sb_length.java +++ /dev/null @@ -1,11 +0,0 @@ -public class test_sb_length { - public static void main(String[] argv) { - StringBuilder tmp = new StringBuilder("prefix"); - //tmp.append("prefix"); - tmp.append("end"); - assert(tmp.length() == 9); - if(argv.length > 1) { - assert(tmp.length() == 12); - } - } -} diff --git a/regression/strings/java_strlen/test.desc b/regression/strings/java_strlen/test.desc deleted file mode 100644 index b98e6f76f0a..00000000000 --- a/regression/strings/java_strlen/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -FUTURE -test_length.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_length.java line 10: SUCCESS$ -^\[assertion.2\] assertion at file test_length.java line 11: FAILURE$ --- diff --git a/regression/strings/java_strlen/test_length.class b/regression/strings/java_strlen/test_length.class deleted file mode 100644 index 7f1c10c02ca3c0b61fb85561752aa7e23c0b36f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 864 zcmZuvU2hUW6g{)-7t3NPNTn*;D&j)1XsbSGZEUb6O{gYfOj;kzvP@v>cGv7K{+Pb_ zV&bzJA+bq)_eWXpP$^YOcJIubIrrWcl!+6@C`+|*z(Km<~A3FT0E2?E;9>s4w?swzfvZ!YwgIU7=t<9kHxaS38ziMI$H50e6Y@&|a zCeC4op)kqW7>nEt!ysfxooS=tj)@hl{?+7pdyhLY`7=coL*AOMRXsWQ$g?f7&@<(h| z<(2K)0Lpr8X#n+sJTDgq(C#Z=pdTQcS2Dd1NF5@%GlcQu6b#OQqOmk;T&9+Q3 1) { - String t = argv[1]; - int i = t.length(); - String u = t.concat(s); - char c = u.charAt(i); - assert(c == 'h'); - assert(c == 'o'); - } - } -} diff --git a/regression/strings/java_substring/test.desc b/regression/strings/java_substring/test.desc deleted file mode 100644 index bd54a8204fe..00000000000 --- a/regression/strings/java_substring/test.desc +++ /dev/null @@ -1,10 +0,0 @@ -FUTURE -test_substring.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_substring.java line 12: SUCCESS$ -^\[assertion.2\] assertion at file test_substring.java line 13: FAILURE$ -^\[assertion.3\] assertion at file test_substring.java line 20: SUCCESS$ -^\[assertion.4\] assertion at file test_substring.java line 21: FAILURE$ --- diff --git a/regression/strings/java_substring/test_substring.class b/regression/strings/java_substring/test_substring.class deleted file mode 100644 index e6532aca43e8ec0108d5f9108ccd271907039b70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1051 zcmbVK-%ry}7(I9EkI@wv%poEuD9U~yQxG(P5D+xZfSSyZfDfkI8Yqqq+fLv7BYfmV z5{*2o$%vZZyML5;ZjlYtCzIxDd+#~tyXSoO$Iq_^048wDfQfzs1Gpf|MOg;hU|>kc zB?H>g-sL!kF{tB;fvXtNkrqe}TfT35fm3t+MaQ>FRl6b})&#T}$8~~PfoM9jBA_hP zDz-r9lH=MB>suw;dm_Qy*s>f~peOxwY14XX<*Syvo-YQT@XW85{7_^}s+#CTftPrCe+m_d~T9)xMxDg8$T$W+I`P2Vqrsc$I1Bv=l=h ztqt;T1aV$66L*--3iDZIHWt&_pyh4yUJ?D85xhYPAIM5kbq?ww37U=`9cTFn!3YnD zj2tbo@gZ)v0KH9sAb<)noNG>CGK?DNPQqv)z5`v^gA)A=wdLS=9J0HLNc)@|T3=}J F{4e6h&lUgx diff --git a/regression/strings/java_substring/test_substring.java b/regression/strings/java_substring/test_substring.java deleted file mode 100644 index 8a2ac883cca..00000000000 --- a/regression/strings/java_substring/test_substring.java +++ /dev/null @@ -1,27 +0,0 @@ -public class test_substring { - - public static void main(String[] argv) { - if(argv.length > 1) { - String t = argv[1]; - - if(t.length() == 6) { - String u = t.substring(2,4); - char c = u.charAt(1); - char d = t.charAt(3); - char e = t.charAt(4); - assert(c == d); - assert(c == e); - } - else if(t.length() == 5){ - CharSequence u = t.subSequence(2,4); - char c = u.charAt(1); - char d = t.charAt(3); - char e = t.charAt(4); - assert(c == d); - assert(c == e); - } - - - } - } -} diff --git a/regression/strings/java_suffix/test.desc b/regression/strings/java_suffix/test.desc deleted file mode 100644 index 2740e87d6e4..00000000000 --- a/regression/strings/java_suffix/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -FUTURE -test_suffix.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_suffix.java line 12: SUCCESS$ -^\[assertion.2\] assertion at file test_suffix.java line 13: FAILURE$ --- diff --git a/regression/strings/java_suffix/test_suffix.class b/regression/strings/java_suffix/test_suffix.class deleted file mode 100644 index 557acd02653a0558f2ddb5117649f5cdd387e77e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 811 zcmZ`%(M}UV6g|^!JKOD+*4APbixf}`1*#H#kq`)Kd?@-*V*@^zZFj)IW!LOZjUV9` z^ap%alQxk=-~A}{&ZbZ_m~8IcJ#*&XbMDN~U*En1SjW1BDO5RTP28}Mz?_MiiFuta z=&+c9jhh^|ELfU%+d>^n9Lo%)MJI|xsAS+rk7VR@J>fF2eTMXg^rhNlNY5FImIq#jO=lF-swhE z$zX2uym5W29rVMVcp`PRf)bH>9rX_mGH=qZ}n1x^{t^^5(R z!gr&NRB!%6p;23razZsGIk%LKC7Bi%HmHxI!_Z8YL zBk`Mn6i0>QDt(Of7KwcA%*6dzEukgYL*xeF#wQrbugFYVojTGbQ%K~twC|Z%$@M>U CNTL-0 diff --git a/regression/strings/java_suffix/test_suffix.java b/regression/strings/java_suffix/test_suffix.java deleted file mode 100644 index f61b0b8ba36..00000000000 --- a/regression/strings/java_suffix/test_suffix.java +++ /dev/null @@ -1,15 +0,0 @@ -public class test_suffix { - - public static void main(String[] argv) { - String s = new String("Hello World!"); - //String t = new String("Hello"); - //String u = new String("Wello"); - String u = "Wello!"; - boolean b = s.endsWith("World!"); - //boolean c = s.startsWith("Wello"); - //boolean b = s.startsWith(t); - boolean c = s.startsWith(u); - assert(b); - assert(c); - } -} diff --git a/regression/strings/java_trim/test.desc b/regression/strings/java_trim/test.desc deleted file mode 100644 index 7c0f1a87978..00000000000 --- a/regression/strings/java_trim/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -FUTURE -test_trim.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_trim.java line 5: SUCCESS$ -^\[assertion.2\] assertion at file test_trim.java line 6: FAILURE$ --- diff --git a/regression/strings/java_trim/test_trim.class b/regression/strings/java_trim/test_trim.class deleted file mode 100644 index 8e6a923dcbc867d6e06db7e6b4ad880270c3084d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 730 zcmZWn%Wl&^6g}fd#&Mk{Bxwkb5*JGA^pyny7OfDdz$z_^ASB8Hjh#{D)^Vuq@G<#; zt^p~PK!QF01mccM5-MbC=FWYbd(WBq`TOg401wcy;ozo)TQ+WExdGLoZekA)0?1-VT7sg@sghBV(Zy1dIVP7(oyJ0L3 zM+09buT?Sy1|p0Z8s59^iTEfwk%*5wy(|gi<6Tu)>SZE0JrE!Ae2#SnYcGiYg4?~} zC<)}tP(dwbGR@vo>0n1eIVhvTP;_14`flJ7iFF4a+73!sWH58LgAHslH0RBqO&PsN zl3_v<3O{fOXNJzP Date: Thu, 30 Mar 2017 09:13:33 +0100 Subject: [PATCH 35/52] New class for sparse vectors in util Sparse vectors represent a 2^64 sized space while allocating only space that is used. --- src/util/sparse_vector.h | 60 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/util/sparse_vector.h diff --git a/src/util/sparse_vector.h b/src/util/sparse_vector.h new file mode 100644 index 00000000000..6c4e050b323 --- /dev/null +++ b/src/util/sparse_vector.h @@ -0,0 +1,60 @@ +/*******************************************************************\ + +Module: Sparse Vectors + +Author: Romain Brenguier + +\*******************************************************************/ + +#ifndef CPROVER_UTIL_SPARSE_VECTOR_H +#define CPROVER_UTIL_SPARSE_VECTOR_H + +#include + +template class sparse_vectort +{ +protected: + typedef std::map underlyingt; + underlyingt underlying; + uint64_t _size; + +public: + sparse_vectort() : + _size(0) {} + + const T &operator[](uint64_t idx) const + { + assert(idx<_size && "index out of range"); + return underlying[idx]; + } + + T &operator[](uint64_t idx) + { + assert(idx<_size && "index out of range"); + return underlying[idx]; + } + + uint64_t size() const + { + return _size; + } + + void resize(uint64_t new_size) + { + assert(new_size>=_size && "sparse vector can't be shrunk (yet)"); + _size=new_size; + } + + typedef typename underlyingt::iterator iteratort; + typedef typename underlyingt::const_iterator const_iteratort; + + iteratort begin() { return underlying.begin(); } + const_iteratort begin() const { return underlying.begin(); } + + iteratort end() { return underlying.end(); } + const_iteratort end() const { return underlying.end(); } + + const_iteratort find(uint64_t idx) { return underlying.find(idx); } +}; + +#endif // CPROVER_UTIL_SPARSE_VECTOR_H From 4e8af3472c988208c449e6110e201f13758f7bba Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Thu, 23 Mar 2017 10:19:41 +0000 Subject: [PATCH 36/52] Interpreter: switch to sparse vector memory map This will allow large address reservations for unbounded-sized objects, with actual cells allocated on demand. Original patch: From: Chris Smowton Date: Tue, 21 Mar 2017 15:24:03 +0000 Subject: [PATCH 1/3] Interpreter: switch to sparse vector memory map --- src/goto-programs/interpreter.cpp | 61 +++++-------- src/goto-programs/interpreter_class.h | 70 +++++++++++++-- src/goto-programs/interpreter_evaluate.cpp | 100 ++++++++++++++++++--- 3 files changed, 176 insertions(+), 55 deletions(-) diff --git a/src/goto-programs/interpreter.cpp b/src/goto-programs/interpreter.cpp index 1f9e22f485a..d9a21197fa6 100644 --- a/src/goto-programs/interpreter.cpp +++ b/src/goto-programs/interpreter.cpp @@ -635,22 +635,24 @@ exprt interpretert::get_value( if(rhs[offset]0) offset++; - + std::size_t address=memory_map[id]; + std::size_t current_size=base_address_to_alloc_size(address); // current size <= size already recorded - if(size<=offset) + if(size<=current_size) return memory_map[id]; } @@ -981,19 +973,12 @@ mp_integer interpretert::build_memory_map( if(size==0) size=1; // This is a hack to create existence - unsigned address=memory.size(); + std::size_t address=memory.size(); memory.resize(address+size); memory_map[id]=address; + inverse_memory_map[address]=id; dynamic_types.insert(std::pair(id, alloc_type)); - for(size_t i=0; i #include +#include #include "goto_functions.h" #include "goto_trace.h" @@ -71,6 +72,9 @@ class interpretert:public messaget // List of dynamically allocated symbols that are not in the symbol table typedef std::map dynamic_typest; + typedef std::map output_valuest; + output_valuest output_values; + // An assignment list annotated with the calling context. struct function_assignments_contextt { @@ -106,27 +110,78 @@ class interpretert:public messaget const goto_functionst &goto_functions; - typedef std::unordered_map memory_mapt; + typedef std::unordered_map memory_mapt; + typedef std::map inverse_memory_mapt; memory_mapt memory_map; + inverse_memory_mapt inverse_memory_map; + + const inverse_memory_mapt::value_type &address_to_object_record( + std::size_t address) const + { + auto lower_bound=inverse_memory_map.lower_bound(address); + if(lower_bound->first!=address) + { + assert(lower_bound!=inverse_memory_map.begin()); + --lower_bound; + } + return *lower_bound; + } + + irep_idt address_to_identifier(std::size_t address) const + { + return address_to_object_record(address).second; + } + + std::size_t address_to_offset(std::size_t address) const + { + return address-(address_to_object_record(address).first); + } + + std::size_t base_address_to_alloc_size(std::size_t address) const + { + assert(address_to_offset(address)==0); + auto upper_bound=inverse_memory_map.upper_bound(address); + std::size_t next_alloc_address= + upper_bound==inverse_memory_map.end() ? + memory.size() : + upper_bound->first; + return next_alloc_address-address; + } + + std::size_t base_address_to_actual_size(std::size_t address) const + { + auto memory_iter=memory.find(address); + if(memory_iter==memory.end()) + return 0; + std::size_t ret=0; + std::size_t alloc_size=base_address_to_alloc_size(address); + while(memory_iter!=memory.end() && ret memoryt; + typedef sparse_vectort memoryt; typedef std::map parameter_sett; // mapping -> value typedef std::pair struct_member_idt; typedef std::map struct_valuest; - // The memory is being annotated/reshaped even during reads // (ie to find a read-before-write location) thus memory // properties need to be mutable to avoid making all calls nonconst @@ -138,6 +193,7 @@ class interpretert:public messaget void build_memory_map(const symbolt &symbol); mp_integer build_memory_map(const irep_idt &id, const typet &type); typet concretize_type(const typet &type); + bool unbounded_size(const typet &); size_t get_size(const typet &type); irep_idt get_component_id(const irep_idt &object, unsigned offset); @@ -172,6 +228,10 @@ class interpretert:public messaget mp_integer address, mp_vectort &dest) const; + void read_unbounded( + mp_integer address, + mp_vectort &dest) const; + virtual void command(); class stack_framet diff --git a/src/goto-programs/interpreter_evaluate.cpp b/src/goto-programs/interpreter_evaluate.cpp index a8da762a7ea..235955a2416 100644 --- a/src/goto-programs/interpreter_evaluate.cpp +++ b/src/goto-programs/interpreter_evaluate.cpp @@ -46,6 +46,34 @@ void interpretert::read( } } +void interpretert::read_unbounded( + mp_integer address, + mp_vectort &dest) const +{ + // copy memory region + std::size_t address_val=integer2size_t(address); + const std::size_t offset=address_to_offset(address_val); + const std::size_t alloc_size= + base_address_to_actual_size(address_val-offset); + const std::size_t to_read=alloc_size-offset; + for(size_t i=0; i0) - cell.initialized=0; + if(cell.second.initialized>0) + cell.second.initialized=0; } } @@ -421,7 +449,8 @@ void interpretert::evaluate( } else if(expr.id()==ID_struct) { - dest.reserve(get_size(expr.type())); + if(!unbounded_size(expr.type())) + dest.reserve(get_size(expr.type())); bool error=false; forall_operands(it, expr) @@ -436,9 +465,9 @@ void interpretert::evaluate( mp_vectort tmp; evaluate(*it, tmp); - if(tmp.size()==sub_size) + if(unbounded_size(it->type()) || tmp.size()==sub_size) { - for(size_t i=0; i0 && address size; + if(ty.size().id()==ID_infinity) + size.push_back(0); + else + evaluate(ty.size(), size); + if(size.size()==1) + { + std::size_t size_int=integer2size_t(size[0]); + for(std::size_t i=0; i where; + std::vector new_value; + evaluate(wexpr.where(), where); + evaluate(wexpr.new_value(), new_value); + const auto &subtype=expr.type().subtype(); + if(!new_value.empty() && where.size()==1 && !unbounded_size(subtype)) + { + // Ignore indices < 0, which the string solver sometimes produces + if(where[0]<0) + return; + std::size_t where_idx=integer2size_t(where[0]); + std::size_t subtype_size=get_size(subtype); + std::size_t need_size=(where_idx+1)*subtype_size; + if(dest.size() Date: Thu, 23 Mar 2017 11:15:30 +0000 Subject: [PATCH 37/52] Add support for unbounded-size objects They get allocated 2^32 address space each (of a 2^64 sized space) using the sparse-vector memory representation to keep the actual storage requirements sensible. Original patch: From: Chris Smowton Date: Tue, 21 Mar 2017 17:13:43 +0000 Subject: [PATCH 2/3] Add support for unbounded-size objects Corrected linting issues Using empty, and comments on get_size --- src/goto-programs/interpreter.cpp | 77 +++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 15 deletions(-) diff --git a/src/goto-programs/interpreter.cpp b/src/goto-programs/interpreter.cpp index d9a21197fa6..5e06c8ec2be 100644 --- a/src/goto-programs/interpreter.cpp +++ b/src/goto-programs/interpreter.cpp @@ -520,16 +520,25 @@ exprt interpretert::get_value( exprt result=array_exprt(to_array_type(real_type)); const exprt &size_expr=static_cast(type.find(ID_size)); size_t subtype_size=get_size(type.subtype()); - mp_integer mp_count; - to_integer(size_expr, mp_count); - unsigned count=integer2unsigned(mp_count); + std::size_t count; + if(size_expr.id()!=ID_constant) + { + count=base_address_to_actual_size(offset)/subtype_size; + } + else + { + mp_integer mp_count; + to_integer(size_expr, mp_count); + count=integer2size_t(mp_count); + } // Retrieve the value for each member in the array result.reserve_operands(count); for(unsigned i=0; i>>>>>> fef1fed6b... update interpreter { + if(unbounded_size(type)) + return 2ULL << 32ULL; + if(type.id()==ID_struct) { const struct_typet::componentst &components= @@ -1084,7 +1128,7 @@ exprt interpretert::get_value(const irep_idt &id) symbol_exprt symbol_expr(id, get_type); mp_integer whole_lhs_object_address=evaluate_address(symbol_expr); - return get_value(get_type, integer2unsigned(whole_lhs_object_address)); + return get_value(get_type, integer2size_t(whole_lhs_object_address)); } void interpreter( @@ -1114,10 +1158,13 @@ Function: interpretert::print_memory void interpretert::print_memory(bool input_flags) { - for(size_t i=0; i(cell.initialized) << ")" From c73de2c78c944b0bcf57519f51793d247fae0b63 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Tue, 28 Mar 2017 17:53:51 +0100 Subject: [PATCH 38/52] Display dynamic object names as 'data' in JSON traces Fixes diffblue/test-gen#147 --- src/util/json_expr.cpp | 70 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/src/util/json_expr.cpp b/src/util/json_expr.cpp index 511e37ef681..90d9846b07c 100644 --- a/src/util/json_expr.cpp +++ b/src/util/json_expr.cpp @@ -17,9 +17,65 @@ Author: Peter Schrammel #include "fixedbv.h" #include "std_expr.h" #include "config.h" +#include "identifier.h" #include "json_expr.h" +/*******************************************************************\ + +Function: simplify_json_expr + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +static exprt simplify_json_expr( + const exprt &src, + const namespacet &ns) +{ + if(src.id()==ID_constant) + { + const typet &type=ns.follow(src.type()); + + if(type.id()==ID_pointer) + { + const irep_idt &value=to_constant_expr(src).get_value(); + + if(value!=ID_NULL && + (value!=std::string(value.size(), '0') || + !config.ansi_c.NULL_is_zero) && + src.operands().size()==1 && + src.op0().id()!=ID_constant) + // try to simplify the constant pointer + return simplify_json_expr(src.op0(), ns); + } + } + else if(src.id()==ID_address_of && + src.operands().size()==1 && + src.op0().id()==ID_member && + id2string(to_member_expr( + src.op0()).get_component_name()).find("@")!=std::string::npos) + { + // simplify things of the form &member_expr(object, @class_identifier) + return simplify_json_expr(src.op0(), ns); + } + else if(src.id()==ID_member && + src.operands().size()==1 && + id2string( + to_member_expr(src).get_component_name()) + .find("@")!=std::string::npos) + { + // simplify things of the form member_expr(object, @class_identifier) + return simplify_json_expr(src.op0(), ns); + } + + return src; +} + json_objectt json(const source_locationt &location) { json_objectt result; @@ -229,9 +285,19 @@ json_objectt json( else if(type.id()==ID_pointer) { result["name"]=json_stringt("pointer"); - result["binary"]=json_stringt(expr.get_string(ID_value)); - if(expr.get(ID_value)==ID_NULL) + exprt simpl_expr=simplify_json_expr(expr, ns); + if(simpl_expr.get(ID_value)==ID_NULL || + // remove typecast on NULL + (simpl_expr.id()==ID_constant && simpl_expr.type().id()==ID_pointer && + simpl_expr.op0().get(ID_value)==ID_NULL)) result["data"]=json_stringt("NULL"); + else if(simpl_expr.id()==ID_symbol) + { + const irep_idt &ptr_id=to_symbol_expr(simpl_expr).get_identifier(); + identifiert identifier(id2string(ptr_id)); + assert(!identifier.components.empty()); + result["data"]=json_stringt(identifier.components.back()); + } } else if(type.id()==ID_bool) { From a2925bb3a06c18206a4f9a5b2f09ac582f97b58c Mon Sep 17 00:00:00 2001 From: Lucas Cordeiro Date: Mon, 6 Mar 2017 09:46:38 +0000 Subject: [PATCH 39/52] set internal for specific variables in the counterexample trace for test-gen-support set internal for variable assignments related to dynamic_object[0-9], dynamic_[0-9]_array, _start function-return step, and CPROVER internal functions (e.g., __CPROVER_initialize). This PR fixes diffblue/test-gen#20. --- src/goto-symex/build_goto_trace.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/goto-symex/build_goto_trace.cpp b/src/goto-symex/build_goto_trace.cpp index 7b6a367f6b2..34f94b9168d 100644 --- a/src/goto-symex/build_goto_trace.cpp +++ b/src/goto-symex/build_goto_trace.cpp @@ -214,6 +214,9 @@ void build_goto_trace( goto_trace_step.formatted=SSA_step.formatted; goto_trace_step.identifier=SSA_step.identifier; + // hide specific variables in the counterexample trace + update_fields_to_hidden(SSA_step, goto_trace_step, ns); + goto_trace_step.assignment_type= (it->is_assignment()&& (SSA_step.assignment_type== From 55b4b240660c290a28d1019fd8c80e8f1a1310c6 Mon Sep 17 00:00:00 2001 From: Lucas Cordeiro Date: Tue, 28 Mar 2017 16:00:35 +0100 Subject: [PATCH 40/52] added internal field to json output Added internal field to json output so that we set it to tru as we find some specific variable that is not supposed to be shown in the counterexample trace. --- src/goto-programs/goto_trace.h | 4 ++ src/goto-programs/json_goto_trace.cpp | 6 ++ src/goto-symex/build_goto_trace.cpp | 84 ++++++++++++++++++++++++++- 3 files changed, 92 insertions(+), 2 deletions(-) diff --git a/src/goto-programs/goto_trace.h b/src/goto-programs/goto_trace.h index 16010145b61..02f230e8943 100644 --- a/src/goto-programs/goto_trace.h +++ b/src/goto-programs/goto_trace.h @@ -83,6 +83,9 @@ class goto_trace_stept // we may choose to hide a step bool hidden; + // this is related to an internal expression + bool internal; + // we categorize enum class assignment_typet { STATE, ACTUAL_PARAMETER }; assignment_typet assignment_type; @@ -127,6 +130,7 @@ class goto_trace_stept step_nr(0), type(typet::NONE), hidden(false), + internal(false), assignment_type(assignment_typet::STATE), thread_nr(0), cond_value(false), diff --git a/src/goto-programs/json_goto_trace.cpp b/src/goto-programs/json_goto_trace.cpp index ddc9f44ad3b..40ed6f29c30 100644 --- a/src/goto-programs/json_goto_trace.cpp +++ b/src/goto-programs/json_goto_trace.cpp @@ -59,6 +59,7 @@ void convert( json_failure["stepType"]=json_stringt("failure"); json_failure["hidden"]=jsont::json_boolean(step.hidden); + json_failure["internal"]=jsont::json_boolean(step.internal); json_failure["thread"]=json_numbert(std::to_string(step.thread_nr)); json_failure["reason"]=json_stringt(id2string(step.comment)); json_failure["property"]=json_stringt(id2string(property_id)); @@ -109,6 +110,7 @@ void convert( json_assignment["value"]=full_lhs_value; json_assignment["lhs"]=json_stringt(full_lhs_string); json_assignment["hidden"]=jsont::json_boolean(step.hidden); + json_assignment["internal"]=jsont::json_boolean(step.internal); json_assignment["thread"]=json_numbert(std::to_string(step.thread_nr)); json_assignment["assignmentType"]= @@ -126,6 +128,7 @@ void convert( json_output["stepType"]=json_stringt("output"); json_output["hidden"]=jsont::json_boolean(step.hidden); + json_output["internal"]=jsont::json_boolean(step.internal); json_output["thread"]=json_numbert(std::to_string(step.thread_nr)); json_output["outputID"]=json_stringt(id2string(step.io_id)); @@ -150,6 +153,7 @@ void convert( json_input["stepType"]=json_stringt("input"); json_input["hidden"]=jsont::json_boolean(step.hidden); + json_input["internal"]=jsont::json_boolean(step.internal); json_input["thread"]=json_numbert(std::to_string(step.thread_nr)); json_input["inputID"]=json_stringt(id2string(step.io_id)); @@ -178,6 +182,7 @@ void convert( json_call_return["stepType"]=json_stringt(tag); json_call_return["hidden"]=jsont::json_boolean(step.hidden); + json_call_return["internal"]=jsont::json_boolean(step.internal); json_call_return["thread"]=json_numbert(std::to_string(step.thread_nr)); const symbolt &symbol=ns.lookup(step.identifier); @@ -201,6 +206,7 @@ void convert( json_objectt &json_location_only=dest_array.push_back().make_object(); json_location_only["stepType"]=json_stringt("location-only"); json_location_only["hidden"]=jsont::json_boolean(step.hidden); + json_location_only["internal"]=jsont::json_boolean(step.internal); json_location_only["thread"]= json_numbert(std::to_string(step.thread_nr)); json_location_only["sourceLocation"]=json_location; diff --git a/src/goto-symex/build_goto_trace.cpp b/src/goto-symex/build_goto_trace.cpp index 34f94b9168d..8bee16c6bd1 100644 --- a/src/goto-symex/build_goto_trace.cpp +++ b/src/goto-symex/build_goto_trace.cpp @@ -109,6 +109,86 @@ exprt adjust_lhs_object( return nil_exprt(); } +/*******************************************************************\ + +Function: set_internal_dynamic_object + + Inputs: + + Outputs: + + Purpose: set internal field for variable assignment related to + dynamic_object[0-9] and dynamic_[0-9]_array. + +\*******************************************************************/ + +void set_internal_dynamic_object( + const exprt &expr, + goto_trace_stept &goto_trace_step, + const namespacet &ns) +{ + if(expr.id()==ID_symbol) + { + const irep_idt &id=to_ssa_expr(expr).get_original_name(); + const symbolt *symbol; + if(!ns.lookup(id, symbol)) + { + bool result=symbol->type.get_bool("#dynamic"); + if(result) + goto_trace_step.internal=true; + } + } + else + { + forall_operands(it, expr) + set_internal_dynamic_object(*it, goto_trace_step, ns); + } +} + +/*******************************************************************\ + +Function: update_internal_field + + Inputs: + + Outputs: + + Purpose: set internal for variables assignments related to + dynamic_object and CPROVER internal functions + (e.g., __CPROVER_initialize) + +\*******************************************************************/ + +void update_internal_field( + const symex_target_equationt::SSA_stept &SSA_step, + goto_trace_stept &goto_trace_step, + const namespacet &ns) +{ + // set internal for dynamic_object in both lhs and rhs expressions + set_internal_dynamic_object(SSA_step.ssa_lhs, goto_trace_step, ns); + set_internal_dynamic_object(SSA_step.ssa_rhs, goto_trace_step, ns); + + // set internal field to CPROVER functions (e.g., __CPROVER_initialize) + if(SSA_step.is_function_call()) + { + if(SSA_step.source.pc->source_location.as_string().empty()) + goto_trace_step.internal=true; + } + + // set internal field to input and output steps + if(goto_trace_step.type==goto_trace_stept::OUTPUT || + goto_trace_step.type==goto_trace_stept::INPUT) + { + goto_trace_step.internal=true; + } + + // set internal field to _start function-return step + if(SSA_step.source.pc->function==goto_functionst::entry_point()) + { + goto_trace_step.internal=true; + } +} + void build_goto_trace( const symex_target_equationt &target, symex_target_equationt::SSA_stepst::const_iterator end_step, @@ -214,8 +294,8 @@ void build_goto_trace( goto_trace_step.formatted=SSA_step.formatted; goto_trace_step.identifier=SSA_step.identifier; - // hide specific variables in the counterexample trace - update_fields_to_hidden(SSA_step, goto_trace_step, ns); + // update internal field for specific variables in the counterexample + update_internal_field(SSA_step, goto_trace_step, ns); goto_trace_step.assignment_type= (it->is_assignment()&& From 557d829a97d4feca5fde4707bb6e3a23456d57ac Mon Sep 17 00:00:00 2001 From: Joel Allred Date: Fri, 31 Mar 2017 14:02:16 +0100 Subject: [PATCH 41/52] Add includes to sparse_vector.h Fixes a build issue with testgen --- src/util/sparse_vector.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/util/sparse_vector.h b/src/util/sparse_vector.h index 6c4e050b323..193e9a68a01 100644 --- a/src/util/sparse_vector.h +++ b/src/util/sparse_vector.h @@ -9,7 +9,9 @@ Author: Romain Brenguier #ifndef CPROVER_UTIL_SPARSE_VECTOR_H #define CPROVER_UTIL_SPARSE_VECTOR_H -#include +#include +#include +#include template class sparse_vectort { From 01474a92cd5e50720dc09e22b9e1240d1f063715 Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Mon, 13 Mar 2017 15:37:51 +0000 Subject: [PATCH 42/52] Adding conversion for functions of the Java Character library This processing of java method calls is meant to replace simple methods of the Character Java by expressions on characters. About 60% of the library is supported, but for some of this methods are limited to ASCII characters. This is meant to be run in conjunction with the string refinement so it is called if the string-refine option is activated. Rename conversion_input to conversion_inputt Corrected linting issues --- .../character_refine_preprocess.cpp | 1968 ++++++++++++----- .../character_refine_preprocess.h | 143 +- 2 files changed, 1544 insertions(+), 567 deletions(-) diff --git a/src/java_bytecode/character_refine_preprocess.cpp b/src/java_bytecode/character_refine_preprocess.cpp index 912ea2ab131..8ccaf58305d 100644 --- a/src/java_bytecode/character_refine_preprocess.cpp +++ b/src/java_bytecode/character_refine_preprocess.cpp @@ -17,12 +17,21 @@ Date: March 2017 #include #include "character_refine_preprocess.h" -/// converts based on a function on expressions -/// \param expr_function: A reference to a function on expressions -/// \param target: A position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_char_function + + Inputs: + expr_function - A reference to a function on expressions + target - A position in a goto program + + Purpose: converts based on a function on expressions + +\*******************************************************************/ + codet character_refine_preprocesst::convert_char_function( exprt (*expr_function)(const exprt &chr, const typet &type), - conversion_input &target) + conversion_inputt &target) { const code_function_callt &function_call=target; assert(function_call.arguments().size()==1); @@ -32,12 +41,22 @@ codet character_refine_preprocesst::convert_char_function( return code_assignt(result, expr_function(arg, type)); } -/// The returned expression is true when the first argument is in the interval -/// defined by the lower and upper bounds (included) -/// \param arg: Expression we want to bound -/// \param lower_bound: Integer lower bound -/// \param upper_bound: Integer upper bound -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::in_interval_expr + + Inputs: + arg - Expression we want to bound + lower_bound - Integer lower bound + upper_bound - Integer upper bound + + Outputs: A Boolean expression + + Purpose: The returned expression is true when the first argument is in the + interval defined by the lower and upper bounds (included) + +\*******************************************************************/ + exprt character_refine_preprocesst::in_interval_expr( const exprt &chr, const mp_integer &lower_bound, @@ -48,11 +67,21 @@ exprt character_refine_preprocesst::in_interval_expr( binary_relation_exprt(chr, ID_le, from_integer(upper_bound, chr.type()))); } -/// The returned expression is true when the given character is equal to one of -/// the element in the list -/// \param chr: An expression of type character -/// \param list: A list of integer representing unicode characters -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::in_list_expr + + Inputs: + chr - An expression of type character + list - A list of integer representing unicode characters + + Outputs: A Boolean expression + + Purpose: The returned expression is true when the given character + is equal to one of the element in the list + +\*******************************************************************/ + exprt character_refine_preprocesst::in_list_expr( const exprt &chr, const std::list &list) { @@ -62,11 +91,21 @@ exprt character_refine_preprocesst::in_list_expr( return disjunction(ops); } -/// Determines the number of char values needed to represent the specified -/// character (Unicode code point). -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A integer expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_char_count + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A integer expression of the given type + + Purpose: Determines the number of char values needed to represent + the specified character (Unicode code point). + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_char_count( const exprt &chr, const typet &type) { @@ -75,36 +114,76 @@ exprt character_refine_preprocesst::expr_of_char_count( return if_exprt(small, from_integer(1, type), from_integer(2, type)); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.charCount:(I)I -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_char_count(conversion_input &target) +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_char_count + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.charCount:(I)I + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_char_count( + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_char_count, target); } -/// Casts the given expression to the given type -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_char_value + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Casts the given expression to the given type + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_char_value( const exprt &chr, const typet &type) { return typecast_exprt(chr, type); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.charValue:()C -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_char_value(conversion_input &target) +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_char_value + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.charValue:()C + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_char_value( + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_char_value, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.compare:(CC)I -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_compare(conversion_input &target) +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_compare + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.compare:(CC)I + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_compare(conversion_inputt &target) { const code_function_callt &function_call=target; assert(function_call.arguments().size()==2); @@ -123,10 +202,20 @@ codet character_refine_preprocesst::convert_compare(conversion_input &target) } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.digit:(CI)I -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_digit_char(conversion_input &target) +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_digit_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.digit:(CI)I + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_digit_char( + conversion_inputt &target) { const code_function_callt &function_call=target; assert(function_call.arguments().size()==2); @@ -196,20 +285,38 @@ codet character_refine_preprocesst::convert_digit_char(conversion_input &target) return code_assignt(result, tc_expr); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.digit:(II)I -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_digit_int(conversion_input &target) +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_char_is_digit_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.digit:(II)I + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_digit_int(conversion_inputt &target) { return convert_digit_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.forDigit:(II)I -/// -/// TODO: For now the radix argument is ignored -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_for_digit(conversion_input &target) +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_for_digit + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.forDigit:(II)I + + TODO: For now the radix argument is ignored + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_for_digit(conversion_inputt &target) { const code_function_callt &function_call=target; assert(function_call.arguments().size()==2); @@ -224,81 +331,155 @@ codet character_refine_preprocesst::convert_for_digit(conversion_input &target) return code_assignt(result, if_exprt(small, value1, value2)); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.getDirectionality:(C)I -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_get_directionality_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.getDirectionality:(C)I + +\*******************************************************************/ + codet character_refine_preprocesst::convert_get_directionality_char( - conversion_input &target) + conversion_inputt &target) { // TODO: This is unimplemented for now as it requires analyzing // the UnicodeData file to find characters directionality. return target; } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.getDirectionality:(I)I -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_char_is_digit_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.getDirectionality:(I)I + +\*******************************************************************/ + codet character_refine_preprocesst::convert_get_directionality_int( - conversion_input &target) + conversion_inputt &target) { return convert_get_directionality_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.getNumericValue:(C)I -/// -/// TODO: For now this is only for ASCII characters +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_get_numeric_value_char + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.getNumericValue:(C)I + + TODO: For now this is only for ASCII characters + +\*******************************************************************/ + codet character_refine_preprocesst::convert_get_numeric_value_char( - conversion_input &target) + conversion_inputt &target) { return convert_digit_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.getNumericValue:(C)I -/// -/// TODO: For now this is only for ASCII characters -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_get_numeric_value_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.getNumericValue:(C)I + + TODO: For now this is only for ASCII characters + +\*******************************************************************/ + codet character_refine_preprocesst::convert_get_numeric_value_int( - conversion_input &target) + conversion_inputt &target) { return convert_digit_int(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.getType:(C)I -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_get_type_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.getType:(C)I + +\*******************************************************************/ + codet character_refine_preprocesst::convert_get_type_char( - conversion_input &target) + conversion_inputt &target) { // TODO: This is unimplemented for now as it requires analyzing // the UnicodeData file to categorize characters. return target; } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.getType:(I)I -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_get_type_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.getType:(I)I + +\*******************************************************************/ + codet character_refine_preprocesst::convert_get_type_int( - conversion_input &target) + conversion_inputt &target) { return convert_get_type_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.hashCode:()I -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_hash_code(conversion_input &target) +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_hash_code + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.hashCode:()I + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_hash_code(conversion_inputt &target) { return convert_char_value(target); } -/// Returns the leading surrogate (a high surrogate code unit) of the surrogate -/// pair representing the specified supplementary character (Unicode code point) -/// in the UTF-16 encoding. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_high_surrogate + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Returns the leading surrogate (a high surrogate code unit) + of the surrogate pair representing the specified + supplementary character (Unicode code point) in the UTF-16 + encoding. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_high_surrogate( const exprt &chr, const typet &type) { @@ -310,43 +491,84 @@ exprt character_refine_preprocesst::expr_of_high_surrogate( return high_surrogate; } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.highSurrogate:(C)Z +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_high_surrogate + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.highSurrogate:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_high_surrogate( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_high_surrogate, target); } -/// Determines if the specified character is an ASCII lowercase character. -/// \param chr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_ascii_lower_case + + Inputs: + chr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the specified character is an ASCII lowercase + character. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_ascii_lower_case( const exprt &chr, const typet &type) { return in_interval_expr(chr, 'a', 'z'); } -/// Determines if the specified character is an ASCII uppercase character. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_ascii_upper_case + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the specified character is an ASCII uppercase + character. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_ascii_upper_case( const exprt &chr, const typet &type) { return in_interval_expr(chr, 'A', 'Z'); } -/// Determines if the specified character is a letter. -/// -/// TODO: for now this is only for ASCII characters, the -/// following unicode categories are not yet considered: -/// TITLECASE_LETTER MODIFIER_LETTER OTHER_LETTER LETTER_NUMBER -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_letter + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Determines if the specified character is a letter. + + TODO: for now this is only for ASCII characters, the + following unicode categories are not yet considered: + TITLECASE_LETTER MODIFIER_LETTER OTHER_LETTER LETTER_NUMBER + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_letter( const exprt &chr, const typet &type) { @@ -355,38 +577,68 @@ exprt character_refine_preprocesst::expr_of_is_letter( expr_of_is_ascii_lower_case(chr, type)); } -/// Determines if the specified character (Unicode code point) is alphabetic. -/// -/// TODO: for now this is only for ASCII characters, the -/// following unicode categorise are not yet considered: -/// TITLECASE_LETTER MODIFIER_LETTER OTHER_LETTER LETTER_NUMBER -/// and contributory property Other_Alphabetic as defined by the -/// Unicode Standard. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_alphabetic + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Determines if the specified character (Unicode code point) + is alphabetic. + + TODO: for now this is only for ASCII characters, the + following unicode categorise are not yet considered: + TITLECASE_LETTER MODIFIER_LETTER OTHER_LETTER LETTER_NUMBER + and contributory property Other_Alphabetic as defined by the + Unicode Standard. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_alphabetic( const exprt &chr, const typet &type) { return expr_of_is_letter(chr, type); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isAlphabetic:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_alphabetic + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isAlphabetic:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_alphabetic( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_alphabetic, target); } -/// Determines whether the specified character (Unicode code point) is in the -/// Basic Multilingual Plane (BMP). Such code points can be represented using a -/// single char. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_bmp_code_point + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines whether the specified character (Unicode code + point) is in the Basic Multilingual Plane (BMP). Such code + points can be represented using a single char. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_bmp_code_point( const exprt &chr, const typet &type) { @@ -394,20 +646,39 @@ exprt character_refine_preprocesst::expr_of_is_bmp_code_point( return is_bmp; } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isBmpCodePoint:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_bmp_code_point + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isBmpCodePoint:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_bmp_code_point( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_bmp_code_point, target); } -/// Determines if a character is defined in Unicode. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_for_is_defined + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Determines if a character is defined in Unicode. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_defined( const exprt &chr, const typet &type) { @@ -439,39 +710,67 @@ exprt character_refine_preprocesst::expr_of_is_defined( return not_exprt(disjunction(intervals)); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isDefined:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_defined_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isDefined:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_defined_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_defined, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isDefined:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_char_is_digit_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isDefined:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_defined_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_defined_char(target); } -/// Determines if the specified character is a digit. A character is a digit if -/// its general category type, provided by Character.getType(ch), is -/// DECIMAL_DIGIT_NUMBER. -/// -/// TODO: for now we only support these ranges of digits: -/// '\u0030' through '\u0039', ISO-LATIN-1 digits ('0' through '9') -/// '\u0660' through '\u0669', Arabic-Indic digits -/// '\u06F0' through '\u06F9', Extended Arabic-Indic digits -/// '\u0966' through '\u096F', Devanagari digits -/// '\uFF10' through '\uFF19', Fullwidth digits -/// Many other character ranges contain digits as well. -/// \param chr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_digit + + Inputs: + chr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Determines if the specified character is a digit. + A character is a digit if its general category type, + provided by Character.getType(ch), is DECIMAL_DIGIT_NUMBER. + + TODO: for now we only support these ranges of digits: + '\u0030' through '\u0039', ISO-LATIN-1 digits ('0' through '9') + '\u0660' through '\u0669', Arabic-Indic digits + '\u06F0' through '\u06F9', Extended Arabic-Indic digits + '\u0966' through '\u096F', Devanagari digits + '\uFF10' through '\uFF19', Fullwidth digits + Many other character ranges contain digits as well. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_digit( const exprt &chr, const typet &type) { @@ -486,54 +785,104 @@ exprt character_refine_preprocesst::expr_of_is_digit( return digit; } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isDigit:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_digit_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isDigit:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_digit_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_digit, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.digit:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_digit_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.digit:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_digit_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_digit_char(target); } -/// Determines if the given char value is a Unicode high-surrogate code unit -/// (also known as leading-surrogate code unit). -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_high_surrogate + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the given char value is a Unicode + high-surrogate code unit (also known as leading-surrogate + code unit). + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_high_surrogate( const exprt &chr, const typet &type) { return in_interval_expr(chr, 0xD800, 0xDBFF); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isHighSurrogate:(C)Z -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_is_high_surrogate( - conversion_input &target) -{ +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_high_surrogate + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isHighSurrogate:(C)Z + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_is_high_surrogate( + conversion_inputt &target) +{ return convert_char_function( &character_refine_preprocesst::expr_of_is_high_surrogate, target); } -/// Determines if the character is one of ignorable in a Java identifier, that -/// is, it is in one of these ranges: '\u0000' through '\u0008' '\u000E' through -/// '\u001B' '\u007F' through '\u009F' -/// -/// TODO: For now, we ignore the FORMAT general category value -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_identifier_ignorable + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the character is one of ignorable in a Java + identifier, that is, it is in one of these ranges: + '\u0000' through '\u0008' + '\u000E' through '\u001B' + '\u007F' through '\u009F' + + TODO: For now, we ignore the FORMAT general category value + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_identifier_ignorable( const exprt &chr, const typet &type) { @@ -545,34 +894,63 @@ exprt character_refine_preprocesst::expr_of_is_identifier_ignorable( return ignorable; } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isIdentifierIgnorable:(C)Z -/// -/// TODO: For now, we ignore the FORMAT general category value -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_identifier_ignorable_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method + Character.isIdentifierIgnorable:(C)Z + + TODO: For now, we ignore the FORMAT general category value + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_identifier_ignorable_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_identifier_ignorable, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isIdentifierIgnorable:(I)Z -/// -/// TODO: For now, we ignore the FORMAT general category value -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_identifier_ignorable_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method + Character.isIdentifierIgnorable:(I)Z + + TODO: For now, we ignore the FORMAT general category value + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_identifier_ignorable_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_identifier_ignorable_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isIdeographic:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_ideographic + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isIdeographic:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_ideographic( - conversion_input &target) + conversion_inputt &target) { const code_function_callt &function_call=target; assert(function_call.arguments().size()==1); @@ -582,11 +960,20 @@ codet character_refine_preprocesst::convert_is_ideographic( return code_assignt(result, is_ideograph); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isISOControl:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_ISO_control_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isISOControl:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_ISO_control_char( - conversion_input &target) + conversion_inputt &target) { const code_function_callt &function_call=target; assert(function_call.arguments().size()==1); @@ -597,154 +984,290 @@ codet character_refine_preprocesst::convert_is_ISO_control_char( return code_assignt(result, iso); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isISOControl:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_ISO_control_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isISOControl:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_ISO_control_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_ISO_control_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isJavaIdentifierPart:(C)Z -/// -/// TODO: For now we do not allow currency symbol, connecting punctuation, -/// combining mark, non-spacing mark -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_java_identifier_part_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isJavaIdentifierPart:(C)Z + + TODO: For now we do not allow currency symbol, connecting punctuation, + combining mark, non-spacing mark + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_java_identifier_part_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_unicode_identifier_part, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method isJavaIdentifierPart:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_java_identifier_part_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method isJavaIdentifierPart:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_java_identifier_part_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_unicode_identifier_part_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method isJavaIdentifierStart:(C)Z -/// -/// TODO: For now we only allow letters and letter numbers. -/// The java specification for this function is not precise on the -/// other characters. -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_java_identifier_start_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method isJavaIdentifierStart:(C)Z + + TODO: For now we only allow letters and letter numbers. + The java specification for this function is not precise on the + other characters. + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_java_identifier_start_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( - &character_refine_preprocesst::expr_of_is_unicode_identifier_start, target); + &character_refine_preprocesst::expr_of_is_unicode_identifier_part, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method isJavaIdentifierStart:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_char_is_digit_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method isJavaIdentifierStart:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_java_identifier_start_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_java_identifier_start_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isJavaLetter:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_java_letter + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isJavaLetter:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_java_letter( - conversion_input &target) + conversion_inputt &target) { return convert_is_java_identifier_start_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method isJavaLetterOrDigit:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_java_letter_or_digit + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method isJavaLetterOrDigit:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_java_letter_or_digit( - conversion_input &target) + conversion_inputt &target) { return convert_is_java_identifier_part_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isLetter:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_letter_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isLetter:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_letter_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_letter, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isLetter:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_letter_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isLetter:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_letter_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_letter_char(target); } -/// Determines if the specified character is a letter or digit. -/// \param chr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_letter_or_digit + + Inputs: + chr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Determines if the specified character is a letter or digit. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_letter_or_digit( const exprt &chr, const typet &type) { return or_exprt(expr_of_is_letter(chr, type), expr_of_is_digit(chr, type)); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isLetterOrDigit:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_letter_or_digit_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isLetterOrDigit:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_letter_or_digit_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_digit, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isLetterOrDigit:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_letter_or_digit_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isLetterOrDigit:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_letter_or_digit_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_letter_or_digit_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isLowerCase:(C)Z -/// -/// TODO: For now we only consider ASCII characters -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_lower_case_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isLowerCase:(C)Z + + TODO: For now we only consider ASCII characters + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_lower_case_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_ascii_lower_case, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isLowerCase:(I)Z -/// -/// TODO: For now we only consider ASCII characters -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_lower_case_int() + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isLowerCase:(I)Z + + TODO: For now we only consider ASCII characters + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_lower_case_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_lower_case_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isLowSurrogate:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_low_surrogate + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isLowSurrogate:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_low_surrogate( - conversion_input &target) + conversion_inputt &target) { const code_function_callt &function_call=target; assert(function_call.arguments().size()==1); @@ -754,55 +1277,103 @@ codet character_refine_preprocesst::convert_is_low_surrogate( return code_assignt(result, is_low_surrogate); } -/// Determines whether the character is mirrored according to the Unicode -/// specification. -/// -/// TODO: For now only ASCII characters are considered -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_mirrored + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Determines whether the character is mirrored according to + the Unicode specification. + + TODO: For now only ASCII characters are considered + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_mirrored( const exprt &chr, const typet &type) { return in_list_expr(chr, {0x28, 0x29, 0x3C, 0x3E, 0x5B, 0x5D, 0x7B, 0x7D}); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isMirrored:(C)Z -/// -/// TODO: For now only ASCII characters are considered -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_mirrored_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isMirrored:(C)Z + + TODO: For now only ASCII characters are considered + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_mirrored_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_mirrored, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isMirrored:(I)Z -/// -/// TODO: For now only ASCII characters are considered -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_mirrored_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isMirrored:(I)Z + + TODO: For now only ASCII characters are considered + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_mirrored_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_mirrored_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isSpace:(C)Z -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_is_space(conversion_input &target) +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_space + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isSpace:(C)Z + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_is_space(conversion_inputt &target) { return convert_is_whitespace_char(target); } -/// Determines if the specified character is white space according to Unicode -/// (SPACE_SEPARATOR, LINE_SEPARATOR, or PARAGRAPH_SEPARATOR) -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_space_char + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the specified character is white space + according to Unicode (SPACE_SEPARATOR, LINE_SEPARATOR, or + PARAGRAPH_SEPARATOR) + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_space_char( const exprt &chr, const typet &type) { @@ -813,71 +1384,138 @@ exprt character_refine_preprocesst::expr_of_is_space_char( return or_exprt(condition0, condition1); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isSpaceChar:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_space_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isSpaceChar:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_space_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_space_char, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isSpaceChar:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_space_char_int() + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isSpaceChar:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_space_char_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_space_char(target); } -/// Determines whether the specified character (Unicode code point) is in the -/// supplementary character range. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_supplementary_code_point + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines whether the specified character (Unicode code + point) is in the supplementary character range. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_supplementary_code_point( const exprt &chr, const typet &type) { return binary_relation_exprt(chr, ID_gt, from_integer(0xFFFF, chr.type())); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isSupplementaryCodePoint:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_supplementary_code_point + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method + Character.isSupplementaryCodePoint:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_supplementary_code_point( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_supplementary_code_point, target); } -/// Determines if the given char value is a Unicode surrogate code unit. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_surrogate + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the given char value is a Unicode surrogate + code unit. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_surrogate( const exprt &chr, const typet &type) { return in_interval_expr(chr, 0xD800, 0xDFFF); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isSurrogate:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_surrogate + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isSurrogate:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_surrogate( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_surrogate, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isSurrogatePair:(CC)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_surrogate_pair + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isSurrogatePair:(CC)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_surrogate_pair( - conversion_input &target) + conversion_inputt &target) { const code_function_callt &function_call=target; assert(function_call.arguments().size()==2); @@ -889,10 +1527,20 @@ codet character_refine_preprocesst::convert_is_surrogate_pair( return code_assignt(result, and_exprt(is_high_surrogate, is_low_surrogate)); } -/// Determines if the specified character is a titlecase character. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_title_case + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the specified character is a titlecase character. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_title_case( const exprt &chr, const typet &type) { @@ -906,30 +1554,58 @@ exprt character_refine_preprocesst::expr_of_is_title_case( return disjunction(conditions); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isTitleCase:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_title_case_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isTitleCase:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_title_case_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_title_case, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isTitleCase:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_title_case_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isTitleCase:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_title_case_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_title_case_char(target); } -/// Determines if the specified character is in the LETTER_NUMBER category of -/// Unicode -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_letter_number + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the specified character is in the LETTER_NUMBER + category of Unicode + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_letter_number( const exprt &chr, const typet &type) { @@ -950,13 +1626,23 @@ exprt character_refine_preprocesst::expr_of_is_letter_number( } -/// Determines if the character may be part of a Unicode identifier. -/// -/// TODO: For now we do not allow connecting punctuation, combining mark, -/// non-spacing mark -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_unicode_identifier_part + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the character may be part of a Unicode identifier. + + TODO: For now we do not allow connecting punctuation, combining mark, + non-spacing mark + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_unicode_identifier_part( const exprt &chr, const typet &type) { @@ -967,30 +1653,60 @@ exprt character_refine_preprocesst::expr_of_is_unicode_identifier_part( return disjunction(conditions); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isUnicodeIdentifierPart:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_unicode_identifier_part_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method + Character.isUnicodeIdentifierPart:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_unicode_identifier_part_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_unicode_identifier_part, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isUnicodeIdentifierPart:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_unicode_identifier_part_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method + Character.isUnicodeIdentifierPart:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_unicode_identifier_part_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_unicode_identifier_part_char(target); } -/// Determines if the specified character is permissible as the first character -/// in a Unicode identifier. -/// \param chr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_unicode_identifier_start + + Inputs: + chr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the specified character is permissible as the + first character in a Unicode identifier. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_unicode_identifier_start( const exprt &chr, const typet &type) { @@ -998,75 +1714,145 @@ exprt character_refine_preprocesst::expr_of_is_unicode_identifier_start( expr_of_is_letter(chr, type), expr_of_is_letter_number(chr, type)); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isUnicodeIdentifierStart:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_unicode_identifier_start_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method + Character.isUnicodeIdentifierStart:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_unicode_identifier_start_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_unicode_identifier_start, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isUnicodeIdentifierStart:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_unicode_identifier_start_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method + Character.isUnicodeIdentifierStart:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_unicode_identifier_start_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_unicode_identifier_start_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isUpperCase:(C)Z -/// -/// TODO: For now we only consider ASCII characters -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_upper_case_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isUpperCase:(C)Z + + TODO: For now we only consider ASCII characters + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_upper_case_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_ascii_upper_case, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isUpperCase:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_upper_case_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isUpperCase:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_upper_case_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_upper_case_char(target); } -/// Determines whether the specified code point is a valid Unicode code point -/// value. That is, in the range of integers from 0 to 0x10FFFF -/// \param chr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_valid_code_point + + Inputs: + chr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines whether the specified code point is a valid + Unicode code point value. + That is, in the range of integers from 0 to 0x10FFFF + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_valid_code_point( const exprt &chr, const typet &type) { return binary_relation_exprt(chr, ID_le, from_integer(0x10FFFF, chr.type())); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isValidCodePoint:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_valid_code_point + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isValidCodePoint:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_valid_code_point( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_valid_code_point, target); } -/// Determines if the specified character is white space according to Java. It -/// is the case when it one of the following: * a Unicode space character -/// (SPACE_SEPARATOR, LINE_SEPARATOR, or PARAGRAPH_SEPARATOR) but is not also a -/// non-breaking space ('\u00A0', '\u2007', '\u202F'). * it is one of these: -/// U+0009 U+000A U+000B U+000C U+000D U+001C U+001D U+001E U+001F -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_whitespace + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the specified character is white space according + to Java. It is the case when it one of the following: + * a Unicode space character (SPACE_SEPARATOR, LINE_SEPARATOR, or + PARAGRAPH_SEPARATOR) but is not also a non-breaking space + ('\u00A0', '\u2007', '\u202F'). + * it is one of these: U+0009 U+000A U+000B U+000C U+000D + U+001C U+001D U+001E U+001F + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_whitespace( const exprt &chr, const typet &type) { @@ -1081,31 +1867,60 @@ exprt character_refine_preprocesst::expr_of_is_whitespace( return disjunction(conditions); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isWhitespace:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_whitespace_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isWhitespace:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_whitespace_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_whitespace, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isWhitespace:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_whitespace_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isWhitespace:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_whitespace_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_whitespace_char(target); } -/// Returns the trailing surrogate (a low surrogate code unit) of the surrogate -/// pair representing the specified supplementary character (Unicode code point) -/// in the UTF-16 encoding. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A integer expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_low_surrogate + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A integer expression of the given type + + Purpose: Returns the trailing surrogate (a low surrogate code unit) + of the surrogate pair representing the specified + supplementary character (Unicode code point) in the UTF-16 + encoding. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_low_surrogate( const exprt &chr, const typet &type) { @@ -1114,21 +1929,40 @@ exprt character_refine_preprocesst::expr_of_low_surrogate( return plus_exprt(uDC00, mod_exprt(chr, u0400)); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.lowSurrogate:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_low_surrogate + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.lowSurrogate:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_low_surrogate( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_low_surrogate, target); } -/// Returns the value obtained by reversing the order of the bytes in the -/// specified char value. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A character expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_reverse_bytes + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A character expression of the given type + + Purpose: Returns the value obtained by reversing the order of the + bytes in the specified char value. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_reverse_bytes( const exprt &chr, const typet &type) { @@ -1137,24 +1971,45 @@ exprt character_refine_preprocesst::expr_of_reverse_bytes( return plus_exprt(first_byte, second_byte); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.reverseBytes:(C)C -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_reverse_bytes + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.reverseBytes:(C)C + +\*******************************************************************/ + codet character_refine_preprocesst::convert_reverse_bytes( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_reverse_bytes, target); } -/// Converts the specified character (Unicode code point) to its UTF-16 -/// representation stored in a char array. If the specified code point is a BMP -/// (Basic Multilingual Plane or Plane 0) value, the resulting char array has -/// the same value as codePoint. If the specified code point is a supplementary -/// code point, the resulting char array has the corresponding surrogate pair. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A character array expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_to_chars + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A character array expression of the given type + + Purpose: Converts the specified character (Unicode code point) to + its UTF-16 representation stored in a char array. + If the specified code point is a BMP (Basic Multilingual + Plane or Plane 0) value, the resulting char array has the + same value as codePoint. + If the specified code point is a supplementary code point, + the resulting char array has the corresponding surrogate pair. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_to_chars( const exprt &chr, const typet &type) { @@ -1170,20 +2025,38 @@ exprt character_refine_preprocesst::expr_of_to_chars( return if_exprt(expr_of_is_bmp_code_point(chr, type), case1, case2); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.toChars:(I)[C -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_to_chars(conversion_input &target) +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_to_chars + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.toChars:(I)[C + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_to_chars(conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_to_chars, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.toCodePoint:(CC)I -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_to_code_point + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.toCodePoint:(CC)I + +\*******************************************************************/ + codet character_refine_preprocesst::convert_to_code_point( - conversion_input &target) + conversion_inputt &target) { const code_function_callt &function_call=target; assert(function_call.arguments().size()==2); @@ -1207,14 +2080,24 @@ codet character_refine_preprocesst::convert_to_code_point( return code_assignt(result, pair_value); } -/// Converts the character argument to lowercase. -/// -/// TODO: For now we only consider ASCII characters but ultimately -/// we should use case mapping information from the -/// UnicodeData file -/// \param chr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_to_lower_case + + Inputs: + chr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Converts the character argument to lowercase. + + TODO: For now we only consider ASCII characters but ultimately + we should use case mapping information from the + UnicodeData file + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_to_lower_case( const exprt &chr, const typet &type) { @@ -1225,29 +2108,57 @@ exprt character_refine_preprocesst::expr_of_to_lower_case( return res; } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.toLowerCase:(C)C -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_to_lower_case_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.toLowerCase:(C)C + +\*******************************************************************/ + codet character_refine_preprocesst::convert_to_lower_case_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_to_lower_case, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.toLowerCase:(I)I -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_to_lower_case_int() + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.toLowerCase:(I)I + +\*******************************************************************/ + codet character_refine_preprocesst::convert_to_lower_case_int( - conversion_input &target) + conversion_inputt &target) { return convert_to_lower_case_char(target); } -/// Converts the character argument to titlecase. -/// \param chr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_to_title_case + + Inputs: + chr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Converts the character argument to titlecase. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_to_title_case( const exprt &chr, const typet &type) { @@ -1281,33 +2192,61 @@ exprt character_refine_preprocesst::expr_of_to_title_case( return res; } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.toTitleCase:(C)C -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_to_title_case_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.toTitleCase:(C)C + +\*******************************************************************/ + codet character_refine_preprocesst::convert_to_title_case_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_to_title_case, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.toTitleCase:(I)I -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_to_title_case_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.toTitleCase:(I)I + +\*******************************************************************/ + codet character_refine_preprocesst::convert_to_title_case_int( - conversion_input &target) + conversion_inputt &target) { return convert_to_title_case_char(target); } -/// Converts the character argument to uppercase. -/// -/// TODO: For now we only consider ASCII characters but ultimately -/// we should use case mapping information from the -/// UnicodeData file -/// \param chr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_to_upper_case + + Inputs: + chr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Converts the character argument to uppercase. + + TODO: For now we only consider ASCII characters but ultimately + we should use case mapping information from the + UnicodeData file + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_to_upper_case( const exprt &chr, const typet &type) { @@ -1318,31 +2257,60 @@ exprt character_refine_preprocesst::expr_of_to_upper_case( return res; } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.toUpperCase:(C)C -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_to_upper_case_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.toUpperCase:(C)C + +\*******************************************************************/ + codet character_refine_preprocesst::convert_to_upper_case_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_to_upper_case, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.toUpperCase:(I)I -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_to_upper_case_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.toUpperCase:(I)I + +\*******************************************************************/ + codet character_refine_preprocesst::convert_to_upper_case_int( - conversion_input &target) + conversion_inputt &target) { return convert_to_upper_case_char(target); } -/// replace function calls to functions of the Character by an affectation if -/// possible, returns the same code otherwise. For this method to have an effect -/// initialize_conversion_table must have been called before. -/// \param code: the code of a function call -/// \return code where character function call get replaced by an simple -/// instruction +/*******************************************************************\ + +Function: character_refine_preprocesst::replace_character_call + + Inputs: + code - the code of a function call + + Outputs: code where character function call get replaced by + an simple instruction + + Purpose: replace function calls to functions of the Character by + an affectation if possible, returns the same code otherwise. + For this method to have an effect initialize_conversion_table + must have been called before. + +\*******************************************************************/ + codet character_refine_preprocesst::replace_character_call( const code_function_callt &code) const { @@ -1358,7 +2326,15 @@ codet character_refine_preprocesst::replace_character_call( return code; } -/// fill maps with correspondance from java method names to conversion functions +/*******************************************************************\ + +Function: character_refine_preprocesst::initialize_conversion_table + + Purpose: fill maps with correspondance from java method names to + conversion functions + +\*******************************************************************/ + void character_refine_preprocesst::initialize_conversion_table() { // All methods are listed here in alphabetic order diff --git a/src/java_bytecode/character_refine_preprocess.h b/src/java_bytecode/character_refine_preprocess.h index afef65eb8dc..2f41b2ec932 100644 --- a/src/java_bytecode/character_refine_preprocess.h +++ b/src/java_bytecode/character_refine_preprocess.h @@ -30,122 +30,123 @@ class character_refine_preprocesst:public messaget codet replace_character_call(const code_function_callt &call) const; private: - typedef const code_function_callt &conversion_input; - typedef codet (*conversion_functiont)(conversion_input &target); + typedef const code_function_callt &conversion_inputt; + typedef codet (*conversion_functiont)(conversion_inputt &target); // A table tells us what method to call for each java method signature std::unordered_map conversion_table; // Conversion functions static exprt expr_of_char_count(const exprt &chr, const typet &type); - static codet convert_char_count(conversion_input &target); + static codet convert_char_count(conversion_inputt &target); static exprt expr_of_char_value(const exprt &chr, const typet &type); - static codet convert_char_value(conversion_input &target); - static codet convert_compare(conversion_input &target); - static codet convert_digit_char(conversion_input &target); - static codet convert_digit_int(conversion_input &target); - static codet convert_for_digit(conversion_input &target); - static codet convert_get_directionality_char(conversion_input &target); - static codet convert_get_directionality_int(conversion_input &target); - static codet convert_get_numeric_value_char(conversion_input &target); - static codet convert_get_numeric_value_int(conversion_input &target); - static codet convert_get_type_char(conversion_input &target); - static codet convert_get_type_int(conversion_input &target); - static codet convert_hash_code(conversion_input &target); + static codet convert_char_value(conversion_inputt &target); + static codet convert_compare(conversion_inputt &target); + static codet convert_digit_char(conversion_inputt &target); + static codet convert_digit_int(conversion_inputt &target); + static codet convert_for_digit(conversion_inputt &target); + static codet convert_get_directionality_char(conversion_inputt &target); + static codet convert_get_directionality_int(conversion_inputt &target); + static codet convert_get_numeric_value_char(conversion_inputt &target); + static codet convert_get_numeric_value_int(conversion_inputt &target); + static codet convert_get_type_char(conversion_inputt &target); + static codet convert_get_type_int(conversion_inputt &target); + static codet convert_hash_code(conversion_inputt &target); static exprt expr_of_high_surrogate(const exprt &chr, const typet &type); - static codet convert_high_surrogate(conversion_input &target); + static codet convert_high_surrogate(conversion_inputt &target); static exprt expr_of_is_alphabetic(const exprt &chr, const typet &type); - static codet convert_is_alphabetic(conversion_input &target); + static codet convert_is_alphabetic(conversion_inputt &target); static exprt expr_of_is_bmp_code_point(const exprt &chr, const typet &type); - static codet convert_is_bmp_code_point(conversion_input &target); + static codet convert_is_bmp_code_point(conversion_inputt &target); static exprt expr_of_is_defined(const exprt &chr, const typet &type); - static codet convert_is_defined_char(conversion_input &target); - static codet convert_is_defined_int(conversion_input &target); + static codet convert_is_defined_char(conversion_inputt &target); + static codet convert_is_defined_int(conversion_inputt &target); static exprt expr_of_is_digit(const exprt &chr, const typet &type); - static codet convert_is_digit_char(conversion_input &target); - static codet convert_is_digit_int(conversion_input &target); + static codet convert_is_digit_char(conversion_inputt &target); + static codet convert_is_digit_int(conversion_inputt &target); static exprt expr_of_is_high_surrogate(const exprt &chr, const typet &type); - static codet convert_is_high_surrogate(conversion_input &target); + static codet convert_is_high_surrogate(conversion_inputt &target); static exprt expr_of_is_identifier_ignorable( const exprt &chr, const typet &type); - static codet convert_is_identifier_ignorable_char(conversion_input &target); - static codet convert_is_identifier_ignorable_int(conversion_input &target); - static codet convert_is_ideographic(conversion_input &target); - static codet convert_is_ISO_control_char(conversion_input &target); - static codet convert_is_ISO_control_int(conversion_input &target); - static codet convert_is_java_identifier_part_char(conversion_input &target); - static codet convert_is_java_identifier_part_int(conversion_input &target); - static codet convert_is_java_identifier_start_char(conversion_input &target); - static codet convert_is_java_identifier_start_int(conversion_input &target); - static codet convert_is_java_letter(conversion_input &target); - static codet convert_is_java_letter_or_digit(conversion_input &target); + static codet convert_is_identifier_ignorable_char(conversion_inputt &target); + static codet convert_is_identifier_ignorable_int(conversion_inputt &target); + static codet convert_is_ideographic(conversion_inputt &target); + static codet convert_is_ISO_control_char(conversion_inputt &target); + static codet convert_is_ISO_control_int(conversion_inputt &target); + static codet convert_is_java_identifier_part_char(conversion_inputt &target); + static codet convert_is_java_identifier_part_int(conversion_inputt &target); + static codet convert_is_java_identifier_start_char(conversion_inputt &target); + static codet convert_is_java_identifier_start_int(conversion_inputt &target); + static codet convert_is_java_letter(conversion_inputt &target); + static codet convert_is_java_letter_or_digit(conversion_inputt &target); static exprt expr_of_is_letter(const exprt &chr, const typet &type); - static codet convert_is_letter_char(conversion_input &target); - static codet convert_is_letter_int(conversion_input &target); + static codet convert_is_letter_char(conversion_inputt &target); + static codet convert_is_letter_int(conversion_inputt &target); static exprt expr_of_is_letter_or_digit(const exprt &chr, const typet &type); - static codet convert_is_letter_or_digit_char(conversion_input &target); - static codet convert_is_letter_or_digit_int(conversion_input &target); + static codet convert_is_letter_or_digit_char(conversion_inputt &target); + static codet convert_is_letter_or_digit_int(conversion_inputt &target); static exprt expr_of_is_ascii_lower_case(const exprt &chr, const typet &type); - static codet convert_is_lower_case_char(conversion_input &target); - static codet convert_is_lower_case_int(conversion_input &target); - static codet convert_is_low_surrogate(conversion_input &target); + static codet convert_is_lower_case_char(conversion_inputt &target); + static codet convert_is_lower_case_int(conversion_inputt &target); + static codet convert_is_low_surrogate(conversion_inputt &target); static exprt expr_of_is_mirrored(const exprt &chr, const typet &type); - static codet convert_is_mirrored_char(conversion_input &target); - static codet convert_is_mirrored_int(conversion_input &target); - static codet convert_is_space(conversion_input &target); + static codet convert_is_mirrored_char(conversion_inputt &target); + static codet convert_is_mirrored_int(conversion_inputt &target); + static codet convert_is_space(conversion_inputt &target); static exprt expr_of_is_space_char(const exprt &chr, const typet &type); - static codet convert_is_space_char(conversion_input &target); - static codet convert_is_space_char_int(conversion_input &target); + static codet convert_is_space_char(conversion_inputt &target); + static codet convert_is_space_char_int(conversion_inputt &target); static exprt expr_of_is_supplementary_code_point( const exprt &chr, const typet &type); - static codet convert_is_supplementary_code_point(conversion_input &target); + static codet convert_is_supplementary_code_point(conversion_inputt &target); static exprt expr_of_is_surrogate(const exprt &chr, const typet &type); - static codet convert_is_surrogate(conversion_input &target); - static codet convert_is_surrogate_pair(conversion_input &target); + static codet convert_is_surrogate(conversion_inputt &target); + static codet convert_is_surrogate_pair(conversion_inputt &target); static exprt expr_of_is_title_case(const exprt &chr, const typet &type); - static codet convert_is_title_case_char(conversion_input &target); - static codet convert_is_title_case_int(conversion_input &target); + static codet convert_is_title_case_char(conversion_inputt &target); + static codet convert_is_title_case_int(conversion_inputt &target); static exprt expr_of_is_letter_number(const exprt &chr, const typet &type); static exprt expr_of_is_unicode_identifier_part( const exprt &chr, const typet &type); static codet convert_is_unicode_identifier_part_char( - conversion_input &target); - static codet convert_is_unicode_identifier_part_int(conversion_input &target); + conversion_inputt &target); + static codet convert_is_unicode_identifier_part_int( + conversion_inputt &target); static exprt expr_of_is_unicode_identifier_start( const exprt &chr, const typet &type); static codet convert_is_unicode_identifier_start_char( - conversion_input &target); + conversion_inputt &target); static codet convert_is_unicode_identifier_start_int( - conversion_input &target); + conversion_inputt &target); static exprt expr_of_is_ascii_upper_case(const exprt &chr, const typet &type); - static codet convert_is_upper_case_char(conversion_input &target); - static codet convert_is_upper_case_int(conversion_input &target); + static codet convert_is_upper_case_char(conversion_inputt &target); + static codet convert_is_upper_case_int(conversion_inputt &target); static exprt expr_of_is_valid_code_point(const exprt &chr, const typet &type); - static codet convert_is_valid_code_point(conversion_input &target); + static codet convert_is_valid_code_point(conversion_inputt &target); static exprt expr_of_is_whitespace(const exprt &chr, const typet &type); - static codet convert_is_whitespace_char(conversion_input &target); - static codet convert_is_whitespace_int(conversion_input &target); + static codet convert_is_whitespace_char(conversion_inputt &target); + static codet convert_is_whitespace_int(conversion_inputt &target); static exprt expr_of_low_surrogate(const exprt &chr, const typet &type); - static codet convert_low_surrogate(conversion_input &target); + static codet convert_low_surrogate(conversion_inputt &target); static exprt expr_of_reverse_bytes(const exprt &chr, const typet &type); - static codet convert_reverse_bytes(conversion_input &target); + static codet convert_reverse_bytes(conversion_inputt &target); static exprt expr_of_to_chars(const exprt &chr, const typet &type); - static codet convert_to_chars(conversion_input &target); - static codet convert_to_code_point(conversion_input &target); + static codet convert_to_chars(conversion_inputt &target); + static codet convert_to_code_point(conversion_inputt &target); static exprt expr_of_to_lower_case(const exprt &chr, const typet &type); - static codet convert_to_lower_case_char(conversion_input &target); - static codet convert_to_lower_case_int(conversion_input &target); + static codet convert_to_lower_case_char(conversion_inputt &target); + static codet convert_to_lower_case_int(conversion_inputt &target); static exprt expr_of_to_title_case(const exprt &chr, const typet &type); - static codet convert_to_title_case_char(conversion_input &target); - static codet convert_to_title_case_int(conversion_input &target); + static codet convert_to_title_case_char(conversion_inputt &target); + static codet convert_to_title_case_int(conversion_inputt &target); static exprt expr_of_to_upper_case(const exprt &chr, const typet &type); - static codet convert_to_upper_case_char(conversion_input &target); - static codet convert_to_upper_case_int(conversion_input &target); + static codet convert_to_upper_case_char(conversion_inputt &target); + static codet convert_to_upper_case_int(conversion_inputt &target); // Helper functions static codet convert_char_function( exprt (*expr_function)(const exprt &chr, const typet &type), - conversion_input &target); + conversion_inputt &target); static exprt in_interval_expr( const exprt &chr, const mp_integer &lower_bound, From 64671ee233f921526c890902b3a3aba725ea91a8 Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Mon, 27 Mar 2017 13:17:06 +0100 Subject: [PATCH 43/52] Corrected type problem for the function Character.forDigit:(II)C --- src/java_bytecode/character_refine_preprocess.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/java_bytecode/character_refine_preprocess.cpp b/src/java_bytecode/character_refine_preprocess.cpp index 8ccaf58305d..435895f7aaf 100644 --- a/src/java_bytecode/character_refine_preprocess.cpp +++ b/src/java_bytecode/character_refine_preprocess.cpp @@ -310,7 +310,7 @@ Function: character_refine_preprocesst::convert_for_digit target - a position in a goto program Purpose: Converts function call to an assignment of an expression - corresponding to the java method Character.forDigit:(II)I + corresponding to the java method Character.forDigit:(II)C TODO: For now the radix argument is ignored @@ -323,11 +323,12 @@ codet character_refine_preprocesst::convert_for_digit(conversion_inputt &target) const exprt &digit=function_call.arguments()[0]; const exprt &result=function_call.lhs(); const typet &type=result.type(); + typecast_exprt casted_digit(digit, type); exprt d10=from_integer(10, type); - binary_relation_exprt small(digit, ID_le, d10); - plus_exprt value1(digit, from_integer('0', type)); - minus_exprt value2(plus_exprt(digit, from_integer('a', digit.type())), d10); + binary_relation_exprt small(casted_digit, ID_le, d10); + plus_exprt value1(casted_digit, from_integer('0', type)); + plus_exprt value2(minus_exprt(casted_digit, d10), from_integer('a', type)); return code_assignt(result, if_exprt(small, value1, value2)); } From 94158bf0e451d3297bd8d84ede0bd076b8ad7307 Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Fri, 17 Mar 2017 13:08:37 +0000 Subject: [PATCH 44/52] Adding options to cbmc for parameters of the string solver We add the options string-max-length, string-non-empty, and string-printable --- src/cbmc/cbmc_parse_options.cpp | 8 ++++++++ src/cbmc/cbmc_parse_options.h | 2 +- src/cbmc/cbmc_solvers.cpp | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/cbmc/cbmc_parse_options.cpp b/src/cbmc/cbmc_parse_options.cpp index bda681dd730..61678e03c03 100644 --- a/src/cbmc/cbmc_parse_options.cpp +++ b/src/cbmc/cbmc_parse_options.cpp @@ -292,6 +292,11 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options) if(cmdline.isset("refine-strings")) { options.set_option("refine-strings", true); + options.set_option("string-non-empty", cmdline.isset("string-non-empty")); + options.set_option("string-printable", cmdline.isset("string-printable")); + if(cmdline.isset("string-max-length")) + options.set_option( + "string-max-length", cmdline.get_value("string-max-length")); } if(cmdline.isset("max-node-refinement")) @@ -1085,6 +1090,9 @@ void cbmc_parse_optionst::help() " --z3 use Z3\n" " --refine use refinement procedure (experimental)\n" " --refine-strings use string refinement (experimental)\n" + " --string-non-empty add constraint that strings are non empty (experimental)\n" // NOLINT(*) + " --string-printable add constraint that strings are printable (experimental)\n" // NOLINT(*) + " --string-max-length add constraint on the length of strings (experimental)\n" // NOLINT(*) " --outfile filename output formula to given file\n" " --arrays-uf-never never turn arrays into uninterpreted functions\n" // NOLINT(*) " --arrays-uf-always always turn arrays into uninterpreted functions\n" // NOLINT(*) diff --git a/src/cbmc/cbmc_parse_options.h b/src/cbmc/cbmc_parse_options.h index c713b2ca470..8320b1a047a 100644 --- a/src/cbmc/cbmc_parse_options.h +++ b/src/cbmc/cbmc_parse_options.h @@ -41,7 +41,7 @@ class optionst; "(no-sat-preprocessor)" \ "(no-pretty-names)(beautify)" \ "(dimacs)(refine)(max-node-refinement):(refine-arrays)(refine-arithmetic)"\ - "(refine-strings)" \ + "(refine-strings)(string-non-empty)(string-printable)(string-max-length):" \ "(aig)(16)(32)(64)(LP64)(ILP64)(LLP64)(ILP32)(LP32)" \ "(little-endian)(big-endian)" \ "(show-goto-functions)(show-loops)" \ diff --git a/src/cbmc/cbmc_solvers.cpp b/src/cbmc/cbmc_solvers.cpp index 5111d21b346..41e029926e9 100644 --- a/src/cbmc/cbmc_solvers.cpp +++ b/src/cbmc/cbmc_solvers.cpp @@ -160,6 +160,39 @@ cbmc_solverst::solvert* cbmc_solverst::get_bv_refinement() return new solvert(bv_refinement, prop); } +/*******************************************************************\ + +Function: cbmc_solverst::get_string_refinement + + Outputs: a solver for cbmc + + Purpose: the string refinement adds to the bit vector refinement + specifications for functions from the Java string library + +\*******************************************************************/ + +cbmc_solverst::solvert* cbmc_solverst::get_string_refinement() +{ + propt *prop; + prop=new satcheck_no_simplifiert(); + prop->set_message_handler(get_message_handler()); + + string_refinementt *string_refinement=new string_refinementt( + ns, *prop, MAX_NB_REFINEMENT); + string_refinement->set_ui(ui); + + string_refinement->do_concretizing=options.get_bool_option("trace"); + if(options.get_bool_option("string-max-length")) + string_refinement->set_max_string_length( + options.get_signed_int_option("string-max-length")); + if(options.get_bool_option("string-non-empty")) + string_refinement->enforce_non_empty_string(); + if(options.get_bool_option("string-printable")) + string_refinement->enforce_printable_characters(); + + return new solvert(string_refinement, prop); +} + cbmc_solverst::solvert* cbmc_solverst::get_smt1(smt1_dect::solvert solver) { no_beautification(); From 39b8812061c9d2959d1f17a63a7a3bbab55af1c7 Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Fri, 17 Mar 2017 12:59:51 +0000 Subject: [PATCH 45/52] Added option to the string solver for string length and printability Added field in string_refinement and string_constraint_generator to bound size of strings in the program and enforce a range on the characters. --- .../refinement/string_constraint_generator.h | 13 +- .../string_constraint_generator_concat.cpp | 3 +- .../string_constraint_generator_main.cpp | 56 +++++-- src/solvers/refinement/string_refinement.cpp | 144 ++++++++++++++---- src/solvers/refinement/string_refinement.h | 14 +- 5 files changed, 184 insertions(+), 46 deletions(-) diff --git a/src/solvers/refinement/string_constraint_generator.h b/src/solvers/refinement/string_constraint_generator.h index 85758ba3864..d15bea25d49 100644 --- a/src/solvers/refinement/string_constraint_generator.h +++ b/src/solvers/refinement/string_constraint_generator.h @@ -33,9 +33,17 @@ class string_constraint_generatort // to the axiom list. string_constraint_generatort(): - mode(ID_unknown) + mode(ID_unknown), + max_string_length(-1), + force_printable_characters(false) { } + // Constraints on the maximal length of strings + int max_string_length; + + // Should we add constraints on the characters + bool force_printable_characters; + void set_mode(irep_idt _mode) { // only C and java modes supported @@ -81,6 +89,8 @@ class string_constraint_generatort // Maps unresolved symbols to the string_exprt that was created for them std::map unresolved_symbols; + // Set of strings that have been created by the generator + std::set created_strings; string_exprt find_or_add_string_of_symbol( const symbol_exprt &sym, @@ -107,6 +117,7 @@ class string_constraint_generatort static irep_idt extract_java_string(const symbol_exprt &s); + void add_default_axioms(const string_exprt &s); exprt axiom_for_is_positive_index(const exprt &x); // The following functions add axioms for the returned value diff --git a/src/solvers/refinement/string_constraint_generator_concat.cpp b/src/solvers/refinement/string_constraint_generator_concat.cpp index b4d33f1ba57..ffd0f0a212d 100644 --- a/src/solvers/refinement/string_constraint_generator_concat.cpp +++ b/src/solvers/refinement/string_constraint_generator_concat.cpp @@ -30,7 +30,8 @@ string_exprt string_constraint_generatort::add_axioms_for_concat( // a4 : forall i<|s1|. res[i]=s1[i] // a5 : forall i<|s2|. res[i+|s1|]=s2[i] - res.length()=plus_exprt_with_overflow_check(s1.length(), s2.length()); + equal_exprt a1(res.length(), plus_exprt_with_overflow_check(s1.length(), s2.length())); + axioms.push_back(a1); axioms.push_back(s1.axiom_for_is_shorter_than(res)); axioms.push_back(s2.axiom_for_is_shorter_than(res)); diff --git a/src/solvers/refinement/string_constraint_generator_main.cpp b/src/solvers/refinement/string_constraint_generator_main.cpp index 5c7f1b7647c..41e5e668d07 100644 --- a/src/solvers/refinement/string_constraint_generator_main.cpp +++ b/src/solvers/refinement/string_constraint_generator_main.cpp @@ -127,10 +127,11 @@ Function: string_constraint_generatort::fresh_string string_exprt string_constraint_generatort::fresh_string( const refined_string_typet &type) { - symbol_exprt length= - fresh_symbol("string_length", type.get_index_type()); + symbol_exprt length=fresh_symbol("string_length", type.get_index_type()); symbol_exprt content=fresh_symbol("string_content", type.get_content_type()); - return string_exprt(length, content, type); + string_exprt str(length, content, type); + created_strings.insert(str); + return str; } /// casts an expression to a string expression, or fetches the actual @@ -191,6 +192,45 @@ string_exprt string_constraint_generatort::convert_java_string_to_string_exprt( /*******************************************************************\ +Function: string_constraint_generatort::add_default_constraints + + Inputs: + s - a string expression + + Outputs: a string expression that is linked to the argument through + axioms that are added to the list + + Purpose: adds standard axioms about the length of the string and + its content: + * its length should be positive + * it should not exceed max_string_length + * if force_printable_characters is true then all characters + should belong to the range of ASCII characters between ' ' and '~' + + +\*******************************************************************/ + +void string_constraint_generatort::add_default_axioms( + const string_exprt &s) +{ + s.axiom_for_is_longer_than(from_integer(0, s.length().type())); + if(max_string_length>=0) + axioms.push_back(s.axiom_for_is_shorter_than(max_string_length)); + + if(force_printable_characters) + { + symbol_exprt qvar=fresh_univ_index("printable", s.length().type()); + exprt chr=s[qvar]; + and_exprt printable( + binary_relation_exprt(chr, ID_ge, from_integer(' ', chr.type())), + binary_relation_exprt(chr, ID_le, from_integer('~', chr.type()))); + string_constraintt sc(qvar, s.length(), printable); + axioms.push_back(sc); + } +} + +/*******************************************************************\ + Function: string_constraint_generatort::add_axioms_for_refined_string Inputs: an expression of refined string type @@ -203,7 +243,6 @@ Function: string_constraint_generatort::add_axioms_for_refined_string \*******************************************************************/ - string_exprt string_constraint_generatort::add_axioms_for_refined_string( const exprt &string) >>>>>>> bdbeaf586... Many corrections in string refinement @@ -218,15 +257,13 @@ string_exprt string_constraint_generatort::add_axioms_for_refined_string( { const symbol_exprt &sym=to_symbol_expr(string); string_exprt s=find_or_add_string_of_symbol(sym, type); - axioms.push_back( - s.axiom_for_is_longer_than(from_integer(0, s.length().type()))); + add_default_axioms(s); return s; } else if(string.id()==ID_nondet_symbol) { string_exprt s=fresh_string(type); - axioms.push_back( - s.axiom_for_is_longer_than(from_integer(0, s.length().type()))); + add_default_axioms(s); return s; } else if(string.id()==ID_if) @@ -236,8 +273,7 @@ string_exprt string_constraint_generatort::add_axioms_for_refined_string( else if(string.id()==ID_struct) { const string_exprt &s=to_string_expr(string); - axioms.push_back( - s.axiom_for_is_longer_than(from_integer(0, s.length().type()))); + add_default_axioms(s); return s; } else diff --git a/src/solvers/refinement/string_refinement.cpp b/src/solvers/refinement/string_refinement.cpp index 93c6d612f1e..a060faf11a9 100644 --- a/src/solvers/refinement/string_refinement.cpp +++ b/src/solvers/refinement/string_refinement.cpp @@ -50,7 +50,8 @@ string_refinementt::string_refinementt( supert(_ns, _prop), use_counter_example(false), do_concretizing(false), - initial_loop_bound(refinement_bound) + initial_loop_bound(refinement_bound), + non_empty_string(false) { } /// determine which language should be used @@ -63,6 +64,52 @@ void string_refinementt::set_mode() generator.set_mode(mode); } +/*******************************************************************\ + +Function: string_refinementt::set_max_string_length + + Inputs: + i - maximum length which is allowed for strings. + negative number means no limit + + Purpose: Add constraints on the size of strings used in the + program. + +\*******************************************************************/ + +void string_refinementt::set_max_string_length(int i) +{ + generator.max_string_length=i; +} + +/*******************************************************************\ + +Function: string_refinementt::set_max_string_length + + Purpose: Add constraints on the size of nondet character arrays + to ensure they have length at least 1 + +\*******************************************************************/ + +void string_refinementt::enforce_non_empty_string() +{ + non_empty_string=true; +} + +/*******************************************************************\ + +Function: string_refinementt::enforce_printable_characters + + Purpose: Add constraints on characters used in the program + to ensure they are printable + +\*******************************************************************/ + +void string_refinementt::enforce_printable_characters() +{ + generator.force_printable_characters=true; +} + /// display the current index set, for debugging void string_refinementt::display_index_set() { @@ -253,52 +300,71 @@ bool string_refinementt::add_axioms_for_string_assigns(const exprt &lhs, /*******************************************************************\ -Function: string_refinementt::concretize_results +Function: string_refinementt::concretize_string - Purpose: For each string whose length has been solved, add constants + Input: + expr - an expression + + Purpose: If the expression is of type string, then adds constants to the index set to force the solver to pick concrete values for each character, and fill the map `found_length` \*******************************************************************/ -void string_refinementt::concretize_results() +void string_refinementt::concretize_string(const exprt &expr) { - for(const auto& it : symbol_resolve) + if(refined_string_typet::is_refined_string_type(expr.type())) { - if(refined_string_typet::is_refined_string_type(it.second.type())) + string_exprt str=to_string_expr(expr); + exprt length=get(str.length()); + add_lemma(equal_exprt(str.length(), length)); + exprt content=str.content(); + replace_expr(symbol_resolve, content); + found_length[content]=length; + mp_integer found_length; + if(!to_integer(length, found_length)) { - string_exprt str=to_string_expr(it.second); - exprt length=current_model[str.length()]; - exprt content=str.content(); - replace_expr(symbol_resolve, content); - found_length[content]=length; - mp_integer found_length; - if(!to_integer(length, found_length)) + assert(found_length.is_long()); + if(found_length < 0) { - assert(found_length.is_long()); - if(found_length < 0) - { - debug() << "concretize_results: WARNING found length is negative" - << eom; - } - else + debug() << "concretize_results: WARNING found length is negative" + << eom; + } + else + { + size_t concretize_limit=found_length.to_long(); + concretize_limit=concretize_limit>MAX_CONCRETE_STRING_SIZE? + MAX_CONCRETE_STRING_SIZE:concretize_limit; + exprt content_expr=str.content(); + for(size_t i=0; iMAX_CONCRETE_STRING_SIZE? - MAX_CONCRETE_STRING_SIZE:concretize_limit; - exprt content_expr=str.content(); - replace_expr(current_model, content_expr); - for(size_t i=0; i found_length; From 78bacbfc87c0c31bce5ff18c6489fa151ff8244f Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Thu, 16 Mar 2017 14:54:57 +0000 Subject: [PATCH 46/52] Bug corrections in string refinement Case of array-of in substitute array access making substitute_array_access do in-place substitution Setting the type for unknown values in substitute_array_access Unknown values could cause type problems if we do not force the type for them. Setting ui for temporary solver Remove the mode option from string solver This option is no longer requiered because the implementation is now language independent. Adapt add_axioms_for_insert for 5 arguments #110 Fixed linting issue in string_constraint_generator_concat.cpp Comment on the maximal length for string Using max_string_length as the limit for refinement Using unsigned type for max string length Using const ref in substitute_array_with_expr Correcting type of max_string_length and length comparison functions space before & sign instead of after Correcting initial_loop_bound type Putting each cbmc option on a separate line for easy merging Use size_t for string sizes Add comment in concretize_string --- src/cbmc/cbmc_parse_options.h | 5 +- .../refinement/string_constraint_generator.h | 17 +- .../string_constraint_generator_concat.cpp | 3 +- .../string_constraint_generator_insert.cpp | 38 +++- .../string_constraint_generator_main.cpp | 4 +- src/solvers/refinement/string_refinement.cpp | 162 +++++++++++++++--- src/solvers/refinement/string_refinement.h | 11 +- src/util/string_expr.h | 6 +- 8 files changed, 184 insertions(+), 62 deletions(-) diff --git a/src/cbmc/cbmc_parse_options.h b/src/cbmc/cbmc_parse_options.h index 8320b1a047a..4f43637234a 100644 --- a/src/cbmc/cbmc_parse_options.h +++ b/src/cbmc/cbmc_parse_options.h @@ -41,7 +41,10 @@ class optionst; "(no-sat-preprocessor)" \ "(no-pretty-names)(beautify)" \ "(dimacs)(refine)(max-node-refinement):(refine-arrays)(refine-arithmetic)"\ - "(refine-strings)(string-non-empty)(string-printable)(string-max-length):" \ + "(refine-strings)" \ + "(string-non-empty)" \ + "(string-printable)" \ + "(string-max-length):" \ "(aig)(16)(32)(64)(LP64)(ILP64)(LLP64)(ILP32)(LP32)" \ "(little-endian)(big-endian)" \ "(show-goto-functions)(show-loops)" \ diff --git a/src/solvers/refinement/string_constraint_generator.h b/src/solvers/refinement/string_constraint_generator.h index d15bea25d49..bb2b05b90b5 100644 --- a/src/solvers/refinement/string_constraint_generator.h +++ b/src/solvers/refinement/string_constraint_generator.h @@ -20,6 +20,7 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com #ifndef CPROVER_SOLVERS_REFINEMENT_STRING_CONSTRAINT_GENERATOR_H #define CPROVER_SOLVERS_REFINEMENT_STRING_CONSTRAINT_GENERATOR_H +#include #include #include #include @@ -29,30 +30,20 @@ class string_constraint_generatort { public: // This module keeps a list of axioms. It has methods which generate - // string constraints for different string funcitons and add them + // string constraints for different string functions and add them // to the axiom list. string_constraint_generatort(): - mode(ID_unknown), - max_string_length(-1), + max_string_length(std::numeric_limits::max()), force_printable_characters(false) { } // Constraints on the maximal length of strings - int max_string_length; + size_t max_string_length; // Should we add constraints on the characters bool force_printable_characters; - void set_mode(irep_idt _mode) - { - // only C and java modes supported - assert((_mode==ID_java) || (_mode==ID_C)); - mode=_mode; - } - - irep_idt &get_mode() { return mode; } - // Axioms are of three kinds: universally quantified string constraint, // not contains string constraints and simple formulas. std::list axioms; diff --git a/src/solvers/refinement/string_constraint_generator_concat.cpp b/src/solvers/refinement/string_constraint_generator_concat.cpp index ffd0f0a212d..311427ec771 100644 --- a/src/solvers/refinement/string_constraint_generator_concat.cpp +++ b/src/solvers/refinement/string_constraint_generator_concat.cpp @@ -30,7 +30,8 @@ string_exprt string_constraint_generatort::add_axioms_for_concat( // a4 : forall i<|s1|. res[i]=s1[i] // a5 : forall i<|s2|. res[i+|s1|]=s2[i] - equal_exprt a1(res.length(), plus_exprt_with_overflow_check(s1.length(), s2.length())); + equal_exprt a1( + res.length(), plus_exprt_with_overflow_check(s1.length(), s2.length())); axioms.push_back(a1); axioms.push_back(s1.axiom_for_is_shorter_than(res)); axioms.push_back(s2.axiom_for_is_shorter_than(res)); diff --git a/src/solvers/refinement/string_constraint_generator_insert.cpp b/src/solvers/refinement/string_constraint_generator_insert.cpp index 89045e52d8f..04e2fa3023d 100644 --- a/src/solvers/refinement/string_constraint_generator_insert.cpp +++ b/src/solvers/refinement/string_constraint_generator_insert.cpp @@ -26,16 +26,40 @@ string_exprt string_constraint_generatort::add_axioms_for_insert( return add_axioms_for_concat(concat1, suf); } -/// add axioms corresponding to the StringBuilder.insert(String) java function -/// \par parameters: function application with three arguments: two strings and -/// an index -/// \return a new string expression +/*******************************************************************\ + +Function: string_constraint_generatort::add_axioms_for_insert + + Inputs: function application with three arguments: two strings and an index + + Outputs: a new string expression + + Purpose: add axioms corresponding to the + StringBuilder.insert(int, CharSequence) + and StringBuilder.insert(int, CharSequence, int, int) + java functions + +\*******************************************************************/ + string_exprt string_constraint_generatort::add_axioms_for_insert( const function_application_exprt &f) { - string_exprt s1=get_string_expr(args(f, 3)[0]); - string_exprt s2=get_string_expr(args(f, 3)[2]); - return add_axioms_for_insert(s1, s2, args(f, 3)[1]); + assert(f.arguments().size()>=3); + string_exprt s1=get_string_expr(f.arguments()[0]); + string_exprt s2=get_string_expr(f.arguments()[2]); + const exprt &offset=f.arguments()[1]; + if(f.arguments().size()==5) + { + const exprt &start=f.arguments()[3]; + const exprt &end=f.arguments()[4]; + string_exprt substring=add_axioms_for_substring(s2, start, end); + return add_axioms_for_insert(s1, substring, offset); + } + else + { + assert(f.arguments().size()==3); + return add_axioms_for_insert(s1, s2, offset); + } } /// add axioms corresponding to the StringBuilder.insert(I) java function diff --git a/src/solvers/refinement/string_constraint_generator_main.cpp b/src/solvers/refinement/string_constraint_generator_main.cpp index 41e5e668d07..00b38f444ef 100644 --- a/src/solvers/refinement/string_constraint_generator_main.cpp +++ b/src/solvers/refinement/string_constraint_generator_main.cpp @@ -169,7 +169,6 @@ Function: string_constraint_generatort::convert_java_string_to_string_exprt string_exprt string_constraint_generatort::convert_java_string_to_string_exprt( const exprt &jls) { - assert(get_mode()==ID_java); assert(jls.id()==ID_struct); exprt length(to_struct_expr(jls).op1()); @@ -214,7 +213,7 @@ void string_constraint_generatort::add_default_axioms( const string_exprt &s) { s.axiom_for_is_longer_than(from_integer(0, s.length().type())); - if(max_string_length>=0) + if(max_string_length!=std::numeric_limits::max()) axioms.push_back(s.axiom_for_is_shorter_than(max_string_length)); if(force_printable_characters) @@ -352,7 +351,6 @@ exprt string_constraint_generatort::add_axioms_for_function_application( // TODO: This part needs some improvement. // Stripping the symbol name is not a very robust process. new_expr.function() = symbol_exprt(str_id.substr(0, pos+4)); - assert(get_mode()==ID_java); new_expr.type() = refined_string_typet(java_int_type(), java_char_type()); auto res_it=function_application_cache.insert(std::make_pair(new_expr, diff --git a/src/solvers/refinement/string_refinement.cpp b/src/solvers/refinement/string_refinement.cpp index a060faf11a9..20fdaf971f6 100644 --- a/src/solvers/refinement/string_refinement.cpp +++ b/src/solvers/refinement/string_refinement.cpp @@ -54,30 +54,22 @@ string_refinementt::string_refinementt( non_empty_string(false) { } -/// determine which language should be used -void string_refinementt::set_mode() -{ - debug() << "initializing mode" << eom; - symbolt init=ns.lookup(irep_idt(CPROVER_PREFIX"initialize")); - irep_idt mode=init.mode; - debug() << "mode detected as " << mode << eom; - generator.set_mode(mode); -} - /*******************************************************************\ Function: string_refinementt::set_max_string_length Inputs: i - maximum length which is allowed for strings. - negative number means no limit + by default the strings length has no other limit + than the maximal integer according to the type of their + length, for instance 2^31-1 for Java. Purpose: Add constraints on the size of strings used in the program. \*******************************************************************/ -void string_refinementt::set_max_string_length(int i) +void string_refinementt::set_max_string_length(size_t i) { generator.max_string_length=i; } @@ -325,16 +317,18 @@ void string_refinementt::concretize_string(const exprt &expr) if(!to_integer(length, found_length)) { assert(found_length.is_long()); - if(found_length < 0) + if(found_length<0) { + // Lengths should not be negative. + // TODO: Add constraints no the sign of string lengths. debug() << "concretize_results: WARNING found length is negative" << eom; } else { size_t concretize_limit=found_length.to_long(); - concretize_limit=concretize_limit>MAX_CONCRETE_STRING_SIZE? - MAX_CONCRETE_STRING_SIZE:concretize_limit; + concretize_limit=concretize_limit>generator.max_string_length? + generator.max_string_length:concretize_limit; exprt content_expr=str.content(); for(size_t i=0; iMAX_CONCRETE_STRING_SIZE) + if(n>generator.max_string_length) { #if 0 debug() << "(sr::get_array) long string (size=" << n << ")" << eom; @@ -898,6 +886,125 @@ void string_refinementt::fill_model() } +/*******************************************************************\ + +Function: string_refinementt::substitute_array_with_expr() + + Inputs: + expr - A (possibly nested) 'with' expression on an `array_of` + expression + index - An index with which to build the equality condition + + Outputs: An expression containing no 'with' expression + + Purpose: Create a new expression where 'with' expressions on arrays + are replaced by 'if' expressions. + e.g. for an array access arr[x], where: + `arr := array_of(12) with {0:=24} with {2:=42}` + the constructed expression will be: + `index==0 ? 24 : index==2 ? 42 : 12` + +\*******************************************************************/ + +exprt string_refinementt::substitute_array_with_expr( + const exprt &expr, const exprt &index) const +{ + if(expr.id()==ID_with) + { + const with_exprt &with_expr=to_with_expr(expr); + const exprt &then_expr=with_expr.new_value(); + exprt else_expr=substitute_array_with_expr(with_expr.old(), index); + const typet &type=then_expr.type(); + assert(else_expr.type()==type); + return if_exprt( + equal_exprt(index, with_expr.where()), then_expr, else_expr, type); + } + else + { + // Only handle 'with' expressions on 'array_of' expressions. + assert(expr.id()==ID_array_of); + return to_array_of_expr(expr).what(); + } +} + +/*******************************************************************\ + +Function: string_refinementt::substitute_array_access() + + Inputs: + expr - an expression containing array accesses + + Outputs: an expression containing no array access + + Purpose: create an equivalent expression where array accesses and + 'with' expressions are replaced by 'if' expressions. + e.g. for an array access arr[x], where: + `arr := {12, 24, 48}` + the constructed expression will be: + `index==0 ? 12 : index==1 ? 24 : 48` + +\*******************************************************************/ + +void string_refinementt::substitute_array_access(exprt &expr) const +{ + for(auto &op : expr.operands()) + substitute_array_access(op); + + if(expr.id()==ID_index) + { + index_exprt &index_expr=to_index_expr(expr); + + if(index_expr.array().id()==ID_symbol) + { + expr=index_expr; + return; + } + + if(index_expr.array().id()==ID_with) + { + expr=substitute_array_with_expr( + index_expr.array(), index_expr.index()); + return; + } + + if(index_expr.array().id()==ID_array_of) + { + expr=to_array_of_expr(index_expr.array()).op(); + return; + } + + assert(index_expr.array().id()==ID_array); + array_exprt &array_expr=to_array_expr(index_expr.array()); + + assert(!array_expr.operands().empty()); + size_t last_index=array_expr.operands().size()-1; + + const typet &char_type=index_expr.array().type().subtype(); + exprt ite=array_expr.operands().back(); + + if(ite.type()!=char_type) + { + // We have to manualy set the type for unknown values + assert(ite.id()==ID_unknown); + ite.type()=char_type; + } + + auto op_it=++array_expr.operands().rbegin(); + for(size_t i=last_index-1; + op_it!=array_expr.operands().rend(); ++op_it, --i) + { + equal_exprt equals(index_expr.index(), from_integer(i, java_int_type())); + ite=if_exprt(equals, *op_it, ite); + if(ite.type()!=char_type) + { + assert(ite.id()==ID_unknown); + ite.type()=char_type; + } + } + expr=ite; + } +} + /*******************************************************************\ Function: string_refinementt::add_negation_of_constraint_to_solver @@ -942,6 +1049,7 @@ void string_refinementt::add_negation_of_constraint_to_solver( and_exprt negaxiom(premise, not_exprt(axiom.body())); debug() << "(sr::check_axioms) negated axiom: " << from_expr(negaxiom) << eom; + substitute_array_access(negaxiom); solver << negaxiom; } @@ -982,6 +1090,7 @@ bool string_refinementt::check_axioms() satcheck_no_simplifiert sat_check; supert solver(ns, sat_check); + solver.set_ui(ui); add_negation_of_constraint_to_solver(axiom_in_model, solver); switch(solver()) @@ -1036,6 +1145,7 @@ bool string_refinementt::check_axioms() exprt premise(axiom.premise()); exprt body(axiom.body()); implies_exprt instance(premise, body); + replace_expr(symbol_resolve, instance); replace_expr(axiom.univ_var(), val, instance); debug() << "adding counter example " << from_expr(instance) << eom; add_lemma(instance); diff --git a/src/solvers/refinement/string_refinement.h b/src/solvers/refinement/string_refinement.h index 209191afbf7..d4f7cba7c01 100644 --- a/src/solvers/refinement/string_refinement.h +++ b/src/solvers/refinement/string_refinement.h @@ -25,11 +25,6 @@ Author: Alberto Griggio, alberto.griggio@gmail.com #include #include -// Defines a limit on the string witnesses we will output. -// Longer strings are still concidered possible by the solver but -// it will not output them. -#define MAX_CONCRETE_STRING_SIZE 500 - #define MAX_NB_REFINEMENT 100 class string_refinementt: public bv_refinementt @@ -48,7 +43,7 @@ class string_refinementt: public bv_refinementt // Should we concretize strings when the solver finished bool do_concretizing; - void set_max_string_length(int i); + void set_max_string_length(size_t i); void enforce_non_empty_string(); void enforce_printable_characters(); @@ -113,8 +108,8 @@ class string_refinementt: public bv_refinementt exprt substitute_function_applications(exprt expr); typet substitute_java_string_types(typet type); exprt substitute_java_strings(exprt expr); - exprt substitute_array_with_expr(exprt &expr, exprt &index) const; - exprt substitute_array_access(exprt &expr) const; + exprt substitute_array_with_expr(const exprt &expr, const exprt &index) const; + void substitute_array_access(exprt &expr) const; void add_symbol_to_symbol_map(const exprt &lhs, const exprt &rhs); bool is_char_array(const typet &type) const; bool add_axioms_for_string_assigns(const exprt &lhs, const exprt &rhs); diff --git a/src/util/string_expr.h b/src/util/string_expr.h index e141f2a1598..cdb801988ae 100644 --- a/src/util/string_expr.h +++ b/src/util/string_expr.h @@ -77,7 +77,7 @@ class string_exprt: public struct_exprt return binary_relation_exprt(rhs.length(), ID_lt, length()); } - binary_relation_exprt axiom_for_is_strictly_longer_than(int i) const + binary_relation_exprt axiom_for_is_strictly_longer_than(mp_integer i) const { return axiom_for_is_strictly_longer_than(from_integer(i, length().type())); } @@ -94,7 +94,7 @@ class string_exprt: public struct_exprt return binary_relation_exprt(length(), ID_le, rhs); } - binary_relation_exprt axiom_for_is_shorter_than(int i) const + binary_relation_exprt axiom_for_is_shorter_than(mp_integer i) const { return axiom_for_is_shorter_than(from_integer(i, length().type())); } @@ -122,7 +122,7 @@ class string_exprt: public struct_exprt return equal_exprt(length(), rhs); } - equal_exprt axiom_for_has_length(int i) const + equal_exprt axiom_for_has_length(mp_integer i) const { return axiom_for_has_length(from_integer(i, length().type())); } From a87ea66213fd8cdcdc42e1200e3a949b2173a69b Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Fri, 3 Feb 2017 09:44:44 +0000 Subject: [PATCH 47/52] Implement function-only coverage This adds support for this-function-only coverage instrumentation. Some function renaming and interface improvement happens at the same time, in particular altering how no-trivial-tests is applied. Adapted from merge commit e7061a0208cde20ec1fe5b582594532e01ce11ab and subsequent fixup d462a7076f2d46bcc1bcee6e70186c76de5e36a8 which appear to have introduced this reworking as part of a merge. Original commit message was "consolidate integration with cover", committed by @cristina-david --- src/goto-instrument/cover.cpp | 312 +++++++++++++++++++++++++--------- src/goto-instrument/cover.h | 37 +++- 2 files changed, 261 insertions(+), 88 deletions(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index ef64691b4a3..2d196aaec57 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -19,6 +19,10 @@ Date: May 2016 #include #include #include +#include +#include + +#include #include "cover.h" @@ -100,6 +104,119 @@ class basic_blockst } }; +/*******************************************************************\ + +Function: coverage_goalst::get_coverage + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +coverage_goalst coverage_goalst::get_coverage_goals(const std::string &coverage, + message_handlert &message_handler) +{ + jsont json; + coverage_goalst goals; + source_locationt source_location; + + // check coverage file + if(parse_json(coverage, message_handler, json)) + { + messaget message(message_handler); + message.error() << coverage << " file is not a valid json file" + << messaget::eom; + exit(6); + } + + // 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, but got " + << json << messaget::eom; + exit(6); + } + + irep_idt file, function, line; + for(jsont::arrayt::const_iterator + it=json.array.begin(); + it!=json.array.end(); + it++) + { + // get the file of each existing goal + file=(*it)["file"].value; + source_location.set_file(file); + + // get the function of each existing goal + function=(*it)["function"].value; + source_location.set_function(function); + + // get the lines array + if((*it)["lines"].is_array()) + { + for(const jsont & entry : (*it)["lines"].array) + { + // get the line of each existing goal + line=entry["number"].value; + source_location.set_line(line); + goals.add_goal(source_location); + } + } + } + return goals; +} + +/*******************************************************************\ + +Function: coverage_goalst::add_goal + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void coverage_goalst::add_goal(source_locationt goal) +{ + existing_goals.push_back(goal); +} + +/*******************************************************************\ + +Function: coverage_goalst::is_existing_goal + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool coverage_goalst::is_existing_goal(source_locationt source_location) const +{ + std::vector::const_iterator it = existing_goals.begin(); + while(it!=existing_goals.end()) + { + if(!source_location.get_file().compare(it->get_file()) && + !source_location.get_function().compare(it->get_function()) && + !source_location.get_line().compare(it->get_line())) + break; + ++it; + } + if(it == existing_goals.end()) + return true; + else + return false; +} + const char *as_string(coverage_criteriont c) { switch(c) @@ -866,8 +983,63 @@ std::set collect_decisions(const goto_programt::const_targett t) void instrument_cover_goals( const symbol_tablet &symbol_table, goto_programt &goto_program, - coverage_criteriont criterion) + coverage_criteriont criterion, + bool function_only) { + coverage_goalst goals; //empty already covered goals + instrument_cover_goals(symbol_table,goto_program, + criterion,goals,function_only,false); +} + +/*******************************************************************\ + +Function: consider_goals + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool consider_goals(const goto_programt &goto_program) +{ + bool result; + unsigned long count_assignments=0, count_goto=0, count_decl=0; + + forall_goto_program_instructions(i_it, goto_program) + { + if(i_it->is_goto()) + ++count_goto; + else if (i_it->is_assign()) + ++count_assignments; + else if (i_it->is_decl()) + ++count_decl; + } + + //check whether this is a constructor/destructor or a get/set (pattern) + if (!count_goto && !count_assignments && !count_decl) + result=false; + else + result = !((count_decl==0) && (count_goto<=1) && + (count_assignments>0 && count_assignments<5)); + + return result; +} + +void instrument_cover_goals( + const symbol_tablet &symbol_table, + goto_programt &goto_program, + coverage_criteriont criterion, + const coverage_goalst &goals, + bool function_only, + bool ignore_trivial) +{ + //exclude trivial coverage goals of a goto program + if(ignore_trivial && !consider_goals(goto_program)) + return; + const namespacet ns(symbol_table); basic_blockst basic_blocks(goto_program); std::set blocks_done; @@ -882,21 +1054,30 @@ void instrument_cover_goals( Forall_goto_program_instructions(i_it, goto_program) { + std::string curr_function = id2string(i_it->function); + + // if the --cover-function-only flag is set, then we only add coverage + // instrumentation for the entry function + bool cover_curr_function= + !function_only || + curr_function.find(config.main)!=std::string::npos; + switch(criterion) { case coverage_criteriont::ASSERTION: // turn into 'assert(false)' to avoid simplification - if(i_it->is_assert()) + if(i_it->is_assert() && cover_curr_function) { i_it->guard=false_exprt(); 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(i_it->function); } break; case coverage_criteriont::COVER: // turn __CPROVER_cover(x) into 'assert(!x)' - if(i_it->is_function_call()) + if(i_it->is_function_call() && cover_curr_function) { const code_function_callt &code_function_call= to_code_function_call(i_it->code); @@ -913,6 +1094,7 @@ void instrument_cover_goals( i_it->source_location.set_comment(comment); 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(i_it->function); } } else if(i_it->is_assert()) @@ -932,10 +1114,14 @@ void instrument_cover_goals( source_locationt source_location= basic_blocks.source_location_map[block_nr]; - if(!source_location.get_file().empty() && + // check whether the current goal already exists + if(goals.is_existing_goal(source_location) && + !source_location.get_file().empty() && !source_location.is_built_in()) + cover_curr_function) { - std::string comment="block "+b; + std::string comment="function "+id2string(i_it->function)+" block "+b; + const irep_idt function=i_it->function; goto_program.insert_before_swap(i_it); i_it->make_assertion(false_exprt()); i_it->source_location=source_location; @@ -943,7 +1129,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++; } } @@ -954,7 +1140,8 @@ void instrument_cover_goals( if(i_it->is_assert()) i_it->make_skip(); - if(i_it==goto_program.instructions.begin()) + if(i_it==goto_program.instructions.begin() && + cover_curr_function) { // we want branch coverage to imply 'entry point of function' // coverage @@ -969,6 +1156,7 @@ void instrument_cover_goals( t->source_location.set_comment(comment); 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); } if(i_it->is_goto() && !i_it->guard.is_true() && @@ -982,6 +1170,7 @@ void instrument_cover_goals( exprt guard=i_it->guard; source_locationt source_location=i_it->source_location; + source_location.set_function(i_it->function); goto_program.insert_before_swap(i_it); i_it->make_assertion(not_exprt(guard)); @@ -1007,7 +1196,7 @@ void instrument_cover_goals( i_it->make_skip(); // Conditions are all atomic predicates in the programs. - if(!i_it->source_location.is_built_in()) + if(cover_curr_function) { const std::set conditions=collect_conditions(i_it); @@ -1018,12 +1207,14 @@ void instrument_cover_goals( const std::string c_string=from_expr(ns, "", c); const std::string comment_t="condition `"+c_string+"' true"; + const irep_idt function=i_it->function; goto_program.insert_before_swap(i_it); i_it->make_assertion(c); i_it->source_location=source_location; i_it->source_location.set_comment(comment_t); 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); const std::string comment_f="condition `"+c_string+"' false"; goto_program.insert_before_swap(i_it); @@ -1032,6 +1223,7 @@ void instrument_cover_goals( i_it->source_location.set_comment(comment_f); 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); } for(std::size_t i=0; imake_skip(); // Decisions are maximal Boolean combinations of conditions. - if(!i_it->source_location.is_built_in()) + if(cover_curr_function) { const std::set decisions=collect_decisions(i_it); @@ -1055,12 +1247,14 @@ void instrument_cover_goals( const std::string d_string=from_expr(ns, "", d); const std::string comment_t="decision `"+d_string+"' true"; + const irep_idt function=i_it->function; goto_program.insert_before_swap(i_it); i_it->make_assertion(d); i_it->source_location=source_location; i_it->source_location.set_comment(comment_t); 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); const std::string comment_f="decision `"+d_string+"' false"; goto_program.insert_before_swap(i_it); @@ -1069,6 +1263,7 @@ void instrument_cover_goals( i_it->source_location.set_comment(comment_f); 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); } for(std::size_t i=0; isource_location.is_built_in()) + if(cover_curr_function) { const std::set conditions=collect_conditions(i_it); const std::set decisions=collect_decisions(i_it); @@ -1112,6 +1307,7 @@ void instrument_cover_goals( std::string p_string=from_expr(ns, "", p); std::string comment_t=description+" `"+p_string+"' true"; + const irep_idt function=i_it->function; goto_program.insert_before_swap(i_it); // i_it->make_assertion(p); i_it->make_assertion(not_exprt(p)); @@ -1119,6 +1315,7 @@ void instrument_cover_goals( i_it->source_location.set_comment(comment_t); 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); std::string comment_f=description+" `"+p_string+"' false"; goto_program.insert_before_swap(i_it); @@ -1128,6 +1325,7 @@ void instrument_cover_goals( i_it->source_location.set_comment(comment_f); 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); } std::set controlling; @@ -1145,6 +1343,7 @@ void instrument_cover_goals( std::string description= "MC/DC independence condition `"+p_string+"'"; + const irep_idt function=i_it->function; goto_program.insert_before_swap(i_it); i_it->make_assertion(not_exprt(p)); // i_it->make_assertion(p); @@ -1152,6 +1351,7 @@ void instrument_cover_goals( i_it->source_location.set_comment(description); 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); } for(std::size_t i=0; isecond.body, - criterion); + criterion, + goals, + function_only, + ignore_trivial); } } @@ -1194,76 +1400,16 @@ bool instrument_cover_goals( const cmdlinet &cmdline, const symbol_tablet &symbol_table, goto_functionst &goto_functions, - message_handlert &msgh) + coverage_criteriont criterion, + bool function_only) { - messaget msg(msgh); - std::list criteria_strings=cmdline.get_values("cover"); - std::set criteria; - bool keep_assertions=false; - - for(const auto &criterion_string : criteria_strings) - { - coverage_criteriont c; - - if(criterion_string=="assertion" || criterion_string=="assertions") - { - keep_assertions=true; - c=coverage_criteriont::ASSERTION; - } - else if(criterion_string=="path" || criterion_string=="paths") - c=coverage_criteriont::PATH; - else if(criterion_string=="branch" || criterion_string=="branches") - c=coverage_criteriont::BRANCH; - else if(criterion_string=="location" || criterion_string=="locations") - c=coverage_criteriont::LOCATION; - else if(criterion_string=="decision" || criterion_string=="decisions") - c=coverage_criteriont::DECISION; - else if(criterion_string=="condition" || criterion_string=="conditions") - c=coverage_criteriont::CONDITION; - else if(criterion_string=="mcdc") - c=coverage_criteriont::MCDC; - else if(criterion_string=="cover") - c=coverage_criteriont::COVER; - else - { - msg.error() << "unknown coverage criterion " - << '\'' << criterion_string << '\'' - << messaget::eom; - return true; - } - - criteria.insert(c); - } - - if(keep_assertions && criteria_strings.size()>1) - { - msg.error() << "assertion coverage cannot currently be used together with " - << "other coverage criteria" << messaget::eom; - return true; - } - - msg.status() << "Rewriting existing assertions as assumptions" - << messaget::eom; - - if(!keep_assertions) - { - // turn assertions (from generic checks) into assumptions - Forall_goto_functions(f_it, goto_functions) - { - goto_programt &body=f_it->second.body; - Forall_goto_program_instructions(i_it, body) - { - if(i_it->is_assert()) - i_it->type=goto_program_instruction_typet::ASSUME; - } - } - } - - msg.status() << "Instrumenting coverage goals" << messaget::eom; - - for(const auto &criterion : criteria) - instrument_cover_goals(symbol_table, goto_functions, criterion); - - goto_functions.update(); - return false; + //empty set of existing goals + coverage_goalst goals; + instrument_cover_goals( + symbol_table, + goto_functions, + criterion, + goals, + function_only, + false); } diff --git a/src/goto-instrument/cover.h b/src/goto-instrument/cover.h index 5a8872bc324..4b2422362ed 100644 --- a/src/goto-instrument/cover.h +++ b/src/goto-instrument/cover.h @@ -15,27 +15,54 @@ Date: May 2016 #define CPROVER_GOTO_INSTRUMENT_COVER_H #include -#include + +class coverage_goalst +{ +public: + static coverage_goalst get_coverage_goals(const std::string &coverage, + message_handlert &message_handler); + void add_goal(source_locationt goal); + bool is_existing_goal(source_locationt source_location) const; + void set_no_trivial_tests(const bool trivial); + const bool get_no_trivial_tests(); + +private: + std::vector existing_goals; + bool no_trivial_tests; +}; enum class coverage_criteriont { LOCATION, BRANCH, DECISION, CONDITION, PATH, MCDC, ASSERTION, COVER }; +void instrument_cover_goals( + const symbol_tablet &symbol_table, + goto_functionst &goto_functions, + coverage_criteriont, + bool function_only=false); + void instrument_cover_goals( const symbol_tablet &symbol_table, goto_programt &goto_program, - coverage_criteriont); + coverage_criteriont, + bool function_only=false); void instrument_cover_goals( const symbol_tablet &symbol_table, goto_functionst &goto_functions, - coverage_criteriont); + coverage_criteriont, + const coverage_goalst &goals, + bool function_only=false, + bool ignore_trivial=false); bool instrument_cover_goals( const cmdlinet &cmdline, const symbol_tablet &symbol_table, - goto_functionst &goto_functions, - message_handlert &msgh); + goto_programt &goto_program, + coverage_criteriont, + const coverage_goalst &goals, + bool function_only=false, + bool ignore_trivial=false); #endif // CPROVER_GOTO_INSTRUMENT_COVER_H From 067d41d6f6759988d920a08c65f679180ee1195e Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Fri, 10 Feb 2017 16:23:10 +0000 Subject: [PATCH 48/52] Apply review comments to coverage code Also improve function names, and make boolean functions return the intuitive true=yes, false=no answer instead of error=true. --- src/goto-instrument/cover.cpp | 118 +++++++++++++++++----------------- src/goto-instrument/cover.h | 9 ++- 2 files changed, 62 insertions(+), 65 deletions(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index 2d196aaec57..7ed202c5565 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -116,59 +116,56 @@ Function: coverage_goalst::get_coverage \*******************************************************************/ -coverage_goalst coverage_goalst::get_coverage_goals(const std::string &coverage, - message_handlert &message_handler) +bool coverage_goalst::get_coverage_goals( + const std::string &coverage_file, + message_handlert &message_handler, + coverage_goalst &goals) { jsont json; - coverage_goalst goals; source_locationt source_location; // check coverage file - if(parse_json(coverage, message_handler, json)) + if(parse_json(coverage_file, message_handler, json)) { messaget message(message_handler); - message.error() << coverage << " file is not a valid json file" + message.error() << coverage_file << " file is not a valid json file" << messaget::eom; - exit(6); + return true; } // 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 + message.error() << "expecting an array in the " << coverage_file << " file, but got " << json << messaget::eom; - exit(6); + return true; } - irep_idt file, function, line; - for(jsont::arrayt::const_iterator - it=json.array.begin(); - it!=json.array.end(); - it++) + for(const auto &goal : json.array) { // get the file of each existing goal - file=(*it)["file"].value; + irep_idt file=goal["file"].value; source_location.set_file(file); // get the function of each existing goal - function=(*it)["function"].value; + irep_idt function=goal["function"].value; source_location.set_function(function); // get the lines array - if((*it)["lines"].is_array()) + if(goal["lines"].is_array()) { - for(const jsont & entry : (*it)["lines"].array) + for(const auto &line_json : goal["lines"].array) { // get the line of each existing goal - line=entry["number"].value; + irep_idt line=line_json["number"].value; source_location.set_line(line); goals.add_goal(source_location); } } } - return goals; + return false; } /*******************************************************************\ @@ -202,19 +199,14 @@ Function: coverage_goalst::is_existing_goal bool coverage_goalst::is_existing_goal(source_locationt source_location) const { - std::vector::const_iterator it = existing_goals.begin(); - while(it!=existing_goals.end()) + for(const auto &existing_loc : existing_goals) { - if(!source_location.get_file().compare(it->get_file()) && - !source_location.get_function().compare(it->get_function()) && - !source_location.get_line().compare(it->get_line())) - break; - ++it; + if(source_location.get_file()==existing_loc.get_file() && + source_location.get_function()==existing_loc.get_function() && + source_location.get_line()==existing_loc.get_line()) + return true; } - if(it == existing_goals.end()) - return true; - else - return false; + return false; } const char *as_string(coverage_criteriont c) @@ -986,46 +978,51 @@ void instrument_cover_goals( coverage_criteriont criterion, bool function_only) { - coverage_goalst goals; //empty already covered goals - instrument_cover_goals(symbol_table,goto_program, - criterion,goals,function_only,false); + coverage_goalst goals; // empty already covered goals + instrument_cover_goals( + symbol_table, + goto_program, + criterion, + goals, + function_only, + false); } /*******************************************************************\ -Function: consider_goals +Function: program_is_trivial - Inputs: + Inputs: Program `goto_program` - Outputs: + Outputs: Returns true if trivial - Purpose: + Purpose: Call a goto_program trivial unless it has: + * Any declarations + * At least 2 branches + * At least 5 assignments \*******************************************************************/ -bool consider_goals(const goto_programt &goto_program) +bool program_is_trivial(const goto_programt &goto_program) { - bool result; - unsigned long count_assignments=0, count_goto=0, count_decl=0; - + unsigned long count_assignments=0, count_goto=0; forall_goto_program_instructions(i_it, goto_program) { if(i_it->is_goto()) - ++count_goto; - else if (i_it->is_assign()) - ++count_assignments; - else if (i_it->is_decl()) - ++count_decl; + { + if((++count_goto)>=2) + return false; + } + else if(i_it->is_assign()) + { + if((++count_assignments)>=5) + return false; + } + else if(i_it->is_decl()) + return false; } - //check whether this is a constructor/destructor or a get/set (pattern) - if (!count_goto && !count_assignments && !count_decl) - result=false; - else - result = !((count_decl==0) && (count_goto<=1) && - (count_assignments>0 && count_assignments<5)); - - return result; + return true; } void instrument_cover_goals( @@ -1036,8 +1033,8 @@ void instrument_cover_goals( bool function_only, bool ignore_trivial) { - //exclude trivial coverage goals of a goto program - if(ignore_trivial && !consider_goals(goto_program)) + // exclude trivial coverage goals of a goto program + if(ignore_trivial && program_is_trivial(goto_program)) return; const namespacet ns(symbol_table); @@ -1115,12 +1112,13 @@ void instrument_cover_goals( basic_blocks.source_location_map[block_nr]; // check whether the current goal already exists - if(goals.is_existing_goal(source_location) && + if(!goals.is_existing_goal(source_location) && !source_location.get_file().empty() && !source_location.is_built_in()) cover_curr_function) { - std::string comment="function "+id2string(i_it->function)+" block "+b; + std::string comment= + "function "+id2string(i_it->function)+" block "+b; const irep_idt function=i_it->function; goto_program.insert_before_swap(i_it); i_it->make_assertion(false_exprt()); @@ -1382,7 +1380,7 @@ void instrument_cover_goals( Forall_goto_functions(f_it, goto_functions) { if(f_it->first==goto_functions.entry_point() || - f_it->first=="__CPROVER_initialize" || + f_it->first==(CPROVER_PREFIX "initialize") || f_it->second.is_hidden()) continue; @@ -1403,7 +1401,7 @@ bool instrument_cover_goals( coverage_criteriont criterion, bool function_only) { - //empty set of existing goals + // empty set of existing goals coverage_goalst goals; instrument_cover_goals( symbol_table, diff --git a/src/goto-instrument/cover.h b/src/goto-instrument/cover.h index 4b2422362ed..0400b583d23 100644 --- a/src/goto-instrument/cover.h +++ b/src/goto-instrument/cover.h @@ -19,16 +19,15 @@ Date: May 2016 class coverage_goalst { public: - static coverage_goalst get_coverage_goals(const std::string &coverage, - message_handlert &message_handler); + static bool get_coverage_goals( + const std::string &coverage, + message_handlert &message_handler, + coverage_goalst &goals); void add_goal(source_locationt goal); bool is_existing_goal(source_locationt source_location) const; - void set_no_trivial_tests(const bool trivial); - const bool get_no_trivial_tests(); private: std::vector existing_goals; - bool no_trivial_tests; }; enum class coverage_criteriont From 4221cce4ce805a611fd2bdaf8edaa292619e8710 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 10 Apr 2017 10:48:47 +0100 Subject: [PATCH 49/52] Restore array skip-initialize flag This allows a java-new-array instruction to indicate that the array will be completely initialized immediately afterwards, and therefore the zero-init instruction can be omitted. The nondet object factory currently uses this to note that it will non-det initialize the whole array. --- src/goto-programs/builtin_functions.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/goto-programs/builtin_functions.cpp b/src/goto-programs/builtin_functions.cpp index a5bf81a722d..a6baf87b433 100644 --- a/src/goto-programs/builtin_functions.cpp +++ b/src/goto-programs/builtin_functions.cpp @@ -701,17 +701,20 @@ void goto_convertt::do_java_new_array( t_p->source_location=location; // zero-initialize the data - exprt zero_element= - zero_initializer( - data.type().subtype(), - location, - ns, - get_message_handler()); - codet array_set(ID_array_set); - array_set.copy_to_operands(data, zero_element); - goto_programt::targett t_d=dest.add_instruction(OTHER); - t_d->code=array_set; - t_d->source_location=location; + if(!rhs.get_bool(ID_skip_initialize)) + { + exprt zero_element= + zero_initializer( + data.type().subtype(), + location, + ns, + get_message_handler()); + codet array_set(ID_array_set); + array_set.copy_to_operands(data, zero_element); + goto_programt::targett t_d=dest.add_instruction(OTHER); + t_d->code=array_set; + t_d->source_location=location; + } if(rhs.operands().size()>=2) { From 1e25df5bc95cf401c54fd7989c1f238255720c6c Mon Sep 17 00:00:00 2001 From: Cristina Date: Mon, 10 Apr 2017 13:54:35 +0100 Subject: [PATCH 50/52] Set function member for class identifier assignment --- src/goto-programs/remove_instanceof.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/goto-programs/remove_instanceof.cpp b/src/goto-programs/remove_instanceof.cpp index ec895ff800d..8a033668f6a 100644 --- a/src/goto-programs/remove_instanceof.cpp +++ b/src/goto-programs/remove_instanceof.cpp @@ -122,6 +122,7 @@ void remove_instanceoft::lower_instanceof( newinst->make_assignment(); newinst->code=code_assignt(newsym.symbol_expr(), object_clsid); newinst->source_location=this_inst->source_location; + newinst->function=this_inst->function; // Insert the check instruction after the existing one. // This will briefly be ill-formed (use before def of From 2e22d8ffa79f300bdaae5a0c14aa460289c92ae9 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Tue, 11 Apr 2017 09:54:57 +0200 Subject: [PATCH 51/52] Fix style to silence cpplint --- src/java_bytecode/java_entry_point.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/java_bytecode/java_entry_point.cpp b/src/java_bytecode/java_entry_point.cpp index 3e2496d1444..e7445b11b85 100644 --- a/src/java_bytecode/java_entry_point.cpp +++ b/src/java_bytecode/java_entry_point.cpp @@ -142,11 +142,19 @@ void java_static_lifetime_init( it->second.type.id()==ID_code && it->second.mode==ID_java) { - code_function_callt function_call; - function_call.lhs()=nil_exprt(); - function_call.function()=it->second.symbol_expr(); - function_call.add_source_location()=source_location; - code_block.add(function_call); + const irep_idt symbol_name= + it->second.symbol_expr().get_identifier(); + const std::string &symbol_str=id2string(symbol_name); + const std::string suffix(".:()V"); + assert(has_suffix(symbol_str, suffix)); + const std::string class_symbol_name= + symbol_str.substr(0, symbol_str.size()-suffix.size()); + const symbolt &class_symbol=symbol_table.lookup(class_symbol_name); + clinits.push_back( + { + it->second.symbol_expr(), + class_symbol.type.get_bool(ID_enumeration) + }); } } } From 8d55b37d556bf78c4620d0dd35e122b433eae846 Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Mon, 10 Apr 2017 11:00:02 +0100 Subject: [PATCH 52/52] Allowing some options for string refinement We allow setting the options refine-arrays, refine-arithmetic and max-node-refinement options in the string solver. Not setting the refine-arrays option can greatly improve performances. --- src/cbmc/cbmc_solvers.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/cbmc/cbmc_solvers.cpp b/src/cbmc/cbmc_solvers.cpp index 41e029926e9..936ca75833b 100644 --- a/src/cbmc/cbmc_solvers.cpp +++ b/src/cbmc/cbmc_solvers.cpp @@ -190,6 +190,15 @@ cbmc_solverst::solvert* cbmc_solverst::get_string_refinement() if(options.get_bool_option("string-printable")) string_refinement->enforce_printable_characters(); + if(options.get_option("max-node-refinement")!="") + string_refinement->max_node_refinement= + options.get_unsigned_int_option("max-node-refinement"); + + string_refinement->do_array_refinement= + options.get_bool_option("refine-arrays"); + string_refinement->do_arithmetic_refinement= + options.get_bool_option("refine-arithmetic"); + return new solvert(string_refinement, prop); }