php / php/php-src

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

Offen
#22,214 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Bug Extension: opcache Status: Needs Triage
Vorherrschende Sprache
C
Sterne
40.4k
Forks
8.2k
Ø Merge
2 T. 13 Std.
Gemergte PRs (30 T.)
96

Beschreibung

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

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne in ext/opcache/zend_accelerator_util_funcs.c und vergleiche _zend_accel_function_hash_copy mit _zend_accel_class_hash_copy, wobei du dich darauf konzentrierst, wie ignore_dups behandelt wird. Füge einen .phpt-Test für doppelte Funktionen hinzu, bei dem opcache.dups_fix aktiviert ist, und überprüfe, dass Duplikate dort toleriert werden, während der Fall mit deaktivierter Direktive weiterhin den Fehler wegen erneuter Deklaration meldet.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
c, php
Bereich
backend
Issue-Typ
Bug
Schwierigkeit
3/5
Geschätzter Aufwand
1-2 Tage
Aktivitätsstatus
Ruhig
Klarheit
Klar beschrieben
Anfängerfreundlichkeit
78/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.