Skip to content

Commit 39e7078

Browse files
committed
Linking: actually replace code type information in expressions
The linker already accepted a number of type mismatches for function declarations, but did not actually modify the goto functions to reflect these type mismatches, just the type information in the symbol table was updated. These changes enable support for conflicts on function return types, which are now resolved by introducing type casts.
1 parent d590932 commit 39e7078

20 files changed

+274
-63
lines changed

regression/ansi-c/undeclared_function/fileB.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
#include <stdlib.h>
1+
void *malloc(__CPROVER_size_t s)
2+
{
3+
return (void *)0 + s;
4+
}
25

36
int f()
47
{

regression/ansi-c/undeclared_function/undeclared_function1.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE gcc-only
22
fileA.c
33
fileB.c --validate-goto-model
44
^EXIT=0$

regression/ansi-c/incomplete-structs/test.desc renamed to regression/cbmc/incomplete-structs/test.desc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
CORE
22
typesmain.c
3-
types1.c types2.c types3.c --verbosity 2
3+
types1.c types2.c types3.c
44
reason for conflict at \*#this.u: number of members is different \(3/0\)
55
reason for conflict at \*#this.u: number of members is different \(0/3\)
66
struct U \(incomplete\)
77
warning: pointer parameter types differ between declaration and definition "bar"
88
warning: pointer parameter types differ between declaration and definition "foo"
9+
^VERIFICATION SUCCESSFUL$
910
^EXIT=0$
1011
^SIGNAL=0$
1112
--

regression/cbmc/return6/test.desc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
CORE
22
main.c
33
f_def.c
4-
^EXIT=6$
4+
^VERIFICATION SUCCESSFUL$
5+
^EXIT=0$
56
^SIGNAL=0$
6-
CONVERSION ERROR
77
--
88
^warning: ignoring
9-
^VERIFICATION SUCCESSFUL$

regression/linking-goto-binaries/chain.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ else
2121
$goto_cc "${main}.gb" "${next}.gb" -o "final.gb"
2222
fi
2323

24-
$cbmc "final.gb"
24+
$cbmc --validate-goto-model "final.gb"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
struct S
2+
{
3+
void *a;
4+
void *b;
5+
};
6+
7+
typedef void (*fptr)(struct S);
8+
9+
extern void foo(struct S s);
10+
11+
fptr A[] = {foo};
12+
13+
extern void bar();
14+
15+
int main()
16+
{
17+
bar();
18+
return 0;
19+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include <assert.h>
2+
3+
struct S
4+
{
5+
void *a;
6+
void *b;
7+
};
8+
9+
typedef void (*fptr)(struct S);
10+
11+
extern fptr A[1];
12+
13+
struct real_S
14+
{
15+
int *a;
16+
int *b;
17+
};
18+
19+
void foo(struct real_S g)
20+
{
21+
assert(*g.a == 42);
22+
assert(*g.b == 41);
23+
}
24+
25+
void bar()
26+
{
27+
int x = 42;
28+
struct real_S s;
29+
s.a = &x;
30+
s.b = &x;
31+
A[0]((struct S){s.a, s.b});
32+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include <assert.h>
2+
3+
struct S
4+
{
5+
void *a;
6+
void *b;
7+
};
8+
9+
typedef void (*fptr)(struct S);
10+
11+
extern fptr A[1];
12+
13+
struct real_S
14+
{
15+
int *a;
16+
int *c;
17+
};
18+
19+
void foo(struct real_S g)
20+
{
21+
assert(*g.a == 42);
22+
assert(*g.c == 41);
23+
}
24+
25+
void bar()
26+
{
27+
int x = 42;
28+
struct real_S s;
29+
s.a = &x;
30+
s.c = &x;
31+
A[0]((struct S){s.a, s.c});
32+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <assert.h>
2+
3+
struct S
4+
{
5+
int i;
6+
};
7+
8+
struct S *function();
9+
10+
int main()
11+
{
12+
assert(function() != 0);
13+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
struct S
2+
{
3+
int i;
4+
int j; // extra member
5+
} some_var;
6+
7+
struct S *function()
8+
{
9+
return &some_var;
10+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
Linking7-main.c
3+
Linking7-module2.c
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
line 21 assertion \*g\.a == 42: SUCCESS
8+
line 22 assertion \*g\.c == 41: FAILURE
9+
^\*\* 1 of 3 failed
10+
--
11+
^warning: ignoring
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
Linking7-return_type1.c
3+
Linking7-return_type2.c
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring
9+
--
10+
Note issue #3081
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
Linking7-main.c
3+
Linking7-module.c
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
^\*\* 1 of 3 failed
8+
line 21 assertion \*g\.a == 42: SUCCESS
9+
line 22 assertion \*g\.b == 41: FAILURE
10+
--
11+
^warning: ignoring

src/goto-programs/link_goto_model.cpp

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ void finalize_linking(
148148
goto_modelt &dest,
149149
const replace_symbolt::expr_mapt &type_updates)
150150
{
151-
unchecked_replace_symbolt object_type_updates;
151+
casting_replace_symbolt object_type_updates;
152152
object_type_updates.get_expr_map().insert(
153153
type_updates.begin(), type_updates.end());
154154

@@ -196,10 +196,30 @@ void finalize_linking(
196196
{
197197
for(auto &instruction : gf_entry.second.body.instructions)
198198
{
199-
instruction.transform([&object_type_updates](exprt expr) {
200-
object_type_updates(expr);
201-
return expr;
202-
});
199+
if(instruction.is_function_call())
200+
{
201+
const bool changed =
202+
!object_type_updates.replace(instruction.call_function());
203+
if(changed && instruction.call_lhs().is_not_nil())
204+
{
205+
object_type_updates(instruction.call_lhs());
206+
if(
207+
instruction.call_lhs().type() !=
208+
to_code_type(instruction.call_function().type()).return_type())
209+
{
210+
instruction.call_lhs() = typecast_exprt{
211+
instruction.call_lhs(),
212+
to_code_type(instruction.call_function().type()).return_type()};
213+
}
214+
}
215+
}
216+
else
217+
{
218+
instruction.transform([&object_type_updates](exprt expr) {
219+
const bool changed = !object_type_updates.replace(expr);
220+
return changed ? optionalt<exprt>{expr} : nullopt;
221+
});
222+
}
203223
}
204224
}
205225
}

0 commit comments

Comments
 (0)