Skip to content

Commit 8e0744f

Browse files
Uses the containing_class to determine accessibility.
An inner class is only as accessible as its containing classes. When determining the accessibility of an inner class, take the strictest of all of its containing classes.
1 parent e0c56ae commit 8e0744f

File tree

4 files changed

+77
-0
lines changed

4 files changed

+77
-0
lines changed

jbmc/src/java_bytecode/java_bytecode_convert_class.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ void java_bytecode_convert_classt::convert(
279279
class_type.set_is_inner_class(c.is_inner_class);
280280
class_type.set_is_static_class(c.is_static_class);
281281
class_type.set_is_anonymous_class(c.is_anonymous_class);
282+
class_type.set_containing_class(c.containing_class);
282283
if(c.is_enum)
283284
{
284285
if(max_array_length != 0 && c.enum_elements > max_array_length)
@@ -1153,3 +1154,60 @@ void mark_java_implicitly_generic_class_type(
11531154
}
11541155
}
11551156
}
1157+
1158+
/// If access1 is stricter than access2, returns true, otherwise returns false.
1159+
/// Assumed order of strictness:
1160+
/// private, default (package_private), protected, public
1161+
bool compare_access(irep_idt access1, irep_idt access2)
1162+
{
1163+
if(access1 == access2)
1164+
return false;
1165+
if(access1 == ID_private)
1166+
return true;
1167+
if(access1 == ID_default && access2 != ID_private)
1168+
return true;
1169+
if(access1 == ID_protected && access2 == ID_public)
1170+
return true;
1171+
return false;
1172+
}
1173+
1174+
/// Inner class accessibility depends not only on the inner class' access
1175+
/// modifier, but the access modifiers of its containing classes. This checks
1176+
/// all of the containing classes of an inner class and sets the access of the
1177+
/// inner class to the strictest of its containing classes. For example, for a
1178+
/// deeply nested structure Outer.Middle.Inner with access modifiers public,
1179+
/// private, public, respectively, the access of Inner should be private
1180+
/// (not public) because one of its containing classes has private access.
1181+
/// \param inner_class_name
1182+
/// \param symbol_table
1183+
void determine_inner_class_accessibility(
1184+
const irep_idt &inner_class_name,
1185+
symbol_tablet &symbol_table)
1186+
{
1187+
const std::string qualified_inner_class_name =
1188+
"java::" + id2string(inner_class_name);
1189+
PRECONDITION(symbol_table.has_symbol(qualified_inner_class_name));
1190+
symbolt &inner_class_symbol =
1191+
symbol_table.get_writeable_ref(qualified_inner_class_name);
1192+
java_class_typet &inner_class_type =
1193+
to_java_class_type(inner_class_symbol.type);
1194+
1195+
if(!inner_class_type.get_is_inner_class())
1196+
return;
1197+
if(inner_class_type.get_containing_class().empty())
1198+
return;
1199+
const std::string qualified_containing_class_name =
1200+
"java::" + id2string(inner_class_type.get_containing_class());
1201+
PRECONDITION(symbol_table.has_symbol(qualified_containing_class_name));
1202+
symbolt &containing_class_symbol =
1203+
symbol_table.get_writeable_ref(qualified_containing_class_name);
1204+
java_class_typet &containing_class_type =
1205+
to_java_class_type(containing_class_symbol.type);
1206+
1207+
if(
1208+
compare_access(
1209+
containing_class_type.get_access(), inner_class_type.get_access()))
1210+
{
1211+
inner_class_type.set_access(containing_class_type.get_access());
1212+
}
1213+
}

jbmc/src/java_bytecode/java_bytecode_convert_class.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ void mark_java_implicitly_generic_class_type(
4141
const irep_idt &class_name,
4242
symbol_tablet &symbol_table);
4343

44+
void determine_inner_class_accessibility(
45+
const irep_idt &class_name,
46+
symbol_tablet &symbol_table);
47+
4448
/// An exception that is raised checking whether a class is implicitly
4549
/// generic if a symbol for an outer class is missing
4650
class missing_outer_class_symbol_exceptiont : public std::logic_error

jbmc/src/java_bytecode/java_bytecode_language.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,16 @@ bool java_bytecode_languaget::typecheck(
677677
}
678678
}
679679

680+
// Determine inner class accessibility by taking the most strict of access
681+
// modifiers of all of the containing classes
682+
for(const auto &c : java_class_loader.get_class_with_overlays_map())
683+
{
684+
if(c.second.front().parsed_class.containing_class.empty())
685+
continue;
686+
determine_inner_class_accessibility(
687+
c.second.front().parsed_class.name, symbol_table);
688+
}
689+
680690
// Infer fields on opaque types based on the method instructions just loaded.
681691
// For example, if we don't have bytecode for field x of class A, but we can
682692
// see an int-typed getfield instruction referring to it, add that field now.

jbmc/src/java_bytecode/java_bytecode_parser.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1643,6 +1643,11 @@ void java_bytecode_parsert::rinner_classes_attribute(
16431643
}
16441644
else
16451645
{
1646+
std::string outer_class_info_name =
1647+
class_infot(pool_entry(outer_class_info_index))
1648+
.get_name(pool_entry_lambda);
1649+
parsed_class.containing_class =
1650+
constant(outer_class_info_index).type().get(ID_C_base_name);
16461651
parsed_class.is_private = is_private;
16471652
parsed_class.is_protected = is_protected;
16481653
parsed_class.is_public = is_public;

0 commit comments

Comments
 (0)