Skip to content

Commit 5c8171f

Browse files
committed
Linking: replace conflicting pointer types when one declaration is extern
1 parent 7bfd36b commit 5c8171f

File tree

10 files changed

+95
-10
lines changed

10 files changed

+95
-10
lines changed

regression/cbmc/Linking8/a.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <stdlib.h>
2+
3+
void foo();
4+
5+
int main()
6+
{
7+
extern void *p;
8+
p = malloc(sizeof(int));
9+
foo();
10+
return 0;
11+
}

regression/cbmc/Linking8/b.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
int *p;
2+
3+
void foo()
4+
{
5+
*p = 42;
6+
}

regression/cbmc/Linking8/test.desc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
b.c
3+
a.c --pointer-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

src/ansi-c/c_typecheck_base.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,23 @@ void c_typecheck_baset::typecheck_symbol(symbolt &symbol)
6767
// and have static lifetime
6868
new_name=root_name;
6969
symbol.is_static_lifetime=true;
70+
71+
if(symbol.value.is_not_nil())
72+
{
73+
// according to the C standard this should be an error, but at least some
74+
// versions of Visual Studio insist to use this in their C library
75+
if(config.ansi_c.mode == configt::ansi_ct::flavourt::VISUAL_STUDIO)
76+
{
77+
warning().source_location = symbol.value.find_source_location();
78+
warning() << "`extern' symbol should not have an initializer" << eom;
79+
}
80+
else
81+
{
82+
error().source_location = symbol.value.find_source_location();
83+
error() << "`extern' symbol should not have an initializer" << eom;
84+
throw 0;
85+
}
86+
}
7087
}
7188
else if(!is_function && symbol.value.id()==ID_code)
7289
{

src/goto-instrument/dump_c.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -958,7 +958,7 @@ void dump_ct::cleanup_harness(code_blockt &b)
958958
}
959959

960960
b.swap(decls);
961-
replace(b);
961+
replace.replace(b, true, true);
962962
}
963963

964964
void dump_ct::convert_function_declaration(

src/goto-instrument/model_argc_argv.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ bool model_argc_argv(
128128
replace_symbolt replace;
129129
replace.insert("ARGC", ns.lookup("argc'").symbol_expr());
130130
replace.insert("ARGV", ns.lookup("argv'").symbol_expr());
131-
replace(value);
131+
replace.replace(value, true, true);
132132
}
133133
else if(
134134
has_prefix(

src/goto-symex/symex_dereference.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,23 @@ exprt goto_symext::address_arithmetic(
214214
else
215215
result=address_of_exprt(result);
216216
}
217+
else if(expr.id() == ID_typecast)
218+
{
219+
const typecast_exprt &tc_expr = to_typecast_expr(expr);
220+
221+
result = address_arithmetic(tc_expr.op(), state, guard, keep_array);
222+
223+
// treat &array as &array[0]
224+
const typet &expr_type = ns.follow(expr.type());
225+
typet dest_type_subtype;
226+
227+
if(expr_type.id() == ID_array && !keep_array)
228+
dest_type_subtype = expr_type.subtype();
229+
else
230+
dest_type_subtype = expr_type;
231+
232+
result = typecast_exprt(result, pointer_type(dest_type_subtype));
233+
}
217234
else
218235
throw "goto_symext::address_arithmetic does not handle "+expr.id_string();
219236

src/linking/linking.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,11 @@ bool linkingt::adjust_object_type_rec(
875875
"conflicting pointer types for variable");
876876
#endif
877877

878+
if(info.old_symbol.is_extern && !info.new_symbol.is_extern)
879+
{
880+
info.set_to_new = true; // store new type
881+
}
882+
878883
return false;
879884
}
880885
else if(t1.id()==ID_array &&
@@ -961,10 +966,10 @@ void linkingt::duplicate_object_symbol(
961966
symbolt &new_symbol)
962967
{
963968
// both are variables
969+
bool set_to_new = false;
964970

965971
if(!base_type_eq(old_symbol.type, new_symbol.type, ns))
966972
{
967-
bool set_to_new=false;
968973
bool failed=
969974
adjust_object_type(old_symbol, new_symbol, set_to_new);
970975

@@ -1043,6 +1048,14 @@ void linkingt::duplicate_object_symbol(
10431048
}
10441049
}
10451050
}
1051+
else if(
1052+
set_to_new && !old_symbol.value.is_nil() &&
1053+
!old_symbol.value.get_bool(ID_C_zero_initializer))
1054+
{
1055+
// the type has been updated, now make sure that the initialising assignment
1056+
// will have matching types
1057+
old_symbol.value.make_typecast(old_symbol.type);
1058+
}
10461059
}
10471060

10481061
void linkingt::duplicate_non_type_symbol(

src/util/replace_symbol.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ void replace_symbolt::insert(
2929

3030
bool replace_symbolt::replace(
3131
exprt &dest,
32-
const bool replace_with_const) const
32+
const bool replace_with_const,
33+
const bool ignore_type_change) const
3334
{
3435
bool result=true; // unchanged
3536

@@ -49,14 +50,16 @@ bool replace_symbolt::replace(
4950
{
5051
member_exprt &me=to_member_expr(dest);
5152

52-
if(!replace(me.struct_op(), replace_with_const)) // Could give non l-value.
53+
// Could yield non l-value.
54+
if(!replace(me.struct_op(), replace_with_const, ignore_type_change))
5355
result=false;
5456
}
5557
else if(dest.id()==ID_index)
5658
{
5759
index_exprt &ie=to_index_expr(dest);
5860

59-
if(!replace(ie.array(), replace_with_const)) // Could give non l-value.
61+
// Could yield non l-value.
62+
if(!replace(ie.array(), replace_with_const, ignore_type_change))
6063
result=false;
6164

6265
if(!replace(ie.index()))
@@ -66,7 +69,7 @@ bool replace_symbolt::replace(
6669
{
6770
address_of_exprt &aoe=to_address_of_expr(dest);
6871

69-
if(!replace(aoe.object(), false))
72+
if(!replace(aoe.object(), false, ignore_type_change))
7073
result=false;
7174
}
7275
else if(dest.id()==ID_symbol)
@@ -83,15 +86,22 @@ bool replace_symbolt::replace(
8386
if(!replace_with_const && e.is_constant()) // Would give non l-value.
8487
return true;
8588

86-
dest=e;
89+
if(ignore_type_change || dest.type() == e.type())
90+
dest = e;
91+
else
92+
{
93+
typet type = dest.type();
94+
dest = e;
95+
dest.make_typecast(type);
96+
}
8797

8898
return false;
8999
}
90100
}
91101
else
92102
{
93103
Forall_operands(it, dest)
94-
if(!replace(*it))
104+
if(!replace(*it, true, ignore_type_change))
95105
result=false;
96106
}
97107

src/util/replace_symbol.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,13 @@ class replace_symbolt
5151
/// \param dest The expression in which to do the replacement
5252
/// \param replace_with_const If false then it disables the rewrites that
5353
/// could result in something that is not an l-value.
54+
/// \param ignore_type_change If true, do not introduce type casts when the
55+
/// replacement would cause expression types to change.
5456
///
5557
virtual bool replace(
5658
exprt &dest,
57-
const bool replace_with_const=true) const;
59+
const bool replace_with_const = true,
60+
const bool ignore_type_change = false) const;
5861

5962
virtual bool replace(typet &dest) const;
6063

0 commit comments

Comments
 (0)