Skip to content

Commit 0f3582e

Browse files
committed
Add --keep-implementations switch to goto-cc
The --keep-implementations switch takes a comma-separated list of identifiers. When this switch is passed to goto-cc, the compiler will not remove the symbols and definitions for the named functions, even when they appear to be unused. This patch is to support running CBMC on projects that define many of their functions as static. Prior to this commit, users could not test the correctness of functions marked as static because the function definitions would not be exported by goto-cc.
1 parent 61d9ea8 commit 0f3582e

File tree

19 files changed

+208
-15
lines changed

19 files changed

+208
-15
lines changed

regression/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,4 @@ add_subdirectory(goto-cc-goto-analyzer)
5050
add_subdirectory(systemc)
5151
add_subdirectory(contracts)
5252
add_subdirectory(goto-harness)
53+
add_subdirectory(goto-cc-static)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
if(WIN32)
2+
set(is_windows true)
3+
else()
4+
set(is_windows false)
5+
endif()
6+
7+
add_test_pl_tests(
8+
"${CMAKE_CURRENT_SOURCE_DIR}/chain.sh $<TARGET_FILE:goto-cc> $<TARGET_FILE:cbmc> ${is_windows}"
9+
)

regression/goto-cc-static/chain.sh

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/usr/bin/env bash
2+
3+
goto_cc=$1
4+
cbmc=$2
5+
is_windows=$3
6+
7+
to_keep=""
8+
if [ $# -gt 3 ]; then
9+
if [ $4!='' ]; then
10+
to_keep="--keep-implementations $4"
11+
fi
12+
fi
13+
14+
cbmc_options=""
15+
if [ $# -gt 4 ]; then
16+
cbmc_options=${*:5:$#-5}
17+
fi
18+
19+
name=${*:$#}
20+
name=${name%.c}
21+
22+
if [[ "${is_windows}" == "true" ]]; then
23+
"${goto_cc}" ${to_keep} "${name}.c"
24+
mv "${name}.exe" "${name}.gb"
25+
else
26+
"${goto_cc}" ${to_keep} "${name}.c" -o "${name}.gb"
27+
fi
28+
29+
"${cbmc}" ${cbmc_options} "${name}.gb" ${cbmc_options}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
static int foo()
2+
{
3+
return 3;
4+
}
5+
6+
int main()
7+
{
8+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
main.c
3+
foo --show-symbol-table
4+
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
^Symbol......: foo$
8+
--
9+
^warning: ignoring
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
static int foo()
2+
{
3+
return 3;
4+
}
5+
6+
int main()
7+
{
8+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
main.c
3+
main --show-symbol-table
4+
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
^Symbol......: main$
8+
--
9+
^Symbol......: foo$
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
static int baz()
2+
{
3+
return 3;
4+
}
5+
6+
static int bar()
7+
{
8+
return 3;
9+
}
10+
11+
static int foo()
12+
{
13+
return 3;
14+
}
15+
16+
int main()
17+
{
18+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
foo,bar --show-symbol-table
4+
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
^Symbol......: foo$
8+
^Symbol......: bar$
9+
--
10+
^Symbol......: baz$

src/ansi-c/ansi_c_language.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ bool ansi_c_languaget::prv_typecheck(
119119
return true;
120120
}
121121

122-
if(remove_internal_symbols(new_symbol_table, *this))
122+
if(remove_internal_symbols(new_symbol_table, symbols_to_keep, *this))
123123
return true;
124124

125125
if(linking(symbol_table, new_symbol_table, get_message_handler()))

src/goto-cc/compile.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ bool compilet::parse_source(const std::string &file_name)
593593
return true;
594594

595595
// we just typecheck one file here
596-
if(language_files.typecheck(goto_model.symbol_table))
596+
if(language_files.typecheck(goto_model.symbol_table, symbols_to_keep))
597597
{
598598
error() << "CONVERSION ERROR" << eom;
599599
return true;
@@ -613,13 +613,20 @@ bool compilet::parse_source(const std::string &file_name)
613613
compilet::compilet(cmdlinet &_cmdline, message_handlert &mh, bool Werror)
614614
: messaget(mh),
615615
ns(goto_model.symbol_table),
616+
symbols_to_keep(),
616617
cmdline(_cmdline),
617618
warning_is_fatal(Werror)
618619
{
619620
mode=COMPILE_LINK_EXECUTABLE;
620621
echo_file_name=false;
621622
wrote_object=false;
622623
working_directory=get_current_working_directory();
624+
if(cmdline.isset("keep-implementations"))
625+
{
626+
std::list<std::string> csv =
627+
cmdline.get_comma_separated_values("keep-implementations");
628+
symbols_to_keep.insert(csv.begin(), csv.end());
629+
}
623630
}
624631

625632
/// cleans up temporary files

src/goto-cc/compile.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ class compilet : public messaget
9292
to_code_type(pair.second.type).parameters().size()});
9393
}
9494

95+
/// \brief Non-exported symbols that this compiler should NOT remove.
96+
std::set<std::string> symbols_to_keep;
97+
9598
protected:
9699
cmdlinet &cmdline;
97100
bool warning_is_fatal;

src/goto-cc/gcc_cmdline.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const char *goto_cc_options_with_separated_argument[]=
2727
"--native-compiler",
2828
"--native-linker",
2929
"--print-rejected-preprocessed-source",
30+
"--keep-implementations",
3031
nullptr
3132
};
3233

src/goto-cc/gcc_mode.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,20 @@ int gcc_modet::doit()
387387
return EX_OK; // Exit!
388388
}
389389

390+
if(cmdline.isset("keep-implementations"))
391+
{
392+
const std::list<std::string> csv =
393+
cmdline.get_comma_separated_values("keep-implementations");
394+
if(csv.empty())
395+
{
396+
error() << "Supply a comma-separated list of functions and variables to"
397+
" keep their implementations"
398+
<< eom;
399+
return EX_USAGE;
400+
}
401+
compiler.symbols_to_keep.insert(csv.begin(), csv.end());
402+
}
403+
390404
if(
391405
cmdline.isset("dumpmachine") || cmdline.isset("dumpspecs") ||
392406
cmdline.isset("dumpversion") || cmdline.isset("print-sysroot") ||

src/goto-cc/ms_cl_mode.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,20 @@ int ms_cl_modet::doit()
6565

6666
debug() << "Visual Studio mode " << ms_cl_version << eom;
6767

68+
if(cmdline.isset("keep-implementations"))
69+
{
70+
const std::list<std::string> csv =
71+
cmdline.get_comma_separated_values("keep-implementations");
72+
if(csv.empty())
73+
{
74+
error() << "Supply a comma-separated list of functions and variables to"
75+
" keep their implementations"
76+
<< eom;
77+
return EX_USAGE;
78+
}
79+
compiler.symbols_to_keep.insert(csv.begin(), csv.end());
80+
}
81+
6882
// model validation
6983
compiler.validate_goto_model = cmdline.isset("validate-goto-model");
7084

src/langapi/language_file.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ bool language_filest::parse()
8282
return false;
8383
}
8484

85-
bool language_filest::typecheck(symbol_tablet &symbol_table)
85+
bool language_filest::typecheck(
86+
symbol_tablet &symbol_table,
87+
const std::set<std::string> &symbols_to_keep)
8688
{
8789
// typecheck interfaces
8890

@@ -129,7 +131,7 @@ bool language_filest::typecheck(symbol_tablet &symbol_table)
129131
{
130132
if(file.second.modules.empty())
131133
{
132-
if(file.second.language->typecheck(symbol_table, ""))
134+
if(file.second.language->typecheck(symbol_table, "", symbols_to_keep))
133135
return true;
134136
// register lazy methods.
135137
// TODO: learn about modules and generalise this
@@ -145,7 +147,7 @@ bool language_filest::typecheck(symbol_tablet &symbol_table)
145147

146148
for(auto &module : module_map)
147149
{
148-
if(typecheck_module(symbol_table, module.second))
150+
if(typecheck_module(symbol_table, module.second, symbols_to_keep))
149151
return true;
150152
}
151153

@@ -195,7 +197,8 @@ bool language_filest::interfaces(
195197

196198
bool language_filest::typecheck_module(
197199
symbol_tablet &symbol_table,
198-
const std::string &module)
200+
const std::string &module,
201+
const std::set<std::string> &symbols_to_keep)
199202
{
200203
// check module map
201204

@@ -207,12 +210,13 @@ bool language_filest::typecheck_module(
207210
return true;
208211
}
209212

210-
return typecheck_module(symbol_table, it->second);
213+
return typecheck_module(symbol_table, it->second, symbols_to_keep);
211214
}
212215

213216
bool language_filest::typecheck_module(
214217
symbol_tablet &symbol_table,
215-
language_modulet &module)
218+
language_modulet &module,
219+
const std::set<std::string> &symbols_to_keep)
216220
{
217221
// already typechecked?
218222

@@ -240,7 +244,7 @@ bool language_filest::typecheck_module(
240244
it!=dependency_set.end();
241245
it++)
242246
{
243-
if(typecheck_module(symbol_table, *it))
247+
if(typecheck_module(symbol_table, *it, symbols_to_keep))
244248
{
245249
module.in_progress=false;
246250
return true;
@@ -251,7 +255,8 @@ bool language_filest::typecheck_module(
251255

252256
status() << "Type-checking " << module.name << eom;
253257

254-
if(module.file->language->typecheck(symbol_table, module.name))
258+
if(module.file->language->typecheck(
259+
symbol_table, module.name, symbols_to_keep))
255260
{
256261
module.in_progress=false;
257262
return true;

src/langapi/language_file.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ class language_filest:public messaget
107107

108108
bool generate_support_functions(symbol_tablet &symbol_table);
109109

110-
bool typecheck(symbol_tablet &symbol_table);
110+
bool typecheck(
111+
symbol_tablet &symbol_table,
112+
const std::set<std::string> &symbols_to_keep = {});
111113

112114
bool final(symbol_table_baset &symbol_table);
113115

@@ -141,11 +143,13 @@ class language_filest:public messaget
141143
protected:
142144
bool typecheck_module(
143145
symbol_tablet &symbol_table,
144-
language_modulet &module);
146+
language_modulet &module,
147+
const std::set<std::string> &symbols_to_keep);
145148

146149
bool typecheck_module(
147150
symbol_tablet &symbol_table,
148-
const std::string &module);
151+
const std::string &module,
152+
const std::set<std::string> &symbols_to_keep);
149153
};
150154

151155
#endif // CPROVER_UTIL_LANGUAGE_FILE_H

src/linking/remove_internal_symbols.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ Author: Daniel Kroening
1919

2020
#include "static_lifetime_init.h"
2121

22+
#include <algorithm>
23+
2224
static void get_symbols(
2325
const namespacet &ns,
2426
const symbolt &in_symbol,
@@ -66,12 +68,17 @@ static void get_symbols(
6668
/// * non-static function with body that is not extern inline
6769
/// * symbol used in an EXPORTED symbol
6870
/// * type used in an EXPORTED symbol
71+
/// * we also consider a symbol to be EXPORTED if it is a member of
72+
/// `symbols_to_keep`.
6973
///
7074
/// Read
7175
/// http://gcc.gnu.org/ml/gcc/2006-11/msg00006.html
7276
/// on "extern inline"
7377
/// \param symbol_table: symbol table to clean up
74-
bool remove_internal_symbols(symbol_tablet &symbol_table, messaget &log)
78+
bool remove_internal_symbols(
79+
symbol_tablet &symbol_table,
80+
const std::set<std::string> &symbols_to_keep,
81+
messaget &log)
7582
{
7683
namespacet ns(symbol_table);
7784
find_symbols_sett exported;
@@ -89,6 +96,10 @@ bool remove_internal_symbols(symbol_tablet &symbol_table, messaget &log)
8996
special.insert(CPROVER_PREFIX "dead_object");
9097
special.insert(CPROVER_PREFIX "rounding_mode");
9198

99+
find_symbols_sett user_kept;
100+
user_kept.insert(symbols_to_keep.begin(), symbols_to_keep.end());
101+
find_symbols_sett user_found;
102+
92103
for(symbol_tablet::symbolst::const_iterator
93104
it=symbol_table.symbols.begin();
94105
it!=symbol_table.symbols.end();
@@ -101,6 +112,14 @@ bool remove_internal_symbols(symbol_tablet &symbol_table, messaget &log)
101112
// not marked yet
102113
const symbolt &symbol=it->second;
103114

115+
if(user_kept.find(symbol.name) != user_kept.end())
116+
{
117+
log.debug() << "Keeping symbol '" << symbol.name << "'" << log.eom;
118+
get_symbols(ns, symbol, exported);
119+
user_found.insert(symbol.name);
120+
continue;
121+
}
122+
104123
if(special.find(symbol.name)!=special.end())
105124
{
106125
get_symbols(ns, symbol, exported);
@@ -147,6 +166,25 @@ bool remove_internal_symbols(symbol_tablet &symbol_table, messaget &log)
147166
}
148167
}
149168

169+
#if 0
170+
std::vector<irep_idt> diff;
171+
std::set_difference(
172+
user_kept.begin(),
173+
user_kept.end(),
174+
user_found.begin(),
175+
user_found.end(),
176+
std::inserter(diff, diff.begin()));
177+
if(!diff.empty())
178+
{
179+
log.error() << "Several symbols requested to be kept were not found"
180+
" in the object file: [";
181+
for(const auto &sym : diff)
182+
log.error() << sym << ", ";
183+
log.error() << "]" << log.eom;
184+
return true;
185+
}
186+
#endif
187+
150188
// remove all that are _not_ exported!
151189
for(symbol_tablet::symbolst::const_iterator
152190
it=symbol_table.symbols.begin();

0 commit comments

Comments
 (0)