Skip to content

Commit 1ab9364

Browse files
Merge pull request #3767 from chrisr-diffblue/validate_goto_programs_symbol_check_fixup
Fix up symbol naming checks so --validate-goto-model can be enabled in regression testing.
2 parents 053b556 + 933c2ef commit 1ab9364

File tree

15 files changed

+170
-39
lines changed

15 files changed

+170
-39
lines changed

regression/cbmc/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
add_test_pl_tests(
2-
"$<TARGET_FILE:cbmc>" -X smt-backend
2+
"$<TARGET_FILE:cbmc> --validate-goto-model" -X smt-backend
33
)

regression/cbmc/Makefile

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
default: tests.log
1+
default: test
22

33
test:
4-
@../test.pl -p -c ../../../src/cbmc/cbmc -X smt-backend
4+
@../test.pl -p -c "../../../src/cbmc/cbmc --validate-goto-model" -X smt-backend
55

66
test-cprover-smt2:
77
@../test.pl -p -c "../../../src/cbmc/cbmc --cprover-smt2"
88

9-
tests.log: ../test.pl
10-
@../test.pl -p -c ../../../src/cbmc/cbmc -X smt-backend
9+
tests.log: ../test.pl test
1110

1211
show:
1312
@for dir in *; do \

regression/cbmc/trace-values/trace-values.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include <stdlib.h>
2+
13
int global_var;
24

35
struct S

regression/cbmc/typedef-return-anon-struct1/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ main.c
55
activate-multi-line-match
66
EXIT=0
77
SIGNAL=0
8-
Base name\.+: return\nMode\.+: C\nType\.+: MYSTRUCT
8+
Base name\.+: return'\nMode\.+: C\nType\.+: MYSTRUCT
99
Base name\.+: fun\nMode\.+: C\nType\.+: MYSTRUCT \(\)
1010
--
1111
warning: ignoring

regression/goto-instrument-typedef/typedef-return-anon-struct1/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ main.c
55
activate-multi-line-match
66
EXIT=0
77
SIGNAL=0
8-
Base name\.+: return\nMode\.+: C\nType\.+: MYSTRUCT
8+
Base name\.+: return'\nMode\.+: C\nType\.+: MYSTRUCT
99
Base name\.+: fun\nMode\.+: C\nType\.+: MYSTRUCT \(\)
1010
--
1111
warning: ignoring

