Integer Overflows (Thema: PHP Beispiele)

Grenzen von Integern in PHP und das Verhalten bei Überschreiten dieser

1. Einführung

Intern werden alle Integerwerte als Binärzahlen gespeichert. Abhängig vom System und der verwendeten PHP-Version stehen 32 oder 64 bit pro Integer zur Verfügung. Ein Bit fällt jeweils weg, um zu kennzeichnen, ob die Zahl positiv oder negativ ist. Bei n zur Verfügung stehenden Bit ergibt sich der größte Dezimalwert, der abgebildet werden kann, aus n2-1. (Für das -1 kann man etwa eine Zahl mit einem Bit betrachten, welche maximal den Dezimalwert 1 abbilden kann.)

2. PHP_INT_MAX

Nachfolgend wird eine 32bit-Version von PHP verwendet. Der größte Dezimalwert lautet für diese Version demnach (32-1)2-1 (ca. 2,1 Milliarden). Dieser Wert ist in der Konstante PHP_INT_MAX abgespeichert, man muss ihn also nicht selbst ausrechnen.

PHP-Code
<?php
	var_dump(PHP_INT_MAX + 2);
	var_dump(PHP_INT_MAX + 1);
	var_dump(PHP_INT_MAX);
	var_dump(PHP_INT_MAX - 1);
	var_dump(PHP_INT_MAX - 2);
?>

HTML-Code: Ausgabe
float(2147483649)
float(2147483648)
int(2147483647)
int(2147483646)
int(2147483645)


Wie im Beispiel zu sehen ist, werden alle Werte bis 312-1 (also 2147483647) als Integer gespeichert. Über diesen Wert hinaus wechselt PHP automatisch zu Float. Im Gegensatz zu anderen Sprachen entsteht also weder eine Fehlermeldung, noch wechselt die Zahl in den negativen Bereich. So ist die Durchführung der meisten Rechnungen zwar noch möglich, kleinere Abweichungen vom erwarteten Wert können sich jedoch ergeben. Insbesondere bei Prüfungen auf Gleichheit kann es bei Floats zu unerwartetem Verhalten kommen. Integer Overflows sollten daher generell vermieden werden.

3. PHP_INT_MIN

Die Konstante „PHP_INT_MIN” ist in PHP nicht vordefiniert. Sie lässt sich aber einfach nachbilden, indem man PHP_INT_MAX*(-1) rechnet.

PHP-Code
<?php
	define('PHP_INT_MIN', PHP_INT_MAX * (-1));
	var_dump(PHP_INT_MIN + 2);
	var_dump(PHP_INT_MIN + 1);
	var_dump(PHP_INT_MIN);
	var_dump(PHP_INT_MIN - 1);
	var_dump(PHP_INT_MIN - 2);
?>

HTML-Code: Ausgabe
int(-2147483645)
int(-2147483646)
int(-2147483647)
int(-2147483648)
float(-2147483649)


In diesem Beispiel beginnt der Wechsel zu Float erst bei (PHP_INT_MAX*(-1) - 1), also nach -2147483648. Wie im nächsten Abschnitt zu sehen ist, sollte man dennoch PHP_INT_MIN nicht als (PHP_INT_MAX*(-1) - 1) definieren.

4. Abweichungen bei Rechnung ohne Konstanten

Zunächst einmal die Ausgaben, wenn man statt (PHP_INT_MAX +/- x) direkt die gewünschten Integerwerte verwendet:

PHP-Code
<?php
	var_dump(2147483649);
	var_dump(2147483648);
	var_dump(2147483647);
?>

HTML-Code: Ausgabe
float(2147483649)
float(2147483648)
int(2147483647)


Das Ergebnis zeigt gegenüber den vorherigen Rechnungen keine Abweichungen und deckt sich daher mit den Erwartungen. Anders sieht es aus, wenn man in den negativen Bereich geht:

PHP-Code
<?php
	var_dump(-2147483647);
	var_dump(-2147483648);
	var_dump(-2147483649);

	// zum Vergleich noch mal der Minimalwert, ausgerechnet via PHP_INT_MAX:
	var_dump(PHP_INT_MAX*(-1) - 1);
?>

HTML-Code: Ausgabe
int(-2147483647)
float(-2147483648)
float(-2147483649)
int(-2147483648)


Die direkte Verwendung von -2147483648 führt also zu einem anderen Ergebnis als die Berechnung des Wertes über PHP_INT_MAX: PHP wechselt bereits eine Stelle früher zu Float. Der Grund dafür ist vermutlich ein PHP-Bug. (Freilich hat dieses Verhalten nur eher akademische Bedeutung und keine wirklichen Auswirkungen auf die Praxis.)

Kommentare (0)

Von neu nach alt