Skip to content

Commit 0b7535c

Browse files
author
Remi Delmas
committed
Disabling pointer checks on CAR inclusion instructions. Enabling pointer overflow checks on CAR upper bound computation.
1 parent 0363985 commit 0b7535c

File tree

5 files changed

+66
-34
lines changed

5 files changed

+66
-34
lines changed

regression/contracts/quantifiers-forall-ensures-enforce/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ int f1(int *arr, int len)
2323
int main()
2424
{
2525
int len;
26-
__CPROVER_assume(0 <= len && len <= MAX_LEN);
26+
__CPROVER_assume(0 < len && len <= MAX_LEN);
2727

2828
int *arr = malloc(len * sizeof(int));
2929
f1(arr, len);

src/goto-instrument/contracts/assigns.cpp

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Date: July 2021
1212
/// Specify write set in code contracts
1313

1414
#include "assigns.h"
15+
#include "utils.h"
1516

1617
#include <analyses/call_graph.h>
1718

@@ -87,41 +88,54 @@ assigns_clauset::conditional_address_ranget::generate_snapshot_instructions()
8788
const
8889
{
8990
goto_programt instructions;
90-
91-
instructions.add(goto_programt::make_decl(validity_condition_var, location));
92-
instructions.add(goto_programt::make_decl(lower_bound_address_var, location));
93-
instructions.add(goto_programt::make_decl(upper_bound_address_var, location));
91+
// adding pragmas to the location to selectively disable checks
92+
// where it is sound to do so
93+
source_locationt location_no_checks = location;
94+
disable_pointer_checks(location_no_checks);
95+
96+
instructions.add(
97+
goto_programt::make_decl(validity_condition_var, location_no_checks));
98+
instructions.add(
99+
goto_programt::make_decl(lower_bound_address_var, location_no_checks));
100+
instructions.add(
101+
goto_programt::make_decl(upper_bound_address_var, location_no_checks));
94102

95103
instructions.add(goto_programt::make_assignment(
96104
lower_bound_address_var,
97105
null_pointer_exprt{to_pointer_type(slice.first.type())},
98-
location));
106+
location_no_checks));
99107
instructions.add(goto_programt::make_assignment(
100108
upper_bound_address_var,
101109
null_pointer_exprt{to_pointer_type(slice.first.type())},
102-
location));
110+
location_no_checks));
103111

104112
goto_programt skip_program;
105-
const auto skip_target = skip_program.add(goto_programt::make_skip(location));
113+
const auto skip_target =
114+
skip_program.add(goto_programt::make_skip(location_no_checks));
106115

107116
const auto validity_check_expr =
108117
and_exprt{all_dereferences_are_valid(source_expr, parent.ns),
109118
w_ok_exprt{slice.first, slice.second}};
110119
instructions.add(goto_programt::make_assignment(
111-
validity_condition_var, validity_check_expr, location));
120+
validity_condition_var, validity_check_expr, location_no_checks));
112121

113122
instructions.add(goto_programt::make_goto(
114-
skip_target, not_exprt{validity_condition_var}, location));
123+
skip_target, not_exprt{validity_condition_var}, location_no_checks));
115124

116125
instructions.add(goto_programt::make_assignment(
117-
lower_bound_address_var, slice.first, location));
126+
lower_bound_address_var, slice.first, location_no_checks));
127+
128+
// the computation of the CAR upper bound can overflow into the object ID bits
129+
// of the pointer with very large allocation sizes.
130+
// We enable pointer overflow checks to detect such cases.
131+
source_locationt location_overflow_check = location;
132+
location_overflow_check.add_pragma("enable:pointer-overflow-check");
118133

119134
instructions.add(goto_programt::make_assignment(
120135
upper_bound_address_var,
121136
minus_exprt{plus_exprt{slice.first, slice.second},
122137
from_integer(1, slice.second.type())},
123-
location));
124-
138+
location_overflow_check));
125139
instructions.destructive_append(skip_program);
126140

127141
// The assignments above are only performed on locally defined temporaries
@@ -134,14 +148,16 @@ const exprt
134148
assigns_clauset::conditional_address_ranget::generate_unsafe_inclusion_check(
135149
const conditional_address_ranget &lhs) const
136150
{
151+
// remark: both lb and ub are derived from the same object so checking
152+
// same_object(upper_bound_address_var, lhs.upper_bound_address_var)
153+
// is redundant
137154
return conjunction(
138155
{validity_condition_var,
139156
same_object(lower_bound_address_var, lhs.lower_bound_address_var),
140-
same_object(lhs.upper_bound_address_var, upper_bound_address_var),
141-
less_than_or_equal_exprt{lower_bound_address_var,
142-
lhs.lower_bound_address_var},
143-
less_than_or_equal_exprt{lhs.upper_bound_address_var,
144-
upper_bound_address_var}});
157+
less_than_or_equal_exprt{pointer_offset(lower_bound_address_var),
158+
pointer_offset(lhs.lower_bound_address_var)},
159+
less_than_or_equal_exprt{pointer_offset(lhs.upper_bound_address_var),
160+
pointer_offset(upper_bound_address_var)}});
145161
}
146162

