@@ -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