diff --git a/src/wp-includes/html-api/class-wp-html-tag-processor.php b/src/wp-includes/html-api/class-wp-html-tag-processor.php
index 17b3f400fcea6..f66b759faeec6 100644
--- a/src/wp-includes/html-api/class-wp-html-tag-processor.php
+++ b/src/wp-includes/html-api/class-wp-html-tag-processor.php
@@ -1113,7 +1113,7 @@ private function parse_next_tag() {
$this->token_starts_at = $at;
- if ( '/' === $this->html[ $at + 1 ] ) {
+ if ( $doc_length > $at + 1 && '/' === $this->html[ $at + 1 ] ) {
$this->is_closing_tag = true;
++$at;
} else {
@@ -1147,7 +1147,7 @@ private function parse_next_tag() {
* Abort if no tag is found before the end of
* the document. There is nothing left to parse.
*/
- if ( $at + 1 >= strlen( $html ) ) {
+ if ( $at + 1 >= $doc_length ) {
return false;
}
@@ -1161,13 +1161,13 @@ private function parse_next_tag() {
* https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state
*/
if (
- strlen( $html ) > $at + 3 &&
+ $doc_length > $at + 3 &&
'-' === $html[ $at + 2 ] &&
'-' === $html[ $at + 3 ]
) {
$closer_at = $at + 4;
// If it's not possible to close the comment then there is nothing more to scan.
- if ( strlen( $html ) <= $closer_at ) {
+ if ( $doc_length <= $closer_at ) {
return false;
}
@@ -1185,18 +1185,18 @@ private function parse_next_tag() {
* See https://html.spec.whatwg.org/#parse-error-incorrectly-closed-comment
*/
--$closer_at; // Pre-increment inside condition below reduces risk of accidental infinite looping.
- while ( ++$closer_at < strlen( $html ) ) {
+ while ( ++$closer_at < $doc_length ) {
$closer_at = strpos( $html, '--', $closer_at );
if ( false === $closer_at ) {
return false;
}
- if ( $closer_at + 2 < strlen( $html ) && '>' === $html[ $closer_at + 2 ] ) {
+ if ( $closer_at + 2 < $doc_length && '>' === $html[ $closer_at + 2 ] ) {
$at = $closer_at + 3;
continue 2;
}
- if ( $closer_at + 3 < strlen( $html ) && '!' === $html[ $closer_at + 2 ] && '>' === $html[ $closer_at + 3 ] ) {
+ if ( $closer_at + 3 < $doc_length && '!' === $html[ $closer_at + 2 ] && '>' === $html[ $closer_at + 3 ] ) {
$at = $closer_at + 4;
continue 2;
}
@@ -1209,7 +1209,7 @@ private function parse_next_tag() {
* https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state
*/
if (
- strlen( $html ) > $at + 8 &&
+ $doc_length > $at + 8 &&
'[' === $html[ $at + 2 ] &&
'C' === $html[ $at + 3 ] &&
'D' === $html[ $at + 4 ] &&
@@ -1233,7 +1233,7 @@ private function parse_next_tag() {
* https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state
*/
if (
- strlen( $html ) > $at + 8 &&
+ $doc_length > $at + 8 &&
( 'D' === $html[ $at + 2 ] || 'd' === $html[ $at + 2 ] ) &&
( 'O' === $html[ $at + 3 ] || 'o' === $html[ $at + 3 ] ) &&
( 'C' === $html[ $at + 4 ] || 'c' === $html[ $at + 4 ] ) &&
@@ -1290,6 +1290,11 @@ private function parse_next_tag() {
* See https://html.spec.whatwg.org/#parse-error-invalid-first-character-of-tag-name
*/
if ( $this->is_closing_tag ) {
+ // No chance of finding a closer
+ if ( $at + 3 > $doc_length ) {
+ return false;
+ }
+
$closer_at = strpos( $html, '>', $at + 3 );
if ( false === $closer_at ) {
return false;
diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php
index 4469f90c4f276..58aa7dcb60670 100644
--- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php
+++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php
@@ -2428,6 +2428,24 @@ public function test_updating_attributes_in_malformed_html( $html, $expected ) {
);
}
+ /**
+ * @covers WP_HTML_Tag_Processor::next_tag
+ */
+ public function test_handles_malformed_taglike_open_short_html() {
+ $p = new WP_HTML_Tag_Processor( '<' );
+ $result = $p->next_tag();
+ $this->assertFalse( $result, 'Did not handle "<" html properly.' );
+ }
+
+ /**
+ * @covers WP_HTML_Tag_Processor::next_tag
+ */
+ public function test_handles_malformed_taglike_close_short_html() {
+ $p = new WP_HTML_Tag_Processor( ' ' );
+ $result = $p->next_tag();
+ $this->assertFalse( $result, 'Did not handle " " html properly.' );
+ }
+
/**
* Data provider.
*