Skip to content

Commit 99e8ac7

Browse files
author
Daniel Kroening
authored
Merge pull request #136 from tautschnig/relaxed-linking
Relaxed linking
2 parents 3aa8b79 + e4cf0f6 commit 99e8ac7

File tree

2 files changed

+268
-66
lines changed

2 files changed

+268
-66
lines changed

src/linking/linking.cpp

Lines changed: 240 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Author: Daniel Kroening, [email protected]
1616
#include <util/std_expr.h>
1717
#include <util/std_types.h>
1818
#include <util/simplify_expr.h>
19+
#include <util/pointer_offset_size.h>
1920

2021
#include <langapi/language_util.h>
2122

@@ -619,26 +620,31 @@ void linkingt::duplicate_code_symbol(
619620
"ignoring conflicting weak function declaration");
620621
}
621622
}
622-
// Linux kernel uses void f(void) as generic prototype
623-
else if((old_t.return_type().id()==ID_empty &&
624-
old_t.parameters().empty() &&
625-
!old_t.has_ellipsis() &&
623+
// aliasing may alter the type
624+
else if((new_symbol.is_macro &&
625+
new_symbol.value.is_not_nil() &&
626626
old_symbol.value.is_nil()) ||
627-
(new_t.return_type().id()==ID_empty &&
628-
new_t.parameters().empty() &&
629-
!new_t.has_ellipsis() &&
627+
(old_symbol.is_macro &&
628+
old_symbol.value.is_not_nil() &&
630629
new_symbol.value.is_nil()))
631630
{
632-
// issue a warning
633631
link_warning(
634632
old_symbol,
635633
new_symbol,
636-
"ignoring conflicting void f(void) function declaration");
634+
"ignoring conflicting function alias declaration");
635+
}
636+
// conflicting declarations without a definition, matching return
637+
// types
638+
else if(base_type_eq(old_t.return_type(), new_t.return_type(), ns) &&
639+
old_symbol.value.is_nil() &&
640+
new_symbol.value.is_nil())
641+
{
642+
link_warning(
643+
old_symbol,
644+
new_symbol,
645+
"ignoring conflicting function declarations");
637646

638-
if(old_t.return_type().id()==ID_empty &&
639-
old_t.parameters().empty() &&
640-
!old_t.has_ellipsis() &&
641-
old_symbol.value.is_nil())
647+
if(old_t.parameters().size()<new_t.parameters().size())
642648
{
643649
old_symbol.type=new_symbol.type;
644650
old_symbol.location=new_symbol.location;
@@ -647,8 +653,10 @@ void linkingt::duplicate_code_symbol(
647653
}
648654
// mismatch on number of parameters is definitively an error
649655
else if((old_t.parameters().size()<new_t.parameters().size() &&
656+
new_symbol.value.is_not_nil() &&
650657
!old_t.has_ellipsis()) ||
651658
(old_t.parameters().size()>new_t.parameters().size() &&
659+
old_symbol.value.is_not_nil() &&
652660
!new_t.has_ellipsis()))
653661
{
654662
link_error(
@@ -683,12 +691,20 @@ void linkingt::duplicate_code_symbol(
683691
}
684692
if(o_it!=old_t.parameters().end())
685693
{
686-
assert(new_t.has_ellipsis());
694+
if(!new_t.has_ellipsis() && old_symbol.value.is_not_nil())
695+
link_error(
696+
old_symbol,
697+
new_symbol,
698+
"conflicting parameter counts of function declarations");
687699
replace=new_symbol.value.is_not_nil();
688700
}
689701
else if(n_it!=new_t.parameters().end())
690702
{
691-
assert(old_t.has_ellipsis());
703+
if(!old_t.has_ellipsis() && new_symbol.value.is_not_nil())
704+
link_error(
705+
old_symbol,
706+
new_symbol,
707+
"conflicting parameter counts of function declarations");
692708
replace=new_symbol.value.is_not_nil();
693709
}
694710

@@ -709,7 +725,8 @@ void linkingt::duplicate_code_symbol(
709725
(old_symbol.value.is_nil() && t2.id()==ID_empty);
710726
}
711727
// different pointer arguments without implementation may work
712-
else if(t1.id()==ID_pointer && t2.id()==ID_pointer &&
728+
else if((t1.id()==ID_pointer || t2.id()==ID_pointer) &&
729+
pointer_offset_bits(t1, ns)==pointer_offset_bits(t2, ns) &&
713730
old_symbol.value.is_nil() && new_symbol.value.is_nil())
714731
{
715732
if(warn_msg.empty())
@@ -718,7 +735,8 @@ void linkingt::duplicate_code_symbol(
718735
// different pointer arguments with implementation - the
719736
// implementation is always right, even though such code may
720737
// be severely broken
721-
else if(t1.id()==ID_pointer && t2.id()==ID_pointer &&
738+
else if((t1.id()==ID_pointer || t2.id()==ID_pointer) &&
739+
pointer_offset_bits(t1, ns)==pointer_offset_bits(t2, ns) &&
722740
old_symbol.value.is_nil()!=new_symbol.value.is_nil())
723741
{
724742
if(warn_msg.empty())
@@ -828,7 +846,7 @@ void linkingt::duplicate_code_symbol(
828846

829847
/*******************************************************************\
830848
831-
Function: linkingt::duplicate_object_symbol
849+
Function: linkingt::adjust_object_type_rec
832850
833851
Inputs:
834852
@@ -838,71 +856,225 @@ Function: linkingt::duplicate_object_symbol
838856
839857
\*******************************************************************/
840858

841-
void linkingt::duplicate_object_symbol(
842-
symbolt &old_symbol,
843-
symbolt &new_symbol)
859+
bool linkingt::adjust_object_type_rec(
860+
const typet &t1,
861+
const typet &t2,
862+
adjust_type_infot &info)
844863
{
845-
// both are variables
864+
if(base_type_eq(t1, t2, ns))
865+
return false;
846866

847-
if(!base_type_eq(old_symbol.type, new_symbol.type, ns))
867+
if(t1.id()==ID_symbol ||
868+
t1.id()==ID_struct_tag ||
869+
t1.id()==ID_union_tag ||
870+
t1.id()==ID_c_enum_tag)
848871
{
849-
const typet &old_type=ns.follow(old_symbol.type);
850-
const typet &new_type=ns.follow(new_symbol.type);
851-
852-
if(old_type.id()==ID_array && new_type.id()==ID_array &&
853-
base_type_eq(old_type.subtype(), new_type.subtype(), ns))
854-
{
855-
// still need to compare size
856-
const exprt &old_size=to_array_type(old_type).size();
857-
const exprt &new_size=to_array_type(new_type).size();
858-
859-
if(old_size.is_nil() && new_size.is_not_nil())
860-
{
861-
old_symbol.type=new_symbol.type; // store new type
862-
}
863-
else if(old_size.is_not_nil() && new_size.is_nil())
864-
{
865-
// ok, we will use the old type
866-
}
867-
else
868-
link_error(
869-
old_symbol,
870-
new_symbol,
871-
"conflicting array sizes for variable");
872-
}
873-
else if(old_type.id()==ID_pointer && new_type.id()==ID_array)
872+
const irep_idt &identifier=t1.get(ID_identifier);
873+
874+
if(info.o_symbols.insert(identifier).second)
874875
{
875-
// store new type
876-
old_symbol.type=new_symbol.type;
876+
bool result=
877+
adjust_object_type_rec(follow_tags_symbols(ns, t1), t2, info);
878+
info.o_symbols.erase(identifier);
879+
880+
return result;
877881
}
878-
else if(old_type.id()==ID_array && new_type.id()==ID_pointer)
882+
883+
return false;
884+
}
885+
else if(t2.id()==ID_symbol ||
886+
t2.id()==ID_struct_tag ||
887+
t2.id()==ID_union_tag ||
888+
t2.id()==ID_c_enum_tag)
889+
{
890+
const irep_idt &identifier=t2.get(ID_identifier);
891+
892+
if(info.n_symbols.insert(identifier).second)
879893
{
880-
// ignore
894+
bool result=
895+
adjust_object_type_rec(t1, follow_tags_symbols(ns, t2), info);
896+
info.n_symbols.erase(identifier);
897+
898+
return result;
881899
}
882-
else if(old_type.id()==ID_pointer && new_type.id()==ID_pointer)
900+
901+
return false;
902+
}
903+
else if(t1.id()==ID_pointer && t2.id()==ID_array)
904+
{
905+
info.set_to_new=true; // store new type
906+
907+
return false;
908+
}
909+
else if(t1.id()==ID_array && t2.id()==ID_pointer)
910+
{
911+
// ignore
912+
return false;
913+
}
914+
else if((t1.id()==ID_incomplete_struct && t2.id()==ID_struct) ||
915+
(t1.id()==ID_incomplete_union && t2.id()==ID_union))
916+
{
917+
info.set_to_new=true; // store new type
918+
919+
return false;
920+
}
921+
else if((t1.id()==ID_struct && t2.id()==ID_incomplete_struct) ||
922+
(t1.id()==ID_union && t2.id()==ID_incomplete_union))
923+
{
924+
// ignore
925+
return false;
926+
}
927+
else if(t1.id()!=t2.id())
928+
{
929+
// type classes do not match and can't be fixed
930+
#ifdef DEBUG
931+
str << "LINKING: cannot join " << t1.id() << " vs. " << t2.id();
932+
debug_msg();
933+
#endif
934+
935+
return true;
936+
}
937+
938+
if(t1.id()==ID_pointer)
939+
{
940+
#if 0
941+
bool s=info.set_to_new;
942+
if(adjust_object_type_rec(t1.subtype(), t2.subtype(), info))
883943
{
884944
link_warning(
885-
old_symbol,
886-
new_symbol,
945+
info.old_symbol,
946+
info.new_symbol,
887947
"conflicting pointer types for variable");
948+
info.set_to_new=s;
888949
}
889-
else if((old_type.id()==ID_incomplete_struct &&
890-
new_type.id()==ID_struct) ||
891-
(old_type.id()==ID_incomplete_union &&
892-
new_type.id()==ID_union))
950+
#else
951+
link_warning(
952+
info.old_symbol,
953+
info.new_symbol,
954+
"conflicting pointer types for variable");
955+
#endif
956+
957+
return false;
958+
}
959+
else if(t1.id()==ID_array &&
960+
!adjust_object_type_rec(t1.subtype(), t2.subtype(), info))
961+
{
962+
// still need to compare size
963+
const exprt &old_size=to_array_type(t1).size();
964+
const exprt &new_size=to_array_type(t2).size();
965+
966+
if((old_size.is_nil() && new_size.is_not_nil()) ||
967+
(old_size.is_zero() && new_size.is_not_nil()) ||
968+
info.old_symbol.is_weak)
893969
{
894-
// store new type
895-
old_symbol.type=new_symbol.type;
970+
info.set_to_new=true; // store new type
896971
}
897-
else if((old_type.id()==ID_struct &&
898-
new_type.id()==ID_incomplete_struct) ||
899-
(old_type.id()==ID_union &&
900-
new_type.id()==ID_incomplete_union))
972+
else if(new_size.is_nil() ||
973+
new_size.is_zero() ||
974+
info.new_symbol.is_weak)
901975
{
902-
// ignore
976+
// ok, we will use the old type
903977
}
904978
else
905979
{
980+
equal_exprt eq(old_size, new_size);
981+
982+
if(!simplify_expr(eq, ns).is_true())
983+
link_error(
984+
info.old_symbol,
985+
info.new_symbol,
986+
"conflicting array sizes for variable");
987+
}
988+
989+
return false;
990+
}
991+
else if(t1.id()==ID_struct || t1.id()==ID_union)
992+
{
993+
const struct_union_typet::componentst &components1=
994+
to_struct_union_type(t1).components();
995+
996+
const struct_union_typet::componentst &components2=
997+
to_struct_union_type(t2).components();
998+
999+
struct_union_typet::componentst::const_iterator
1000+
it1=components1.begin(), it2=components2.begin();
1001+
for( ;
1002+
it1!=components1.end() && it2!=components2.end();
1003+
++it1, ++it2)
1004+
{
1005+
if(it1->get_name()!=it2->get_name() ||
1006+
adjust_object_type_rec(it1->type(), it2->type(), info))
1007+
return true;
1008+
}
1009+
if(it1!=components1.end() || it2!=components2.end())
1010+
return true;
1011+
1012+
return false;
1013+
}
1014+
1015+
return true;
1016+
}
1017+
1018+
/*******************************************************************\
1019+
1020+
Function: linkingt::adjust_object_type
1021+
1022+
Inputs:
1023+
1024+
Outputs:
1025+
1026+
Purpose:
1027+
1028+
\*******************************************************************/
1029+
1030+
bool linkingt::adjust_object_type(
1031+
const symbolt &old_symbol,
1032+
const symbolt &new_symbol,
1033+
bool &set_to_new)
1034+
{
1035+
#ifdef DEBUG
1036+
str << "LINKING: trying to adjust types of " << old_symbol.name;
1037+
debug_msg();
1038+
#endif
1039+
1040+
const typet &old_type=follow_tags_symbols(ns, old_symbol.type);
1041+
const typet &new_type=follow_tags_symbols(ns, new_symbol.type);
1042+
1043+
adjust_type_infot info(old_symbol, new_symbol);
1044+
bool result=adjust_object_type_rec(old_type, new_type, info);
1045+
set_to_new=info.set_to_new;
1046+
1047+
return result;
1048+
}
1049+
1050+
/*******************************************************************\
1051+
1052+
Function: linkingt::duplicate_object_symbol
1053+
1054+
Inputs:
1055+
1056+
Outputs:
1057+
1058+
Purpose:
1059+
1060+
\*******************************************************************/
1061+
1062+
void linkingt::duplicate_object_symbol(
1063+
symbolt &old_symbol,
1064+
symbolt &new_symbol)
1065+
{
1066+
// both are variables
1067+
1068+
if(!base_type_eq(old_symbol.type, new_symbol.type, ns))
1069+
{
1070+
bool set_to_new=false;
1071+
bool failed=
1072+
adjust_object_type(old_symbol, new_symbol, set_to_new);
1073+
1074+
if(failed)
1075+
{
1076+
const typet &old_type=follow_tags_symbols(ns, old_symbol.type);
1077+
9061078
// provide additional diagnostic output for
9071079
// struct/union/array/enum
9081080
if(old_type.id()==ID_struct ||
@@ -920,6 +1092,8 @@ void linkingt::duplicate_object_symbol(
9201092
new_symbol,
9211093
"conflicting types for variable");
9221094
}
1095+
else if(set_to_new)
1096+
old_symbol.type=new_symbol.type;
9231097
}
9241098

9251099
// care about initializers

0 commit comments

Comments
 (0)