Skip to content

Commit 44b9f07

Browse files
author
Matthias Güdemann
committed
Refactor BootstrapMethods attribute reading into function
1 parent 0496cf6 commit 44b9f07

File tree

1 file changed

+118
-111
lines changed

1 file changed

+118
-111
lines changed

src/java_bytecode/java_bytecode_parser.cpp

Lines changed: 118 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ class java_bytecode_parsert:public parsert
136136
void parse_local_variable_type_table(methodt &method);
137137
optionalt<lambda_method_handlet>
138138
parse_method_handle(const class method_handle_infot &entry);
139+
void read_bootstrapmethods_entry(classt &);
139140

140141
void skip_bytes(std::size_t bytes)
141142
{
@@ -1595,117 +1596,7 @@ void java_bytecode_parsert::rclass_attribute(classt &parsed_class)
15951596

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

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

0 commit comments

Comments
 (0)