Skip to content

Commit 7d5801f

Browse files
committed
Dump-C: support struct/union types without tags
Dump-C assumed that all occurrences of struct or union types would be via their tags. This was never a documented invariant, but largely true until 5ea97b3: that commit does introduce struct types in place, without making any effort to create tags. Dump-C now supports this case. Fixes: #7158
1 parent 6c6a4d4 commit 7d5801f

File tree

3 files changed

+79
-6
lines changed

3 files changed

+79
-6
lines changed
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <stdlib.h>
2+
3+
int main()
4+
{
5+
// CBMC's model of calloc includes an overflow check, which in turn creates a
6+
// struct that holds both the arithmetic result and the overflow information.
7+
// dump-c did not support this struct defined in place.
8+
calloc(10, 1);
9+
}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
main.c
3+
--dump-c
4+
VERIFICATION SUCCESSFUL
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^Invariant check failed
9+
^warning: ignoring
10+
irep
11+
--
12+
This test must pass compiling the output generated using dump-c, which implies
13+
that dump-c succeeded and that all struct declarations are present.

Diff for: src/goto-instrument/dump_c.cpp

+57-6
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,35 @@ Author: Daniel Kroening, [email protected]
2525
#include <util/string_utils.h>
2626

2727
#include <ansi-c/expr2c.h>
28+
#include <ansi-c/type2name.h>
29+
#include <cpp/cpp_type2name.h>
2830
#include <cpp/expr2cpp.h>
2931
#include <linking/static_lifetime_init.h>
3032

3133
#include "goto_program2code.h"
3234

35+
static std::string clean_identifier(const irep_idt &id)
36+
{
37+
std::string result;
38+
result.reserve(id2string(id).size());
39+
40+
for(auto c : id2string(id))
41+
{
42+
if(c >= '0' && c <= '9')
43+
result += c;
44+
else if(c >= 'A' && c <= 'Z')
45+
result += c;
46+
else if(c >= 'a' && c <= 'z')
47+
result += c;
48+
else if(c == '_' || c == '$')
49+
result += c;
50+
else
51+
result += "_" + std::to_string(c);
52+
}
53+
54+
return result;
55+
}
56+
3357
dump_c_configurationt dump_c_configurationt::default_configuration =
3458
dump_c_configurationt();
3559

@@ -58,11 +82,32 @@ void dump_ct::operator()(std::ostream &os)
5882

5983
// add copies of struct types when ID_C_transparent_union is only
6084
// annotated to parameter
61-
symbol_tablet symbols_transparent;
85+
symbol_tablet additional_symbols;
6286
for(const auto &named_symbol : copied_symbol_table.symbols)
6387
{
6488
const symbolt &symbol=named_symbol.second;
6589

90+
if(
91+
(symbol.type.id() == ID_union || symbol.type.id() == ID_struct) &&
92+
!symbol.is_type)
93+
{
94+
type_symbolt ts{symbol.type};
95+
ts.mode = symbol.mode;
96+
if(mode == ID_C)
97+
ts.name = "tag-" + type2name(symbol.type, ns);
98+
else if(mode == ID_cpp)
99+
ts.name = "tag-" + cpp_type2name(symbol.type);
100+
else
101+
UNREACHABLE;
102+
typet &type =
103+
copied_symbol_table.get_writeable_ref(named_symbol.first).type;
104+
if(ts.type.id() == ID_union)
105+
type = union_tag_typet{ts.name};
106+
else
107+
type = struct_tag_typet{ts.name};
108+
additional_symbols.add(ts);
109+
}
110+
66111
if(symbol.type.id()!=ID_code)
67112
continue;
68113

@@ -86,14 +131,14 @@ void dump_ct::operator()(std::ostream &os)
86131
new_type_sym.type.set(ID_C_transparent_union, true);
87132

88133
// we might have it already, in which case this has no effect
89-
symbols_transparent.add(new_type_sym);
134+
additional_symbols.add(new_type_sym);
90135

91136
to_union_tag_type(type).set_identifier(new_type_sym.name);
92137
type.remove(ID_C_transparent_union);
93138
}
94139
}
95140
}
96-
for(const auto &symbol_pair : symbols_transparent.symbols)
141+
for(const auto &symbol_pair : additional_symbols.symbols)
97142
{
98143
copied_symbol_table.add(symbol_pair.second);
99144
}
@@ -509,11 +554,11 @@ void dump_ct::convert_compound(
509554
collect_typedefs(comp.type(), true);
510555
}
511556

512-
irep_idt comp_name=comp.get_name();
513-
514-
struct_body << indent(1) << "// " << comp_name << '\n';
557+
struct_body << indent(1) << "// " << comp.get_name() << '\n';
515558
struct_body << indent(1);
516559

560+
irep_idt comp_name = clean_identifier(comp.get_name());
561+
517562
// component names such as "main" would collide with other objects in the
518563
// namespace
519564
std::string fake_unique_name="NO/SUCH/NS::"+id2string(comp_name);
@@ -1519,6 +1564,12 @@ void dump_ct::cleanup_expr(exprt &expr)
15191564
expr = unary_exprt{ID_initializer_list, bu.value()};
15201565
}
15211566
}
1567+
else if(expr.id() == ID_member)
1568+
{
1569+
member_exprt &member_expr = to_member_expr(expr);
1570+
member_expr.set_component_name(
1571+
clean_identifier(member_expr.get_component_name()));
1572+
}
15221573
}
15231574

15241575
void dump_ct::cleanup_type(typet &type)

0 commit comments

Comments
 (0)