Skip to content

Commit c8f69b5

Browse files
authored
Merge pull request diffblue#1108 from karkhaz/kk-neu-cprover-remove
goto-gcc removes CPROVER macros for native gcc
2 parents 52cbfe8 + ede380f commit c8f69b5

File tree

9 files changed

+182
-43
lines changed

9 files changed

+182
-43
lines changed

appveyor.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ test_script:
109109
rmdir /s /q cbmc-java\classpath1
110110
rmdir /s /q cbmc-java\jar-file3
111111
rmdir /s /q cbmc-java\tableswitch2
112+
rmdir /s /q goto-gcc
112113
rmdir /s /q goto-instrument\slice08
113114
114115
make test

regression/Makefile

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ DIRS = ansi-c \
66
cbmc-cover \
77
goto-analyzer \
88
goto-diff \
9+
goto-gcc \
910
goto-instrument \
1011
goto-instrument-typedef \
1112
invariants \
@@ -14,9 +15,14 @@ DIRS = ansi-c \
1415
test-script \
1516
# Empty last line
1617

17-
18+
# Check for the existence of $dir. Tests under goto-gcc cannot be run on
19+
# Windows, so appveyor.yml unlinks the entire directory under Windows.
1820
test:
19-
$(foreach var,$(DIRS), $(MAKE) -C $(var) test || exit 1;)
21+
@for dir in $(DIRS); do \
22+
if [ -d "$$dir" ]; then \
23+
$(MAKE) -C "$$dir" test || exit 1; \
24+
fi; \
25+
done;
2026

2127
clean:
2228
@for dir in *; do \

regression/goto-gcc/Makefile

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
default: tests.log
2+
3+
test:
4+
-@ln -s goto-cc ../../src/goto-cc/goto-gcc
5+
@if ! ../test.pl -c ../../../src/goto-cc/goto-gcc ; then \
6+
../failed-tests-printer.pl ; \
7+
exit 1 ; \
8+
fi
9+
10+
tests.log: ../test.pl
11+
-@ln -s goto-cc ../../src/goto-cc/goto-gcc
12+
@if ! ../test.pl -c ../../../src/goto-cc/goto-gcc ; then \
13+
../failed-tests-printer.pl ; \
14+
exit 1 ; \
15+
fi
16+
17+
show:
18+
@for dir in *; do \
19+
if [ -d "$$dir" ]; then \
20+
vim -o "$$dir/*.c" "$$dir/*.out"; \
21+
fi; \
22+
done;
23+
24+
clean:
25+
find -name '*.out' -execdir $(RM) '{}' \;
26+
find -name '*.gb' -execdir $(RM) '{}' \;
27+
$(RM) tests.log
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
int main()
2+
{
3+
unsigned x;
4+
__CPROVER_assume(x);
5+
__CPROVER_assert(x, "");
6+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
7+
^warning: ignoring
8+
^CONVERSION ERROR$
9+
--
10+
--
11+
goto-gcc must define out all CPROVER macros that are used in the
12+
codebase. This test succeeds iff GCC doesn't see the CPROVER macros in
13+
the test file.

src/goto-cc/compile.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ bool compilet::link()
379379
output_file_executable, symbol_table, compiled_functions))
380380
return true;
381381

382-
return false;
382+
return add_written_cprover_symbols(symbol_table);
383383
}
384384

385385
/// parses source files and writes object files, or keeps the symbols in the
@@ -430,6 +430,9 @@ bool compilet::compile()
430430
if(write_object_file(cfn, symbol_table, compiled_functions))
431431
return true;
432432

433+
if(add_written_cprover_symbols(symbol_table))
434+
return true;
435+
433436
symbol_table.clear(); // clean symbol table for next source file.
434437
compiled_functions.clear();
435438
}
@@ -616,6 +619,7 @@ bool compilet::write_bin_object_file(
616619
<< "; " << cnt << " have a body." << eom;
617620

618621
outfile.close();
622+
wrote_object=true;
619623

620624
return false;
621625
}
@@ -650,6 +654,7 @@ compilet::compilet(cmdlinet &_cmdline, ui_message_handlert &mh, bool Werror):
650654
{
651655
mode=COMPILE_LINK_EXECUTABLE;
652656
echo_file_name=false;
657+
wrote_object=false;
653658
working_directory=get_current_working_directory();
654659
}
655660

