Skip to content

Commit 3086f21

Browse files
committed
Linking: replace conflicting pointer types when one declaration is extern
1 parent 7f31123 commit 3086f21

File tree

7 files changed

+98
-5
lines changed

7 files changed

+98
-5
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: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ 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, and
75+
// GCC just warns as well.
76+
warning().source_location = symbol.value.find_source_location();
77+
warning() << "`extern' symbol should not have an initializer" << eom;
78+
}
7079
}
7180
else if(!is_function && symbol.value.id()==ID_code)
7281
{

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: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,21 @@ Author: Daniel Kroening, [email protected]
2424

2525
#include "linking_class.h"
2626

27+
bool casting_replace_symbolt::replace_symbol_expr(symbol_exprt &s) const
28+
{
29+
expr_mapt::const_iterator it = expr_map.find(s.get_identifier());
30+
31+
if(it == expr_map.end())
32+
return true;
33+
34+
const exprt &e = it->second;
35+
36+
typet type = s.type();
37+
static_cast<exprt &>(s) = typecast_exprt::conditional_cast(e, type);
38+
39+
return false;
40+
}
41+
2742
std::string linkingt::expr_to_string(
2843
const namespacet &ns,
2944
const irep_idt &identifier,
@@ -875,6 +890,11 @@ bool linkingt::adjust_object_type_rec(
875890
"conflicting pointer types for variable");
876891
#endif
877892

893+
if(info.old_symbol.is_extern && !info.new_symbol.is_extern)
894+
{
895+
info.set_to_new = true; // store new type
896+
}
897+
878898
return false;
879899
}
880900
else if(t1.id()==ID_array &&
@@ -961,10 +981,10 @@ void linkingt::duplicate_object_symbol(
961981
symbolt &new_symbol)
962982
{
963983
// both are variables
984+
bool set_to_new = false;
964985

965986
if(!base_type_eq(old_symbol.type, new_symbol.type, ns))
966987
{
967-
bool set_to_new=false;
968988
bool failed=
969989
adjust_object_type(old_symbol, new_symbol, set_to_new);
970990

@@ -1043,6 +1063,14 @@ void linkingt::duplicate_object_symbol(
10431063
}
10441064
}
10451065
}
1066+
else if(
1067+
set_to_new && !old_symbol.value.is_nil() &&
1068+
!old_symbol.value.get_bool(ID_C_zero_initializer))
1069+
{
1070+
// the type has been updated, now make sure that the initialising assignment
1071+
// will have matching types
1072+
old_symbol.value.make_typecast(old_symbol.type);
1073+
}
10461074
}
10471075

10481076
void linkingt::duplicate_non_type_symbol(

src/linking/linking_class.h

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@ Author: Daniel Kroening, [email protected]
1818
#include <util/typecheck.h>
1919
#include <util/std_expr.h>
2020

21+
class casting_replace_symbolt : public replace_symbolt
22+
{
23+
public:
24+
casting_replace_symbolt(const namespacet &ns)
25+
: replace_symbolt(ns)
26+
{
27+
}
28+
29+
private:
30+
bool replace_symbol_expr(symbol_exprt &dest) const override;
31+
};
32+
2133
class linkingt:public typecheckt
2234
{
2335
public:
@@ -28,15 +40,13 @@ class linkingt:public typecheckt
2840
typecheckt(_message_handler),
2941
main_symbol_table(_main_symbol_table),
3042
src_symbol_table(_src_symbol_table),
31-
ns(_main_symbol_table)
43+
ns(_main_symbol_table),
44+
object_type_updates(ns)
3245
{
3346
}
3447

3548
virtual void typecheck();
3649

37-
rename_symbolt rename_symbol;
38-
unchecked_replace_symbolt object_type_updates;
39-
4050
protected:
4151
bool needs_renaming_type(
4252
const symbolt &old_symbol,
@@ -177,6 +187,10 @@ class linkingt:public typecheckt
177187

178188
// the new IDs created by renaming
179189
std::unordered_set<irep_idt> renamed_ids;
190+
191+
public:
192+
casting_replace_symbolt object_type_updates;
193+
rename_symbolt rename_symbol;
180194
};
181195

182196
#endif // CPROVER_LINKING_LINKING_CLASS_H

0 commit comments

Comments
 (0)