Skip to content

Commit e53df5d

Browse files
committed
java-unwind-enum-static: also unwind clone loop in Enum.values()
If an enumeration type's values() method clones an array, we assume it is cloning the array of enumeration values and therefore is bounded by the enumeration's size, similar to the existing handling of enumeration static initializers.
1 parent 4985554 commit e53df5d

File tree

4 files changed

+43
-15
lines changed

4 files changed

+43
-15
lines changed

jbmc/src/java_bytecode/java_enum_static_init_unwind_handler.cpp

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,40 @@ Author: Chris Smowton, [email protected]
1414
#include <util/invariant.h>
1515
#include <util/suffix.h>
1616

17+
/// Check if we may be in a function that loops over the cases of an
18+
/// enumeration (note we return a candidate function that matches a pattern;
19+
/// our caller must verify it really belongs to an enumeration).
20+
/// At the moment we know of two cases that definitely do so:
21+
/// * An enumeration type's static initialiser
22+
/// * The array[reference].clone() method when called from an enumeration type's
23+
/// 'values()' method
24+
/// \param context: the current call stack
25+
/// \return the name of an enclosing function that may be defined on the
26+
/// relevant enum type, or an empty string if we don't find one.
27+
static irep_idt
28+
find_enum_function_on_stack(const goto_symex_statet::call_stackt &context)
29+
{
30+
static irep_idt reference_array_clone_id =
31+
"java::array[reference].clone:()Ljava/lang/Object;";
32+
33+
PRECONDITION(!context.empty());
34+
const irep_idt &current_function = context.back().function_identifier;
35+
36+
if(context.size() >= 2 && current_function == reference_array_clone_id)
37+
{
38+
const irep_idt &clone_caller =
39+
context.at(context.size() - 2).function_identifier;
40+
if(id2string(clone_caller).find(".values:()[L") != std::string::npos)
41+
return clone_caller;
42+
else
43+
return irep_idt();
44+
}
45+
else if(has_suffix(id2string(current_function), ".<clinit>:()V"))
46+
return current_function;
47+
else
48+
return irep_idt();
49+
}
50+
1751
/// Unwind handler that special-cases the clinit (static initializer) functions
1852
/// of enumeration classes. When java_bytecode_convert_classt has annotated them
1953
/// with a size of the enumeration type, this forces unwinding of any loop in
@@ -29,17 +63,17 @@ Author: Chris Smowton, [email protected]
2963
/// unwind_count is <= the enumeration size, or unknown (defer / no decision)
3064
/// otherwise.
3165
tvt java_enum_static_init_unwind_handler(
32-
const irep_idt &function_id,
66+
const goto_symex_statet::call_stackt &context,
3367
unsigned loop_number,
3468
unsigned unwind_count,
3569
unsigned &unwind_max,
3670
const symbol_tablet &symbol_table)
3771
{
38-
const std::string &function_str = id2string(function_id);
39-
if(!has_suffix(function_str, ".<clinit>:()V"))
72+
const irep_idt enum_function_id = find_enum_function_on_stack(context);
73+
if(enum_function_id.empty())
4074
return tvt::unknown();
4175

42-
const symbolt &function_symbol = symbol_table.lookup_ref(function_str);
76+
const symbolt &function_symbol = symbol_table.lookup_ref(enum_function_id);
4377
irep_idt class_id = function_symbol.type.get(ID_C_class);
4478
INVARIANT(
4579
!class_id.empty(), "functions should have their defining class annotated");

jbmc/src/java_bytecode/java_enum_static_init_unwind_handler.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ Author: Chris Smowton, [email protected]
1212
#ifndef CPROVER_JAVA_BYTECODE_JAVA_ENUM_STATIC_INIT_UNWIND_HANDLER_H
1313
#define CPROVER_JAVA_BYTECODE_JAVA_ENUM_STATIC_INIT_UNWIND_HANDLER_H
1414

15+
#include <goto-symex/goto_symex_state.h>
16+
1517
#include <util/symbol_table.h>
1618
#include <util/threeval.h>
1719

1820
tvt java_enum_static_init_unwind_handler(
19-
const irep_idt &function_id,
21+
const goto_symex_statet::call_stackt &context,
2022
unsigned loop_number,
2123
unsigned unwind_count,
2224
unsigned &unwind_max,

jbmc/src/jbmc/jbmc_parse_options.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -485,11 +485,7 @@ int jbmc_parse_optionst::doit()
485485
unsigned unwind,
486486
unsigned &max_unwind) {
487487
return java_enum_static_init_unwind_handler(
488-
context,
489-
loop_number,
490-
unwind,
491-
max_unwind,
492-
symbol_table);
488+
context, loop_number, unwind, max_unwind, symbol_table);
493489
});
494490
};
495491
}

src/cbmc/symex_bmc.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,7 @@ bool symex_bmct::get_unwind(
117117
for(auto handler : loop_unwind_handlers)
118118
{
119119
abort_unwind_decision =
120-
handler(
121-
context,
122-
source.pc->loop_number,
123-
unwind,
124-
this_loop_limit);
120+
handler(context, source.pc->loop_number, unwind, this_loop_limit);
125121
if(abort_unwind_decision.is_known())
126122
break;
127123
}

0 commit comments

Comments
 (0)