Skip to content

Commit e0ccb12

Browse files
author
Matthias Güdemann
committed
Refactor BootstrapMethods attribute reading into function
1 parent 463ffe1 commit e0ccb12

File tree

1 file changed

+118
-111
lines changed

1 file changed

+118
-111
lines changed

src/java_bytecode/java_bytecode_parser.cpp

+118-111
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ class java_bytecode_parsert:public parsert
135135
void parse_local_variable_type_table(methodt &method);
136136
optionalt<lambda_method_handlet>
137137
parse_method_handle(const class method_handle_infot &entry);
138+
void read_bootstrapmethods_entry(classt &);
138139

139140
void skip_bytes(std::size_t bytes)
140141
{
@@ -1619,117 +1620,7 @@ void java_bytecode_parsert::rclass_attribute(classt &parsed_class)
16191620

16201621
// mark as read in parsed class
16211622
parsed_class.attribute_bootstrapmethods_read = true;
1622-
u2 num_bootstrap_methods = read_u2();
1623-
for(size_t i = 0; i < num_bootstrap_methods; i++)
1624-
{
1625-
u2 bootstrap_methodhandle_ref = read_u2();
1626-
const pool_entryt &entry = pool_entry(bootstrap_methodhandle_ref);
1627-
1628-
method_handle_infot method_handle{entry};
1629-
1630-
u2 num_bootstrap_arguments = read_u2();
1631-
debug() << "INFO: parse BootstrapMethod handle "
1632-
<< num_bootstrap_arguments << " #args" << eom;
1633-
1634-
// try parsing bootstrap method handle
1635-
if(num_bootstrap_arguments >= 3)
1636-
{
1637-
// each entry contains a MethodHandle structure
1638-
// u2 tag
1639-
// u2 reference kind which must be in the range from 1 to 9
1640-
// u2 reference index into the constant pool
1641-
//
1642-
// reference kinds use the following
1643-
// 1 to 4 must point to a CONSTANT_Fieldref structure
1644-
// 5 or 8 must point to a CONSTANT_Methodref structure
1645-
// 6 or 7 must point to a CONSTANT_Methodref or
1646-
// CONSTANT_InterfaceMethodref structure, if the class file version
1647-
// number is 52.0 or above, to a CONSTANT_Methodref only in the case
1648-
// of less than 52.0
1649-
// 9 must point to a CONSTANT_InterfaceMethodref structure
1650-
1651-
// the index must point to a CONSTANT_String
1652-
// CONSTANT_Class
1653-
// CONSTANT_Integer
1654-
// CONSTANT_Long
1655-
// CONSTANT_Float
1656-
// CONSTANT_Double
1657-
// CONSTANT_MethodHandle
1658-
// CONSTANT_MethodType
1659-
1660-
// We read the three arguments here to see whether they correspond to
1661-
// our hypotheses for this being a lambda function entry.
1662-
1663-
u2 argument_index1 = read_u2();
1664-
u2 argument_index2 = read_u2();
1665-
u2 argument_index3 = read_u2();
1666-
1667-
// The additional arguments for the altmetafactory call are skipped,
1668-
// as they are currently not used. We verify though that they are of
1669-
// CONSTANT_Integer type, cases where this does not hold will be
1670-
// analyzed further.
1671-
bool recognized = true;
1672-
for(size_t i = 3; i < num_bootstrap_arguments; i++)
1673-
{
1674-
u2 skipped_argument = read_u2();
1675-
recognized |= pool_entry(skipped_argument).tag == CONSTANT_Integer;
1676-
}
1677-
if(!recognized)
1678-
{
1679-
debug() << "format of BootstrapMethods entry not recognized" << eom;
1680-
return;
1681-
}
1682-
1683-
const pool_entryt &interface_type_argument =
1684-
pool_entry(argument_index1);
1685-
const pool_entryt &method_handle_argument =
1686-
pool_entry(argument_index2);
1687-
const pool_entryt &method_type_argument = pool_entry(argument_index3);
1688-
1689-
if(
1690-
!(interface_type_argument.tag == CONSTANT_MethodType &&
1691-
method_handle_argument.tag == CONSTANT_MethodHandle &&
1692-
method_type_argument.tag == CONSTANT_MethodType))
1693-
return;
1694-
1695-
debug() << "INFO: parse lambda handle" << eom;
1696-
optionalt<lambda_method_handlet> lambda_method_handle =
1697-
parse_method_handle(method_handle_infot{method_handle_argument});
1698-
1699-
if(
1700-
lambda_method_handle.has_value() &&
1701-
lambda_method_handle->handle_type !=
1702-
method_handle_typet::LAMBDA_METHOD_HANDLE)
1703-
{
1704-
error() << "ERROR: could not parse lambda function method handle"
1705-
<< eom;
1706-
}
1707-
else
1708-
{
1709-
lambda_method_handle->interface_type =
1710-
pool_entry(interface_type_argument.ref1).s;
1711-
lambda_method_handle->method_type =
1712-
pool_entry(method_type_argument.ref1).s;
1713-
debug() << "lambda function reference "
1714-
<< id2string(lambda_method_handle->lambda_method_name)
1715-
<< " in class \"" << parsed_class.name << "\""
1716-
<< "\n interface type is "
1717-
<< id2string(pool_entry(interface_type_argument.ref1).s)
1718-
<< "\n method type is "
1719-
<< id2string(pool_entry(method_type_argument.ref1).s)
1720-
<< eom;
1721-
parsed_class.lambda_method_handle_map[{parsed_class.name, i}] =
1722-
*lambda_method_handle;
1723-
}
1724-
}
1725-
else
1726-
{
1727-
// skip bytes to align for next entry
1728-
for(size_t i = 0; i < num_bootstrap_arguments; i++)
1729-
read_u2();
1730-
error() << "ERROR: num_bootstrap_arguments must be at least 3" << eom;
1731-
}
1732-
}
1623+
read_bootstrapmethods_entry(parsed_class);
17331624
}
17341625
else
17351626
skip_bytes(attribute_length);
@@ -1903,3 +1794,119 @@ java_bytecode_parsert::parse_method_handle(const method_handle_infot &entry)
19031794

