Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

ext/mbstring: mb_regex_substitute() reads past the replacement string's end on a truncated trailing multibyte lead byte

Cerrado Apto para principiantes
#24,769 3 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
2/5
Tiempo estimado
1-3 horas
Aptitud para principiantes
74/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
c
Área
backend, security

Línea de trabajo

Lee ext/mbstring/php_mbregex.c e inspecciona el bucle principal de mb_regex_substitute() junto con las llamadas cercanas con límite. Empieza ejecutando el reproductor proporcionado de mb_ereg_replace() y después revisa los tests pertinentes de mbstring para comprobar la cobertura. El trabajo está hecho cuando el byte multibyte final truncado se copia solo hasta el final de la cadena de reemplazo y el reproductor devuelve el resultado esperado de 2 bytes.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

Description

509e27bae1 (GH-23499, fixed August 2026) corrected two places in mb_regex_substitute() (ext/mbstring/php_mbregex.c, the replacement-string interpolation behind mb_ereg_replace()/mb_eregi_replace()) where php_mb_mbchar_bytes()'s claimed character width was used to advance a pointer without checking it against the buffer's actual remaining length -- both were clamped to MIN(p + clen, eos). f6852befa3 (GH-24498, fixed October 2026) separately fixed the same bug class in a different file, php_mb_rfc1867_getword().

Neither fix touched the first php_mb_mbchar_bytes() call in mb_regex_substitute()'s main loop -- the check that runs on every character, before any backslash/backref handling, to decide whether it's an ordinary character or the start of a backreference:

while (p < eos) {
	...
	clen = (int) php_mb_mbchar_bytes(p, enc);
	if (clen != 1 || p == eos || p[0] != '\\') {
		/* skip anything that's not an ascii backslash */
		smart_str_appendl(pbuf, p, clen);
		p += clen;
		continue;
	}

If the character at p is not a backslash, and its lead byte (looked up in the current mbregex encoding's mblen_table) claims a width of 2-4 bytes but fewer than clen - 1 bytes actually remain before eos, smart_str_appendl(pbuf, p, clen) copies clen bytes starting at p regardless -- reading past the replacement string's real content. This is the identical shape as the two already-fixed call sites a few lines later in the same function, which use MIN(p + clen, eos) instead.

Minimal reproducer:

<?php
mb_regex_encoding('UTF-8');
$replacement = "x" . "\xF0"; // ends in a UTF-8 4-byte lead byte with 0 continuation bytes present
var_dump(mb_ereg_replace('a', $replacement, 'a'));

Resulted in this output:

string(5) "x..."

(5 bytes: the input is only 2 bytes, but php_mb_mbchar_bytes() claims the trailing \xF0 byte is a 4-byte character, so 4 bytes get copied starting from it -- 3 of them past the replacement string's actual end.)

But I expected this output instead: a 2-byte result ("x\xF0"), i.e. the same MIN(p + clen, eos)-style clamping already applied to the other two call sites in this function.

This was repeatable across 20 differently-sized/content inputs ending the same way -- always exactly claimed_width - 1 extra bytes beyond the logical input length. In shorter variants the extra bytes were non-zero, unpredictable content rather than a fixed pattern, consistent with genuine adjacent heap memory being copied into the return value.

Suggested fix: apply the same clamp already used nearby in the same function:

clen = (int) php_mb_mbchar_bytes(p, enc);
if (clen != 1 || p == eos || p[0] != '\\') {
	size_t avail = MIN((size_t) clen, (size_t) (eos - p));
	smart_str_appendl(pbuf, p, avail);
	p += avail;
	continue;
}

Confirmed present, unmodified, on PHP-8.3, PHP-8.4, and PHP-8.5, and master.

PHP Version
PHP 8.7.0-dev (cli) (built: Oct 26 2026 09:57:01) (NTS DEBUG)
Copyright © The PHP Group and Contributors
Zend Engine v4.7.0-dev, Copyright © Zend by Perforce
    with Zend OPcache v8.7.0-dev, Copyright ©, by Zend by Perforce

Also confirmed present on the PHP-8.3, PHP-8.4, and PHP-8.5 branches via direct content check.

Operating System

Ubuntu 24.04 (Docker), but this is pure string-handling logic, not OS-specific.

Lenguaje dominante
C
Estrellas
41.7k
Forks
8.5k
Merge medio
2 d 10 h
PR fusionados (30 d)
158

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de php/php-src

Todos los issues de php/php-src

Issues similares

Más issues de C

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.