php / php/php-src

opcache.dups_fix is honored for duplicate classes but not duplicate functions

Ouverte
#22,214 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Bug Extension: opcache Status: Needs Triage
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

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. 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

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.