19041795
return {};
19051796
}
1797+
1798+
/// Read all entries of the `BootstrapMethods` attribute of a class file.
1799+
/// \param parsed_class: the class representation of the class file that is
1800+
/// currently parsed
1801+
void java_bytecode_parsert::read_bootstrapmethods_entry(
1802+
classt &parsed_class)
1803+
{
1804+
u2 num_bootstrap_methods = read_u2();
1805+
for(size_t i = 0; i < num_bootstrap_methods; i++)
1806+
{
1807+
u2 bootstrap_methodhandle_ref = read_u2();
1808+
const pool_entryt &entry = pool_entry(bootstrap_methodhandle_ref);
1809+
1810+
method_handle_infot method_handle{entry};
1811+
1812+
u2 num_bootstrap_arguments = read_u2();
1813+
debug() << "INFO: parse BootstrapMethod handle "
1814+
<< num_bootstrap_arguments << " #args" << eom;
1815+
1816+
// try parsing bootstrap method handle
1817+
if(num_bootstrap_arguments >= 3)
1818+
{
1819+
// each entry contains a MethodHandle structure
1820+
// u2 tag
1821+
// u2 reference kind which must be in the range from 1 to 9
1822+
// u2 reference index into the constant pool
1823+
//
1824+
// reference kinds use the following
1825+
// 1 to 4 must point to a CONSTANT_Fieldref structure
1826+
// 5 or 8 must point to a CONSTANT_Methodref structure
1827+
// 6 or 7 must point to a CONSTANT_Methodref or
1828+
// CONSTANT_InterfaceMethodref structure, if the class file version
1829+
// number is 52.0 or above, to a CONSTANT_Methodref only in the case
1830+
// of less than 52.0
1831+
// 9 must point to a CONSTANT_InterfaceMethodref structure
1832+
1833+
// the index must point to a CONSTANT_String
1834+
// CONSTANT_Class
1835+
// CONSTANT_Integer
1836+
// CONSTANT_Long
1837+
// CONSTANT_Float
1838+
// CONSTANT_Double
1839+
// CONSTANT_MethodHandle
1840+
// CONSTANT_MethodType
1841+
1842+
// We read the three arguments here to see whether they correspond to
1843+
// our hypotheses for this being a lambda function entry.
1844+
1845+
u2 argument_index1 = read_u2();
1846+
u2 argument_index2 = read_u2();
1847+
u2 argument_index3 = read_u2();
1848+
1849+
// The additional arguments for the altmetafactory call are skipped,
1850+
// as they are currently not used. We verify though that they are of
1851+
// CONSTANT_Integer type, cases where this does not hold will be
1852+
// analyzed further.
1853+
bool recognized = true;
1854+
for(size_t i = 3; i < num_bootstrap_arguments; i++)
1855+
{
1856+
u2 skipped_argument = read_u2();
1857+
recognized &= pool_entry(skipped_argument).tag == CONSTANT_Integer;
1858+
}
1859+
if(!recognized)
1860+
{
1861+
debug() << "format of BootstrapMethods entry not recognized" << eom;
1862+
return;
1863+
}
1864+
1865+
const pool_entryt &interface_type_argument = pool_entry(argument_index1);
1866+
const pool_entryt &method_handle_argument = pool_entry(argument_index2);
1867+
const pool_entryt &method_type_argument = pool_entry(argument_index3);
1868+
1869+
if(
1870+
!(interface_type_argument.tag == CONSTANT_MethodType &&
1871+
method_handle_argument.tag == CONSTANT_MethodHandle &&
1872+
method_type_argument.tag == CONSTANT_MethodType))
1873+
return;
1874+
1875+
debug() << "INFO: parse lambda handle" << eom;
1876+
optionalt<lambda_method_handlet> lambda_method_handle =
1877+
parse_method_handle(method_handle_infot{method_handle_argument});
1878+
1879+
if(
1880+
lambda_method_handle.has_value() &&
1881+
lambda_method_handle->handle_type !=
1882+
method_handle_typet::LAMBDA_METHOD_HANDLE)
1883+
{
1884+
error() << "ERROR: could not parse lambda function method handle"
1885+
<< eom;
1886+
}
1887+
else
1888+
{
1889+
lambda_method_handle->interface_type =
1890+
pool_entry(interface_type_argument.ref1).s;
1891+
lambda_method_handle->method_type =
1892+
pool_entry(method_type_argument.ref1).s;
1893+
debug() << "lambda function reference "
1894+
<< id2string(lambda_method_handle->lambda_method_name)
1895+
<< " in class \"" << parsed_class.name << "\""
1896+
<< "\n interface type is "
1897+
<< id2string(pool_entry(interface_type_argument.ref1).s)
1898+
<< "\n method type is "
1899+
<< id2string(pool_entry(method_type_argument.ref1).s) << eom;
1900+
parsed_class.lambda_method_handle_map[{parsed_class.name, i}] =
1901+
*lambda_method_handle;
1902+
}
1903+
}
1904+
else
1905+
{
1906+
// skip bytes to align for next entry
1907+
for(size_t i = 0; i < num_bootstrap_arguments; i++)
1908+
read_u2();
1909+
error() << "ERROR: num_bootstrap_arguments must be at least 3" << eom;
1910+
}
1911+
}
1912+
}

0 commit comments

Comments
 (0)