Skip to content

Commit 5f70d13

Browse files
author
Owen Jones
committed
Added tests for addition/removal of hard/soft casts
1 parent c14b2a2 commit 5f70d13

File tree

3 files changed

+154
-2
lines changed

3 files changed

+154
-2
lines changed

regression/LVSA/TestCasts/Test.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package LVSA.TestCasts;
2+
3+
public class Test {
4+
public static TestInterface interfaceFromChild;
5+
public static TestInterface interfaceFromParent;
6+
public static TestParent parentFromChild;
7+
public static TestParent parentFromInterface;
8+
public static TestChild childFromInterface;
9+
public static TestChild childFromParent;
10+
11+
public void cast_from_child() {
12+
TestChild testChild = new TestChild();
13+
14+
interfaceFromChild = (TestInterface)testChild;
15+
parentFromChild = (TestParent)testChild;
16+
}
17+
18+
public void cast_from_parent() {
19+
TestParent testParent = new TestChild();
20+
21+
interfaceFromParent = (TestInterface)testParent;
22+
childFromParent = (TestChild)testParent;
23+
}
24+
25+
public void cast_from_interface() {
26+
TestInterface testInterface = (TestInterface)new TestChild();
27+
28+
parentFromInterface = (TestParent)testInterface;
29+
childFromInterface = (TestChild)testInterface;
30+
}
31+
}
32+
33+
interface TestInterface {
34+
}
35+
36+
class TestParent {
37+
}
38+
39+
class TestChild extends TestParent implements TestInterface {
40+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import fasteners
2+
import regression.LVSA.lvsa_driver as driver
3+
import os
4+
import regression.utils as utils
5+
6+
7+
def _get_this_file_dir():
8+
return os.path.dirname(os.path.abspath(__file__))
9+
10+
11+
def _get_folder_name():
12+
return os.path.basename(_get_this_file_dir())
13+
14+
15+
@fasteners.interprocess_locked(os.path.join(os.path.dirname(__file__), ".build_lock"))
16+
def test_cast_from_child(tmpdir):
17+
""" Test addition and removal of casts to DO's """
18+
with utils.working_dir(_get_this_file_dir()):
19+
os.system("javac Test.java")
20+
lvsa_driver = driver.LvsaDriver(tmpdir, _get_folder_name()).with_test_function('cast_from_child')
21+
lvsa_expectation = lvsa_driver.run()
22+
23+
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('interfaceFromChild')
24+
value_set_expectation.check_number_of_values(1)
25+
value_set_expectation.check_contains_typecast_dynamic_object(1, True, 'LVSA.TestCasts.TestInterface')
26+
27+
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('parentFromChild')
28+
value_set_expectation.check_number_of_values(1)
29+
value_set_expectation.check_contains_soft_cast_dynamic_object(1, True, 'LVSA.TestCasts.TestParent')
30+
31+
32+
@fasteners.interprocess_locked(os.path.join(os.path.dirname(__file__), ".build_lock"))
33+
def test_cast_from_parent(tmpdir):
34+
""" Test addition and removal of casts to DO's """
35+
with utils.working_dir(_get_this_file_dir()):
36+
os.system("javac Test.java")
37+
lvsa_driver = driver.LvsaDriver(tmpdir, _get_folder_name()).with_test_function('cast_from_parent')
38+
lvsa_expectation = lvsa_driver.run()
39+
40+
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('interfaceFromParent')
41+
value_set_expectation.check_number_of_values(1)
42+
value_set_expectation.check_contains_typecast_dynamic_object(1, True, 'LVSA.TestCasts.TestInterface')
43+
44+
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('childFromParent')
45+
value_set_expectation.check_number_of_values(1)
46+
value_set_expectation.check_contains_dynamic_object(1, True)
47+
48+
49+
@fasteners.interprocess_locked(os.path.join(os.path.dirname(__file__), ".build_lock"))
50+
def test_cast_from_interface(tmpdir):
51+
""" Test addition and removal of casts to DO's """
52+
with utils.working_dir(_get_this_file_dir()):
53+
os.system("javac Test.java")
54+
lvsa_driver = driver.LvsaDriver(tmpdir, _get_folder_name()).with_test_function('cast_from_interface')
55+
lvsa_expectation = lvsa_driver.run()
56+
57+
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('parentFromInterface')
58+
value_set_expectation.check_number_of_values(1)
59+
value_set_expectation.check_contains_soft_cast_dynamic_object(1, True, 'LVSA.TestCasts.TestParent')
60+
61+
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('childFromInterface')
62+
value_set_expectation.check_number_of_values(1)
63+
value_set_expectation.check_contains_dynamic_object(1, True)
64+

regression/LVSA/lvsa_driver.py

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ class Expr:
1010

1111
def __init__(self, expr):
1212
if expr['namedSub']['type']['id'] == 'symbol':
13-
self.type_identifier = expr['namedSub']['type']['namedSub']['identifier']['id']
13+
self.type_identifier = expr['namedSub']['type']['namedSub']['identifier']['id'].replace('java::', '')
14+
elif expr['namedSub']['type']['id'] == 'struct':
15+
self.type_identifier = expr['namedSub']['type']['namedSub']['base_name']['id']
1416
else:
1517
self.type_identifier = None
1618

@@ -27,6 +29,28 @@ def __init__(self, dynamic_object_expr):
2729
dynamic_object_expr['namedSub']['is_most_recent_allocation']['id'] == 'most_recent_allocation'
2830

2931

32+
class TypecastDynamicObject(Expr):
33+
"""Turn the json for a typecast dynamic object expr into a python object"""
34+
35+
def __init__(self, typecast_dynamic_object_expr):
36+
assert typecast_dynamic_object_expr['id'] == 'typecast'
37+
assert typecast_dynamic_object_expr['sub'][0]['id'] == 'dynamic_object'
38+
Expr.__init__(self, typecast_dynamic_object_expr)
39+
self.dynamic_object = DynamicObject(typecast_dynamic_object_expr['sub'][0])
40+
41+
42+
class SoftCastDynamicObject(Expr):
43+
"""Turn the json for a soft-cast dynamic object expr into a python object"""
44+
45+
def __init__(self, soft_cast_dynamic_object_expr):
46+
assert soft_cast_dynamic_object_expr['id'] == 'member'
47+
assert soft_cast_dynamic_object_expr['namedSub']['component_name']['id'].startswith('@')
48+
assert soft_cast_dynamic_object_expr['sub'][0]['id'] == 'dynamic_object'
49+
Expr.__init__(self, soft_cast_dynamic_object_expr)
50+
assert soft_cast_dynamic_object_expr['namedSub']['component_name']['id'] == '@' + self.type_identifier
51+
self.dynamic_object = DynamicObject(soft_cast_dynamic_object_expr['sub'][0])
52+
53+
3054
class EvsType(Enum):
3155
root_object = '0'
3256
per_field = '1'
@@ -72,13 +96,19 @@ def __init__(self, evs_expr):
7296
else:
7397
assert False
7498

99+
75100
class ValueSetExpectation:
76101
"""Encapsulate the states that a particular variable can take"""
77102

78103
def __init__(self, var_state):
79104
self.var_state = var_state['values']
80105
self.null_objects = [x for x in self.var_state if x['id'] == 'NULL-object']
81106
self.dynamic_objects = [DynamicObject(x) for x in self.var_state if x['id'] == 'dynamic_object']
107+
self.typecast_dynamic_objects = [TypecastDynamicObject(x) for x in self.var_state if x['id'] ==
108+
'typecast' and x['sub'][0]['id'] == 'dynamic_object']
109+
self.soft_cast_dynamic_objects = [SoftCastDynamicObject(x) for x in self.var_state if
110+
x['id'] == 'member' and x['namedSub']['component_name']['id'].startswith(
111+
'@') and x['sub'][0]['id'] == 'dynamic_object']
82112
self.external_value_sets = [ExternalValueSet(x) for x in self.var_state if x['id'] == 'external_value_set']
83113
self.unknown = [x for x in self.var_state if x['id'] == 'unknown']
84114

@@ -100,6 +130,23 @@ def check_contains_dynamic_object(self, expected_number=1, is_most_recent_alloca
100130
matches = [x for x in matches if x.is_most_recent_allocation == is_most_recent_allocation]
101131
assert expected_number == len(matches)
102132

133+
def check_contains_typecast_dynamic_object(self, expected_number=1, is_most_recent_allocation=None, type=None):
134+
matches = self.typecast_dynamic_objects
135+
if is_most_recent_allocation is not None:
136+
# Expect True or False
137+
matches = [x for x in matches if x.dynamic_object.is_most_recent_allocation == is_most_recent_allocation]
138+
if type is not None:
139+
# Expect string
140+
matches = [x for x in matches if x.type_identifier == type]
141+
assert expected_number == len(matches)
142+
143+
def check_contains_soft_cast_dynamic_object(self, expected_number=1, is_most_recent_allocation=None, type=None):
144+
matches = self.soft_cast_dynamic_objects
145+
if is_most_recent_allocation is not None:
146+
# Expect string
147+
matches = [x for x in matches if x.type_identifier == type]
148+
assert expected_number == len(matches)
149+
103150
def check_contains_root_object_evs(self, expected_number=1, label_suffix=None):
104151
matches = [x for x in self.external_value_sets if x.evs_type == EvsType.root_object]
105152
if label_suffix is not None:
@@ -267,7 +314,8 @@ def run(self):
267314
class_path = os.path.join('LVSA', self.folder_name, self.class_filename)
268315
cmd = [executable_path, '--local-value-set-analysis', '--lvsa-summary-directory', self.temp_dir_path,
269316
'--function', fq_function_name, '--show-value-sets', '--json-ui']
270-
if "SECURITY_REGRESSION_TESTS_USE_CSVSA" in os.environ and os.environ["SECURITY_REGRESSION_TESTS_USE_CSVSA"] != 0:
317+
if "SECURITY_REGRESSION_TESTS_USE_CSVSA" in os.environ and os.environ[
318+
"SECURITY_REGRESSION_TESTS_USE_CSVSA"] != 0:
271319
cmd.append("--lazy-methods-context-sensitive")
272320
if self.max_input_tree_depth is not None:
273321
cmd += ['--java-max-input-tree-depth', str(self.max_input_tree_depth)]

0 commit comments

Comments
 (0)