opcache.dups_fix is honored for duplicate classes but not duplicate functions
Nadie ha tomado este issue todavía.
- Lenguaje dominante
- C
- Estrellas
- 40.4k
- Forks
- 8.1k
- Merge medio
- 2 d 13 h
- PR fusionados (30 d)
- 96
Descripción
Description
opcache.dups_fix is documented as a fix for "Cannot redeclare" errors, but it only covers classes, not functions.
Inside opcache the directive is read in the table-copy that installs a cached script's symbols (ext/opcache/zend_accelerator_util_funcs.c). The class-table copy honors it — when ignore_dups is set it keeps the existing class and skips the duplicate:
/* _zend_accel_class_hash_copy */
} else if (UNEXPECTED(!ZCG(accel_directives).ignore_dups)) {
...
zend_class_redeclaration_error(E_ERROR, Z_PTR_P(t));
return;
}
continue; /* ignore_dups: keep the first definition */
The function-table copy right next to it doesn't check the directive at all — it goes straight to the fatal:
/* _zend_accel_function_hash_copy */
t = zend_hash_find_known_hash(target, p->key);
if (UNEXPECTED(t != NULL)) {
goto failure; /* -> "Cannot redeclare function ..." regardless of opcache.dups_fix */
}
So with opcache.dups_fix=1 a duplicate class is tolerated (first wins) but a duplicate function still fatals. The directive name and docs don't distinguish between the two, so this reads like an oversight rather than something intentional.
Where it bites
Long-running application servers that re-execute require_once'd files per request (we ran into this building ZealPHP, an OpenSwoole-based runtime). opcache re-installs a cached script's symbols into a table that already has them; dups_fix covers the class collision, but the function collision still kills the request with "Cannot redeclare function". So dups_fix only half-solves it for these setups — WordPress for example gets past its class redeclares with dups_fix=1 but then dies on the first function (_wp_can_use_pcre_u in wp-includes/compat.php).
Suggested fix
Make the function copy consistent with the class copy:
t = zend_hash_find_known_hash(target, p->key);
if (UNEXPECTED(t != NULL)) {
- goto failure;
+ /* Honor opcache.dups_fix for functions too — the class-table
+ * copy above already does. Keep the first-declared function. */
+ if (!ZCG(accel_directives).ignore_dups) {
+ goto failure;
+ }
+ continue;
}
I've tested this against 8.4 and it does the job (WordPress runs clean under opcache + a per-request re-execution model with it). Happy to open a PR with a .phpt if the asymmetry is agreed to be unintended — mostly wanted to check whether it's deliberate before sending one.
PHP Version
PHP 8.4 (the code is the same on master)
Operating System
Linux
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Línea de trabajo
Empieza en ext/opcache/zend_accelerator_util_funcs.c y compara _zend_accel_function_hash_copy con _zend_accel_class_hash_copy, centrándote en cómo se gestiona ignore_dups. Añade una prueba .phpt para funciones duplicadas con opcache.dups_fix habilitado y verifica que allí se toleran los duplicados, mientras que el caso con la directiva deshabilitada sigue informando del error de redeclaración.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- c, php
- Área
- backend
- Tipo de issue
- Error
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Estado de actividad
- Tranquilo
- Claridad
- Bien especificado
- Aptitud para principiantes
- 78/100