PHP-Sicherheitsupdate: JIT-Rechenfehler in PHP 8.5/8.4/8.3 gefixt

PHP-Sicherheitsupdate: JIT-Rechenfehler in PHP 8.5/8.4/8.3 gefixt

Ein unsichtbarer Rechenfehler im JIT-Compiler sorgt derzeit für falsche Ergebnisse bei Additionen und Multiplikationen, ohne Fehlermeldungen zu hinterlassen. Besonders für Shopware- und Symfony-Projekte stellt dieser Bug ein massives Risiko für Preisberechnungen und die Buchhaltung dar. Installieren Sie umgehend die neuen PHP-Releases 8.5.5, 8.4.20 oder 8.3.30, um Ihre produktiven Systeme abzusichern.

Dennis Schwenker-Sanders 9 Min. Lesezeit

JIT rechnet falsch: Warum Sie PHP 8.5.5, 8.4.20 oder 8.3.30 sofort einspielen sollten

Stellen Sie sich vor, Ihr Shopware-Shop berechnet Rabatte falsch. Nicht weil jemand einen Fehler im Code gemacht hat, sondern weil PHP selbst falsche Ergebnisse liefert. Keine Fehlermeldung, kein Warning, keine Exception. Die Berechnung läuft durch, das Ergebnis ist falsch, und niemand bemerkt es, bis ein Kunde sich beschwert oder die Buchhaltung nicht aufgeht.

Genau das konnte passieren. Am 9. April 2026 erschienen parallel drei PHP-Releases: 8.5.5, 8.4.20 und 8.3.30. Der kritischste Fix betrifft GH-20838: "JIT compiler produces wrong arithmetic results". Der JIT-Compiler hat unter bestimmten Bedingungen falsche Ergebnisse bei Addition, Subtraktion und Multiplikation geliefert. Still. Ohne sichtbaren Fehler.

Wer JIT in Produktion einsetzt (was bei Symfony- und Shopware-Projekten eine gängige Performance-Optimierung ist), muss zeitnah upgraden. PHP 8.4 ist der Standard-Default vieler deutscher Hoster wie Mittwald und Hetzner. PHP 8.3 befindet sich bereits im Security-Only-Mode. Und PHP 8.5 ist die aktuelle Active-Support-Version.

Als PHP-Entwickler mit Fokus auf E-Commerce und Symfony-Projekte ist das für mich der Worst-Case-Bug: Ein Fehler, der keine Spuren hinterlässt, bis der Schaden da ist. Falsche Preisberechnungen, falsche Steuersätze, falsche Rabattierungen. In einem Shopware-Shop kann das nicht nur Kundenvertrauen kosten, sondern steuer- und wettbewerbsrechtlich relevant werden.

Was genau gefixt wurde

Der JIT-Arithmetik-Bug (GH-20838)

Der Bug betrifft den JIT-Tracing-Compiler in der Einstellung opcache.jit=1255 (oder vergleichbaren Tracing-Modi). Konkret: Wenn der JIT-Compiler eine Berechnung mit Operanden kompiliert, die aus einem polymorphen Kontext kommen (etwa aus JSON-dekodierten Daten oder Datenbank-Abfragen), fehlten Type Guards auf den Bailout-Pfaden für ADD, SUB und MUL Operationen. Der JIT-Compiler hat den Typ der Operanden angenommen, ohne ihn zu verifizieren.

Das Ergebnis: In seltenen Fällen, wenn ein Operand den Typ IS_UNDEF oder einen nicht-numerischen Typ hatte, hat der JIT-kompilierte Code trotzdem die schnelle numerische Berechnung ausgeführt, mit dem falschen Wert. Nicht immer. Nicht bei jeder Berechnung. Nur wenn bestimmte Trace-Bedingungen zusammenkommen.

Der Fix von Dmitry Stogov und Ilia Alshanetsky fügt CHECK_OP1_TRACE_TYPE und CHECK_OP2_TRACE_TYPE Guards ein, die sicherstellen, dass die Operanden tatsächlich IS_LONG oder IS_DOUBLE sind, bevor der numerische Fast-Path genutzt wird.

# PHP-Version und JIT-Status prüfen
$ php -v
$ php -r "var_dump(opcache_get_status()['jit']);"

# Betroffene JIT-Konfigurationen:
# opcache.jit=1255 (Tracing JIT, volle Optimierung)
# opcache.jit=1254 (Tracing JIT, moderate Optimierung)
# opcache.jit=tracing (Alias für 1255 seit PHP 8.5)

# NICHT betroffen:
# opcache.jit=1251 (Function JIT)
# opcache.jit=0 (JIT deaktiviert)
# opcache.jit=off

