@@ -1091,12 +1091,10 @@ public function test_deep_nesting_fails_process_without_error() {
10911091 $ html = str_repeat ( '<i> ' , WP_HTML_Processor::MAX_BOOKMARKS * 2 );
10921092 $ processor = WP_HTML_Processor::create_fragment ( $ html );
10931093
1094- // The fragment parser starts with a few context tokens already bookmarked.
1095- $ reached_tokens = ( fn () => count ( $ this ->bookmarks ) )->call ( $ processor );
10961094 while ( $ processor ->next_token () ) {
1097- ++ $ reached_tokens ;
1095+ // Process tokens.
10981096 }
1099- $ this -> assertSame ( WP_HTML_Processor:: MAX_BOOKMARKS , $ reached_tokens );
1097+
11001098 $ this ->assertSame (
11011099 WP_HTML_Processor::ERROR_EXCEEDED_MAX_BOOKMARKS ,
11021100 $ processor ->get_last_error (),
@@ -1110,36 +1108,77 @@ public function test_deep_nesting_fails_process_without_error() {
11101108 * @expectedIncorrectUsage WP_HTML_Tag_Processor::set_bookmark
11111109 */
11121110 public function test_deep_nesting_fails_processing_virtual_tokens_without_error () {
1113- $ html = str_repeat ( '<table><td> ' , WP_HTML_Processor::MAX_BOOKMARKS * 2 );
1114- $ processor = WP_HTML_Processor::create_fragment ( $ html );
1115-
1116- // The fragment parser starts with a few context tokens already bookmarked.
1117- $ reached_tokens = ( fn () => count ( $ this ->bookmarks ) )->call ( $ processor );
1118- while ( $ processor ->next_token () ) {
1119- ++$ reached_tokens ;
1120- }
1121-
11221111 /*
11231112 * This test has some variability depending on how the virtual tokens align.
1124- * It will produce 1 real, 2 virtual, 1 real.
1113+ * In order to ensure that bookmarks are exhausted on a virtual token
1114+ * without throwing an error, 3 documents are parsed with different "offsets"
1115+ * to ensure that the bookmarks are exhaused on a virtual token in at least one of the runs.
11251116 *
11261117 * "<table><td><table><td>…" produces:
1127- * └─TABLE
1118+ * └─TABLE (real)
11281119 * └─TBODY (virtual)
11291120 * └─TR (virtual)
1130- * └─TD
1131- * └─TABLE
1121+ * └─TD (real)
1122+ * └─TABLE (real)
11321123 * └─TBODY (virtual)
11331124 * └─TR (virtual)
1134- * └─TD
1125+ * └─TD (real)
11351126 * └─…
11361127 */
1137- $ this ->assertGreaterThanOrEqual ( WP_HTML_Processor::MAX_BOOKMARKS - 1 , $ reached_tokens );
1138- $ this ->assertLessThanOrEqual ( WP_HTML_Processor::MAX_BOOKMARKS + 1 , $ reached_tokens );
1128+ $ html_table_td = str_repeat ( '<table><td> ' , WP_HTML_Processor::MAX_BOOKMARKS * 2 );
1129+
1130+ // Offset 0
1131+ $ processor = WP_HTML_Processor::create_fragment ( $ html_table_td );
1132+ while ( $ processor ->next_token () ) {
1133+ // Process tokens.
1134+ }
1135+ $ this ->assertSame (
1136+ WP_HTML_Processor::ERROR_EXCEEDED_MAX_BOOKMARKS ,
1137+ $ processor ->get_last_error (),
1138+ 'Failed to report exceeded-max-bookmarks error. '
1139+ );
1140+
1141+ // Offset 1
1142+ $ processor = WP_HTML_Processor::create_fragment ( "<div> {$ html_table_td }" );
1143+ while ( $ processor ->next_token () ) {
1144+ // Process tokens.
1145+ }
1146+ $ this ->assertSame (
1147+ WP_HTML_Processor::ERROR_EXCEEDED_MAX_BOOKMARKS ,
1148+ $ processor ->get_last_error (),
1149+ 'Failed to report exceeded-max-bookmarks error. '
1150+ );
1151+
1152+ // Offset 2
1153+ $ processor = WP_HTML_Processor::create_fragment ( "<div><div> {$ html_table_td }" );
1154+ while ( $ processor ->next_token () ) {
1155+ // Process tokens.
1156+ }
11391157 $ this ->assertSame (
11401158 WP_HTML_Processor::ERROR_EXCEEDED_MAX_BOOKMARKS ,
11411159 $ processor ->get_last_error (),
11421160 'Failed to report exceeded-max-bookmarks error. '
11431161 );
11441162 }
1163+
1164+ /**
1165+ * @ticket 64394
1166+ *
1167+ * @expectedIncorrectUsage WP_HTML_Tag_Processor::set_bookmark
1168+ */
1169+ public function test_prevents_unbounded_bookmarking () {
1170+ $ processor = WP_HTML_Processor::create_full_parser ( '<!DOCTYPE html><html> ' );
1171+ $ processor ->next_tag ();
1172+
1173+ // This might fail before the MAX_BOOKMARK limit, which is okay.
1174+ foreach ( range ( 0 , WP_HTML_Processor::MAX_BOOKMARKS ) as $ n ) {
1175+ if ( ! $ processor ->set_bookmark ( "{$ n }" ) ) {
1176+ break ;
1177+ }
1178+ }
1179+
1180+ $ this ->assertFalse (
1181+ $ processor ->set_bookmark ( 'beyond the limit ' )
1182+ );
1183+ }
11451184}
0 commit comments