147163
assigns_clauset::assigns_clauset(

src/goto-instrument/contracts/contracts.cpp

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,9 @@ void code_contractst::instrument_call_statement(
911911
}
912912
else if(callee_name == "free")
913913
{
914+
source_locationt location_no_checks =
915+
instruction_it->source_location();
916+
disable_pointer_checks(location_no_checks);
914917
const auto free_car = add_inclusion_check(
915918
body,
916919
assigns,
@@ -920,10 +923,9 @@ void code_contractst::instrument_call_statement(
920923
// skip all invalidation business if we're freeing invalid memory
921924
goto_programt alias_checking_instructions, skip_program;
922925
alias_checking_instructions.add(goto_programt::make_goto(
923-
skip_program.add(
924-
goto_programt::make_skip(instruction_it->source_location())),
926+
skip_program.add(goto_programt::make_skip(location_no_checks)),
925927
not_exprt{free_car.validity_condition_var},
926-
instruction_it->source_location()));
928+
location_no_checks));
927929

928930
// Since the argument to free may be an "alias" (but not identical)
929931
// to existing CARs' source_expr, structural equality wouldn't work.
@@ -943,8 +945,8 @@ void code_contractst::instrument_call_statement(
943945
.symbol_expr();
944946
write_set_validity_addrs.insert(object_validity_var_addr);
945947

946-
alias_checking_instructions.add(goto_programt::make_decl(
947-
object_validity_var_addr, instruction_it->source_location()));
948+
alias_checking_instructions.add(
949+
goto_programt::make_decl(object_validity_var_addr, location_no_checks));
948950
// if the CAR was defined on the same_object as the one being `free`d,
949951
// record its validity variable's address, otherwise record NULL
950952
alias_checking_instructions.add(goto_programt::make_assignment(
@@ -956,7 +958,7 @@ void code_contractst::instrument_call_statement(
956958
free_car.lower_bound_address_var, w_car.lower_bound_address_var)},
957959
address_of_exprt{w_car.validity_condition_var},
958960
null_pointer_exprt{to_pointer_type(object_validity_var_addr.type())}},
959-
instruction_it->source_location()));
961+
location_no_checks));
960962
}
961963

962964
alias_checking_instructions.destructive_append(skip_program);
@@ -972,24 +974,22 @@ void code_contractst::instrument_call_statement(
972974
goto_programt invalidation_instructions;
973975
skip_program.clear();
974976
invalidation_instructions.add(goto_programt::make_goto(
975-
skip_program.add(
976-
goto_programt::make_skip(instruction_it->source_location())),
977+
skip_program.add(goto_programt::make_skip(location_no_checks)),
977978
not_exprt{free_car.validity_condition_var},
978-
instruction_it->source_location()));
979+
location_no_checks));
979980

980981
// invalidate all recorded CAR validity variables
981982
for(const auto &w_car_validity_addr : write_set_validity_addrs)
982983
{
983984
goto_programt w_car_skip_program;
984985
invalidation_instructions.add(goto_programt::make_goto(
985-
w_car_skip_program.add(
986-
goto_programt::make_skip(instruction_it->source_location())),
986+
w_car_skip_program.add(goto_programt::make_skip(location_no_checks)),
987987
null_pointer(w_car_validity_addr),
988-
instruction_it->source_location()));
988+
location_no_checks));
989989
invalidation_instructions.add(goto_programt::make_assignment(
990990
dereference_exprt{w_car_validity_addr},
991991
false_exprt{},
992-
instruction_it->source_location()));
992+
location_no_checks));
993993
invalidation_instructions.destructive_append(w_car_skip_program);
994994
}
995995

@@ -1175,6 +1175,10 @@ void code_contractst::check_frame_conditions(
11751175
else if(instruction_it->is_dead())
11761176
{
11771177
const auto &symbol = instruction_it->dead_symbol();
1178+
source_locationt location_no_checks =
1179+
instruction_it->source_location();
1180+
disable_pointer_checks(location_no_checks);
1181+
11781182
// CAR equality and hash are defined on source_expr alone,
11791183
// therefore this temporary CAR should be "found"
11801184
const auto &symbol_car = assigns.get_write_set().find(
@@ -1228,10 +1232,13 @@ code_contractst::add_inclusion_check(
12281232
program, instruction_it, snapshot_instructions);
12291233

12301234
goto_programt assertion;
1231-
assertion.add(goto_programt::make_assertion(
1232-
assigns.generate_inclusion_check(car), instruction_it->source_location()));
1233-
assertion.instructions.back().source_location_nonconst().set_comment(
1235+
source_locationt location_no_checks =
1236+
instruction_it->source_location_nonconst();
1237+
disable_pointer_checks(location_no_checks);
1238+
location_no_checks.set_comment(
12341239
"Check that " + from_expr(ns, expr.id(), expr) + " is assignable");
1240+
assertion.add(goto_programt::make_assertion(
1241+
assigns.generate_inclusion_check(car), location_no_checks));
12351242
insert_before_swap_and_advance(program, instruction_it, assertion);
12361243

12371244
return car;

src/goto-instrument/contracts/utils.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,10 @@ const symbolt &new_tmp_symbol(
156156
new_symbol.is_auxiliary = is_auxiliary;
157157
return new_symbol;
158158
}
159+
160+
void disable_pointer_checks(source_locationt &source_location)
161+
{
162+
source_location.add_pragma("disable:pointer-check");
163+
source_location.add_pragma("disable:pointer-primitive-check");
164+
source_location.add_pragma("disable:pointer-overflow-check");
159165
}

src/goto-instrument/contracts/utils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,7 @@ const symbolt &new_tmp_symbol(
122122
std::string suffix = "tmp_cc",
123123
bool is_auxiliary = false);
124124

125+
/// Add disable pragmas for all pointer checks on the given location
126+
void disable_pointer_checks(source_locationt &source_location);
127+
125128
#endif // CPROVER_GOTO_INSTRUMENT_CONTRACTS_UTILS_H

0 commit comments

Comments
 (0)