php

【PHP】数値オーバーフローが発生するパターン



PHPはとても柔軟なプログラムのためオーバーフローって基本的に起こらないのですが、
特定のパターンだと数値のオーバーフローが起こってしまう場合があるので、
今回はPHPでの数値オーバーフローのご紹介。

PHPでのINT最大値

PHPのint型の最大値は32bit環境では2147483647、64bit環境では9223372036854775808となります。
プログラムによりますがint型で宣言されているものがint型の桁数を超えた場合にオーバーフローが発生します。
でも、PHPは柔軟なプログラムのためint型の最大値を超えた場合は自動的にfloat型になります。

<?php
// 桁数が多いため32bit版での説明
$max = PHP_INT_MAX; // 2147483647
var_dump($max);
var_dump($max + 1);
実行結果
int(2147483647)
float(2147483648) 

実行すると自動的にfloat型に切り替わってしまいます。
ですが、PHPでもバッファオーバーフローが発生する場合があるのです。
ちなみに、PHP_INT_MAXはその環境でのint型最大値を取得してくれます。

PHPでのオーバーフロー

私が確認している中でPHPでのオーバーフローのパターンは2つあります。

配列キー

配列の数値キーがint型最大値を超えた場合、オーバーフローします。
<?php
$hoge = array(PHP_INT_MAX => "MAX", PHP_INT_MAX + 1 => "OVER FLOW");
var_dump($hoge);
実行結果
array(2) {
	[2147483647]=> string(3) "MAX"
	[-2147483648]=> string(9) "OVER FLOW"
}
結果は上記の通りになってしまいます。
なので配列の数値キーを使う場合はお気をつけ下さい。

intval()関数

intval()関数を使用した際に、int型の最大値を超えたfloat型の値を、強制的にint型にするため発生します。
<?php
var_dump(intval(PHP_INT_MAX));
var_dump(intval(PHP_INT_MAX + 1));

実行結果
int(2147483647)
int(-2147483648) 
結果はオーバーフローしてしまいます。
強制的にint型にした時にオーバーフローが発生してしまいます。

発生理由

発生した理由はintvalでは強制的にint型にしたために正負を表す、符号部にマイナスの値が入ってしまったと思われます。
配列の数値キーの場合はおそらくfloatに自動変換する機能がないと思われます。

わかりやすく説明するために2進数に置き換えてみます。
<?php
echo decbin(PHP_INT_MAX);
echo decbin(PHP_INT_MAX + 1);
01111111111111111111111111111111
10000000000000000000000000000000
2進数の符号付数値表現がわかる方ならこの時点でわかるかと思います。
32bitの場合1桁目が正負の符号部分になるため0の場合は正の数、1の場合は負の数となります。
配列、intvalどちらもint型にする時に桁の切り捨てて行っているがためにこのような事象が発生していると考えられます。

まとめ

今回はPHPではオーバーフローは起きないと言われたため、実際に起きないか色々調べてみました。
バッファオーバーフロー自体はバグとして記載されているのを見つけましたが、具体的な方法は載ってなかったので試してないです。
配列とintvalのオーバーフローは恐らく、クリティカルなエラーが発生しないのと、PHP使用者自体が気をつけるべきことなので対応は今後もされないと思われますね。


最近、忙しすぎて書き留めておこうと思うことが多いのですが、書く時間が殆ど取れない状態になっていました・・・orz


コメントを残す