Weitere JIT-Bugs in derselben Release-Welle

GH-20838 ist nicht der einzige JIT-Fix. Zwei weitere Bugs unterstreichen, dass der JIT-Compiler in den letzten Versionen instabil war:

GH-21267 (Tracing Infinite Loop): Ein FETCH_OBJ_R-Opcode mit einer IS_UNDEF Property in einem polymorphen Kontext konnte den Tracing-JIT in eine Endlosschleife schicken. Kein Absturz, keine Exception, nur 100% CPU und ein nicht mehr reagierender PHP-Prozess. In einem Web-Server-Kontext: Ein einzelner Request blockiert einen Worker dauerhaft.

GH-21395 (Use-After-Free): Ein Use-After-Free im JIT, der theoretisch zu Speicherzugriffsverletzungen und Crashes führen kann. In der Praxis: Segfaults unter Last, die schwer reproduzierbar und noch schwerer zu debuggen sind.

Alle drei Bugs betreffen den Tracing-JIT. Wer den Function-JIT (opcache.jit=1251) oder keinen JIT einsetzt, ist nicht betroffen. Aber: Die meisten Performance-Guides empfehlen den Tracing-JIT, weil er die höchsten Performance-Gewinne bringt. Und genau der war fehlerhaft.

Ist Ihr Server betroffen?

Die entscheidende Frage für Ihr Projekt ist: Läuft JIT in Ihrer Produktion? Und wenn ja, in welchem Modus?

Was viele unterschätzen: Viele Managed-Hosting-Provider aktivieren OPcache inklusive JIT automatisch. Bei Mittwald ist JIT standardmäßig aktiv. Bei Hetzner Cloud-Servern hängt es von der PHP-Konfiguration ab, die bei der Einrichtung gewählt wurde. Bei IONOS und Strato ist JIT meist deaktiviert, weil die Shared-Hosting-Umgebungen die zusätzliche Speicherbelastung vermeiden. Bei Root-Servern und VPS-Installationen ist die Konfiguration komplett in der Hand des Administrators.

Aus meiner Erfahrung mit Symfony-Projekten: Das Risiko-Profil hängt stark vom Applikationstyp ab. Am stärksten betroffen sind E-Commerce-Shops (Shopware, WooCommerce, Custom Symfony Shops), die Preise, Rabatte und Steuern dynamisch berechnen. Werte aus der Datenbank oder aus API-Responses werden in arithmetischen Ausdrücken verwendet, genau das Muster, das den Bug triggert. ERP-Integrationen, die Bestelldaten transformieren, sind ebenfalls betroffen. Content-Websites und Blog-Systeme haben ein geringeres Risiko, weil sie weniger arithmetische Operationen auf dynamischen Daten ausführen.

Ein häufiger Fehler, den ich in Audits sehe: Teams wissen nicht, ob JIT aktiv ist. Die php.ini wird einmal bei der Server-Einrichtung konfiguriert und dann vergessen. Ein einfacher Check:

# In einer PHP-Datei auf dem Server:
<?php
$status = opcache_get_status();
echo 'JIT aktiv: ' . ($status['jit']['enabled'] ? 'JA' : 'NEIN') . PHP_EOL;
echo 'JIT Modus: ' . ($status['jit']['opt_level'] ?? 'n/a') . PHP_EOL;
echo 'PHP Version: ' . phpversion() . PHP_EOL;

# Oder per CLI:
$ php -r "print_r(opcache_get_status()['jit']);"

Wenn die Antwort "JIT aktiv: JA" ist und Ihre PHP-Version älter als 8.5.5, 8.4.20 oder 8.3.30 ist: Upgraden Sie. Heute. Nicht nächste Woche.

Deep-Dive: Warum dieser Bug so tückisch ist

Warum erzeugt der Bug keine Fehlermeldung?

Was auf den ersten Blick einfach wirkt (ein Arithmetik-Bug, den man doch in Tests fangen müsste), hat in Production Implikationen, die das ganze Problem verschärfen. Der Bug tritt nur im Tracing-JIT auf. Das bedeutet: Er tritt erst nach vielen Durchläufen derselben Code-Stelle auf, wenn der JIT-Compiler den Code als "hot" klassifiziert und eine optimierte Trace-Version erstellt. In Unit-Tests, die jeden Test isoliert ausführen, wird der Code nie "hot".

Das erklärt, warum der Bug seit Januar 2026 offen war (GH-20838 wurde am 5. Januar gemeldet) und erst im April gefixt wurde: Er war schwer reproduzierbar. Der Melder hat es mit einer komplexen JSON-basierten Berechnung demonstriert, bei der Werte aus JSON-dekodierten Arrays in arithmetischen Ausdrücken verwendet werden. Genau das Muster, das in E-Commerce-Anwendungen überall vorkommt: Preise aus der Datenbank, Rabattsätze aus Konfigurationen, Steuersätze aus externen Quellen.

