Skip to content

Commit a904f08

Browse files
author
thk123
committed
Add class for randomly selecting a concrete child of an abstract class
When generating a pointer to an abstract type, replace it with a pointer to a concrete type that derives from that abstract type.
1 parent 8dcff58 commit a904f08

File tree

4 files changed

+149
-2
lines changed

4 files changed

+149
-2
lines changed

src/java_bytecode/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ SRC = bytecode_info.cpp \
22
character_refine_preprocess.cpp \
33
ci_lazy_methods.cpp \
44
expr2java.cpp \
5+
get_concrete_class_at_random.cpp \
56
jar_file.cpp \
67
java_bytecode_convert_class.cpp \
78
java_bytecode_convert_method.cpp \
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Copyright 2016-2017 DiffBlue Limited. All Rights Reserved.
2+
3+
/// \file
4+
/// Java Bytecode Language Conversion
5+
6+
#include "get_concrete_class_at_random.h"
7+
8+
#include <algorithm>
9+
#include <random>
10+
11+
#include <util/namespace.h>
12+
#include <util/std_types.h>
13+
#include <util/symbol_table.h>
14+
15+
#include <goto-programs/class_hierarchy.h>
16+
17+
/// Get type the pointer is pointing to, replacing it with a concrete
18+
/// implementation when it is abstract.
19+
/// \param `pointer_type`: The type of the pointer
20+
/// \return The subtype of the pointer. If this is an abstract class then we
21+
/// will randomly select a concrete child class.
22+
typet get_concrete_class_at_randomt::operator()(
23+
const pointer_typet &pointer_type)
24+
{
25+
const typet &subtype=ns.follow(pointer_type.subtype());
26+
if(subtype.id()==ID_struct)
27+
{
28+
const class_typet &class_type=to_class_type(subtype);
29+
30+
if(class_type.is_class() && class_type.is_abstract())
31+
{
32+
return select_concrete_type(class_type);
33+
}
34+
}
35+
36+
// Here we must return the original subtype as if it is a pointer to a java
37+
// array java_object_factoryt::gen_nondet_array_init relies on the subtype
38+
// being a ID_symbol, here we have followed the symbol to its resolution.
39+
// Perhaps java_object_factoryt::gen_nondet_array_init should support this
40+
// Perhaps select_concrete_type when it fails should also ensure it doesn't
41+
// modify the subtype (currently if no concrete implementations we'd do the same
42+
// - swap a symbol to a struct
43+
return pointer_type.subtype();
44+
}
45+
46+
/// Randomly select a concrete sub-class of an abstract class or interface This
47+
/// can be then used when analyzing the function.
48+
/// \param `abstract_type`: an class type that is abstract (i.e. either an
49+
/// interface or a abstract class).
50+
/// \return A class_typet that the GOTO code should instantiate to fill this
51+
/// type. This will be a concrete type unless no concrete types are found that
52+
/// inherit from the abstract_type. `
53+
class_typet get_concrete_class_at_randomt::select_concrete_type(
54+
const class_typet &abstract_type)
55+
{
56+
if(!abstract_type.is_abstract())
57+
throw std::invalid_argument("abstract_type");
58+
59+
const symbol_tablet &symbol_table=ns.get_symbol_table();
60+
// abstract class - we should find a derived class ideally to test with
61+
class_hierarchyt class_hierachy;
62+
class_hierachy(symbol_table);
63+
class_hierarchyt::idst child_ids=
64+
class_hierachy.get_children_trans(abstract_type.get_string(ID_name));
65+
66+
// filter out abstract classes
67+
class_hierarchyt::idst concrete_childen;
68+
std::copy_if(
69+
child_ids.begin(),
70+
child_ids.end(),
71+
std::back_inserter(concrete_childen),
72+
[&] (const irep_idt &child_class_id)
73+
{
74+
const symbolt &type_symbol=symbol_table.lookup(child_class_id);
75+
const class_typet &child_type=to_class_type(type_symbol.type);
76+
return child_type.is_class() && !child_type.is_abstract();
77+
});
78+
79+
80+
if(concrete_childen.size()>0)
81+
{
82+
//Will be used to obtain a seed for the random number engine
83+
std::random_device rd;
84+
//Standard mersenne_twister_engine seeded with rd()
85+
std::mt19937 gen(rd());
86+
std::uniform_int_distribution<unsigned long> class_selector(
87+
0, concrete_childen.size()-1);
88+
unsigned long selected_class_index=class_selector(gen);
89+
const symbolt &type_symbol=
90+
symbol_table.lookup(concrete_childen[selected_class_index]);
91+
const class_typet &child_type=to_class_type(type_symbol.type);
92+
return child_type;
93+
}
94+
else
95+
{
96+
// else no children in the symbol table - here the best we can do is
97+
// mock the interface/abstract object
98+
return abstract_type;
99+
}
100+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*******************************************************************\
2+
3+
Module: Java Bytecode Language Conversion
4+
5+
Author: DiffBlue Limited. All rights reserved.
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Java Bytecode Language Conversion
11+
12+
#ifndef CPROVER_JAVA_BYTECODE_GET_CONCRETE_CLASS_AT_RANDOM_H
13+
#define CPROVER_JAVA_BYTECODE_GET_CONCRETE_CLASS_AT_RANDOM_H
14+
15+
#include <util/std_types.h>
16+
17+
class namespacet;
18+
19+
class get_concrete_class_at_randomt
20+
{
21+
public:
22+
explicit get_concrete_class_at_randomt (const namespacet &ns):ns(ns)
23+
{}
24+
25+
typet operator()(const pointer_typet &pointer_type);
26+
27+
private:
28+
const namespacet& ns;
29+
class_typet select_concrete_type(const class_typet &abstract_type);
30+
};
31+
32+
#endif // CPROVER_JAVA_BYTECODE_GET_CONCRETE_CLASS_AT_RANDOM_H

src/java_bytecode/java_object_factory.cpp

+16-2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ Author: Daniel Kroening, [email protected]
2727

2828
#include <goto-programs/goto_functions.h>
2929

30+
#include <java_bytecode/get_concrete_class_at_random.h>
31+
3032
#include "java_types.h"
3133
#include "java_utils.h"
3234

@@ -396,6 +398,7 @@ void java_object_factoryt::gen_nondet_pointer_init(
396398
{
397399
const struct_typet &struct_type=to_struct_type(subtype);
398400
const irep_idt &struct_tag=struct_type.get_tag();
401+
399402
// If this is a recursive type of some kind, set null.
400403
if(!recursion_set.insert(struct_tag).second)
401404
{
@@ -854,12 +857,23 @@ exprt object_factory(
854857
irep_idt identifier=id2string(goto_functionst::entry_point())+
855858
"::"+id2string(base_name);
856859

860+
typet real_type=type;
861+
if(type.id()==ID_pointer && type.subtype().id()==ID_symbol)
862+
{
863+
const pointer_typet &pointer_type=to_pointer_type(type);
864+
const namespacet ns(symbol_table);
865+
get_concrete_class_at_randomt get_concrete_class_at_random(ns);
866+
const typet &resolved_type=
867+
get_concrete_class_at_random(pointer_type);
868+
real_type.subtype()=resolved_type;
869+
}
870+
857871
auxiliary_symbolt main_symbol;
858872
main_symbol.mode=ID_java;
859873
main_symbol.is_static_lifetime=false;
860874
main_symbol.name=identifier;
861875
main_symbol.base_name=base_name;
862-
main_symbol.type=type;
876+
main_symbol.type=real_type;
863877
main_symbol.location=loc;
864878

865879
exprt object=main_symbol.symbol_expr();
@@ -871,7 +885,7 @@ exprt object_factory(
871885
std::vector<const symbolt *> symbols_created;
872886
symbols_created.push_back(main_symbol_ptr);
873887

874-
symbolt &aux_symbol=new_tmp_symbol(symbol_table, loc, type);
888+
symbolt &aux_symbol=new_tmp_symbol(symbol_table, loc, real_type);
875889
aux_symbol.is_static_lifetime=true;
876890

877891
java_object_factoryt state(

0 commit comments

Comments
 (0)