Skip to content

Commit bcaf5f6

Browse files
authored
Merge pull request #4967 from smowton/smowton/feature/straightforward-remove-instanceof
Don't use temporaries in remove_instanceof
2 parents d263955 + 581540c commit bcaf5f6

File tree

4 files changed

+23
-54
lines changed

4 files changed

+23
-54
lines changed
Binary file not shown.
114 Bytes
Binary file not shown.

jbmc/regression/jbmc/clean_derefs/Test.java

+5
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ public static void main(int nondet) {
3535
(nondet == 30 ? c1 : c3).t.field++;
3636
(nondet == 40 ? c2.t : tarray[3]).field--;
3737

38+
// Check that we produce a clean deref when a cast restricts the possible
39+
// targets of a field access:
40+
Object o = nondet % 2 == 0 ? new Object() : new Container(new Test(10));
41+
int field = ((Container)o).t.field;
42+
3843
assert false;
3944

4045
}

jbmc/src/java_bytecode/remove_instanceof.cpp

+18-54
Original file line numberDiff line numberDiff line change
@@ -110,70 +110,34 @@ bool remove_instanceoft::lower_instanceof(
110110
return a.compare(b) < 0;
111111
});
112112

113-
// Make temporaries to store the class identifier (avoids repeated derefs) and
114-
// the instanceof result:
115-
116113
auto jlo = to_struct_tag_type(java_lang_object_type().subtype());
117114
exprt object_clsid = get_class_identifier_field(check_ptr, jlo, ns);
118115

119-
symbolt &clsid_tmp_sym = fresh_java_symbol(
120-
object_clsid.type(),
121-
"class_identifier_tmp",
122-
this_inst->source_location,
123-
function_identifier,
124-
symbol_table);
125-
126-
symbolt &instanceof_result_sym = fresh_java_symbol(
127-
bool_typet(),
128-
"instanceof_result_tmp",
129-
this_inst->source_location,
130-
function_identifier,
131-
symbol_table);
132-
133-
// Create
134-
// if(expr == null)
135-
// instanceof_result = false;
136-
// else
137-
// string clsid = expr->@class_identifier
138-
// instanceof_result = clsid == "A" || clsid == "B" || ...
139-
140-
// According to the Java specification, null instanceof T is false for all
141-
// possible values of T.
142-
// (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.20.2)
143-
144-
code_blockt else_block;
145-
else_block.add(code_declt(clsid_tmp_sym.symbol_expr()));
146-
else_block.add(code_assignt(clsid_tmp_sym.symbol_expr(), object_clsid));
116+
// Replace the instanceof operation with (check_ptr != null &&
117+
// (check_ptr->@class_identifier == "A" ||
118+
// check_ptr->@class_identifier == "B" || ...
119+
120+
// By operating directly on a pointer rather than using a temporary
121+
// (x->@clsid == "A" rather than id = x->@clsid; id == "A") we enable symex's
122+
// value-set filtering to discard no-longer-viable candidates for "x" (in the
123+
// case where 'x' is a symbol, not a general expression like x->y->@clsid).
124+
// This means there are more clean dereference operations (ones where there
125+
// is no possibility of reading a null, invalid or incorrectly-typed object),
126+
// and less pessimistic aliasing assumptions possibly causing goto-symex to
127+
// explore in-fact-unreachable paths.
147128

148129
exprt::operandst or_ops;
149130
for(const auto &clsname : children)
150131
{
151132
constant_exprt clsexpr(clsname, string_typet());
152-
equal_exprt test(clsid_tmp_sym.symbol_expr(), clsexpr);
133+
equal_exprt test(object_clsid, clsexpr);
153134
or_ops.push_back(test);
154135
}
155-
else_block.add(
156-
code_assignt(instanceof_result_sym.symbol_expr(), disjunction(or_ops)));
157-
158-
const code_ifthenelset is_null_branch(
159-
equal_exprt(
160-
check_ptr, null_pointer_exprt(to_pointer_type(check_ptr.type()))),
161-
code_assignt(instanceof_result_sym.symbol_expr(), false_exprt()),
162-
std::move(else_block));
163-
164-
// Replace the instanceof construct with instanceof_result:
165-
expr = instanceof_result_sym.symbol_expr();
166-
167-
// Insert the new test block before it:
168-
goto_programt new_check_program;
169-
goto_convert(
170-
is_null_branch,
171-
symbol_table,
172-
new_check_program,
173-
message_handler,
174-
ID_java);
175-
176-
goto_program.destructive_insert(this_inst, new_check_program);
136+
137+
notequal_exprt not_null(
138+
check_ptr, null_pointer_exprt(to_pointer_type(check_ptr.type())));
139+
140+
expr = and_exprt(not_null, disjunction(or_ops));
177141

178142
return true;
179143
}

0 commit comments

Comments
 (0)