Skip to content

Commit 8869dd8

Browse files
author
Matthias Güdemann
authored
Merge pull request diffblue#1920 from diffblue/bugfix/continue_bootstrapmethods_parsing_after_unsupported_entry
Continue bootstrapmethods parsing after unsupported entry
2 parents d404a55 + ea6f00f commit 8869dd8

File tree

6 files changed

+192
-114
lines changed

6 files changed

+192
-114
lines changed
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import java.util.function.Function;
2+
import java.util.function.BiFunction;
3+
4+
public class StaticMethodRef{
5+
public Integer Smr(Integer ctr) {
6+
Function<Integer, Integer> func1 = Integer::valueOf;
7+
8+
// Uses Integer.valueOf(String)
9+
Function<String, Integer> func2 = Integer::valueOf;
10+
11+
BiFunction<String, Integer, Integer> func3 = Integer::valueOf;
12+
13+
if (ctr.equals(func1.apply(9)))
14+
return func1.apply(9);
15+
16+
if (ctr.equals(func2.apply("8")))
17+
return func2.apply("8");
18+
19+
if (ctr.equals(func3.apply("0111", 2)))
20+
return func3.apply("0111", 2);
21+
22+
return ctr;
23+
}
24+
}
+2
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
from https://github.com/symphonyoss/symphony-java-client/
2+
3+
The StaticMethodRef.class is compiled using the Eclipse Compiler
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE
2+
StaticMethodRef.class
3+
--function StaticMethodRef.Smr
4+
VERIFICATION FAILED
5+
EXIT=10
6+
SIGNAL=0
7+
^SIGNAL=0
8+
--
9+
--
10+
Tests that it doesn't crash when failing to read a `BootstrapMethods` entry and
11+
there is another attribute after this. The EXIT=10/VERIFCATION FAILED comes from
12+
the fact that the invokedynamic currently returns a null object, causing our
13+
model of this to predict a null pointer exception. This test will need to be
14+
adjusted when lambdas work.

src/java_bytecode/java_bytecode_parse_tree.h

+22
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,20 @@ class java_bytecode_parse_treet
194194
lambda_method_handlet() : handle_type(method_handle_typet::UNKNOWN_HANDLE)
195195
{
196196
}
197+
198+
static lambda_method_handlet
199+
create_unknown_handle(const u2_valuest params)
200+
{
201+
lambda_method_handlet lambda_method_handle;
202+
lambda_method_handle.handle_type = method_handle_typet::UNKNOWN_HANDLE;
203+
lambda_method_handle.u2_values = std::move(params);
204+
return lambda_method_handle;
205+
}
197206
};
198207

208+
// TODO(tkiley): This map shouldn't be interacted with directly (instead
209+
// TODO(tkiley): using add_method_handle and get_method_handle and instead
210+
// TODO(tkiley): should be made private. TG-2785
199211
typedef std::map<std::pair<irep_idt, size_t>, lambda_method_handlet>
200212
lambda_method_handle_mapt;
201213
lambda_method_handle_mapt lambda_method_handle_map;
@@ -221,6 +233,16 @@ class java_bytecode_parse_treet
221233
return methods.back();
222234
}
223235

236+
void add_method_handle(size_t bootstrap_index, lambda_method_handlet handle)
237+
{
238+
lambda_method_handle_map[{name, bootstrap_index}] = handle;
239+
}
240+
241+
const lambda_method_handlet &get_method_handle(size_t bootstrap_index) const
242+
{
243+
return lambda_method_handle_map.at({name, bootstrap_index});
244+
}
245+
224246
void output(std::ostream &out) const;
225247

226248
void swap(classt &other);

src/java_bytecode/java_bytecode_parser.cpp

+130-114
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,6 @@ class java_bytecode_parsert:public parsert
5252
method_handle_typet;
5353
typedef java_bytecode_parse_treet::classt::lambda_method_handlet
5454
lambda_method_handlet;
55-
typedef java_bytecode_parse_treet::classt::lambda_method_handle_mapt
56-
lambda_method_handle_mapt;
5755
typedef java_bytecode_parse_treet::classt::u2_valuest u2_valuest;
5856

