From bdea1f302a80f6cb552a75618d06f37b00e1ea99 Mon Sep 17 00:00:00 2001 From: Dennis Snell <dennis.snell@automattic.com> Date: Thu, 15 Dec 2022 16:19:11 -0700 Subject: [PATCH] Tag Processor: Fix a problem backing up too far after updating HTML A defect introduced in #46018 led to the tag processor backing up one index too far after flushing its queued changes on a document. For most operations this didn't cause any harm because when immediately moving forward after an update, the `next_tag()` returned to the same spot: it was backing up to one position before the current tag instead of at the start of the current tag. Unfortunately, when the current tag was the first in the document this would lead the processor to rewind to position `-1`, right before the start of the document, and lead to errors with `strpos()` when it received out-of-bounds indices. In this fix we're correcting the adjustment for the HTML tag's `<` and documenting the math in the file so that it's clearer why it's there and providing guidance should another fix be necessary. Props to @anton-vlasenko for finding this bug. --- lib/experimental/html/class-wp-html-tag-processor.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/experimental/html/class-wp-html-tag-processor.php b/lib/experimental/html/class-wp-html-tag-processor.php index affbb6fb27b5c1..f21d52ddf810a5 100644 --- a/lib/experimental/html/class-wp-html-tag-processor.php +++ b/lib/experimental/html/class-wp-html-tag-processor.php @@ -1657,7 +1657,14 @@ public function get_updated_html() { $this->updated_bytes = strlen( $this->updated_html ); // 3. Point this tag processor at the original tag opener and consume it - $this->parsed_bytes = strlen( $updated_html_up_to_current_tag_name_end ) - $this->tag_name_length - 2; + + /* + * When we get here we're at the end of the tag name, and we want to rewind to before it + * <p>Previous HTML<em>More HTML</em></p> + * ^ | back up by the length of the tag name plus the opening < + * \<-/ back up by strlen("em") + 1 ==> 3 + */ + $this->parsed_bytes = strlen( $updated_html_up_to_current_tag_name_end ) - $this->tag_name_length - 1; $this->next_tag(); return $this->html;