@@ -724,3 +729,28 @@ void compilet::convert_symbols(goto_functionst &dest)
724729
}
725730
}
726731
}
732+
733+
bool compilet::add_written_cprover_symbols(const symbol_tablet &symbol_table)
734+
{
735+
for(const auto &pair : symbol_table.symbols)
736+
{
737+
const irep_idt &name=pair.second.name;
738+
const typet &new_type=pair.second.type;
739+
if(!(has_prefix(id2string(name), CPROVER_PREFIX) && new_type.id()==ID_code))
740+
continue;
741+
742+
bool inserted;
743+
std::map<irep_idt, symbolt>::iterator old;
744+
std::tie(old, inserted)=written_macros.insert({name, pair.second});
745+
746+
if(!inserted && old->second.type!=new_type)
747+
{
748+
error() << "Incompatible CPROVER macro symbol types:" << eom
749+
<< old->second.type.pretty() << "(at " << old->second.location
750+
<< ")" << eom << "and" << eom << new_type.pretty()
751+
<< "(at " << pair.second.location << ")" << eom;
752+
return true;
753+
}
754+
}
755+
return false;
756+
}

src/goto-cc/compile.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,23 @@ class compilet:public language_uit
7272
const symbol_tablet &,
7373
goto_functionst &);
7474

75+
/// \brief Has this compiler written any object files?
76+
bool wrote_object_files() const { return wrote_object; }
77+
78+
/// \brief `__CPROVER_...` macros written to object files and their arities
79+
///
80+
/// \return A mapping from every `__CPROVER` macro that this compiler
81+
/// wrote to one or more object files, to how many parameters that
82+
/// `__CPROVER` macro has.
83+
void cprover_macro_arities(std::map<irep_idt,
84+
std::size_t> &cprover_macros) const
85+
{
86+
PRECONDITION(wrote_object);
87+
for(const auto &pair : written_macros)
88+
cprover_macros.insert({pair.first,
89+
to_code_type(pair.second.type).parameters().size()});
90+
}
91+
7592
protected:
7693
cmdlinet &cmdline;
7794
bool warning_is_fatal;
@@ -81,6 +98,16 @@ class compilet:public language_uit
8198
void add_compiler_specific_defines(class configt &config) const;
8299

83100
void convert_symbols(goto_functionst &dest);
101+
102+
bool add_written_cprover_symbols(const symbol_tablet &symbol_table);
103+
std::map<irep_idt, symbolt> written_macros;
104+
105+
// clients must only call add_written_cprover_symbols() if an object
106+
// file has been written. The case where an object file was written
107+
// but there were no __CPROVER symbols in the goto-program is distinct
108+
// from the case where the user forgot to write an object file before
109+
// calling add_written_cprover_symbols().
110+
bool wrote_object;
84111
};
85112

86113
#endif // CPROVER_GOTO_CC_COMPILE_H

src/goto-cc/gcc_mode.cpp

Lines changed: 62 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@ Author: CM Wintersteiger, 2006
1919
#include <sysexits.h>
2020
#endif
2121

22+
#include <cstddef>
2223
#include <cstdio>
2324
#include <iostream>
2425
#include <fstream>
2526
#include <cstring>
27+
#include <numeric>
28+
#include <sstream>
2629

2730
#include <util/string2int.h>
2831
#include <util/invariant.h>
@@ -337,10 +340,16 @@ int gcc_modet::doit()
337340
std::cout << "gcc version 3.4.4 (goto-cc " CBMC_VERSION ")\n";
338341
}
339342

