Skip to content

Commit 2f09d57

Browse files
committed
Fix dump-c output involving typedef names
Follow-up to 99067de, which made expr2c prefer typedef names over original type expressions. Thanks Andreas Stahlbauer for providing the regression tests and help in debugging. Fixes: #882
1 parent f761d81 commit 2f09d57

File tree

6 files changed

+264
-3
lines changed

6 files changed

+264
-3
lines changed
+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
typedef long int off_t;
2+
typedef signed char smallint;
3+
4+
typedef struct chain_s {
5+
struct node_s *first;
6+
struct node_s *last;
7+
const char *programname;
8+
} chain;
9+
10+
typedef struct func_s {
11+
struct chain_s body;
12+
} func;
13+
14+
typedef struct node_s {
15+
struct node_s *n;
16+
} node;
17+
18+
typedef struct dumper_t_x {
19+
node n;
20+
off_t dump_skip;
21+
signed int dump_length;
22+
smallint dump_vflag;
23+
} dumper_t;
24+
25+
typedef struct FS_x {
26+
struct FS *nextfs;
27+
signed int bcnt;
28+
} FS;
29+
30+
dumper_t * alloc_dumper(void) {
31+
return (void*) 0;
32+
}
33+
34+
typedef unsigned int uint32_t;
35+
36+
const uint32_t xx[2];
37+
38+
typedef struct node_s2 {
39+
uint32_t info;
40+
} node2;
41+
42+
typedef struct {
43+
int x;
44+
} anon_name;
45+
46+
typedef struct node_s3 {
47+
union {
48+
struct node_s *n;
49+
func *f;
50+
} r;
51+
} node3;
52+
53+
int main() {
54+
node n;
55+
chain c;
56+
dumper_t a;
57+
dumper_t b[3];
58+
node2* sn;
59+
anon_name d;
60+
node3* s3;
61+
alloc_dumper();
62+
return 0;
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--dump-c
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
7+
^warning: ignoring
8+
--
9+
This test should be run via chain.sh, which will try to recompile the dumped C
10+
code. Missing/incomplete typedef output would cause a failure.

src/goto-instrument/dump_c.cpp

+174-3
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ void dump_ct::operator()(std::ostream &os)
6262
std::stringstream func_body_stream;
6363
local_static_declst local_static_decls;
6464

65+
gather_global_typedefs();
66+
6567
// add copies of struct types when ID_C_transparent_union is only
6668
// annotated to parameter
6769
symbol_tablet symbols_transparent;
@@ -113,6 +115,9 @@ void dump_ct::operator()(std::ostream &os)
113115
symbolt &symbol=it->second;
114116
bool tag_added=false;
115117

118+
// TODO we could get rid of some of the ID_anonymous by looking up
119+
// the origin symbol types in typedef_types and adjusting any other
120+
// uses of ID_tag
116121
if((symbol.type.id()==ID_union || symbol.type.id()==ID_struct) &&
117122
symbol.type.get(ID_tag).empty())
118123
{
@@ -285,6 +290,8 @@ void dump_ct::operator()(std::ostream &os)
285290
os << std::endl;
286291
}
287292

293+
dump_typedefs(os);
294+
288295
if(!func_decl_stream.str().empty())
289296
os << func_decl_stream.str() << std::endl;
290297
if(!compound_body_stream.str().empty())
@@ -408,6 +415,9 @@ void dump_ct::convert_compound(
408415
if(!converted_compound.insert(name).second)
409416
return;
410417

418+
// make sure typedef names used in the declaration are available
419+
collect_typedefs(type, true);
420+
411421
const irept &bases = type.find(ID_bases);
412422
std::stringstream base_decls;
413423
forall_irep(parent_it, bases.get_sub())
@@ -466,8 +476,13 @@ void dump_ct::convert_compound(
466476
while(non_array_type->id()==ID_array)
467477
non_array_type=&(ns.follow(non_array_type->subtype()));
468478

469-
if(recursive && non_array_type->id()!=ID_pointer)
470-
convert_compound(comp.type(), comp.type(), recursive, os);
479+
if(recursive)
480+
{
481+
if(non_array_type->id()!=ID_pointer)
482+
convert_compound(comp.type(), comp.type(), recursive, os);
483+
else
484+
collect_typedefs(comp.type(), true);
485+
}
471486

472487
irep_idt comp_name=comp.get_name();
473488

@@ -521,7 +536,21 @@ void dump_ct::convert_compound(
521536
struct_body << ";" << std::endl;
522537
}
523538

524-
os << type_to_string(unresolved);
539+
typet unresolved_clean=unresolved;
540+
typedef_typest::const_iterator td_entry=
541+
typedef_types.find(unresolved);
542+
irep_idt typedef_str;
543+
if(td_entry!=typedef_types.end())
544+
{
545+
unresolved_clean.remove(ID_C_typedef);
546+
typedef_str=td_entry->second;
547+
std::pair<std::string, bool> &td_map_entry=typedef_map[typedef_str];
548+
if(!td_map_entry.second)
549+
td_map_entry.first="";
550+
os << "typedef ";
551+
}
552+
553+
os << type_to_string(unresolved_clean);
525554
if(!base_decls.str().empty())
526555
{
527556
assert(language->id()=="cpp");
@@ -548,6 +577,8 @@ void dump_ct::convert_compound(
548577
os << " __attribute__ ((__transparent_union__))";
549578
if(type.get_bool(ID_C_packed))
550579
os << " __attribute__ ((__packed__))";
580+
if(!typedef_str.empty())
581+
os << " " << typedef_str;
551582
os << ";";
552583
os << std::endl;
553584
os << std::endl;
@@ -901,6 +932,10 @@ void dump_ct::cleanup_decl(
901932

902933
tmp.add_instruction(END_FUNCTION);
903934

935+
std::unordered_set<irep_idt, irep_id_hash> typedef_names;
936+
for(const auto &td : typedef_map)
937+
typedef_names.insert(td.first);
938+
904939
code_blockt b;
905940
goto_program2codet p2s(
906941
irep_idt(),
@@ -909,6 +944,7 @@ void dump_ct::cleanup_decl(
909944
b,
910945
local_static,
911946
local_type_decls,
947+
typedef_names,
912948
system_headers);
913949
p2s();
914950

@@ -918,6 +954,132 @@ void dump_ct::cleanup_decl(
918954

919955
/*******************************************************************\
920956
957+
Function: dump_ct::collect_typedefs
958+
959+
Inputs:
960+
type Type to inspect for ID_C_typedef entry
961+
early Set to true to enforce that typedef is dumped before any
962+
function declarations or struct definitions
963+
964+
Outputs:
965+
966+
Purpose: Find any typedef names contained in the input type and store
967+
their declaration strings in typedef_map for eventual output.
968+
969+
\*******************************************************************/
970+
971+
void dump_ct::collect_typedefs(const typet &type, bool early)
972+
{
973+
if(type.id()==ID_code)
974+
{
975+
const code_typet &code_type=to_code_type(type);
976+
977+
collect_typedefs(code_type.return_type(), early);
978+
for(const auto &param : code_type.parameters())
979+
collect_typedefs(param.type(), early);
980+
}
981+
else if(type.id()==ID_pointer || type.id()==ID_array)
982+
{
983+
collect_typedefs(type.subtype(), early);
984+
}
985+
else if(type.id()==ID_symbol)
986+
{
987+
const symbolt &symbol=
988+
ns.lookup(to_symbol_type(type).get_identifier());
989+
collect_typedefs(symbol.type, early);
990+
}
991+
992+
const irep_idt &typedef_str=type.get(ID_C_typedef);
993+
994+
if(!typedef_str.empty())
995+
{
996+
std::pair<typedef_mapt::iterator, bool> entry=
997+
typedef_map.insert({typedef_str, {"", early}});
998+
999+
if(entry.second)
1000+
{
1001+
if(typedef_str=="__gnuc_va_list" || typedef_str == "va_list")
1002+
{
1003+
system_headers.insert("stdarg.h");
1004+
}
1005+
else
1006+
{
1007+
typet t=type;
1008+
t.remove(ID_C_typedef);
1009+
1010+
std::ostringstream oss;
1011+
oss << "typedef " << type_to_string(t) << " "
1012+
<< typedef_str << ';';
1013+
1014+
entry.first->second.first=oss.str();
1015+
}
1016+
}
1017+
else if(early)
1018+
{
1019+
entry.first->second.second=true;
1020+
}
1021+
}
1022+
}
1023+
1024+
/*******************************************************************\
1025+
1026+
Function: dump_ct::gather_global_typedefs
1027+
1028+
Inputs:
1029+
1030+
Outputs:
1031+
1032+
Purpose: find all global typdefs in the symbol table and store them
1033+
in typedef_types
1034+
1035+
\*******************************************************************/
1036+
1037+
void dump_ct::gather_global_typedefs()
1038+
{
1039+
for(const auto &symbol_entry : copied_symbol_table.symbols)
1040+
{
1041+
const symbolt &symbol=symbol_entry.second;
1042+
1043+
if(symbol.is_macro && symbol.is_type && !ignore(symbol) &&
1044+
symbol.location.get_function().empty())
1045+
{
1046+
assert(!symbol.type.get(ID_C_typedef).empty());
1047+
typedef_types[symbol.type]=symbol.type.get(ID_C_typedef);
1048+
collect_typedefs(symbol.type, false);
1049+
}
1050+
}
1051+
}
1052+
1053+
/*******************************************************************\
1054+
1055+
Function: dump_ct::dump_typedefs
1056+
1057+
Inputs:
1058+
1059+
Outputs: os output stream
1060+
1061+
Purpose: print all typedefs that are not covered via
1062+
typedef struct xyz { ... } name;
1063+
1064+
\*******************************************************************/
1065+
1066+
void dump_ct::dump_typedefs(std::ostream &os) const
1067+
{
1068+
bool need_newline=false;
1069+
1070+
for(const auto &td : typedef_map)
1071+
if(!td.second.first.empty())
1072+
{
1073+
need_newline=true;
1074+
os << td.second.first << std::endl;
1075+
}
1076+
1077+
if(need_newline)
1078+
os << std::endl;
1079+
}
1080+
1081+
/*******************************************************************\
1082+
9211083
Function: dump_ct::convert_global_variables
9221084
9231085
Inputs:
@@ -1024,13 +1186,18 @@ void dump_ct::convert_function_declaration(
10241186
code_blockt b;
10251187
std::list<irep_idt> type_decls, local_static;
10261188

1189+
std::unordered_set<irep_idt, irep_id_hash> typedef_names;
1190+
for(const auto &td : typedef_map)
1191+
typedef_names.insert(td.first);
1192+
10271193
goto_program2codet p2s(
10281194
symbol.name,
10291195
func_entry->second.body,
10301196
copied_symbol_table,
10311197
b,
10321198
local_static,
10331199
type_decls,
1200+
typedef_names,
10341201
system_headers);
10351202
p2s();
10361203

@@ -1069,6 +1236,10 @@ void dump_ct::convert_function_declaration(
10691236
os_decl << "// " << symbol.location << std::endl;
10701237
os_decl << make_decl(symbol.name, symbol.type) << ";" << std::endl;
10711238
}
1239+
1240+
// make sure typedef names used in the function declaration are
1241+
// available
1242+
collect_typedefs(symbol.type, true);
10721243
}
10731244

10741245
/*******************************************************************\

src/goto-instrument/dump_c_class.h

+9
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ class dump_ct
5959
declared_enum_constants_mapt;
6060
declared_enum_constants_mapt declared_enum_constants;
6161

62+
typedef std::map<irep_idt, std::pair<std::string, bool>> typedef_mapt;
63+
typedef_mapt typedef_map;
64+
typedef std::unordered_map<typet, irep_idt, irep_hash> typedef_typest;
65+
typedef_typest typedef_types;
66+
6267
void init_system_library_map();
6368

6469
std::string type_to_string(const typet &type);
@@ -85,6 +90,10 @@ class dump_ct
8590
return d_str.substr(0, d_str.size()-1);
8691
}
8792

93+
void collect_typedefs(const typet &type, bool early);
94+
void gather_global_typedefs();
95+
void dump_typedefs(std::ostream &os) const;
96+
8897
void convert_compound_declaration(
8998
const symbolt &symbol,
9099
std::ostream &os_body);

src/goto-instrument/goto_program2code.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -1818,6 +1818,11 @@ void goto_program2codet::cleanup_code(
18181818

18191819
add_local_types(code.op0().type());
18201820

1821+
const irep_idt &typedef_str=code.op0().type().get(ID_C_typedef);
1822+
if(!typedef_str.empty() &&
1823+
typedef_names.find(typedef_str)==typedef_names.end())
1824+
code.op0().type().remove(ID_C_typedef);
1825+
18211826
return;
18221827
}
18231828
else if(code.get_statement()==ID_function_call)

0 commit comments

Comments
 (0)