From 57e024a15760bd0721a4a97fdd8986a802f58132 Mon Sep 17 00:00:00 2001
From: Sergey Biryukov <sergeybiryukov.ru@gmail.com>
Date: Sat, 14 Dec 2024 23:53:24 +0000
Subject: [PATCH] Formatting: Check the result of `preg_split()` in
 `convert_smilies()`.

This aims to avoid a fatal error from `count()` when `preg_split()` fails on large input.

Includes:
* Optimizing the regular expression used to split the input by tags to avoid unlimited backtracking for better performance.
* Adjusting the function logic for better readability.

Follow-up to [340], [4380], [26191].

Props podpirate, nathkrill, rajinsharwar, dmsnell, bjorsch, q0rban, audrasjb, rupw, Ov3rfly, jorbin, nhrrob, chaion07, mcqueen22, azaozz, narenin, roybellingan, SergeyBiryukov.
See #51019.
Built from https://develop.svn.wordpress.org/trunk@59515


git-svn-id: http://core.svn.wordpress.org/trunk@58901 1a063a9b-81f0-0310-95a4-ce76da25c4cd
---
 wp-includes/formatting.php | 71 +++++++++++++++++++++-----------------
 wp-includes/version.php    |  2 +-
 2 files changed, 41 insertions(+), 32 deletions(-)

diff --git a/wp-includes/formatting.php b/wp-includes/formatting.php
index b579bcd324..3ecc352528 100644
--- a/wp-includes/formatting.php
+++ b/wp-includes/formatting.php
@@ -3473,40 +3473,49 @@ function translate_smiley( $matches ) {
  */
 function convert_smilies( $text ) {
 	global $wp_smiliessearch;
-	$output = '';
-	if ( get_option( 'use_smilies' ) && ! empty( $wp_smiliessearch ) ) {
-		// HTML loop taken from texturize function, could possible be consolidated.
-		$textarr = preg_split( '/(<.*>)/U', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // Capture the tags as well as in between.
-		$stop    = count( $textarr ); // Loop stuff.
 
-		// Ignore processing of specific tags.
-		$tags_to_ignore       = 'code|pre|style|script|textarea';
-		$ignore_block_element = '';
-
-		for ( $i = 0; $i < $stop; $i++ ) {
-			$content = $textarr[ $i ];
-
-			// If we're in an ignore block, wait until we find its closing tag.
-			if ( '' === $ignore_block_element && preg_match( '/^<(' . $tags_to_ignore . ')[^>]*>/', $content, $matches ) ) {
-				$ignore_block_element = $matches[1];
-			}
-
-			// If it's not a tag and not in ignore block.
-			if ( '' === $ignore_block_element && strlen( $content ) > 0 && '<' !== $content[0] ) {
-				$content = preg_replace_callback( $wp_smiliessearch, 'translate_smiley', $content );
-			}
-
-			// Did we exit ignore block?
-			if ( '' !== $ignore_block_element && '</' . $ignore_block_element . '>' === $content ) {
-				$ignore_block_element = '';
-			}
-
-			$output .= $content;
-		}
-	} else {
+	if ( ! get_option( 'use_smilies' ) || empty( $wp_smiliessearch ) ) {
 		// Return default text.
-		$output = $text;
+		return $text;
 	}
+
+	// HTML loop taken from texturize function, could possible be consolidated.
+	$textarr = preg_split( '/(<[^>]*>)/U', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // Capture the tags as well as in between.
+
+	if ( false === $textarr ) {
+		// Return default text.
+		return $text;
+	}
+
+	// Loop stuff.
+	$stop   = count( $textarr );
+	$output = '';
+
+	// Ignore processing of specific tags.
+	$tags_to_ignore       = 'code|pre|style|script|textarea';
+	$ignore_block_element = '';
+
+	for ( $i = 0; $i < $stop; $i++ ) {
+		$content = $textarr[ $i ];
+
+		// If we're in an ignore block, wait until we find its closing tag.
+		if ( '' === $ignore_block_element && preg_match( '/^<(' . $tags_to_ignore . ')[^>]*>/', $content, $matches ) ) {
+			$ignore_block_element = $matches[1];
+		}
+
+		// If it's not a tag and not in ignore block.
+		if ( '' === $ignore_block_element && strlen( $content ) > 0 && '<' !== $content[0] ) {
+			$content = preg_replace_callback( $wp_smiliessearch, 'translate_smiley', $content );
+		}
+
+		// Did we exit ignore block?
+		if ( '' !== $ignore_block_element && '</' . $ignore_block_element . '>' === $content ) {
+			$ignore_block_element = '';
+		}
+
+		$output .= $content;
+	}
+
 	return $output;
 }
 
diff --git a/wp-includes/version.php b/wp-includes/version.php
index c8beddbf30..391edd9fe4 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
  *
  * @global string $wp_version
  */
-$wp_version = '6.8-alpha-59514';
+$wp_version = '6.8-alpha-59515';
 
 /**
  * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.