5957
java_bytecode_parse_treet parse_tree;
@@ -186,6 +184,11 @@ class java_bytecode_parsert:public parsert
186184
{
187185
return read_bytes(8);
188186
}
187+
188+
void store_unknown_method_handle(
189+
classt &parsed_class,
190+
size_t bootstrap_method_index,
191+
u2_valuest u2_values) const;
189192
};
190193

191194
#define CONSTANT_Class 7
@@ -1803,7 +1806,9 @@ java_bytecode_parsert::parse_method_handle(const method_handle_infot &entry)
18031806
void java_bytecode_parsert::read_bootstrapmethods_entry(classt &parsed_class)
18041807
{
18051808
u2 num_bootstrap_methods = read_u2();
1806-
for(size_t i = 0; i < num_bootstrap_methods; i++)
1809+
for(size_t bootstrap_method_index = 0;
1810+
bootstrap_method_index < num_bootstrap_methods;
1811+
++bootstrap_method_index)
18071812
{
18081813
u2 bootstrap_methodhandle_ref = read_u2();
18091814
const pool_entryt &entry = pool_entry(bootstrap_methodhandle_ref);
@@ -1820,122 +1825,133 @@ void java_bytecode_parsert::read_bootstrapmethods_entry(classt &parsed_class)
18201825
u2_values[i] = read_u2();
18211826

18221827
// try parsing bootstrap method handle
1823-
if(num_bootstrap_arguments >= 3)
1828+
// each entry contains a MethodHandle structure
1829+
// u2 tag
1830+
// u2 reference kind which must be in the range from 1 to 9
1831+
// u2 reference index into the constant pool
1832+
//
1833+
// reference kinds use the following
1834+
// 1 to 4 must point to a CONSTANT_Fieldref structure
1835+
// 5 or 8 must point to a CONSTANT_Methodref structure
1836+
// 6 or 7 must point to a CONSTANT_Methodref or
1837+
// CONSTANT_InterfaceMethodref structure, if the class file version
1838+
// number is 52.0 or above, to a CONSTANT_Methodref only in the case
1839+
// of less than 52.0
1840+
// 9 must point to a CONSTANT_InterfaceMethodref structure
1841+
1842+
// the index must point to a CONSTANT_String
1843+
// CONSTANT_Class
1844+
// CONSTANT_Integer
1845+
// CONSTANT_Long
1846+
// CONSTANT_Float
1847+
// CONSTANT_Double
1848+
// CONSTANT_MethodHandle
1849+
// CONSTANT_MethodType
1850+
1851+
// We read the three arguments here to see whether they correspond to
1852+
// our hypotheses for this being a lambda function entry.
1853+
1854+
// Need at least 3 arguments, the interface type, the method hanlde
1855+
// and the method_type, otherwise it doesn't look like a call that we
1856+
// understand
1857+
if(num_bootstrap_arguments < 3)
18241858
{
1825-
// each entry contains a MethodHandle structure
1826-
// u2 tag
1827-
// u2 reference kind which must be in the range from 1 to 9
1828-
// u2 reference index into the constant pool
1829-
//
1830-
// reference kinds use the following
1831-
// 1 to 4 must point to a CONSTANT_Fieldref structure
1832-
// 5 or 8 must point to a CONSTANT_Methodref structure
1833-
// 6 or 7 must point to a CONSTANT_Methodref or
1834-
// CONSTANT_InterfaceMethodref structure, if the class file version
1835-
// number is 52.0 or above, to a CONSTANT_Methodref only in the case
1836-
// of less than 52.0
1837-
// 9 must point to a CONSTANT_InterfaceMethodref structure
1838-
1839-
// the index must point to a CONSTANT_String
1840-
// CONSTANT_Class
1841-
// CONSTANT_Integer
1842-
// CONSTANT_Long
1843-
// CONSTANT_Float
1844-
// CONSTANT_Double
1845-
// CONSTANT_MethodHandle
1846-
// CONSTANT_MethodType
1847-
1848-
// We read the three arguments here to see whether they correspond to
1849-
// our hypotheses for this being a lambda function entry.
1850-
1851-
u2 argument_index1 = u2_values[0];
1852-
u2 argument_index2 = u2_values[1];
1853-
u2 argument_index3 = u2_values[2];
1854-
1855-
// The additional arguments for the altmetafactory call are skipped,
1856-
// as they are currently not used. We verify though that they are of
1857-
// CONSTANT_Integer type, cases where this does not hold will be
1858-
// analyzed further.
1859-
bool recognized = true;
1860-
for(size_t i = 3; i < num_bootstrap_arguments; i++)
1861-
{
1862-
u2 skipped_argument = u2_values[i];
1863-
recognized &= pool_entry(skipped_argument).tag == CONSTANT_Integer;
1864-
}
1865-
if(!recognized)
1866-
{
1867-
debug() << "format of BootstrapMethods entry not recognized" << eom;
1868-
lambda_method_handlet lambda_method_handle;
1869-
lambda_method_handle.handle_type = method_handle_typet::UNKNOWN_HANDLE;
1870-
lambda_method_handle.u2_values = std::move(u2_values);
1871-
parsed_class.lambda_method_handle_map[{parsed_class.name, i}] =
1872-
lambda_method_handle;
1873-
return;
1874-
}
1875-
const pool_entryt &interface_type_argument = pool_entry(argument_index1);
1876-
const pool_entryt &method_handle_argument = pool_entry(argument_index2);
1877-
const pool_entryt &method_type_argument = pool_entry(argument_index3);
1878-
1879-
if(
1880-
!(interface_type_argument.tag == CONSTANT_MethodType &&
1881-
method_handle_argument.tag == CONSTANT_MethodHandle &&
1882-
method_type_argument.tag == CONSTANT_MethodType))
1883-
{
1884-
lambda_method_handlet lambda_method_handle;
1885-
lambda_method_handle.handle_type = method_handle_typet::UNKNOWN_HANDLE;
1886-
lambda_method_handle.u2_values = std::move(u2_values);
1887-
parsed_class.lambda_method_handle_map[{parsed_class.name, i}] =
1888-
lambda_method_handle;
1889-
return;
1890-
}
1859+
store_unknown_method_handle(
1860+
parsed_class, bootstrap_method_index, std::move(u2_values));
1861+
debug()
1862+
<< "format of BootstrapMethods entry not recognized: too few arguments"
1863+
<< eom;
1864+
continue;
1865+
}
18911866

1892-
debug() << "INFO: parse lambda handle" << eom;
1893-
optionalt<lambda_method_handlet> lambda_method_handle =
1894-
parse_method_handle(method_handle_infot{method_handle_argument});
1867+
u2 interface_type_index = u2_values[0];
1868+
u2 method_handle_index = u2_values[1];
1869+
u2 method_type_index = u2_values[2];
18951870

1896-
if(!lambda_method_handle.has_value())
1897-
{
1898-
lambda_method_handlet lambda_method_handle;
1899-
lambda_method_handle.handle_type = method_handle_typet::UNKNOWN_HANDLE;
1900-
lambda_method_handle.u2_values = std::move(u2_values);
1901-
parsed_class.lambda_method_handle_map[{parsed_class.name, i}] =
1902-
lambda_method_handle;
1903-
return;
1904-
}
1905-
else if(
1906-
lambda_method_handle->handle_type !=
1907-
method_handle_typet::LAMBDA_METHOD_HANDLE)
1908-
{
1909-
lambda_method_handle->u2_values = std::move(u2_values);
1910-
error() << "ERROR: could not parse lambda function method handle"
1911-
<< eom;
1912-
}
1913-
else
1914-
{
1915-
lambda_method_handle->interface_type =
1916-
pool_entry(interface_type_argument.ref1).s;
1917-
lambda_method_handle->method_type =
1918-
pool_entry(method_type_argument.ref1).s;
1919-
lambda_method_handle->u2_values = std::move(u2_values);
1920-
debug() << "lambda function reference "
1921-
<< id2string(lambda_method_handle->lambda_method_name)
1922-
<< " in class \"" << parsed_class.name << "\""
1923-
<< "\n interface type is "
1924-
<< id2string(pool_entry(interface_type_argument.ref1).s)
1925-
<< "\n method type is "
1926-
<< id2string(pool_entry(method_type_argument.ref1).s) << eom;
1927-
}
1928-
parsed_class.lambda_method_handle_map[{parsed_class.name, i}] =
1929-
*lambda_method_handle;
1871+
// The additional arguments for the altmetafactory call are skipped,
1872+
// as they are currently not used. We verify though that they are of
1873+
// CONSTANT_Integer type, cases where this does not hold will be
1874+
// analyzed further.
1875+
bool recognized = true;
1876+
for(size_t i = 3; i < num_bootstrap_arguments; i++)
1877+
{
1878+
u2 skipped_argument = u2_values[i];
1879+
recognized &= pool_entry(skipped_argument).tag == CONSTANT_Integer;
19301880
}
1931-
else
1881+
1882+
if(!recognized)
19321883
{
1933-
lambda_method_handlet lambda_method_handle;
1934-
lambda_method_handle.handle_type = method_handle_typet::UNKNOWN_HANDLE;
1935-
lambda_method_handle.u2_values = std::move(u2_values);
1936-
parsed_class.lambda_method_handle_map[{parsed_class.name, i}] =
1937-
lambda_method_handle;
1938-
error() << "ERROR: num_bootstrap_arguments must be at least 3" << eom;
1884+
debug() << "format of BootstrapMethods entry not recognized: extra "
1885+
"arguments of wrong type"
1886+
<< eom;
1887+
store_unknown_method_handle(
1888+
parsed_class, bootstrap_method_index, std::move(u2_values));
1889+
continue;
1890+
}
1891+
1892+
const pool_entryt &interface_type_argument =
1893+
pool_entry(interface_type_index);
1894+
const pool_entryt &method_handle_argument = pool_entry(method_handle_index);
1895+
const pool_entryt &method_type_argument = pool_entry(method_type_index);
1896+
1897+
if(
1898+
interface_type_argument.tag != CONSTANT_MethodType ||
1899+
method_handle_argument.tag != CONSTANT_MethodHandle ||
1900+
method_type_argument.tag != CONSTANT_MethodType)
1901+
{
1902+
debug() << "format of BootstrapMethods entry not recognized: arguments "
1903+
"wrong type"
1904+
<< eom;
1905+
store_unknown_method_handle(
1906+
parsed_class, bootstrap_method_index, std::move(u2_values));
1907+
continue;
1908+
}
1909+
1910+
debug() << "INFO: parse lambda handle" << eom;
1911+
optionalt<lambda_method_handlet> lambda_method_handle =
1912+
parse_method_handle(method_handle_infot{method_handle_argument});
1913+
1914+
if(!lambda_method_handle.has_value())
1915+
{
1916+
debug() << "format of BootstrapMethods entry not recognized: method "
1917+
"handle not recognised"
1918+
<< eom;
1919+
store_unknown_method_handle(
1920+
parsed_class, bootstrap_method_index, std::move(u2_values));
1921+
continue;
19391922
}
1923+
1924+
// If parse_method_handle can't parse the lambda method, it should return {}
1925+
POSTCONDITION(
1926+
lambda_method_handle->handle_type != method_handle_typet::UNKNOWN_HANDLE);
1927+
1928+
lambda_method_handle->interface_type =
1929+
pool_entry(interface_type_argument.ref1).s;
1930+
lambda_method_handle->method_type = pool_entry(method_type_argument.ref1).s;
1931+
lambda_method_handle->u2_values = std::move(u2_values);
1932+
debug() << "lambda function reference "
1933+
<< id2string(lambda_method_handle->lambda_method_name)
1934+
<< " in class \"" << parsed_class.name << "\""
1935+
<< "\n interface type is "
1936+
<< id2string(pool_entry(interface_type_argument.ref1).s)
1937+
<< "\n method type is "
1938+
<< id2string(pool_entry(method_type_argument.ref1).s) << eom;
1939+
parsed_class.add_method_handle(
1940+
bootstrap_method_index, *lambda_method_handle);
19401941
}
19411942
}
1943+
1944+
/// Creates an unknown method handle and puts it into the parsed_class
1945+
/// \param parsed_class: The class whose bootstrap method handles we are using
1946+
/// \param bootstrap_method_index: The current index in the bootstrap entry
1947+
/// table
1948+
/// \param u2_values: The indices of the arguments for the call
1949+
void java_bytecode_parsert::store_unknown_method_handle(
1950+
java_bytecode_parsert::classt &parsed_class,
1951+
size_t bootstrap_method_index,
1952+
java_bytecode_parsert::u2_valuest u2_values) const
1953+
{
1954+
const lambda_method_handlet lambda_method_handle =
1955+
lambda_method_handlet::create_unknown_handle(move(u2_values));
1956+
parsed_class.add_method_handle(bootstrap_method_index, lambda_method_handle);
1957+
}

0 commit comments

Comments
 (0)