In der Praxis scheitert das oft an der Testabdeckung. Unit-Tests mit festcodierten Werten reproduzieren den Bug nicht, weil der JIT-Compiler die Typen korrekt inferiert. Nur wenn die Werte aus externen Quellen kommen (JSON, Datenbank, API-Response) und der polymorphe Kontext den JIT-Compiler in die Irre führt, treten die falschen Ergebnisse auf.

Wie ich im Artikel zu PHP 8.6 beschrieben habe, werden die PHP-Runtime-Features immer komplexer. Native Lazy Objects, Property Hooks, Pipe Operator. Der JIT-Compiler muss diese Features korrekt kompilieren, und die Komplexität steigt mit jedem Release. GH-20838 ist ein Symptom dieser wachsenden Komplexität.

Die JIT-Konfiguration Ihres Servers erfordert eine Analyse, die über php.ini-Einstellungen hinausgeht. → Server-Audit anfragen

Weitere Fixes in der Release-Welle

Welche Bugs sind außerhalb des JIT relevant?

Neben den drei JIT-Bugs bringen die Releases weitere Fixes, die für Web-Applikationen relevant sind:

PCRE Re-Entrancy (alle Versionen): Ein Re-Entrancy-Problem in den PCRE-Funktionen (preg_match, preg_replace, preg_split, preg_grep) wurde gefixt. Das betrifft Szenarien, in denen Regex-Funktionen aus Callbacks heraus erneut aufgerufen werden. In Symfony-Projekten kommt das bei Custom Validators, Twig-Extensions und Event-Listenern vor.

FFI Resource Leak (alle Versionen): Ein Resource-Leak in FFI::cdef() bei Symbol-Resolution-Failures. Betrifft Projekte, die FFI für C-Library-Anbindungen nutzen (etwa für Bildverarbeitung oder Kryptographie-Operationen).

Cookie-Parsing-Bug (alle Versionen): Ein Offset-Fehler beim Parsen von Set-Cookie-Attributen in der SOAP-Extension. Betrifft SOAP-basierte API-Integrationen, die Session-Cookies verwenden.

SplHeap Write-Lock (alle Versionen): Eine fehlende Write-Lock-Validierung in SplHeap, die zu Race Conditions in Multi-Thread-Szenarien führen konnte.

Phar Use-After-Free (nur PHP 8.5): Ein Use-After-Free beim Unlinking von Einträgen während der Iteration über ein komprimiertes Phar-Archiv. Betrifft Deployment-Tools und Build-Pipelines, die mit Phar-Archiven arbeiten.

Strategische Empfehlungen

Welches Update brauchen Sie?

PHP 8.5 (Active Support): Update auf 8.5.5. Enthält alle Fixes plus PHP 8.5-spezifische Korrekturen (Phar, Signal-Handler). Empfohlen für neue Projekte und Projekte, die bereits auf 8.5 laufen.

PHP 8.4 (Active Support): Update auf 8.4.20. Die wichtigste Version für die meisten deutschen Managed-Hosting-Umgebungen. Wie ich im KW16-Artikel geschrieben habe, ist PHP 8.4 Voraussetzung für Symfony UX 3.0 und Doctrine ORM 4.0. Ein Update auf 8.4.20 ist der natürliche erste Schritt.

PHP 8.3 (Security-Only): Update auf 8.3.30. PHP 8.3 erhält nur noch Security-Fixes. Dass der JIT-Bug auch hier gebackported wurde, zeigt die Schwere des Problems. Aber langfristig: Planen Sie das PHP-8.4-Upgrade.

JIT deaktivieren oder upgraden?

Die schnellste Sofortmaßnahme ist, den Tracing-JIT zu deaktivieren (opcache.jit=0). Das eliminiert das Risiko sofort, kostet aber Performance. Für die meisten Symfony- und Shopware-Projekte liegt der JIT-Performance-Gewinn bei 5-15% für CPU-intensive Operationen (Routing, Serialisierung, Template-Rendering).

Meine Empfehlung: Upgraden statt deaktivieren. Die PHP-Updates sind reine Bugfix-Releases ohne Breaking Changes. Ein apt update && apt upgrade (Debian/Ubuntu) oder das Managed-Hosting-Panel ist in den meisten Fällen ausreichend. Testen Sie danach einen Full-Durchlauf Ihrer Applikation (besonders Bestell-Prozesse und Preisberechnungen bei Shops).