343+
compilet compiler(cmdline,
344+
gcc_message_handler,
345+
cmdline.isset("Werror") &&
346+
cmdline.isset("Wextra") &&
347+
!cmdline.isset("Wno-error"));
348+
340349
if(cmdline.isset("version"))
341350
{
342351
if(produce_hybrid_binary)
343-
return run_gcc();
352+
return run_gcc(compiler);
344353

345354
std::cout << '\n' <<
346355
"Copyright (C) 2006-2014 Daniel Kroening, Christoph Wintersteiger\n" <<
@@ -354,7 +363,7 @@ int gcc_modet::doit()
354363
if(cmdline.isset("dumpversion"))
355364
{
356365
if(produce_hybrid_binary)
357-
return run_gcc();
366+
return run_gcc(compiler);
358367

359368
std::cout << "3.4.4\n";
360369
return EX_OK;
@@ -390,6 +399,24 @@ int gcc_modet::doit()
390399
debug() << "GCC mode" << eom;
391400
}
392401

402+
// determine actions to be undertaken
403+
if(act_as_ld)
404+
compiler.mode=compilet::LINK_LIBRARY;
405+
else if(cmdline.isset('S'))
406+
compiler.mode=compilet::ASSEMBLE_ONLY;
407+
else if(cmdline.isset('c'))
408+
compiler.mode=compilet::COMPILE_ONLY;
409+
else if(cmdline.isset('E'))
410+
{
411+
compiler.mode=compilet::PREPROCESS_ONLY;
412+
UNREACHABLE;
413+
}
414+
else if(cmdline.isset("shared") ||
415+
cmdline.isset('r')) // really not well documented
416+
compiler.mode=compilet::COMPILE_LINK;
417+
else
418+
compiler.mode=compilet::COMPILE_LINK_EXECUTABLE;
419+
393420
// In gcc mode, we have just pass on to gcc to handle the following:
394421
// * if -M or -MM is given, we do dependencies only
395422
// * preprocessing (-E)
@@ -402,7 +429,7 @@ int gcc_modet::doit()
402429
cmdline.isset("MM") ||
403430
cmdline.isset('E') ||
404431
!cmdline.have_infile_arg())
405-
return run_gcc(); // exit!
432+
return run_gcc(compiler); // exit!
406433

407434
// get configuration
408435
config.set(cmdline);
@@ -489,30 +516,6 @@ int gcc_modet::doit()
489516
if(cmdline.isset("fshort-double"))
490517
config.ansi_c.double_width=config.ansi_c.single_width;
491518

492-
// determine actions to be undertaken
493-
compilet compiler(cmdline,
494-
gcc_message_handler,
495-
cmdline.isset("Werror") &&
496-
cmdline.isset("Wextra") &&
497-
!cmdline.isset("Wno-error"));
498-
499-
if(act_as_ld)
500-
compiler.mode=compilet::LINK_LIBRARY;
501-
else if(cmdline.isset('S'))
502-
compiler.mode=compilet::ASSEMBLE_ONLY;
503-
else if(cmdline.isset('c'))
504-
compiler.mode=compilet::COMPILE_ONLY;
505-
else if(cmdline.isset('E'))
506-
{
507-
compiler.mode=compilet::PREPROCESS_ONLY;
508-
UNREACHABLE;
509-
}
510-
else if(cmdline.isset("shared") ||
511-
cmdline.isset('r')) // really not well documented
512-
compiler.mode=compilet::COMPILE_LINK;
513-
else
514-
compiler.mode=compilet::COMPILE_LINK_EXECUTABLE;
515-
516519
switch(compiler.mode)
517520
{
518521
case compilet::LINK_LIBRARY:
@@ -695,10 +698,10 @@ int gcc_modet::doit()
695698

696699
if(compiler.source_files.empty() &&
697700
compiler.object_files.empty())
698-
return run_gcc(); // exit!
701+
return run_gcc(compiler); // exit!
699702

700703
if(compiler.mode==compilet::ASSEMBLE_ONLY)
701-
return asm_output(act_as_bcc, compiler.source_files);
704+
return asm_output(act_as_bcc, compiler.source_files, compiler);
702705

703706
// do all the rest
704707
if(compiler.doit())
@@ -707,7 +710,7 @@ int gcc_modet::doit()
707710
// We can generate hybrid ELF and Mach-O binaries
708711
// containing both executable machine code and the goto-binary.
709712
if(produce_hybrid_binary && !act_as_bcc)
710-
return gcc_hybrid_binary();
713+
return gcc_hybrid_binary(compiler);
711714

712715
return EX_OK;
713716
}
@@ -791,8 +794,7 @@ int gcc_modet::preprocess(
791794
return run(new_argv[0], new_argv, cmdline.stdin_file, stdout_file);
792795
}
793796