src/ansi-c/ansi_c_entry_point.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ bool generate_ansi_c_start_function(
238238
return_symbol.mode=ID_C;
239239
return_symbol.is_static_lifetime=false;
240240
return_symbol.name="return'";
241-
return_symbol.base_name="return";
241+
return_symbol.base_name = "return'";
242242
return_symbol.type=to_code_type(symbol.type).return_type();
243243

244244
symbol_table.add(return_symbol);
@@ -261,7 +261,7 @@ bool generate_ansi_c_start_function(
261261
{
262262
symbolt argc_symbol;
263263

264-
argc_symbol.base_name = "argc";
264+
argc_symbol.base_name = "argc'";
265265
argc_symbol.name = "argc'";
266266
argc_symbol.type = signed_int_type();
267267
argc_symbol.is_static_lifetime = true;

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,7 @@ void c_typecheck_baset::typecheck_expr_builtin_va_arg(exprt &expr)
538538
symbol.base_name=ID_gcc_builtin_va_arg;
539539
symbol.name=ID_gcc_builtin_va_arg;
540540
symbol.type=symbol_type;
541+
symbol.mode = ID_C;
541542

542543
symbol_table.insert(std::move(symbol));
543544
}

src/ansi-c/c_typecheck_type.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,7 @@ void c_typecheck_baset::typecheck_compound_type(struct_union_typet &type)
769769
typecheck_compound_body(to_struct_union_type(compound_symbol.type));
770770

771771
std::string typestr = type2name(compound_symbol.type, *this);
772-
compound_symbol.base_name="#anon-"+typestr;
772+
compound_symbol.base_name = "#anon#" + typestr;
773773
compound_symbol.name="tag-#anon#"+typestr;
774774
identifier=compound_symbol.name;
775775

src/goto-programs/goto_convert_class.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ class goto_convertt:public messaget
335335

336336
typedef std::vector<codet> destructor_stackt;
337337

338-
symbol_exprt exception_flag();
338+
symbol_exprt exception_flag(const irep_idt &mode);
339339
void unwind_destructor_stack(
340340
const source_locationt &,
341341
std::size_t stack_size,

src/goto-programs/goto_convert_exceptions.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ void goto_convertt::convert_CPROVER_try_catch(
168168
targets.set_throw(tmp.instructions.begin());
169169

170170
// now put 'catch' code onto destructor stack
171-
code_ifthenelset catch_code(exception_flag(), to_code(code.op1()));
171+
code_ifthenelset catch_code(exception_flag(mode), to_code(code.op1()));
172172
catch_code.add_source_location()=code.source_location();
173173

174174
targets.destructor_stack.push_back(std::move(catch_code));
@@ -194,7 +194,7 @@ void goto_convertt::convert_CPROVER_throw(
194194
dest.add_instruction(ASSIGN);
195195

196196
t_set_exception->source_location=code.source_location();
197-
t_set_exception->code=code_assignt(exception_flag(), true_exprt());
197+
t_set_exception->code = code_assignt(exception_flag(mode), true_exprt());
198198
}
199199

200200
// do we catch locally?
@@ -244,7 +244,7 @@ void goto_convertt::convert_CPROVER_try_finally(
244244
convert(to_code(code.op1()), dest, mode);
245245
}
246246

247-
symbol_exprt goto_convertt::exception_flag()
247+
symbol_exprt goto_convertt::exception_flag(const irep_idt &mode)
248248
{
249249
irep_idt id="$exception_flag";
250250

@@ -260,6 +260,7 @@ symbol_exprt goto_convertt::exception_flag()
260260
new_symbol.is_thread_local=true;
261261
new_symbol.is_file_local=false;
262262
new_symbol.type=bool_typet();
263+
new_symbol.mode = mode;
263264
symbol_table.insert(std::move(new_symbol));
264265
}
265266

src/goto-programs/goto_function.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,36 @@ void get_local_identifiers(
3131
dest.insert(identifier);
3232
}
3333
}
34+
35+
/// Check that the goto function is well-formed
36+
///
37+
/// The validation mode indicates whether well-formedness check failures are
38+
/// reported via DATA_INVARIANT violations or exceptions.
39+
void goto_functiont::validate(const namespacet &ns, const validation_modet vm)
40+
const
41+
{
42+
body.validate(ns, vm);
43+
44+
find_symbols_sett typetags;
45+
find_type_symbols(type, typetags);
46+
const symbolt *symbol;
47+
for(const auto &identifier : typetags)
48+
{
49+
DATA_CHECK(
50+
vm, !ns.lookup(identifier, symbol), id2string(identifier) + " not found");
51+
}
52+
53+
// Check that a void function does not contain any RETURN instructions
54+
if(to_code_type(type).return_type().id() == ID_empty)
55+
{
56+
forall_goto_program_instructions(instruction, body)
57+
{
58+
DATA_CHECK(
59+
vm,
60+
!instruction->is_return(),
61+
"void function should not return a value");
62+
}
63+
}
64+
65+
validate_full_type(type, ns, vm);
66+
}

src/goto-programs/goto_function.h

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -116,23 +116,7 @@ class goto_functiont
116116
///
117117
/// The validation mode indicates whether well-formedness check failures are
118118
/// reported via DATA_INVARIANT violations or exceptions.
119-
void validate(const namespacet &ns, const validation_modet vm) const
120-
{
121-
body.validate(ns, vm);
122-
123-
find_symbols_sett typetags;
124-
find_type_symbols(type, typetags);
125-
const symbolt *symbol;
126-
for(const auto &identifier : typetags)
127-
{
128-
DATA_CHECK(
129-
vm,
130-
!ns.lookup(identifier, symbol),
131-
id2string(identifier) + " not found");
132-
}
133-
134-
validate_full_type(type, ns, vm);
135-
}
119+
void validate(const namespacet &ns, const validation_modet vm) const;
136120
};
137121

138122
void get_local_identifiers(const goto_functiont &, std::set<irep_idt> &dest);

src/goto-programs/goto_program.cpp

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ Author: Daniel Kroening, [email protected]
2222

2323
#include <langapi/language_util.h>
2424

25+
#include "remove_returns.h"
26+
2527
/// Writes to \p out a two/three line string representation of a given
2628
/// \p instruction. The output is of the format:
2729
/// ```
@@ -709,13 +711,75 @@ void goto_programt::instructiont::validate(
709711
const auto &goto_id = goto_symbol_expr.get_identifier();
710712

711713
if(!ns.lookup(goto_id, table_symbol))
714+
{
715+
bool symbol_expr_type_matches_symbol_table =
716+
base_type_eq(goto_symbol_expr.type(), table_symbol->type, ns);
717+
718+
if(
719+
!symbol_expr_type_matches_symbol_table &&
720+
table_symbol->type.id() == ID_code)
721+
{
722+
// Return removal sets the return type of a function symbol table
723+
// entry to 'void', but some callsites still expect the original
724+
// type (e.g. if a function is passed as a parameter)
725+
symbol_expr_type_matches_symbol_table = base_type_eq(
726+
goto_symbol_expr.type(),
727+
original_return_type(ns.get_symbol_table(), goto_id),
728+
ns);
729+
730+
if(
731+
!symbol_expr_type_matches_symbol_table &&
732+
goto_symbol_expr.type().id() == ID_code)
733+
{
734+
// If a function declaration and its definition are in different
735+
// translation units they may have different return types,
736+
// which remove_returns patches up with a typecast. If thats
737+
// the case, then the return type in the symbol table may differ
738+
// from the return type in the symbol expr
739+
if(
740+
goto_symbol_expr.type().source_location().get_file() !=
741+
table_symbol->type.source_location().get_file())
742+
{
743+
// temporarily fixup the return types
744+
auto goto_symbol_expr_type =
745+
to_code_type(goto_symbol_expr.type());
746+
auto table_symbol_type = to_code_type(table_symbol->type);
747+
748+
goto_symbol_expr_type.return_type() =
749+
table_symbol_type.return_type();
750+
751+
symbol_expr_type_matches_symbol_table =
752+
base_type_eq(goto_symbol_expr_type, table_symbol_type, ns);
753+
}
754+
}
755+
}
756+
757+
if(
758+
!symbol_expr_type_matches_symbol_table &&
759+
goto_symbol_expr.type().id() == ID_array &&
760+
to_array_type(goto_symbol_expr.type()).is_incomplete())
761+
{
762+
// If the symbol expr has an incomplete array type, it may not have
763+
// a constant size value, whereas the symbol table entry may have
764+
// an (assumed) constant size of 1 (which mimics gcc behaviour)
765+
if(table_symbol->type.id() == ID_array)
766+
{
767+
auto symbol_table_array_type = to_array_type(table_symbol->type);
768+
symbol_table_array_type.size() = nil_exprt();
769+
770+
symbol_expr_type_matches_symbol_table = base_type_eq(
771+
goto_symbol_expr.type(), symbol_table_array_type, ns);
772+
}
773+
}
774+
712775
DATA_CHECK_WITH_DIAGNOSTICS(
713776
vm,
714-
base_type_eq(goto_symbol_expr.type(), table_symbol->type, ns),
777+
symbol_expr_type_matches_symbol_table,
715778
id2string(goto_id) + " type inconsistency\n" +
716779
"goto program type: " + goto_symbol_expr.type().id_string() +
717780
"\n" + "symbol table type: " + table_symbol->type.id_string(),
718781
current_source_location);
782+
}
719783
}
720784
};
721785

src/util/std_code.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,12 +1135,7 @@ class code_function_callt:public codet
11351135
{
11361136
check(code, vm);
11371137

1138-
if(code.op0().id() == ID_nil)
1139-
DATA_CHECK(
1140-
vm,
1141-
to_code_type(code.op1().type()).return_type().id() == ID_empty,
1142-
"void function should not return value");
1143-
else
1138+
if(code.op0().id() != ID_nil)
11441139
DATA_CHECK(
11451140
vm,
11461141
base_type_eq(

src/util/symbol.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Author: Daniel Kroening, [email protected]
1212

1313
#include "source_location.h"
1414
#include "std_expr.h"
15+
#include "string_utils.h"
1516
#include "suffix.h"
1617

1718
/// Dump the state of a symbol object to a given output stream.
@@ -137,11 +138,62 @@ bool symbolt::is_well_formed() const
137138
// Well-formedness criterion number 2 is for a symbol
138139
// to have it's base name as a suffix to it's more
139140
// general name.
141+
140142
// Exception: Java symbols' base names do not have type signatures
141143
// (for example, they can have name "someclass.method:(II)V" and base name
142144
// "method")
143145
if(!has_suffix(id2string(name), id2string(base_name)) && mode != ID_java)
144-
return false;
146+
{
147+
bool criterion_must_hold = true;
148+
149+
// There are some special cases where this criterion doesn't hold, check
150+
// to see if we have one of those cases
151+
152+
if(is_type)
153+
{
154+
// Typedefs
155+
if(
156+
type.find(ID_C_typedef).is_not_nil() &&
157+
type.find(ID_C_typedef).id() == base_name)
158+
{
159+
criterion_must_hold = false;
160+
}
161+
162+
// Tag types
163+
if(type.find(ID_tag).is_not_nil() && type.find(ID_tag).id() == base_name)
164+
{
165+
criterion_must_hold = false;
166+
}
167+
}
168+
169+
// Linker renaming may have added $linkN suffixes to the name, and other
170+
// suffixes such as #return_value may have then be subsequently added.
171+
// Strip out the first $linkN substring and then see if the criterion holds
172+
const auto &unstripped_name = id2string(name);
173+
const size_t dollar_link_start_pos = unstripped_name.find("$link");
174+
175+
if(dollar_link_start_pos != std::string::npos)
176+
{
177+
size_t dollar_link_end_pos = dollar_link_start_pos + 5;
178+
while(isdigit(unstripped_name[dollar_link_end_pos]))
179+
{
180+
++dollar_link_end_pos;
181+
}
182+
183+
const auto stripped_name =
184+
unstripped_name.substr(0, dollar_link_start_pos) +
185+
unstripped_name.substr(dollar_link_end_pos, std::string::npos);
186+
187+
if(has_suffix(stripped_name, id2string(base_name)))
188+
criterion_must_hold = false;
189+
}
190+
191+
if(criterion_must_hold)
192+
{
193+
// For all other cases this criterion should hold
194+
return false;
195+
}
196+
}
145197

146198
return true;
147199
}

0 commit comments

Comments
 (0)