Für Projekte, die ein Upgrade nicht sofort durchführen können (festgefrorene Server-Versionen, Compliance-Anforderungen, Freigabe-Prozesse): Deaktivieren Sie den Tracing-JIT und wechseln Sie auf den Function-JIT (opcache.jit=1251). Der Function-JIT ist nicht betroffen und liefert immer noch einen Teil des Performance-Vorteils. Das ist ein guter Kompromiss für die Übergangszeit.

# Sofortmaßnahme: Tracing-JIT deaktivieren
# In php.ini:
opcache.jit=0

# Alternativ: Function-JIT statt Tracing-JIT
opcache.jit=1251

# Empfohlen: Update + Tracing-JIT beibehalten
# Debian/Ubuntu:
$ sudo apt update && sudo apt upgrade php8.4-opcache

# Nach dem Update: Verify
$ php -r "echo phpversion();" 
# Sollte 8.4.20, 8.5.5 oder 8.3.30 zeigen

Was sollten Sie nach dem Update testen?

Nach dem PHP-Update empfehle ich einen gezielten Smoke-Test der kritischen Berechnungen in Ihrer Applikation. Für Shopware-Shops: Legen Sie eine Testbestellung mit Rabattcodes, gestaffelten Preisen und verschiedenen Steuersätzen an. Prüfen Sie, ob die Summen korrekt sind. Für Symfony-Applikationen: Führen Sie Ihre Test-Suite aus und achten Sie besonders auf Tests, die mit Gleitkomma-Arithmetik arbeiten.

Ein Punkt, der in der Diskussion untergeht: Wenn Sie vor dem Update bereits falsche Berechnungen hatten (und das nicht bemerkt haben), hilft das Update allein nicht. Die bereits falschen Daten (Bestellungen, Rechnungen) bleiben falsch. Ein nachträglicher Datenabgleich für den betroffenen Zeitraum ist dann notwendig. Das ist aufwändig, aber bei steuerrelevanten Daten unvermeidbar.

Ob Ihre Server-Konfiguration optimal ist, hängt von Ihrem Hosting-Setup und Ihrem Applikationsprofil ab. → Lassen Sie uns das gemeinsam evaluieren

Zusammenfassung und Ausblick

Die PHP-Bugfix-Welle vom 9. April 2026 behebt kritische JIT-Compiler-Fehler, die stille Datenkorruption verursachen konnten. Die wichtigsten Takeaways:

GH-20838 ist geschäftskritisch: Der JIT-Compiler hat unter bestimmten Bedingungen falsche Arithmetik-Ergebnisse geliefert. Ohne Fehlermeldung, ohne Warning. Besonders gefährlich für Preis- und Steuerberechnungen in E-Commerce-Anwendungen.

Nur der Tracing-JIT ist betroffen (opcache.jit=1255 oder tracing). Function-JIT und kein JIT sind nicht betroffen. Aber die meisten Performance-optimierten Setups nutzen den Tracing-JIT.

Alle drei aktiven PHP-Branches sind betroffen und gepatcht: 8.5.5, 8.4.20, 8.3.30. Ein Update ist ohne Breaking Changes möglich.

Sofortmaßnahme: Prüfen Sie, ob JIT auf Ihren Servern aktiv ist. Wenn ja: Upgraden. Wenn ein Upgrade nicht sofort möglich ist: JIT temporär deaktivieren.

Langfristiger Kontext: Der JIT-Compiler wird mit zunehmender PHP-Komplexität (Property Hooks, Lazy Objects, Pipe Operator) anfälliger für Edge-Case-Bugs. Regelmäßige PHP-Updates sind keine Option, sondern Pflicht.

PHP 8.5 wird bis Ende 2027 aktiv unterstützt. PHP 8.4 bis Ende 2026. PHP 8.3 erhält nur noch Security-Fixes bis Dezember 2026. Wer noch auf 8.3 ist, sollte das Versions-Upgrade auf 8.4 oder 8.5 jetzt einplanen, nicht erst wenn der Security-Support ausläuft.

Server-Audit und PHP-Update-Beratung

Ist JIT auf Ihren Servern aktiv? Auf welcher PHP-Version laufen Ihre Projekte? Ist Ihr Hosting-Provider bereits auf dem aktuellen Patch-Level? In einem kostenlosen Erstgespräch prüfe ich Ihren Server-Status und gebe eine klare Handlungsempfehlung.

→ Kostenloses Server-Audit anfragen

Dennis Schwenker-Sanders ist PHP & Symfony-Entwickler mit Fokus auf Server-Konfiguration, Performance-Optimierung und Security-Updates für deutsche Agenturen und KMU. Er begleitet Teams bei der systematischen Aktualisierung ihrer PHP-Infrastruktur.

Artikel teilen: