Skip to content

Commit 26dc976

Browse files
author
Remi Delmas
committed
Disabling pointer checks on CAR inclusion instructions. Enabling pointer overflow checks on CAR upper bound computation.
1 parent 850578b commit 26dc976

File tree

4 files changed

+66
-36
lines changed

4 files changed

+66
-36
lines changed

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: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,8 @@ void code_contractst::instrument_call_statement(
911911
}
912912
else if(callee_name == "free")
913913
{
914+
source_locationt location_no_checks = instruction_it->source_location();
915+
disable_pointer_checks(location_no_checks);
914916
const auto free_car = add_inclusion_check(
915917
body,
916918
assigns,
@@ -920,10 +922,9 @@ void code_contractst::instrument_call_statement(
920922
// skip all invalidation business if we're freeing invalid memory
921923
goto_programt alias_checking_instructions, skip_program;
922924
alias_checking_instructions.add(goto_programt::make_goto(
923-
skip_program.add(
924-
goto_programt::make_skip(instruction_it->source_location())),
925+
skip_program.add(goto_programt::make_skip(location_no_checks)),
925926
not_exprt{free_car.validity_condition_var},
926-
instruction_it->source_location()));
927+
location_no_checks));
927928

928929
// Since the argument to free may be an "alias" (but not identical)
929930
// to existing CARs' source_expr, structural equality wouldn't work.
@@ -943,8 +944,8 @@ void code_contractst::instrument_call_statement(
943944
.symbol_expr();
944945
write_set_validity_addrs.insert(object_validity_var_addr);
945946

946-
alias_checking_instructions.add(goto_programt::make_decl(
947-
object_validity_var_addr, instruction_it->source_location()));
947+
alias_checking_instructions.add(
948+
goto_programt::make_decl(object_validity_var_addr, location_no_checks));
948949
// if the CAR was defined on the same_object as the one being `free`d,
949950
// record its validity variable's address, otherwise record NULL
950951
alias_checking_instructions.add(goto_programt::make_assignment(
@@ -956,7 +957,7 @@ void code_contractst::instrument_call_statement(
956957
free_car.lower_bound_address_var, w_car.lower_bound_address_var)},
957958
address_of_exprt{w_car.validity_condition_var},
958959
null_pointer_exprt{to_pointer_type(object_validity_var_addr.type())}},
959-
instruction_it->source_location()));
960+
location_no_checks));
960961
}
961962

962963
alias_checking_instructions.destructive_append(skip_program);
@@ -972,24 +973,22 @@ void code_contractst::instrument_call_statement(
972973
goto_programt invalidation_instructions;
973974
skip_program.clear();
974975
invalidation_instructions.add(goto_programt::make_goto(
975-
skip_program.add(
976-
goto_programt::make_skip(instruction_it->source_location())),
976+
skip_program.add(goto_programt::make_skip(location_no_checks)),
977977
not_exprt{free_car.validity_condition_var},
978-
instruction_it->source_location()));
978+
location_no_checks));
979979

980980
// invalidate all recorded CAR validity variables
981981
for(const auto &w_car_validity_addr : write_set_validity_addrs)
982982
{
983983
goto_programt w_car_skip_program;
984984
invalidation_instructions.add(goto_programt::make_goto(
985-
w_car_skip_program.add(
986-
goto_programt::make_skip(instruction_it->source_location())),
985+
w_car_skip_program.add(goto_programt::make_skip(location_no_checks)),
987986
null_pointer(w_car_validity_addr),
988-
instruction_it->source_location()));
987+
location_no_checks));
989988
invalidation_instructions.add(goto_programt::make_assignment(
990989
dereference_exprt{w_car_validity_addr},
991990
false_exprt{},
992-
instruction_it->source_location()));
991+
location_no_checks));
993992
invalidation_instructions.destructive_append(w_car_skip_program);
994993
}
995994

@@ -1175,6 +1174,9 @@ void code_contractst::check_frame_conditions(
11751174
else if(instruction_it->is_dead())
11761175
{
11771176
const auto &symbol = instruction_it->dead_symbol();
1177+
source_locationt location_no_checks = instruction_it->source_location();
1178+
disable_pointer_checks(location_no_checks);
1179+
11781180
// CAR equality and hash are defined on source_expr alone,
11791181
// therefore this temporary CAR should be "found"
11801182
const auto &symbol_car = assigns.get_write_set().find(
@@ -1228,10 +1230,13 @@ code_contractst::add_inclusion_check(
12281230
program, instruction_it, snapshot_instructions);
12291231

12301232
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(
1233+
source_locationt location_no_checks =
1234+
instruction_it->source_location_nonconst();
1235+
disable_pointer_checks(location_no_checks);
1236+
location_no_checks.set_comment(
12341237
"Check that " + from_expr(ns, expr.id(), expr) + " is assignable");
1238+
assertion.add(goto_programt::make_assertion(
1239+
assigns.generate_inclusion_check(car), location_no_checks));
12351240
insert_before_swap_and_advance(program, instruction_it, assertion);
12361241

12371242
return car;

src/goto-instrument/contracts/utils.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,13 @@ const symbolt &new_tmp_symbol(
153153
location,
154154
mode,
155155
symtab);
156-
new_symbol.is_auxiliary = is_auxiliary;
157-
return new_symbol;
156+
new_symbol.is_auxiliary = is_auxiliary;
157+
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: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ void insert_before_swap_and_advance(
112112
/// \param mode: The mode for the new symbol, e.g. ID_C, ID_java.
113113
/// \param symtab: The symbol table to which the new symbol is to be added.
114114
/// \param suffix: Suffix to use to generate the unique name
115-
/// \param is_auxiliary: Do not print symbol in traces if true (default = false)
115+
/// \param is_auxiliary: Do not print symbol in traces if true (default = false)
116116
/// \return The new symbolt object.
117117
const symbolt &new_tmp_symbol(
118118
const typet &type,
@@ -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)