794-
/// run gcc or clang with original command line
795-
int gcc_modet::run_gcc()
797+
int gcc_modet::run_gcc(const compilet &compiler)
796798
{
797799
PRECONDITION(!cmdline.parsed_argv.empty());
798800

@@ -802,6 +804,28 @@ int gcc_modet::run_gcc()
802804
for(const auto &a : cmdline.parsed_argv)
803805
new_argv.push_back(a.arg);
804806

807+
if(compiler.wrote_object_files())
808+
{
809+
// Undefine all __CPROVER macros for the system compiler
810+
std::map<irep_idt, std::size_t> arities;
811+
compiler.cprover_macro_arities(arities);
812+
for(const auto &pair : arities)
813+
{
814+
std::ostringstream addition;
815+
addition << "-D" << id2string(pair.first) << "(";
816+
std::vector<char> params(pair.second);
817+
std::iota(params.begin(), params.end(), 'a');
818+
for(std::vector<char>::iterator it=params.begin(); it!=params.end(); ++it)
819+
{
820+
addition << *it;
821+
if(it+1!=params.end())
822+
addition << ",";
823+
}
824+
addition << ")= ";
825+
new_argv.push_back(addition.str());
826+
}
827+
}
828+
805829
// overwrite argv[0]
806830
new_argv[0]=native_tool_name;
807831

@@ -813,7 +837,7 @@ int gcc_modet::run_gcc()
813837
return run(new_argv[0], new_argv, cmdline.stdin_file, "");
814838
}
815839

816-
int gcc_modet::gcc_hybrid_binary()
840+
int gcc_modet::gcc_hybrid_binary(const compilet &compiler)
817841
{
818842
{
819843
bool have_files=false;
@@ -861,7 +885,7 @@ int gcc_modet::gcc_hybrid_binary()
861885
if(output_files.empty() ||
862886
(output_files.size()==1 &&
863887
output_files.front()=="/dev/null"))
864-
return run_gcc();
888+
return EX_OK;
865889

866890
debug() << "Running " << native_tool_name
867891
<< " to generate hybrid binary" << eom;
@@ -893,7 +917,7 @@ int gcc_modet::gcc_hybrid_binary()
893917
}
894918
objcopy_cmd+="objcopy";
895919

896-
int result=run_gcc();
920+
int result=run_gcc(compiler);
897921

898922
// merge output from gcc with goto-binaries
899923
// using objcopy, or do cleanup if an earlier call failed
@@ -975,7 +999,8 @@ int gcc_modet::gcc_hybrid_binary()
975999

9761000
int gcc_modet::asm_output(
9771001
bool act_as_bcc,
978-
const std::list<std::string> &preprocessed_source_files)
1002+
const std::list<std::string> &preprocessed_source_files,
1003+
const compilet &compiler)
9791004
{
9801005
{
9811006
bool have_files=false;
@@ -996,7 +1021,7 @@ int gcc_modet::asm_output(
9961021
debug() << "Running " << native_tool_name
9971022
<< " to generate native asm output" << eom;
9981023

999-
int result=run_gcc();
1024+
int result=run_gcc(compiler);
10001025
if(result!=0)
10011026
// native tool failed
10021027
return result;

0 commit comments

Comments
 (0)