From b1d8917133228ce47efe0bce6efebfcf1a2a7ee7 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Thu, 31 Mar 2016 22:51:10 +0000 Subject: [PATCH 001/101] Permit linking of functions with ellipsis against fixed argument length --- src/linking/linking.cpp | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/linking/linking.cpp b/src/linking/linking.cpp index 58a73fb6c91..8e2935e82fe 100644 --- a/src/linking/linking.cpp +++ b/src/linking/linking.cpp @@ -564,7 +564,10 @@ void linkingt::duplicate_code_symbol( } } // mismatch on number of parameters is definitively an error - else if(old_t.parameters().size()!=new_t.parameters().size()) + else if((old_t.parameters().size()new_t.parameters().size() && + !new_t.has_ellipsis())) { link_error( old_symbol, @@ -584,17 +587,28 @@ void linkingt::duplicate_code_symbol( conflicts.push_back( std::make_pair(old_t.return_type(), new_t.return_type())); - code_typet::parameterst::const_iterator n_it= - new_t.parameters().begin(); - for(code_typet::parameterst::const_iterator - o_it=old_t.parameters().begin(); - o_it!=old_t.parameters().end(); + code_typet::parameterst::const_iterator + n_it=new_t.parameters().begin(), + o_it=old_t.parameters().begin(); + for( ; + o_it!=old_t.parameters().end() && + n_it!=new_t.parameters().end(); ++o_it, ++n_it) { if(!base_type_eq(o_it->type(), n_it->type(), ns)) conflicts.push_back( std::make_pair(o_it->type(), n_it->type())); } + if(o_it!=old_t.parameters().end()) + { + assert(new_t.has_ellipsis()); + replace=new_symbol.value.is_not_nil(); + } + else if(n_it!=new_t.parameters().end()) + { + assert(old_t.has_ellipsis()); + replace=new_symbol.value.is_not_nil(); + } while(!conflicts.empty()) { From ed522f76671e2096dc7c5b41be43ae0d935f0664 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Thu, 31 Mar 2016 22:51:43 +0000 Subject: [PATCH 002/101] Handle more cases of transparent-union vs. member type linking conflicts --- src/linking/linking.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/linking/linking.cpp b/src/linking/linking.cpp index 8e2935e82fe..a5533b4d4d3 100644 --- a/src/linking/linking.cpp +++ b/src/linking/linking.cpp @@ -649,12 +649,10 @@ void linkingt::duplicate_code_symbol( // _GNU_SOURCE consistent else if((t1.id()==ID_union && (t1.get_bool(ID_C_transparent_union) || - conflicts.front().first.get_bool(ID_C_transparent_union)) && - new_symbol.value.is_nil()) || + conflicts.front().first.get_bool(ID_C_transparent_union))) || (t2.id()==ID_union && (t2.get_bool(ID_C_transparent_union) || - conflicts.front().second.get_bool(ID_C_transparent_union)) && - old_symbol.value.is_nil())) + conflicts.front().second.get_bool(ID_C_transparent_union)))) { const bool use_old= t1.id()==ID_union && @@ -662,14 +660,14 @@ void linkingt::duplicate_code_symbol( conflicts.front().first.get_bool(ID_C_transparent_union)) && new_symbol.value.is_nil(); - const union_typet &dest_union_type= - to_union_type(use_old?t1:t2); - const typet &src_type=use_old?t2:t1; + const union_typet &union_type= + to_union_type(t1.id()==ID_union?t1:t2); + const typet &src_type=t1.id()==ID_union?t2:t1; bool found=false; for(union_typet::componentst::const_iterator - it=dest_union_type.components().begin(); - !found && it!=dest_union_type.components().end(); + it=union_type.components().begin(); + !found && it!=union_type.components().end(); it++) if(base_type_eq(it->type(), src_type, ns)) { From 7ef5cf9d9d77f8ff682f98af5a1bd223ed2118a9 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Mon, 11 Apr 2016 16:13:05 +0200 Subject: [PATCH 003/101] Support klibc's version of __assert_fail, cleanup of assert handling --- src/goto-programs/builtin_functions.cpp | 73 ++++--------------------- 1 file changed, 11 insertions(+), 62 deletions(-) diff --git a/src/goto-programs/builtin_functions.cpp b/src/goto-programs/builtin_functions.cpp index 379067c3afe..cf6917cd0ca 100644 --- a/src/goto-programs/builtin_functions.cpp +++ b/src/goto-programs/builtin_functions.cpp @@ -1283,60 +1283,31 @@ void goto_convertt::do_function_call_symbol( { do_printf(lhs, function, arguments, dest); } - else if(identifier=="__assert_fail") + else if(identifier=="__assert_fail" || + identifier=="_assert" || + identifier=="__assert_c99" || + identifier=="_wassert") { // __assert_fail is Linux // These take four arguments: // "expression", "file.c", line, __func__ + // klibc has __assert_fail with 3 arguments + // "expression", "file.c", line - if(arguments.size()!=4) - { - err_location(function); - throw "`"+id2string(identifier)+"' expected to have four arguments"; - } - - const irep_idt description= - "assertion "+id2string(get_string_constant(arguments[0])); - - goto_programt::targett t=dest.add_instruction(ASSERT); - t->guard=false_exprt(); - t->source_location=function.source_location(); - t->source_location.set("user-provided", true); - t->source_location.set_property_class(ID_assertion); - t->source_location.set_comment(description); - // we ignore any LHS - } - else if(identifier=="_assert") - { // MingW has // void _assert (const char*, const char*, int); // with three arguments: // "expression", "file.c", line - if(arguments.size()!=3) - { - err_location(function); - throw "`"+id2string(identifier)+"' expected to have three arguments"; - } - - const irep_idt description= - "assertion "+id2string(get_string_constant(arguments[0])); - - goto_programt::targett t=dest.add_instruction(ASSERT); - t->guard=false_exprt(); - t->source_location=function.source_location(); - t->source_location.set("user-provided", true); - t->source_location.set_property_class(ID_assertion); - t->source_location.set_comment(description); - // we ignore any LHS - } - else if(identifier=="__assert_c99") - { // This has been seen in Solaris 11. // Signature: // void __assert_c99(const char *desc, const char *file, int line, const char *func); - if(arguments.size()!=4) + // _wassert is Windows. The arguments are + // L"expression", L"file.c", line + + if(arguments.size()!=4 && + arguments.size()!=3) { err_location(function); throw "`"+id2string(identifier)+"' expected to have four arguments"; @@ -1402,28 +1373,6 @@ void goto_convertt::do_function_call_symbol( const irep_idt description= "assertion "+id2string(get_string_constant(arguments[3])); - goto_programt::targett t=dest.add_instruction(ASSERT); - - t->guard=false_exprt(); - t->source_location=function.source_location(); - t->source_location.set("user-provided", true); - t->source_location.set_property_class(ID_assertion); - t->source_location.set_comment(description); - // we ignore any LHS - } - else if(identifier=="_wassert") - { - // This is Windows. The arguments are - // L"expression", L"file.c", line - - if(arguments.size()!=3) - { - err_location(function); - throw "`"+id2string(identifier)+"' expected to have three arguments"; - } - - const irep_idt description= - "assertion "+id2string(get_string_constant(arguments[0])); goto_programt::targett t=dest.add_instruction(ASSERT); t->guard=false_exprt(); From ad24b5a9b921e8629a3f315c2e257fbfefffb034 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Mon, 11 Apr 2016 16:12:41 +0200 Subject: [PATCH 004/101] Permit preprocessor command within __attribute__ --- regression/ansi-c/gcc_attributes7/main.i | 55 +++++++++++++++++++++ regression/ansi-c/gcc_attributes7/test.desc | 8 +++ src/ansi-c/scanner.l | 27 +++++++++- 3 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 regression/ansi-c/gcc_attributes7/main.i create mode 100644 regression/ansi-c/gcc_attributes7/test.desc diff --git a/regression/ansi-c/gcc_attributes7/main.i b/regression/ansi-c/gcc_attributes7/main.i new file mode 100644 index 00000000000..ddb730cfd32 --- /dev/null +++ b/regression/ansi-c/gcc_attributes7/main.i @@ -0,0 +1,55 @@ +struct X { + int a; +}; + +struct S { + struct X x __attribute__((aligned( +# 81 "ring.h" 3 4 + 16 +# 81 "ring.h" + ))); + struct X x2 __attribute__((aligned( +# 82 "ring.h" 3 4 + ((( +# 82 "ring.h" + sizeof(struct X) +# 82 "ring.h" 3 4 + )+16 -1)&~(16 -1)) +# 82 "ring.h" + ))); +}; + +typedef int int8_t +# 194 "/usr/include/x86_64-linux-gnu/sys/types.h" +__attribute__( +# 194 "/usr/include/x86_64-linux-gnu/sys/types.h" 3 4 +(__mode__ (__QI__)) +# 194 "/usr/include/x86_64-linux-gnu/sys/types.h" +) +# 194 "/usr/include/x86_64-linux-gnu/sys/types.h" 3 4 + ; + +int extundelete_process_dir_block(int fs, + int b +# 29 "block.h" 3 4 + __attribute__( +# 29 "block.h" + (unused) +# 29 "block.h" 3 4 + ) +# 29 "block.h" + , + int ref_offset +# 30 "block.h" 3 4 + __attribute__( +# 30 "block.h" + (unused) +# 30 "block.h" 3 4 + ) +# 30 "block.h" + , + void *priv_data); + +int main() +{ +} diff --git a/regression/ansi-c/gcc_attributes7/test.desc b/regression/ansi-c/gcc_attributes7/test.desc new file mode 100644 index 00000000000..e5548900ad5 --- /dev/null +++ b/regression/ansi-c/gcc_attributes7/test.desc @@ -0,0 +1,8 @@ +CORE +main.i + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +^CONVERSION ERROR$ diff --git a/src/ansi-c/scanner.l b/src/ansi-c/scanner.l index 4e4626d9274..99e8b488f72 100644 --- a/src/ansi-c/scanner.l +++ b/src/ansi-c/scanner.l @@ -195,6 +195,7 @@ string_lit ("L"|"u"|"U"|"u8")?["]{s_char}*["] %x MSC_PRAGMA %x MSC_ANNOTATION %x GCC_ATTRIBUTE1 +%x GCC_ATTRIBUTE1a %x GCC_ATTRIBUTE2 %x GCC_ATTRIBUTE3 %x GCC_ATTRIBUTE4 @@ -1346,8 +1347,22 @@ __decltype { if(PARSER.cpp98 && PARSER.mode==ansi_c_parsert::GCC) } { -"("{ws}"(" | -"("{newline}"(" { BEGIN(GCC_ATTRIBUTE2); PARSER.parenthesis_counter=0; } +{cpplineno} { + preprocessor_line(yytext, PARSER); + PARSER.set_line_no(PARSER.get_line_no()-1); + } +{ws} { /* ignore */ } +{newline} { /* ignore */ } +"(" { BEGIN(GCC_ATTRIBUTE1a); } +. { BEGIN(GRAMMAR); loc(); return yytext[0]; } +} + +{ +{cpplineno} { + preprocessor_line(yytext, PARSER); + PARSER.set_line_no(PARSER.get_line_no()-1); + } +"(" { BEGIN(GCC_ATTRIBUTE2); PARSER.parenthesis_counter=0; } {ws} { /* ignore */ } {newline} { /* ignore */ } . { BEGIN(GRAMMAR); loc(); return yytext[0]; } @@ -1386,6 +1401,10 @@ __decltype { if(PARSER.cpp98 && PARSER.mode==ansi_c_parsert::GCC) } { // an attribute we do process +{cpplineno} { + preprocessor_line(yytext, PARSER); + PARSER.set_line_no(PARSER.get_line_no()-1); + } "(" { PARSER.parenthesis_counter++; loc(); return '('; } ")" { if(PARSER.parenthesis_counter==0) { @@ -1436,6 +1455,10 @@ __decltype { if(PARSER.cpp98 && PARSER.mode==ansi_c_parsert::GCC) } { // end bit: the closing parenthesis +{cpplineno} { + preprocessor_line(yytext, PARSER); + PARSER.set_line_no(PARSER.get_line_no()-1); + } ")" { BEGIN(GRAMMAR); } {ws} { /* Throw away */ } {newline} { /* Throw away */ } From a210c2d98454564edc0561eb8fc30b9226cf116f Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Thu, 14 Apr 2016 15:06:54 +0000 Subject: [PATCH 005/101] Refactor OS-specific path concatenation into utility function --- src/goto-cc/compile.cpp | 7 +------ src/util/file_util.cpp | 21 +++++++++++++++++++++ src/util/file_util.h | 3 +++ src/util/tempdir.cpp | 6 +----- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/goto-cc/compile.cpp b/src/goto-cc/compile.cpp index 9bbf51eee5c..aff2218949d 100644 --- a/src/goto-cc/compile.cpp +++ b/src/goto-cc/compile.cpp @@ -214,12 +214,7 @@ bool compilet::add_input_file(const std::string &file_name) if(file_name[0]!='/') #endif { - cmd << "ar x " << - #ifdef _WIN32 - working_directory << "\\" << file_name; - #else - working_directory << "/" << file_name; - #endif + cmd << "ar x " << concat_dir_file(working_directory, file_name); } else { diff --git a/src/util/file_util.cpp b/src/util/file_util.cpp index d3932cc0dab..a3504953030 100644 --- a/src/util/file_util.cpp +++ b/src/util/file_util.cpp @@ -115,3 +115,24 @@ void delete_directory(const std::string &path) rmdir(path.c_str()); } +/*******************************************************************\ + +Function: concat_dir_file + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +std::string concat_dir_file(const std::string &directory, + const std::string &file_name) +{ + #ifdef _WIN32 + return directory+"\\"+file_name; + #else + return directory+"/"+file_name; + #endif +} diff --git a/src/util/file_util.h b/src/util/file_util.h index b6db7ad4655..94939c9d6ec 100644 --- a/src/util/file_util.h +++ b/src/util/file_util.h @@ -15,4 +15,7 @@ void delete_directory(const std::string &path); std::string get_current_working_directory(); +std::string concat_dir_file(const std::string &directory, + const std::string &file_name); + #endif diff --git a/src/util/tempdir.cpp b/src/util/tempdir.cpp index 6a310a39b52..625a7801e2c 100644 --- a/src/util/tempdir.cpp +++ b/src/util/tempdir.cpp @@ -116,11 +116,7 @@ Function: temp_dirt::operator() std::string temp_dirt::operator()(const std::string &file) { - #ifdef _WIN32 - return path+"\\"+file; - #else - return path+"/"+file; - #endif + return concat_dir_file(path, file); } /*******************************************************************\ From 7656b6c3f2d5f492cb0de812c7f67325b7f96f63 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Thu, 14 Apr 2016 15:09:24 +0000 Subject: [PATCH 006/101] Store the current working directory with each translation unit This will enable recovering the full path to a source file where necessary. --- src/util/irep_ids.txt | 1 + src/util/parser.h | 3 +++ src/util/source_location.h | 10 ++++++++++ 3 files changed, 14 insertions(+) diff --git a/src/util/irep_ids.txt b/src/util/irep_ids.txt index 452b12ba4aa..86a5d39d08b 100644 --- a/src/util/irep_ids.txt +++ b/src/util/irep_ids.txt @@ -724,3 +724,4 @@ C_spec_requires #spec_requires C_spec_ensures #spec_ensures virtual_function C_element_type #element_type +working_directory diff --git a/src/util/parser.h b/src/util/parser.h index 8cd510bbd52..dd672e81b1a 100644 --- a/src/util/parser.h +++ b/src/util/parser.h @@ -7,6 +7,7 @@ #include "expr.h" #include "message.h" +#include "file_util.h" class parsert:public messaget { @@ -75,6 +76,8 @@ class parsert:public messaget inline void set_file(const irep_idt &file) { source_location.set_file(file); + source_location.set_working_directory( + get_current_working_directory()); } inline irep_idt get_file() const diff --git a/src/util/source_location.h b/src/util/source_location.h index 46b01ed0ea4..7be5aaa9f29 100644 --- a/src/util/source_location.h +++ b/src/util/source_location.h @@ -25,6 +25,11 @@ class source_locationt:public irept return get(ID_file); } + inline const irep_idt &get_working_directory() const + { + return get(ID_working_directory); + } + inline const irep_idt &get_line() const { return get(ID_line); @@ -60,6 +65,11 @@ class source_locationt:public irept set(ID_file, file); } + inline void set_working_directory(const irep_idt &cwd) + { + set(ID_working_directory, cwd); + } + inline void set_line(const irep_idt &line) { set(ID_line, line); From ff703e962474b9f373134bbe2fa15eddd5a595fe Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Thu, 14 Apr 2016 15:11:57 +0000 Subject: [PATCH 007/101] Use working-directory information to print full names Used for coverage output and dead-code analysis --- src/goto-analyzer/unreachable_instructions.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/goto-analyzer/unreachable_instructions.cpp b/src/goto-analyzer/unreachable_instructions.cpp index 60b36f865f9..e7e88fe0116 100644 --- a/src/goto-analyzer/unreachable_instructions.cpp +++ b/src/goto-analyzer/unreachable_instructions.cpp @@ -11,6 +11,7 @@ Date: April 2016 #include #include +#include #include @@ -145,7 +146,9 @@ static void add_to_json( entry["function"]=json_stringt(id2string(end_function->function)); entry["file name"]= - json_stringt(id2string(end_function->source_location.get_file())); + json_stringt(concat_dir_file( + id2string(end_function->source_location.get_working_directory()), + id2string(end_function->source_location.get_file()))); json_arrayt &dead_ins=entry["unreachable instructions"].make_array(); From 72e9b3676a08fbaa91c1c0820574f0f002e261d1 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Thu, 21 Apr 2016 11:34:35 +0000 Subject: [PATCH 008/101] New goto-instrument option --list-eloc --- src/goto-instrument/count_eloc.cpp | 69 +++++++++++++++---- src/goto-instrument/count_eloc.h | 2 + .../goto_instrument_parse_options.cpp | 7 ++ .../goto_instrument_parse_options.h | 2 +- 4 files changed, 66 insertions(+), 14 deletions(-) diff --git a/src/goto-instrument/count_eloc.cpp b/src/goto-instrument/count_eloc.cpp index 5bf5ee276a4..5a92186fda7 100644 --- a/src/goto-instrument/count_eloc.cpp +++ b/src/goto-instrument/count_eloc.cpp @@ -11,12 +11,17 @@ Date: December 2012 #include #include +#include #include "count_eloc.h" +typedef hash_set_cont linest; +typedef hash_map_cont filest; +typedef hash_map_cont working_dirst; + /*******************************************************************\ -Function: count_eloc +Function: collect_eloc Inputs: @@ -26,16 +31,22 @@ Function: count_eloc \*******************************************************************/ -std::size_t count_eloc(const goto_programt &goto_program) +static void collect_eloc( + const goto_functionst &goto_functions, + working_dirst &dest) { - hash_set_cont lines; - - forall_goto_program_instructions(it, goto_program) - if(it->source_location.is_not_nil() && - !has_prefix(id2string(it->source_location.get_file()), "source_location.get_line()); - - return lines.size(); + forall_goto_functions(f_it, goto_functions) + { + forall_goto_program_instructions(it, f_it->second.body) + { + filest &files=dest[it->source_location.get_working_directory()]; + const irep_idt &file=it->source_location.get_file(); + + if(!file.empty() && + !has_prefix(id2string(file), "source_location.get_line()); + } + } } /*******************************************************************\ @@ -53,10 +64,42 @@ Function: count_eloc void count_eloc(const goto_functionst &goto_functions) { std::size_t eloc=0; - - forall_goto_functions(f_it, goto_functions) - eloc+=count_eloc(f_it->second.body); + + working_dirst eloc_map; + collect_eloc(goto_functions, eloc_map); + + for(const std::pair &files : eloc_map) + for(const std::pair &lines : files.second) + eloc+=lines.second.size(); std::cout << "Effective lines of code: " << eloc << '\n'; } +/*******************************************************************\ + +Function: list_eloc + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void list_eloc(const goto_functionst &goto_functions) +{ + working_dirst eloc_map; + collect_eloc(goto_functions, eloc_map); + + for(const std::pair &files : eloc_map) + for(const std::pair &lines : files.second) + { + std::string file=id2string(lines.first); + if(!files.first.empty()) + file=concat_dir_file(id2string(files.first), file); + + for(const irep_idt &line : lines.second) + std::cout << file << ':' << line << '\n'; + } +} diff --git a/src/goto-instrument/count_eloc.h b/src/goto-instrument/count_eloc.h index 1228e035f49..f3417606f5b 100644 --- a/src/goto-instrument/count_eloc.h +++ b/src/goto-instrument/count_eloc.h @@ -15,4 +15,6 @@ Date: December 2012 void count_eloc(const goto_functionst &goto_functions); +void list_eloc(const goto_functionst &goto_functions); + #endif diff --git a/src/goto-instrument/goto_instrument_parse_options.cpp b/src/goto-instrument/goto_instrument_parse_options.cpp index 6e1c04075a9..14759d53a58 100644 --- a/src/goto-instrument/goto_instrument_parse_options.cpp +++ b/src/goto-instrument/goto_instrument_parse_options.cpp @@ -407,6 +407,12 @@ int goto_instrument_parse_optionst::doit() return 0; } + if(cmdline.isset("list-eloc")) + { + list_eloc(goto_functions); + return 0; + } + if(cmdline.isset("list-symbols")) { show_symbol_table(true); @@ -1271,6 +1277,7 @@ void goto_instrument_parse_optionst::help() " --dot generate CFG graph in DOT format\n" " --interpreter do concrete execution\n" " --count-eloc count effective lines of code\n" + " --list-eloc list full path names of lines containing code\n" "\n" "Diagnosis:\n" " --show-loops show the loops in the program\n" diff --git a/src/goto-instrument/goto_instrument_parse_options.h b/src/goto-instrument/goto_instrument_parse_options.h index abd41931081..7348e44c3c9 100644 --- a/src/goto-instrument/goto_instrument_parse_options.h +++ b/src/goto-instrument/goto_instrument_parse_options.h @@ -58,7 +58,7 @@ Author: Daniel Kroening, kroening@kroening.com "(accelerate)(constant-propagator)" \ "(k-induction):(step-case)(base-case)" \ "(show-call-sequences)(check-call-sequence)" \ - "(interpreter)(show-reaching-definitions)(count-eloc)" \ + "(interpreter)(show-reaching-definitions)(count-eloc)(list-eloc)" \ "(list-symbols)(list-undefined-functions)" \ "(z3)(add-library)(show-dependence-graph)" \ "(horn)(skip-loops):(apply-code-contracts)" From 777744b3ad7218510be9918ad8b0aed694fb0638 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Sun, 8 May 2016 12:09:19 +0100 Subject: [PATCH 009/101] package creation for El Capitan --- src/cbmc/cbmc.plist | 18 ------------------ src/cbmc/dist-macos | 35 +++++++++++++++++++---------------- src/cbmc/distribution.xml | 29 +++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 34 deletions(-) delete mode 100644 src/cbmc/cbmc.plist create mode 100644 src/cbmc/distribution.xml diff --git a/src/cbmc/cbmc.plist b/src/cbmc/cbmc.plist deleted file mode 100644 index c0663f45de5..00000000000 --- a/src/cbmc/cbmc.plist +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - BundleHasStrictIdentifier - - BundleIsRelocatable - - BundleIsVersionChecked - - BundleOverwriteAction - upgrade - RootRelativeBundlePath - usr/bin/cbmc - - - diff --git a/src/cbmc/dist-macos b/src/cbmc/dist-macos index 7d324cbacc5..bbf54cc8c20 100755 --- a/src/cbmc/dist-macos +++ b/src/cbmc/dist-macos @@ -17,35 +17,38 @@ echo $VERSION_FILE mkdir /tmp/cbmc-dist mkdir /tmp/cbmc-dist/package-root mkdir /tmp/cbmc-dist/package-root/usr -mkdir /tmp/cbmc-dist/package-root/usr/bin +mkdir /tmp/cbmc-dist/package-root/usr/local +mkdir /tmp/cbmc-dist/package-root/usr/local/bin mkdir /tmp/cbmc-dist/resources mkdir /tmp/cbmc-dist/resources/en.lproj cp ../cbmc/cbmc ../goto-cc/goto-cc \ - ../goto-instrument/goto-instrument /tmp/cbmc-dist/package-root/usr/bin -cp ../../LICENSE /tmp/cbmc-dist/resources/License.txt + ../goto-instrument/goto-instrument /tmp/cbmc-dist/package-root/usr/local/bin/ +cp ../../LICENSE /tmp/cbmc-dist/resources/license.html +cp distribution.xml /tmp/cbmc-dist/ echo "Building cbmc-${VERSION_FILE}.pkg (${BITS} bits)" -#/Applications/PackageMaker.app/Contents/MacOS/PackageMaker \ -# --root /tmp/cbmc-dist/package-root/ \ -# -o /tmp/cbmc-dist/cbmc-${VERSION_FILE}.pkg \ -# --version $VERSION \ -# --title "CBMC ${VERSION}" \ -# --resources /tmp/cbmc-dist/resources/ \ -# --target 10.5 \ -# --id org.cprover.cbmc +# Do the 'component package' pkgbuild \ --root /tmp/cbmc-dist/package-root/ \ --identifier org.cprover.cbmc \ --version $VERSION \ - --verbose \ - /tmp/cbmc-dist/cbmc-${VERSION_FILE}.pkg + /tmp/cbmc-dist/cbmc-component.pkg + +# Now do the 'product archive' + +productbuild \ + --distribution /tmp/cbmc-dist/distribution.xml \ + --resources /tmp/cbmc-dist/resources/ \ + --package-path /tmp/cbmc-dist \ + --version $VERSION \ + /tmp/cbmc-dist/cbmc-${VERSION_FILE}.pkg -#echo Copying. -#scp /tmp/cbmc-dist/cbmc-${VERSION_FILE}.pkg \ -# kroening@dkr-srv.cs.ox.ac.uk:/srv/www/cprover.org/cbmc/download/ +echo Copying. +scp /tmp/cbmc-dist/cbmc-${VERSION_FILE}.pkg \ + kroening@dkr-srv.cs.ox.ac.uk:/srv/www/cprover.org/cbmc/download/ #cd /tmp #rm -R /tmp/cbmc-dist diff --git a/src/cbmc/distribution.xml b/src/cbmc/distribution.xml new file mode 100644 index 00000000000..d87174232dd --- /dev/null +++ b/src/cbmc/distribution.xml @@ -0,0 +1,29 @@ + + + The CBMC Bounded Model Checker + org.cprover.cbmc + + + + + + + + cbmc-component.pkg + + + + + + + + + From f62bf5c420e75857f2ee9a8aebcfda46a5a53a26 Mon Sep 17 00:00:00 2001 From: Cristina Date: Thu, 12 May 2016 10:48:47 +0100 Subject: [PATCH 010/101] For Java skip the check for dereference of a deallocated or dead object --- src/analyses/goto_check.cpp | 43 +++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/analyses/goto_check.cpp b/src/analyses/goto_check.cpp index 467ac8df0ef..8cd792f1fd0 100644 --- a/src/analyses/goto_check.cpp +++ b/src/analyses/goto_check.cpp @@ -944,23 +944,34 @@ void goto_checkt::pointer_validity_check( expr, guard); - if(flags.is_unknown() || flags.is_dynamic_heap()) - add_guarded_claim( - not_exprt(deallocated(pointer, ns)), - "dereference failure: deallocated dynamic object", - "pointer dereference", - expr.find_source_location(), - expr, - guard); - if(flags.is_unknown() || flags.is_dynamic_local()) - add_guarded_claim( - not_exprt(dead_object(pointer, ns)), - "dereference failure: dead object", - "pointer dereference", - expr.find_source_location(), - expr, - guard); + symbol_tablet symbol_table = ns.get_symbol_table(); + + symbol_tablet::symbolst::iterator s_it= + symbol_table.symbols.find(CPROVER_PREFIX "initialize"); + + // For Java don't check dereference of a deallocated or dead object + if (s_it==symbol_table.symbols.end() || (s_it->second).mode != ID_java) + { + + if(flags.is_unknown() || flags.is_dynamic_heap()) + add_guarded_claim( + not_exprt(deallocated(pointer, ns)), + "dereference failure: deallocated dynamic object", + "pointer dereference", + expr.find_source_location(), + expr, + guard); + + if(flags.is_unknown() || flags.is_dynamic_local()) + add_guarded_claim( + not_exprt(dead_object(pointer, ns)), + "dereference failure: dead object", + "pointer dereference", + expr.find_source_location(), + expr, + guard); + } if(enable_bounds_check) { From 0c510627038dfa25b2ec734bd29d7c463da373e0 Mon Sep 17 00:00:00 2001 From: Cristina Date: Fri, 13 May 2016 12:55:41 +0100 Subject: [PATCH 011/101] + regression test for NULL object dereferencing in Java --- regression/cbmc-java/pointer_check1/A.class | Bin 0 -> 207 bytes regression/cbmc-java/pointer_check1/B.class | Bin 0 -> 277 bytes .../pointer_check1/pointer_check1.class | Bin 0 -> 335 bytes .../pointer_check1/pointer_check1.java | 21 ++++++++++++++++++ regression/cbmc-java/pointer_check1/test.desc | 8 +++++++ 5 files changed, 29 insertions(+) create mode 100644 regression/cbmc-java/pointer_check1/A.class create mode 100644 regression/cbmc-java/pointer_check1/B.class create mode 100644 regression/cbmc-java/pointer_check1/pointer_check1.class create mode 100644 regression/cbmc-java/pointer_check1/pointer_check1.java create mode 100644 regression/cbmc-java/pointer_check1/test.desc diff --git a/regression/cbmc-java/pointer_check1/A.class b/regression/cbmc-java/pointer_check1/A.class new file mode 100644 index 0000000000000000000000000000000000000000..a80b733cb82166ebb011b09541a224a368b9590c GIT binary patch literal 207 zcmXYqO$z~06o%hpz8K@9td%7eBwHydrNn}4b?3Tq$GD?u_+M7a!VmDHs&pg5n2o=2E9n!L;x2a-<%NYIrn2>4*gXaDVd>#0)Gz>mksCt;srKE YrY6rkbGi@E{TG+GyFZynK2rhZFVv(XoB#j- literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/pointer_check1/B.class b/regression/cbmc-java/pointer_check1/B.class new file mode 100644 index 0000000000000000000000000000000000000000..09ba3d25408dc7ed77dc3ffe780ac4baafb6a11b GIT binary patch literal 277 zcmZ9GL2JT55QX1F&1#ye)p`_qR11pqs0daN1kr=yRW|9Ot7%d~;;-tZAQXD&5Aa8c zvw{}~cINTTd%Jr&|NR4aL(M@Jj|CJ_5-1Bi5$wJWbuu7i8qF0UJBmIOp)}Q@nx&tf zikH$0nAjVYtYpBVF&*}r6N0md(%4sHZPwMVNQa4v*Zx-d`)+$D57I>rwm`*270(2E zCzK8E1Tx%o=H5>E3F9HZeK0rE1TV<&4^3HoI1YkfRp&{Dw0=Q9EC_k-W^HUh0S@b% T^%{OX!ur0m3N}43v*2C;OwB3~ literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/pointer_check1/pointer_check1.class b/regression/cbmc-java/pointer_check1/pointer_check1.class new file mode 100644 index 0000000000000000000000000000000000000000..891a91b81f7cf6f5503e6a04d44b53e603d24910 GIT binary patch literal 335 zcmY*U!AiqG5Pg%RiKa1W8|_W-m?{{=V^vT=5P}{m1@R!8xWujLMndX;d9k422l!Fq zY%j%ynfI7|?=kc9`}qyv7(*W}A`d+u79!L79tIv_f_tL0YR?FEGMW;c%lb(YqD*Od zvzX_yxf6NC6K5`zCJd8@Y$o1BS_xgIleSU192=uQsTWNluaptTueH*xY#xheS-cz_ z8b<&R8w9!tu#Fu;_+LZlt#fblnJijfu9WRmR7{fWd_20w9y)x9c@`H3g0RVKmysAd z`%BO}6JChByBc;`(nY}BNK>}jjL{dY`z7q`fIi@yu1(?UyU*DJgoxR;#c~VbA2RDY AQUCw| literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/pointer_check1/pointer_check1.java b/regression/cbmc-java/pointer_check1/pointer_check1.java new file mode 100644 index 00000000000..f3a3c312022 --- /dev/null +++ b/regression/cbmc-java/pointer_check1/pointer_check1.java @@ -0,0 +1,21 @@ +class A +{ + int val; +} + +class B +{ + int getVal(A a) + { + return a.val; + } +} + +class pointer_check1 +{ + public static void main(String[] args) + { + B b = new B(); + int myval = b.getVal(null); + } +} diff --git a/regression/cbmc-java/pointer_check1/test.desc b/regression/cbmc-java/pointer_check1/test.desc new file mode 100644 index 00000000000..03121d320c6 --- /dev/null +++ b/regression/cbmc-java/pointer_check1/test.desc @@ -0,0 +1,8 @@ +CORE +pointer_check1.class +--pointer-check +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +^warning: ignoring \ No newline at end of file From 3138148c7115667874b016cd19a5755506c66851 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Sat, 14 May 2016 09:48:46 +0100 Subject: [PATCH 012/101] return something in ctime and asctime --- src/ansi-c/library/time.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ansi-c/library/time.c b/src/ansi-c/library/time.c index 8bc1272e78d..fadc175cdb6 100644 --- a/src/ansi-c/library/time.c +++ b/src/ansi-c/library/time.c @@ -143,6 +143,9 @@ char *asctime(const struct tm *timeptr) char *asctime_result; __CPROVER_set_must(asctime_result, "asctime_result"); return asctime_result; + #else + static char asctime_result[1]; + return asctime_result; #endif } @@ -161,6 +164,9 @@ char *ctime(const time_t *clock) char *ctime_result; __CPROVER_set_must(ctime_result, "ctime_result"); return ctime_result; + #else + static char ctime_result[1]; + return ctime_result; #endif } From 4a97f9ecc62c5d24561ef917793bf4572c6b1de3 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Sat, 14 May 2016 09:50:33 +0100 Subject: [PATCH 013/101] return something in strerror --- src/ansi-c/library/string.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ansi-c/library/string.c b/src/ansi-c/library/string.c index 2793f9e8bdd..809a7e99a33 100644 --- a/src/ansi-c/library/string.c +++ b/src/ansi-c/library/string.c @@ -736,10 +736,14 @@ inline char *strrchr(const char *src, int c) char *strerror(int errnum) { __CPROVER_HIDE:; + (void)errnum; #ifdef __CPROVER_CUSTOM_BITVECTOR_ANALYSIS __CPROVER_event("invalidate_pointer", "strerror_result"); char *strerror_result; __CPROVER_set_must(strerror_result, "strerror_result"); return strerror_result; + #else + static char strerror_result[1]; + return strerror_result; #endif } From 72aa254e51e5862f751964b1c31d5d35e05123ec Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Sat, 14 May 2016 09:53:36 +0100 Subject: [PATCH 014/101] return something in setlocale and localeconv --- src/ansi-c/library/locale.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ansi-c/library/locale.c b/src/ansi-c/library/locale.c index 8c030d81a44..61d5353457e 100644 --- a/src/ansi-c/library/locale.c +++ b/src/ansi-c/library/locale.c @@ -9,12 +9,16 @@ inline char *setlocale(int category, const char *locale) { __CPROVER_HIDE:; + (void)category; (void)*locale; #ifdef __CPROVER_CUSTOM_BITVECTOR_ANALYSIS __CPROVER_event("invalidate_pointer", "setlocale_result"); char *setlocale_result; __CPROVER_set_may(setlocale_result, "setlocale_result"); return setlocale_result; + #else + static char setlocale_result[1]; + return setlocale_result; #endif } @@ -33,5 +37,8 @@ inline struct lconv *localeconv(void) struct lconv *localeconv_result; __CPROVER_set_may(localeconv_result, "localeconv_result"); return localeconv_result; + #else + static struct lconv localeconv_result; + return &localeconv_result; #endif } From 5a5bb126ba54cf5136587ffd1dadb5985f877e14 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Sat, 14 May 2016 16:54:38 +0100 Subject: [PATCH 015/101] missing object file --- src/goto-analyzer/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/goto-analyzer/Makefile b/src/goto-analyzer/Makefile index bf510f6e210..ed6f626b0df 100644 --- a/src/goto-analyzer/Makefile +++ b/src/goto-analyzer/Makefile @@ -7,6 +7,7 @@ OBJ += ../ansi-c/ansi-c$(LIBEXT) \ ../big-int/big-int$(LIBEXT) \ ../goto-programs/goto-programs$(LIBEXT) \ ../analyses/analyses$(LIBEXT) \ + ../pointer-analysis/pointer-analysis$(LIBEXT) \ ../langapi/langapi$(LIBEXT) \ ../json/json$(LIBEXT) \ ../assembler/assembler$(LIBEXT) \ From 0114f7eaaa55121c8ce67f90b98f0791492aa04d Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Mon, 16 May 2016 12:54:20 +0100 Subject: [PATCH 016/101] source locations in location coverage --- src/goto-instrument/cover.cpp | 19 +++++++++++++++---- src/goto-programs/goto_convert.cpp | 3 ++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index ed252966d9e..ff8e0fa5523 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -27,15 +27,24 @@ class basic_blockst block_map[it]=block_count; + if(!it->source_location.is_nil() && + source_location_map.find(block_count)==source_location_map.end()) + source_location_map[block_count]=it->source_location; + next_is_target= it->is_goto() || it->is_return() || it->is_function_call() || it->is_assume(); } } - + + // map program locations to block numbers typedef std::map block_mapt; block_mapt block_map; + // map block numbers to source code locations + typedef std::map source_location_mapt; + source_location_mapt source_location_map; + inline unsigned operator[](goto_programt::const_targett t) { return block_map[t]; @@ -134,12 +143,14 @@ void instrument_cover_goals( { std::string b=i2string(block_nr); std::string id=id2string(i_it->function)+"#"+b; - if(i_it->source_location.get_file()!="") + source_locationt source_location= + basic_blocks.source_location_map[block_nr]; + + if(source_location.get_file()!="") { std::string comment= - "block "+i_it->source_location.as_string()+" "+i2string(i_it->location_number); + "block "+source_location.as_string()+" "+i2string(i_it->location_number); - source_locationt source_location=i_it->source_location; goto_program.insert_before_swap(i_it); i_it->make_assertion(false_exprt()); i_it->source_location=source_location; diff --git a/src/goto-programs/goto_convert.cpp b/src/goto-programs/goto_convert.cpp index 2033f974837..650db34e3ee 100644 --- a/src/goto-programs/goto_convert.cpp +++ b/src/goto-programs/goto_convert.cpp @@ -2224,7 +2224,8 @@ void goto_convertt::generate_ifthenelse( goto_programt tmp_z; goto_programt::targett z=tmp_z.add_instruction(); z->make_skip(); - z->source_location=source_location; + // We deliberately don't set a location for 'z', it's a dummy + // target. // y: Q; goto_programt tmp_y; From c58a5e11132897bd78f9bc3056e393d23d8e46ef Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Mon, 16 May 2016 16:56:27 +0100 Subject: [PATCH 017/101] decision and condition coverage --- src/goto-instrument/cover.cpp | 231 +++++++++++++++++++++++++++++++--- 1 file changed, 212 insertions(+), 19 deletions(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index ff8e0fa5523..9a1751e9e4e 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -79,6 +79,65 @@ const char *as_string(coverage_criteriont c) /*******************************************************************\ +Function: collect_conditions_rec + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void collect_conditions_rec(const exprt &src, std::set &dest) +{ + if(src.id()==ID_address_of) + { + return; + } + + for(const auto & op : src.operands()) + collect_conditions_rec(op, dest); + + if(src.type().id()==ID_bool) + { + if(src.id()==ID_and || src.id()==ID_or || + src.id()==ID_not || src.id()==ID_implies) + { + // ignore me + } + else if(src.is_constant()) + { + // ignore me + } + else + { + dest.insert(src); + } + } +} + +/*******************************************************************\ + +Function: collect_conditions + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +std::set collect_conditions(const exprt &src) +{ + std::set result; + collect_conditions_rec(src, result); + return result; +} + +/*******************************************************************\ + Function: collect_conditions Inputs: @@ -89,21 +148,114 @@ Function: collect_conditions \*******************************************************************/ -void collect_conditions(const exprt &src, std::set &dest) +std::set collect_conditions(const goto_programt::const_targett t) { - if(src.id()==ID_and || src.id()==ID_or || - src.id()==ID_not || src.id()==ID_implies) + switch(t->type) { - forall_operands(it, src) - collect_conditions(*it, dest); + case GOTO: + case ASSUME: + case ASSERT: + return collect_conditions(t->guard); + + case ASSIGN: + case FUNCTION_CALL: + return collect_conditions(t->code); + + default:; } - else if(src.is_true()) + + return std::set(); +} + +/*******************************************************************\ + +Function: collect_decisions_rec + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void collect_decisions_rec(const exprt &src, std::set &dest) +{ + if(src.id()==ID_address_of) { + return; + } + + if(src.type().id()==ID_bool) + { + if(src.is_constant()) + { + // ignore me + } + else if(src.id()==ID_not) + { + collect_decisions_rec(src.op0(), dest); + } + else + { + dest.insert(src); + } } else { - dest.insert(src); + for(const auto & op : src.operands()) + collect_decisions_rec(op, dest); + } +} + +/*******************************************************************\ + +Function: collect_decisions + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +std::set collect_decisions(const exprt &src) +{ + std::set result; + collect_decisions_rec(src, result); + return result; +} + +/*******************************************************************\ + +Function: collect_decisions + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +std::set collect_decisions(const goto_programt::const_targett t) +{ + switch(t->type) + { + case GOTO: + case ASSUME: + case ASSERT: + return collect_decisions(t->guard); + + case ASSIGN: + case FUNCTION_CALL: + return collect_decisions(t->code); + + default:; } + + return std::set(); } /*******************************************************************\ @@ -190,32 +342,73 @@ void instrument_cover_goals( break; case coverage_criteriont::CONDITION: - if(i_it->is_goto()) + // Conditions are all atomic predicates in the programs. { - std::set conditions; + std::set conditions= + collect_conditions(i_it); + + source_locationt source_location=i_it->source_location; - collect_conditions(i_it->guard, conditions); - unsigned i=0; + for(const auto & c : conditions) + { + std::string comment_t="condition "+from_expr(ns, "", c)+" true"; + 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); + + std::string comment_f="condition "+from_expr(ns, "", c)+" false"; + goto_program.insert_before_swap(i_it); + i_it->make_assertion(not_exprt(c)); + i_it->source_location=source_location; + i_it->source_location.set_comment(comment_f); + } + + for(unsigned i=0; i decisions= + collect_decisions(i_it); - exprt guard=i_it->guard; source_locationt source_location=i_it->source_location; - for(std::set::const_iterator it=conditions.begin(); - it!=conditions.end(); - it++, i++) + for(const auto & d : decisions) { - std::string comment="condition "+from_expr(ns, "", *it); + std::string comment_t="decision "+from_expr(ns, "", d)+" true"; goto_program.insert_before_swap(i_it); - i_it->make_assertion(*it); + i_it->make_assertion(d); i_it->source_location=source_location; - i_it->source_location.set_comment(comment); + i_it->source_location.set_comment(comment_t); + + std::string comment_f="decision "+from_expr(ns, "", d)+" false"; + goto_program.insert_before_swap(i_it); + i_it->make_assertion(not_exprt(d)); + i_it->source_location=source_location; + i_it->source_location.set_comment(comment_f); } - for(unsigned i=0; i Date: Sat, 9 Apr 2016 21:44:15 +0100 Subject: [PATCH 018/101] Started type checking jsil programs --- src/jsil/Makefile | 2 +- src/jsil/jsil_internal_additions.cpp | 27 + src/jsil/jsil_language.cpp | 5 +- src/jsil/jsil_parse_tree.cpp | 14 +- src/jsil/jsil_parse_tree.h | 34 + src/jsil/jsil_typecheck.cpp | 1057 +++++++++++++++++++++++++- src/jsil/jsil_typecheck.h | 49 +- src/jsil/jsil_types.cpp | 266 +++++++ src/jsil/jsil_types.h | 106 +++ src/jsil/parser.y | 10 +- 10 files changed, 1551 insertions(+), 19 deletions(-) create mode 100644 src/jsil/jsil_types.cpp create mode 100644 src/jsil/jsil_types.h diff --git a/src/jsil/Makefile b/src/jsil/Makefile index 10c915844f2..e3bcb1b92ce 100644 --- a/src/jsil/Makefile +++ b/src/jsil/Makefile @@ -1,5 +1,5 @@ SRC = jsil_y.tab.cpp jsil_lex.yy.cpp \ - jsil_convert.cpp jsil_language.cpp jsil_parse_tree.cpp \ + jsil_convert.cpp jsil_language.cpp jsil_parse_tree.cpp jsil_types.cpp \ jsil_parser.cpp jsil_typecheck.cpp expr2jsil.cpp \ jsil_entry_point.cpp jsil_internal_additions.cpp diff --git a/src/jsil/jsil_internal_additions.cpp b/src/jsil/jsil_internal_additions.cpp index 00da0cf0102..c2906a6e979 100644 --- a/src/jsil/jsil_internal_additions.cpp +++ b/src/jsil/jsil_internal_additions.cpp @@ -12,6 +12,8 @@ Author: Michael Tautschnig, tautschn@amazon.com #include +#include "jsil_types.h" + #include "jsil_internal_additions.h" /*******************************************************************\ @@ -70,4 +72,29 @@ void jsil_internal_additions(symbol_tablet &dest) symbol.mode="jsil"; dest.add(symbol); } + + // add builtin objects + const std::vector builtin_objects= + { "#lg", "#lg_isNan", "#lg_isFinite", "#lop", "#lop_toString", + "#lop_valueOf", "#lop_isPrototypeOf", "#lfunction", "#lfp", + "#leval", "#lerror", "#lep", "#lrerror", "#lrep", "#lterror", + "#ltep", "#lserror", "#lsep", "#levalerror", "#levalerrorp", + "#lrangeerror", "#lrangeerrorp", "#lurierror", "#lurierrorp", + "#lobject", "#lobject_get_prototype_of", "#lboolean", "#lbp", + "#lbp_toString", "#lbp_valueOf", "#lnumber", "#lnp", + "#lnp_toString", "#lnp_valueOf", "#lmath", "#lstring", "#lsp", + "#lsp_toString", "#lsp_valueOf", "#larray", "#lap", "#ljson" + }; + + for(const auto & identifier : builtin_objects) + { + symbolt new_symbol; + new_symbol.name=identifier; + new_symbol.type=jsil_builtin_objectt(); + new_symbol.base_name=identifier; + new_symbol.mode="jsil"; + new_symbol.is_type=false; + new_symbol.is_lvalue=false; + dest.add(new_symbol); + } } diff --git a/src/jsil/jsil_language.cpp b/src/jsil/jsil_language.cpp index 58a9b315ef1..844e49fe3b4 100644 --- a/src/jsil/jsil_language.cpp +++ b/src/jsil/jsil_language.cpp @@ -120,7 +120,7 @@ Function: jsil_languaget::typecheck Outputs: - Purpose: + Purpose: Converting from parse tree and type checking. \*******************************************************************/ @@ -131,6 +131,8 @@ bool jsil_languaget::typecheck( if(jsil_convert(parse_tree, symbol_table, get_message_handler())) return true; + jsil_internal_additions(symbol_table); + // now typecheck if(jsil_typecheck(symbol_table, get_message_handler())) return true; @@ -152,7 +154,6 @@ Function: jsil_languaget::final bool jsil_languaget::final(symbol_tablet &symbol_table) { - jsil_internal_additions(symbol_table); if(jsil_entry_point( symbol_table, diff --git a/src/jsil/jsil_parse_tree.cpp b/src/jsil/jsil_parse_tree.cpp index 2f394e31abf..f6ec26084bf 100644 --- a/src/jsil/jsil_parse_tree.cpp +++ b/src/jsil/jsil_parse_tree.cpp @@ -8,6 +8,8 @@ Author: Michael Tautschnig, tautschn@amazon.com #include +#include "jsil_types.h" + #include "jsil_parse_tree.h" /*******************************************************************\ @@ -66,10 +68,19 @@ void jsil_declarationt::to_symbol(symbolt &symbol) const symbol_exprt s(to_symbol_expr( static_cast(find(ID_declarator)))); + code_typet symbol_type=to_code_type(s.type()); + + irep_idt proc_type=s.get("proc_type"); + + if(proc_type=="builtin") + symbol_type=jsil_builtin_code_typet(symbol_type); + else if(proc_type=="spec") + symbol_type=jsil_spec_code_typet(symbol_type); + symbol.name=s.get_identifier(); symbol.base_name=s.get_identifier(); symbol.mode="jsil"; - symbol.type=s.type(); + symbol.type=symbol_type; symbol.location=s.source_location(); code_blockt code(to_code_block( @@ -133,4 +144,3 @@ void jsil_parse_treet::output(std::ostream &out) const out << "\n"; } } - diff --git a/src/jsil/jsil_parse_tree.h b/src/jsil/jsil_parse_tree.h index 11ac901ab44..8cf500f9300 100644 --- a/src/jsil/jsil_parse_tree.h +++ b/src/jsil/jsil_parse_tree.h @@ -29,6 +29,16 @@ class jsil_declarationt:public exprt add(ID_declarator, expr); } + const symbol_exprt &declarator() const + { + return static_cast(find(ID_declarator)); + } + + symbol_exprt &declarator() + { + return static_cast(add(ID_declarator)); + } + void add_returns( const irep_idt &value, const irep_idt &label) @@ -37,6 +47,14 @@ class jsil_declarationt:public exprt add(ID_return).set(ID_label, label); } + const irep_idt &returns_value() const { + return find(ID_return).get(ID_value); + } + + const irep_idt &returns_label() const { + return find(ID_return).get(ID_label); + } + void add_throws( const irep_idt &value, const irep_idt &label) @@ -45,11 +63,27 @@ class jsil_declarationt:public exprt add(ID_throw).set(ID_label, label); } + const irep_idt &throws_value() const { + return find(ID_throw).get(ID_value); + } + + const irep_idt &throws_label() const { + return find(ID_throw).get(ID_label); + } + void add_value(const code_blockt &code) { add(ID_value, code); } + const code_blockt &value() const { + return static_cast (find(ID_value)); + } + + code_blockt &value() { + return static_cast (add(ID_value)); + } + void to_symbol(symbolt &symbol) const; void output(std::ostream &) const; diff --git a/src/jsil/jsil_typecheck.cpp b/src/jsil/jsil_typecheck.cpp index f0a26a988ec..419b2a99acb 100644 --- a/src/jsil/jsil_typecheck.cpp +++ b/src/jsil/jsil_typecheck.cpp @@ -7,8 +7,10 @@ Author: Michael Tautschnig, tautschn@amazon.com \*******************************************************************/ #include +#include #include "expr2jsil.h" +#include "jsil_types.h" #include "jsil_typecheck.h" @@ -48,7 +50,1029 @@ std::string jsil_typecheckt::to_string(const typet &type) /*******************************************************************\ -Function: java_bytecode_typecheckt::typecheck_non_type_symbol +Function: jsil_typecheckt::add_prefix + + Inputs: + + Outputs: + + Purpose: Prefix parameters and variables with a procedure name + +\*******************************************************************/ + +irep_idt jsil_typecheckt::add_prefix(const irep_idt &ds) +{ + return id2string(proc_name)+"::"+id2string(ds); +} + +/*******************************************************************\ + +Function: jsil_typecheckt::update_expr_type + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +void jsil_typecheckt::update_expr_type(exprt &expr, const typet &type) +{ + expr.type()=type; + + if(expr.id()==ID_symbol) + { + symbol_exprt &sexpr=to_symbol_expr(expr); + const irep_idt &id=sexpr.get_identifier(); + + if(!symbol_table.has_symbol(id)) + throw "Unexpected symbol "+id2string(id); + + symbolt &s=symbol_table.lookup(id); + if(s.type.id_string().empty() || s.type.is_nil()) + s.type=type; + else + s.type=jsil_union(s.type, type); + } +} + +/*******************************************************************\ + +Function: jsil_typecheckt::make_type_compatible + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::make_type_compatible( + exprt &expr, + const typet &type, + bool must) +{ + if(expr.type().id().empty() || expr.type().is_nil()) + { + // Type is not yet set + update_expr_type(expr, type); + return; + } + + if(must) + { + if(jsil_union_typet(expr.type()).intersect_with( + jsil_union_typet(type)).components().empty()) + throw "Failed to typecheck expr "+expr.pretty()+ + " with type "+expr.type().pretty()+"; required type "+ + type.pretty(); + } + else + { + if(!jsil_is_subtype(type, expr.type())) + { + // Types are not compatible + typet upper=jsil_union(expr.type(), type); + update_expr_type(expr, upper); + } + } +} + +/*******************************************************************\ + +Function: jsil_typecheckt::typecheck_type + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_type(typet &type) +{ + if(type.id()==ID_code) + { + code_typet ¶meters=to_code_type(type); + + for (code_typet::parametert& p : parameters.parameters()) + { + // create the symbol + parameter_symbolt new_symbol; + new_symbol.base_name=p.get_identifier(); + // appending procedure name to parameters + p.set_identifier(add_prefix(p.get_identifier())); + new_symbol.name=p.get_identifier(); + + if(is_jsil_builtin_code_type(type)) + new_symbol.type=jsil_value_or_emptyt(); + else if(is_jsil_spec_code_type(type)) + new_symbol.type=jsil_value_or_referencet(); + else + // User defined function + new_symbol.type=jsil_valuet(); + + new_symbol.mode="jsil"; + + if(symbol_table.add(new_symbol)) + throw "failed to add parameter symbol"; + } + } +} + +/*******************************************************************\ + +Function: jsil_typecheckt::typecheck_type + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr(exprt &expr) +{ + // first do sub-nodes + typecheck_expr_operands(expr); + + // now do case-split + typecheck_expr_main(expr); +} + +/*******************************************************************\ + +Function: jsil_typecheckt::typecheck_expr_operands + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_operands(exprt &expr) +{ + Forall_operands(it, expr) + typecheck_expr(*it); +} + +/*******************************************************************\ + +Function: jsil_typecheckt::typecheck_expr_main + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_main(exprt &expr) +{ + if(expr.id()==ID_code) + { + err_location(expr); + str << "typecheck_expr_main got code: " << expr.pretty(); + throw 0; + } + else if(expr.id()==ID_symbol) + typecheck_symbol_expr(to_symbol_expr (expr)); + else if(expr.id()==ID_side_effect) + typecheck_expr_side_effect(to_side_effect_expr(expr)); + else if(expr.id()==ID_constant || + expr.id()==ID_string_constant || + expr.id()==ID_null || + expr.id()=="undefined" || + expr.id()==ID_empty) + typecheck_expr_constant(expr); + else if(expr.id()=="null_type" || + expr.id()=="undefined_type" || + expr.id()==ID_boolean || + expr.id()==ID_string || + expr.id()=="number" || + expr.id()=="builtin_object" || + expr.id()=="user_object" || + expr.id()=="object" || + expr.id()==ID_reference || + expr.id()==ID_member || + expr.id()=="variable") + expr.type()=jsil_kindt(); + else if(expr.id()=="proto" || + expr.id()=="fid" || + expr.id()=="scope" || + expr.id()=="constructid" || + expr.id()=="primvalue" || + expr.id()=="targetfunction" || + expr.id()==ID_class) + { + // TODO: builtin fields -- do we want special field type? + expr.type()=string_typet(); + } + else if(expr.id()==ID_not) + typecheck_expr_unary_boolean(expr); + else if(expr.id()=="string_to_num") + typecheck_expr_unary_string(expr); + else if(expr.id()==ID_unary_minus || + expr.id()=="num_to_int32" || + expr.id()=="num_to_uint32" || + expr.id()==ID_bitnot) + { + typecheck_expr_unary_num(expr); + expr.type() = floatbv_typet(); + } + else if(expr.id()=="num_to_string") + { + typecheck_expr_unary_num(expr); + expr.type() = string_typet(); + } + else if(expr.id()==ID_equal) + typecheck_exp_binary_equal(expr); + else if(expr.id()==ID_lt || + expr.id()==ID_le) + typecheck_expr_binary_compare(expr); + else if(expr.id()==ID_plus || + expr.id()==ID_minus || + expr.id()==ID_mult || + expr.id()==ID_div || + expr.id()==ID_mod) + typecheck_expr_binary_arith(expr); + else if(expr.id()==ID_and || + expr.id()==ID_or) + typecheck_expr_binary_boolean(expr); + else if(expr.id()=="subtype_of") + typecheck_expr_subtype(expr); + else if(expr.id()==ID_concatenation) + typecheck_expr_concatenation(expr); + else if(expr.id()=="ref") + typecheck_expr_ref(expr); + else if(expr.id()=="field") + typecheck_expr_field(expr); + else if(expr.id()==ID_base) + typecheck_expr_base(expr); + else if(expr.id()==ID_typeof) + expr.type()=jsil_kindt(); + else if(expr.id()=="new") + expr.type()=jsil_user_objectt(); + else if(expr.id()=="hasField") + typecheck_expr_has_field(expr); + else if(expr.id()==ID_index) + typecheck_expr_index(expr); + else if(expr.id()=="delete") + typecheck_expr_delete(expr); + else if(expr.id()=="protoField") + typecheck_expr_proto_field(expr); + else if(expr.id()=="protoObj") + typecheck_expr_proto_obj(expr); + else if(expr.is_nil()) + { + assert(false); + } + else + { + err_location(expr); + str << "unexpected expression: " << expr.pretty(); + throw 0; + } +} + +/*******************************************************************\ + +Function: jsil_typecheck_baset::typecheck_expr_constant + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_constant(exprt &expr) +{ + // no need to typecheck ID_constant + // TODO: make compatible with string_typet + // (expr.id()==ID_string_constant) + if(expr.id()==ID_null) + expr.type()=jsil_nullt(); + else if(expr.id()=="undefined") + expr.type()=jsil_undefinedt(); + else if(expr.id()==ID_empty) + expr.type()=empty_typet(); +} + +/*******************************************************************\ + +Function: jsil_typecheck_baset::typecheck_expr_proto_field + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_proto_field(exprt &expr) +{ + if(expr.operands().size()!=2) + { + err_location(expr); + str << "operator `" << expr.id() << "' expects two operands"; + throw 0; + } + + exprt &operand1=expr.op0(); + make_type_compatible(operand1, jsil_objectt(), true); + + exprt &operand2=expr.op1(); + make_type_compatible(operand2, string_typet(), true); + + expr.type()=jsil_value_or_emptyt(); +} + +/*******************************************************************\ + +Function: jsil_typecheck_baset::typecheck_expr_proto_field + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_proto_obj(exprt &expr) +{ + if(expr.operands().size()!=2) + { + err_location(expr); + str << "operator `" << expr.id() << "' expects two operands"; + throw 0; + } + + exprt &operand1=expr.op0(); + make_type_compatible(operand1, jsil_objectt(), true); + + exprt &operand2=expr.op1(); + make_type_compatible(operand2, jsil_objectt(), true); + + expr.type()=bool_typet(); +} + +/*******************************************************************\ + +Function: jsil_typecheck_baset::typecheck_expr_delete + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_delete(exprt &expr) +{ + if(expr.operands().size()!=2) + { + err_location(expr); + str << "operator `" << expr.id() << "' expects two operands"; + throw 0; + } + + exprt &operand1=expr.op0(); + make_type_compatible(operand1, jsil_objectt(), true); + + exprt &operand2=expr.op1(); + make_type_compatible(operand2, string_typet(), true); + + expr.type()=bool_typet(); +} + +/*******************************************************************\ + +Function: jsil_typecheck_baset::typecheck_expr_hasfield + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_index(exprt &expr) +{ + if(expr.operands().size()!=2) + { + err_location(expr); + str << "operator `" << expr.id() << "' expects two operands"; + throw 0; + } + + exprt &operand1=expr.op0(); + make_type_compatible(operand1, jsil_objectt(), true); + + exprt &operand2=expr.op1(); + make_type_compatible(operand2, string_typet(), true); + + expr.type()=jsil_valuet(); +} + +/*******************************************************************\ + +Function: jsil_typecheck_baset::typecheck_expr_hasfield + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_has_field(exprt &expr) +{ + if(expr.operands().size()!=2) + { + err_location(expr); + str << "operator `" << expr.id() << "' expects two operands"; + throw 0; + } + + exprt &operand1=expr.op0(); + make_type_compatible(operand1, jsil_objectt(), true); + + exprt &operand2=expr.op1(); + make_type_compatible(operand2, string_typet(), true); + + expr.type()=bool_typet(); +} + +/*******************************************************************\ + +Function: jsil_typecheck_baset::typecheck_expr_field + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_field(exprt &expr) +{ + if(expr.operands().size()!=1) + { + err_location(expr); + str << "operator `" << expr.id() << "' expects single operand"; + throw 0; + } + + exprt &operand1=expr.op0(); + make_type_compatible(operand1, jsil_referencet(), true); + + expr.type()=string_typet(); +} + +/*******************************************************************\ + +Function: jsil_typecheck_baset::typecheck_expr_base + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_base(exprt &expr) +{ + if(expr.operands().size()!=1) + { + err_location(expr); + str << "operator `" << expr.id() << "' expects single operand"; + throw 0; + } + + exprt &operand1=expr.op0(); + make_type_compatible(operand1, jsil_referencet(), true); + + // TODO: can we be more precise here we know something more about op0? + expr.type()=jsil_valuet(); +} + +/*******************************************************************\ + +Function: jsil_typecheck_baset::typecheck_expr_ref + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_ref(exprt &expr) +{ + if(expr.operands().size()!=3) + { + err_location(expr); + str << "operator `" << expr.id() << "' expects three operands"; + throw 0; + } + + exprt &operand1=expr.op0(); + make_type_compatible(operand1, jsil_valuet(), true); + exprt &operand2=expr.op1(); + // TODO: do we want a new field type? since we have built-in fields + make_type_compatible(operand2, string_typet(), true); + exprt &operand3=expr.op2(); + make_type_compatible(operand3, jsil_kindt(), true); + + if(operand3.id()==ID_member) + expr.type()=jsil_member_referencet(); + else if(operand3.id()=="variable") + expr.type()=jsil_variable_referencet(); + else + { + err_location(expr); + str << "operator `" << expr.id() + << "' expects reference type in the third parameter. But got:" + << operand3.pretty(); + throw 0; + } +} + +/*******************************************************************\ + +Function: jsil_typecheck_baset::typecheck_expr_concatenation + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_concatenation(exprt &expr) +{ + if(expr.operands().size()!=2) + { + err_location(expr); + str << "operator `" << expr.id() << "' expects two operands"; + throw 0; + } + + exprt &operand1=expr.op0(); + make_type_compatible(operand1, string_typet(), true); + exprt &operand2=expr.op1(); + make_type_compatible(operand2, string_typet(), true); + + expr.type()=string_typet(); +} + +/*******************************************************************\ + +Function: jsil_typecheck_baset::typecheck_expr_subtype + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_subtype(exprt &expr) +{ + if(expr.operands().size()!=2) + { + err_location(expr); + str << "operator `" << expr.id() << "' expects two operands"; + throw 0; + } + + exprt &operand1=expr.op0(); + make_type_compatible(operand1, jsil_kindt(), true); + exprt &operand2=expr.op1(); + make_type_compatible(operand2, jsil_kindt(), true); + + expr.type()=bool_typet(); +} + +/*******************************************************************\ + +Function: jsil_typecheck_baset::typecheck_expr_binary_boolean + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_binary_boolean(exprt &expr) +{ + if(expr.operands().size()!=2) + { + err_location(expr); + str << "operator `" << expr.id() << "' expects two operands"; + throw 0; + } + + exprt &operand1=expr.op0(); + make_type_compatible(operand1, bool_typet(), true); + exprt &operand2=expr.op1(); + make_type_compatible(operand2, bool_typet(), true); + + expr.type()=bool_typet(); +} + +/*******************************************************************\ + +Function: jsil_typecheck_baset::typecheck_expr_binary_arith + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_binary_arith(exprt &expr) +{ + if(expr.operands().size()!=2) + { + err_location(expr); + str << "operator `" << expr.id() << "' expects two operands"; + throw 0; + } + + exprt &operand1=expr.op0(); + make_type_compatible(operand1, floatbv_typet(), true); + exprt &operand2=expr.op1(); + make_type_compatible(operand2, floatbv_typet(), true); + + expr.type()=floatbv_typet(); +} + +/*******************************************************************\ + +Function: jsil_typecheck_baset::typecheck_exp_binary_equal + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_exp_binary_equal(exprt &expr) +{ + if(expr.operands().size()!=2) + { + err_location(expr); + str << "operator `" << expr.id() << "' expects two operands"; + throw 0; + } + + // operands can be of any types + + expr.type()=bool_typet(); +} + +/*******************************************************************\ + +Function: jsil_typecheck_baset::typecheck_expr_binary_compare + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_binary_compare(exprt &expr) +{ + if(expr.operands().size()!=2) + { + err_location(expr); + str << "operator `" << expr.id() << "' expects two operands"; + throw 0; + } + + exprt &operand1=expr.op0(); + make_type_compatible(operand1, floatbv_typet(), true); + exprt &operand2=expr.op1(); + make_type_compatible(operand2, floatbv_typet(), true); + + expr.type()=bool_typet(); +} + +/*******************************************************************\ + +Function: jsil_typecheck_baset::typecheck_expr_unary_boolean + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_unary_boolean(exprt &expr) +{ + if(expr.operands().size()!=1) + { + err_location(expr); + str << "operator `" << expr.id() << "' expects one operand"; + throw 0; + } + + exprt &operand=expr.op0(); + make_type_compatible(operand, bool_typet(), true); + + expr.type()=bool_typet(); +} + +/*******************************************************************\ + +Function: jsil_typecheck_baset::typecheck_expr_unary_string + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_unary_string(exprt &expr) +{ + if(expr.operands().size()!=1) + { + err_location(expr); + str << "operator `" << expr.id() + << "' expects one operand"; + throw 0; + } + + exprt &operand=expr.op0(); + make_type_compatible(operand, string_typet(), true); + + expr.type()=floatbv_typet(); +} + +/*******************************************************************\ + +Function: jsil_typecheck_baset::typecheck_expr_unary_num + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_unary_num(exprt &expr) +{ + if(expr.operands().size()!=1) + { + err_location(expr); + str << "operator `" << expr.id() << "' expects one operand"; + throw 0; + } + + exprt &operand=expr.op0(); + make_type_compatible(operand, floatbv_typet(), true); +} + +/*******************************************************************\ + +Function: jsil_typecheckt::typecheck_symbol_expr + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_symbol_expr(symbol_exprt &symbol_expr) +{ + irep_idt identifier=symbol_expr.get_identifier(); + + // if it is another identifier, such as #lop, #builtin-fid + // check if it is in the table and add it's type + if(has_prefix(id2string(identifier), "#")) + { + // does it exist already in the symbol table? + symbol_tablet::symbolst::const_iterator s_it= + symbol_table.symbols.find(identifier); + + if(s_it==symbol_table.symbols.end()) + throw "Unexpected internal symbol: "+id2string(identifier); + } + else + { + // if it is a variable, we need to check if we already prefixed it + // and add to the table if it is not there already + irep_idt identifier_base = identifier; + if(!has_prefix(id2string(identifier), id2string(proc_name))) + { + identifier = add_prefix(identifier); + symbol_expr.set_identifier(identifier); + } + + // does it exist already in the symbol table? + symbol_tablet::symbolst::const_iterator s_it= + symbol_table.symbols.find(identifier); + + if(s_it==symbol_table.symbols.end()) + { + // no, create the symbol + symbolt new_symbol; + new_symbol.name=identifier; + new_symbol.type=symbol_expr.type(); + new_symbol.base_name=identifier_base; + new_symbol.mode="jsil"; + new_symbol.is_type=false; + + if(new_symbol.type.id()==ID_code) + new_symbol.is_lvalue=false; + else + new_symbol.is_lvalue=true; + + if(symbol_table.add(new_symbol)) + throw "failed to add expression symbol to symbol table"; + } + else + { + // symbol already exists + assert(!s_it->second.is_type); + + const symbolt &symbol=s_it->second; + + // type the expression + symbol_expr.type()=symbol.type; + } + } +} + +/*******************************************************************\ + +Function: jsil_typecheckt::typecheck_code + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_code(codet &code) +{ + const irep_idt &statement=code.get_statement(); + + if(statement==ID_function_call) + typecheck_function_call(to_code_function_call(code)); + if(statement==ID_decl) + typecheck_decl(to_code_decl(code)); + else if(statement==ID_return) + typecheck_return(code); + else if(statement==ID_expression) + { + if(code.operands().size()!=1) + throw "expression statement expected to have one operand"; + exprt &op=code.op0(); + typecheck_expr(op); + } + else if(statement==ID_label) + { + // TODO: produce defined label set + } + else if(statement==ID_block) + typecheck_block(code); + else if(statement==ID_ifthenelse) + typecheck_ifthenelse(to_code_ifthenelse(code)); + else if(statement==ID_goto) + { + // TODO: produce used label set + } + else if(statement==ID_assign) + typecheck_assign(code); + else if(statement==ID_try_catch) + typecheck_try_catch(to_code_try_catch(code)); + else if(statement==ID_skip) + { + } + else + { + err_location(code); + str << "unexpected statement: " << statement; + throw 0; + } +} + +/*******************************************************************\ + +Function: jsil_typecheckt::typecheck_block + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_block(codet &code) +{ + Forall_operands(it, code) + typecheck_code(to_code(*it)); +} + +/*******************************************************************\ + +Function: jsil_typecheckt::typecheck_try_catch + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_try_catch(code_try_catcht &code) +{ + // A special case of try catch with one catch clause + if(code.operands().size()!=3) + throw "try_catch expected to have three operands"; + + codet &try_code=code.try_code(); + // function call + typecheck_function_call(to_code_function_call(try_code)); + + code_declt &decl_code=code.get_catch_decl(0); + typecheck_decl(decl_code); + + codet &catch_code=code.get_catch_code(0); + typecheck_code(catch_code); +} + + +/*******************************************************************\ + +Function: jsil_typecheckt::typecheck_ifthenelse + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_ifthenelse(code_ifthenelset &code) +{ + if(code.operands().size()!=3) + throw "ifthenelse expected to have three operands"; + + exprt &cond=code.cond(); + + typecheck_expr(cond); + make_type_compatible(cond, bool_typet(), true); + + typecheck_code(to_code(code.then_case())); + + if(!code.else_case().is_nil()) + typecheck_code(to_code(code.else_case())); +} + +/*******************************************************************\ + +Function: jsil_typecheckt::typecheck_assign Inputs: @@ -58,11 +1082,40 @@ Function: java_bytecode_typecheckt::typecheck_non_type_symbol \*******************************************************************/ +void jsil_typecheckt::typecheck_assign(codet &code) +{ + if(code.operands().size()!=2) + throw "assignment statement expected to have two operands"; + + typecheck_expr(code.op0()); + typecheck_expr(code.op1()); + + make_type_compatible(code.op0(), code.op1().type(), false); +} + +/*******************************************************************\ + +Function: java_bytecode_typecheckt::typecheck_non_type_symbol + + Inputs: symbol denotes a procedure declaration + + Outputs: + + Purpose: + +\*******************************************************************/ + void jsil_typecheckt::typecheck_non_type_symbol(symbolt &symbol) { assert(!symbol.is_type); + proc_name = symbol.name; typecheck_type(symbol.type); - typecheck_expr(symbol.value); + if (symbol.value.is_nil()) {} + else if (symbol.value.id()==ID_code) + typecheck_code(to_code(symbol.value)); + else throw ("Non type symbol value " + symbol.value.pretty()); + + // TODO: mark as 'already typechecked' } /*******************************************************************\ diff --git a/src/jsil/jsil_typecheck.h b/src/jsil/jsil_typecheck.h index 8768781525e..8acda569474 100644 --- a/src/jsil/jsil_typecheck.h +++ b/src/jsil/jsil_typecheck.h @@ -11,6 +11,7 @@ Author: Michael Tautschnig, tautschn@amazon.com #include #include +#include "jsil_parse_tree.h" class codet; @@ -31,29 +32,58 @@ class jsil_typecheckt:public legacy_typecheckt message_handlert &_message_handler): legacy_typecheckt(_message_handler), symbol_table(_symbol_table), - ns(symbol_table) + ns(symbol_table), + proc_name("") { } virtual ~jsil_typecheckt() { } virtual void typecheck(); - virtual void typecheck_expr(exprt &expr) {}; + virtual void typecheck_expr(exprt &expr); protected: symbol_tablet &symbol_table; const namespacet ns; + // prefix to variables which is set in typecheck_declaration + irep_idt proc_name; + void update_expr_type (exprt &expr, const typet &type); + void make_type_compatible(exprt &expr, const typet &type, bool must); void typecheck_type_symbol(symbolt &symbol) {}; void typecheck_non_type_symbol(symbolt &symbol); + void typecheck_symbol_expr(symbol_exprt &symbol_expr); + void typecheck_expr_side_effect(side_effect_exprt &expr) {}; + void typecheck_expr_delete(exprt &expr); + void typecheck_expr_index(exprt &expr); + void typecheck_expr_proto_field(exprt &expr); + void typecheck_expr_proto_obj(exprt &expr); + void typecheck_expr_has_field(exprt &expr); + void typecheck_expr_ref(exprt &expr); + void typecheck_expr_field(exprt &expr); + void typecheck_expr_base(exprt &expr); + void typecheck_expr_constant(exprt &expr); + void typecheck_expr_concatenation(exprt &expr); + void typecheck_expr_subtype(exprt &expr); + void typecheck_expr_binary_boolean(exprt &expr); + void typecheck_expr_binary_arith(exprt &expr); + void typecheck_exp_binary_equal(exprt &expr); + void typecheck_expr_binary_compare(exprt &expr); + void typecheck_expr_unary_boolean(exprt &expr); + void typecheck_expr_unary_string(exprt &expr); + void typecheck_expr_unary_num(exprt &expr); + void typecheck_expr_operands(exprt &expr); + void typecheck_expr_main(exprt &expr); void typecheck_code(codet &code); - void typecheck_type(typet &type) {}; -#if 0 - void typecheck_expr_symbol(symbol_exprt &expr); - void typecheck_expr_member(member_exprt &expr); - void typecheck_expr_java_new(side_effect_exprt &expr); - void typecheck_expr_java_new_array(side_effect_exprt &expr); -#endif + void typecheck_function_call(code_function_callt &code) {}; + void typecheck_decl(code_declt &code) {}; + void typecheck_return(codet &code) {}; + void typecheck_block(codet &code); + void typecheck_ifthenelse(code_ifthenelset &code); + void typecheck_assign(codet &code); + void typecheck_try_catch (code_try_catcht &code); + void typecheck_type(typet &type); + dstring add_prefix(const dstring &ds); // overload to use language-specific syntax virtual std::string to_string(const exprt &expr); @@ -63,4 +93,3 @@ class jsil_typecheckt:public legacy_typecheckt }; #endif - diff --git a/src/jsil/jsil_types.cpp b/src/jsil/jsil_types.cpp new file mode 100644 index 00000000000..d6ba6cfa499 --- /dev/null +++ b/src/jsil/jsil_types.cpp @@ -0,0 +1,266 @@ +/*******************************************************************\ + +Module: Jsil Language + +Author: Daiva Naudziuniene, daivan@amazon.com + +\*******************************************************************/ + +#include "jsil_types.h" + +typet jsil_any_typet() +{ + return jsil_union_typet({ + empty_typet(), + jsil_referencet(), + jsil_valuet() + }); +} + +typet jsil_value_or_emptyt() +{ + return jsil_union_typet({ + jsil_valuet(), + empty_typet() + }); +} + +typet jsil_value_or_referencet() +{ + return jsil_union_typet({ + jsil_valuet(), + jsil_referencet() + }); +} + +typet jsil_valuet() +{ + return jsil_union_typet({ + jsil_undefinedt(), + jsil_nullt(), + jsil_prim_typet(), + jsil_objectt() + }); +} + +typet jsil_prim_typet() +{ + return jsil_union_typet({ + floatbv_typet(), + string_typet(), + bool_typet() + }); +} + +typet jsil_referencet() { + return jsil_union_typet({ + jsil_member_referencet(), + jsil_variable_referencet() + }); +} + +typet jsil_member_referencet() +{ + return typet("jsil_member_referencet"); +} + +typet jsil_variable_referencet() +{ + return typet("jsil_variable_referencet"); +} + +typet jsil_objectt() { + return jsil_union_typet({ + jsil_user_objectt(), + jsil_builtin_objectt() + }); +} + +typet jsil_user_objectt() +{ + return typet("jsil_user_objectt"); +} + +typet jsil_builtin_objectt() +{ + return typet("jsil_builtin_objectt"); +} + +typet jsil_nullt() +{ + return typet("jsil_nullt"); +} + +typet jsil_undefinedt() +{ + return typet("jsil_undefinedt"); +} + +typet jsil_kindt() +{ + return typet("jsil_kindt"); +} + +/*******************************************************************\ + +Function: jsil_upper_bound_type + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool jsil_is_subtype(const typet &type1, const typet &type2) +{ + if(type2.id()==ID_union) + { + const jsil_union_typet &type2_union=to_jsil_union_type(type2); + if(type1.id()==ID_union) + { + return to_jsil_union_type(type1).is_subtype(type2_union); + } + else + { + return (jsil_union_typet(type1).is_subtype(type2_union)); + } + } + else + return type1.id()==type2.id(); +} + +typet jsil_union(const typet &type1, const typet &type2) +{ + return jsil_union_typet(type1).union_with( + jsil_union_typet(type2)).to_type(); +} + +bool compare_components( + const union_typet::componentt &comp1, + const union_typet::componentt &comp2) +{ + return comp1.type().id().get_no() < comp2.type().id().get_no(); +} + +jsil_union_typet::jsil_union_typet( + const std::vector &types):union_typet() +{ + auto &elements=components(); + for(const auto &type : types) + { + if(type.id()==ID_union) + { + for(const auto &component : to_union_type(type).components()) + { + elements.push_back(component); + } + } + else + elements.push_back(componentt(ID_anonymous, type)); + } + + std::sort(elements.begin(), elements.end(), compare_components); +} + +/*******************************************************************\ + +Function: jsil_union_typet::union_with + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +jsil_union_typet jsil_union_typet::union_with( + const jsil_union_typet &other) const +{ + auto &elements1 = components(); + auto &elements2 = other.components(); + jsil_union_typet result; + auto &elements = result.components(); + elements.resize(elements1.size()+elements2.size()); + std::vector::iterator it=std::set_union( + elements1.begin(), elements1.end(), elements2.begin(), elements2.end(), + elements.begin(), compare_components); + elements.resize(it-elements.begin()); + return result; +} + +/*******************************************************************\ + +Function: jsil_union_typet::intersect_with + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +jsil_union_typet jsil_union_typet::intersect_with( + const jsil_union_typet &other) const +{ + auto &elements1=components(); + auto &elements2=other.components(); + jsil_union_typet result; + auto &elements=result.components(); + elements.resize(std::min(elements1.size(),elements2.size())); + std::vector::iterator it=std::set_intersection( + elements1.begin(), elements1.end(), elements2.begin(), elements2.end(), + elements.begin(), compare_components); + elements.resize(it-elements.begin()); + + return result; +} + +/*******************************************************************\ + +Function: jsil_union_typet::is_subtype + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool jsil_union_typet::is_subtype(const jsil_union_typet &other) const +{ + auto &elements1=components(); + auto &elements2=other.components(); + std::vector diff(elements1.size()); + std::vector::iterator it=std::set_difference( + elements1.begin(), elements1.end(), elements2.begin(), elements2.end(), + diff.begin(), compare_components); + diff.resize(it-diff.begin()); + + return diff.empty(); +} + +/*******************************************************************\ + +Function: jsil_union_typet::to_type() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +const typet& jsil_union_typet::to_type() const +{ + auto &elements=components(); + if (elements.size()==1) + return elements[0].type(); + + return *this; +} diff --git a/src/jsil/jsil_types.h b/src/jsil/jsil_types.h new file mode 100644 index 00000000000..d8cb1043fb7 --- /dev/null +++ b/src/jsil/jsil_types.h @@ -0,0 +1,106 @@ +/*******************************************************************\ + +Module: Jsil Language + +Author: Daiva Naudziuniene, daivan@amazon.com + +\*******************************************************************/ + +#ifndef CPROVER_JSIL_TYPES_H +#define CPROVER_JSIL_TYPES_H + +#include +#include + +typet jsil_kindt(); +typet jsil_any_typet(); +typet jsil_value_or_emptyt(); +typet jsil_value_or_referencet(); +typet jsil_valuet(); +typet jsil_prim_typet(); +typet jsil_referencet(); +typet jsil_member_referencet(); +typet jsil_variable_referencet(); +typet jsil_objectt(); +typet jsil_user_objectt(); +typet jsil_builtin_objectt(); +typet jsil_nullt(); +typet jsil_undefinedt(); + +bool jsil_is_subtype(const typet &type1, const typet &type2); +typet jsil_union(const typet &type1, const typet &type2); + +class jsil_builtin_code_typet:public code_typet +{ +public: + inline jsil_builtin_code_typet(code_typet &code):code_typet(code) + { + set("jsil_builtin_proceduret", true); + } +}; + +extern inline jsil_builtin_code_typet &to_jsil_builtin_code_type(code_typet &code) +{ + assert(code.get_bool("jsil_builtin_proceduret")); + return static_cast(code); +} + +extern inline bool is_jsil_builtin_code_type(const typet &type) +{ + return type.id()==ID_code && + type.get_bool("jsil_builtin_proceduret"); +} + +class jsil_spec_code_typet:public code_typet +{ +public: + inline jsil_spec_code_typet(code_typet &code):code_typet(code) + { + set("jsil_spec_proceduret", true); + } +}; + +extern inline jsil_spec_code_typet &to_jsil_spec_code_type(code_typet &code) +{ + assert(code.get_bool("jsil_spec_proceduret")); + return static_cast(code); +} + +extern inline bool is_jsil_spec_code_type(const typet &type) +{ + return type.id()==ID_code && + type.get_bool("jsil_spec_proceduret"); +} + +class jsil_union_typet:public union_typet +{ +public: + inline jsil_union_typet():union_typet() { } + + inline jsil_union_typet(const typet &type) + :jsil_union_typet(std::vector({type})) { } + + jsil_union_typet(const std::vector &types); + + jsil_union_typet union_with(const jsil_union_typet &other) const; + + jsil_union_typet intersect_with(const jsil_union_typet &other) const; + + bool is_subtype(const jsil_union_typet &other) const; + + const typet& to_type() const; +}; + +extern inline jsil_union_typet &to_jsil_union_type(typet &type) +{ + assert(type.id()==ID_union); + return static_cast(type); +} + +extern inline const jsil_union_typet &to_jsil_union_type(const typet &type) +{ + assert(type.id()==ID_union); + return static_cast(type); +} + +#endif diff --git a/src/jsil/parser.y b/src/jsil/parser.y index dd6c6901be8..02a5b0e7aa2 100644 --- a/src/jsil/parser.y +++ b/src/jsil/parser.y @@ -153,7 +153,13 @@ proc_ident: TOK_IDENTIFIER newstack($$).swap(e); } | TOK_BUILTIN_IDENTIFIER + { + stack($$).set("proc_type", "builtin"); + } | TOK_SPEC_IDENTIFIER + { + stack($$).set("proc_type", "spec"); + } ; proc_ident_expr: proc_ident @@ -570,11 +576,11 @@ unary_op: TOK_NOT jsil_type: TOK_T_NULL { - newstack($$).id(ID_null); + newstack($$).id("null_type"); } | TOK_T_UNDEFINED { - newstack($$).id("undefined"); + newstack($$).id("undefined_type"); } | TOK_T_BOOLEAN { From 4fe44e8aa486ffbc17fba555897d8f1972a20339 Mon Sep 17 00:00:00 2001 From: Daiva Naudziuniene Date: Mon, 16 May 2016 23:19:56 +0000 Subject: [PATCH 019/101] Improvements to Jsil type checking Catch decl in the try/catch is not used. Making string constants to be ID_constant expressions with string_typet Typecheking function call. Added "nan" symbol. Assigning type to lhs after unknown function call. White spaces, positioning { in new line. Cleaning up the code. Correct includes. Renaming jsil types. Explicit constructors. Inlining expressions if used only once. Asserting that expression does not have type set just yet. More efficient implementation for is_subtype. Introduced jsil_incompatible_types to hide low level implementation. Fixed bug in is_subtype. Typechecking throw and return labels. Typechecking bitwise operators. Avoiding duplicate type-checking by marking symbols as type-checked. Add empty decl symbol. Special case for index expression. Clean up. Converting all procedure declarations to symbols before typechecking. --- src/jsil/jsil_convert.cpp | 11 +- src/jsil/jsil_internal_additions.cpp | 59 ++- src/jsil/jsil_language.cpp | 27 +- src/jsil/jsil_language.h | 1 + src/jsil/jsil_parse_tree.cpp | 2 +- src/jsil/jsil_parse_tree.h | 30 +- src/jsil/jsil_typecheck.cpp | 633 +++++++++++++++++---------- src/jsil/jsil_typecheck.h | 16 +- src/jsil/jsil_types.cpp | 394 ++++++++++++++--- src/jsil/jsil_types.h | 49 ++- src/jsil/parser.y | 9 +- 11 files changed, 860 insertions(+), 371 deletions(-) diff --git a/src/jsil/jsil_convert.cpp b/src/jsil/jsil_convert.cpp index bee5d0299b1..6142c929905 100644 --- a/src/jsil/jsil_convert.cpp +++ b/src/jsil/jsil_convert.cpp @@ -56,6 +56,14 @@ bool jsil_convertt::operator()(const jsil_parse_treet &parse_tree) if(convert_code(new_symbol, to_code(new_symbol.value))) return true; + if(symbol_table.has_symbol(new_symbol.name)) + { + symbolt &s=symbol_table.lookup(new_symbol.name); + if(s.value.id()=="no-body-just-yet") + { + symbol_table.remove(s.name); + } + } if(symbol_table.add(new_symbol)) { throw "duplicate symbol "+id2string(new_symbol.name); @@ -104,7 +112,8 @@ bool jsil_convertt::convert_code(const symbolt &symbol, codet &code) code_try_catcht t_c; t_c.try_code().swap(t); - code_declt d(symbol.symbol_expr()); + // Adding empty symbol to catch decl + code_declt d(symbol_exprt("decl_symbol")); t_c.add_catch(d, g); t_c.add_source_location()=code.source_location(); diff --git a/src/jsil/jsil_internal_additions.cpp b/src/jsil/jsil_internal_additions.cpp index c2906a6e979..9f583fbb56b 100644 --- a/src/jsil/jsil_internal_additions.cpp +++ b/src/jsil/jsil_internal_additions.cpp @@ -41,6 +41,8 @@ void jsil_internal_additions(symbol_tablet &dest) symbol.is_lvalue=true; symbol.is_state_var=true; symbol.is_thread_local=true; + // mark as already typechecked + symbol.is_extern=true; dest.add(symbol); } @@ -55,6 +57,8 @@ void jsil_internal_additions(symbol_tablet &dest) symbol.is_lvalue=true; symbol.is_state_var=true; symbol.is_thread_local=true; + // mark as already typechecked + symbol.is_extern=true; dest.add(symbol); } @@ -73,28 +77,57 @@ void jsil_internal_additions(symbol_tablet &dest) dest.add(symbol); } + // add nan + + { + symbolt symbol; + symbol.base_name="nan"; + symbol.name="nan"; + symbol.type=floatbv_typet(); + symbol.mode="jsil"; + // mark as already typechecked + symbol.is_extern=true; + dest.add(symbol); + } + + // add empty symbol used for decl statemements + + { + symbolt symbol; + symbol.base_name="decl_symbol"; + symbol.name="decl_symbol"; + symbol.type=empty_typet(); + symbol.mode="jsil"; + // mark as already typechecked + symbol.is_extern=true; + dest.add(symbol); + } + // add builtin objects const std::vector builtin_objects= - { "#lg", "#lg_isNan", "#lg_isFinite", "#lop", "#lop_toString", - "#lop_valueOf", "#lop_isPrototypeOf", "#lfunction", "#lfp", - "#leval", "#lerror", "#lep", "#lrerror", "#lrep", "#lterror", - "#ltep", "#lserror", "#lsep", "#levalerror", "#levalerrorp", - "#lrangeerror", "#lrangeerrorp", "#lurierror", "#lurierrorp", - "#lobject", "#lobject_get_prototype_of", "#lboolean", "#lbp", - "#lbp_toString", "#lbp_valueOf", "#lnumber", "#lnp", - "#lnp_toString", "#lnp_valueOf", "#lmath", "#lstring", "#lsp", - "#lsp_toString", "#lsp_valueOf", "#larray", "#lap", "#ljson" - }; - - for(const auto & identifier : builtin_objects) + { + "#lg", "#lg_isNan", "#lg_isFinite", "#lop", "#lop_toString", + "#lop_valueOf", "#lop_isPrototypeOf", "#lfunction", "#lfp", + "#leval", "#lerror", "#lep", "#lrerror", "#lrep", "#lterror", + "#ltep", "#lserror", "#lsep", "#levalerror", "#levalerrorp", + "#lrangeerror", "#lrangeerrorp", "#lurierror", "#lurierrorp", + "#lobject", "#lobject_get_prototype_of", "#lboolean", "#lbp", + "#lbp_toString", "#lbp_valueOf", "#lnumber", "#lnp", + "#lnp_toString", "#lnp_valueOf", "#lmath", "#lstring", "#lsp", + "#lsp_toString", "#lsp_valueOf", "#larray", "#lap", "#ljson" + }; + + for(const auto &identifier : builtin_objects) { symbolt new_symbol; new_symbol.name=identifier; - new_symbol.type=jsil_builtin_objectt(); + new_symbol.type=jsil_builtin_object_type(); new_symbol.base_name=identifier; new_symbol.mode="jsil"; new_symbol.is_type=false; new_symbol.is_lvalue=false; + // mark as already typechecked + new_symbol.is_extern=true; dest.add(new_symbol); } } diff --git a/src/jsil/jsil_language.cpp b/src/jsil/jsil_language.cpp index 844e49fe3b4..552073e4b77 100644 --- a/src/jsil/jsil_language.cpp +++ b/src/jsil/jsil_language.cpp @@ -56,6 +56,27 @@ void jsil_languaget::modules_provided(std::set &modules) /*******************************************************************\ +Function: jsil_languaget::interfaces + + Inputs: + + Outputs: + + Purpose: Adding symbols for all procedure declarations + +\*******************************************************************/ + +bool jsil_languaget::interfaces(symbol_tablet &symbol_table) +{ + if(jsil_convert(parse_tree, symbol_table, get_message_handler())) + return true; + + jsil_internal_additions(symbol_table); + return false; +} + +/*******************************************************************\ + Function: jsil_languaget::preprocess Inputs: @@ -128,12 +149,6 @@ bool jsil_languaget::typecheck( symbol_tablet &symbol_table, const std::string &module) { - if(jsil_convert(parse_tree, symbol_table, get_message_handler())) - return true; - - jsil_internal_additions(symbol_table); - - // now typecheck if(jsil_typecheck(symbol_table, get_message_handler())) return true; diff --git a/src/jsil/jsil_language.h b/src/jsil/jsil_language.h index 9604777a2c2..3b9f154fb4b 100644 --- a/src/jsil/jsil_language.h +++ b/src/jsil/jsil_language.h @@ -62,6 +62,7 @@ class jsil_languaget:public languaget virtual std::set extensions() const; virtual void modules_provided(std::set &modules); + virtual bool interfaces(symbol_tablet &symbol_table); protected: jsil_parse_treet parse_tree; diff --git a/src/jsil/jsil_parse_tree.cpp b/src/jsil/jsil_parse_tree.cpp index f6ec26084bf..874e36ccef6 100644 --- a/src/jsil/jsil_parse_tree.cpp +++ b/src/jsil/jsil_parse_tree.cpp @@ -73,7 +73,7 @@ void jsil_declarationt::to_symbol(symbolt &symbol) const irep_idt proc_type=s.get("proc_type"); if(proc_type=="builtin") - symbol_type=jsil_builtin_code_typet(symbol_type); + symbol_type=jsil_builtin_code_typet(symbol_type); else if(proc_type=="spec") symbol_type=jsil_spec_code_typet(symbol_type); diff --git a/src/jsil/jsil_parse_tree.h b/src/jsil/jsil_parse_tree.h index 8cf500f9300..201ffb15542 100644 --- a/src/jsil/jsil_parse_tree.h +++ b/src/jsil/jsil_parse_tree.h @@ -47,12 +47,14 @@ class jsil_declarationt:public exprt add(ID_return).set(ID_label, label); } - const irep_idt &returns_value() const { - return find(ID_return).get(ID_value); + const irep_idt &returns_value() const + { + return find(ID_return).get(ID_value); } - const irep_idt &returns_label() const { - return find(ID_return).get(ID_label); + const irep_idt &returns_label() const + { + return find(ID_return).get(ID_label); } void add_throws( @@ -63,12 +65,14 @@ class jsil_declarationt:public exprt add(ID_throw).set(ID_label, label); } - const irep_idt &throws_value() const { - return find(ID_throw).get(ID_value); + const irep_idt &throws_value() const + { + return find(ID_throw).get(ID_value); } - const irep_idt &throws_label() const { - return find(ID_throw).get(ID_label); + const irep_idt &throws_label() const + { + return find(ID_throw).get(ID_label); } void add_value(const code_blockt &code) @@ -76,12 +80,14 @@ class jsil_declarationt:public exprt add(ID_value, code); } - const code_blockt &value() const { - return static_cast (find(ID_value)); + const code_blockt &value() const + { + return static_cast(find(ID_value)); } - code_blockt &value() { - return static_cast (add(ID_value)); + code_blockt &value() + { + return static_cast(add(ID_value)); } void to_symbol(symbolt &symbol) const; diff --git a/src/jsil/jsil_typecheck.cpp b/src/jsil/jsil_typecheck.cpp index 419b2a99acb..ee251f93f93 100644 --- a/src/jsil/jsil_typecheck.cpp +++ b/src/jsil/jsil_typecheck.cpp @@ -8,6 +8,7 @@ Author: Michael Tautschnig, tautschn@amazon.com #include #include +#include #include "expr2jsil.h" #include "jsil_types.h" @@ -62,7 +63,7 @@ Function: jsil_typecheckt::add_prefix irep_idt jsil_typecheckt::add_prefix(const irep_idt &ds) { - return id2string(proc_name)+"::"+id2string(ds); + return id2string(proc_name) + "::" + id2string(ds); } /*******************************************************************\ @@ -76,20 +77,20 @@ Function: jsil_typecheckt::update_expr_type Purpose: \*******************************************************************/ + void jsil_typecheckt::update_expr_type(exprt &expr, const typet &type) { expr.type()=type; if(expr.id()==ID_symbol) { - symbol_exprt &sexpr=to_symbol_expr(expr); - const irep_idt &id=sexpr.get_identifier(); + const irep_idt &id=to_symbol_expr(expr).get_identifier(); if(!symbol_table.has_symbol(id)) - throw "Unexpected symbol "+id2string(id); + throw "Unexpected symbol: "+id2string(id); symbolt &s=symbol_table.lookup(id); - if(s.type.id_string().empty() || s.type.is_nil()) + if(s.type.id().empty() || s.type.is_nil()) s.type=type; else s.type=jsil_union(s.type, type); @@ -109,10 +110,17 @@ Function: jsil_typecheckt::make_type_compatible \*******************************************************************/ void jsil_typecheckt::make_type_compatible( - exprt &expr, - const typet &type, - bool must) + exprt &expr, + const typet &type, + bool must) { + if(type.id().empty() || type.is_nil()) + { + err_location(expr); + str << "make_type_compatible got empty type: " << expr.pretty(); + throw 0; + } + if(expr.type().id().empty() || expr.type().is_nil()) { // Type is not yet set @@ -122,21 +130,22 @@ void jsil_typecheckt::make_type_compatible( if(must) { - if(jsil_union_typet(expr.type()).intersect_with( - jsil_union_typet(type)).components().empty()) - throw "Failed to typecheck expr "+expr.pretty()+ - " with type "+expr.type().pretty()+"; required type "+ - type.pretty(); - } - else - { - if(!jsil_is_subtype(type, expr.type())) + if(jsil_incompatible_types(expr.type(), type)) { - // Types are not compatible - typet upper=jsil_union(expr.type(), type); - update_expr_type(expr, upper); + err_location(expr); + str << "failed to typecheck expr " + << expr.pretty() << " with type " + << expr.type().pretty() + << "; required type " << type.pretty(); + throw 0; } } + else if(!jsil_is_subtype(type, expr.type())) + { + // Types are not compatible + typet upper=jsil_union(expr.type(), type); + update_expr_type(expr, upper); + } } /*******************************************************************\ @@ -157,27 +166,34 @@ void jsil_typecheckt::typecheck_type(typet &type) { code_typet ¶meters=to_code_type(type); - for (code_typet::parametert& p : parameters.parameters()) + for(code_typet::parametert &p : parameters.parameters()) { - // create the symbol + // create new symbol parameter_symbolt new_symbol; new_symbol.base_name=p.get_identifier(); - // appending procedure name to parameters + + // append procedure name to parameters p.set_identifier(add_prefix(p.get_identifier())); new_symbol.name=p.get_identifier(); if(is_jsil_builtin_code_type(type)) - new_symbol.type=jsil_value_or_emptyt(); + new_symbol.type=jsil_value_or_empty_type(); else if(is_jsil_spec_code_type(type)) - new_symbol.type=jsil_value_or_referencet(); + new_symbol.type=jsil_value_or_reference_type(); else - // User defined function - new_symbol.type=jsil_valuet(); + new_symbol.type=jsil_value_type(); // User defined function new_symbol.mode="jsil"; + // mark as already typechecked + new_symbol.is_extern=true; + if(symbol_table.add(new_symbol)) - throw "failed to add parameter symbol"; + { + str << "failed to add parameter symbol `" + << new_symbol.name << "' in the symbol table"; + throw 0; + } } } } @@ -243,107 +259,136 @@ void jsil_typecheckt::typecheck_expr_main(exprt &expr) } else if(expr.id()==ID_symbol) typecheck_symbol_expr(to_symbol_expr (expr)); - else if(expr.id()==ID_side_effect) - typecheck_expr_side_effect(to_side_effect_expr(expr)); - else if(expr.id()==ID_constant || - expr.id()==ID_string_constant || - expr.id()==ID_null || - expr.id()=="undefined" || - expr.id()==ID_empty) - typecheck_expr_constant(expr); - else if(expr.id()=="null_type" || - expr.id()=="undefined_type" || - expr.id()==ID_boolean || - expr.id()==ID_string || - expr.id()=="number" || - expr.id()=="builtin_object" || - expr.id()=="user_object" || - expr.id()=="object" || - expr.id()==ID_reference || - expr.id()==ID_member || - expr.id()=="variable") - expr.type()=jsil_kindt(); - else if(expr.id()=="proto" || - expr.id()=="fid" || - expr.id()=="scope" || - expr.id()=="constructid" || - expr.id()=="primvalue" || - expr.id()=="targetfunction" || - expr.id()==ID_class) - { - // TODO: builtin fields -- do we want special field type? - expr.type()=string_typet(); - } - else if(expr.id()==ID_not) - typecheck_expr_unary_boolean(expr); - else if(expr.id()=="string_to_num") - typecheck_expr_unary_string(expr); - else if(expr.id()==ID_unary_minus || - expr.id()=="num_to_int32" || - expr.id()=="num_to_uint32" || - expr.id()==ID_bitnot) + else if(expr.id()==ID_constant) { - typecheck_expr_unary_num(expr); - expr.type() = floatbv_typet(); - } - else if(expr.id()=="num_to_string") - { - typecheck_expr_unary_num(expr); - expr.type() = string_typet(); - } - else if(expr.id()==ID_equal) - typecheck_exp_binary_equal(expr); - else if(expr.id()==ID_lt || - expr.id()==ID_le) - typecheck_expr_binary_compare(expr); - else if(expr.id()==ID_plus || - expr.id()==ID_minus || - expr.id()==ID_mult || - expr.id()==ID_div || - expr.id()==ID_mod) - typecheck_expr_binary_arith(expr); - else if(expr.id()==ID_and || - expr.id()==ID_or) - typecheck_expr_binary_boolean(expr); - else if(expr.id()=="subtype_of") - typecheck_expr_subtype(expr); - else if(expr.id()==ID_concatenation) - typecheck_expr_concatenation(expr); - else if(expr.id()=="ref") - typecheck_expr_ref(expr); - else if(expr.id()=="field") - typecheck_expr_field(expr); - else if(expr.id()==ID_base) - typecheck_expr_base(expr); - else if(expr.id()==ID_typeof) - expr.type()=jsil_kindt(); - else if(expr.id()=="new") - expr.type()=jsil_user_objectt(); - else if(expr.id()=="hasField") - typecheck_expr_has_field(expr); - else if(expr.id()==ID_index) - typecheck_expr_index(expr); - else if(expr.id()=="delete") - typecheck_expr_delete(expr); - else if(expr.id()=="protoField") - typecheck_expr_proto_field(expr); - else if(expr.id()=="protoObj") - typecheck_expr_proto_obj(expr); - else if(expr.is_nil()) - { - assert(false); } else { - err_location(expr); - str << "unexpected expression: " << expr.pretty(); - throw 0; + // expressions are expected not to have type set just yet + assert(expr.type().is_nil()||expr.type().id().empty()); + + if (expr.id()==ID_null || + expr.id()=="undefined" || + expr.id()==ID_empty) + typecheck_expr_constant(expr); + else if(expr.id()=="null_type" || + expr.id()=="undefined_type" || + expr.id()==ID_boolean || + expr.id()==ID_string || + expr.id()=="number" || + expr.id()=="builtin_object" || + expr.id()=="user_object" || + expr.id()=="object" || + expr.id()==ID_reference || + expr.id()==ID_member || + expr.id()=="variable") + expr.type()=jsil_kind(); + else if(expr.id()=="proto" || + expr.id()=="fid" || + expr.id()=="scope" || + expr.id()=="constructid" || + expr.id()=="primvalue" || + expr.id()=="targetfunction" || + expr.id()==ID_class) + { + // TODO: have a special type for builtin fields + expr.type()=string_typet(); + } + else if(expr.id()==ID_not) + typecheck_expr_unary_boolean(expr); + else if(expr.id()=="string_to_num") + typecheck_expr_unary_string(expr); + else if(expr.id()==ID_unary_minus || + expr.id()=="num_to_int32" || + expr.id()=="num_to_uint32" || + expr.id()==ID_bitnot) + { + typecheck_expr_unary_num(expr); + expr.type()=floatbv_typet(); + } + else if(expr.id()=="num_to_string") { + typecheck_expr_unary_num(expr); + expr.type()=string_typet(); + } + else if(expr.id()==ID_equal) + typecheck_exp_binary_equal(expr); + else if(expr.id()==ID_lt || + expr.id()==ID_le) + typecheck_expr_binary_compare(expr); + else if(expr.id()==ID_plus || + expr.id()==ID_minus || + expr.id()==ID_mult || + expr.id()==ID_div || + expr.id()==ID_mod || + expr.id()==ID_bitand || + expr.id()==ID_bitor || + expr.id()==ID_bitxor || + expr.id()==ID_shl || + expr.id()==ID_shr || + expr.id()==ID_lshr) + typecheck_expr_binary_arith(expr); + else if(expr.id()==ID_and || + expr.id()==ID_or) + typecheck_expr_binary_boolean(expr); + else if(expr.id()=="subtype_of") + typecheck_expr_subtype(expr); + else if(expr.id()==ID_concatenation) + typecheck_expr_concatenation(expr); + else if(expr.id()=="ref") + typecheck_expr_ref(expr); + else if(expr.id()=="field") + typecheck_expr_field(expr); + else if(expr.id()==ID_base) + typecheck_expr_base(expr); + else if(expr.id()==ID_typeof) + expr.type()=jsil_kind(); + else if(expr.id()=="new") + expr.type()=jsil_user_object_type(); + else if(expr.id()=="hasField") + typecheck_expr_has_field(expr); + else if(expr.id()==ID_index) + typecheck_expr_index(expr); + else if(expr.id()=="delete") + typecheck_expr_delete(expr); + else if(expr.id()=="protoField") + typecheck_expr_proto_field(expr); + else if(expr.id()=="protoObj") + typecheck_expr_proto_obj(expr); + else if(expr.id()==ID_side_effect) + typecheck_expr_side_effect_throw(to_side_effect_expr_throw(expr)); + else + { + err_location(expr); + str << "unexpected expression: " << expr.pretty(); + throw 0; + } } } /*******************************************************************\ -Function: jsil_typecheck_baset::typecheck_expr_constant +Function: jsil_typecheckt::typecheck_expr_side_effect_throw + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_expr_side_effect_throw( + side_effect_expr_throwt &expr) +{ + irept &excep_list=expr.add(ID_exception_list); + assert(excep_list.id()==ID_symbol); + symbol_exprt &s=static_cast(excep_list); + typecheck_symbol_expr(s); +} + +/*******************************************************************\ + +Function: jsil_typecheckt::typecheck_expr_constant Inputs: @@ -355,15 +400,12 @@ Function: jsil_typecheck_baset::typecheck_expr_constant void jsil_typecheckt::typecheck_expr_constant(exprt &expr) { - // no need to typecheck ID_constant - // TODO: make compatible with string_typet - // (expr.id()==ID_string_constant) if(expr.id()==ID_null) - expr.type()=jsil_nullt(); + expr.type()=jsil_null_type(); else if(expr.id()=="undefined") - expr.type()=jsil_undefinedt(); + expr.type()=jsil_undefined_type(); else if(expr.id()==ID_empty) - expr.type()=empty_typet(); + expr.type()=jsil_empty_type(); } /*******************************************************************\ @@ -387,13 +429,10 @@ void jsil_typecheckt::typecheck_expr_proto_field(exprt &expr) throw 0; } - exprt &operand1=expr.op0(); - make_type_compatible(operand1, jsil_objectt(), true); - - exprt &operand2=expr.op1(); - make_type_compatible(operand2, string_typet(), true); + make_type_compatible(expr.op0(), jsil_object_type(), true); + make_type_compatible(expr.op1(), string_typet(), true); - expr.type()=jsil_value_or_emptyt(); + expr.type()=jsil_value_or_empty_type(); } /*******************************************************************\ @@ -417,11 +456,8 @@ void jsil_typecheckt::typecheck_expr_proto_obj(exprt &expr) throw 0; } - exprt &operand1=expr.op0(); - make_type_compatible(operand1, jsil_objectt(), true); - - exprt &operand2=expr.op1(); - make_type_compatible(operand2, jsil_objectt(), true); + make_type_compatible(expr.op0(), jsil_object_type(), true); + make_type_compatible(expr.op1(), jsil_object_type(), true); expr.type()=bool_typet(); } @@ -447,11 +483,8 @@ void jsil_typecheckt::typecheck_expr_delete(exprt &expr) throw 0; } - exprt &operand1=expr.op0(); - make_type_compatible(operand1, jsil_objectt(), true); - - exprt &operand2=expr.op1(); - make_type_compatible(operand2, string_typet(), true); + make_type_compatible(expr.op0(), jsil_object_type(), true); + make_type_compatible(expr.op1(), string_typet(), true); expr.type()=bool_typet(); } @@ -477,13 +510,14 @@ void jsil_typecheckt::typecheck_expr_index(exprt &expr) throw 0; } - exprt &operand1=expr.op0(); - make_type_compatible(operand1, jsil_objectt(), true); + make_type_compatible(expr.op0(), jsil_object_type(), true); + make_type_compatible(expr.op1(), string_typet(), true); - exprt &operand2=expr.op1(); - make_type_compatible(operand2, string_typet(), true); - - expr.type()=jsil_valuet(); + // special case for function identifiers + if (expr.op1().id()=="fid" || expr.op1().id()=="constructid") + expr.type()=code_typet(); + else + expr.type()=jsil_value_type(); } /*******************************************************************\ @@ -507,11 +541,8 @@ void jsil_typecheckt::typecheck_expr_has_field(exprt &expr) throw 0; } - exprt &operand1=expr.op0(); - make_type_compatible(operand1, jsil_objectt(), true); - - exprt &operand2=expr.op1(); - make_type_compatible(operand2, string_typet(), true); + make_type_compatible(expr.op0(), jsil_object_type(), true); + make_type_compatible(expr.op1(), string_typet(), true); expr.type()=bool_typet(); } @@ -537,8 +568,7 @@ void jsil_typecheckt::typecheck_expr_field(exprt &expr) throw 0; } - exprt &operand1=expr.op0(); - make_type_compatible(operand1, jsil_referencet(), true); + make_type_compatible(expr.op0(), jsil_reference_type(), true); expr.type()=string_typet(); } @@ -564,11 +594,9 @@ void jsil_typecheckt::typecheck_expr_base(exprt &expr) throw 0; } - exprt &operand1=expr.op0(); - make_type_compatible(operand1, jsil_referencet(), true); + make_type_compatible(expr.op0(), jsil_reference_type(), true); - // TODO: can we be more precise here we know something more about op0? - expr.type()=jsil_valuet(); + expr.type()=jsil_value_type(); } /*******************************************************************\ @@ -592,24 +620,22 @@ void jsil_typecheckt::typecheck_expr_ref(exprt &expr) throw 0; } - exprt &operand1=expr.op0(); - make_type_compatible(operand1, jsil_valuet(), true); - exprt &operand2=expr.op1(); - // TODO: do we want a new field type? since we have built-in fields - make_type_compatible(operand2, string_typet(), true); + make_type_compatible(expr.op0(), jsil_value_type(), true); + make_type_compatible(expr.op1(), string_typet(), true); + exprt &operand3=expr.op2(); - make_type_compatible(operand3, jsil_kindt(), true); + make_type_compatible(operand3, jsil_kind(), true); if(operand3.id()==ID_member) - expr.type()=jsil_member_referencet(); + expr.type()=jsil_member_reference_type(); else if(operand3.id()=="variable") - expr.type()=jsil_variable_referencet(); + expr.type()=jsil_variable_reference_type(); else { err_location(expr); str << "operator `" << expr.id() - << "' expects reference type in the third parameter. But got:" - << operand3.pretty(); + << "' expects reference type in the third parameter. Got:" + << operand3.pretty(); throw 0; } } @@ -635,10 +661,8 @@ void jsil_typecheckt::typecheck_expr_concatenation(exprt &expr) throw 0; } - exprt &operand1=expr.op0(); - make_type_compatible(operand1, string_typet(), true); - exprt &operand2=expr.op1(); - make_type_compatible(operand2, string_typet(), true); + make_type_compatible(expr.op0(), string_typet(), true); + make_type_compatible(expr.op1(), string_typet(), true); expr.type()=string_typet(); } @@ -664,10 +688,8 @@ void jsil_typecheckt::typecheck_expr_subtype(exprt &expr) throw 0; } - exprt &operand1=expr.op0(); - make_type_compatible(operand1, jsil_kindt(), true); - exprt &operand2=expr.op1(); - make_type_compatible(operand2, jsil_kindt(), true); + make_type_compatible(expr.op0(), jsil_kind(), true); + make_type_compatible(expr.op1(), jsil_kind(), true); expr.type()=bool_typet(); } @@ -693,10 +715,8 @@ void jsil_typecheckt::typecheck_expr_binary_boolean(exprt &expr) throw 0; } - exprt &operand1=expr.op0(); - make_type_compatible(operand1, bool_typet(), true); - exprt &operand2=expr.op1(); - make_type_compatible(operand2, bool_typet(), true); + make_type_compatible(expr.op0(), bool_typet(), true); + make_type_compatible(expr.op1(), bool_typet(), true); expr.type()=bool_typet(); } @@ -722,10 +742,9 @@ void jsil_typecheckt::typecheck_expr_binary_arith(exprt &expr) throw 0; } - exprt &operand1=expr.op0(); - make_type_compatible(operand1, floatbv_typet(), true); - exprt &operand2=expr.op1(); - make_type_compatible(operand2, floatbv_typet(), true); + + make_type_compatible(expr.op0(), floatbv_typet(), true); + make_type_compatible(expr.op1(), floatbv_typet(), true); expr.type()=floatbv_typet(); } @@ -777,10 +796,8 @@ void jsil_typecheckt::typecheck_expr_binary_compare(exprt &expr) throw 0; } - exprt &operand1=expr.op0(); - make_type_compatible(operand1, floatbv_typet(), true); - exprt &operand2=expr.op1(); - make_type_compatible(operand2, floatbv_typet(), true); + make_type_compatible(expr.op0(), floatbv_typet(), true); + make_type_compatible(expr.op1(), floatbv_typet(), true); expr.type()=bool_typet(); } @@ -806,8 +823,7 @@ void jsil_typecheckt::typecheck_expr_unary_boolean(exprt &expr) throw 0; } - exprt &operand=expr.op0(); - make_type_compatible(operand, bool_typet(), true); + make_type_compatible(expr.op0(), bool_typet(), true); expr.type()=bool_typet(); } @@ -829,13 +845,11 @@ void jsil_typecheckt::typecheck_expr_unary_string(exprt &expr) if(expr.operands().size()!=1) { err_location(expr); - str << "operator `" << expr.id() - << "' expects one operand"; + str << "operator `" << expr.id() << "' expects one operand"; throw 0; } - exprt &operand=expr.op0(); - make_type_compatible(operand, string_typet(), true); + make_type_compatible(expr.op0(), string_typet(), true); expr.type()=floatbv_typet(); } @@ -861,8 +875,7 @@ void jsil_typecheckt::typecheck_expr_unary_num(exprt &expr) throw 0; } - exprt &operand=expr.op0(); - make_type_compatible(operand, floatbv_typet(), true); + make_type_compatible(expr.op0(), floatbv_typet(), true); } /*******************************************************************\ @@ -881,21 +894,32 @@ void jsil_typecheckt::typecheck_symbol_expr(symbol_exprt &symbol_expr) { irep_idt identifier=symbol_expr.get_identifier(); - // if it is another identifier, such as #lop, #builtin-fid - // check if it is in the table and add it's type - if(has_prefix(id2string(identifier), "#")) + // if this is a built-in identifier, check if it exists in the + // symbol table and retrieve it's type + // TODO: add a flag for not needing to prefix internal symbols + // that do not start with hash + if(has_prefix(id2string(identifier), "#") || + identifier=="eval" || + identifier=="nan") { - // does it exist already in the symbol table? symbol_tablet::symbolst::const_iterator s_it= symbol_table.symbols.find(identifier); if(s_it==symbol_table.symbols.end()) - throw "Unexpected internal symbol: "+id2string(identifier); + throw "unexpected internal symbol: "+id2string(identifier); + else + { + // symbol already exists + const symbolt &symbol=s_it->second; + + // type the expression + symbol_expr.type()=symbol.type; + } } else { - // if it is a variable, we need to check if we already prefixed it - // and add to the table if it is not there already + // if this is a variable, we need to check if we already + // prefixed it and add to the symbol table if it is not there already irep_idt identifier_base = identifier; if(!has_prefix(id2string(identifier), id2string(proc_name))) { @@ -903,27 +927,29 @@ void jsil_typecheckt::typecheck_symbol_expr(symbol_exprt &symbol_expr) symbol_expr.set_identifier(identifier); } - // does it exist already in the symbol table? symbol_tablet::symbolst::const_iterator s_it= - symbol_table.symbols.find(identifier); + symbol_table.symbols.find(identifier); if(s_it==symbol_table.symbols.end()) { - // no, create the symbol + // create new symbol symbolt new_symbol; new_symbol.name=identifier; new_symbol.type=symbol_expr.type(); new_symbol.base_name=identifier_base; new_symbol.mode="jsil"; new_symbol.is_type=false; + new_symbol.is_lvalue=new_symbol.type.id()!=ID_code; - if(new_symbol.type.id()==ID_code) - new_symbol.is_lvalue=false; - else - new_symbol.is_lvalue=true; + // mark as already typechecked + new_symbol.is_extern=true; if(symbol_table.add(new_symbol)) - throw "failed to add expression symbol to symbol table"; + { + str << "failed to add symbol `" + << new_symbol.name << "' in the symbol table"; + throw 0; + } } else { @@ -956,19 +982,18 @@ void jsil_typecheckt::typecheck_code(codet &code) if(statement==ID_function_call) typecheck_function_call(to_code_function_call(code)); - if(statement==ID_decl) - typecheck_decl(to_code_decl(code)); else if(statement==ID_return) - typecheck_return(code); + typecheck_return(to_code_return(code)); else if(statement==ID_expression) { if(code.operands().size()!=1) throw "expression statement expected to have one operand"; - exprt &op=code.op0(); - typecheck_expr(op); + + typecheck_expr(code.op0()); } else if(statement==ID_label) { + typecheck_code(to_code_label(code).code()); // TODO: produce defined label set } else if(statement==ID_block) @@ -980,7 +1005,7 @@ void jsil_typecheckt::typecheck_code(codet &code) // TODO: produce used label set } else if(statement==ID_assign) - typecheck_assign(code); + typecheck_assign(to_code_assign(code)); else if(statement==ID_try_catch) typecheck_try_catch(to_code_try_catch(code)); else if(statement==ID_skip) @@ -996,6 +1021,24 @@ void jsil_typecheckt::typecheck_code(codet &code) /*******************************************************************\ +Function: jsil_typecheckt::typecheck_return + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_return(code_returnt &code) +{ + if(code.has_return_value()) + typecheck_expr(code.return_value()); +} + +/*******************************************************************\ + Function: jsil_typecheckt::typecheck_block Inputs: @@ -1030,17 +1073,117 @@ void jsil_typecheckt::typecheck_try_catch(code_try_catcht &code) if(code.operands().size()!=3) throw "try_catch expected to have three operands"; - codet &try_code=code.try_code(); // function call - typecheck_function_call(to_code_function_call(try_code)); + typecheck_function_call(to_code_function_call(code.try_code())); - code_declt &decl_code=code.get_catch_decl(0); - typecheck_decl(decl_code); + // catch decl is not used, but is required by goto-programs - codet &catch_code=code.get_catch_code(0); - typecheck_code(catch_code); + typecheck_code(code.get_catch_code(0)); } +/*******************************************************************\ + +Function: jsil_typecheckt::typecheck_function_call + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void jsil_typecheckt::typecheck_function_call( + code_function_callt &call) +{ + if(call.operands().size()!=3) + throw "function call expected to have three operands"; + + exprt &lhs=call.lhs(); + typecheck_expr(lhs); + + exprt &f=call.function(); + typecheck_expr(f); + + for(auto &arg : call.arguments()) + typecheck_expr(arg); + + // Look for a function declaration symbol in the symbol table + if(f.id()==ID_symbol) + { + const irep_idt &id=to_symbol_expr(f).get_identifier(); + + if(symbol_table.has_symbol(id)) + { + symbolt &s=symbol_table.lookup(id); + + if(s.type.id()==ID_code) + { + code_typet &codet=to_code_type(s.type); + + for (int i=0; i=call.arguments().size()) break; + + const typet ¶m_type=codet.parameters()[i].type(); + + if(!param_type.id().empty() && param_type.is_not_nil()) + { + // check argument's type if parameter's type is given + make_type_compatible(call.arguments()[i], param_type, true); + } + } + + // if there are too few arguments, add undefined + if(codet.parameters().size()>call.arguments().size()) + { + for(int i=call.arguments().size(); + i #include -#include "jsil_parse_tree.h" +#include + class codet; @@ -33,7 +34,7 @@ class jsil_typecheckt:public legacy_typecheckt legacy_typecheckt(_message_handler), symbol_table(_symbol_table), ns(symbol_table), - proc_name("") + proc_name() { } @@ -53,7 +54,7 @@ class jsil_typecheckt:public legacy_typecheckt void typecheck_type_symbol(symbolt &symbol) {}; void typecheck_non_type_symbol(symbolt &symbol); void typecheck_symbol_expr(symbol_exprt &symbol_expr); - void typecheck_expr_side_effect(side_effect_exprt &expr) {}; + void typecheck_expr_side_effect_throw(side_effect_expr_throwt &expr); void typecheck_expr_delete(exprt &expr); void typecheck_expr_index(exprt &expr); void typecheck_expr_proto_field(exprt &expr); @@ -75,15 +76,14 @@ class jsil_typecheckt:public legacy_typecheckt void typecheck_expr_operands(exprt &expr); void typecheck_expr_main(exprt &expr); void typecheck_code(codet &code); - void typecheck_function_call(code_function_callt &code) {}; - void typecheck_decl(code_declt &code) {}; - void typecheck_return(codet &code) {}; + void typecheck_function_call(code_function_callt &function_call); + void typecheck_return(code_returnt &code); void typecheck_block(codet &code); void typecheck_ifthenelse(code_ifthenelset &code); - void typecheck_assign(codet &code); + void typecheck_assign(code_assignt &code); void typecheck_try_catch (code_try_catcht &code); void typecheck_type(typet &type); - dstring add_prefix(const dstring &ds); + irep_idt add_prefix(const irep_idt &ds); // overload to use language-specific syntax virtual std::string to_string(const exprt &expr); diff --git a/src/jsil/jsil_types.cpp b/src/jsil/jsil_types.cpp index d6ba6cfa499..c9d96f4d64b 100644 --- a/src/jsil/jsil_types.cpp +++ b/src/jsil/jsil_types.cpp @@ -6,44 +6,106 @@ Author: Daiva Naudziuniene, daivan@amazon.com \*******************************************************************/ +#include + #include "jsil_types.h" -typet jsil_any_typet() +/*******************************************************************\ + +Function: jsil_any_type + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +typet jsil_any_type() { return jsil_union_typet({ - empty_typet(), - jsil_referencet(), - jsil_valuet() + jsil_empty_type(), + jsil_reference_type(), + jsil_value_type() }); } -typet jsil_value_or_emptyt() +/*******************************************************************\ + +Function: jsil_value_or_empty_type + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +typet jsil_value_or_empty_type() { return jsil_union_typet({ - jsil_valuet(), - empty_typet() + jsil_value_type(), + jsil_empty_type() }); } -typet jsil_value_or_referencet() +/*******************************************************************\ + +Function: jsil_value_or_reference_type + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +typet jsil_value_or_reference_type() { return jsil_union_typet({ - jsil_valuet(), - jsil_referencet() + jsil_value_type(), + jsil_reference_type() }); } -typet jsil_valuet() +/*******************************************************************\ + +Function: jsil_value_type + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +typet jsil_value_type() { return jsil_union_typet({ - jsil_undefinedt(), - jsil_nullt(), - jsil_prim_typet(), - jsil_objectt() + jsil_undefined_type(), + jsil_null_type(), + jsil_prim_type(), + jsil_object_type() }); } -typet jsil_prim_typet() +/*******************************************************************\ + +Function: jsil_prim_type + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +typet jsil_prim_type() { return jsil_union_typet({ floatbv_typet(), @@ -52,58 +114,185 @@ typet jsil_prim_typet() }); } -typet jsil_referencet() { +/*******************************************************************\ + +Function: jsil_reference_type + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +typet jsil_reference_type() +{ return jsil_union_typet({ - jsil_member_referencet(), - jsil_variable_referencet() + jsil_member_reference_type(), + jsil_variable_reference_type() }); } -typet jsil_member_referencet() +/*******************************************************************\ + +Function: jsil_member_reference_type + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +typet jsil_member_reference_type() { - return typet("jsil_member_referencet"); + return typet("jsil_member_reference_type"); } -typet jsil_variable_referencet() +/*******************************************************************\ + +Function: jsil_variable_reference_type + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +typet jsil_variable_reference_type() { - return typet("jsil_variable_referencet"); + return typet("jsil_variable_reference_type"); } -typet jsil_objectt() { +/*******************************************************************\ + +Function: jsil_object_type + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +typet jsil_object_type() +{ return jsil_union_typet({ - jsil_user_objectt(), - jsil_builtin_objectt() + jsil_user_object_type(), + jsil_builtin_object_type() }); } -typet jsil_user_objectt() +/*******************************************************************\ + +Function: jsil_user_object_type + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +typet jsil_user_object_type() +{ + return typet("jsil_user_object_type"); +} + +/*******************************************************************\ + +Function: jsil_builtin_object_type + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +typet jsil_builtin_object_type() { - return typet("jsil_user_objectt"); + return typet("jsil_builtin_object_type"); } -typet jsil_builtin_objectt() +/*******************************************************************\ + +Function: jsil_null_type + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +typet jsil_null_type() { - return typet("jsil_builtin_objectt"); + return typet("jsil_null_type"); } -typet jsil_nullt() +/*******************************************************************\ + +Function: jsil_undefined_type + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +typet jsil_undefined_type() { - return typet("jsil_nullt"); + return typet("jsil_undefined_type"); } -typet jsil_undefinedt() +/*******************************************************************\ + +Function: jsil_kind + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +typet jsil_kind() { - return typet("jsil_undefinedt"); + return typet("jsil_kind"); } -typet jsil_kindt() +/*******************************************************************\ + +Function: jsil_empty_type + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +typet jsil_empty_type() { - return typet("jsil_kindt"); + return typet("jsil_empty_type"); } /*******************************************************************\ -Function: jsil_upper_bound_type +Function: jsil_is_subtype Inputs: @@ -118,34 +307,85 @@ bool jsil_is_subtype(const typet &type1, const typet &type2) if(type2.id()==ID_union) { const jsil_union_typet &type2_union=to_jsil_union_type(type2); + if(type1.id()==ID_union) - { return to_jsil_union_type(type1).is_subtype(type2_union); - } else - { - return (jsil_union_typet(type1).is_subtype(type2_union)); - } + return jsil_union_typet(type1).is_subtype(type2_union); } else return type1.id()==type2.id(); } +/*******************************************************************\ + +Function: jsil_incompatible_types + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool jsil_incompatible_types(const typet &type1, const typet &type2) +{ + return jsil_union_typet(type1).intersect_with( + jsil_union_typet(type2)).components().empty(); +} + +/*******************************************************************\ + +Function: jsil_union + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + typet jsil_union(const typet &type1, const typet &type2) { - return jsil_union_typet(type1).union_with( - jsil_union_typet(type2)).to_type(); + return jsil_union_typet(type1) + .union_with(jsil_union_typet(type2)).to_type(); } +/*******************************************************************\ + +Function: compare_components + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + bool compare_components( const union_typet::componentt &comp1, const union_typet::componentt &comp2) { - return comp1.type().id().get_no() < comp2.type().id().get_no(); + return comp1.type().id() &types):union_typet() +/*******************************************************************\ + +Function: jsil_union_typet::jsil_union_typet + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +jsil_union_typet::jsil_union_typet(const std::vector &types): + union_typet() { auto &elements=components(); for(const auto &type : types) @@ -153,9 +393,7 @@ jsil_union_typet::jsil_union_typet( if(type.id()==ID_union) { for(const auto &component : to_union_type(type).components()) - { elements.push_back(component); - } } else elements.push_back(componentt(ID_anonymous, type)); @@ -177,17 +415,19 @@ Function: jsil_union_typet::union_with \*******************************************************************/ jsil_union_typet jsil_union_typet::union_with( - const jsil_union_typet &other) const + const jsil_union_typet &other) const { - auto &elements1 = components(); - auto &elements2 = other.components(); + auto &elements1=components(); + auto &elements2=other.components(); jsil_union_typet result; - auto &elements = result.components(); + auto &elements=result.components(); elements.resize(elements1.size()+elements2.size()); std::vector::iterator it=std::set_union( - elements1.begin(), elements1.end(), elements2.begin(), elements2.end(), - elements.begin(), compare_components); + elements1.begin(), elements1.end(), + elements2.begin(), elements2.end(), + elements.begin(), compare_components); elements.resize(it-elements.begin()); + return result; } @@ -202,9 +442,8 @@ Function: jsil_union_typet::intersect_with Purpose: \*******************************************************************/ - jsil_union_typet jsil_union_typet::intersect_with( - const jsil_union_typet &other) const + const jsil_union_typet &other) const { auto &elements1=components(); auto &elements2=other.components(); @@ -212,7 +451,8 @@ jsil_union_typet jsil_union_typet::intersect_with( auto &elements=result.components(); elements.resize(std::min(elements1.size(),elements2.size())); std::vector::iterator it=std::set_intersection( - elements1.begin(), elements1.end(), elements2.begin(), elements2.end(), + elements1.begin(), elements1.end(), + elements2.begin(), elements2.end(), elements.begin(), compare_components); elements.resize(it-elements.begin()); @@ -233,15 +473,35 @@ Function: jsil_union_typet::is_subtype bool jsil_union_typet::is_subtype(const jsil_union_typet &other) const { - auto &elements1=components(); - auto &elements2=other.components(); - std::vector diff(elements1.size()); - std::vector::iterator it=std::set_difference( - elements1.begin(), elements1.end(), elements2.begin(), elements2.end(), - diff.begin(), compare_components); - diff.resize(it-diff.begin()); + auto it=components().begin(); + auto it2=other.components().begin(); + while(it=other.components().end()) + { + // We haven't found all types, but the second array finishes + return false; + } + + if(it->type().id()==it2->type().id()) + { + // Found the type + it++; + it2++; + } + else if(it->type().id()type().id()) + { + // Missing type + return false; + } + else // it->type().id()>it2->type().id() + { + // Skip one element in the second array + it2++; + } + } - return diff.empty(); + return true; } /*******************************************************************\ @@ -259,7 +519,7 @@ Function: jsil_union_typet::to_type() const typet& jsil_union_typet::to_type() const { auto &elements=components(); - if (elements.size()==1) + if(elements.size()==1) return elements[0].type(); return *this; diff --git a/src/jsil/jsil_types.h b/src/jsil/jsil_types.h index d8cb1043fb7..57950ef340e 100644 --- a/src/jsil/jsil_types.h +++ b/src/jsil/jsil_types.h @@ -12,34 +12,38 @@ Author: Daiva Naudziuniene, daivan@amazon.com #include #include -typet jsil_kindt(); -typet jsil_any_typet(); -typet jsil_value_or_emptyt(); -typet jsil_value_or_referencet(); -typet jsil_valuet(); -typet jsil_prim_typet(); -typet jsil_referencet(); -typet jsil_member_referencet(); -typet jsil_variable_referencet(); -typet jsil_objectt(); -typet jsil_user_objectt(); -typet jsil_builtin_objectt(); -typet jsil_nullt(); -typet jsil_undefinedt(); +typet jsil_kind(); +typet jsil_any_type(); +typet jsil_value_or_empty_type(); +typet jsil_value_or_reference_type(); +typet jsil_value_type(); +typet jsil_prim_type(); +typet jsil_reference_type(); +typet jsil_member_reference_type(); +typet jsil_variable_reference_type(); +typet jsil_object_type(); +typet jsil_user_object_type(); +typet jsil_builtin_object_type(); +typet jsil_null_type(); +typet jsil_undefined_type(); +typet jsil_empty_type(); bool jsil_is_subtype(const typet &type1, const typet &type2); +bool jsil_incompatible_types(const typet &type1, const typet &type2); typet jsil_union(const typet &type1, const typet &type2); class jsil_builtin_code_typet:public code_typet { public: - inline jsil_builtin_code_typet(code_typet &code):code_typet(code) + explicit inline jsil_builtin_code_typet(code_typet &code): + code_typet(code) { set("jsil_builtin_proceduret", true); } }; -extern inline jsil_builtin_code_typet &to_jsil_builtin_code_type(code_typet &code) +extern inline jsil_builtin_code_typet &to_jsil_builtin_code_type( + code_typet &code) { assert(code.get_bool("jsil_builtin_proceduret")); return static_cast(code); @@ -54,13 +58,15 @@ extern inline bool is_jsil_builtin_code_type(const typet &type) class jsil_spec_code_typet:public code_typet { public: - inline jsil_spec_code_typet(code_typet &code):code_typet(code) + explicit inline jsil_spec_code_typet(code_typet &code): + code_typet(code) { set("jsil_spec_proceduret", true); } }; -extern inline jsil_spec_code_typet &to_jsil_spec_code_type(code_typet &code) +extern inline jsil_spec_code_typet &to_jsil_spec_code_type( + code_typet &code) { assert(code.get_bool("jsil_spec_proceduret")); return static_cast(code); @@ -77,10 +83,10 @@ class jsil_union_typet:public union_typet public: inline jsil_union_typet():union_typet() { } - inline jsil_union_typet(const typet &type) + explicit inline jsil_union_typet(const typet &type) :jsil_union_typet(std::vector({type})) { } - jsil_union_typet(const std::vector &types); + explicit jsil_union_typet(const std::vector &types); jsil_union_typet union_with(const jsil_union_typet &other) const; @@ -97,7 +103,8 @@ extern inline jsil_union_typet &to_jsil_union_type(typet &type) return static_cast(type); } -extern inline const jsil_union_typet &to_jsil_union_type(const typet &type) +extern inline const jsil_union_typet &to_jsil_union_type( + const typet &type) { assert(type.id()==ID_union); return static_cast(type); diff --git a/src/jsil/parser.y b/src/jsil/parser.y index 02a5b0e7aa2..9581c944e9d 100644 --- a/src/jsil/parser.y +++ b/src/jsil/parser.y @@ -423,6 +423,11 @@ literal: TOK_IDENTIFIER } | TOK_FLOATING | TOK_STRING + { + constant_exprt c(to_string_constant(stack($$)) + .get_value(), string_typet()); + stack($$).swap(c); + } | TOK_BUILTIN_LOC | jsil_type | builtin_field @@ -524,11 +529,11 @@ bitwise_op: '&' } | '|' { - newstack($$).id(ID_or); + newstack($$).id(ID_bitor); } | '^' { - newstack($$).id(ID_xor); + newstack($$).id(ID_bitxor); } | TOK_LEFT_SHIFT { From e9b1c21bc9b134465fe9e7baa4910bda80d50f72 Mon Sep 17 00:00:00 2001 From: Daiva Naudziuniene Date: Mon, 16 May 2016 23:21:04 +0000 Subject: [PATCH 020/101] Added jsil mode to be supported by goto_convert_functions --- src/goto-programs/goto_convert_functions.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/goto-programs/goto_convert_functions.cpp b/src/goto-programs/goto_convert_functions.cpp index 128c125b649..85d85ecc5d1 100644 --- a/src/goto-programs/goto_convert_functions.cpp +++ b/src/goto-programs/goto_convert_functions.cpp @@ -80,7 +80,8 @@ void goto_convert_functionst::goto_convert() it->second.type.id()==ID_code && (it->second.mode==ID_C || it->second.mode==ID_cpp || - it->second.mode==ID_java)) + it->second.mode==ID_java || + it->second.mode=="jsil")) symbol_list.push_back(it->first); } From 5435ed579ca523f38718b435fb5a41fd02491c31 Mon Sep 17 00:00:00 2001 From: Daiva Naudziuniene Date: Mon, 16 May 2016 23:21:28 +0000 Subject: [PATCH 021/101] Modified taint analysis to match procedure calls from languages other than Java --- src/goto-analyzer/taint_analysis.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/goto-analyzer/taint_analysis.cpp b/src/goto-analyzer/taint_analysis.cpp index 22ece7b9950..444624851df 100644 --- a/src/goto-analyzer/taint_analysis.cpp +++ b/src/goto-analyzer/taint_analysis.cpp @@ -134,7 +134,8 @@ void taint_analysist::instrument( { bool match=false; for(const auto & i : identifiers) - if(has_prefix(id2string(i), "java::"+id2string(rule.function_identifier)+":")) + if(has_prefix(id2string(i), "java::"+id2string(rule.function_identifier)+":") || + id2string(i)==id2string(rule.function_identifier)) { match=true; break; From 0066b669f373c244b6eed938de1852acc082a66c Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Fri, 11 Mar 2016 13:45:07 +0000 Subject: [PATCH 022/101] goto-gcc: stop early on errors, minor cleanup --- src/goto-cc/gcc_mode.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/goto-cc/gcc_mode.cpp b/src/goto-cc/gcc_mode.cpp index c08eddb59fc..10ba45a451b 100644 --- a/src/goto-cc/gcc_mode.cpp +++ b/src/goto-cc/gcc_mode.cpp @@ -392,7 +392,7 @@ bool gcc_modet::doit() // We can generate hybrid ELF and Mach-O binaries // containing both executable machine code and the goto-binary. - if(produce_hybrid_binary) + if(!result && produce_hybrid_binary) { if(gcc_hybrid_binary()) result=true; @@ -477,9 +477,11 @@ int gcc_modet::preprocess( // source file new_argv.push_back(src); + const char *compiler=compiler_name(); + // overwrite argv[0] assert(new_argv.size()>=1); - new_argv[0]=compiler_name(); + new_argv[0]=compiler; #if 0 std::cout << "RUN:"; @@ -488,7 +490,7 @@ int gcc_modet::preprocess( std::cout << std::endl; #endif - return run(compiler_name(), new_argv); + return run(compiler, new_argv); } /*******************************************************************\ @@ -656,7 +658,7 @@ int gcc_modet::gcc_hybrid_binary() // using objcopy for(std::list::const_iterator it=output_files.begin(); - it!=output_files.end(); + result==0 && it!=output_files.end(); it++) { debug() << "merging " << *it << eom; @@ -672,7 +674,8 @@ int gcc_modet::gcc_hybrid_binary() objcopy_argv.push_back("--remove-section=goto-cc"); objcopy_argv.push_back(*it); - run(objcopy_argv[0], objcopy_argv); + result=run(objcopy_argv[0], objcopy_argv); + if(result!=0) break; } // now add goto-binary as goto-cc section @@ -683,7 +686,7 @@ int gcc_modet::gcc_hybrid_binary() objcopy_argv.push_back("goto-cc="+saved); objcopy_argv.push_back(*it); - run(objcopy_argv[0], objcopy_argv); + result=run(objcopy_argv[0], objcopy_argv); remove(saved.c_str()); #elif defined(__APPLE__) @@ -700,7 +703,7 @@ int gcc_modet::gcc_hybrid_binary() lipo_argv.push_back("-output"); lipo_argv.push_back(*it); - run(lipo_argv[0], lipo_argv); + result=run(lipo_argv[0], lipo_argv); remove(saved.c_str()); From 0c09ec079020a4e15ae5feea1857925d951d1b92 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Fri, 11 Mar 2016 13:46:01 +0000 Subject: [PATCH 023/101] Extend goto-gcc to also work as a wrapper for more compiler names Supports, e.g., x86_64-apple-darwin14-llvm-gcc-4.2 when invoked as x86_64-apple-darwin14-llvm-goto-gcc-4.2 cr https://cr.amazon.com/r/4975025/ --- src/goto-cc/gcc_mode.h | 30 ++++++++++++++++++++++++------ src/goto-cc/goto_cc_main.cpp | 7 ++++++- src/util/get_base_name.cpp | 5 ++++- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/goto-cc/gcc_mode.h b/src/goto-cc/gcc_mode.h index a1df04cf6eb..b094fe51af6 100644 --- a/src/goto-cc/gcc_mode.h +++ b/src/goto-cc/gcc_mode.h @@ -31,6 +31,7 @@ class gcc_modet:public goto_cc_modet protected: bool act_as_ld; + std::string native_compiler_name; int preprocess( const std::string &language, @@ -43,13 +44,30 @@ class gcc_modet:public goto_cc_modet static bool needs_preprocessing(const std::string &); - static inline const char *compiler_name() + inline const char *compiler_name() { - #ifdef __FreeBSD__ - return "clang"; - #else - return "gcc"; - #endif + if(native_compiler_name.empty()) + { + std::string::size_type pos=base_name.find("goto-gcc"); + + if(pos==std::string::npos || + base_name=="goto-gcc" || + base_name=="goto-ld") + { + #ifdef __FreeBSD__ + native_compiler_name="clang"; + #else + native_compiler_name="gcc"; + #endif + } + else + { + native_compiler_name=base_name; + native_compiler_name.replace(pos, 8, "gcc"); + } + } + + return native_compiler_name.c_str(); } }; diff --git a/src/goto-cc/goto_cc_main.cpp b/src/goto-cc/goto_cc_main.cpp index 59bb21ba74d..4496562c919 100644 --- a/src/goto-cc/goto_cc_main.cpp +++ b/src/goto-cc/goto_cc_main.cpp @@ -40,7 +40,9 @@ Function: to_lower_string std::string to_lower_string(const std::string &s) { std::string result=s; + #ifdef _MSC_VER transform(result.begin(), result.end(), result.begin(), tolower); + #endif return result; } @@ -105,7 +107,10 @@ int main(int argc, const char **argv) armcc_mode.base_name=base_name; return armcc_mode.main(argc, argv); } - else if(base_name=="goto-gcc") + // handle GCC names like x86_64-apple-darwin14-llvm-gcc-4.2 + // via x86_64-apple-darwin14-llvm-goto-gcc-4.2 + else if(base_name=="goto-clang" || + base_name.find("goto-gcc")!=std::string::npos) { // this produces ELF/Mach-O "hybrid binaries", // with a GCC-style command-line interface, diff --git a/src/util/get_base_name.cpp b/src/util/get_base_name.cpp index 3e1bbdf6add..5dd58f85224 100644 --- a/src/util/get_base_name.cpp +++ b/src/util/get_base_name.cpp @@ -24,7 +24,10 @@ Function: get_base_name std::string get_base_name(const std::string &in) { - size_t r=in.rfind('.', in.length()-1); + size_t r=std::string::npos; + #ifdef _MSC_VER + r=in.rfind('.', in.length()-1); + #endif if(r==std::string::npos) r=in.length(); size_t f=in.rfind('/', in.length()-1); From 48d072666b0ba4d91967daed6d0b2c1f85008a56 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Sat, 12 Mar 2016 23:43:49 +0000 Subject: [PATCH 024/101] Properly handle extended ld names --- src/goto-cc/gcc_mode.cpp | 6 +++--- src/goto-cc/gcc_mode.h | 22 ++++++++++++++++++++++ src/goto-cc/goto_cc_main.cpp | 2 +- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/goto-cc/gcc_mode.cpp b/src/goto-cc/gcc_mode.cpp index 10ba45a451b..b5091a28eb2 100644 --- a/src/goto-cc/gcc_mode.cpp +++ b/src/goto-cc/gcc_mode.cpp @@ -64,8 +64,8 @@ Function: gcc_modet::doit bool gcc_modet::doit() { act_as_ld= - has_prefix(base_name, "ld") || - has_prefix(base_name, "goto-ld"); + base_name=="ld" || + base_name.find("goto-ld")!=std::string::npos; if(cmdline.isset('?') || cmdline.isset("help")) @@ -641,7 +641,7 @@ int gcc_modet::gcc_hybrid_binary() assert(new_argv.size()>=1); if(act_as_ld) - new_argv[0]="ld"; + new_argv[0]=linker_name(); else new_argv[0]=compiler_name(); diff --git a/src/goto-cc/gcc_mode.h b/src/goto-cc/gcc_mode.h index b094fe51af6..0e3b21a9667 100644 --- a/src/goto-cc/gcc_mode.h +++ b/src/goto-cc/gcc_mode.h @@ -69,6 +69,28 @@ class gcc_modet:public goto_cc_modet return native_compiler_name.c_str(); } + + inline const char *linker_name() + { + if(native_compiler_name.empty()) + { + std::string::size_type pos=base_name.find("goto-ld"); + + if(pos==std::string::npos || + base_name=="goto-gcc" || + base_name=="goto-ld") + { + native_compiler_name="ld"; + } + else + { + native_compiler_name=base_name; + native_compiler_name.replace(pos, 7, "ld"); + } + } + + return native_compiler_name.c_str(); + } }; #endif /* GOTO_CC_GCC_MODE_H */ diff --git a/src/goto-cc/goto_cc_main.cpp b/src/goto-cc/goto_cc_main.cpp index 4496562c919..1e83625cd98 100644 --- a/src/goto-cc/goto_cc_main.cpp +++ b/src/goto-cc/goto_cc_main.cpp @@ -121,7 +121,7 @@ int main(int argc, const char **argv) gcc_mode.produce_hybrid_binary=true; return gcc_mode.main(argc, argv); } - else if(base_name=="goto-ld") + else if(base_name.find("goto-ld")!=std::string::npos) { // this simulates "ld" for linking ld_cmdlinet cmdline; From 237195c4171cb45757fd10e02494c06ab6625abf Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Sun, 13 Mar 2016 14:26:59 +0000 Subject: [PATCH 025/101] Run ld where required --- src/goto-cc/gcc_mode.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/goto-cc/gcc_mode.cpp b/src/goto-cc/gcc_mode.cpp index b5091a28eb2..65492661954 100644 --- a/src/goto-cc/gcc_mode.cpp +++ b/src/goto-cc/gcc_mode.cpp @@ -520,11 +520,13 @@ int gcc_modet::run_gcc() new_argv.push_back(it->arg); } - const char *compiler=compiler_name(); - // overwrite argv[0] assert(new_argv.size()>=1); - new_argv[0]=compiler; + + if(act_as_ld) + new_argv[0]=linker_name(); + else + new_argv[0]=compiler_name(); #if 0 std::cout << "RUN:"; @@ -533,7 +535,7 @@ int gcc_modet::run_gcc() std::cout << std::endl; #endif - return run(compiler, new_argv); + return run(new_argv[0], new_argv); } /*******************************************************************\ From d18cd6405df0928af5f7dbb2f713f0063a3dff09 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Thu, 17 Mar 2016 22:07:56 +0000 Subject: [PATCH 026/101] Properly identify the base name of a file Windows vs. Unix need distinct treatment for executables; cleanup of duplicate declaration (using include instead) and formatting. --- src/goto-cc/compile.cpp | 2 +- src/goto-cc/compile.h | 2 -- src/goto-cc/gcc_mode.cpp | 12 ++++++------ src/goto-cc/goto_cc_main.cpp | 8 +++++--- src/goto-cc/ms_cl_mode.cpp | 22 +++++++++++----------- src/jsil/jsil_language.cpp | 2 +- src/util/get_base_name.cpp | 7 +++---- src/util/get_base_name.h | 2 +- 8 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/goto-cc/compile.cpp b/src/goto-cc/compile.cpp index 9bbf51eee5c..46b8d0740c6 100644 --- a/src/goto-cc/compile.cpp +++ b/src/goto-cc/compile.cpp @@ -463,7 +463,7 @@ bool compilet::compile() std::string cfn; if(output_file_object=="") - cfn=get_base_name(file_name) + "." + object_file_extension; + cfn=get_base_name(file_name, true)+"."+object_file_extension; else cfn=output_file_object; diff --git a/src/goto-cc/compile.h b/src/goto-cc/compile.h index 2a4eb3a0c7b..73a38a2d603 100644 --- a/src/goto-cc/compile.h +++ b/src/goto-cc/compile.h @@ -75,6 +75,4 @@ class compilet:public language_uit void convert_symbols(goto_functionst &dest); }; -std::string get_base_name(const std::string &); - #endif /*COMPILE_H_*/ diff --git a/src/goto-cc/gcc_mode.cpp b/src/goto-cc/gcc_mode.cpp index 65492661954..17848eb1bf1 100644 --- a/src/goto-cc/gcc_mode.cpp +++ b/src/goto-cc/gcc_mode.cpp @@ -20,6 +20,7 @@ Author: CM Wintersteiger, 2006 #include "compile.h" #include "run.h" +#include "get_base_name.h" #include "gcc_mode.h" @@ -342,7 +343,8 @@ bool gcc_modet::doit() else new_suffix=has_suffix(arg_it->arg, ".c")?".i":".ii"; - std::string new_name=get_base_name(arg_it->arg)+new_suffix; + std::string new_name= + get_base_name(arg_it->arg, true)+new_suffix; std::string dest=temp_dir(new_name); int exit_code=preprocess(language, arg_it->arg, dest); @@ -581,11 +583,9 @@ int gcc_modet::gcc_hybrid_binary() i_it=cmdline.parsed_argv.begin(); i_it!=cmdline.parsed_argv.end(); i_it++) - if(i_it->is_infile_name) - { - if(needs_preprocessing(i_it->arg)) - output_files.push_back(get_base_name(i_it->arg)+".o"); - } + if(i_it->is_infile_name && + needs_preprocessing(i_it->arg)) + output_files.push_back(get_base_name(i_it->arg, true)+".o"); } } else diff --git a/src/goto-cc/goto_cc_main.cpp b/src/goto-cc/goto_cc_main.cpp index 1e83625cd98..4e20b24165e 100644 --- a/src/goto-cc/goto_cc_main.cpp +++ b/src/goto-cc/goto_cc_main.cpp @@ -40,9 +40,7 @@ Function: to_lower_string std::string to_lower_string(const std::string &s) { std::string result=s; - #ifdef _MSC_VER transform(result.begin(), result.end(), result.begin(), tolower); - #endif return result; } @@ -74,9 +72,13 @@ int main(int argc, const char **argv) return 1; } + #ifdef _MSC_VER // we do 'to_lower_string' because of Windows std::string base_name= - to_lower_string(get_base_name(argv[0])); + to_lower_string(get_base_name(argv[0], true)); + #else + std::string base_name=get_base_name(argv[0], false); + #endif if(base_name=="goto-link" || base_name=="link" || base_name=="goto-cl" || base_name=="cl") diff --git a/src/goto-cc/ms_cl_mode.cpp b/src/goto-cc/ms_cl_mode.cpp index 5f1acca8ab1..09ac6540a23 100644 --- a/src/goto-cc/ms_cl_mode.cpp +++ b/src/goto-cc/ms_cl_mode.cpp @@ -17,6 +17,7 @@ Author: CM Wintersteiger, 2006 #include "ms_cl_mode.h" #include "compile.h" +#include "get_base_name.h" /*******************************************************************\ @@ -87,11 +88,10 @@ bool ms_cl_modet::doit() compiler.output_file_object=cmdline.get_value("Fo"); // this could be a directory - if(is_directory(compiler.output_file_object)) - { - if(cmdline.args.size()>=1) - compiler.output_file_object+=get_base_name(cmdline.args[0])+".obj"; - } + if(is_directory(compiler.output_file_object) && + cmdline.args.size()>=1) + compiler.output_file_object+= + get_base_name(cmdline.args[0], true)+".obj"; } if(cmdline.isset("Fe")) @@ -99,18 +99,18 @@ bool ms_cl_modet::doit() compiler.output_file_executable=cmdline.get_value("Fe"); // this could be a directory - if(is_directory(compiler.output_file_executable)) - { - if(cmdline.args.size()>=1) - compiler.output_file_executable+=get_base_name(cmdline.args[0])+".exe"; - } + if(is_directory(compiler.output_file_executable) && + cmdline.args.size()>=1) + compiler.output_file_executable+= + get_base_name(cmdline.args[0], true)+".exe"; } else { // We need at least one argument. // CL uses the first file name it gets! if(cmdline.args.size()>=1) - compiler.output_file_executable=get_base_name(cmdline.args[0])+".exe"; + compiler.output_file_executable= + get_base_name(cmdline.args[0], true)+".exe"; } if(cmdline.isset('J')) diff --git a/src/jsil/jsil_language.cpp b/src/jsil/jsil_language.cpp index 58a9b315ef1..953212ee5aa 100644 --- a/src/jsil/jsil_language.cpp +++ b/src/jsil/jsil_language.cpp @@ -51,7 +51,7 @@ Function: jsil_languaget::modules_provided void jsil_languaget::modules_provided(std::set &modules) { - modules.insert(get_base_name(parse_path)); + modules.insert(get_base_name(parse_path, true)); } /*******************************************************************\ diff --git a/src/util/get_base_name.cpp b/src/util/get_base_name.cpp index 5dd58f85224..944603ce86d 100644 --- a/src/util/get_base_name.cpp +++ b/src/util/get_base_name.cpp @@ -22,12 +22,11 @@ Function: get_base_name \*******************************************************************/ -std::string get_base_name(const std::string &in) +std::string get_base_name(const std::string &in, bool strip_suffix) { size_t r=std::string::npos; - #ifdef _MSC_VER - r=in.rfind('.', in.length()-1); - #endif + if(strip_suffix) + r=in.rfind('.', in.length()-1); if(r==std::string::npos) r=in.length(); size_t f=in.rfind('/', in.length()-1); diff --git a/src/util/get_base_name.h b/src/util/get_base_name.h index c38500a1c54..cabf7741a4f 100644 --- a/src/util/get_base_name.h +++ b/src/util/get_base_name.h @@ -10,4 +10,4 @@ Author: CM Wintersteiger #include -std::string get_base_name(const std::string &in); +std::string get_base_name(const std::string &in, bool strip_suffix); From 2e4ce203c922fb710d28c56ea7d6dbddedd72323 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Thu, 17 Mar 2016 22:12:42 +0000 Subject: [PATCH 027/101] No hyrid binary if /dev/null when is goto-gcc's output file --- src/goto-cc/gcc_mode.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/goto-cc/gcc_mode.cpp b/src/goto-cc/gcc_mode.cpp index 17848eb1bf1..fc9aef3f011 100644 --- a/src/goto-cc/gcc_mode.cpp +++ b/src/goto-cc/gcc_mode.cpp @@ -597,7 +597,9 @@ int gcc_modet::gcc_hybrid_binary() output_files.push_back("a.out"); } - if(output_files.empty()) return 0; + if(output_files.empty() || + (output_files.size()==1 && + output_files.front()=="/dev/null")) return 0; if(act_as_ld) debug() << "Running ld to generate hybrid binary" << eom; From a8114b332ba8cd01a6892d31a207210983330b57 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Thu, 17 Mar 2016 22:24:50 +0000 Subject: [PATCH 028/101] GCC's -m16 is actually a 32-bit machine emulation! --- src/goto-cc/gcc_mode.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/goto-cc/gcc_mode.cpp b/src/goto-cc/gcc_mode.cpp index fc9aef3f011..17aee2e5941 100644 --- a/src/goto-cc/gcc_mode.cpp +++ b/src/goto-cc/gcc_mode.cpp @@ -157,9 +157,10 @@ bool gcc_modet::doit() config.set(cmdline); // Intel-specific - if(cmdline.isset("m16")) - config.ansi_c.set_16(); - else if(cmdline.isset("m32") || cmdline.isset("mx32")) + // in GCC, m16 is 32-bit (!), as documented here: + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59672 + if(cmdline.isset("m16") || + cmdline.isset("m32") || cmdline.isset("mx32")) { config.ansi_c.arch="i386"; config.ansi_c.set_arch_spec_i386(); From 9877d6c1c19f68c8894476b173a43c516659b8a4 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Sun, 3 Apr 2016 16:14:49 +0000 Subject: [PATCH 029/101] get_base_name is semantically equivalent to translation_unit --- src/ansi-c/Makefile | 2 +- src/ansi-c/ansi_c_language.cpp | 4 ++-- src/ansi-c/trans_unit.cpp | 41 ---------------------------------- src/ansi-c/trans_unit.h | 11 --------- src/cpp/cpp_language.cpp | 4 ++-- src/goto-cc/gcc_mode.cpp | 2 +- src/goto-cc/ms_cl_mode.cpp | 2 +- 7 files changed, 7 insertions(+), 59 deletions(-) delete mode 100644 src/ansi-c/trans_unit.cpp delete mode 100644 src/ansi-c/trans_unit.h diff --git a/src/ansi-c/Makefile b/src/ansi-c/Makefile index 18de1c5fb8e..0764c137f49 100644 --- a/src/ansi-c/Makefile +++ b/src/ansi-c/Makefile @@ -1,6 +1,6 @@ SRC = c_typecast.cpp ansi_c_y.tab.cpp ansi_c_lex.yy.cpp ansi_c_parser.cpp \ expr2c.cpp ansi_c_language.cpp c_sizeof.cpp ansi_c_scope.cpp \ - c_types.cpp trans_unit.cpp ansi_c_typecheck.cpp \ + c_types.cpp ansi_c_typecheck.cpp \ c_preprocess.cpp c_storage_spec.cpp \ c_typecheck_base.cpp c_typecheck_initializer.cpp \ c_typecheck_typecast.cpp c_typecheck_code.cpp \ diff --git a/src/ansi-c/ansi_c_language.cpp b/src/ansi-c/ansi_c_language.cpp index 3a968fc8e2e..9bc9559beeb 100644 --- a/src/ansi-c/ansi_c_language.cpp +++ b/src/ansi-c/ansi_c_language.cpp @@ -13,6 +13,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include +#include #include #include @@ -22,7 +23,6 @@ Author: Daniel Kroening, kroening@kroening.com #include "ansi_c_typecheck.h" #include "ansi_c_parser.h" #include "expr2c.h" -#include "trans_unit.h" #include "c_preprocess.h" #include "ansi_c_internal_additions.h" #include "type2name.h" @@ -61,7 +61,7 @@ Function: ansi_c_languaget::modules_provided void ansi_c_languaget::modules_provided(std::set &modules) { - modules.insert(translation_unit(parse_path)); + modules.insert(get_base_name(parse_path, true)); } /*******************************************************************\ diff --git a/src/ansi-c/trans_unit.cpp b/src/ansi-c/trans_unit.cpp deleted file mode 100644 index b57fbeed216..00000000000 --- a/src/ansi-c/trans_unit.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/*******************************************************************\ - -Module: Translation Unit - -Author: Daniel Kroening, kroening@kroening.com - -\*******************************************************************/ - -#include "trans_unit.h" - -/*******************************************************************\ - -Function: translation_unit - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -std::string translation_unit(const std::string &path) -{ - // convert path into a suggestion for a translation unit name - - std::string unit=path; - - std::string::size_type pos; - - pos=unit.find_last_of("/\\"); - if(pos!=std::string::npos) - unit=std::string(unit, pos+1); - - pos=unit.find_last_of('.'); - if(pos!=std::string::npos) - unit=std::string(unit, 0, pos); - - return unit; -} - diff --git a/src/ansi-c/trans_unit.h b/src/ansi-c/trans_unit.h deleted file mode 100644 index ba1665d948c..00000000000 --- a/src/ansi-c/trans_unit.h +++ /dev/null @@ -1,11 +0,0 @@ -/*******************************************************************\ - -Module: Translation Unit - -Author: Daniel Kroening, kroening@kroening.com - -\*******************************************************************/ - -#include - -std::string translation_unit(const std::string &path); diff --git a/src/cpp/cpp_language.cpp b/src/cpp/cpp_language.cpp index a09952407fc..115f9270b87 100644 --- a/src/cpp/cpp_language.cpp +++ b/src/cpp/cpp_language.cpp @@ -12,12 +12,12 @@ Author: Daniel Kroening, kroening@cs.cmu.edu #include #include +#include #include #include #include -#include #include "cpp_internal_additions.h" #include "cpp_language.h" @@ -70,7 +70,7 @@ Function: cpp_languaget::modules_provided void cpp_languaget::modules_provided(std::set &modules) { - modules.insert(translation_unit(parse_path)); + modules.insert(get_base_name(parse_path, true)); } /*******************************************************************\ diff --git a/src/goto-cc/gcc_mode.cpp b/src/goto-cc/gcc_mode.cpp index 17aee2e5941..365173d66d0 100644 --- a/src/goto-cc/gcc_mode.cpp +++ b/src/goto-cc/gcc_mode.cpp @@ -15,12 +15,12 @@ Author: CM Wintersteiger, 2006 #include #include #include +#include #include #include "compile.h" #include "run.h" -#include "get_base_name.h" #include "gcc_mode.h" diff --git a/src/goto-cc/ms_cl_mode.cpp b/src/goto-cc/ms_cl_mode.cpp index 09ac6540a23..067b28d069d 100644 --- a/src/goto-cc/ms_cl_mode.cpp +++ b/src/goto-cc/ms_cl_mode.cpp @@ -12,12 +12,12 @@ Author: CM Wintersteiger, 2006 #include #include #include +#include #include #include "ms_cl_mode.h" #include "compile.h" -#include "get_base_name.h" /*******************************************************************\ From 61f76cbecab7622f66498dfc752a716630cebebf Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Mon, 2 May 2016 12:35:13 +0000 Subject: [PATCH 030/101] goto-cc: when input file is stdin, copy it into a file to replay multiple times Before, hybrid binaries could not be built from stdin as noticed by Norbert. This was caused by preprocessing consuming stdin, leaving no input left for subsequent (native) gcc invocations. Now an input file "-" triggers reading all input into a temporary file, which is then opened and set as file descriptor for subprocesses. --- src/goto-cc/gcc_mode.cpp | 10 +++---- src/goto-cc/goto_cc_cmdline.cpp | 51 +++++++++++++++++++++++++++++++++ src/goto-cc/goto_cc_cmdline.h | 10 +++---- src/goto-cc/run.cpp | 31 +++++++++++++++++++- src/goto-cc/run.h | 3 +- 5 files changed, 93 insertions(+), 12 deletions(-) diff --git a/src/goto-cc/gcc_mode.cpp b/src/goto-cc/gcc_mode.cpp index 365173d66d0..d346129a4d9 100644 --- a/src/goto-cc/gcc_mode.cpp +++ b/src/goto-cc/gcc_mode.cpp @@ -493,7 +493,7 @@ int gcc_modet::preprocess( std::cout << std::endl; #endif - return run(compiler, new_argv); + return run(compiler, new_argv, cmdline.stdin_file); } /*******************************************************************\ @@ -538,7 +538,7 @@ int gcc_modet::run_gcc() std::cout << std::endl; #endif - return run(new_argv[0], new_argv); + return run(new_argv[0], new_argv, cmdline.stdin_file); } /*******************************************************************\ @@ -679,7 +679,7 @@ int gcc_modet::gcc_hybrid_binary() objcopy_argv.push_back("--remove-section=goto-cc"); objcopy_argv.push_back(*it); - result=run(objcopy_argv[0], objcopy_argv); + result=run(objcopy_argv[0], objcopy_argv, ""); if(result!=0) break; } @@ -691,7 +691,7 @@ int gcc_modet::gcc_hybrid_binary() objcopy_argv.push_back("goto-cc="+saved); objcopy_argv.push_back(*it); - result=run(objcopy_argv[0], objcopy_argv); + result=run(objcopy_argv[0], objcopy_argv, ""); remove(saved.c_str()); #elif defined(__APPLE__) @@ -708,7 +708,7 @@ int gcc_modet::gcc_hybrid_binary() lipo_argv.push_back("-output"); lipo_argv.push_back(*it); - result=run(lipo_argv[0], lipo_argv); + result=run(lipo_argv[0], lipo_argv, ""); remove(saved.c_str()); diff --git a/src/goto-cc/goto_cc_cmdline.cpp b/src/goto-cc/goto_cc_cmdline.cpp index 005b74d20cd..7d170d00b3d 100644 --- a/src/goto-cc/goto_cc_cmdline.cpp +++ b/src/goto-cc/goto_cc_cmdline.cpp @@ -10,13 +10,33 @@ Date: April 2010 #include #include +#include #include +#include #include "goto_cc_cmdline.h" /*******************************************************************\ +Function: goto_cc_cmdlinet::~goto_cc_cmdlinet + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +goto_cc_cmdlinet::~goto_cc_cmdlinet() +{ + if(!stdin_file.empty()) + remove(stdin_file.c_str()); +} + +/*******************************************************************\ + Function: goto_cc_cmdlinet::in_list Inputs: @@ -131,3 +151,34 @@ std::size_t goto_cc_cmdlinet::get_optnr(const std::string &opt_string) return optnr; } + +/*******************************************************************\ + +Function: goto_cc_cmdlinet::add_infile_arg + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void goto_cc_cmdlinet::add_infile_arg(const std::string &arg) +{ + parsed_argv.push_back(argt(arg)); + parsed_argv.back().is_infile_name=true; + + if(arg=="-") + { + stdin_file=get_temporary_file("goto-cc", "stdin"); + + FILE *tmp=fopen(stdin_file.c_str(), "wt"); + + char ch; + while(std::cin.read(&ch, 1)) + fputc(ch, tmp); + + fclose(tmp); + } +} diff --git a/src/goto-cc/goto_cc_cmdline.h b/src/goto-cc/goto_cc_cmdline.h index d8e2c474cb6..3115ee4c99c 100644 --- a/src/goto-cc/goto_cc_cmdline.h +++ b/src/goto-cc/goto_cc_cmdline.h @@ -16,6 +16,8 @@ Date: April 2010 class goto_cc_cmdlinet:public cmdlinet { public: + ~goto_cc_cmdlinet(); + using cmdlinet::parse; virtual bool parse(int argc, const char **argv)=0; @@ -65,17 +67,15 @@ class goto_cc_cmdlinet:public cmdlinet return false; } + std::string stdin_file; + protected: void add_arg(const std::string &arg) { parsed_argv.push_back(argt(arg)); } - void add_infile_arg(const std::string &arg) - { - parsed_argv.push_back(argt(arg)); - parsed_argv.back().is_infile_name=true; - } + void add_infile_arg(const std::string &arg); }; #endif /* GOTO_CC_CMDLINE_H */ diff --git a/src/goto-cc/run.cpp b/src/goto-cc/run.cpp index f689b6f45f3..8dc8a8fb748 100644 --- a/src/goto-cc/run.cpp +++ b/src/goto-cc/run.cpp @@ -20,6 +20,7 @@ Date: August 2012 #include #include +#include #endif @@ -41,9 +42,13 @@ Function: run int run( const std::string &what, - const std::vector &argv) + const std::vector &argv, + const std::string &std_input) { #ifdef _WIN32 + // we don't support stdin on Windows + assert(std_input.empty()); + // unicode version of the arguments std::vector wargv; @@ -70,6 +75,18 @@ int run( return status; #else + int stdin_fd=STDIN_FILENO; + + if(!std_input.empty()) + { + stdin_fd=open(std_input.c_str(), O_RDONLY); + if(stdin_fd==-1) + { + perror("Failed to open stdin copy"); + return 1; + } + } + pid_t childpid; /* variable to store the child's pid */ /* now create new process */ @@ -85,6 +102,8 @@ int run( _argv[argv.size()]=NULL; + if(stdin_fd!=STDIN_FILENO) + dup2(stdin_fd, STDIN_FILENO); execvp(what.c_str(), _argv); /* usually no return */ return 1; @@ -99,13 +118,23 @@ int run( else { perror("Waiting for child process failed"); + if(stdin_fd!=STDIN_FILENO) + close(stdin_fd); return 1; } + if(stdin_fd!=STDIN_FILENO) + close(stdin_fd); + return WEXITSTATUS(status); } } else /* fork returns -1 on failure */ + { + if(stdin_fd!=STDIN_FILENO) + close(stdin_fd); + return 1; + } #endif } diff --git a/src/goto-cc/run.h b/src/goto-cc/run.h index b1cca1c156e..9e2c88473dd 100644 --- a/src/goto-cc/run.h +++ b/src/goto-cc/run.h @@ -16,6 +16,7 @@ Date: August 2012 int run( const std::string &what, - const std::vector &argv); + const std::vector &argv, + const std::string &std_input); #endif /* GOTO_CC_RUN_H */ From 70a313bf02988cdaedc53b2ab0aa1ef43a47d890 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Mon, 2 May 2016 13:14:20 +0000 Subject: [PATCH 031/101] Ensure that cleanup of .saved temporary files happens even if gcc fails --- src/goto-cc/gcc_mode.cpp | 57 ++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/src/goto-cc/gcc_mode.cpp b/src/goto-cc/gcc_mode.cpp index d346129a4d9..6401cd780bf 100644 --- a/src/goto-cc/gcc_mode.cpp +++ b/src/goto-cc/gcc_mode.cpp @@ -660,17 +660,17 @@ int gcc_modet::gcc_hybrid_binary() int result=run(new_argv[0], new_argv); // merge output from gcc with goto-binaries - // using objcopy + // using objcopy, or do cleanup if an earlier call failed for(std::list::const_iterator it=output_files.begin(); - result==0 && it!=output_files.end(); + it!=output_files.end(); it++) { debug() << "merging " << *it << eom; std::string saved=*it+".goto-cc-saved"; #ifdef __linux__ - if(!cmdline.isset('c')) + if(result==0 && !cmdline.isset('c')) { // remove any existing goto-cc section std::vector objcopy_argv; @@ -680,35 +680,40 @@ int gcc_modet::gcc_hybrid_binary() objcopy_argv.push_back(*it); result=run(objcopy_argv[0], objcopy_argv, ""); - if(result!=0) break; } - // now add goto-binary as goto-cc section - std::vector objcopy_argv; - - objcopy_argv.push_back("objcopy"); - objcopy_argv.push_back("--add-section"); - objcopy_argv.push_back("goto-cc="+saved); - objcopy_argv.push_back(*it); - - result=run(objcopy_argv[0], objcopy_argv, ""); + if(result==0) + { + // now add goto-binary as goto-cc section + std::vector objcopy_argv; + + objcopy_argv.push_back("objcopy"); + objcopy_argv.push_back("--add-section"); + objcopy_argv.push_back("goto-cc="+saved); + objcopy_argv.push_back(*it); + + result=run(objcopy_argv[0], objcopy_argv, ""); + } remove(saved.c_str()); #elif defined(__APPLE__) // Mac - std::vector lipo_argv; - - // now add goto-binary as hppa7100LC section - lipo_argv.push_back("lipo"); - lipo_argv.push_back(*it); - lipo_argv.push_back("-create"); - lipo_argv.push_back("-arch"); - lipo_argv.push_back("hppa7100LC"); - lipo_argv.push_back(saved); - lipo_argv.push_back("-output"); - lipo_argv.push_back(*it); - - result=run(lipo_argv[0], lipo_argv, ""); + if(result==0) + { + std::vector lipo_argv; + + // now add goto-binary as hppa7100LC section + lipo_argv.push_back("lipo"); + lipo_argv.push_back(*it); + lipo_argv.push_back("-create"); + lipo_argv.push_back("-arch"); + lipo_argv.push_back("hppa7100LC"); + lipo_argv.push_back(saved); + lipo_argv.push_back("-output"); + lipo_argv.push_back(*it); + + result=run(lipo_argv[0], lipo_argv, ""); + } remove(saved.c_str()); From ad1b396273b3e339d32bf3b90ef6706d90497dbf Mon Sep 17 00:00:00 2001 From: Norbert Manthey Date: Fri, 29 Apr 2016 14:36:30 +0200 Subject: [PATCH 032/101] Add -z option handling to goto-gcc Do not handle "-m" any more, as recent gcc versions do not support it. Signed-off-by: Norbert Manthey CC: Michael Tautschnig CC: Daniel Kroening CR: https://cr.amazon.com/r/5198492/ --- src/goto-cc/gcc_cmdline.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/goto-cc/gcc_cmdline.cpp b/src/goto-cc/gcc_cmdline.cpp index e89a24cd984..9ebb0e2d94a 100644 --- a/src/goto-cc/gcc_cmdline.cpp +++ b/src/goto-cc/gcc_cmdline.cpp @@ -74,6 +74,7 @@ const char *gcc_options_with_separated_argument[]= "--include", // undocumented "-current_version", // on the Mac "-compatibility_version", // on the Mac + "-z", NULL }; From 16f8b291faa597219fa102f7f48a6968cccc864b Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Tue, 17 May 2016 10:56:04 +0100 Subject: [PATCH 033/101] beautify coverage output --- src/cbmc/bmc_cover.cpp | 9 ++++++++- src/goto-instrument/cover.cpp | 13 +++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/cbmc/bmc_cover.cpp b/src/cbmc/bmc_cover.cpp index 85a37e87d69..0ff2231eee3 100644 --- a/src/cbmc/bmc_cover.cpp +++ b/src/cbmc/bmc_cover.cpp @@ -377,7 +377,12 @@ bool bmc_covert::operator()() else { status() << "[" << it->first << "]"; + + if(goal.source_location.is_not_nil()) + status() << ' ' << goal.source_location; + if(!goal.description.empty()) status() << ' ' << goal.description; + status() << ": " << (goal.satisfied?"SATISFIED":"FAILED") << eom; } @@ -387,9 +392,11 @@ bool bmc_covert::operator()() status() << "** " << goals_covered << " of " << goal_map.size() << " covered (" + << std::fixed << std::setw(1) << std::setprecision(1) + << 100.0*goals_covered/goal_map.size() << "%), using " << cover_goals.iterations() << " iteration" << (cover_goals.iterations()==1?"":"s") - << ")" << eom; + << eom; return false; } diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index 9a1751e9e4e..66c4cf65b4c 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -298,10 +298,11 @@ void instrument_cover_goals( source_locationt source_location= basic_blocks.source_location_map[block_nr]; - if(source_location.get_file()!="") + if(!source_location.get_file().empty() && + source_location.get_file()[0]!='<') { std::string comment= - "block "+source_location.as_string()+" "+i2string(i_it->location_number); + "block "+i2string(i_it->location_number); goto_program.insert_before_swap(i_it); i_it->make_assertion(false_exprt()); @@ -351,13 +352,13 @@ void instrument_cover_goals( for(const auto & c : conditions) { - std::string comment_t="condition "+from_expr(ns, "", c)+" true"; + std::string comment_t="condition `"+from_expr(ns, "", c)+"' true"; 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); - std::string comment_f="condition "+from_expr(ns, "", c)+" false"; + std::string comment_f="condition `"+from_expr(ns, "", c)+"' false"; goto_program.insert_before_swap(i_it); i_it->make_assertion(not_exprt(c)); i_it->source_location=source_location; @@ -379,13 +380,13 @@ void instrument_cover_goals( for(const auto & d : decisions) { - std::string comment_t="decision "+from_expr(ns, "", d)+" true"; + std::string comment_t="decision `"+from_expr(ns, "", d)+"' true"; 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); - std::string comment_f="decision "+from_expr(ns, "", d)+" false"; + std::string comment_f="decision `"+from_expr(ns, "", d)+"' false"; goto_program.insert_before_swap(i_it); i_it->make_assertion(not_exprt(d)); i_it->source_location=source_location; From 7067366985d951f9841b935ddec33af952f303a2 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Tue, 17 May 2016 11:24:05 +0100 Subject: [PATCH 034/101] remove tabs --- src/ansi-c/library/math.c | 12 +- src/ansi-c/scanner.l | 392 +++++++++++++++++++------------------- src/assembler/scanner.l | 74 ++++--- src/common | 6 +- src/json/parser.y | 10 +- src/json/scanner.l | 34 ++-- src/xmllang/parser.y | 22 +-- src/xmllang/scanner.l | 56 +++--- 8 files changed, 302 insertions(+), 304 deletions(-) diff --git a/src/ansi-c/library/math.c b/src/ansi-c/library/math.c index 7fdd935a224..48bd24e8d53 100644 --- a/src/ansi-c/library/math.c +++ b/src/ansi-c/library/math.c @@ -617,8 +617,8 @@ float sqrtf(float f) if ( f < 0.0f ) return 0.0f/0.0f; // NaN else if (__CPROVER_isinff(f) || // +Inf only - f == 0.0f || // Includes -0 - __CPROVER_isnanf(f)) + f == 0.0f || // Includes -0 + __CPROVER_isnanf(f)) return f; else if (__CPROVER_isnormalf(f)) { @@ -702,8 +702,8 @@ double sqrt(double d) if ( d < 0.0 ) return 0.0/0.0; // NaN else if (__CPROVER_isinfd(d) || // +Inf only - d == 0.0 || // Includes -0 - __CPROVER_isnand(d)) + d == 0.0 || // Includes -0 + __CPROVER_isnand(d)) return d; else if (__CPROVER_isnormald(d)) { @@ -771,8 +771,8 @@ long double sqrtl(long double d) if(d < 0.0l) return 0.0l/0.0l; // NaN else if (__CPROVER_isinfld(d) || // +Inf only - d == 0.0l || // Includes -0 - __CPROVER_isnanld(d)) + d == 0.0l || // Includes -0 + __CPROVER_isnanld(d)) return d; else if (__CPROVER_isnormalld(d)) { diff --git a/src/ansi-c/scanner.l b/src/ansi-c/scanner.l index 118395385d3..977f428231e 100644 --- a/src/ansi-c/scanner.l +++ b/src/ansi-c/scanner.l @@ -44,7 +44,7 @@ int make_identifier() // this hashes the identifier irep_idt base_name=yytext; - + if(PARSER.cpp98) { stack(yyansi_clval).id(ID_symbol); @@ -139,43 +139,43 @@ delimiter [ \t\b\r] newline [\n\f\v]|"\\\n" whitespace {delimiter}+ ws {delimiter}* -ucletter [A-Z] -lcletter [a-z] -letter ({ucletter}|{lcletter}) -digit [0-9] -bindigit [01] -octdigit [0-7] -hexdigit [0-9a-fA-F] -identifier (({letter}|"_"|"$")({letter}|{digit}|"_"|"$")*) -integer {digit}+ -binary {bindigit}+ +ucletter [A-Z] +lcletter [a-z] +letter ({ucletter}|{lcletter}) +digit [0-9] +bindigit [01] +octdigit [0-7] +hexdigit [0-9a-fA-F] +identifier (({letter}|"_"|"$")({letter}|{digit}|"_"|"$")*) +integer {digit}+ +binary {bindigit}+ msiw_suffix ([iI]("8"|"16"|"32"|"64"|"128")) int_suffix [uUlLiIjJ]*|[uU]?{msiw_suffix} -bininteger "0"[bB]({bindigit}|"'")+{int_suffix} -decinteger [1-9]({digit}|"'")*{int_suffix} -octinteger "0"({octdigit}|"'")*{int_suffix} -hexinteger "0"[xX]{hexdigit}({hexdigit}|"'")*{int_suffix} +bininteger "0"[bB]({bindigit}|"'")+{int_suffix} +decinteger [1-9]({digit}|"'")*{int_suffix} +octinteger "0"({octdigit}|"'")*{int_suffix} +hexinteger "0"[xX]{hexdigit}({hexdigit}|"'")*{int_suffix} integer_s {decinteger}|{bininteger}|{octinteger}|{hexinteger} -octchar "\\"{octdigit}{1,3} -hexchar "\\x"{hexdigit}+ -exponent [eE][+-]?{integer} -fraction {integer} -float1 {integer}"."{fraction}?({exponent})? -float2 "."{fraction}({exponent})? -float3 {integer}{exponent} +octchar "\\"{octdigit}{1,3} +hexchar "\\x"{hexdigit}+ +exponent [eE][+-]?{integer} +fraction {integer} +float1 {integer}"."{fraction}?({exponent})? +float2 "."{fraction}({exponent})? +float3 {integer}{exponent} hexfloat1 "0"[xX]{hexdigit}+"."{hexdigit}+[pP][+-]?{integer} hexfloat2 "0"[xX]{hexdigit}+"."[pP][+-]?{integer} hexfloat3 "0"[xX]{hexdigit}+[pP][+-]?{integer} float_suffix [fFlLiIjJ]* gcc_ext_float_suffix [wWqQ]|[dD][fFdDlL]? -float {float1}|{float2}|{float3}|{hexfloat1}|{hexfloat2}|{hexfloat3} +float {float1}|{float2}|{float3}|{hexfloat1}|{hexfloat2}|{hexfloat3} float_s {float}{float_suffix}|{integer}[fF] -gcc_ext_float_s {float}{gcc_ext_float_suffix} -bitvector {binary}[bB] -bitvector_u {binary}([uU][bB]|[bB][uU]) -cppstart {ws}"#"{ws} -cpplineno {cppstart}"line"*{ws}{integer}{ws}.*{newline} -cppdirective {cppstart}.* +gcc_ext_float_s {float}{gcc_ext_float_suffix} +bitvector {binary}[bB] +bitvector_u {binary}([uU][bB]|[bB][uU]) +cppstart {ws}"#"{ws} +cpplineno {cppstart}"line"*{ws}{integer}{ws}.*{newline} +cppdirective {cppstart}.* escape_sequence [\\][^\n] c_char [^'\\\n]|{escape_sequence} @@ -214,35 +214,35 @@ void ansi_c_scanner_init() %% .|\n { BEGIN(GRAMMAR); - yyless(0); /* start again with this character */ - } + yyless(0); /* start again with this character */ + } "/*" { BEGIN(COMMENT1); } /* begin C comment state */ { - "*/" { BEGIN(GRAMMAR); } /* end comment state, back to GRAMMAR */ - "/*" { yyansi_cerror("Probably nested comments"); } - <> { yyansi_cerror("Unterminated comment"); return TOK_SCANNER_ERROR; } - [^*/\n]* { /* ignore every char except '*' and NL (performance!) */ } - . { } /* all single characters within comments are ignored */ - \n { } - } + "*/" { BEGIN(GRAMMAR); } /* end comment state, back to GRAMMAR */ + "/*" { yyansi_cerror("Probably nested comments"); } + <> { yyansi_cerror("Unterminated comment"); return TOK_SCANNER_ERROR; } + [^*/\n]* { /* ignore every char except '*' and NL (performance!) */ } + . { } /* all single characters within comments are ignored */ + \n { } +} { - "*/" { BEGIN(STRING_LITERAL); } /* end comment state, back to STRING_LITERAL */ - "/*" { yyansi_cerror("Probably nested comments"); } - <> { yyansi_cerror("Unterminated comment"); return TOK_SCANNER_ERROR; } - [^*/\n]* { /* ignore every char except '*' and NL (performance!) */ } - . { } /* all single characters within comments are ignored */ - \n { } - } + "*/" { BEGIN(STRING_LITERAL); } /* end comment state, back to STRING_LITERAL */ + "/*" { yyansi_cerror("Probably nested comments"); } + <> { yyansi_cerror("Unterminated comment"); return TOK_SCANNER_ERROR; } + [^*/\n]* { /* ignore every char except '*' and NL (performance!) */ } + . { } /* all single characters within comments are ignored */ + \n { } +} -"//" { BEGIN(COMMENT2); } /* begin C++ comment state */ +"//" { BEGIN(COMMENT2); } /* begin C++ comment state */ { - \n { BEGIN(GRAMMAR); } /* end comment state, back GRAMMAR */ - .* { } /* all characters within comments are ignored */ - } + \n { BEGIN(GRAMMAR); } /* end comment state, back GRAMMAR */ + .* { } /* all characters within comments are ignored */ +} {char_lit} { newstack(yyansi_clval); @@ -267,10 +267,10 @@ void ansi_c_scanner_init() {cpplineno} { preprocessor_line(yytext, PARSER); PARSER.set_line_no(PARSER.get_line_no()-1); - } + } {cppdirective} { /* ignore */ } "/*" { BEGIN(STRING_LITERAL_COMMENT); /* C comment, ignore */ } -"//".*\n { /* C++ comment, ignore */ } +"//".*\n { /* C++ comment, ignore */ } . { // anything else: back to normal source_locationt l=stack(yyansi_clval).source_location(); stack(yyansi_clval)=convert_string_literal(PARSER.string_literal); @@ -280,140 +280,140 @@ void ansi_c_scanner_init() return TOK_STRING; } -{newline} { } /* skipped */ -{whitespace} { } /* skipped */ +{newline} { } /* skipped */ +{whitespace} { } /* skipped */ -{cpplineno} { +{cpplineno} { preprocessor_line(yytext, PARSER); PARSER.set_line_no(PARSER.get_line_no()-1); - } + } {cppstart}"pragma"{ws}"pack"{ws}"("{ws}"push"{ws}")"{ws}{newline} { - // Done by Visual Studio and gcc - // http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx - // push, pop could also use identifiers - if(PARSER.pragma_pack.empty()) - PARSER.pragma_pack.push_back(convert_integer_literal("0")); - else - PARSER.pragma_pack.push_back(PARSER.pragma_pack.back()); - } + // Done by Visual Studio and gcc + // http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx + // push, pop could also use identifiers + if(PARSER.pragma_pack.empty()) + PARSER.pragma_pack.push_back(convert_integer_literal("0")); + else + PARSER.pragma_pack.push_back(PARSER.pragma_pack.back()); + } {cppstart}"pragma"{ws}"pack"{ws}"("{ws}"push"{ws}","{ws}{integer_s}{ws}")"{ws}{newline} { - // Done by Visual Studio and gcc - // http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx - // push, pop could also use identifiers - std::string tmp(yytext); - std::string::size_type p=tmp.find(',')+1; - while(tmp[p]==' ' || tmp[p]=='\t') ++p; - std::string value=std::string(tmp, p, tmp.find_last_not_of(") \t\n\r")+1-p); - exprt n=convert_integer_literal(value); - PARSER.pragma_pack.push_back(n); - } + // Done by Visual Studio and gcc + // http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx + // push, pop could also use identifiers + std::string tmp(yytext); + std::string::size_type p=tmp.find(',')+1; + while(tmp[p]==' ' || tmp[p]=='\t') ++p; + std::string value=std::string(tmp, p, tmp.find_last_not_of(") \t\n\r")+1-p); + exprt n=convert_integer_literal(value); + PARSER.pragma_pack.push_back(n); + } {cppstart}"pragma"{ws}"pack"{ws}"("{ws}{integer_s}{ws}")"{ws}{newline} { - // Done by Visual Studio and gcc - // http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx - std::string tmp(yytext); - std::string::size_type p=tmp.find('(')+1; - while(tmp[p]==' ' || tmp[p]=='\t') ++p; - std::string value=std::string(tmp, p, tmp.find_last_not_of(") \t\n\r")+1-p); - exprt n=convert_integer_literal(value); - PARSER.pragma_pack.push_back(n); - } + // Done by Visual Studio and gcc + // http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx + std::string tmp(yytext); + std::string::size_type p=tmp.find('(')+1; + while(tmp[p]==' ' || tmp[p]=='\t') ++p; + std::string value=std::string(tmp, p, tmp.find_last_not_of(") \t\n\r")+1-p); + exprt n=convert_integer_literal(value); + PARSER.pragma_pack.push_back(n); + } {cppstart}"pragma"{ws}"pack"{ws}"("{ws}"pop"{ws}")"{ws}{newline} { - // Done by Visual Studio and gcc - // http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx - // push, pop could also use identifiers - if(!PARSER.pragma_pack.empty()) PARSER.pragma_pack.pop_back(); - } + // Done by Visual Studio and gcc + // http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx + // push, pop could also use identifiers + if(!PARSER.pragma_pack.empty()) PARSER.pragma_pack.pop_back(); + } {cppstart}"pragma"{ws}"pack"{ws}"("{ws}")"{ws}{newline} { - // Done by Visual Studio and gcc - // http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx - // should be equivalent to pop-all - PARSER.pragma_pack.clear(); - } + // Done by Visual Studio and gcc + // http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx + // should be equivalent to pop-all + PARSER.pragma_pack.clear(); + } {cppstart}"pragma"{ws}.* { - // silently ignore other pragmas - } + // silently ignore other pragmas + } {cppstart}"ident"{ws}.* { /* ignore */ } {cppstart}"define"{ws}.* { /* ignore */ } {cppstart}"undef"{ws}.* { /* ignore */ } -{cppdirective} { - yyansi_cerror("Preprocessor directive found"); - return TOK_SCANNER_ERROR; - } +{cppdirective} { + yyansi_cerror("Preprocessor directive found"); + return TOK_SCANNER_ERROR; + } %{ /*** keywords ***/ %} { -"auto" { loc(); return TOK_AUTO; } -"_Bool" { if(PARSER.cpp98) +"auto" { loc(); return TOK_AUTO; } +"_Bool" { if(PARSER.cpp98) return make_identifier(); else { loc(); return TOK_BOOL; } } -"break" { loc(); return TOK_BREAK; } -"case" { loc(); return TOK_CASE; } -"char" { loc(); return TOK_CHAR; } -"_Complex" { loc(); return TOK_COMPLEX; } -"const" { loc(); return TOK_CONST; } -"continue" { loc(); return TOK_CONTINUE; } -"default" { loc(); return TOK_DEFAULT; } -"do" { loc(); return TOK_DO; } -"double" { loc(); return TOK_DOUBLE; } -"else" { loc(); return TOK_ELSE; } -"enum" { loc(); PARSER.tag_following=true; return TOK_ENUM; } -"extern" { loc(); return TOK_EXTERN; } -"float" { loc(); return TOK_FLOAT; } -"for" { loc(); return TOK_FOR; } -"goto" { loc(); return TOK_GOTO; } -"if" { loc(); return TOK_IF; } -"inline" { loc(); return TOK_INLINE; } -"int" { loc(); return TOK_INT; } -"long" { loc(); return TOK_LONG; } -"register" { loc(); return TOK_REGISTER; } +"break" { loc(); return TOK_BREAK; } +"case" { loc(); return TOK_CASE; } +"char" { loc(); return TOK_CHAR; } +"_Complex" { loc(); return TOK_COMPLEX; } +"const" { loc(); return TOK_CONST; } +"continue" { loc(); return TOK_CONTINUE; } +"default" { loc(); return TOK_DEFAULT; } +"do" { loc(); return TOK_DO; } +"double" { loc(); return TOK_DOUBLE; } +"else" { loc(); return TOK_ELSE; } +"enum" { loc(); PARSER.tag_following=true; return TOK_ENUM; } +"extern" { loc(); return TOK_EXTERN; } +"float" { loc(); return TOK_FLOAT; } +"for" { loc(); return TOK_FOR; } +"goto" { loc(); return TOK_GOTO; } +"if" { loc(); return TOK_IF; } +"inline" { loc(); return TOK_INLINE; } +"int" { loc(); return TOK_INT; } +"long" { loc(); return TOK_LONG; } +"register" { loc(); return TOK_REGISTER; } "restrict" { loc(); return TOK_RESTRICT; } -"return" { loc(); return TOK_RETURN; } -"short" { loc(); return TOK_SHORT; } -"signed" { loc(); return TOK_SIGNED; } -"sizeof" { loc(); return TOK_SIZEOF; } -"static" { loc(); return TOK_STATIC; } -"struct" { loc(); PARSER.tag_following=true; return TOK_STRUCT; } -"switch" { loc(); return TOK_SWITCH; } -"typedef" { loc(); return TOK_TYPEDEF; } -"union" { loc(); PARSER.tag_following=true; return TOK_UNION; } -"unsigned" { loc(); return TOK_UNSIGNED; } -"void" { loc(); return TOK_VOID; } -"volatile" { loc(); return TOK_VOLATILE; } -"while" { loc(); return TOK_WHILE; } +"return" { loc(); return TOK_RETURN; } +"short" { loc(); return TOK_SHORT; } +"signed" { loc(); return TOK_SIGNED; } +"sizeof" { loc(); return TOK_SIZEOF; } +"static" { loc(); return TOK_STATIC; } +"struct" { loc(); PARSER.tag_following=true; return TOK_STRUCT; } +"switch" { loc(); return TOK_SWITCH; } +"typedef" { loc(); return TOK_TYPEDEF; } +"union" { loc(); PARSER.tag_following=true; return TOK_UNION; } +"unsigned" { loc(); return TOK_UNSIGNED; } +"void" { loc(); return TOK_VOID; } +"volatile" { loc(); return TOK_VOLATILE; } +"while" { loc(); return TOK_WHILE; } "__auto_type" { if(PARSER.mode==ansi_c_parsert::GCC && !PARSER.cpp98) - { loc(); return TOK_GCC_AUTO_TYPE; } + { loc(); return TOK_GCC_AUTO_TYPE; } else return make_identifier(); } -"__float80" { if(PARSER.mode==ansi_c_parsert::GCC) - { loc(); return TOK_GCC_FLOAT80; } +"__float80" { if(PARSER.mode==ansi_c_parsert::GCC) + { loc(); return TOK_GCC_FLOAT80; } else return make_identifier(); } -"__float128" { if(PARSER.mode==ansi_c_parsert::GCC) - { loc(); return TOK_GCC_FLOAT128; } +"__float128" { if(PARSER.mode==ansi_c_parsert::GCC) + { loc(); return TOK_GCC_FLOAT128; } else return make_identifier(); } -"__int128" { if(PARSER.mode==ansi_c_parsert::GCC) - { loc(); return TOK_GCC_INT128; } +"__int128" { if(PARSER.mode==ansi_c_parsert::GCC) + { loc(); return TOK_GCC_INT128; } else return make_identifier(); } @@ -467,7 +467,7 @@ void ansi_c_scanner_init() } "__real__" | -"__real" { if(PARSER.mode==ansi_c_parsert::GCC || +"__real" { if(PARSER.mode==ansi_c_parsert::GCC || PARSER.mode==ansi_c_parsert::ARM) { loc(); return TOK_REAL; } else @@ -475,7 +475,7 @@ void ansi_c_scanner_init() } "__imag__" | -"__imag" { if(PARSER.mode==ansi_c_parsert::GCC || +"__imag" { if(PARSER.mode==ansi_c_parsert::GCC || PARSER.mode==ansi_c_parsert::ARM) { loc(); return TOK_IMAG; } else @@ -608,11 +608,11 @@ void ansi_c_scanner_init() return make_identifier(); } -"__wchar_t" { if(PARSER.mode==ansi_c_parsert::MSC) - { loc(); return TOK_WCHAR_T; } +"__wchar_t" { if(PARSER.mode==ansi_c_parsert::MSC) + { loc(); return TOK_WCHAR_T; } else return make_identifier(); - } + } %{ /* C++ Keywords and Operators */ @@ -658,7 +658,7 @@ typeid { return cpp98_keyword(TOK_TYPEID); } typename { return cpp98_keyword(TOK_TYPENAME); } using { return cpp98_keyword(TOK_USING); } virtual { return cpp98_keyword(TOK_VIRTUAL); } -wchar_t { // CodeWarrior doesn't have wchar_t built in, +wchar_t { // CodeWarrior doesn't have wchar_t built in, // and MSC has a command-line option to turn it off if(PARSER.mode==ansi_c_parsert::CW) return make_identifier(); @@ -737,14 +737,14 @@ __decltype { if(PARSER.cpp98 && PARSER.mode==ansi_c_parsert::GCC) "["{ws}"emitidl" | "["{ws}"module" | "["{ws}"export" { if(PARSER.mode==ansi_c_parsert::MSC) - BEGIN(MSC_ANNOTATION); + BEGIN(MSC_ANNOTATION); else - { - yyless(1); // puts all but [ back into stream - loc(); - PARSER.tag_following=false; - return yytext[0]; // returns the [ - } + { + yyless(1); // puts all but [ back into stream + loc(); + PARSER.tag_following=false; + return yytext[0]; // returns the [ + } } "__char16_t" { if(PARSER.mode==ansi_c_parsert::GCC) @@ -1013,8 +1013,8 @@ __decltype { if(PARSER.cpp98 && PARSER.mode==ansi_c_parsert::GCC) return make_identifier(); } -"__inline" { loc(); return TOK_INLINE; } -"__inline__" { loc(); return TOK_INLINE; } +"__inline" { loc(); return TOK_INLINE; } +"__inline__" { loc(); return TOK_INLINE; } "__label__" { if(PARSER.mode==ansi_c_parsert::GCC || PARSER.mode==ansi_c_parsert::ARM) @@ -1144,10 +1144,10 @@ __decltype { if(PARSER.cpp98 && PARSER.mode==ansi_c_parsert::GCC) /* This is a C11 keyword. It can be used as a type qualifier and as a type specifier, which introduces ambiguity into the grammar. We thus have two different tokens. - + 6.7.2.4 - 4: If the _Atomic keyword is immediately followed by a left parenthesis, it is interpreted as a type specifier (with a type name), - not as a type qualifier. + not as a type qualifier. */ "_Atomic"{ws}"(" { // put back all but _Atomic @@ -1224,29 +1224,29 @@ __decltype { if(PARSER.cpp98 && PARSER.mode==ansi_c_parsert::GCC) /* operators following */ { -"->" { loc(); return TOK_ARROW; } -"++" { loc(); return TOK_INCR; } -"--" { loc(); return TOK_DECR; } -"<<" { loc(); return TOK_SHIFTLEFT; } -">>" { loc(); return TOK_SHIFTRIGHT; } -"<=" { loc(); return TOK_LE; } -">=" { loc(); return TOK_GE; } -"==" { loc(); return TOK_EQ; } -"!=" { loc(); return TOK_NE; } -"&&" { loc(); return TOK_ANDAND; } -"||" { loc(); return TOK_OROR; } -"..." { loc(); return TOK_ELLIPSIS; } - -"*=" { loc(); return TOK_MULTASSIGN; } -"/=" { loc(); return TOK_DIVASSIGN; } -"%=" { loc(); return TOK_MODASSIGN; } -"+=" { loc(); return TOK_PLUSASSIGN; } -"-=" { loc(); return TOK_MINUSASSIGN; } -"<<=" { loc(); return TOK_SHLASSIGN; } -">>=" { loc(); return TOK_SHRASSIGN; } -"&=" { loc(); return TOK_ANDASSIGN; } -"^=" { loc(); return TOK_XORASSIGN; } -"|=" { loc(); return TOK_ORASSIGN; } +"->" { loc(); return TOK_ARROW; } +"++" { loc(); return TOK_INCR; } +"--" { loc(); return TOK_DECR; } +"<<" { loc(); return TOK_SHIFTLEFT; } +">>" { loc(); return TOK_SHIFTRIGHT; } +"<=" { loc(); return TOK_LE; } +">=" { loc(); return TOK_GE; } +"==" { loc(); return TOK_EQ; } +"!=" { loc(); return TOK_NE; } +"&&" { loc(); return TOK_ANDAND; } +"||" { loc(); return TOK_OROR; } +"..." { loc(); return TOK_ELLIPSIS; } + +"*=" { loc(); return TOK_MULTASSIGN; } +"/=" { loc(); return TOK_DIVASSIGN; } +"%=" { loc(); return TOK_MODASSIGN; } +"+=" { loc(); return TOK_PLUSASSIGN; } +"-=" { loc(); return TOK_MINUSASSIGN; } +"<<=" { loc(); return TOK_SHLASSIGN; } +">>=" { loc(); return TOK_SHRASSIGN; } +"&=" { loc(); return TOK_ANDASSIGN; } +"^=" { loc(); return TOK_XORASSIGN; } +"|=" { loc(); return TOK_ORASSIGN; } /* digraphs */ "<:" { loc(); return '['; } @@ -1257,7 +1257,7 @@ __decltype { if(PARSER.cpp98 && PARSER.mode==ansi_c_parsert::GCC) { -{identifier} { return make_identifier(); } +{identifier} { return make_identifier(); } {integer_s} { newstack(yyansi_clval); stack(yyansi_clval)=convert_integer_literal(yytext); @@ -1265,24 +1265,24 @@ __decltype { if(PARSER.cpp98 && PARSER.mode==ansi_c_parsert::GCC) return TOK_INTEGER; } -{gcc_ext_float_s} { if(PARSER.mode!=ansi_c_parsert::GCC) +{gcc_ext_float_s} { if(PARSER.mode!=ansi_c_parsert::GCC) { - yyansi_cerror("Preprocessor directive found"); - return TOK_SCANNER_ERROR; + yyansi_cerror("Preprocessor directive found"); + return TOK_SCANNER_ERROR; } - newstack(yyansi_clval); - stack(yyansi_clval)=convert_float_literal(yytext); - PARSER.set_source_location(stack(yyansi_clval)); - return TOK_FLOATING; - } + newstack(yyansi_clval); + stack(yyansi_clval)=convert_float_literal(yytext); + PARSER.set_source_location(stack(yyansi_clval)); + return TOK_FLOATING; + } -{float_s} { newstack(yyansi_clval); +{float_s} { newstack(yyansi_clval); stack(yyansi_clval)=convert_float_literal(yytext); PARSER.set_source_location(stack(yyansi_clval)); - return TOK_FLOATING; - } + return TOK_FLOATING; + } -"{" { +"{" { PARSER.tag_following=false; if(PARSER.asm_block_following) { BEGIN(ASM_BLOCK); } loc(); @@ -1296,7 +1296,7 @@ __decltype { if(PARSER.cpp98 && PARSER.mode==ansi_c_parsert::GCC) } /* This catches all one-character operators */ -. { loc(); PARSER.tag_following=false; return yytext[0]; } +. { loc(); PARSER.tag_following=false; return yytext[0]; } } "]" { BEGIN(GRAMMAR); } @@ -1419,7 +1419,7 @@ __decltype { if(PARSER.cpp98 && PARSER.mode==ansi_c_parsert::GCC) } {ws} { /* ignore */ } {newline} { /* ignore */ } -{identifier} { return make_identifier(); } +{identifier} { return make_identifier(); } . { loc(); return yytext[0]; } } @@ -1442,7 +1442,7 @@ __decltype { if(PARSER.cpp98 && PARSER.mode==ansi_c_parsert::GCC) . { BEGIN(GRAMMAR); loc(); return yytext[0]; } } -<> { yyterminate(); /* done! */ } +<> { yyterminate(); /* done! */ } %% diff --git a/src/assembler/scanner.l b/src/assembler/scanner.l index 55a10ad142c..1ae46542e02 100644 --- a/src/assembler/scanner.l +++ b/src/assembler/scanner.l @@ -23,23 +23,23 @@ newline [\n\f\v]|"\\\n" whitespace {delimiter}+ ws {delimiter}* ws_or_newline ({delimiter}|{newline})* -ucletter [A-Z] -lcletter [a-z] -letter ({ucletter}|{lcletter}) -digit [0-9] -bindigit [01] -octdigit [0-7] -hexdigit [0-9a-fA-F] -identifier (({letter}|"_"|"$"|".")({letter}|{digit}|"_"|"$"|".")*) -integer {digit}+ -binary {bindigit}+ -bininteger "0"[bB]{bindigit}+{int_suffix} -decinteger [1-9]{digit}*{int_suffix} -octinteger "0"{octdigit}*{int_suffix} -hexinteger "0"[xX]{hexdigit}+{int_suffix} +ucletter [A-Z] +lcletter [a-z] +letter ({ucletter}|{lcletter}) +digit [0-9] +bindigit [01] +octdigit [0-7] +hexdigit [0-9a-fA-F] +identifier (({letter}|"_"|"$"|".")({letter}|{digit}|"_"|"$"|".")*) +integer {digit}+ +binary {bindigit}+ +bininteger "0"[bB]{bindigit}+{int_suffix} +decinteger [1-9]{digit}*{int_suffix} +octinteger "0"{octdigit}*{int_suffix} +hexinteger "0"[xX]{hexdigit}+{int_suffix} integer_s {decinteger}|{bininteger}|{octinteger}|{hexinteger} -octchar "\\"{octdigit}{1,3} -hexchar "\\x"{hexdigit}+ +octchar "\\"{octdigit}{1,3} +hexchar "\\x"{hexdigit}+ escape_sequence [\\][^\n] c_char [^'\\\n]|{escape_sequence} @@ -62,46 +62,44 @@ void assemlber_scanner_init() %% .|\n { BEGIN(GRAMMAR); - yyless(0); /* start again with this character */ - } + yyless(0); /* start again with this character */ + } -"#" { PARSER.new_instruction(); BEGIN(LINE_COMMENT); } /* begin comment state */ +"#" { PARSER.new_instruction(); BEGIN(LINE_COMMENT); } /* begin comment state */ { - \n { BEGIN(GRAMMAR); } /* end comment state, back GRAMMAR */ - .* { } /* all characters within comments are ignored */ - } + \n { BEGIN(GRAMMAR); } /* end comment state, back GRAMMAR */ + .* { } /* all characters within comments are ignored */ +} -{newline} { PARSER.new_instruction(); } -";" { PARSER.new_instruction(); } -{whitespace} { } /* skipped */ +{newline} { PARSER.new_instruction(); } +";" { PARSER.new_instruction(); } +{whitespace} { } /* skipped */ -%{ -/*** keywords ***/ -%} + /*** keywords ***/ { -".data" { } +".data" { } } -%{ -/*** rest ***/ -%} + /*** rest ***/ { -{ws} { /* ignore */ } -{identifier} { irept identifier(ID_symbol); - identifier.set(ID_identifier, yytext); - PARSER.add_token(identifier); } +{ws} { /* ignore */ } +{identifier} { irept identifier(ID_symbol); + identifier.set(ID_identifier, yytext); + PARSER.add_token(identifier); + } ">>" { PARSER.add_token(irept(ID_shr)); } "<<" { PARSER.add_token(irept(ID_shl)); } . { std::string s; s+=yytext[0]; - PARSER.add_token(irept(s)); } + PARSER.add_token(irept(s)); + } } -<> { yyterminate(); /* done! */ } +<> { yyterminate(); /* done! */ } %% diff --git a/src/common b/src/common index 3c2659db467..1fab097b524 100644 --- a/src/common +++ b/src/common @@ -100,7 +100,7 @@ else ifeq ($(BUILD_ENV_),Cygwin) CP_CXXFLAGS = -MMD -MP -std=c++11 -U__STRICT_ANSI__ LINKFLAGS = -static -std=c++11 LINKLIB = ar rcT $@ $^ - LINKBIN = $(CXX) $(LINKFLAGS) -o $@ -Wl,--start-group $^ -Wl,--end-group $(LIBS) -static + LINKBIN = $(CXX) $(LINKFLAGS) -o $@ -Wl,--start-group $^ -Wl,--end-group $(LIBS) -static LINKNATIVE = $(HOSTCXX) -std=c++11 -o $@ $^ -static ifeq ($(origin CC),default) #CC = gcc @@ -127,7 +127,7 @@ else ifeq ($(BUILD_ENV_),MSVC) CFLAGS ?= /W3 /O2 /GF CXXFLAGS ?= /W3 /D_CRT_SECURE_NO_WARNINGS /O2 /GF CP_CFLAGS = - CP_CXXFLAGS = + CP_CXXFLAGS = LINKLIB = lib /NOLOGO /OUT:$@ $^ LINKBIN = $(CXX) $(LINKFLAGS) /Fe$@ $^ $(LIBS) LINKNATIVE = $(HOSTCXX) /Fe$@ $^ @@ -161,7 +161,7 @@ CP_CXXFLAGS += $(CXXFLAGS) $(INCLUDES) OBJ += $(patsubst %.cpp, %$(OBJEXT), $(filter %.cpp, $(SRC))) OBJ += $(patsubst %.cc, %$(OBJEXT), $(filter %.cc, $(SRC))) -.SUFFIXES: .cc .d .cpp +.SUFFIXES: .cc .d .cpp %.o:%.cpp $(CXX) -c $(CP_CXXFLAGS) -o $@ $< diff --git a/src/json/parser.y b/src/json/parser.y index e08345f40a9..1273c5cf087 100644 --- a/src/json/parser.y +++ b/src/json/parser.y @@ -58,11 +58,11 @@ int yyjsonerror(const std::string &error) %} -%token TOK_STRING -%token TOK_NUMBER -%token TOK_TRUE -%token TOK_FALSE -%token TOK_NULL +%token TOK_STRING +%token TOK_NUMBER +%token TOK_TRUE +%token TOK_FALSE +%token TOK_NULL %% diff --git a/src/json/scanner.l b/src/json/scanner.l index 45c7c7ca2f1..ee2435559e4 100644 --- a/src/json/scanner.l +++ b/src/json/scanner.l @@ -20,27 +20,27 @@ static int isatty(int) { return 0; } #include "json_y.tab.h" %} -string \"\"|\"{chars}\" -chars {char}+ -char [^\"]|\\\" - -number {int}|{int}{frac}|{int}{exp}|{int}{frac}{exp} -int {digit}|{digit19}{digits}|-{digit}|-{digit19}{digits} -frac "."{digits} -exp e{digits} -digits {digit}+ +string \"\"|\"{chars}\" +chars {char}+ +char [^\"]|\\\" + +number {int}|{int}{frac}|{int}{exp}|{int}{frac}{exp} +int {digit}|{digit19}{digits}|-{digit}|-{digit19}{digits} +frac "."{digits} +exp {e}{digits} +digits {digit}+ digit [0-9] digit19 [1-9] -e e|e\+|e-|E|E\+|E- +e e|e\+|e-|E|E\+|E- %% -{string} { return TOK_STRING; } -{number} { return TOK_NUMBER; } -"true" { return TOK_TRUE; } -"false" { return TOK_FALSE; } -"null" { return TOK_NULL; } +{string} { return TOK_STRING; } +{number} { return TOK_NUMBER; } +"true" { return TOK_TRUE; } +"false" { return TOK_FALSE; } +"null" { return TOK_NULL; } -[" "\r\n\t] { /* eat */ } -. { return yytext[0]; } +[" "\r\n\t] { /* eat */ } +. { return yytext[0]; } diff --git a/src/xmllang/parser.y b/src/xmllang/parser.y index 5bfd4a2ef3d..727c4c947db 100644 --- a/src/xmllang/parser.y +++ b/src/xmllang/parser.y @@ -48,7 +48,7 @@ misc_seq_opt ; misc - : COMMENT { free($1); } + : COMMENT { free($1); } | PI ; @@ -58,24 +58,24 @@ PI attribute_seq_opt { xml_parser.stack.pop_back(); } ENDPI - ; + ; element - : START { xml_parser.current().name=$1; + : START { xml_parser.current().name=$1; free($1); - } + } attribute_seq_opt empty_or_content ; empty_or_content - : SLASH CLOSE { } - | CLOSE { } - content END name_opt CLOSE { free($5); } + : SLASH CLOSE { } + | CLOSE { } + content END name_opt CLOSE { free($5); } ; content - : content DATA { xml_parser.current().data+=xmlt::unescape($2); free($2); } + : content DATA { xml_parser.current().data+=xmlt::unescape($2); free($2); } | content misc | content { xml_parser.new_level(); } @@ -85,8 +85,8 @@ content ; name_opt - : NAME { $$=$1; } - | /*empty*/ { $$=strdup(""); } + : NAME { $$=$1; } + | /*empty*/ { $$=strdup(""); } ; attribute_seq_opt @@ -95,7 +95,7 @@ attribute_seq_opt ; attribute - : NAME EQ VALUE { xml_parser.current().set_attribute( + : NAME EQ VALUE { xml_parser.current().set_attribute( xmlt::unescape($1), xmlt::unescape($3)); free($1); free($3);} ; diff --git a/src/xmllang/scanner.l b/src/xmllang/scanner.l index 281aaecab01..9db5f50c243 100644 --- a/src/xmllang/scanner.l +++ b/src/xmllang/scanner.l @@ -17,7 +17,7 @@ static int isatty(int) { return 0; } #define PARSER xml_parser -//static int keep; /* To store start condition */ +//static int keep; /* To store start condition */ static char *word(char *s) { @@ -34,17 +34,17 @@ static char *word(char *s) %} -nl (\r\n|\r|\n) -ws [ \t\r\n]+ -open {nl}?"<" -close ">"{nl}? -namestart [A-Za-z\200-\377_] -namechar [A-Za-z\200-\377_0-9.:-] -esc "&#"[0-9]+";"|"&#x"[0-9a-fA-F]+";"|"&"[a-zA-Z]+";" -name {namestart}{namechar}* -data ([^<\n&]|\n[^<&]|\n{esc}|{esc})+ -comment {open}"!--"([^-]|"-"[^-])*"--"{close} -string \"([^"&]|{esc})*\"|\'([^'&]|{esc})*\' +nl (\r\n|\r|\n) +ws [ \t\r\n]+ +open {nl}?"<" +close ">"{nl}? +namestart [A-Za-z\200-\377_] +namechar [A-Za-z\200-\377_0-9.:-] +esc "&#"[0-9]+";"|"&#x"[0-9a-fA-F]+";"|"&"[a-zA-Z]+";" +name {namestart}{namechar}* +data ([^<\n&]|\n[^<&]|\n{esc}|{esc})+ +comment {open}"!--"([^-]|"-"[^-])*"--"{close} +string \"([^"&]|{esc})*\"|\'([^'&]|{esc})*\' /* * The CONTENT mode is used for the content of elements, i.e., @@ -59,28 +59,28 @@ string \"([^"&]|{esc})*\"|\'([^'&]|{esc})*\' %% -{ws} {/* skip */} -"/" {return SLASH;} -"=" {return EQ;} -{close} {BEGIN(CONTENT); return CLOSE;} -{name} {yyxmllval.s=strdup(yytext); return NAME;} -{string} {yyxmllval.s=strdup(yytext); return VALUE;} -"?"{close} {BEGIN(INITIAL); return ENDPI;} +{ws} {/* skip */} +"/" {return SLASH;} +"=" {return EQ;} +{close} {BEGIN(CONTENT); return CLOSE;} +{name} {yyxmllval.s=strdup(yytext); return NAME;} +{string} {yyxmllval.s=strdup(yytext); return VALUE;} +"?"{close} {BEGIN(INITIAL); return ENDPI;} -{open}{ws}?{name} {BEGIN(INITIAL); yyxmllval.s=word(yytext); return START;} -{open}{ws}?"/" {BEGIN(INITIAL); return END;} -{open}"?xml" {BEGIN(INITIAL); return STARTXMLDECL;} -{open}"?" {BEGIN(PI); yyxmllval.s=word(yytext); return STARTPI;} -{comment} {yyxmllval.s=strdup(yytext); return COMMENT;} +{open}{ws}?{name} {BEGIN(INITIAL); yyxmllval.s=word(yytext); return START;} +{open}{ws}?"/" {BEGIN(INITIAL); return END;} +{open}"?xml" {BEGIN(INITIAL); return STARTXMLDECL;} +{open}"?" {BEGIN(PI); yyxmllval.s=word(yytext); return STARTPI;} +{comment} {yyxmllval.s=strdup(yytext); return COMMENT;} -{data} {yyxmllval.s=strdup(yytext); return DATA;} +{data} {yyxmllval.s=strdup(yytext); return DATA;} {open}"!"{ws}?"DOCTYPE" {BEGIN(DTD); /* skip */} -. {/* skip */} +. {/* skip */} \]{close} {BEGIN(INITIAL); /* skip */} -. { yyxmlerror("unexpected character"); } -{nl} {/* skip, must be an extra one at EOF */;} +. { yyxmlerror("unexpected character"); } +{nl} {/* skip, must be an extra one at EOF */;} %% From fe7d0f0b4dfeddb0e49a5baa7017d2c4f7b58ea5 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Wed, 18 May 2016 11:49:46 +0100 Subject: [PATCH 035/101] new interface for run() --- src/goto-cc/gcc_mode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/goto-cc/gcc_mode.cpp b/src/goto-cc/gcc_mode.cpp index 6401cd780bf..3991aa823bc 100644 --- a/src/goto-cc/gcc_mode.cpp +++ b/src/goto-cc/gcc_mode.cpp @@ -657,7 +657,7 @@ int gcc_modet::gcc_hybrid_binary() std::cout << std::endl; #endif - int result=run(new_argv[0], new_argv); + int result=run(new_argv[0], new_argv, ""); // merge output from gcc with goto-binaries // using objcopy, or do cleanup if an earlier call failed From 2a337943edb9b62f80a6b35db4c32eea32886390 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Wed, 18 May 2016 12:16:44 +0100 Subject: [PATCH 036/101] do generate dummy code for empty ifthenelse --- src/goto-programs/goto_convert.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/goto-programs/goto_convert.cpp b/src/goto-programs/goto_convert.cpp index 650db34e3ee..4297ceb8b8e 100644 --- a/src/goto-programs/goto_convert.cpp +++ b/src/goto-programs/goto_convert.cpp @@ -2151,7 +2151,17 @@ void goto_convertt::generate_ifthenelse( { if(is_empty(true_case) && is_empty(false_case)) + { + // hmpf. Useless branch. + goto_programt tmp_z; + goto_programt::targett z=tmp_z.add_instruction(); + z->make_skip(); + goto_programt::targett v=dest.add_instruction(); + v->make_goto(z, guard); + v->source_location=source_location; + dest.destructive_append(tmp_z); return; + } // do guarded gotos directly if(is_empty(false_case) && From 7de7b08b047a5d9c32ab9f2463175a8018a3042f Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Wed, 18 May 2016 12:41:05 +0100 Subject: [PATCH 037/101] conjunction and disjunction on lists --- src/util/std_expr.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++ src/util/std_expr.h | 18 +++++++++++++-- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/util/std_expr.cpp b/src/util/std_expr.cpp index 42fb6f13201..d19fcc3de07 100644 --- a/src/util/std_expr.cpp +++ b/src/util/std_expr.cpp @@ -64,6 +64,33 @@ exprt disjunction(const exprt::operandst &op) /*******************************************************************\ +Function: disjunction + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt disjunction(const std::list &op) +{ + if(op.empty()) + return false_exprt(); + else if(op.size()==1) + return op.front(); + else + { + or_exprt result; + result.operands().resize(op.size()); + for(const auto & e : op) result.operands().push_back(e); + return result; + } +} + +/*******************************************************************\ + Function: conjunction Inputs: @@ -90,6 +117,33 @@ exprt conjunction(const exprt::operandst &op) /*******************************************************************\ +Function: conjunction + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt conjunction(const std::list &op) +{ + if(op.empty()) + return true_exprt(); + else if(op.size()==1) + return op.front(); + else + { + and_exprt result; + result.operands().resize(op.size()); + for(const auto & e : op) result.operands().push_back(e); + return result; + } +} + +/*******************************************************************\ + Function: build_object_descriptor_rec Inputs: diff --git a/src/util/std_expr.h b/src/util/std_expr.h index 288bc23f11e..449038a9975 100644 --- a/src/util/std_expr.h +++ b/src/util/std_expr.h @@ -1720,7 +1720,14 @@ class and_exprt:public exprt * 3) returns true otherwise */ -exprt conjunction(const exprt::operandst &op); +exprt conjunction(const exprt::operandst &); + +/*! 1) generates a conjunction for two or more operands + * 2) for one operand, returns the operand + * 3) returns true otherwise +*/ + +exprt conjunction(const std::list &); /*! \brief Cast a generic exprt to a \ref and_exprt * @@ -1822,7 +1829,14 @@ class or_exprt:public exprt * 3) returns false otherwise */ -exprt disjunction(const exprt::operandst &op); +exprt disjunction(const exprt::operandst &); + +/*! 1) generates a disjunction for two or more operands + * 2) for one operand, returns the operand + * 3) returns false otherwise +*/ + +exprt disjunction(const std::list &); /*! \brief Cast a generic exprt to a \ref or_exprt * From 62e3ce7ddb52007862405c05a2c0a8d3140b03e8 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Wed, 18 May 2016 12:41:22 +0100 Subject: [PATCH 038/101] fix output of literal expressions --- src/ansi-c/expr2c.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/ansi-c/expr2c.cpp b/src/ansi-c/expr2c.cpp index c372206f597..f4dcac5616a 100644 --- a/src/ansi-c/expr2c.cpp +++ b/src/ansi-c/expr2c.cpp @@ -1260,10 +1260,7 @@ std::string expr2ct::convert_literal( const exprt &src, unsigned &precedence) { - if(src.operands().size()==1) - return "L("+src.get_string(ID_literal)+")"; - else - return convert_norep(src, precedence); + return "L("+src.get_string(ID_literal)+")"; } /*******************************************************************\ @@ -4501,8 +4498,6 @@ std::string expr2ct::convert( return convert_prob_coin(src, precedence=16); else if(statement=="prob_unif") return convert_prob_uniform(src, precedence=16); - else if(statement==ID_literal) - return convert_literal(src, precedence=16); else if(statement==ID_statement_expression) return convert_statement_expression(src, precedence=15); else if(statement==ID_gcc_builtin_va_arg_next) @@ -4511,6 +4506,9 @@ std::string expr2ct::convert( return convert_norep(src, precedence); } + else if(src.id()==ID_literal) + return convert_literal(src, precedence=16); + else if(src.id()==ID_not) return convert_unary(src, "!", precedence=15); From eac49f24d21f0c9fadb637194ebbe8c7c9131bb4 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Wed, 18 May 2016 12:47:41 +0100 Subject: [PATCH 039/101] conjunction and disjunction now take initializer_lists --- src/util/std_expr.cpp | 18 ++++++++---------- src/util/std_expr.h | 6 ++++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/util/std_expr.cpp b/src/util/std_expr.cpp index d19fcc3de07..eabec0081f5 100644 --- a/src/util/std_expr.cpp +++ b/src/util/std_expr.cpp @@ -74,17 +74,16 @@ Function: disjunction \*******************************************************************/ -exprt disjunction(const std::list &op) +exprt disjunction(const std::initializer_list &op) { - if(op.empty()) + if(op.size()==0) return false_exprt(); else if(op.size()==1) - return op.front(); + return *op.begin(); else { or_exprt result; - result.operands().resize(op.size()); - for(const auto & e : op) result.operands().push_back(e); + result.operands()=exprt::operandst(op); return result; } } @@ -127,17 +126,16 @@ Function: conjunction \*******************************************************************/ -exprt conjunction(const std::list &op) +exprt conjunction(const std::initializer_list &op) { - if(op.empty()) + if(op.size()==0) return true_exprt(); else if(op.size()==1) - return op.front(); + return *op.begin(); else { and_exprt result; - result.operands().resize(op.size()); - for(const auto & e : op) result.operands().push_back(e); + result.operands()=exprt::operandst(op); return result; } } diff --git a/src/util/std_expr.h b/src/util/std_expr.h index 449038a9975..6408c63bb9d 100644 --- a/src/util/std_expr.h +++ b/src/util/std_expr.h @@ -18,6 +18,8 @@ Author: Daniel Kroening, kroening@kroening.com #include +#include + #include "std_types.h" /*! \defgroup gr_std_expr Conversion to specific expressions @@ -1727,7 +1729,7 @@ exprt conjunction(const exprt::operandst &); * 3) returns true otherwise */ -exprt conjunction(const std::list &); +exprt conjunction(const std::initializer_list &); /*! \brief Cast a generic exprt to a \ref and_exprt * @@ -1836,7 +1838,7 @@ exprt disjunction(const exprt::operandst &); * 3) returns false otherwise */ -exprt disjunction(const std::list &); +exprt disjunction(const std::initializer_list &); /*! \brief Cast a generic exprt to a \ref or_exprt * From 4996502107d4957a4f16b7e43a5248898aacdccf Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Wed, 18 May 2016 12:52:59 +0100 Subject: [PATCH 040/101] get rid of conjunction and disjunction taking initializer_lists --- src/util/std_expr.cpp | 52 ------------------------------------------- src/util/std_expr.h | 16 ------------- 2 files changed, 68 deletions(-) diff --git a/src/util/std_expr.cpp b/src/util/std_expr.cpp index eabec0081f5..42fb6f13201 100644 --- a/src/util/std_expr.cpp +++ b/src/util/std_expr.cpp @@ -64,32 +64,6 @@ exprt disjunction(const exprt::operandst &op) /*******************************************************************\ -Function: disjunction - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -exprt disjunction(const std::initializer_list &op) -{ - if(op.size()==0) - return false_exprt(); - else if(op.size()==1) - return *op.begin(); - else - { - or_exprt result; - result.operands()=exprt::operandst(op); - return result; - } -} - -/*******************************************************************\ - Function: conjunction Inputs: @@ -116,32 +90,6 @@ exprt conjunction(const exprt::operandst &op) /*******************************************************************\ -Function: conjunction - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -exprt conjunction(const std::initializer_list &op) -{ - if(op.size()==0) - return true_exprt(); - else if(op.size()==1) - return *op.begin(); - else - { - and_exprt result; - result.operands()=exprt::operandst(op); - return result; - } -} - -/*******************************************************************\ - Function: build_object_descriptor_rec Inputs: diff --git a/src/util/std_expr.h b/src/util/std_expr.h index 6408c63bb9d..6f9f665326c 100644 --- a/src/util/std_expr.h +++ b/src/util/std_expr.h @@ -18,8 +18,6 @@ Author: Daniel Kroening, kroening@kroening.com #include -#include - #include "std_types.h" /*! \defgroup gr_std_expr Conversion to specific expressions @@ -1724,13 +1722,6 @@ class and_exprt:public exprt exprt conjunction(const exprt::operandst &); -/*! 1) generates a conjunction for two or more operands - * 2) for one operand, returns the operand - * 3) returns true otherwise -*/ - -exprt conjunction(const std::initializer_list &); - /*! \brief Cast a generic exprt to a \ref and_exprt * * This is an unchecked conversion. \a expr must be known to be \ref @@ -1833,13 +1824,6 @@ class or_exprt:public exprt exprt disjunction(const exprt::operandst &); -/*! 1) generates a disjunction for two or more operands - * 2) for one operand, returns the operand - * 3) returns false otherwise -*/ - -exprt disjunction(const std::initializer_list &); - /*! \brief Cast a generic exprt to a \ref or_exprt * * This is an unchecked conversion. \a expr must be known to be \ref From e35f6b7fff772127475176e1b026df096a8d41ad Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Wed, 18 May 2016 12:59:41 +0100 Subject: [PATCH 041/101] fix for bmc_cover --- src/cbmc/bmc_cover.cpp | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/src/cbmc/bmc_cover.cpp b/src/cbmc/bmc_cover.cpp index 0ff2231eee3..dd27eb46e31 100644 --- a/src/cbmc/bmc_cover.cpp +++ b/src/cbmc/bmc_cover.cpp @@ -146,13 +146,9 @@ class bmc_covert: } }; - inline irep_idt id( - goto_programt::const_targett loc, - const std::string suffix="") + inline irep_idt id(goto_programt::const_targett loc) { - return id2string(loc->function)+ - "#"+i2string(loc->location_number)+ - suffix; + return loc->source_location.get_property_id(); } typedef std::map goal_mapt; @@ -261,20 +257,6 @@ bool bmc_covert::operator()() // stop the time absolute_timet sat_start=current_time(); - // we don't want the assertions to become constraints - for(symex_target_equationt::SSA_stepst::iterator - it=bmc.equation.SSA_steps.begin(); - it!=bmc.equation.SSA_steps.end(); - it++) - if(it->type==goto_trace_stept::ASSERT) - it->type=goto_trace_stept::LOCATION; - - bmc.do_conversion(); - - //bmc.equation.output(std::cout); - - std::map location_map; - // Collect _all_ goals in `goal_map'. // This maps property IDs to 'goalt' forall_goto_functions(f_it, goto_functions) @@ -291,6 +273,12 @@ bool bmc_covert::operator()() } } + // Do conversion to next solver layer + + bmc.do_conversion(); + + //bmc.equation.output(std::cout); + // collects assumptions and_exprt::operandst assumptions; @@ -306,9 +294,13 @@ bool bmc_covert::operator()() if(it->source.pc->is_assert()) { - and_exprt c_expr(conjunction(assumptions), literal_exprt(it->guard_literal)); - literalt c=solver.convert(c_expr); - goal_map[id(it->source.pc)].add_instance(it, c); + exprt c= + conjunction({ + conjunction(assumptions), + literal_exprt(it->guard_literal), + literal_exprt(it->cond_literal) }); + literalt l_c=solver.convert(c); + goal_map[id(it->source.pc)].add_instance(it, l_c); } } From 3f01cce50a9387c4d6b4c4fee8532bf4d418e105 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Sun, 17 Apr 2016 14:15:32 +0000 Subject: [PATCH 042/101] Support __attribute__((constructor)) --- src/ansi-c/ansi_c_convert_type.cpp | 31 +++++++++++++++++++++++++ src/ansi-c/ansi_c_convert_type.h | 3 ++- src/ansi-c/expr2c.cpp | 5 ++++ src/ansi-c/parser.y | 6 +++++ src/ansi-c/scanner.l | 6 +++++ src/cpp/cpp_typecheck.cpp | 3 +-- src/linking/remove_internal_symbols.cpp | 9 +++++++ src/linking/static_lifetime_init.cpp | 4 ++-- 8 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/ansi-c/ansi_c_convert_type.cpp b/src/ansi-c/ansi_c_convert_type.cpp index 618568bd5da..e35aa32d9b6 100644 --- a/src/ansi-c/ansi_c_convert_type.cpp +++ b/src/ansi-c/ansi_c_convert_type.cpp @@ -229,6 +229,10 @@ void ansi_c_convert_typet::read_rec(const typet &type) } else if(type.id()==ID_noreturn) c_qualifiers.is_noreturn=true; + else if(type.id()==ID_constructor) + constructor=true; + else if(type.id()==ID_destructor) + destructor=true; else other.push_back(type); } @@ -274,6 +278,33 @@ void ansi_c_convert_typet::write(typet &type) } type.swap(other.front()); + + if(constructor || destructor) + { + if(constructor && destructor) + { + err_location(source_location); + str << "combining constructor and destructor not supported"; + error_msg(); + throw 0; + } + else if(type.id()!=ID_empty) + { + err_location(source_location); + str << "constructor and destructor required to be type void"; + error_msg(); + throw 0; + } + + type.id(constructor ? ID_constructor : ID_destructor); + } + } + else if(constructor || destructor) + { + err_location(source_location); + str << "constructor and destructor required to be type void"; + error_msg(); + throw 0; } else if(gcc_float128_cnt) { diff --git a/src/ansi-c/ansi_c_convert_type.h b/src/ansi-c/ansi_c_convert_type.h index eff7353dffd..a40d3f3549e 100644 --- a/src/ansi-c/ansi_c_convert_type.h +++ b/src/ansi-c/ansi_c_convert_type.h @@ -34,6 +34,7 @@ class ansi_c_convert_typet:public message_streamt bool packed, aligned; exprt vector_size, alignment, bv_width, fraction_width; exprt msc_based; // this is Visual Studio + bool constructor, destructor; // storage spec c_storage_spect c_storage_spec; @@ -67,7 +68,7 @@ class ansi_c_convert_typet:public message_streamt msc_based.make_nil(); gcc_attribute_mode.make_nil(); - packed=aligned=false; + packed=aligned=constructor=destructor=false; other.clear(); c_storage_spec.clear(); diff --git a/src/ansi-c/expr2c.cpp b/src/ansi-c/expr2c.cpp index f4dcac5616a..c8797e8c726 100644 --- a/src/ansi-c/expr2c.cpp +++ b/src/ansi-c/expr2c.cpp @@ -694,6 +694,11 @@ std::string expr2ct::convert_rec( { return q+"__builtin_va_list"+d; } + else if(src.id()==ID_constructor || + src.id()==ID_destructor) + { + return q+"__attribute__(("+id2string(src.id())+")) void"+d; + } { lispexprt lisp; diff --git a/src/ansi-c/parser.y b/src/ansi-c/parser.y index 4e404c94a3a..a933daafe29 100644 --- a/src/ansi-c/parser.y +++ b/src/ansi-c/parser.y @@ -133,6 +133,8 @@ extern char *yyansi_ctext; %token TOK_GCC_ATTRIBUTE_GNU_INLINE "__gnu_inline__" %token TOK_GCC_ATTRIBUTE_WEAK "weak" %token TOK_GCC_ATTRIBUTE_NORETURN "noreturn" +%token TOK_GCC_ATTRIBUTE_CONSTRUCTOR "constructor" +%token TOK_GCC_ATTRIBUTE_DESTRUCTOR "destructor" %token TOK_GCC_ATTRIBUTE_END ")" %token TOK_GCC_LABEL "__label__" %token TOK_MSC_ASM "__asm" @@ -1566,6 +1568,10 @@ gcc_type_attribute: { $$=$1; set($$, ID_noreturn); } | TOK_GCC_ATTRIBUTE_NORETURN TOK_GCC_ATTRIBUTE_END { $$=$1; set($$, ID_noreturn); } + | TOK_GCC_ATTRIBUTE_CONSTRUCTOR TOK_GCC_ATTRIBUTE_END + { $$=$1; set($$, ID_constructor); } + | TOK_GCC_ATTRIBUTE_DESTRUCTOR TOK_GCC_ATTRIBUTE_END + { $$=$1; set($$, ID_destructor); } | gcc_attribute_specifier ; diff --git a/src/ansi-c/scanner.l b/src/ansi-c/scanner.l index 977f428231e..fa9284bc888 100644 --- a/src/ansi-c/scanner.l +++ b/src/ansi-c/scanner.l @@ -1378,6 +1378,12 @@ __decltype { if(PARSER.cpp98 && PARSER.mode==ansi_c_parsert::GCC) "noreturn" | "__noreturn__" { BEGIN(GCC_ATTRIBUTE3); loc(); return TOK_GCC_ATTRIBUTE_NORETURN; } +"constructor" | +"__constructor__" { BEGIN(GCC_ATTRIBUTE3); loc(); return TOK_GCC_ATTRIBUTE_CONSTRUCTOR; } + +"destructor" | +"__destructor__" { BEGIN(GCC_ATTRIBUTE3); loc(); return TOK_GCC_ATTRIBUTE_DESTRUCTOR; } + {ws} { /* ignore */ } {newline} { /* ignore */ } {identifier} { BEGIN(GCC_ATTRIBUTE4); } diff --git a/src/cpp/cpp_typecheck.cpp b/src/cpp/cpp_typecheck.cpp index 232b494849b..73230c0723a 100644 --- a/src/cpp/cpp_typecheck.cpp +++ b/src/cpp/cpp_typecheck.cpp @@ -301,8 +301,7 @@ void cpp_typecheckt::static_and_dynamic_initialization() init_symbol.mode=ID_cpp; init_symbol.module=module; init_symbol.type=code_typet(); - init_symbol.type.add(ID_return_type)=typet(ID_empty); - init_symbol.type.set("initialization", true); + init_symbol.type.add(ID_return_type)=typet(ID_constructor); init_symbol.is_type=false; init_symbol.is_macro=false; diff --git a/src/linking/remove_internal_symbols.cpp b/src/linking/remove_internal_symbols.cpp index 71c801254ce..cdb59b3baa9 100644 --- a/src/linking/remove_internal_symbols.cpp +++ b/src/linking/remove_internal_symbols.cpp @@ -132,6 +132,15 @@ void remove_internal_symbols( symbol.value.is_not_nil() && !symbol.value.get_bool(ID_C_zero_initializer); + // __attribute__((constructor)), __attribute__((destructor)) + if(symbol.mode==ID_C && is_function && is_file_local) + { + const code_typet &code_type=to_code_type(symbol.type); + if(code_type.return_type().id()==ID_constructor || + code_type.return_type().id()==ID_destructor) + is_file_local=false; + } + if(is_type) { // never EXPORTED by itself diff --git a/src/linking/static_lifetime_init.cpp b/src/linking/static_lifetime_init.cpp index 6c909e19d11..096a4e7f749 100644 --- a/src/linking/static_lifetime_init.cpp +++ b/src/linking/static_lifetime_init.cpp @@ -160,8 +160,8 @@ bool static_lifetime_init( { const symbolt &symbol=ns.lookup(id); - if(symbol.type.get_bool("initialization") && - symbol.type.id()==ID_code) + if(symbol.type.id()==ID_code && + to_code_type(symbol.type).return_type().id()==ID_constructor) { code_function_callt function_call; function_call.function()=symbol.symbol_expr(); From 838e780787ecb153e3fc3daa1d9cc56ef1637802 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Fri, 18 Mar 2016 09:01:04 +0000 Subject: [PATCH 043/101] Extended linking conflict reporting --- src/linking/linking.cpp | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/linking/linking.cpp b/src/linking/linking.cpp index a5533b4d4d3..b07a82bb119 100644 --- a/src/linking/linking.cpp +++ b/src/linking/linking.cpp @@ -217,6 +217,8 @@ void linkingt::detailed_conflict_report_rec( const struct_union_typet::componentst &components2= to_struct_union_type(t2).components(); + exprt conflict_path_before=conflict_path; + if(components1.size()!=components2.size()) { msg="number of members is different ("; @@ -238,11 +240,25 @@ void linkingt::detailed_conflict_report_rec( } else if(!base_type_eq(subtype1, subtype2, ns)) { + typedef hash_set_cont type_sett; + type_sett parent_types; + + exprt e=conflict_path_before; + while(e.id()==ID_dereference || + e.id()==ID_member || + e.id()==ID_index) + { + parent_types.insert(e.type()); + e=e.op0(); + } + + conflict_path=conflict_path_before; conflict_path.type()=t1; conflict_path= member_exprt(conflict_path, components1[i].get_name()); - if(depth>0) + if(depth>0 && + parent_types.find(t1)==parent_types.end()) detailed_conflict_report_rec( old_symbol, new_symbol, @@ -251,11 +267,29 @@ void linkingt::detailed_conflict_report_rec( depth-1, conflict_path); else + { msg="type of member "+ id2string(components1[i].get_name())+ " differs"; + if(depth>0) + { + std::string msg_bak; + msg_bak.swap(msg); + symbol_exprt c(ID_C_this); + detailed_conflict_report_rec( + old_symbol, + new_symbol, + subtype1, + subtype2, + depth-1, + c); + msg.swap(msg_bak); + } - break; + } + + if(parent_types.find(t1)==parent_types.end()) + break; } } } From 9c2b02fceaac1dcbe7276d9a7590161b0e21837a Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Fri, 18 Mar 2016 09:03:34 +0000 Subject: [PATCH 044/101] Permit some (ab)use of void f(void) in place of a full function declaration --- src/linking/linking.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/linking/linking.cpp b/src/linking/linking.cpp index b07a82bb119..35a175744ae 100644 --- a/src/linking/linking.cpp +++ b/src/linking/linking.cpp @@ -597,6 +597,32 @@ void linkingt::duplicate_code_symbol( old_symbol.location=new_symbol.location; } } + // Linux kernel uses void f(void) as generic prototype + else if((old_t.return_type().id()==ID_empty && + old_t.parameters().empty() && + !old_t.has_ellipsis() && + old_symbol.value.is_nil()) || + (new_t.return_type().id()==ID_empty && + new_t.parameters().empty() && + !new_t.has_ellipsis() && + new_symbol.value.is_nil())) + { + // issue a warning + link_warning( + old_symbol, + new_symbol, + "ignoring conflicting void f(void) function declaration"); + + if(old_t.return_type().id()==ID_empty && + old_t.parameters().empty() && + !old_t.has_ellipsis() && + old_symbol.value.is_nil()) + { + old_symbol.type=new_symbol.type; + old_symbol.location=new_symbol.location; + old_symbol.is_weak=new_symbol.is_weak; + } + } // mismatch on number of parameters is definitively an error else if((old_t.parameters().size() Date: Sun, 20 Mar 2016 23:19:31 +0000 Subject: [PATCH 045/101] Fix type renaming of array types with non-constant size --- src/ansi-c/type2name.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ansi-c/type2name.cpp b/src/ansi-c/type2name.cpp index 77533b7b7a4..af24fd311ef 100644 --- a/src/ansi-c/type2name.cpp +++ b/src/ansi-c/type2name.cpp @@ -187,10 +187,10 @@ static std::string type2name( { const array_typet &t=to_array_type(type); mp_integer size; - if(to_integer(t.size(), size)) - result+="ARR?"; - else if(t.size().id()==ID_symbol) + if(t.size().id()==ID_symbol) result+="ARR"+t.size().get_string(ID_identifier); + else if(to_integer(t.size(), size)) + result+="ARR?"; else result+="ARR"+integer2string(size); } From 927b9ff6f812e9b90a1fd5bf7c5eead96be6f8cf Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Sun, 20 Mar 2016 23:21:12 +0000 Subject: [PATCH 046/101] Array-size symbols may also trigger a type renaming --- src/linking/linking.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/linking/linking.cpp b/src/linking/linking.cpp index 35a175744ae..de064c52070 100644 --- a/src/linking/linking.cpp +++ b/src/linking/linking.cpp @@ -1141,7 +1141,7 @@ Function: linkingt::do_type_dependencies void linkingt::do_type_dependencies(id_sett &needs_to_be_renamed) { - // Any type that uses a type that will be renamed also + // Any type that uses a symbol that will be renamed also // needs to be renamed, and so on, until saturation. used_byt used_by; @@ -1150,12 +1150,13 @@ void linkingt::do_type_dependencies(id_sett &needs_to_be_renamed) { if(s_it->second.is_type) { - find_symbols_sett type_symbols_used; - find_type_symbols(s_it->second.type, type_symbols_used); + // find type and array-size symbols + find_symbols_sett symbols_used; + find_type_and_expr_symbols(s_it->second.type, symbols_used); for(find_symbols_sett::const_iterator - it=type_symbols_used.begin(); - it!=type_symbols_used.end(); + it=symbols_used.begin(); + it!=symbols_used.end(); it++) { used_by[*it].insert(s_it->first); From 4030c968dc8e3756594182f5841b942ffb545a8e Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Wed, 24 Feb 2016 10:31:17 +0000 Subject: [PATCH 047/101] Cleanup --- src/ansi-c/parser.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansi-c/parser.y b/src/ansi-c/parser.y index 4e404c94a3a..bcb7051f651 100644 --- a/src/ansi-c/parser.y +++ b/src/ansi-c/parser.y @@ -1983,7 +1983,7 @@ type_name: initializer_opt: /* nothing */ { - newstack($$); + init($$); stack($$).make_nil(); } | '=' initializer From 1eeaf5cd694e2ab3a5748419e1e7a8512c38b88e Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Thu, 31 Mar 2016 21:38:57 +0100 Subject: [PATCH 048/101] Removed unused include --- src/ansi-c/ansi_c_language.cpp | 1 - src/ansi-c/cprover_library.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/ansi-c/ansi_c_language.cpp b/src/ansi-c/ansi_c_language.cpp index 9bc9559beeb..1fa90f9a102 100644 --- a/src/ansi-c/ansi_c_language.cpp +++ b/src/ansi-c/ansi_c_language.cpp @@ -11,7 +11,6 @@ Author: Daniel Kroening, kroening@kroening.com #include #include -#include #include #include diff --git a/src/ansi-c/cprover_library.cpp b/src/ansi-c/cprover_library.cpp index 3db1c632448..79c4a662c15 100644 --- a/src/ansi-c/cprover_library.cpp +++ b/src/ansi-c/cprover_library.cpp @@ -9,7 +9,6 @@ Author: Daniel Kroening, kroening@kroening.com #include #include -#include #include "cprover_library.h" #include "ansi_c_language.h" From bb80cdcc27380242f0b72670ffda919193cac4c9 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 5 Apr 2016 12:12:58 +0000 Subject: [PATCH 049/101] Transparent unions require argument conversion, do this for all union types Also improves the readabilit of error output when argument conversion is denied --- src/goto-symex/symex_function_call.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/goto-symex/symex_function_call.cpp b/src/goto-symex/symex_function_call.cpp index 8ce2d378f2d..cb16ffc7b1d 100644 --- a/src/goto-symex/symex_function_call.cpp +++ b/src/goto-symex/symex_function_call.cpp @@ -7,6 +7,7 @@ Author: Daniel Kroening, kroening@kroening.com \*******************************************************************/ #include +#include #include #include @@ -121,23 +122,30 @@ void goto_symext::parameter_assignments( f_parameter_type.id()==ID_unsignedbv || f_parameter_type.id()==ID_c_enum_tag || f_parameter_type.id()==ID_bool || - f_parameter_type.id()==ID_pointer) && + f_parameter_type.id()==ID_pointer || + f_parameter_type.id()==ID_union) && (f_rhs_type.id()==ID_signedbv || f_rhs_type.id()==ID_unsignedbv || f_rhs_type.id()==ID_c_bit_field || f_rhs_type.id()==ID_c_enum_tag || f_rhs_type.id()==ID_bool || - f_rhs_type.id()==ID_pointer)) + f_rhs_type.id()==ID_pointer || + f_rhs_type.id()==ID_union)) { - rhs.make_typecast(parameter_type); + rhs= + byte_extract_exprt( + byte_extract_id(), + rhs, + gen_zero(index_type()), + parameter_type); } else { - std::string error="function call: parameter \""+ - id2string(identifier)+"\" type mismatch: got "+ - rhs.type().to_string()+", expected "+ - parameter_type.to_string(); - throw error; + std::ostringstream error; + error << "function call: parameter \"" << identifier + << "\" type mismatch: got " << rhs.type().pretty() + << ", expected " << parameter_type.pretty(); + throw error.str(); } } From db61ac8d78ae99583687831ff8a3c991e4ec9d13 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Thu, 17 Mar 2016 22:32:06 +0000 Subject: [PATCH 050/101] Do not skip attributes of pointer types --- src/ansi-c/c_storage_spec.cpp | 3 ++- src/ansi-c/c_typecheck_base.cpp | 18 +++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/ansi-c/c_storage_spec.cpp b/src/ansi-c/c_storage_spec.cpp index 2fa57e55c27..fd8dc27834e 100644 --- a/src/ansi-c/c_storage_spec.cpp +++ b/src/ansi-c/c_storage_spec.cpp @@ -24,7 +24,8 @@ Function: c_storage_spect::read void c_storage_spect::read(const typet &type) { - if(type.id()==ID_merged_type) + if(type.id()==ID_merged_type || + type.id()==ID_code) { forall_subtypes(it, type) read(*it); diff --git a/src/ansi-c/c_typecheck_base.cpp b/src/ansi-c/c_typecheck_base.cpp index 175388b88dd..69938e4960b 100644 --- a/src/ansi-c/c_typecheck_base.cpp +++ b/src/ansi-c/c_typecheck_base.cpp @@ -711,13 +711,6 @@ void c_typecheck_baset::typecheck_declaration( { // get storage spec c_storage_spect c_storage_spec(declaration.type()); - - declaration.set_is_inline(c_storage_spec.is_inline); - declaration.set_is_static(c_storage_spec.is_static); - declaration.set_is_extern(c_storage_spec.is_extern); - declaration.set_is_thread_local(c_storage_spec.is_thread_local); - declaration.set_is_register(c_storage_spec.is_register); - declaration.set_is_typedef(c_storage_spec.is_typedef); // first typecheck the type of the declaration typecheck_type(declaration.type()); @@ -743,6 +736,17 @@ void c_typecheck_baset::typecheck_declaration( d_it!=declaration.declarators().end(); d_it++) { + c_storage_spect full_spec(declaration.full_type(*d_it)); + full_spec|=c_storage_spec; + + declaration.set_is_inline(full_spec.is_inline); + declaration.set_is_static(full_spec.is_static); + declaration.set_is_extern(full_spec.is_extern); + declaration.set_is_thread_local(full_spec.is_thread_local); + declaration.set_is_register(full_spec.is_register); + declaration.set_is_typedef(full_spec.is_typedef); + declaration.set_is_weak(full_spec.is_weak); + symbolt symbol; declaration.to_symbol(*d_it, symbol); irep_idt identifier=symbol.name; From 36f81d657b5cfead0e788269883cf71874be7d19 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Fri, 18 Mar 2016 09:09:20 +0000 Subject: [PATCH 051/101] Linking for weak symbols --- src/goto-programs/read_goto_binary.cpp | 20 ++++++++--- src/linking/linking.cpp | 46 ++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/src/goto-programs/read_goto_binary.cpp b/src/goto-programs/read_goto_binary.cpp index 74d1827b441..4abede465ae 100644 --- a/src/goto-programs/read_goto_binary.cpp +++ b/src/goto-programs/read_goto_binary.cpp @@ -281,11 +281,13 @@ Function: link_functions static bool link_functions( symbol_tablet &dest_symbol_table, goto_functionst &dest_functions, - symbol_tablet &src_symbol_table, + const symbol_tablet &src_symbol_table, goto_functionst &src_functions, - const rename_symbolt &rename_symbol) + const rename_symbolt &rename_symbol, + const hash_set_cont &weak_symbols) { namespacet ns(dest_symbol_table); + namespacet src_ns(src_symbol_table); // merge functions Forall_goto_functions(src_it, src_functions) @@ -320,7 +322,8 @@ static bool link_functions( goto_functionst::goto_functiont &src_func=src_it->second; - if(in_dest_symbol_table.body.instructions.empty()) + if(in_dest_symbol_table.body.instructions.empty() || + weak_symbols.find(final_id)!=weak_symbols.end()) { // the one with body wins! rename_symbols_in_function(src_func, rename_symbol); @@ -328,7 +331,8 @@ static bool link_functions( in_dest_symbol_table.body.swap(src_func.body); in_dest_symbol_table.type=src_func.type; } - else if(src_func.body.instructions.empty()) + else if(src_func.body.instructions.empty() || + src_ns.lookup(src_it->first).is_weak) { // just keep the old one in dest } @@ -377,6 +381,12 @@ bool read_object_and_link( message_handler)) return true; + typedef hash_set_cont id_sett; + id_sett weak_symbols; + forall_symbols(it, symbol_table.symbols) + if(it->second.is_weak) + weak_symbols.insert(it->first); + linkingt linking(symbol_table, temp_model.symbol_table, message_handler); @@ -386,7 +396,7 @@ bool read_object_and_link( if(link_functions(symbol_table, functions, temp_model.symbol_table, temp_model.goto_functions, - linking.rename_symbol)) + linking.rename_symbol, weak_symbols)) return true; return false; diff --git a/src/linking/linking.cpp b/src/linking/linking.cpp index a5533b4d4d3..9a4f454349f 100644 --- a/src/linking/linking.cpp +++ b/src/linking/linking.cpp @@ -502,7 +502,9 @@ bool linkingt::needs_renaming_non_type( // These are static functions, or static variables // inside static function bodies. if(new_symbol.is_file_local || - old_symbol.is_file_local) + old_symbol.is_file_local || + (new_symbol.is_weak && + old_symbol.is_weak)) return true; return false; @@ -542,6 +544,7 @@ void linkingt::duplicate_code_symbol( old_symbol.type=new_symbol.type; old_symbol.location=new_symbol.location; + old_symbol.is_weak=new_symbol.is_weak; } else if(!new_symbol.location.get_function().empty() && new_symbol.value.is_nil()) @@ -561,6 +564,42 @@ void linkingt::duplicate_code_symbol( { old_symbol.type=new_symbol.type; old_symbol.location=new_symbol.location; + old_symbol.is_weak=new_symbol.is_weak; + } + } + // replace weak symbols + else if(old_symbol.is_weak) + { + if(new_symbol.value.is_nil()) + link_warning( + old_symbol, + new_symbol, + "function declaration conflicts with with weak definition"); + else + { + // new weak symbol should have been renamed + assert(!new_symbol.is_weak); + old_symbol.value.make_nil(); + old_symbol.is_weak=false; + } + } + else if(new_symbol.is_weak) + { + if(new_symbol.value.is_nil() || + old_symbol.value.is_not_nil()) + { + new_symbol.value.make_nil(); + + link_warning( + old_symbol, + new_symbol, + "ignoring conflicting weak function declaration"); + } + else + { + // new weak symbol should have been renamed + assert(!old_symbol.is_weak); + old_symbol.is_weak=true; } } // mismatch on number of parameters is definitively an error @@ -845,12 +884,13 @@ void linkingt::duplicate_object_symbol( !new_symbol.value.get_bool(ID_C_zero_initializer)) { if(old_symbol.value.is_nil() || - old_symbol.value.get_bool(ID_C_zero_initializer)) + old_symbol.value.get_bool(ID_C_zero_initializer) || + old_symbol.is_weak) { // new_symbol wins old_symbol.value=new_symbol.value; } - else + else if(!new_symbol.is_weak) { // try simplifier exprt tmp_old=old_symbol.value, From 1e093abcd3d6f2116fbe9406755c9912d9f5485e Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Sun, 17 Apr 2016 00:06:04 +0000 Subject: [PATCH 052/101] weak symbols need not necessarily be treated as file-local --- src/linking/linking.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/linking/linking.cpp b/src/linking/linking.cpp index 9a4f454349f..41b96844814 100644 --- a/src/linking/linking.cpp +++ b/src/linking/linking.cpp @@ -502,9 +502,7 @@ bool linkingt::needs_renaming_non_type( // These are static functions, or static variables // inside static function bodies. if(new_symbol.is_file_local || - old_symbol.is_file_local || - (new_symbol.is_weak && - old_symbol.is_weak)) + old_symbol.is_file_local) return true; return false; From 84e761176663f45e92be99a6a987b147a0a0a063 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Mon, 16 May 2016 22:33:56 +0000 Subject: [PATCH 053/101] Further weak-symbol-linking fixes --- src/linking/linking.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/linking/linking.cpp b/src/linking/linking.cpp index 41b96844814..238268d8f57 100644 --- a/src/linking/linking.cpp +++ b/src/linking/linking.cpp @@ -574,12 +574,7 @@ void linkingt::duplicate_code_symbol( new_symbol, "function declaration conflicts with with weak definition"); else - { - // new weak symbol should have been renamed - assert(!new_symbol.is_weak); old_symbol.value.make_nil(); - old_symbol.is_weak=false; - } } else if(new_symbol.is_weak) { @@ -593,12 +588,6 @@ void linkingt::duplicate_code_symbol( new_symbol, "ignoring conflicting weak function declaration"); } - else - { - // new weak symbol should have been renamed - assert(!old_symbol.is_weak); - old_symbol.is_weak=true; - } } // mismatch on number of parameters is definitively an error else if((old_t.parameters().size() Date: Thu, 19 May 2016 10:08:00 +0100 Subject: [PATCH 054/101] initialize cond_literal and guard_literal --- src/goto-symex/symex_target_equation.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/goto-symex/symex_target_equation.h b/src/goto-symex/symex_target_equation.h index 13499e87f8b..1169f0c8b4f 100644 --- a/src/goto-symex/symex_target_equation.h +++ b/src/goto-symex/symex_target_equation.h @@ -223,11 +223,13 @@ class symex_target_equationt:public symex_targett type(goto_trace_stept::NONE), hidden(false), guard(static_cast(get_nil_irep())), + guard_literal(const_literal(false)), ssa_lhs(static_cast(get_nil_irep())), ssa_full_lhs(static_cast(get_nil_irep())), original_full_lhs(static_cast(get_nil_irep())), ssa_rhs(static_cast(get_nil_irep())), cond_expr(static_cast(get_nil_irep())), + cond_literal(const_literal(false)), formatted(false), atomic_section_id(0), ignore(false) From 7d4e004fde47d178ab1d30eb1673e99c2e34e45b Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Thu, 19 May 2016 12:07:52 +0100 Subject: [PATCH 055/101] make bmc_cover work, and test it --- regression/cbmc-cover/Makefile | 20 ++++++++++++++++++++ regression/cbmc-cover/branch1/main.c | 17 +++++++++++++++++ regression/cbmc-cover/branch1/test.desc | 13 +++++++++++++ regression/cbmc-cover/condition1/main.c | 17 +++++++++++++++++ regression/cbmc-cover/condition1/test.desc | 18 ++++++++++++++++++ regression/cbmc-cover/decision1/main.c | 11 +++++++++++ regression/cbmc-cover/decision1/test.desc | 8 ++++++++ regression/cbmc-cover/location1/main.c | 15 +++++++++++++++ regression/cbmc-cover/location1/test.desc | 13 +++++++++++++ src/cbmc/bmc_cover.cpp | 18 +++++++++--------- src/goto-instrument/cover.cpp | 8 +++----- 11 files changed, 144 insertions(+), 14 deletions(-) create mode 100644 regression/cbmc-cover/Makefile create mode 100644 regression/cbmc-cover/branch1/main.c create mode 100644 regression/cbmc-cover/branch1/test.desc create mode 100644 regression/cbmc-cover/condition1/main.c create mode 100644 regression/cbmc-cover/condition1/test.desc create mode 100644 regression/cbmc-cover/decision1/main.c create mode 100644 regression/cbmc-cover/decision1/test.desc create mode 100644 regression/cbmc-cover/location1/main.c create mode 100644 regression/cbmc-cover/location1/test.desc diff --git a/regression/cbmc-cover/Makefile b/regression/cbmc-cover/Makefile new file mode 100644 index 00000000000..cbdd3378bac --- /dev/null +++ b/regression/cbmc-cover/Makefile @@ -0,0 +1,20 @@ +default: tests.log + +test: + @if ! ../test.pl -c ../../../src/cbmc/cbmc ; then \ + ../failed-tests-printer.pl ; \ + exit 1 ; \ + fi + +tests.log: ../test.pl + @if ! ../test.pl -c ../../../src/cbmc/cbmc ; then \ + ../failed-tests-printer.pl ; \ + exit 1 ; \ + fi + +show: + @for dir in *; do \ + if [ -d "$$dir" ]; then \ + vim -o "$$dir/*.c" "$$dir/*.out"; \ + fi; \ + done; diff --git a/regression/cbmc-cover/branch1/main.c b/regression/cbmc-cover/branch1/main.c new file mode 100644 index 00000000000..f84c00cd074 --- /dev/null +++ b/regression/cbmc-cover/branch1/main.c @@ -0,0 +1,17 @@ +int main() +{ + int input1, input2; + + if(input1) + { + if(input1) // dependent + { + } + } + else + { + if(input2) // independent + { + } + } +} diff --git a/regression/cbmc-cover/branch1/test.desc b/regression/cbmc-cover/branch1/test.desc new file mode 100644 index 00000000000..379f3be82d0 --- /dev/null +++ b/regression/cbmc-cover/branch1/test.desc @@ -0,0 +1,13 @@ +CORE +main.c +--cover branch +^EXIT=0$ +^SIGNAL=0$ +^\[main.1\] file main.c line 5 function main function main block 1 branch false: SATISFIED$ +^\[main.2\] file main.c line 5 function main function main block 1 branch true: SATISFIED$ +^\[main.3\] file main.c line 7 function main function main block 2 branch false: FAILED$ +^\[main.4\] file main.c line 7 function main function main block 2 branch true: SATISFIED$ +^\[main.5\] file main.c line 13 function main function main block 4 branch false: SATISFIED$ +^\[main.6\] file main.c line 13 function main function main block 4 branch true: SATISFIED$ +-- +^warning: ignoring diff --git a/regression/cbmc-cover/condition1/main.c b/regression/cbmc-cover/condition1/main.c new file mode 100644 index 00000000000..5043af9a82b --- /dev/null +++ b/regression/cbmc-cover/condition1/main.c @@ -0,0 +1,17 @@ +int main() +{ + int input1, input2; + + if(input1 && input2) + { + } + else if(input1) + { + } + else if(input2) + { + if(input1) // can't be true + { + } + } +} diff --git a/regression/cbmc-cover/condition1/test.desc b/regression/cbmc-cover/condition1/test.desc new file mode 100644 index 00000000000..ac613048d44 --- /dev/null +++ b/regression/cbmc-cover/condition1/test.desc @@ -0,0 +1,18 @@ +CORE +main.c +--cover condition +^EXIT=0$ +^SIGNAL=0$ +^\[main.1] file main.c line 5 function main condition .* false: SATISFIED +^\[main.2] file main.c line 5 function main condition .* true: SATISFIED +^\[main.3] file main.c line 5 function main condition .* false: SATISFIED +^\[main.4] file main.c line 5 function main condition .* true: SATISFIED +^\[main.5] file main.c line 8 function main condition .* false: SATISFIED +^\[main.6] file main.c line 8 function main condition .* true: SATISFIED +^\[main.7] file main.c line 11 function main condition .* false: SATISFIED +^\[main.8] file main.c line 11 function main condition .* true: SATISFIED +^\[main.9] file main.c line 13 function main condition .* false: FAILED +^\[main.10] file main.c line 13 function main condition .* true: SATISFIED +^\*\* 9 of 10 covered (90.0%) +-- +^warning: ignoring diff --git a/regression/cbmc-cover/decision1/main.c b/regression/cbmc-cover/decision1/main.c new file mode 100644 index 00000000000..2a14f5d774d --- /dev/null +++ b/regression/cbmc-cover/decision1/main.c @@ -0,0 +1,11 @@ +int main() +{ + int input1, input2, input3; + + if(input1 && input2 && input3) + { + } + else + { + } +} diff --git a/regression/cbmc-cover/decision1/test.desc b/regression/cbmc-cover/decision1/test.desc new file mode 100644 index 00000000000..d275c08f759 --- /dev/null +++ b/regression/cbmc-cover/decision1/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--cover decision +^EXIT=0$ +^SIGNAL=0$ +^\*\* 2 of 2 covered (100.0%), using 2 iterations$ +-- +^warning: ignoring diff --git a/regression/cbmc-cover/location1/main.c b/regression/cbmc-cover/location1/main.c new file mode 100644 index 00000000000..5553dbe94bc --- /dev/null +++ b/regression/cbmc-cover/location1/main.c @@ -0,0 +1,15 @@ +int main() +{ + int input1; + int x=0; + + if(input1) + { + x=1; + } + + if(input1 && !x) + { + x=2; // I am dead! + } +} diff --git a/regression/cbmc-cover/location1/test.desc b/regression/cbmc-cover/location1/test.desc new file mode 100644 index 00000000000..6e7e7174e48 --- /dev/null +++ b/regression/cbmc-cover/location1/test.desc @@ -0,0 +1,13 @@ +CORE +main.c +--cover location +^EXIT=0$ +^SIGNAL=0$ +^\[main.1\] file main.c line 3 function main block 1: SATISFIED$ +^\[main.2\] file main.c line 8 function main block 2: SATISFIED$ +^\[main.3\] file main.c line 11 function main block 3: SATISFIED$ +^\[main.4\] file main.c line 13 function main block 4: FAILED$ +^\[main.5\] file main.c line 15 function main block 5: SATISFIED$ +^\*\* 4 of 5 covered (80.0%) +-- +^warning: ignoring diff --git a/src/cbmc/bmc_cover.cpp b/src/cbmc/bmc_cover.cpp index dd27eb46e31..700a7ecc60a 100644 --- a/src/cbmc/bmc_cover.cpp +++ b/src/cbmc/bmc_cover.cpp @@ -272,6 +272,12 @@ bool bmc_covert::operator()() i_it->source_location); } } + + for(symex_target_equationt::SSA_stepst::iterator + it=bmc.equation.SSA_steps.begin(); + it!=bmc.equation.SSA_steps.end(); + it++) + it->cond_literal=literalt(0, 0); // Do conversion to next solver layer @@ -279,9 +285,6 @@ bool bmc_covert::operator()() //bmc.equation.output(std::cout); - // collects assumptions - and_exprt::operandst assumptions; - // get the conditions for these goals from formula // collect all 'instances' of the goals for(symex_target_equationt::SSA_stepst::iterator @@ -289,16 +292,13 @@ bool bmc_covert::operator()() it!=bmc.equation.SSA_steps.end(); it++) { - if(it->is_assume()) - assumptions.push_back(literal_exprt(it->cond_literal)); - - if(it->source.pc->is_assert()) + if(it->is_assert()) { + assert(it->source.pc->is_assert()); exprt c= conjunction({ - conjunction(assumptions), literal_exprt(it->guard_literal), - literal_exprt(it->cond_literal) }); + literal_exprt(!it->cond_literal) }); literalt l_c=solver.convert(c); goal_map[id(it->source.pc)].add_instance(it, l_c); } diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index 66c4cf65b4c..cc3777767dd 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -301,9 +301,7 @@ void instrument_cover_goals( if(!source_location.get_file().empty() && source_location.get_file()[0]!='<') { - std::string comment= - "block "+i2string(i_it->location_number); - + std::string comment="block "+b; goto_program.insert_before_swap(i_it); i_it->make_assertion(false_exprt()); i_it->source_location=source_location; @@ -328,12 +326,12 @@ void instrument_cover_goals( source_locationt source_location=i_it->source_location; goto_program.insert_before_swap(i_it); - i_it->make_assertion(guard); + i_it->make_assertion(not_exprt(guard)); i_it->source_location=source_location; i_it->source_location.set_comment(true_comment); goto_program.insert_before_swap(i_it); - i_it->make_assertion(not_exprt(guard)); + i_it->make_assertion(guard); i_it->source_location=source_location; i_it->source_location.set_comment(false_comment); From 701c3318c24308105bdaf1972c9a4d0d636873a0 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Thu, 19 May 2016 12:37:01 +0100 Subject: [PATCH 056/101] further work on --cover --- regression/cbmc-cover/assertion1/main.c | 11 +++++ regression/cbmc-cover/assertion1/test.desc | 9 ++++ regression/cbmc-cover/cover1/main.c | 12 +++++ regression/cbmc-cover/cover1/test.desc | 10 +++++ src/cbmc/bmc_cover.cpp | 3 +- src/cbmc/cbmc_parse_options.cpp | 4 +- src/goto-instrument/cover.cpp | 25 ++++++++++- src/goto-instrument/cover.h | 2 +- src/goto-programs/builtin_functions.cpp | 52 ---------------------- src/goto-programs/goto_convert_class.h | 1 - src/goto-programs/goto_inline.cpp | 3 +- 11 files changed, 74 insertions(+), 58 deletions(-) create mode 100644 regression/cbmc-cover/assertion1/main.c create mode 100644 regression/cbmc-cover/assertion1/test.desc create mode 100644 regression/cbmc-cover/cover1/main.c create mode 100644 regression/cbmc-cover/cover1/test.desc diff --git a/regression/cbmc-cover/assertion1/main.c b/regression/cbmc-cover/assertion1/main.c new file mode 100644 index 00000000000..93871ca260d --- /dev/null +++ b/regression/cbmc-cover/assertion1/main.c @@ -0,0 +1,11 @@ +int main() +{ + int input1, input2; + + __CPROVER_assert(!input1, ""); + + if(input1) + { + __CPROVER_assert(!input1, ""); // will work, we ignore the assertion + } +} diff --git a/regression/cbmc-cover/assertion1/test.desc b/regression/cbmc-cover/assertion1/test.desc new file mode 100644 index 00000000000..c9c30e9753d --- /dev/null +++ b/regression/cbmc-cover/assertion1/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--cover assertion +^EXIT=0$ +^SIGNAL=0$ +^\[main.assertion.1\] file main.c line 5 function main: SATISFIED$ +^\[main.assertion.2\] file main.c line 9 function main: SATISFIED$ +-- +^warning: ignoring diff --git a/regression/cbmc-cover/cover1/main.c b/regression/cbmc-cover/cover1/main.c new file mode 100644 index 00000000000..03714724776 --- /dev/null +++ b/regression/cbmc-cover/cover1/main.c @@ -0,0 +1,12 @@ +int main() +{ + int input1, input2; + + __CPROVER_cover(input1); + __CPROVER_cover(!input1); + + if(input1) + { + __CPROVER_cover(!input1); // won't work + } +} diff --git a/regression/cbmc-cover/cover1/test.desc b/regression/cbmc-cover/cover1/test.desc new file mode 100644 index 00000000000..933418cbfd0 --- /dev/null +++ b/regression/cbmc-cover/cover1/test.desc @@ -0,0 +1,10 @@ +CORE +main.c +--cover cover +^EXIT=0$ +^SIGNAL=0$ +^\[main.1] file main.c line 5 function main condition .*: SATISFIED$ +^\[main.2] file main.c line 6 function main condition .*: SATISFIED$ +^\[main.3] file main.c line 10 function main condition .*: FAILED$ +-- +^warning: ignoring diff --git a/src/cbmc/bmc_cover.cpp b/src/cbmc/bmc_cover.cpp index 700a7ecc60a..4bb42ac01d7 100644 --- a/src/cbmc/bmc_cover.cpp +++ b/src/cbmc/bmc_cover.cpp @@ -385,7 +385,8 @@ bool bmc_covert::operator()() status() << "** " << goals_covered << " of " << goal_map.size() << " covered (" << std::fixed << std::setw(1) << std::setprecision(1) - << 100.0*goals_covered/goal_map.size() << "%), using " + << (goal_map.empty()?0.0:100.0*goals_covered/goal_map.size()) + << "%), using " << cover_goals.iterations() << " iteration" << (cover_goals.iterations()==1?"":"s") << eom; diff --git a/src/cbmc/cbmc_parse_options.cpp b/src/cbmc/cbmc_parse_options.cpp index b996f09d54c..bdec0116408 100644 --- a/src/cbmc/cbmc_parse_options.cpp +++ b/src/cbmc/cbmc_parse_options.cpp @@ -937,10 +937,12 @@ bool cbmc_parse_optionst::process_goto_program( c=coverage_criteriont::CONDITION; else if(criterion=="mcdc") c=coverage_criteriont::MCDC; + else if(criterion=="cover") + c=coverage_criteriont::COVER; else { error() << "unknown coverage criterion" << eom; - return false; + return true; } status() << "Instrumenting coverge goals" << eom; diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index cc3777767dd..5b4f82c946d 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -73,6 +73,7 @@ const char *as_string(coverage_criteriont c) case coverage_criteriont::PATH: return "path"; case coverage_criteriont::MCDC: return "MC/DC"; case coverage_criteriont::ASSERTION: return "assertion"; + case coverage_criteriont::COVER: return "cover instructions"; default: return ""; } } @@ -285,7 +286,29 @@ void instrument_cover_goals( { case coverage_criteriont::ASSERTION: // turn into 'assert(false)' to avoid simplification - i_it->guard=false_exprt(); + if(i_it->is_assert()) + i_it->guard=false_exprt(); + break; + + case coverage_criteriont::COVER: + // turn __CPROVER_cover(x) into 'assert(!x)' + if(i_it->is_function_call()) + { + const code_function_callt &code_function_call= + to_code_function_call(i_it->code); + if(code_function_call.function().id()==ID_symbol && + to_symbol_expr(code_function_call.function()).get_identifier()== + "__CPROVER_cover" && + code_function_call.arguments().size()==1) + { + const exprt c=code_function_call.arguments()[0]; + std::string comment="condition `"+from_expr(ns, "", c)+"'"; + i_it->guard=not_exprt(c); + i_it->type=ASSERT; + i_it->code.clear(); + i_it->source_location.set_comment(comment); + } + } break; case coverage_criteriont::LOCATION: diff --git a/src/goto-instrument/cover.h b/src/goto-instrument/cover.h index 962965ed598..cf51972f6e6 100644 --- a/src/goto-instrument/cover.h +++ b/src/goto-instrument/cover.h @@ -15,7 +15,7 @@ Date: May 2016 enum class coverage_criteriont { LOCATION, BRANCH, DECISION, CONDITION, - PATH, MCDC, ASSERTION }; + PATH, MCDC, ASSERTION, COVER }; void instrument_cover_goals( const symbol_tablet &symbol_table, diff --git a/src/goto-programs/builtin_functions.cpp b/src/goto-programs/builtin_functions.cpp index 4bb8ef4cbd0..87865642f2a 100644 --- a/src/goto-programs/builtin_functions.cpp +++ b/src/goto-programs/builtin_functions.cpp @@ -270,53 +270,6 @@ void goto_convertt::do_input( /*******************************************************************\ -Function: goto_convertt::do_cover - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -void goto_convertt::do_cover( - const exprt &lhs, - const exprt &function, - const exprt::operandst &arguments, - goto_programt &dest) -{ - codet output_code; - output_code.set_statement(ID_output); - output_code.add_source_location()=function.source_location(); - - if(arguments.size()!=1) - { - err_location(function); - throw "cover takes one argument"; - } - - // build string constant - exprt string_constant(ID_string_constant); - string_constant.type()=array_typet(); - string_constant.type().subtype()=char_type(); - string_constant.set(ID_value, ID_cover); - - index_exprt index_expr; - index_expr.type()=char_type(); - index_expr.array()=string_constant; - index_expr.index()=gen_zero(index_type()); - - output_code.copy_to_operands(address_of_exprt(index_expr)); - - forall_expr(it, arguments) - output_code.copy_to_operands(*it); - - copy(output_code, OTHER, dest); -} - -/*******************************************************************\ - Function: goto_convertt::do_output Inputs: @@ -1154,11 +1107,6 @@ void goto_convertt::do_function_call_symbol( { do_input(lhs, function, arguments, dest); } - else if(identifier==CPROVER_PREFIX "cover" || - identifier=="__CPROVER::cover") - { - do_cover(lhs, function, arguments, dest); - } else if(identifier==CPROVER_PREFIX "output" || identifier=="__CPROVER::output") { diff --git a/src/goto-programs/goto_convert_class.h b/src/goto-programs/goto_convert_class.h index 098fd2ede5a..c14ef4f32be 100644 --- a/src/goto-programs/goto_convert_class.h +++ b/src/goto-programs/goto_convert_class.h @@ -466,7 +466,6 @@ class goto_convertt:public message_streamt void do_printf (const exprt &lhs, const exprt &rhs, const exprt::operandst &arguments, goto_programt &dest); void do_input (const exprt &lhs, const exprt &rhs, const exprt::operandst &arguments, goto_programt &dest); void do_output (const exprt &lhs, const exprt &rhs, const exprt::operandst &arguments, goto_programt &dest); - void do_cover (const exprt &lhs, const exprt &rhs, const exprt::operandst &arguments, goto_programt &dest); void do_prob_coin (const exprt &lhs, const exprt &rhs, const exprt::operandst &arguments, goto_programt &dest); void do_prob_uniform (const exprt &lhs, const exprt &rhs, const exprt::operandst &arguments, goto_programt &dest); diff --git a/src/goto-programs/goto_inline.cpp b/src/goto-programs/goto_inline.cpp index 1509ef146c2..85ccf4006de 100644 --- a/src/goto-programs/goto_inline.cpp +++ b/src/goto-programs/goto_inline.cpp @@ -414,7 +414,8 @@ void goto_inlinet::expand_function_call( identifier=="__CPROVER_set_must" || identifier=="__CPROVER_set_may" || identifier=="__CPROVER_clear_must" || - identifier=="__CPROVER_clear_may") + identifier=="__CPROVER_clear_may" || + identifier=="__CPROVER_cover") { target++; return; // ignore From 08faebcbf212289b898714ccea372a4c11a2b48a Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Thu, 19 May 2016 12:54:46 +0100 Subject: [PATCH 057/101] fix Minisat 2.2.1 URL --- COMPILING | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/COMPILING b/COMPILING index eb30060b262..46c5c791cdc 100644 --- a/COMPILING +++ b/COMPILING @@ -142,7 +142,7 @@ Follow these instructions: 1) You need a SAT solver (in source). We recommend MiniSat2. Using a browser, download from - http://minisat.se/downloads/minisat-2.2.1.tar.gz + http://ftp.debian.org/debian/pool/main/m/minisat2/minisat2_2.2.1.orig.tar.gz and then unpack with From f141d772e24d402bcda927f6feb2e6d745ef231c Mon Sep 17 00:00:00 2001 From: Daniel Poetzl Date: Tue, 17 May 2016 16:38:26 +0100 Subject: [PATCH 058/101] java entry point with nondet structs --- regression/cbmc-java/function1/Main.class | Bin 0 -> 281 bytes regression/cbmc-java/function1/Main.java | 19 ++ regression/cbmc-java/function1/Other.class | Bin 0 -> 524 bytes regression/cbmc-java/function1/test.desc | 8 + regression/cbmc-java/function2/A.class | Bin 0 -> 195 bytes regression/cbmc-java/function2/B.class | Bin 0 -> 180 bytes regression/cbmc-java/function2/C.class | Bin 0 -> 180 bytes regression/cbmc-java/function2/D.class | Bin 0 -> 598 bytes regression/cbmc-java/function2/Main.class | Bin 0 -> 277 bytes regression/cbmc-java/function2/Main.java | 34 ++ regression/cbmc-java/function2/test.desc | 8 + regression/cbmc-java/function3/A.class | Bin 0 -> 244 bytes regression/cbmc-java/function3/B.class | Bin 0 -> 197 bytes regression/cbmc-java/function3/Main.class | Bin 0 -> 277 bytes regression/cbmc-java/function3/Main.java | 22 ++ regression/cbmc-java/function3/test.desc | 8 + src/java_bytecode/java_entry_point.cpp | 368 ++++++++++++++++++--- 17 files changed, 425 insertions(+), 42 deletions(-) create mode 100644 regression/cbmc-java/function1/Main.class create mode 100644 regression/cbmc-java/function1/Main.java create mode 100644 regression/cbmc-java/function1/Other.class create mode 100644 regression/cbmc-java/function1/test.desc create mode 100644 regression/cbmc-java/function2/A.class create mode 100644 regression/cbmc-java/function2/B.class create mode 100644 regression/cbmc-java/function2/C.class create mode 100644 regression/cbmc-java/function2/D.class create mode 100644 regression/cbmc-java/function2/Main.class create mode 100644 regression/cbmc-java/function2/Main.java create mode 100644 regression/cbmc-java/function2/test.desc create mode 100644 regression/cbmc-java/function3/A.class create mode 100644 regression/cbmc-java/function3/B.class create mode 100644 regression/cbmc-java/function3/Main.class create mode 100644 regression/cbmc-java/function3/Main.java create mode 100644 regression/cbmc-java/function3/test.desc diff --git a/regression/cbmc-java/function1/Main.class b/regression/cbmc-java/function1/Main.class new file mode 100644 index 0000000000000000000000000000000000000000..4cb1cb6f542360452e840462e2e94176926429cf GIT binary patch literal 281 zcmYL^y-or_6ot8vF{NT9^5n@3&Z9YxS z6#pQ|&k@sdZ59n~5pX+y6u1;()(hTls6q|z_mFQIhOS%+1};_r literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/function1/Main.java b/regression/cbmc-java/function1/Main.java new file mode 100644 index 00000000000..7152318684e --- /dev/null +++ b/regression/cbmc-java/function1/Main.java @@ -0,0 +1,19 @@ + +class Other +{ + public void fail() + { + assert i == 0; + } + + private int i; +} + +public class Main +{ + public static void main(String[] args) + { + Other o = new Other(); + } +} + diff --git a/regression/cbmc-java/function1/Other.class b/regression/cbmc-java/function1/Other.class new file mode 100644 index 0000000000000000000000000000000000000000..2ee3eeda9d7087712196ebc7a86a133f7f4b6dd4 GIT binary patch literal 524 zcmYLFO;5r=5PjPg3Z*E5Aby~jcu)>fB!ze0qkJiLJYY$qF7KNZ(`Acft-mY3(HtBQD9(_?kPiN zg9m}|L)rC$BN_0PE85g)GDIuVli@ytzPWYDU{t$p!7zI!J#pTDIR5hIIXj~eu%CW`boG5Ro# z4y^}LdF6!=oi14eX;M|7%qT}n1F#n=XgkH|5Y#BnO{jY$rKq`AXnmwh@6ex+_=0gY zK;%cwYQtHJvQo&xM4BocEK6Q86QSLq43N$s`T?^K(|CrVzd@Udj14G(2(;vZvN=E8 Gk^Kk3zgZyw literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/function1/test.desc b/regression/cbmc-java/function1/test.desc new file mode 100644 index 00000000000..1b33b740986 --- /dev/null +++ b/regression/cbmc-java/function1/test.desc @@ -0,0 +1,8 @@ +CORE +Main.class +--function "java::Other.fail:()V" +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/function2/A.class b/regression/cbmc-java/function2/A.class new file mode 100644 index 0000000000000000000000000000000000000000..7af0cd759fb662760a420053da2d71e0cf5478c4 GIT binary patch literal 195 zcmW-aJqp4=5QX2EKNF+z0)nMln8H>B5dq1bQYA{*icLgKxw1Pc$~p~T4+^YhK) z&HMh|9{>wP0W5?b`W^-ZQd~QNyHr}$D}ptdUI_N4yh=ipC@l}oJ(bm2qy=AsQ`uCR z+^QD*y-<3di-!o|!sAbC!m#DI5c(D$(_CgX#^`V)z&dO=Weqr%;*HM&ZwFZtru2GaQ{1?y9&LMY6TI*;lvJlt-OjMTrhYRi4e- z))4Nr%_o_D=op_sE-j@N3~0#@5WvN2HtK|MTd3bS;Ei9XXJd!beUWKGk<1pIKXL&W A?f?J) literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/function2/C.class b/regression/cbmc-java/function2/C.class new file mode 100644 index 0000000000000000000000000000000000000000..8531053409a2dcd199997b80a24a2de43361a57f GIT binary patch literal 180 zcmW-ay9&ZU5Jk_Lmxmz|+{4XoP!VmDH#7T;|Gw0r6 z=KFhpfGJ6YLmbcz=qc1iYNhaJHn;b=!WoVZ3O6lIMv<&-Zno7eGv!`qS8<|UQI$ut zv^9hqZS%=lKXi;wAeU091p`|00|apKnu&TtxGmIg67a?^)U%00QD1C`MI-4gI)8I) B81?`F literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/function2/D.class b/regression/cbmc-java/function2/D.class new file mode 100644 index 0000000000000000000000000000000000000000..02d4e15c990c023b08087d64947e739a691c972e GIT binary patch literal 598 zcmYL_QBM<55QV?HyX|(jTd5#WR0IKq)*=taCyCJ%O-w)&F(&f1-LB@Ab!&FF{+IFx zd{&7hn&`Vf$~d<``*6;k%$%HiX8!*B`5Sn^wojEM50C4HZg|{e+0ZRRD=w=(E=w-A zeb!ia*-)rRVefYyDdsl9Jdd+N57K;3=V3RAdon*#ly`Nii^n3|YQ9xCok1^F%SVHU;DwUK)Vp-%7j!_Q$rovQ&? zm1E7kSvJTd;+{(@;2v#7eJXp^?Z;6e>9&X4ISdz=Z|FR;{#2?^~ zBD}R>i+OJ+-5RpJ$IKejs zt#kY}UztUTI|SU!KLsv?h_%MwHC3q9#{=YxhJ#td|7Mpy!3DiX?-^Cp_y_9!fJ%DC P{k6aiv0K7*dWFjq98fI5 literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/function2/Main.java b/regression/cbmc-java/function2/Main.java new file mode 100644 index 00000000000..7ca39a8e703 --- /dev/null +++ b/regression/cbmc-java/function2/Main.java @@ -0,0 +1,34 @@ + +class A +{ + public int i; +} + +class B extends A +{ + public int j; +} + +class C extends B +{ + public int k; +} + +class D +{ + protected C c; + + public void fail() + { + assert c.i == 0 || c.j == 0 || c.k == 0; + } +} + +public class Main +{ + public static void main(String[] args) + { + D d = new D(); + } +} + diff --git a/regression/cbmc-java/function2/test.desc b/regression/cbmc-java/function2/test.desc new file mode 100644 index 00000000000..6ce063c8359 --- /dev/null +++ b/regression/cbmc-java/function2/test.desc @@ -0,0 +1,8 @@ +CORE +Main.class +--function "java::D.fail:()V" +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/function3/A.class b/regression/cbmc-java/function3/A.class new file mode 100644 index 0000000000000000000000000000000000000000..ed5eaf69452f314a635d97a824e5562d333780f5 GIT binary patch literal 244 zcmZ9Fy9&ZU5Jm6A#F+Sqt%YEz7Ft*;f(lkX3dMdmS!6>VAV%=BtON@`z>gBgEi5c% zm^=5(o!9&E1TaF=M+tQo4Hp4{B%!pLj|t_8&h&Z8vfDcl>_r|aLa@@A+7zi&r@fE~ zZ=9$|(<{N><;5vfOZ{DXYoW72EH0vkGF;A`5t?5;Ohk4ZZe^^(Gdi&NIlw+_I6PTg ke89TGQ`rm$256|ABbiv1-Xav@$IB)*rGVBrJ!P~s-d?0z%s z?DzNn0GK26VIpwRbI~V|AeixbL2#Bzt7^qKo?Hmlwzx_{7%MFg^*xd0StL0-{;8N!0?}N!`wXUb;)q1%7M)=Wl9Ylx)GT;Q? z6lBNvM_HL^gFA%W%s&M#gqZb&zgwzMTMt{vhK7S#qeC;LPjE`_(JrHk+Wv)_Y!MVk Q++Pb^5xXYbp;tKj2Nx17n*aa+ literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/function3/Main.java b/regression/cbmc-java/function3/Main.java new file mode 100644 index 00000000000..e8aac10625c --- /dev/null +++ b/regression/cbmc-java/function3/Main.java @@ -0,0 +1,22 @@ + +class A +{ + public void dummy() {} + + public B b; +} + +class B +{ + public A a; +} + + +public class Main +{ + public static void main(String[] args) + { + B B = new B(); + } +} + diff --git a/regression/cbmc-java/function3/test.desc b/regression/cbmc-java/function3/test.desc new file mode 100644 index 00000000000..fb68b442fdc --- /dev/null +++ b/regression/cbmc-java/function3/test.desc @@ -0,0 +1,8 @@ +CORE +Main.class +--function "java::A.dummy:()V" +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/src/java_bytecode/java_entry_point.cpp b/src/java_bytecode/java_entry_point.cpp index 21676f3dd6f..65764e55fba 100644 --- a/src/java_bytecode/java_entry_point.cpp +++ b/src/java_bytecode/java_entry_point.cpp @@ -8,6 +8,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include #include @@ -16,6 +17,10 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include +#include +#include +#include +#include #include @@ -96,6 +101,183 @@ exprt gen_argument(const typet &type) /*******************************************************************\ +Function: gen_nondet_init + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +namespace { +void gen_nondet_init( + const exprt &expr, + code_blockt &init_code, + const namespacet &ns, + std::set &recursion_set, + bool is_sub, + irep_idt class_identifier) +{ + const typet &type=ns.follow(expr.type()); + + if(type.id()==ID_struct) + { + typedef struct_typet::componentt componentt; + typedef struct_typet::componentst componentst; + + const struct_typet &struct_type=to_struct_type(type); + const irep_idt struct_tag=struct_type.get_tag(); + + componentst components=struct_type.components(); + + if(!is_sub) + class_identifier=struct_tag; + + recursion_set.insert(struct_tag); + assert(!recursion_set.empty()); + + for(componentst::const_iterator it=components.begin(); + it!=components.end(); it++) + { + const componentt &component=*it; + const typet &component_type=component.type(); + irep_idt name=component.get_name(); + + member_exprt me(expr, name, component_type); + + if(name=="@class_identifier") + { + constant_exprt ci(class_identifier, string_typet()); + + code_assignt code(me, ci); + init_code.copy_to_operands(code); + } + else + { + irep_idt new_class_identifier; + assert(!name.empty()); + + is_sub = name[0]=='@'; + + gen_nondet_init( + me, init_code, ns, recursion_set, is_sub, class_identifier); + } + } + + recursion_set.erase(struct_tag); + } + else if(type.id()!=ID_pointer) + { + assert(type.id()!= ID_struct); + + side_effect_expr_nondett se=side_effect_expr_nondett(type); + + code_assignt code(expr, se); + init_code.copy_to_operands(code); + } + else + { + assert(type.id()==ID_pointer); + + // dereferenced type + const pointer_typet &pointer_type=to_pointer_type(type); + const typet &subtype=ns.follow(pointer_type.subtype()); + + if(subtype.id()==ID_struct) + { + const struct_typet &struct_type=to_struct_type(subtype); + const irep_idt struct_tag=struct_type.get_tag(); + + if(recursion_set.find(struct_tag)!=recursion_set.end()) + { + // make null + null_pointer_exprt null_pointer_expr(pointer_type); + code_assignt code(expr, null_pointer_expr); + init_code.copy_to_operands(code); + + return; + } + } + + // build size expression + exprt object_size=size_of_expr(subtype, ns); + + assert(!object_size.is_nil()); + + // malloc expression + side_effect_exprt malloc_expr(ID_malloc); + malloc_expr.copy_to_operands(object_size); + malloc_expr.type()=pointer_type; + + code_assignt code(expr, malloc_expr); + init_code.copy_to_operands(code); + + // dereference expression + dereference_exprt deref_expr(expr, subtype); + + gen_nondet_init(deref_expr, init_code, ns, recursion_set, false, ""); + } +} +} + +/*******************************************************************\ + +Function: gen_nondet_init + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +namespace { +void gen_nondet_init( + const exprt &expr, + code_blockt &init_code, + const namespacet &ns) +{ + std::set recursion_set; + gen_nondet_init(expr, init_code, ns, recursion_set, false, ""); +} +} + +/*******************************************************************\ + +Function: gen_nondet_init + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +namespace { +symbolt &new_tmp_symbol(symbol_tablet &symbol_table) +{ + static int temporary_counter=0; + + auxiliary_symbolt new_symbol; + symbolt *symbol_ptr; + + do + { + new_symbol.name="tmp_struct_init$"+i2string(++temporary_counter); + new_symbol.base_name=new_symbol.name; + new_symbol.mode=ID_java; + } while(symbol_table.move(new_symbol, symbol_ptr)); + + return *symbol_ptr; +} +} + +/*******************************************************************\ + Function: java_static_lifetime_init Inputs: @@ -176,54 +358,138 @@ bool java_entry_point( symbol_table.symbols.end()) return false; // silently ignore - // are we given a main class? - if(main_class.empty()) - return false; // silently ignore - - std::string entry_method= - id2string(main_class)+".main"; +#if 0 + std::cout << "Main: " << config.main << std::endl; +#endif - std::string prefix="java::"+entry_method+":"; + messaget message(message_handler); - // look it up - std::set matches; + code_blockt struct_init_code; // struct init code if needed + bool have_struct=false; + symbol_exprt struct_ptr; - for(symbol_tablet::symbolst::const_iterator - s_it=symbol_table.symbols.begin(); - s_it!=symbol_table.symbols.end(); - s_it++) - { - if(s_it->second.type.id()==ID_code && - has_prefix(id2string(s_it->first), prefix)) - matches.insert(s_it->first); - } + symbolt symbol; // main function symbol - if(matches.empty()) + // find main symbol + if(config.main!="") { - // Not found, silently ignore - return false; - } + // look it up + symbol_tablet::symbolst::const_iterator s_it + =symbol_table.symbols.find(config.main); - if(matches.size()>=2) - { - messaget message(message_handler); - message.error() << "main method in `" << main_class - << "' is ambiguous" << messaget::eom; - return true; // give up with error, no main - } + if(s_it==symbol_table.symbols.end()) + { + message.error() << "main symbol `" << config.main + << "' not found" << messaget::eom; + return true; + } + + // function symbol + symbol=s_it->second; + + if(symbol.type.id()!=ID_code) + { + message.error() << "main symbol `" << config.main + << "' not a function" << messaget::eom; + return true; + } + + // check if it has a body + if(symbol.value.is_nil()) + { + message.error() << "main method `" << main_class + << "' has no body" << messaget::eom; + return true; + } + + // get name of associated struct + size_t idx=config.main.rfind("."); + assert(idx!=std::string::npos); + assert(idxsecond.type.id()==ID_struct) + { + const symbolt &struct_symbol=st_it->second; + assert(struct_symbol.type.id()==ID_struct); + const struct_typet &struct_type=to_struct_type(struct_symbol.type); + const pointer_typet pointer_type(struct_type); + + symbolt &aux_symbol=new_tmp_symbol(symbol_table); + aux_symbol.type=pointer_type; + aux_symbol.is_static_lifetime=true; - const symbolt &symbol= - symbol_table.symbols.find(*matches.begin())->second; + struct_ptr=aux_symbol.symbol_expr(); - // check if it has a body - if(symbol.value.is_nil()) + namespacet ns(symbol_table); + gen_nondet_init(struct_ptr, struct_init_code, ns); + + have_struct=true; + } + } + else { - messaget message(message_handler); - message.error() << "main method `" << main_class - << "' has no body" << messaget::eom; - return true; // give up with error + // no function given, we look for the main class + assert(config.main==""); + + // are we given a main class? + if(main_class.empty()) + return false; // silently ignore + + std::string entry_method= + id2string(main_class)+".main"; + + std::string prefix="java::"+entry_method+":"; + + // look it up + std::set matches; + + for(symbol_tablet::symbolst::const_iterator + s_it=symbol_table.symbols.begin(); + s_it!=symbol_table.symbols.end(); + s_it++) + { + if(s_it->second.type.id()==ID_code && + has_prefix(id2string(s_it->first), prefix)) + matches.insert(s_it->first); + } + + if(matches.empty()) + { + // Not found, silently ignore + return false; + } + + if(matches.size()>=2) + { + message.error() << "main method in `" << main_class + << "' is ambiguous" << messaget::eom; + return true; // give up with error, no main + } + + // function symbol + symbol=symbol_table.symbols.find(*matches.begin())->second; + + // check if it has a body + if(symbol.value.is_nil()) + { + message.error() << "main method `" << main_class + << "' has no body" << messaget::eom; + return true; // give up with error + } } + assert(!symbol.value.is_nil()); + assert(symbol.type.id()==ID_code); + create_initialize(symbol_table); if(java_static_lifetime_init(symbol_table, symbol.location, message_handler)) @@ -238,7 +504,6 @@ bool java_entry_point( if(init_it==symbol_table.symbols.end()) { - messaget message(message_handler); message.error() << "failed to find " INITIALIZE " symbol" << messaget::eom; return true; // give up with error @@ -246,12 +511,25 @@ bool java_entry_point( code_function_callt call_init; call_init.lhs().make_nil(); - call_init.add_source_location() = symbol.location; + call_init.add_source_location()=symbol.location; call_init.function()=init_it->second.symbol_expr(); init_code.move_to_operands(call_init); } + // add struct init code + + if(have_struct) + { + typedef code_blockt::operandst operandst; + const operandst &operands=struct_init_code.operands(); + + for(operandst::const_iterator it=operands.begin(); it!=operands.end(); it++) + { + init_code.add((const codet&)*it); + } + } + // build call to main method code_function_callt call_main; @@ -264,7 +542,15 @@ bool java_entry_point( exprt::operandst main_arguments; main_arguments.resize(parameters.size()); - for(unsigned i=0; i=1) + { + main_arguments[0]=struct_ptr; + i++; + } + + for(; i Date: Thu, 19 May 2016 14:24:38 +0100 Subject: [PATCH 059/101] missing cassert header --- src/goto-cc/run.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/goto-cc/run.cpp b/src/goto-cc/run.cpp index 8dc8a8fb748..78c1ca6f277 100644 --- a/src/goto-cc/run.cpp +++ b/src/goto-cc/run.cpp @@ -17,6 +17,7 @@ Date: August 2012 #include #include #include +#include #include #include From 014d9ec0d37cb38e1f101506465d86000d3c196a Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Thu, 19 May 2016 15:02:19 +0100 Subject: [PATCH 060/101] another attempt at cassert --- src/goto-cc/run.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/goto-cc/run.cpp b/src/goto-cc/run.cpp index 78c1ca6f277..e566026ec32 100644 --- a/src/goto-cc/run.cpp +++ b/src/goto-cc/run.cpp @@ -8,6 +8,8 @@ Date: August 2012 \*******************************************************************/ +#include + #ifdef _WIN32 #include #else @@ -17,7 +19,6 @@ Date: August 2012 #include #include #include -#include #include #include From 1e4845eb01abbdcce4818bea9d92224b30687d58 Mon Sep 17 00:00:00 2001 From: Cristina Date: Thu, 12 May 2016 10:48:47 +0100 Subject: [PATCH 061/101] For Java skip the check for dereference of a deallocated or dead object --- src/analyses/goto_check.cpp | 43 +++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/analyses/goto_check.cpp b/src/analyses/goto_check.cpp index 467ac8df0ef..8cd792f1fd0 100644 --- a/src/analyses/goto_check.cpp +++ b/src/analyses/goto_check.cpp @@ -944,23 +944,34 @@ void goto_checkt::pointer_validity_check( expr, guard); - if(flags.is_unknown() || flags.is_dynamic_heap()) - add_guarded_claim( - not_exprt(deallocated(pointer, ns)), - "dereference failure: deallocated dynamic object", - "pointer dereference", - expr.find_source_location(), - expr, - guard); - if(flags.is_unknown() || flags.is_dynamic_local()) - add_guarded_claim( - not_exprt(dead_object(pointer, ns)), - "dereference failure: dead object", - "pointer dereference", - expr.find_source_location(), - expr, - guard); + symbol_tablet symbol_table = ns.get_symbol_table(); + + symbol_tablet::symbolst::iterator s_it= + symbol_table.symbols.find(CPROVER_PREFIX "initialize"); + + // For Java don't check dereference of a deallocated or dead object + if (s_it==symbol_table.symbols.end() || (s_it->second).mode != ID_java) + { + + if(flags.is_unknown() || flags.is_dynamic_heap()) + add_guarded_claim( + not_exprt(deallocated(pointer, ns)), + "dereference failure: deallocated dynamic object", + "pointer dereference", + expr.find_source_location(), + expr, + guard); + + if(flags.is_unknown() || flags.is_dynamic_local()) + add_guarded_claim( + not_exprt(dead_object(pointer, ns)), + "dereference failure: dead object", + "pointer dereference", + expr.find_source_location(), + expr, + guard); + } if(enable_bounds_check) { From c019f86c280bcb09d1551f1cf1e5d7457f97f741 Mon Sep 17 00:00:00 2001 From: Cristina Date: Fri, 13 May 2016 12:55:41 +0100 Subject: [PATCH 062/101] + regression test for NULL object dereferencing in Java --- regression/cbmc-java/pointer_check1/A.class | Bin 0 -> 207 bytes regression/cbmc-java/pointer_check1/B.class | Bin 0 -> 277 bytes .../pointer_check1/pointer_check1.class | Bin 0 -> 335 bytes .../pointer_check1/pointer_check1.java | 21 ++++++++++++++++++ regression/cbmc-java/pointer_check1/test.desc | 8 +++++++ 5 files changed, 29 insertions(+) create mode 100644 regression/cbmc-java/pointer_check1/A.class create mode 100644 regression/cbmc-java/pointer_check1/B.class create mode 100644 regression/cbmc-java/pointer_check1/pointer_check1.class create mode 100644 regression/cbmc-java/pointer_check1/pointer_check1.java create mode 100644 regression/cbmc-java/pointer_check1/test.desc diff --git a/regression/cbmc-java/pointer_check1/A.class b/regression/cbmc-java/pointer_check1/A.class new file mode 100644 index 0000000000000000000000000000000000000000..a80b733cb82166ebb011b09541a224a368b9590c GIT binary patch literal 207 zcmXYqO$z~06o%hpz8K@9td%7eBwHydrNn}4b?3Tq$GD?u_+M7a!VmDHs&pg5n2o=2E9n!L;x2a-<%NYIrn2>4*gXaDVd>#0)Gz>mksCt;srKE YrY6rkbGi@E{TG+GyFZynK2rhZFVv(XoB#j- literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/pointer_check1/B.class b/regression/cbmc-java/pointer_check1/B.class new file mode 100644 index 0000000000000000000000000000000000000000..09ba3d25408dc7ed77dc3ffe780ac4baafb6a11b GIT binary patch literal 277 zcmZ9GL2JT55QX1F&1#ye)p`_qR11pqs0daN1kr=yRW|9Ot7%d~;;-tZAQXD&5Aa8c zvw{}~cINTTd%Jr&|NR4aL(M@Jj|CJ_5-1Bi5$wJWbuu7i8qF0UJBmIOp)}Q@nx&tf zikH$0nAjVYtYpBVF&*}r6N0md(%4sHZPwMVNQa4v*Zx-d`)+$D57I>rwm`*270(2E zCzK8E1Tx%o=H5>E3F9HZeK0rE1TV<&4^3HoI1YkfRp&{Dw0=Q9EC_k-W^HUh0S@b% T^%{OX!ur0m3N}43v*2C;OwB3~ literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/pointer_check1/pointer_check1.class b/regression/cbmc-java/pointer_check1/pointer_check1.class new file mode 100644 index 0000000000000000000000000000000000000000..891a91b81f7cf6f5503e6a04d44b53e603d24910 GIT binary patch literal 335 zcmY*U!AiqG5Pg%RiKa1W8|_W-m?{{=V^vT=5P}{m1@R!8xWujLMndX;d9k422l!Fq zY%j%ynfI7|?=kc9`}qyv7(*W}A`d+u79!L79tIv_f_tL0YR?FEGMW;c%lb(YqD*Od zvzX_yxf6NC6K5`zCJd8@Y$o1BS_xgIleSU192=uQsTWNluaptTueH*xY#xheS-cz_ z8b<&R8w9!tu#Fu;_+LZlt#fblnJijfu9WRmR7{fWd_20w9y)x9c@`H3g0RVKmysAd z`%BO}6JChByBc;`(nY}BNK>}jjL{dY`z7q`fIi@yu1(?UyU*DJgoxR;#c~VbA2RDY AQUCw| literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/pointer_check1/pointer_check1.java b/regression/cbmc-java/pointer_check1/pointer_check1.java new file mode 100644 index 00000000000..f3a3c312022 --- /dev/null +++ b/regression/cbmc-java/pointer_check1/pointer_check1.java @@ -0,0 +1,21 @@ +class A +{ + int val; +} + +class B +{ + int getVal(A a) + { + return a.val; + } +} + +class pointer_check1 +{ + public static void main(String[] args) + { + B b = new B(); + int myval = b.getVal(null); + } +} diff --git a/regression/cbmc-java/pointer_check1/test.desc b/regression/cbmc-java/pointer_check1/test.desc new file mode 100644 index 00000000000..03121d320c6 --- /dev/null +++ b/regression/cbmc-java/pointer_check1/test.desc @@ -0,0 +1,8 @@ +CORE +pointer_check1.class +--pointer-check +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +^warning: ignoring \ No newline at end of file From 5c679e1b26a144144a12dfc10e8b6add5fb41d9b Mon Sep 17 00:00:00 2001 From: Cristina Date: Fri, 20 May 2016 16:41:30 +0100 Subject: [PATCH 063/101] + test generating a type mismatch for enum in java --- regression/cbmc-java/enum1/enum1$Name.class | Bin 0 -> 1229 bytes regression/cbmc-java/enum1/enum1.class | Bin 0 -> 518 bytes regression/cbmc-java/enum1/enum1.java | 27 ++++++++++++++++++++ regression/cbmc-java/enum1/test.desc | 8 ++++++ 4 files changed, 35 insertions(+) create mode 100644 regression/cbmc-java/enum1/enum1$Name.class create mode 100644 regression/cbmc-java/enum1/enum1.class create mode 100644 regression/cbmc-java/enum1/enum1.java create mode 100644 regression/cbmc-java/enum1/test.desc diff --git a/regression/cbmc-java/enum1/enum1$Name.class b/regression/cbmc-java/enum1/enum1$Name.class new file mode 100644 index 0000000000000000000000000000000000000000..620ea04a9fe63b9c02f7a09144247ee20e140003 GIT binary patch literal 1229 zcmZuwYfsZq7=F&yu3af?t1uZi5vOiLxu|$!;w}!XS+>LulEp8UQJ0a@lChEa5Bxbg zf*6g4&;BUmd&*?ZupiEQdEU$OzUTD!pYOi_Ji?nW1UytoTa%EK@I=7`p7P@vN1pRz zT}E6&Rw4BTw>M-=NqEWCoQ!D+d9D^@%y3zh@QOjq8%14b5Gv+@#h~hrW3`L6d30nQ zky*B!?!ju3gX;{Tg1)6!Y7A1LS}m9I71D~;?MkimmO(jeyB)XT+WH;?qmuHzd2H4` z9#Yv@nd{58=`@$U;#4ebw3?3D>9z?UAI7tp4GNKxJNfc<$zT|LH^k)Fw7Z;PB$Xb5 zgrd7gB_rjQV^z8byH>kq?%L#$yqxL>hWV7QpV4WzoaTCZs6n>nv^pCMssF_4x-b7? zp7ajGWa^5a&%q%%+pzlugDLKq^HnI(j?#d_n%Zz z!ls0+f1r0qD$;nZViCHESRwMBkId){{h-BBFd9o}`U{;U?(;EJUaHHc1x{#%AWGz`i1Ij^Jmq=q=D0@~|Mqr;)jg4|rZh6Efc*o`_6~#ymUX*-}w&ZkB>_~sX(v?)u;ZpBo*Q*(8SksiNBeb@!0?X literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/enum1/enum1.class b/regression/cbmc-java/enum1/enum1.class new file mode 100644 index 0000000000000000000000000000000000000000..f5ea86aff3970a731461efc75ba3fb778448d536 GIT binary patch literal 518 zcmZutO-lk%6g_V~oSZBzok_DVAxcA%B3h(GAOwQe!f4Z`rwuYT&d509FX)%FX&nSb z3x7cWq<_#VyKf?b=q>KK_uX^uJ@37JzD@ufU_*zBjE)$LI0aL~l7_5?9D{Pk2Npx3 z;kuSzclc;zjTmAz+qHvZ2DwKa$47lwwn8mARpO1OP z;cltX!@wFS zK%pNKM*L?b)tz}flTB%%u_DteY%ekZp*b7NUieZSUyw? zW%V9QWkcCNQu8_W3G#LAPGJwzcQH_k2Aa|K3{?iQFtI_ng&dN^Fd$8dq-sbp4GWC? Vd{9fmVkA#vhEN!ekss|O_XQDyU%CJQ literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/enum1/enum1.java b/regression/cbmc-java/enum1/enum1.java new file mode 100644 index 00000000000..4e35155e29c --- /dev/null +++ b/regression/cbmc-java/enum1/enum1.java @@ -0,0 +1,27 @@ +public class enum1 { + + public enum Name { + ASCII(1, String.class), + BIGINT(2, Long.class), + BOOLEAN(3, Boolean.class), + COUNTER(4, Long.class); + + final int protocolId; + final Class javaType; + + private Name(int protocolId, Class javaType) { + this.protocolId = protocolId; + this.javaType = javaType; + } + + }; + + public static void main(String args[]) { + int i = 0; + for (Name t : Name.values()) { + i += t.protocolId; + } + + } +} + diff --git a/regression/cbmc-java/enum1/test.desc b/regression/cbmc-java/enum1/test.desc new file mode 100644 index 00000000000..15de63a7ead --- /dev/null +++ b/regression/cbmc-java/enum1/test.desc @@ -0,0 +1,8 @@ +CORE +enum1.class + +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring \ No newline at end of file From 49395057e8b7029a9ecbc012b624a130d97a622d Mon Sep 17 00:00:00 2001 From: Cristina Date: Fri, 20 May 2016 16:54:51 +0100 Subject: [PATCH 064/101] + test failing to find a null pointer dereferencing when some classes are missing (pointer related assertions missing from the goto program) --- .../missing_class1/missing_class1.class | Bin 0 -> 360 bytes .../missing_class1/missing_class1.java | 16 ++++++++++++++++ regression/cbmc-java/missing_class1/test.desc | 8 ++++++++ 3 files changed, 24 insertions(+) create mode 100644 regression/cbmc-java/missing_class1/missing_class1.class create mode 100644 regression/cbmc-java/missing_class1/missing_class1.java create mode 100644 regression/cbmc-java/missing_class1/test.desc diff --git a/regression/cbmc-java/missing_class1/missing_class1.class b/regression/cbmc-java/missing_class1/missing_class1.class new file mode 100644 index 0000000000000000000000000000000000000000..9654a6aad1cd6b623ceb471d6d020c97972ca6c0 GIT binary patch literal 360 zcmY+9O-sW-5Qg80X=7rV#6;`&!CR|h5d;sFf)xZI>Y*Zt2ie3>HY6z|ssBqT6cqdc z{wQ&_m*Ot-v9s?pJNxtd`3>M4`xXp%2G%WT@Jx2Ti2xf0HVw21%}ZIxdO%p|be{wM!eO7YAzR9Ji$gT| zYiemA)ttS>rvr|}v2ip9eQ-ipW8Yj9Etc76ajv8njOrYNFKEwme&Tor{qAIj#$XBh S3yB)P#oK`omvM(N4elQTXgbya literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/missing_class1/missing_class1.java b/regression/cbmc-java/missing_class1/missing_class1.java new file mode 100644 index 00000000000..7525cdd2867 --- /dev/null +++ b/regression/cbmc-java/missing_class1/missing_class1.java @@ -0,0 +1,16 @@ +class B { + int j; +} + +class A { + int i; + B b; +} + +public class missing_class1 { + public static void main(String[] args) { + A a = new A(); + B b = a.b; + int j = b.j; // NULL pointer dereference + } +} diff --git a/regression/cbmc-java/missing_class1/test.desc b/regression/cbmc-java/missing_class1/test.desc new file mode 100644 index 00000000000..7f9f1a72c0b --- /dev/null +++ b/regression/cbmc-java/missing_class1/test.desc @@ -0,0 +1,8 @@ +CORE +missing_class1.class +--pointer-check +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +^warning: ignoring \ No newline at end of file From b17b7cc234c7d5f28f7b4e85a32f421b99fdb72a Mon Sep 17 00:00:00 2001 From: Cristina Date: Fri, 20 May 2016 17:03:01 +0100 Subject: [PATCH 065/101] + test generating a warning (ignoring java_string_literal) when instrumented with pointer checks --- .../pointer_check2/pointer_check2.class | Bin 0 -> 631 bytes .../pointer_check2/pointer_check2.java | 24 ++++++++++++++++++ regression/cbmc-java/pointer_check2/test.desc | 8 ++++++ 3 files changed, 32 insertions(+) create mode 100644 regression/cbmc-java/pointer_check2/pointer_check2.class create mode 100644 regression/cbmc-java/pointer_check2/pointer_check2.java create mode 100644 regression/cbmc-java/pointer_check2/test.desc diff --git a/regression/cbmc-java/pointer_check2/pointer_check2.class b/regression/cbmc-java/pointer_check2/pointer_check2.class new file mode 100644 index 0000000000000000000000000000000000000000..1428f9917674c73d2f64c6a82c52833af106b112 GIT binary patch literal 631 zcmY+B&u-H|5XQfC+-&SPG$bSeLTI5-lKzP$#I2|oB&0|VAW~IA9IB18O5NJ)C|#rG zReIvaxg1gnBp!f=s+e`fA(nP$ygT!oZ)X4A{`v#p4SW}6v^XBRu+TEwqY@sM(01?y z9T!ir;bIfdIG%HCF%;iMD$<7xg>LVd!G4!cB*S_TDfuBw#&Uin#xb4PiHHqT z6W@d%3pMpedLF6ifk~{4v4tj&tn8k&b35_Pr=)Q5+c$E5|sB29CDUt)y7)v$P zr}+dazn-_U8bxJhCMTu|nli`q0_L5}XVIb=fI1+rLza=Bbr?wXSK)GXoN3m86euD2VQCh+=Oe<$@6Aj?> oS0XVEam#3skT!XnsACIFnrsU-imJf6MVq6}@qlp>(8w{(f41j)bpQYW literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/pointer_check2/pointer_check2.java b/regression/cbmc-java/pointer_check2/pointer_check2.java new file mode 100644 index 00000000000..029200bee54 --- /dev/null +++ b/regression/cbmc-java/pointer_check2/pointer_check2.java @@ -0,0 +1,24 @@ +import java.util.*; + +class pointer_check2 +{ + public static void main(String[] args) + { + String s = null; + Random rand = new Random(); + int day = rand.nextInt(7); + + if (day == 0) + { + s = "Monday"; + } + else + { + if (day == 1) + { + s = "Tuesday" ; + } + } + System.out.println(s.length()); + } +} diff --git a/regression/cbmc-java/pointer_check2/test.desc b/regression/cbmc-java/pointer_check2/test.desc new file mode 100644 index 00000000000..4dec5bca133 --- /dev/null +++ b/regression/cbmc-java/pointer_check2/test.desc @@ -0,0 +1,8 @@ +CORE +pointer_check2.class +--pointer-check +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +^warning: ignoring \ No newline at end of file From fb2da2e60eba6683d0139f432a299d6c3d340449 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Mon, 23 May 2016 10:04:37 +0100 Subject: [PATCH 066/101] more work on MC/DC --- src/goto-instrument/cover.cpp | 61 ++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index 5b4f82c946d..085cdab7411 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -366,20 +366,21 @@ void instrument_cover_goals( case coverage_criteriont::CONDITION: // Conditions are all atomic predicates in the programs. { - std::set conditions= - collect_conditions(i_it); + const std::set conditions=collect_conditions(i_it); - source_locationt source_location=i_it->source_location; + const source_locationt source_location=i_it->source_location; for(const auto & c : conditions) { - std::string comment_t="condition `"+from_expr(ns, "", c)+"' true"; + const std::string c_string=from_expr(ns, "", c); + + const std::string comment_t="condition `"+c_string+"' true"; 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); - std::string comment_f="condition `"+from_expr(ns, "", c)+"' false"; + const std::string comment_f="condition `"+c_string+"' false"; goto_program.insert_before_swap(i_it); i_it->make_assertion(not_exprt(c)); i_it->source_location=source_location; @@ -394,20 +395,21 @@ void instrument_cover_goals( case coverage_criteriont::DECISION: // Decisions are maximal Boolean combinations of conditions. { - std::set decisions= - collect_decisions(i_it); + const std::set decisions=collect_decisions(i_it); - source_locationt source_location=i_it->source_location; + const source_locationt source_location=i_it->source_location; for(const auto & d : decisions) { - std::string comment_t="decision `"+from_expr(ns, "", d)+"' true"; + const std::string d_string=from_expr(ns, "", d); + + const std::string comment_t="decision `"+d_string+"' true"; 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); - std::string comment_f="decision `"+from_expr(ns, "", d)+"' false"; + const std::string comment_f="decision `"+d_string+"' false"; goto_program.insert_before_swap(i_it); i_it->make_assertion(not_exprt(d)); i_it->source_location=source_location; @@ -418,7 +420,6 @@ void instrument_cover_goals( i_it++; } break; - case coverage_criteriont::MCDC: // 1. Each entry and exit point is invoked @@ -426,6 +427,44 @@ void instrument_cover_goals( // 3. Each condition in a decision takes every possible outcome // 4. Each condition in a decision is shown to independently // affect the outcome of the decision. + { + const std::set conditions=collect_conditions(i_it); + 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())); + + const source_locationt source_location=i_it->source_location; + + for(const auto & p : both) + { + bool is_decision=decisions.find(p)!=decisions.end(); + bool is_condition=conditions.find(p)!=conditions.end(); + + std::string description= + (is_decision && is_condition)?"decision/condition": + is_decision?"decision":"condition"; + + std::string p_string=from_expr(ns, "", p); + + std::string comment_t=description+" `"+p_string+"' true"; + goto_program.insert_before_swap(i_it); + i_it->make_assertion(p); + i_it->source_location=source_location; + i_it->source_location.set_comment(comment_t); + + std::string comment_f=description+" `"+p_string+"' false"; + goto_program.insert_before_swap(i_it); + i_it->make_assertion(not_exprt(p)); + i_it->source_location=source_location; + i_it->source_location.set_comment(comment_f); + } + + for(unsigned i=0; i Date: Tue, 24 May 2016 08:21:29 +0100 Subject: [PATCH 067/101] missing header --- src/goto-instrument/cover.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index 085cdab7411..bea19537000 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -8,6 +8,8 @@ Date: May 2016 \*******************************************************************/ +#include + #include #include "cover.h" From fe72590f554987aca86cfaa7c5203d5f4b8033d9 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Tue, 24 May 2016 10:29:33 +0100 Subject: [PATCH 068/101] another go at superflous deads --- src/goto-programs/goto_convert.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/goto-programs/goto_convert.cpp b/src/goto-programs/goto_convert.cpp index 4297ceb8b8e..abf7b595cf7 100644 --- a/src/goto-programs/goto_convert.cpp +++ b/src/goto-programs/goto_convert.cpp @@ -542,7 +542,18 @@ void goto_convertt::convert( else copy(code, OTHER, dest); + // We only need to kill the temporaries if control + // can get to the end of the block. + #if 0 + if(!dest.empty() && + dest.instructions.back().is_goto() && + dest.instructions.back().guard.is_true()) + tmp_symbols.resize(old_tmp_symbols_size); + else + kill_tmp_symbols(old_tmp_symbols_size, dest); + #else kill_tmp_symbols(old_tmp_symbols_size, dest); + #endif // make sure dest is never empty if(dest.instructions.empty()) From 92484aa57b4497c7f315658dac36b271e7319108 Mon Sep 17 00:00:00 2001 From: marcelosousa Date: Tue, 24 May 2016 10:23:45 -0400 Subject: [PATCH 069/101] added script to run datastax benchmarks and changed test.pl to support inner class names --- regression/run-datastax.sh | 13 +++++++++++++ regression/test.pl | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100755 regression/run-datastax.sh diff --git a/regression/run-datastax.sh b/regression/run-datastax.sh new file mode 100755 index 00000000000..793be5a9097 --- /dev/null +++ b/regression/run-datastax.sh @@ -0,0 +1,13 @@ +#!/bin/bash +test_cases=`find cbmc-java/datastax/ -name *.desc -exec dirname {} \;` +./test.pl -c $1 ${test_cases} + +count=0 +for test_case in ${test_cases}; do + out_file=`find ${test_case} -name '*.out'` + if grep -q "identifier.*not found" ${out_file}; then + echo ${out_file} + count=$((${count}+1)) + fi +done; +echo "Missing symbols: ${count}" diff --git a/regression/test.pl b/regression/test.pl index d8b669c9a91..afd878fed9a 100755 --- a/regression/test.pl +++ b/regression/test.pl @@ -107,7 +107,7 @@ ($$$$$) my $r; $result =~ s/\\/\\\\/g; $result =~ s/([^\\])\$/$1\\r\\\\?\$/; - system("bash", "-c", "grep \$'$result' '$name/$output' >/dev/null"); + system("bash", "-c", "grep \$'$result' \"$name/$output\" >/dev/null"); $r = ($included ? $? != 0 : $? == 0); if($r) { print LOG "$result [FAILED]\n"; From e6517b31cbb569f2acad5ef018d73e267ca685b1 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Tue, 24 May 2016 20:48:01 +0100 Subject: [PATCH 070/101] more work on unnecessary destructor calls --- src/goto-programs/goto_convert.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/goto-programs/goto_convert.cpp b/src/goto-programs/goto_convert.cpp index abf7b595cf7..ea16e9c8547 100644 --- a/src/goto-programs/goto_convert.cpp +++ b/src/goto-programs/goto_convert.cpp @@ -618,7 +618,14 @@ void goto_convertt::convert_block( } // see if we need to do any destructors - unwind_destructor_stack(end_location, old_stack_size, dest); + if(!dest.empty() && + dest.instructions.back().is_goto() && + dest.instructions.back().guard.is_true()) + { + // don't do destructors when we are unreachable + } + else + unwind_destructor_stack(end_location, old_stack_size, dest); // remove those destructors targets.destructor_stack.resize(old_stack_size); @@ -1588,7 +1595,7 @@ void goto_convertt::convert_return( // Need to process _entire_ destructor stack. unwind_destructor_stack(code.source_location(), 0, dest); - + // add goto to end-of-function goto_programt::targett t=dest.add_instruction(); t->make_goto(targets.return_target, true_exprt()); From f02d8b36538aaad5913cc4b650874c10ee08ff7f Mon Sep 17 00:00:00 2001 From: marcelosousa Date: Wed, 25 May 2016 06:17:18 -0400 Subject: [PATCH 071/101] test.pl now supports multiple .desc files in directory --- regression/test.pl | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/regression/test.pl b/regression/test.pl index afd878fed9a..44d7cf0fbfb 100755 --- a/regression/test.pl +++ b/regression/test.pl @@ -59,7 +59,7 @@ ($) sub test($$$$$) { my ($name, $test, $t_level, $cmd, $ign) = @_; - my ($level, $input, $options, @results) = load("$name/$test"); + my ($level, $input, $options, @results) = load("$test"); $options =~ s/$ign//g if(defined($ign)); my $output = $input; @@ -212,7 +212,11 @@ ($$$$) print "Loading\n"; my @tests = @ARGV != 0 ? @ARGV : dirs(); -my $count = @tests; +my $count = 0; +for (@tests){ + my @testfiles = glob "$_/*desc"; + $count += $#testfiles+1; +} print " $count " . (1==$count?"test":"tests") . " found\n\n"; use Cwd qw(getcwd); @@ -225,20 +229,22 @@ ($) { my ($test) = @_; my $failed_skipped = 0; - - defined($pool) or print " Running $test"; - $failed_skipped = test($test, "test.desc", $t_level, $opt_c, $opt_i); - - lock($skips); - defined($pool) and print " Running $test"; - if(2 == $failed_skipped) { - $skips++; - print " [SKIPPED]\n"; - } elsif(0 == $failed_skipped) { - print " [OK]\n"; - } else { - $failures++; - print " [FAILED]\n"; + my @files = glob "$test/*.desc"; + for (0..$#files){ + defined($pool) or print " Running $files[$_]"; + $failed_skipped = test($test, $files[$_], $t_level, $opt_c, $opt_i); + + lock($skips); + defined($pool) and print " Running $test $files[$_]"; + if(2 == $failed_skipped) { + $skips++; + print " [SKIPPED]\n"; + } elsif(0 == $failed_skipped) { + print " [OK]\n"; + } else { + $failures++; + print " [FAILED]\n"; + } } } From cd402224a0ef28dbfecdd19f6853fd447900016c Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Wed, 25 May 2016 12:39:27 +0100 Subject: [PATCH 072/101] another test for branch coverage --- regression/cbmc-cover/branch2/main.c | 9 +++++++++ regression/cbmc-cover/branch2/test.desc | 9 +++++++++ 2 files changed, 18 insertions(+) create mode 100644 regression/cbmc-cover/branch2/main.c create mode 100644 regression/cbmc-cover/branch2/test.desc diff --git a/regression/cbmc-cover/branch2/main.c b/regression/cbmc-cover/branch2/main.c new file mode 100644 index 00000000000..afda13cd004 --- /dev/null +++ b/regression/cbmc-cover/branch2/main.c @@ -0,0 +1,9 @@ +#include + +int main() +{ + int ch; + while((ch=getc(stdin))!=-1) + { + } +} diff --git a/regression/cbmc-cover/branch2/test.desc b/regression/cbmc-cover/branch2/test.desc new file mode 100644 index 00000000000..52b687d5229 --- /dev/null +++ b/regression/cbmc-cover/branch2/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--cover branch --unwind 2 +^EXIT=0$ +^SIGNAL=0$ +^\[main.1\] file main.c line 6 function main function main block 5 branch false: SATISFIED +^\[main.2\] file main.c line 6 function main function main block 5 branch true: SATISFIED +-- +^warning: ignoring From 022b14b9885e81919d0f465b516e8286b7941e66 Mon Sep 17 00:00:00 2001 From: Daniel Poetzl Date: Wed, 25 May 2016 13:16:48 +0100 Subject: [PATCH 073/101] no malloc for void or when we don't know the type size --- src/java_bytecode/java_entry_point.cpp | 30 ++++++++++++++++---------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/java_bytecode/java_entry_point.cpp b/src/java_bytecode/java_entry_point.cpp index 65764e55fba..a37cb0c3d0b 100644 --- a/src/java_bytecode/java_entry_point.cpp +++ b/src/java_bytecode/java_entry_point.cpp @@ -204,20 +204,28 @@ void gen_nondet_init( // build size expression exprt object_size=size_of_expr(subtype, ns); - assert(!object_size.is_nil()); - - // malloc expression - side_effect_exprt malloc_expr(ID_malloc); - malloc_expr.copy_to_operands(object_size); - malloc_expr.type()=pointer_type; + if(subtype.id()!=ID_empty && !object_size.is_nil()) + { + // malloc expression + side_effect_exprt malloc_expr(ID_malloc); + malloc_expr.copy_to_operands(object_size); + malloc_expr.type()=pointer_type; - code_assignt code(expr, malloc_expr); - init_code.copy_to_operands(code); + code_assignt code(expr, malloc_expr); + init_code.copy_to_operands(code); - // dereference expression - dereference_exprt deref_expr(expr, subtype); + // dereference expression + dereference_exprt deref_expr(expr, subtype); - gen_nondet_init(deref_expr, init_code, ns, recursion_set, false, ""); + gen_nondet_init(deref_expr, init_code, ns, recursion_set, false, ""); + } + else + { + // make null + null_pointer_exprt null_pointer_expr(pointer_type); + code_assignt code(expr, null_pointer_expr); + init_code.copy_to_operands(code); + } } } } From c7c1b4034bf6c38906704d795a9470f12af632ae Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Wed, 25 May 2016 23:23:43 +0100 Subject: [PATCH 074/101] use ranged for --- src/cbmc/bmc_cover.cpp | 60 +++++++++++++----------------------------- 1 file changed, 19 insertions(+), 41 deletions(-) diff --git a/src/cbmc/bmc_cover.cpp b/src/cbmc/bmc_cover.cpp index 4bb42ac01d7..5788ab1f52f 100644 --- a/src/cbmc/bmc_cover.cpp +++ b/src/cbmc/bmc_cover.cpp @@ -69,12 +69,9 @@ class bmc_covert: void output(std::ostream &out) { - for(block_mapt::const_iterator - b_it=block_map.begin(); - b_it!=block_map.end(); - b_it++) - out << b_it->first->source_location - << " -> " << b_it->second + for(const auto &b_it : block_map) + out << b_it.first->source_location + << " -> " << b_it.second << '\n'; } }; @@ -136,11 +133,8 @@ class bmc_covert: { std::vector tmp; - for(instancest::const_iterator - it=instances.begin(); - it!=instances.end(); - it++) - tmp.push_back(literal_exprt(it->condition)); + for(const auto &it : instances) + tmp.push_back(literal_exprt(it.condition)); return conjunction(tmp); } @@ -176,29 +170,23 @@ Function: bmc_covert::goal_covered void bmc_covert::goal_covered(const cover_goalst::goalt &) { - for(goal_mapt::iterator - g_it=goal_map.begin(); - g_it!=goal_map.end(); - g_it++) + for(auto &g_it : goal_map) { - goalt &g=g_it->second; + goalt &g=g_it.second; // covered already? if(g.satisfied) continue; // check whether satisfied - for(goalt::instancest::const_iterator - c_it=g.instances.begin(); - c_it!=g.instances.end(); - c_it++) + for(const auto &c_it : g.instances) { - literalt cond=c_it->condition; + literalt cond=c_it.condition; if(solver.l_get(cond).is_true()) { status() << "Covered " << g.description << messaget::eom; g.satisfied=true; - symex_target_equationt::SSA_stepst::iterator next=c_it->step; + symex_target_equationt::SSA_stepst::iterator next=c_it.step; next++; // include the instruction itself build_goto_trace(bmc.equation, next, solver, bmc.ns, g.goto_trace); break; @@ -273,11 +261,8 @@ bool bmc_covert::operator()() } } - for(symex_target_equationt::SSA_stepst::iterator - it=bmc.equation.SSA_steps.begin(); - it!=bmc.equation.SSA_steps.end(); - it++) - it->cond_literal=literalt(0, 0); + for(auto & it : bmc.equation.SSA_steps) + it.cond_literal=literalt(0, 0); // Do conversion to next solver layer @@ -287,8 +272,7 @@ bool bmc_covert::operator()() // get the conditions for these goals from formula // collect all 'instances' of the goals - for(symex_target_equationt::SSA_stepst::iterator - it=bmc.equation.SSA_steps.begin(); + for(auto it = bmc.equation.SSA_steps.begin(); it!=bmc.equation.SSA_steps.end(); it++) { @@ -310,12 +294,9 @@ bool bmc_covert::operator()() cover_goals.register_observer(*this); - for(goal_mapt::const_iterator - it=goal_map.begin(); - it!=goal_map.end(); - it++) + for(const auto &it : goal_map) { - literalt l=solver.convert(it->second.as_expr()); + literalt l=solver.convert(it.second.as_expr()); cover_goals.add(l); } @@ -342,19 +323,16 @@ bool bmc_covert::operator()() unsigned goals_covered=0; - for(goal_mapt::const_iterator - it=goal_map.begin(); - it!=goal_map.end(); - it++) + for(const auto & it : goal_map) { - const goalt &goal=it->second; + const goalt &goal=it.second; if(goal.satisfied) goals_covered++; if(bmc.ui==ui_message_handlert::XML_UI) { xmlt xml_result("result"); - xml_result.set_attribute("goal", id2string(it->first)); + xml_result.set_attribute("goal", id2string(it.first)); xml_result.set_attribute("description", goal.description); xml_result.set_attribute("status", goal.satisfied?"SATISFIED":"FAILED"); @@ -368,7 +346,7 @@ bool bmc_covert::operator()() } else { - status() << "[" << it->first << "]"; + status() << "[" << it.first << "]"; if(goal.source_location.is_not_nil()) status() << ' ' << goal.source_location; From e3923c117200e2c62af014b63270f6c37f2215aa Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Wed, 25 May 2016 23:25:49 +0100 Subject: [PATCH 075/101] bugfix for multiple instances --- src/cbmc/bmc_cover.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cbmc/bmc_cover.cpp b/src/cbmc/bmc_cover.cpp index 5788ab1f52f..c5fc0469ff1 100644 --- a/src/cbmc/bmc_cover.cpp +++ b/src/cbmc/bmc_cover.cpp @@ -136,7 +136,7 @@ class bmc_covert: for(const auto &it : instances) tmp.push_back(literal_exprt(it.condition)); - return conjunction(tmp); + return disjunction(tmp); } }; @@ -288,7 +288,7 @@ bool bmc_covert::operator()() } } - status() << "Aiming to cover " << goal_map.size() << " goals" << eom; + status() << "Aiming to cover " << goal_map.size() << " goal(s)" << eom; cover_goalst cover_goals(solver); From 707e70f2d726934e975b5b736f12eded17e4f89d Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Thu, 26 May 2016 10:45:30 +0100 Subject: [PATCH 076/101] another test for branch coverage --- regression/cbmc-cover/branch3/main.c | 20 ++++++++++++++++++++ regression/cbmc-cover/branch3/test.desc | 8 ++++++++ 2 files changed, 28 insertions(+) create mode 100644 regression/cbmc-cover/branch3/main.c create mode 100644 regression/cbmc-cover/branch3/test.desc diff --git a/regression/cbmc-cover/branch3/main.c b/regression/cbmc-cover/branch3/main.c new file mode 100644 index 00000000000..c4446281161 --- /dev/null +++ b/regression/cbmc-cover/branch3/main.c @@ -0,0 +1,20 @@ +#include +#include + +int main() +{ + char ch; + unsigned state=0; + while((ch=getc(stdin))!=-1) + { + switch(state) + { + case 0: if(ch=='<') state=1; else state=0; break; + case 1: if(ch=='h') state=2; else state=0; break; + case 2: if(ch=='t') state=3; else state=0; break; + case 3: if(ch=='m') state=4; else state=0; break; + case 4: if(ch=='l') state=5; else state=0; break; + default:; + } + } +} diff --git a/regression/cbmc-cover/branch3/test.desc b/regression/cbmc-cover/branch3/test.desc new file mode 100644 index 00000000000..0b36798349f --- /dev/null +++ b/regression/cbmc-cover/branch3/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--cover branch --unwind 6 +^EXIT=0$ +^SIGNAL=0$ +^\*\* 22 of 22 covered (100.0%), using .* iterations$ +-- +^warning: ignoring From e506ff472cf07a229a51b98c6bcba1efae6347c7 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Fri, 27 May 2016 07:52:31 +0100 Subject: [PATCH 077/101] do not cover existing assertions --- src/goto-instrument/cover.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index bea19537000..bd631242e7d 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -34,8 +34,7 @@ class basic_blockst source_location_map[block_count]=it->source_location; next_is_target= - it->is_goto() || it->is_return() || - it->is_function_call() || it->is_assume(); + it->is_goto() || it->is_function_call(); } } @@ -156,7 +155,6 @@ std::set collect_conditions(const goto_programt::const_targett t) switch(t->type) { case GOTO: - case ASSUME: case ASSERT: return collect_conditions(t->guard); @@ -247,7 +245,6 @@ std::set collect_decisions(const goto_programt::const_targett t) switch(t->type) { case GOTO: - case ASSUME: case ASSERT: return collect_decisions(t->guard); @@ -311,9 +308,14 @@ void instrument_cover_goals( i_it->source_location.set_comment(comment); } } + else if(i_it->is_assert()) + i_it->make_skip(); break; case coverage_criteriont::LOCATION: + if(i_it->is_assert()) + i_it->make_skip(); + { unsigned block_nr=basic_blocks[i_it]; if(blocks_done.insert(block_nr).second) @@ -363,9 +365,15 @@ void instrument_cover_goals( i_it++; i_it++; } + else if(i_it->is_assert()) + i_it->make_skip(); + break; case coverage_criteriont::CONDITION: + if(i_it->is_assert()) + i_it->make_skip(); + // Conditions are all atomic predicates in the programs. { const std::set conditions=collect_conditions(i_it); @@ -395,6 +403,9 @@ void instrument_cover_goals( break; case coverage_criteriont::DECISION: + if(i_it->is_assert()) + i_it->make_skip(); + // Decisions are maximal Boolean combinations of conditions. { const std::set decisions=collect_decisions(i_it); @@ -424,6 +435,9 @@ void instrument_cover_goals( break; case coverage_criteriont::MCDC: + if(i_it->is_assert()) + i_it->make_skip(); + // 1. Each entry and exit point is invoked // 2. Each decision takes every possible outcome // 3. Each condition in a decision takes every possible outcome @@ -470,6 +484,8 @@ void instrument_cover_goals( break; case coverage_criteriont::PATH: + if(i_it->is_assert()) + i_it->make_skip(); break; default:; From 800d72cc030599958bd14c06a1f6e41f2ff9285e Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Fri, 27 May 2016 08:11:27 +0100 Subject: [PATCH 078/101] more tests --- regression/cbmc-cover/branch2/test.desc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/regression/cbmc-cover/branch2/test.desc b/regression/cbmc-cover/branch2/test.desc index 52b687d5229..79093e780b6 100644 --- a/regression/cbmc-cover/branch2/test.desc +++ b/regression/cbmc-cover/branch2/test.desc @@ -3,7 +3,7 @@ main.c --cover branch --unwind 2 ^EXIT=0$ ^SIGNAL=0$ -^\[main.1\] file main.c line 6 function main function main block 5 branch false: SATISFIED -^\[main.2\] file main.c line 6 function main function main block 5 branch true: SATISFIED +^\[main.1\] file main.c line 6 function main function main block 2 branch false: SATISFIED +^\[main.2\] file main.c line 6 function main function main block 2 branch true: SATISFIED -- ^warning: ignoring From 3309d9c3b89267fde2951d98e4e110672556b64b Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Fri, 27 May 2016 08:14:39 +0100 Subject: [PATCH 079/101] test that assertions are ignore --- regression/cbmc-cover/cover1/main.c | 3 +++ regression/cbmc-cover/cover1/test.desc | 1 + 2 files changed, 4 insertions(+) diff --git a/regression/cbmc-cover/cover1/main.c b/regression/cbmc-cover/cover1/main.c index 03714724776..58e813e34e7 100644 --- a/regression/cbmc-cover/cover1/main.c +++ b/regression/cbmc-cover/cover1/main.c @@ -9,4 +9,7 @@ int main() { __CPROVER_cover(!input1); // won't work } + + // should not produce a goal + __CPROVER_assert(input1, ""); } diff --git a/regression/cbmc-cover/cover1/test.desc b/regression/cbmc-cover/cover1/test.desc index 933418cbfd0..f0c123955bf 100644 --- a/regression/cbmc-cover/cover1/test.desc +++ b/regression/cbmc-cover/cover1/test.desc @@ -6,5 +6,6 @@ main.c ^\[main.1] file main.c line 5 function main condition .*: SATISFIED$ ^\[main.2] file main.c line 6 function main condition .*: SATISFIED$ ^\[main.3] file main.c line 10 function main condition .*: FAILED$ +^\*\* 2 of 3 covered (66.7%), using .* iterations$ -- ^warning: ignoring From 3018e8f7bbe692c4112914918fdf8752ac55d169 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Mon, 30 May 2016 10:48:36 +0100 Subject: [PATCH 080/101] make typecheckt API more similar to old one for transition --- src/util/typecheck.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/util/typecheck.h b/src/util/typecheck.h index 5823c0b2e34..c300bea81ca 100644 --- a/src/util/typecheck.h +++ b/src/util/typecheck.h @@ -44,7 +44,18 @@ class typecheckt:public messaget return messaget::error(); } + // not pretty, but makes transition easier + inline void err_location(const exprt &src) + { + error().source_location=src.find_source_location(); + } + bool error_found; + + inline bool get_error_found() const + { + return error_found; + } protected: // main function -- overload this one From b05f4c1aaf7bbbb34ef59f68c7f08942c0d93a83 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Mon, 30 May 2016 10:54:46 +0100 Subject: [PATCH 081/101] use new messaging API in typecheckers --- src/jsil/jsil_typecheck.cpp | 90 ++++++++++++++++++------------- src/jsil/jsil_typecheck.h | 4 +- src/linking/linking.cpp | 102 +++++++++++++++++------------------- src/linking/linking_class.h | 4 +- 4 files changed, 105 insertions(+), 95 deletions(-) diff --git a/src/jsil/jsil_typecheck.cpp b/src/jsil/jsil_typecheck.cpp index ee251f93f93..5f19edf5358 100644 --- a/src/jsil/jsil_typecheck.cpp +++ b/src/jsil/jsil_typecheck.cpp @@ -117,7 +117,7 @@ void jsil_typecheckt::make_type_compatible( if(type.id().empty() || type.is_nil()) { err_location(expr); - str << "make_type_compatible got empty type: " << expr.pretty(); + error() << "make_type_compatible got empty type: " << expr.pretty() << eom; throw 0; } @@ -133,10 +133,10 @@ void jsil_typecheckt::make_type_compatible( if(jsil_incompatible_types(expr.type(), type)) { err_location(expr); - str << "failed to typecheck expr " - << expr.pretty() << " with type " - << expr.type().pretty() - << "; required type " << type.pretty(); + error() << "failed to typecheck expr " + << expr.pretty() << " with type " + << expr.type().pretty() + << "; required type " << type.pretty() << eom; throw 0; } } @@ -190,8 +190,8 @@ void jsil_typecheckt::typecheck_type(typet &type) if(symbol_table.add(new_symbol)) { - str << "failed to add parameter symbol `" - << new_symbol.name << "' in the symbol table"; + error() << "failed to add parameter symbol `" + << new_symbol.name << "' in the symbol table" << eom; throw 0; } } @@ -254,7 +254,7 @@ void jsil_typecheckt::typecheck_expr_main(exprt &expr) if(expr.id()==ID_code) { err_location(expr); - str << "typecheck_expr_main got code: " << expr.pretty(); + error() << "typecheck_expr_main got code: " << expr.pretty() << eom; throw 0; } else if(expr.id()==ID_symbol) @@ -359,7 +359,7 @@ void jsil_typecheckt::typecheck_expr_main(exprt &expr) else { err_location(expr); - str << "unexpected expression: " << expr.pretty(); + error() << "unexpected expression: " << expr.pretty() << eom; throw 0; } } @@ -425,7 +425,8 @@ void jsil_typecheckt::typecheck_expr_proto_field(exprt &expr) if(expr.operands().size()!=2) { err_location(expr); - str << "operator `" << expr.id() << "' expects two operands"; + error() << "operator `" << expr.id() + << "' expects two operands" << eom; throw 0; } @@ -452,7 +453,8 @@ void jsil_typecheckt::typecheck_expr_proto_obj(exprt &expr) if(expr.operands().size()!=2) { err_location(expr); - str << "operator `" << expr.id() << "' expects two operands"; + error() << "operator `" << expr.id() + << "' expects two operands"; throw 0; } @@ -479,7 +481,8 @@ void jsil_typecheckt::typecheck_expr_delete(exprt &expr) if(expr.operands().size()!=2) { err_location(expr); - str << "operator `" << expr.id() << "' expects two operands"; + error() << "operator `" << expr.id() + << "' expects two operands" << eom; throw 0; } @@ -506,7 +509,8 @@ void jsil_typecheckt::typecheck_expr_index(exprt &expr) if(expr.operands().size()!=2) { err_location(expr); - str << "operator `" << expr.id() << "' expects two operands"; + error() << "operator `" << expr.id() + << "' expects two operands" << eom; throw 0; } @@ -537,7 +541,8 @@ void jsil_typecheckt::typecheck_expr_has_field(exprt &expr) if(expr.operands().size()!=2) { err_location(expr); - str << "operator `" << expr.id() << "' expects two operands"; + error() << "operator `" << expr.id() + << "' expects two operands" << eom; throw 0; } @@ -564,7 +569,8 @@ void jsil_typecheckt::typecheck_expr_field(exprt &expr) if(expr.operands().size()!=1) { err_location(expr); - str << "operator `" << expr.id() << "' expects single operand"; + error() << "operator `" << expr.id() + << "' expects single operand" << eom; throw 0; } @@ -590,7 +596,8 @@ void jsil_typecheckt::typecheck_expr_base(exprt &expr) if(expr.operands().size()!=1) { err_location(expr); - str << "operator `" << expr.id() << "' expects single operand"; + error() << "operator `" << expr.id() + << "' expects single operand" << eom; throw 0; } @@ -616,7 +623,8 @@ void jsil_typecheckt::typecheck_expr_ref(exprt &expr) if(expr.operands().size()!=3) { err_location(expr); - str << "operator `" << expr.id() << "' expects three operands"; + error() << "operator `" << expr.id() + << "' expects three operands" << eom; throw 0; } @@ -633,9 +641,9 @@ void jsil_typecheckt::typecheck_expr_ref(exprt &expr) else { err_location(expr); - str << "operator `" << expr.id() - << "' expects reference type in the third parameter. Got:" - << operand3.pretty(); + error() << "operator `" << expr.id() + << "' expects reference type in the third parameter. Got:" + << operand3.pretty() << eom; throw 0; } } @@ -657,7 +665,8 @@ void jsil_typecheckt::typecheck_expr_concatenation(exprt &expr) if(expr.operands().size()!=2) { err_location(expr); - str << "operator `" << expr.id() << "' expects two operands"; + error() << "operator `" << expr.id() + << "' expects two operands" << eom; throw 0; } @@ -684,7 +693,8 @@ void jsil_typecheckt::typecheck_expr_subtype(exprt &expr) if(expr.operands().size()!=2) { err_location(expr); - str << "operator `" << expr.id() << "' expects two operands"; + error() << "operator `" << expr.id() + << "' expects two operands" << eom; throw 0; } @@ -711,7 +721,8 @@ void jsil_typecheckt::typecheck_expr_binary_boolean(exprt &expr) if(expr.operands().size()!=2) { err_location(expr); - str << "operator `" << expr.id() << "' expects two operands"; + error() << "operator `" << expr.id() + << "' expects two operands" << eom; throw 0; } @@ -738,7 +749,8 @@ void jsil_typecheckt::typecheck_expr_binary_arith(exprt &expr) if(expr.operands().size()!=2) { err_location(expr); - str << "operator `" << expr.id() << "' expects two operands"; + error() << "operator `" << expr.id() + << "' expects two operands" << eom; throw 0; } @@ -766,7 +778,8 @@ void jsil_typecheckt::typecheck_exp_binary_equal(exprt &expr) if(expr.operands().size()!=2) { err_location(expr); - str << "operator `" << expr.id() << "' expects two operands"; + error() << "operator `" << expr.id() + << "' expects two operands" << eom; throw 0; } @@ -792,7 +805,8 @@ void jsil_typecheckt::typecheck_expr_binary_compare(exprt &expr) if(expr.operands().size()!=2) { err_location(expr); - str << "operator `" << expr.id() << "' expects two operands"; + error() << "operator `" << expr.id() + << "' expects two operands" << eom; throw 0; } @@ -819,7 +833,8 @@ void jsil_typecheckt::typecheck_expr_unary_boolean(exprt &expr) if(expr.operands().size()!=1) { err_location(expr); - str << "operator `" << expr.id() << "' expects one operand"; + error() << "operator `" << expr.id() + << "' expects one operand" << eom; throw 0; } @@ -845,7 +860,8 @@ void jsil_typecheckt::typecheck_expr_unary_string(exprt &expr) if(expr.operands().size()!=1) { err_location(expr); - str << "operator `" << expr.id() << "' expects one operand"; + error() << "operator `" << expr.id() + << "' expects one operand" << eom; throw 0; } @@ -871,7 +887,8 @@ void jsil_typecheckt::typecheck_expr_unary_num(exprt &expr) if(expr.operands().size()!=1) { err_location(expr); - str << "operator `" << expr.id() << "' expects one operand"; + error() << "operator `" << expr.id() + << "' expects one operand" << eom; throw 0; } @@ -946,8 +963,9 @@ void jsil_typecheckt::typecheck_symbol_expr(symbol_exprt &symbol_expr) if(symbol_table.add(new_symbol)) { - str << "failed to add symbol `" - << new_symbol.name << "' in the symbol table"; + error() << "failed to add symbol `" + << new_symbol.name << "' in the symbol table" + << eom; throw 0; } } @@ -1014,7 +1032,7 @@ void jsil_typecheckt::typecheck_code(codet &code) else { err_location(code); - str << "unexpected statement: " << statement; + error() << "unexpected statement: " << statement << eom; throw 0; } } @@ -1363,19 +1381,17 @@ bool jsil_typecheck( catch(int e) { - jsil_typecheck.error_msg(); + jsil_typecheck.error(); } catch(const char *e) { - jsil_typecheck.str << e; - jsil_typecheck.error_msg(); + jsil_typecheck.error() << e << messaget::eom; } catch(const std::string &e) { - jsil_typecheck.str << e; - jsil_typecheck.error_msg(); + jsil_typecheck.error() << e << messaget::eom; } return jsil_typecheck.get_error_found(); diff --git a/src/jsil/jsil_typecheck.h b/src/jsil/jsil_typecheck.h index ca6051418d5..c12a4525c9c 100644 --- a/src/jsil/jsil_typecheck.h +++ b/src/jsil/jsil_typecheck.h @@ -25,13 +25,13 @@ bool jsil_typecheck( message_handlert &message_handler, const namespacet &ns); -class jsil_typecheckt:public legacy_typecheckt +class jsil_typecheckt:public typecheckt { public: jsil_typecheckt( symbol_tablet &_symbol_table, message_handlert &_message_handler): - legacy_typecheckt(_message_handler), + typecheckt(_message_handler), symbol_table(_symbol_table), ns(symbol_table), proc_name() diff --git a/src/linking/linking.cpp b/src/linking/linking.cpp index 772a0d21576..76724e30856 100644 --- a/src/linking/linking.cpp +++ b/src/linking/linking.cpp @@ -176,8 +176,7 @@ void linkingt::detailed_conflict_report_rec( exprt &conflict_path) { #ifdef DEBUG - str << ""; - debug_msg(); + debug() << "" << eom; #endif std::string msg; @@ -402,19 +401,18 @@ void linkingt::detailed_conflict_report_rec( if(!msg.empty()) { - str << std::endl; - str << "reason for conflict at " - << expr_to_string(ns, "", conflict_path) - << ": " << msg << std::endl; - - str << std::endl; - str << type_to_string_verbose(ns, old_symbol, t1) << std::endl; - str << type_to_string_verbose(ns, new_symbol, t2) << std::endl; + error() << '\n'; + error() << "reason for conflict at " + << expr_to_string(ns, "", conflict_path) + << ": " << msg << '\n'; + + error() << '\n'; + error() << type_to_string_verbose(ns, old_symbol, t1) << '\n'; + error() << type_to_string_verbose(ns, new_symbol, t2) << '\n'; } #ifdef DEBUG - str << ""; - debug_msg(); + debug() << "" << eom; #endif } @@ -435,17 +433,17 @@ void linkingt::link_error( const symbolt &new_symbol, const std::string &msg) { - err_location(new_symbol.location); - - str << "error: " << msg << " `" - << old_symbol.display_name() - << "'" << "\n"; - str << "old definition in module `" << old_symbol.module - << "' " << old_symbol.location << "\n" - << type_to_string_verbose(ns, old_symbol) << "\n"; - str << "new definition in module `" << new_symbol.module - << "' " << new_symbol.location << "\n" - << type_to_string_verbose(ns, new_symbol); + error().source_location=new_symbol.location; + + error() << "error: " << msg << " `" + << old_symbol.display_name() + << "'" << '\n'; + error() << "old definition in module `" << old_symbol.module + << "' " << old_symbol.location << '\n' + << type_to_string_verbose(ns, old_symbol) << '\n'; + error() << "new definition in module `" << new_symbol.module + << "' " << new_symbol.location << '\n' + << type_to_string_verbose(ns, new_symbol) << eom; throw 0; } @@ -467,17 +465,15 @@ void linkingt::link_warning( const symbolt &new_symbol, const std::string &msg) { - str << "warning: " << msg << " \"" - << old_symbol.display_name() - << "\"" << std::endl; - str << "old definition in module " << old_symbol.module - << " " << old_symbol.location << std::endl - << type_to_string_verbose(ns, old_symbol) << std::endl; - str << "new definition in module " << new_symbol.module - << " " << new_symbol.location << std::endl - << type_to_string_verbose(ns, new_symbol) << std::endl; - - warning_msg(); + warning() << "warning: " << msg << " \"" + << old_symbol.display_name() + << "\"" << '\n'; + warning() << "old definition in module " << old_symbol.module + << " " << old_symbol.location << '\n' + << type_to_string_verbose(ns, old_symbol) << '\n'; + warning() << "new definition in module " << new_symbol.module + << " " << new_symbol.location << '\n' + << type_to_string_verbose(ns, new_symbol) << eom; } /*******************************************************************\ @@ -817,10 +813,9 @@ void linkingt::duplicate_code_symbol( else if(base_type_eq(old_symbol.type, new_symbol.type, ns)) { // keep the one in old_symbol -- libraries come last! - str << "warning: function `" << old_symbol.name << "' in module `" << - new_symbol.module << "' is shadowed by a definition in module `" << - old_symbol.module << "'" << std::endl; - warning_msg(); + warning() << "function `" << old_symbol.name << "' in module `" + << new_symbol.module << "' is shadowed by a definition in module `" + << old_symbol.module << "'" << eom; } else link_error( @@ -954,15 +949,15 @@ void linkingt::duplicate_object_symbol( else { err_location(new_symbol.value); - str << "error: conflicting initializers for variable \"" - << old_symbol.name - << "\"" << '\n'; - str << "old value in module " << old_symbol.module - << " " << old_symbol.value.find_source_location() << '\n' - << expr_to_string(ns, old_symbol.name, tmp_old) << '\n'; - str << "new value in module " << new_symbol.module - << " " << new_symbol.value.find_source_location() << '\n' - << expr_to_string(ns, new_symbol.name, tmp_new); + error() << "error: conflicting initializers for variable \"" + << old_symbol.name + << "\"" << '\n'; + error() << "old value in module " << old_symbol.module + << " " << old_symbol.value.find_source_location() << '\n' + << expr_to_string(ns, old_symbol.name, tmp_old) << '\n'; + error() << "new value in module " << new_symbol.module + << " " << new_symbol.value.find_source_location() << '\n' + << expr_to_string(ns, new_symbol.name, tmp_new) << eom; throw 0; } } @@ -1215,8 +1210,8 @@ void linkingt::do_type_dependencies(id_sett &needs_to_be_renamed) { queue.push(*d_it); #ifdef DEBUG - str << "LINKING: needs to be renamed (dependency): " << *d_it; - debug_msg(); + debug() << "LINKING: needs to be renamed (dependency): " + << *d_it << eom; #endif } } @@ -1255,9 +1250,8 @@ void linkingt::rename_symbols(const id_sett &needs_to_be_renamed) new_symbol.name=new_identifier; #ifdef DEBUG - str << "LINKING: renaming " << *it << " to " - << new_identifier; - debug_msg(); + debug() << "LINKING: renaming " << *it << " to " + << new_identifier << eom; #endif if(new_symbol.is_type) @@ -1364,8 +1358,8 @@ void linkingt::typecheck() { needs_to_be_renamed.insert(s_it->first); #ifdef DEBUG - str << "LINKING: needs to be renamed: " << s_it->first; - debug_msg(); + debug() << "LINKING: needs to be renamed: " + << s_it->first << eom; #endif } } diff --git a/src/linking/linking_class.h b/src/linking/linking_class.h index e15a33cb80e..40b6217102f 100644 --- a/src/linking/linking_class.h +++ b/src/linking/linking_class.h @@ -15,14 +15,14 @@ Author: Daniel Kroening, kroening@kroening.com #include #include -class linkingt:public legacy_typecheckt +class linkingt:public typecheckt { public: linkingt( symbol_tablet &_main_symbol_table, symbol_tablet &_src_symbol_table, message_handlert &_message_handler): - legacy_typecheckt(_message_handler), + typecheckt(_message_handler), main_symbol_table(_main_symbol_table), src_symbol_table(_src_symbol_table), ns(_main_symbol_table) From cb90b89b307a1cc21b56d774eb5a3ee3ceb76394 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Mon, 30 May 2016 10:57:13 +0100 Subject: [PATCH 082/101] use new messaging API in Java typechecker --- src/java_bytecode/java_bytecode_typecheck.h | 4 ++-- src/java_bytecode/java_bytecode_typecheck_expr.cpp | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/java_bytecode/java_bytecode_typecheck.h b/src/java_bytecode/java_bytecode_typecheck.h index b88d7d5f3e1..aae798ef280 100644 --- a/src/java_bytecode/java_bytecode_typecheck.h +++ b/src/java_bytecode/java_bytecode_typecheck.h @@ -27,13 +27,13 @@ bool java_bytecode_typecheck( message_handlert &message_handler, const namespacet &ns); -class java_bytecode_typecheckt:public legacy_typecheckt +class java_bytecode_typecheckt:public typecheckt { public: java_bytecode_typecheckt( symbol_tablet &_symbol_table, message_handlert &_message_handler): - legacy_typecheckt(_message_handler), + typecheckt(_message_handler), symbol_table(_symbol_table), ns(symbol_table) { diff --git a/src/java_bytecode/java_bytecode_typecheck_expr.cpp b/src/java_bytecode/java_bytecode_typecheck_expr.cpp index de42b23b2cc..e1e00ce817a 100644 --- a/src/java_bytecode/java_bytecode_typecheck_expr.cpp +++ b/src/java_bytecode/java_bytecode_typecheck_expr.cpp @@ -191,14 +191,9 @@ void java_bytecode_typecheckt::typecheck_expr_member(member_exprt &expr) expr.struct_op()=m; } - #if 0 warning().source_location=expr.source_location(); warning() << "failed to find field `" << component_name << "` in class hierarchy" << eom; - #else - warning_msg("failed to find field `"+ - id2string(component_name)+"` in class hierarchy"); - #endif // We replace by a non-det of same type side_effect_expr_nondett nondet(expr.type()); From 6fa1fdce72a9b4d9bb269568e5e3edfe9f1ed582 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Thu, 14 Apr 2016 11:29:36 +0000 Subject: [PATCH 083/101] Do not add unreachable instructions during goto conversion --- src/goto-programs/goto_convert.cpp | 52 +++---------------- src/goto-programs/goto_convert_class.h | 5 -- .../goto_convert_side_effect.cpp | 15 ++---- 3 files changed, 11 insertions(+), 61 deletions(-) diff --git a/src/goto-programs/goto_convert.cpp b/src/goto-programs/goto_convert.cpp index ea16e9c8547..4afea029858 100644 --- a/src/goto-programs/goto_convert.cpp +++ b/src/goto-programs/goto_convert.cpp @@ -419,8 +419,6 @@ void goto_convertt::convert( const codet &code, goto_programt &dest) { - std::size_t old_tmp_symbols_size=tmp_symbols.size(); - const irep_idt &statement=code.get_statement(); if(statement==ID_block) @@ -542,19 +540,6 @@ void goto_convertt::convert( else copy(code, OTHER, dest); - // We only need to kill the temporaries if control - // can get to the end of the block. - #if 0 - if(!dest.empty() && - dest.instructions.back().is_goto() && - dest.instructions.back().guard.is_true()) - tmp_symbols.resize(old_tmp_symbols_size); - else - kill_tmp_symbols(old_tmp_symbols_size, dest); - #else - kill_tmp_symbols(old_tmp_symbols_size, dest); - #endif - // make sure dest is never empty if(dest.instructions.empty()) { @@ -566,31 +551,6 @@ void goto_convertt::convert( /*******************************************************************\ -Function: goto_convertt::kill_tmp_symbols - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -void goto_convertt::kill_tmp_symbols( - std::size_t final_size, - goto_programt &dest) -{ - while(tmp_symbols.size()>final_size) - { - symbol_exprt symbol=tmp_symbols.back(); - tmp_symbols.pop_back(); - dest.add_instruction(DEAD); - dest.instructions.back().code=code_deadt(symbol); - } -} - -/*******************************************************************\ - Function: goto_convertt::convert_block Inputs: @@ -617,7 +577,8 @@ void goto_convertt::convert_block( convert(b_code, dest); } - // see if we need to do any destructors + // see if we need to do any destructors -- may have been processed + // in a prior break/continue/return already, don't create dead code if(!dest.empty() && dest.instructions.back().is_goto() && dest.instructions.back().guard.is_true()) @@ -2564,11 +2525,10 @@ symbolt &goto_convertt::new_tmp_symbol( new_symbol.location=source_location; } while(symbol_table.move(new_symbol, symbol_ptr)); - tmp_symbols.push_back(symbol_ptr->symbol_expr()); - - goto_programt::targett t=dest.add_instruction(DECL); - t->code=code_declt(symbol_ptr->symbol_expr()); - t->source_location=source_location; + code_declt decl; + decl.symbol()=symbol_ptr->symbol_expr(); + decl.add_source_location()=source_location; + convert_decl(decl, dest); return *symbol_ptr; } diff --git a/src/goto-programs/goto_convert_class.h b/src/goto-programs/goto_convert_class.h index c14ef4f32be..fe9115530f8 100644 --- a/src/goto-programs/goto_convert_class.h +++ b/src/goto-programs/goto_convert_class.h @@ -63,9 +63,6 @@ class goto_convertt:public message_streamt symbol_exprt make_compound_literal( const exprt &expr, goto_programt &dest); - - typedef std::list tmp_symbolst; - tmp_symbolst tmp_symbols; // // translation of C expressions (with side effects) @@ -87,8 +84,6 @@ class goto_convertt:public message_streamt exprt &expr, const std::string &suffix, goto_programt &); - - void kill_tmp_symbols(std::size_t, goto_programt &); void rewrite_boolean(exprt &dest); diff --git a/src/goto-programs/goto_convert_side_effect.cpp b/src/goto-programs/goto_convert_side_effect.cpp index 1a0909bdc82..0d6da6daa09 100644 --- a/src/goto-programs/goto_convert_side_effect.cpp +++ b/src/goto-programs/goto_convert_side_effect.cpp @@ -417,8 +417,6 @@ void goto_convertt::remove_function_call( new_name(new_symbol); - tmp_symbols.push_back(new_symbol.symbol_expr()); - { code_declt decl; decl.symbol()=new_symbol.symbol_expr(); @@ -488,7 +486,11 @@ void goto_convertt::remove_cpp_new( new_symbol.name=tmp_symbol_prefix+id2string(new_symbol.base_name); new_name(new_symbol); - tmp_symbols.push_back(new_symbol.symbol_expr()); + + code_declt decl; + decl.symbol()=new_symbol.symbol_expr(); + decl.add_source_location()=new_symbol.location; + convert_decl(decl, dest); call=code_assignt(new_symbol.symbol_expr(), expr); @@ -560,7 +562,6 @@ void goto_convertt::remove_malloc( new_symbol.location=expr.source_location(); new_name(new_symbol); - tmp_symbols.push_back(new_symbol.symbol_expr()); code_declt decl; decl.symbol()=new_symbol.symbol_expr(); @@ -703,15 +704,9 @@ void goto_convertt::remove_statement_expression( id2string(last.get(ID_statement))+"'"; { - // this likely needs to be a proper stack - tmp_symbolst old_tmp_symbols; - old_tmp_symbols.swap(tmp_symbols); - goto_programt tmp; convert(code, tmp); dest.destructive_append(tmp); - - old_tmp_symbols.swap(tmp_symbols); } static_cast(expr)=tmp_symbol_expr; From 38980173c6c7512950d2501d40179acbaa98142e Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Thu, 14 Apr 2016 15:12:53 +0000 Subject: [PATCH 084/101] Dead code analysis: no need to skip known-dead instructions with recent fix --- src/goto-analyzer/unreachable_instructions.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/goto-analyzer/unreachable_instructions.cpp b/src/goto-analyzer/unreachable_instructions.cpp index e7e88fe0116..3219e74a88b 100644 --- a/src/goto-analyzer/unreachable_instructions.cpp +++ b/src/goto-analyzer/unreachable_instructions.cpp @@ -47,12 +47,6 @@ static void unreachable_instructions( it!=dominators.cfg.entry_map.end(); ++it) { - if(it->first->is_dead() || - (it->first->is_assign() && - to_code_assign(it->first->code).lhs().get(ID_identifier)== - "__CPROVER_dead_object")) - continue; - const cfg_dominatorst::cfgt::nodet &n=dominators.cfg[it->second]; if(n.dominators.empty()) dest.insert(std::make_pair(it->first->location_number, @@ -78,11 +72,7 @@ static void all_unreachable( dead_mapt &dest) { forall_goto_program_instructions(it, goto_program) - if(!it->is_end_function() && - !it->is_dead() && - !(it->is_assign() && - to_code_assign(it->code).lhs().get(ID_identifier)== - "__CPROVER_dead_object")) + if(!it->is_end_function()) dest.insert(std::make_pair(it->location_number, it)); } From 46a10b47c76f9355029a4b939ea055e3d8a3c23c Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Sun, 6 Mar 2016 18:50:10 +0000 Subject: [PATCH 085/101] Object descriptor should skip typecasts --- src/util/std_expr.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/util/std_expr.cpp b/src/util/std_expr.cpp index 42fb6f13201..08a1cf59760 100644 --- a/src/util/std_expr.cpp +++ b/src/util/std_expr.cpp @@ -154,6 +154,14 @@ static void build_object_descriptor_rec( typecast_exprt(to_byte_extract_expr(expr).offset(), index_type)); } + else if(expr.id()==ID_typecast) + { + const typecast_exprt &tc=to_typecast_expr(expr); + + dest.object()=tc.op(); + + build_object_descriptor_rec(ns, tc.op(), dest); + } } /*******************************************************************\ From 03c1b4127a8c7f277cf859f5a298a28ed65ec685 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Fri, 18 Mar 2016 22:24:43 +0000 Subject: [PATCH 086/101] Do not require a constant member offset when building a byte-extract expression --- src/util/std_expr.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/util/std_expr.cpp b/src/util/std_expr.cpp index 08a1cf59760..25fbc97ad0f 100644 --- a/src/util/std_expr.cpp +++ b/src/util/std_expr.cpp @@ -125,20 +125,15 @@ static void build_object_descriptor_rec( { const member_exprt &member=to_member_expr(expr); const exprt &struct_op=member.struct_op(); - const typet &struct_type=ns.follow(struct_op.type()); build_object_descriptor_rec(ns, struct_op, dest); - if(struct_type.id()==ID_union) - return; - - mp_integer offset= - member_offset(to_struct_type(struct_type), - member.get_component_name(), ns); - assert(offset>=0); + exprt offset=member_offset_expr(member, ns); + assert(offset.is_not_nil()); dest.offset()= - plus_exprt(dest.offset(), from_integer(offset, index_type)); + plus_exprt(dest.offset(), + typecast_exprt(offset, index_type)); } else if(expr.id()==ID_byte_extract_little_endian || expr.id()==ID_byte_extract_big_endian) From 1f62eef4a60b03307ce04f6e0a591faff528be42 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Wed, 1 Jun 2016 18:25:30 +0100 Subject: [PATCH 087/101] more MC/DC --- src/goto-instrument/cover.cpp | 65 ++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index bd631242e7d..cc2c4194239 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -170,6 +170,55 @@ std::set collect_conditions(const goto_programt::const_targett t) /*******************************************************************\ +Function: collect_mcdc_controlling_rec + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void collect_mcdc_controlling_rec( + const exprt &src, + std::set &result) +{ + if(src.id()==ID_and) + { + } + else if(src.id()==ID_or) + { + } + else if(src.id()==ID_not) + collect_mcdc_controlling_rec(to_not_expr(src).op(), result); +} + +/*******************************************************************\ + +Function: collect_mcdc_controlling + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +std::set collect_mcdc_controlling( + const std::set &decisions) +{ + std::set result; + + for(const auto &d : decisions) + collect_mcdc_controlling_rec(d, result); + + return result; +} + +/*******************************************************************\ + Function: collect_decisions_rec Inputs: @@ -478,7 +527,21 @@ void instrument_cover_goals( i_it->source_location.set_comment(comment_f); } - for(unsigned i=0; i controlling; + controlling=collect_mcdc_controlling(decisions); + + for(const auto & p : controlling) + { + std::string description= + "MC/DC independence condition"; + + goto_program.insert_before_swap(i_it); + i_it->make_assertion(p); + i_it->source_location=source_location; + i_it->source_location.set_comment(description); + } + + for(unsigned i=0; i Date: Wed, 1 Jun 2016 19:28:38 +0100 Subject: [PATCH 088/101] fix java_string_literals --- src/java_bytecode/java_bytecode_parser.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/java_bytecode/java_bytecode_parser.cpp b/src/java_bytecode/java_bytecode_parser.cpp index ecacf2ab751..1d76529be19 100644 --- a/src/java_bytecode/java_bytecode_parser.cpp +++ b/src/java_bytecode/java_bytecode_parser.cpp @@ -552,6 +552,7 @@ void java_bytecode_parsert::rconstant_pool() { symbol_typet string_type("java::java.lang.String"); exprt result(ID_java_string_literal, pointer_typet(string_type)); + result.set(ID_value, pool_entry(it->ref1).s); it->expr=result; } break; From 39839426c416b70fdb58792bcc181d29aea1088f Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Wed, 1 Jun 2016 19:46:57 +0100 Subject: [PATCH 089/101] more MC/DC --- regression/cbmc-cover/mcdc1/main.c | 16 ++++++++++++++++ regression/cbmc-cover/mcdc1/test.desc | 8 ++++++++ src/goto-instrument/cover.cpp | 18 +++++++++++++++++- 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 regression/cbmc-cover/mcdc1/main.c create mode 100644 regression/cbmc-cover/mcdc1/test.desc diff --git a/regression/cbmc-cover/mcdc1/main.c b/regression/cbmc-cover/mcdc1/main.c new file mode 100644 index 00000000000..5c26f23df5e --- /dev/null +++ b/regression/cbmc-cover/mcdc1/main.c @@ -0,0 +1,16 @@ +int main() +{ + int input1, input2; + + if(input1 && input2) + { + // ok + } + + if(!input1) + input2=1; + + if(input1 && input2) // masked! + { + } +} diff --git a/regression/cbmc-cover/mcdc1/test.desc b/regression/cbmc-cover/mcdc1/test.desc new file mode 100644 index 00000000000..377c983c1aa --- /dev/null +++ b/regression/cbmc-cover/mcdc1/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--cover mcdc +^EXIT=0$ +^SIGNAL=0$ +^\*\* 17 of 18 covered +-- +^warning: ignoring diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index cc2c4194239..5f6970993f3 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -11,6 +11,7 @@ Date: May 2016 #include #include +#include #include "cover.h" @@ -186,6 +187,19 @@ void collect_mcdc_controlling_rec( { if(src.id()==ID_and) { + if(src.operands().size()==2) + { + exprt cond1= + conjunction({ src.op0(), not_exprt(src.op1()) }); + + exprt cond2= + conjunction({ not_exprt(src.op0()), src.op1() }); + + result.insert(cond1); + result.insert(cond2); + } + else + collect_mcdc_controlling_rec(make_binary(src), result); } else if(src.id()==ID_or) { @@ -532,8 +546,10 @@ void instrument_cover_goals( for(const auto & p : controlling) { + std::string p_string=from_expr(ns, "", p); + std::string description= - "MC/DC independence condition"; + "MC/DC independence condition `"+p_string+"'"; goto_program.insert_before_swap(i_it); i_it->make_assertion(p); From 639974d07b7a1b1edca6a739c35cc9d75cf27f27 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Thu, 2 Jun 2016 13:44:02 +0100 Subject: [PATCH 090/101] MC/DC now works --- regression/cbmc-cover/mcdc1/main.c | 16 ++- regression/cbmc-cover/mcdc1/test.desc | 2 +- src/goto-instrument/cover.cpp | 145 ++++++++++++++++++++------ 3 files changed, 122 insertions(+), 41 deletions(-) diff --git a/regression/cbmc-cover/mcdc1/main.c b/regression/cbmc-cover/mcdc1/main.c index 5c26f23df5e..11f46cd74e0 100644 --- a/regression/cbmc-cover/mcdc1/main.c +++ b/regression/cbmc-cover/mcdc1/main.c @@ -1,16 +1,14 @@ int main() { - int input1, input2; - - if(input1 && input2) + // Condition and decision coverage can be had with 2 tests, + // but MC/DC needs six (n+1 for n conditions). + + __CPROVER_bool A, B, C, D, E; + + if ((A || B) && C && D && E) { - // ok } - - if(!input1) - input2=1; - - if(input1 && input2) // masked! + else { } } diff --git a/regression/cbmc-cover/mcdc1/test.desc b/regression/cbmc-cover/mcdc1/test.desc index 377c983c1aa..83951c6a6e9 100644 --- a/regression/cbmc-cover/mcdc1/test.desc +++ b/regression/cbmc-cover/mcdc1/test.desc @@ -3,6 +3,6 @@ main.c --cover mcdc ^EXIT=0$ ^SIGNAL=0$ -^\*\* 17 of 18 covered +^\*\* .* of .* covered (100.0%), using 6 iterations$ -- ^warning: ignoring diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index 5f6970993f3..c0fa79158f8 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -64,6 +64,18 @@ class basic_blockst } }; +/*******************************************************************\ + +Function: as_string + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + const char *as_string(coverage_criteriont c) { switch(c) @@ -82,6 +94,30 @@ const char *as_string(coverage_criteriont c) /*******************************************************************\ +Function: is_condition + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool is_condition(const exprt &src) +{ + if(src.type().id()!=ID_bool) return false; + + // conditions are 'atomic predicates' + if(src.id()==ID_and || src.id()==ID_or || + src.id()==ID_not || src.id()==ID_implies) + return false; + + return true; +} + +/*******************************************************************\ + Function: collect_conditions_rec Inputs: @@ -102,22 +138,8 @@ void collect_conditions_rec(const exprt &src, std::set &dest) for(const auto & op : src.operands()) collect_conditions_rec(op, dest); - if(src.type().id()==ID_bool) - { - if(src.id()==ID_and || src.id()==ID_or || - src.id()==ID_not || src.id()==ID_implies) - { - // ignore me - } - else if(src.is_constant()) - { - // ignore me - } - else - { - dest.insert(src); - } - } + if(is_condition(src) && !src.is_constant()) + dest.insert(src); } /*******************************************************************\ @@ -171,6 +193,29 @@ std::set collect_conditions(const goto_programt::const_targett t) /*******************************************************************\ +Function: collect_operands + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void collect_operands(const exprt &src, std::vector &dest) +{ + for(const exprt &op : src.operands()) + { + if(op.id()==src.id()) + collect_operands(op, dest); + else + dest.push_back(op); + } +} + +/*******************************************************************\ + Function: collect_mcdc_controlling_rec Inputs: @@ -183,29 +228,67 @@ Function: collect_mcdc_controlling_rec void collect_mcdc_controlling_rec( const exprt &src, + const std::vector &conditions, std::set &result) { - if(src.id()==ID_and) + if(src.id()==ID_and || + src.id()==ID_or) { - if(src.operands().size()==2) - { - exprt cond1= - conjunction({ src.op0(), not_exprt(src.op1()) }); + std::vector operands; + collect_operands(src, operands); - exprt cond2= - conjunction({ not_exprt(src.op0()), src.op1() }); + if(operands.size()==1) + { + exprt e=*operands.begin(); + collect_mcdc_controlling_rec(e, conditions, result); + } + else if(!operands.empty()) + { + for(unsigned i=0; i o=operands; - result.insert(cond1); - result.insert(cond2); + // 'o[i]' needs to be true and false + std::vector new_conditions=conditions; + new_conditions.push_back(conjunction(o)); + result.insert(conjunction(new_conditions)); + + o[i].make_not(); + new_conditions.back()=conjunction(o); + result.insert(conjunction(new_conditions)); + } + else + { + std::vector others; + others.reserve(operands.size()-1); + + for(unsigned j=0; j new_conditions=conditions; + new_conditions.push_back(c); + + collect_mcdc_controlling_rec(op, new_conditions, result); + } + } } - else - collect_mcdc_controlling_rec(make_binary(src), result); } - else if(src.id()==ID_or) + else if(src.id()==ID_not) { + exprt e=to_not_expr(src).op(); + collect_mcdc_controlling_rec(e, conditions, result); } - else if(src.id()==ID_not) - collect_mcdc_controlling_rec(to_not_expr(src).op(), result); } /*******************************************************************\ @@ -226,7 +309,7 @@ std::set collect_mcdc_controlling( std::set result; for(const auto &d : decisions) - collect_mcdc_controlling_rec(d, result); + collect_mcdc_controlling_rec(d, { }, result); return result; } From 5a775c15c2e64e7639ef7611d4c64a6fda779bdd Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Sun, 5 Jun 2016 21:10:21 +0200 Subject: [PATCH 091/101] Fix consistency error in SSA level 1 renaming a5bc493713 introduced cases where information in the frame may become inconsistent with the actual renaming being used, as shown in the regression test. --- regression/cbmc/Local_out_of_scope2/main.c | 25 +++++++++++++++++++ regression/cbmc/Local_out_of_scope2/test.desc | 8 ++++++ src/goto-symex/symex_function_call.cpp | 2 +- 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 regression/cbmc/Local_out_of_scope2/main.c create mode 100644 regression/cbmc/Local_out_of_scope2/test.desc diff --git a/regression/cbmc/Local_out_of_scope2/main.c b/regression/cbmc/Local_out_of_scope2/main.c new file mode 100644 index 00000000000..0794c634c53 --- /dev/null +++ b/regression/cbmc/Local_out_of_scope2/main.c @@ -0,0 +1,25 @@ +inline void foo(int x) +{ +} + +void bar() +{ + foo(0); +} + +void foobar() +{ + // different argument values must not cause an inconsistency in the + // equation system + foo(0); + bar(); + foo(1); +} + +int main() +{ + foobar(); + foobar(); + __CPROVER_assert(0, ""); + return 0; +} diff --git a/regression/cbmc/Local_out_of_scope2/test.desc b/regression/cbmc/Local_out_of_scope2/test.desc new file mode 100644 index 00000000000..6de79559914 --- /dev/null +++ b/regression/cbmc/Local_out_of_scope2/test.desc @@ -0,0 +1,8 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/src/goto-symex/symex_function_call.cpp b/src/goto-symex/symex_function_call.cpp index cb16ffc7b1d..869a9193806 100644 --- a/src/goto-symex/symex_function_call.cpp +++ b/src/goto-symex/symex_function_call.cpp @@ -501,9 +501,9 @@ void goto_symext::locality( while(state.l1_history.find(l1_name)!=state.l1_history.end()) { state.level1.increase_counter(l0_name); + ++offset; ssa.set_level_1(frame_nr+offset); l1_name=ssa.get_identifier(); - ++offset; } // now unique -- store From 962b7d6489d5ebc9d05b1c37140a9f4de4b4a4fa Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Sun, 5 Jun 2016 21:50:42 +0200 Subject: [PATCH 092/101] Support for postfixed __attribute__((constructor)) Follow-up to 3f01cce50a to support void foo() __attribute__((constructor)); in addition to void __attribute__((constructor)) foo(); --- src/ansi-c/ansi_c_convert_type.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/ansi-c/ansi_c_convert_type.cpp b/src/ansi-c/ansi_c_convert_type.cpp index e35aa32d9b6..e6e953ad3b5 100644 --- a/src/ansi-c/ansi_c_convert_type.cpp +++ b/src/ansi-c/ansi_c_convert_type.cpp @@ -288,21 +288,28 @@ void ansi_c_convert_typet::write(typet &type) error_msg(); throw 0; } - else if(type.id()!=ID_empty) + + typet *type_p=&type; + if(type.id()==ID_code) + type_p=&(to_code_type(type).return_type()); + + else if(type_p->id()!=ID_empty) { err_location(source_location); - str << "constructor and destructor required to be type void"; + str << "constructor and destructor required to be type void, " + << "found " << type_p->pretty(); error_msg(); throw 0; } - type.id(constructor ? ID_constructor : ID_destructor); + type_p->id(constructor ? ID_constructor : ID_destructor); } } else if(constructor || destructor) { err_location(source_location); - str << "constructor and destructor required to be type void"; + str << "constructor and destructor required to be type void, " + << "found " << type.pretty(); error_msg(); throw 0; } From 5a64339028152b9a2bea0e569e170795ae070c76 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Mon, 6 Jun 2016 08:59:04 +0200 Subject: [PATCH 093/101] Fix java bytecode translation of control-flow joins Fixes if_expr1 regresion test. --- src/java_bytecode/java_bytecode_convert.cpp | 76 ++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/src/java_bytecode/java_bytecode_convert.cpp b/src/java_bytecode/java_bytecode_convert.cpp index 99eae9fd294..1debdd54e6e 100644 --- a/src/java_bytecode/java_bytecode_convert.cpp +++ b/src/java_bytecode/java_bytecode_convert.cpp @@ -599,6 +599,7 @@ codet java_bytecode_convertt::convert_instructions( instructionst::const_iterator source; std::list successors; + std::set predecessors; codet code; stackt stack; bool done; @@ -624,7 +625,8 @@ codet java_bytecode_convertt::convert_instructions( if(i_it->statement!="goto" && i_it->statement!="return" && - !(i_it->statement==patternt("?return"))) + !(i_it->statement==patternt("?return")) && + i_it->statement!="athrow") { instructionst::const_iterator next=i_it; if(++next!=instructions.end()) @@ -665,6 +667,20 @@ codet java_bytecode_convertt::convert_instructions( } } + for(address_mapt::iterator + it=address_map.begin(); + it!=address_map.end(); + ++it) + { + for(unsigned s : it->second.successors) + { + address_mapt::iterator a_it=address_map.find(s); + assert(a_it!=address_map.end()); + + a_it->second.predecessors.insert(it->first); + } + } + std::set working_set; if(!instructions.empty()) working_set.insert(instructions.front().address); @@ -685,6 +701,11 @@ codet java_bytecode_convertt::convert_instructions( a_it->second.stack.clear(); codet &c=a_it->second.code; + assert(stack.empty() || + a_it->second.predecessors.size()<=1 || + has_prefix(stack.front().get_string(ID_C_base_name), + "$stack")); + irep_idt statement=i_it->statement; exprt arg0=i_it->args.size()>=1?i_it->args[0]:nil_exprt(); exprt arg1=i_it->args.size()>=2?i_it->args[1]:nil_exprt(); @@ -1423,11 +1444,64 @@ codet java_bytecode_convertt::convert_instructions( address_mapt::iterator a_it2=address_map.find(*it); assert(a_it2!=address_map.end()); + if(!stack.empty() && a_it2->second.predecessors.size()>1) + { + // copy into temporaries + code_blockt more_code; + + // introduce temporaries when successor is seen for the first + // time + if(a_it2->second.stack.empty()) + { + for(stackt::iterator s_it=stack.begin(); + s_it!=stack.end(); + ++s_it) + { + symbol_exprt lhs=tmp_variable("$stack", s_it->type()); + code_assignt a(lhs, *s_it); + more_code.copy_to_operands(a); + + s_it->swap(lhs); + } + } + else + { + assert(a_it2->second.stack.size()==stack.size()); + stackt::const_iterator os_it=a_it2->second.stack.begin(); + for(stackt::iterator s_it=stack.begin(); + s_it!=stack.end(); + ++s_it) + { + assert(has_prefix(os_it->get_string(ID_C_base_name), + "$stack")); + symbol_exprt lhs=to_symbol_expr(*os_it); + code_assignt a(lhs, *s_it); + more_code.copy_to_operands(a); + + s_it->swap(lhs); + ++os_it; + } + } + + if(results.empty()) + { + more_code.copy_to_operands(c); + c.swap(more_code); + } + else + { + c.make_block(); + forall_operands(o_it, more_code) + c.copy_to_operands(*o_it); + } + } + a_it2->second.stack=stack; } } // TODO: add exception handlers from exception table + // review successor computation of athrow! code_blockt code; // temporaries From 02b66288cce63799b2a4408c58892c3fc93a9e69 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Mon, 6 Jun 2016 08:41:46 +0100 Subject: [PATCH 094/101] test from \#104 --- .../cbmc-java/static_method1/static_method1.class | Bin 0 -> 316 bytes .../cbmc-java/static_method1/static_method1.java | 12 ++++++++++++ regression/cbmc-java/static_method1/test.desc | 8 ++++++++ 3 files changed, 20 insertions(+) create mode 100644 regression/cbmc-java/static_method1/static_method1.class create mode 100644 regression/cbmc-java/static_method1/static_method1.java create mode 100644 regression/cbmc-java/static_method1/test.desc diff --git a/regression/cbmc-java/static_method1/static_method1.class b/regression/cbmc-java/static_method1/static_method1.class new file mode 100644 index 0000000000000000000000000000000000000000..06626cd8c91129762317e782f3228d004d781d78 GIT binary patch literal 316 zcmZvWPfJ2U6vfZ={nN=*aHqHsH`XEvT3VYR5JDG4+nV>BY~=YK*y#6i6}0FB_@SaR zwTQ@pxp(HC-#Og<=lchM3$zph94BZbXbR%7Ev&l|1jCaDL3mxxji7mJ3p3rUQnS9- zY0il}3!>p<;vrcG)Lpq*XXeIwvHj|_v)SXyxR-K%ezw$GT}OyW(D*9}T3#IGx>$^6 z>C$8leN?!SKLNM_BG#C{9=otdr*DuQAA*E6{vHZysPg`x16qAV((Qy#`QENs1aApKBBpT`WM=RE?NKp literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/static_method1/static_method1.java b/regression/cbmc-java/static_method1/static_method1.java new file mode 100644 index 00000000000..3da92fb1c50 --- /dev/null +++ b/regression/cbmc-java/static_method1/static_method1.java @@ -0,0 +1,12 @@ +public class static_method1 +{ + + static public void f(int a, int b) { + int c = b/(a+1); + } + + static public void g(int a, int b) { + int c = a/(b+1); + } + +} diff --git a/regression/cbmc-java/static_method1/test.desc b/regression/cbmc-java/static_method1/test.desc new file mode 100644 index 00000000000..209305bac89 --- /dev/null +++ b/regression/cbmc-java/static_method1/test.desc @@ -0,0 +1,8 @@ +CORE +static_method1.class + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +^warning: ignoring From 1fcc4eaad164ffb4abd1f1d395a862fb0d98f27b Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Tue, 7 Jun 2016 16:33:17 +0100 Subject: [PATCH 095/101] added test for static methods --- regression/cbmc-java/static_method1/test.desc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regression/cbmc-java/static_method1/test.desc b/regression/cbmc-java/static_method1/test.desc index 209305bac89..c26f4061d02 100644 --- a/regression/cbmc-java/static_method1/test.desc +++ b/regression/cbmc-java/static_method1/test.desc @@ -1,6 +1,6 @@ CORE static_method1.class - +--function "static_method1.f" --div-by-zero-check ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ From 5b67c0181ddd6a86271750ab797229c7237fc991 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Tue, 7 Jun 2016 16:33:48 +0100 Subject: [PATCH 096/101] methods can now be specified without java:: prefix and without type suffix, if unambiguous --- regression/cbmc-java/function1/test.desc | 2 +- regression/cbmc-java/function2/test.desc | 2 +- regression/cbmc-java/function3/test.desc | 2 +- src/java_bytecode/java_entry_point.cpp | 66 ++++++++++++++++++------ 4 files changed, 54 insertions(+), 18 deletions(-) diff --git a/regression/cbmc-java/function1/test.desc b/regression/cbmc-java/function1/test.desc index 1b33b740986..3800f47f81a 100644 --- a/regression/cbmc-java/function1/test.desc +++ b/regression/cbmc-java/function1/test.desc @@ -1,6 +1,6 @@ CORE Main.class ---function "java::Other.fail:()V" +--function "Other.fail:()V" ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/cbmc-java/function2/test.desc b/regression/cbmc-java/function2/test.desc index 6ce063c8359..423018ec7c8 100644 --- a/regression/cbmc-java/function2/test.desc +++ b/regression/cbmc-java/function2/test.desc @@ -1,6 +1,6 @@ CORE Main.class ---function "java::D.fail:()V" +--function "D.fail:()V" ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/cbmc-java/function3/test.desc b/regression/cbmc-java/function3/test.desc index fb68b442fdc..d035fa2e0a8 100644 --- a/regression/cbmc-java/function3/test.desc +++ b/regression/cbmc-java/function3/test.desc @@ -1,6 +1,6 @@ CORE Main.class ---function "java::A.dummy:()V" +--function "A.dummy:()V" ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/src/java_bytecode/java_entry_point.cpp b/src/java_bytecode/java_entry_point.cpp index a37cb0c3d0b..ba471f009b4 100644 --- a/src/java_bytecode/java_entry_point.cpp +++ b/src/java_bytecode/java_entry_point.cpp @@ -21,6 +21,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include +#include #include @@ -366,10 +367,6 @@ bool java_entry_point( symbol_table.symbols.end()) return false; // silently ignore -#if 0 - std::cout << "Main: " << config.main << std::endl; -#endif - messaget message(message_handler); code_blockt struct_init_code; // struct init code if needed @@ -381,15 +378,57 @@ bool java_entry_point( // find main symbol if(config.main!="") { - // look it up - symbol_tablet::symbolst::const_iterator s_it - =symbol_table.symbols.find(config.main); + // Add java:: prefix + std::string main_identifier="java::"+config.main; + + symbol_tablet::symbolst::const_iterator s_it; + + // Does it have a type signature? (':' suffix) + if(config.main.rfind(':')==std::string::npos) + { + std::string prefix=main_identifier+':'; + std::set matches; + + for(const auto & s : symbol_table.symbols) + if(has_prefix(id2string(s.first), prefix) && + s.second.type.id()==ID_code) + matches.insert(s.first); + + if(matches.empty()) + { + message.error() << "main symbol `" << config.main + << "' not found" << messaget::eom; + return true; + } + else if(matches.size()==1) + { + s_it=symbol_table.symbols.find(*matches.begin()); + assert(s_it!=symbol_table.symbols.end()); + } + else + { + message.error() << "main symbol `" << config.main + << "' is ambiguous:\n"; - if(s_it==symbol_table.symbols.end()) + for(const auto & s : matches) + message.error() << " " << s << '\n'; + + message.error() << messaget::eom; + + return true; + } + } + else { - message.error() << "main symbol `" << config.main - << "' not found" << messaget::eom; - return true; + // just look it up + s_it=symbol_table.symbols.find(main_identifier); + + if(s_it==symbol_table.symbols.end()) + { + message.error() << "main symbol `" << config.main + << "' not found" << messaget::eom; + return true; + } } // function symbol @@ -411,13 +450,10 @@ bool java_entry_point( } // get name of associated struct - size_t idx=config.main.rfind("."); + size_t idx=config.main.rfind('.'); assert(idx!=std::string::npos); assert(idx Date: Thu, 12 May 2016 10:48:47 +0100 Subject: [PATCH 097/101] For Java skip the check for dereference of a deallocated or dead object --- src/analyses/goto_check.cpp | 43 +++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/analyses/goto_check.cpp b/src/analyses/goto_check.cpp index 467ac8df0ef..8cd792f1fd0 100644 --- a/src/analyses/goto_check.cpp +++ b/src/analyses/goto_check.cpp @@ -944,23 +944,34 @@ void goto_checkt::pointer_validity_check( expr, guard); - if(flags.is_unknown() || flags.is_dynamic_heap()) - add_guarded_claim( - not_exprt(deallocated(pointer, ns)), - "dereference failure: deallocated dynamic object", - "pointer dereference", - expr.find_source_location(), - expr, - guard); - if(flags.is_unknown() || flags.is_dynamic_local()) - add_guarded_claim( - not_exprt(dead_object(pointer, ns)), - "dereference failure: dead object", - "pointer dereference", - expr.find_source_location(), - expr, - guard); + symbol_tablet symbol_table = ns.get_symbol_table(); + + symbol_tablet::symbolst::iterator s_it= + symbol_table.symbols.find(CPROVER_PREFIX "initialize"); + + // For Java don't check dereference of a deallocated or dead object + if (s_it==symbol_table.symbols.end() || (s_it->second).mode != ID_java) + { + + if(flags.is_unknown() || flags.is_dynamic_heap()) + add_guarded_claim( + not_exprt(deallocated(pointer, ns)), + "dereference failure: deallocated dynamic object", + "pointer dereference", + expr.find_source_location(), + expr, + guard); + + if(flags.is_unknown() || flags.is_dynamic_local()) + add_guarded_claim( + not_exprt(dead_object(pointer, ns)), + "dereference failure: dead object", + "pointer dereference", + expr.find_source_location(), + expr, + guard); + } if(enable_bounds_check) { From 6ccc3536c7b7cc7bcf9d3b06e1cbd40f896b2fd5 Mon Sep 17 00:00:00 2001 From: Cristina Date: Fri, 13 May 2016 12:55:41 +0100 Subject: [PATCH 098/101] + regression test for NULL object dereferencing in Java --- regression/cbmc-java/pointer_check1/A.class | Bin 0 -> 207 bytes regression/cbmc-java/pointer_check1/B.class | Bin 0 -> 277 bytes .../pointer_check1/pointer_check1.class | Bin 0 -> 335 bytes .../pointer_check1/pointer_check1.java | 21 ++++++++++++++++++ regression/cbmc-java/pointer_check1/test.desc | 8 +++++++ 5 files changed, 29 insertions(+) create mode 100644 regression/cbmc-java/pointer_check1/A.class create mode 100644 regression/cbmc-java/pointer_check1/B.class create mode 100644 regression/cbmc-java/pointer_check1/pointer_check1.class create mode 100644 regression/cbmc-java/pointer_check1/pointer_check1.java create mode 100644 regression/cbmc-java/pointer_check1/test.desc diff --git a/regression/cbmc-java/pointer_check1/A.class b/regression/cbmc-java/pointer_check1/A.class new file mode 100644 index 0000000000000000000000000000000000000000..a80b733cb82166ebb011b09541a224a368b9590c GIT binary patch literal 207 zcmXYqO$z~06o%hpz8K@9td%7eBwHydrNn}4b?3Tq$GD?u_+M7a!VmDHs&pg5n2o=2E9n!L;x2a-<%NYIrn2>4*gXaDVd>#0)Gz>mksCt;srKE YrY6rkbGi@E{TG+GyFZynK2rhZFVv(XoB#j- literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/pointer_check1/B.class b/regression/cbmc-java/pointer_check1/B.class new file mode 100644 index 0000000000000000000000000000000000000000..09ba3d25408dc7ed77dc3ffe780ac4baafb6a11b GIT binary patch literal 277 zcmZ9GL2JT55QX1F&1#ye)p`_qR11pqs0daN1kr=yRW|9Ot7%d~;;-tZAQXD&5Aa8c zvw{}~cINTTd%Jr&|NR4aL(M@Jj|CJ_5-1Bi5$wJWbuu7i8qF0UJBmIOp)}Q@nx&tf zikH$0nAjVYtYpBVF&*}r6N0md(%4sHZPwMVNQa4v*Zx-d`)+$D57I>rwm`*270(2E zCzK8E1Tx%o=H5>E3F9HZeK0rE1TV<&4^3HoI1YkfRp&{Dw0=Q9EC_k-W^HUh0S@b% T^%{OX!ur0m3N}43v*2C;OwB3~ literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/pointer_check1/pointer_check1.class b/regression/cbmc-java/pointer_check1/pointer_check1.class new file mode 100644 index 0000000000000000000000000000000000000000..891a91b81f7cf6f5503e6a04d44b53e603d24910 GIT binary patch literal 335 zcmY*U!AiqG5Pg%RiKa1W8|_W-m?{{=V^vT=5P}{m1@R!8xWujLMndX;d9k422l!Fq zY%j%ynfI7|?=kc9`}qyv7(*W}A`d+u79!L79tIv_f_tL0YR?FEGMW;c%lb(YqD*Od zvzX_yxf6NC6K5`zCJd8@Y$o1BS_xgIleSU192=uQsTWNluaptTueH*xY#xheS-cz_ z8b<&R8w9!tu#Fu;_+LZlt#fblnJijfu9WRmR7{fWd_20w9y)x9c@`H3g0RVKmysAd z`%BO}6JChByBc;`(nY}BNK>}jjL{dY`z7q`fIi@yu1(?UyU*DJgoxR;#c~VbA2RDY AQUCw| literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/pointer_check1/pointer_check1.java b/regression/cbmc-java/pointer_check1/pointer_check1.java new file mode 100644 index 00000000000..f3a3c312022 --- /dev/null +++ b/regression/cbmc-java/pointer_check1/pointer_check1.java @@ -0,0 +1,21 @@ +class A +{ + int val; +} + +class B +{ + int getVal(A a) + { + return a.val; + } +} + +class pointer_check1 +{ + public static void main(String[] args) + { + B b = new B(); + int myval = b.getVal(null); + } +} diff --git a/regression/cbmc-java/pointer_check1/test.desc b/regression/cbmc-java/pointer_check1/test.desc new file mode 100644 index 00000000000..03121d320c6 --- /dev/null +++ b/regression/cbmc-java/pointer_check1/test.desc @@ -0,0 +1,8 @@ +CORE +pointer_check1.class +--pointer-check +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +^warning: ignoring \ No newline at end of file From 5f4f49cfc5b49643c4a14379a8b143267ecbe8ed Mon Sep 17 00:00:00 2001 From: Cristina Date: Fri, 20 May 2016 16:41:30 +0100 Subject: [PATCH 099/101] + test generating a type mismatch for enum in java --- regression/cbmc-java/enum1/enum1$Name.class | Bin 0 -> 1229 bytes regression/cbmc-java/enum1/enum1.class | Bin 0 -> 518 bytes regression/cbmc-java/enum1/enum1.java | 27 ++++++++++++++++++++ regression/cbmc-java/enum1/test.desc | 8 ++++++ 4 files changed, 35 insertions(+) create mode 100644 regression/cbmc-java/enum1/enum1$Name.class create mode 100644 regression/cbmc-java/enum1/enum1.class create mode 100644 regression/cbmc-java/enum1/enum1.java create mode 100644 regression/cbmc-java/enum1/test.desc diff --git a/regression/cbmc-java/enum1/enum1$Name.class b/regression/cbmc-java/enum1/enum1$Name.class new file mode 100644 index 0000000000000000000000000000000000000000..620ea04a9fe63b9c02f7a09144247ee20e140003 GIT binary patch literal 1229 zcmZuwYfsZq7=F&yu3af?t1uZi5vOiLxu|$!;w}!XS+>LulEp8UQJ0a@lChEa5Bxbg zf*6g4&;BUmd&*?ZupiEQdEU$OzUTD!pYOi_Ji?nW1UytoTa%EK@I=7`p7P@vN1pRz zT}E6&Rw4BTw>M-=NqEWCoQ!D+d9D^@%y3zh@QOjq8%14b5Gv+@#h~hrW3`L6d30nQ zky*B!?!ju3gX;{Tg1)6!Y7A1LS}m9I71D~;?MkimmO(jeyB)XT+WH;?qmuHzd2H4` z9#Yv@nd{58=`@$U;#4ebw3?3D>9z?UAI7tp4GNKxJNfc<$zT|LH^k)Fw7Z;PB$Xb5 zgrd7gB_rjQV^z8byH>kq?%L#$yqxL>hWV7QpV4WzoaTCZs6n>nv^pCMssF_4x-b7? zp7ajGWa^5a&%q%%+pzlugDLKq^HnI(j?#d_n%Zz z!ls0+f1r0qD$;nZViCHESRwMBkId){{h-BBFd9o}`U{;U?(;EJUaHHc1x{#%AWGz`i1Ij^Jmq=q=D0@~|Mqr;)jg4|rZh6Efc*o`_6~#ymUX*-}w&ZkB>_~sX(v?)u;ZpBo*Q*(8SksiNBeb@!0?X literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/enum1/enum1.class b/regression/cbmc-java/enum1/enum1.class new file mode 100644 index 0000000000000000000000000000000000000000..f5ea86aff3970a731461efc75ba3fb778448d536 GIT binary patch literal 518 zcmZutO-lk%6g_V~oSZBzok_DVAxcA%B3h(GAOwQe!f4Z`rwuYT&d509FX)%FX&nSb z3x7cWq<_#VyKf?b=q>KK_uX^uJ@37JzD@ufU_*zBjE)$LI0aL~l7_5?9D{Pk2Npx3 z;kuSzclc;zjTmAz+qHvZ2DwKa$47lwwn8mARpO1OP z;cltX!@wFS zK%pNKM*L?b)tz}flTB%%u_DteY%ekZp*b7NUieZSUyw? zW%V9QWkcCNQu8_W3G#LAPGJwzcQH_k2Aa|K3{?iQFtI_ng&dN^Fd$8dq-sbp4GWC? Vd{9fmVkA#vhEN!ekss|O_XQDyU%CJQ literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/enum1/enum1.java b/regression/cbmc-java/enum1/enum1.java new file mode 100644 index 00000000000..4e35155e29c --- /dev/null +++ b/regression/cbmc-java/enum1/enum1.java @@ -0,0 +1,27 @@ +public class enum1 { + + public enum Name { + ASCII(1, String.class), + BIGINT(2, Long.class), + BOOLEAN(3, Boolean.class), + COUNTER(4, Long.class); + + final int protocolId; + final Class javaType; + + private Name(int protocolId, Class javaType) { + this.protocolId = protocolId; + this.javaType = javaType; + } + + }; + + public static void main(String args[]) { + int i = 0; + for (Name t : Name.values()) { + i += t.protocolId; + } + + } +} + diff --git a/regression/cbmc-java/enum1/test.desc b/regression/cbmc-java/enum1/test.desc new file mode 100644 index 00000000000..15de63a7ead --- /dev/null +++ b/regression/cbmc-java/enum1/test.desc @@ -0,0 +1,8 @@ +CORE +enum1.class + +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring \ No newline at end of file From 300416d7b4c030301a90ec46062a0b080dd51995 Mon Sep 17 00:00:00 2001 From: Cristina Date: Fri, 20 May 2016 16:54:51 +0100 Subject: [PATCH 100/101] + test failing to find a null pointer dereferencing when some classes are missing (pointer related assertions missing from the goto program) --- .../missing_class1/missing_class1.class | Bin 0 -> 360 bytes .../missing_class1/missing_class1.java | 16 ++++++++++++++++ regression/cbmc-java/missing_class1/test.desc | 8 ++++++++ 3 files changed, 24 insertions(+) create mode 100644 regression/cbmc-java/missing_class1/missing_class1.class create mode 100644 regression/cbmc-java/missing_class1/missing_class1.java create mode 100644 regression/cbmc-java/missing_class1/test.desc diff --git a/regression/cbmc-java/missing_class1/missing_class1.class b/regression/cbmc-java/missing_class1/missing_class1.class new file mode 100644 index 0000000000000000000000000000000000000000..9654a6aad1cd6b623ceb471d6d020c97972ca6c0 GIT binary patch literal 360 zcmY+9O-sW-5Qg80X=7rV#6;`&!CR|h5d;sFf)xZI>Y*Zt2ie3>HY6z|ssBqT6cqdc z{wQ&_m*Ot-v9s?pJNxtd`3>M4`xXp%2G%WT@Jx2Ti2xf0HVw21%}ZIxdO%p|be{wM!eO7YAzR9Ji$gT| zYiemA)ttS>rvr|}v2ip9eQ-ipW8Yj9Etc76ajv8njOrYNFKEwme&Tor{qAIj#$XBh S3yB)P#oK`omvM(N4elQTXgbya literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/missing_class1/missing_class1.java b/regression/cbmc-java/missing_class1/missing_class1.java new file mode 100644 index 00000000000..7525cdd2867 --- /dev/null +++ b/regression/cbmc-java/missing_class1/missing_class1.java @@ -0,0 +1,16 @@ +class B { + int j; +} + +class A { + int i; + B b; +} + +public class missing_class1 { + public static void main(String[] args) { + A a = new A(); + B b = a.b; + int j = b.j; // NULL pointer dereference + } +} diff --git a/regression/cbmc-java/missing_class1/test.desc b/regression/cbmc-java/missing_class1/test.desc new file mode 100644 index 00000000000..7f9f1a72c0b --- /dev/null +++ b/regression/cbmc-java/missing_class1/test.desc @@ -0,0 +1,8 @@ +CORE +missing_class1.class +--pointer-check +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +^warning: ignoring \ No newline at end of file From bd2ac45cba7c36a63b37e9f7880d083c4b640261 Mon Sep 17 00:00:00 2001 From: Cristina Date: Fri, 20 May 2016 17:03:01 +0100 Subject: [PATCH 101/101] + test generating a warning (ignoring java_string_literal) when instrumented with pointer checks --- .../pointer_check2/pointer_check2.class | Bin 0 -> 631 bytes .../pointer_check2/pointer_check2.java | 24 ++++++++++++++++++ regression/cbmc-java/pointer_check2/test.desc | 8 ++++++ 3 files changed, 32 insertions(+) create mode 100644 regression/cbmc-java/pointer_check2/pointer_check2.class create mode 100644 regression/cbmc-java/pointer_check2/pointer_check2.java create mode 100644 regression/cbmc-java/pointer_check2/test.desc diff --git a/regression/cbmc-java/pointer_check2/pointer_check2.class b/regression/cbmc-java/pointer_check2/pointer_check2.class new file mode 100644 index 0000000000000000000000000000000000000000..1428f9917674c73d2f64c6a82c52833af106b112 GIT binary patch literal 631 zcmY+B&u-H|5XQfC+-&SPG$bSeLTI5-lKzP$#I2|oB&0|VAW~IA9IB18O5NJ)C|#rG zReIvaxg1gnBp!f=s+e`fA(nP$ygT!oZ)X4A{`v#p4SW}6v^XBRu+TEwqY@sM(01?y z9T!ir;bIfdIG%HCF%;iMD$<7xg>LVd!G4!cB*S_TDfuBw#&Uin#xb4PiHHqT z6W@d%3pMpedLF6ifk~{4v4tj&tn8k&b35_Pr=)Q5+c$E5|sB29CDUt)y7)v$P zr}+dazn-_U8bxJhCMTu|nli`q0_L5}XVIb=fI1+rLza=Bbr?wXSK)GXoN3m86euD2VQCh+=Oe<$@6Aj?> oS0XVEam#3skT!XnsACIFnrsU-imJf6MVq6}@qlp>(8w{(f41j)bpQYW literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/pointer_check2/pointer_check2.java b/regression/cbmc-java/pointer_check2/pointer_check2.java new file mode 100644 index 00000000000..029200bee54 --- /dev/null +++ b/regression/cbmc-java/pointer_check2/pointer_check2.java @@ -0,0 +1,24 @@ +import java.util.*; + +class pointer_check2 +{ + public static void main(String[] args) + { + String s = null; + Random rand = new Random(); + int day = rand.nextInt(7); + + if (day == 0) + { + s = "Monday"; + } + else + { + if (day == 1) + { + s = "Tuesday" ; + } + } + System.out.println(s.length()); + } +} diff --git a/regression/cbmc-java/pointer_check2/test.desc b/regression/cbmc-java/pointer_check2/test.desc new file mode 100644 index 00000000000..4dec5bca133 --- /dev/null +++ b/regression/cbmc-java/pointer_check2/test.desc @@ -0,0 +1,8 @@ +CORE +pointer_check2.class +--pointer-check +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +^warning: ignoring \ No newline at end of file