opcache.dups_fix is honored for duplicate classes but not duplicate functions
Personne n'a encore pris cette issue.
- Langage dominant
- C
- Étoiles
- 40.4k
- Forks
- 8.1k
- Merge moyen
- 2 j 13 h
- PR mergées (30 j)
- 96
Description
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
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
Commencez dans ext/opcache/zend_accelerator_util_funcs.c et comparez _zend_accel_function_hash_copy à _zend_accel_class_hash_copy, en vous concentrant sur la manière dont ignore_dups est géré. Ajoutez un test .phpt pour les fonctions dupliquées avec opcache.dups_fix activé et vérifiez que les doublons y sont tolérés, tandis que le cas où la directive est désactivée signale toujours l’erreur de redéclaration.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- c, php
- Domaine
- backend
- Type d'issue
- Bug
- Difficulté
- 3/5
- Temps estimé
- 1-2 jours
- Activité
- Calme
- Clarté
- Clairement spécifiée
- Accessibilité débutants
- 78/100