PHP float bug: PHP зависает на числовом значении - PullRequest
4 голосов
/ 05 января 2011

Я только что прочитал интересную статью о зависании php на определенных числах с плавающей точкой, см. Реестр и Исследование двоичного файла .

Я никогда не использую поплавки явно, я используюnumber_format() для очистки моего ввода и отображения, например, цен.

Кроме того, насколько мне известно, все входные данные, например из форм, являются строками, пока я не скажу им иначе, поэтому я полагаю, что эта проблема неповлиять на меня.

Прав ли я, или мне нужно проверить, например, установки Wordpress и Squirrelmail на моем сервере, чтобы увидеть, бросают ли они что-нибудь для плавания?Или лучше, grep все php файлы на моих серверах для float?

Ответы [ 8 ]

5 голосов
/ 05 января 2011

Способы смягчения проблемы:

  1. Используйте современный процессор.Большинство современных 64-битных процессоров были бы невосприимчивы (у меня действительно были проблемы с поиском хоста, который позволяет воспроизводить его, поскольку они, как правило, используют более современное оборудование).Виртуальные машины Amazon тоже кажутся невосприимчивыми.
  2. Обновите версию PHP - после выпуска 5.3.5 и 5.2.17 (вероятно, сегодня) исправьте.
  3. Сборка с -ffloat-store в CFLAGSзамедлит код).
  4. Вручную примените patch к своему коду и пересоберите PHP.

Ищете код, который float, вероятно, выигралЭто не помогает, поскольку zend_strtod используется движком во многих сценариях преобразования чисел в строки.

PS Этот код, кстати, является стандартной библиотекой BSD strtod, не уникальным для PHP.Таким образом, другие проекты, использующие этот код, также могут быть затронуты.

4 голосов
/ 05 января 2011

С hackernews :

Эта проблема возникает из-за IA-32 80-битная арифметика с плавающей точкой. простое исправление: добавьте флаг "-ffloat-store" на ваши CFLAGS.

проблемный функция, zend_strtod, кажется, анализирует мантисса (2.225 ... 011 часть) и показатель (часть -308) отдельно, c> вычислить приближение m * 10 ^ e и последовательно улучшать это приближение, пока ошибка не станет менее 0,5 цел. Проблема в том, что это конкретное число вызывает бесконечный цикл (т.е. итерация делает не исправить ошибку вообще) в 80-битная FP, но не в 64-битной FP. Так как x86-64 вообще использует SSE2 набор инструкций (с 64-битной FP) вместо устаревшего х87 это делает не имеют этой проблемы.

3 голосов
/ 05 января 2011

В качестве быстрого обходного пути вы можете сканировать входные массивы:

foreach(array("_GET","_POST","_REQUEST","_COOKIES") as $G) {
    if (in_array('2.2250738585072011e-308', $$G)) {
         header("Status: 422 Unprocessable Entity");
         exit;
    }
}

Этого достаточно, если вы не используете подмассивы во входных переменных.Это будет работать, потому что он содержит float как строку, входные массивы содержат строки, а in_array работает и в строковом контексте.

Однако я не рассматривал, есть ли другие представления этого значения.Это единственный, который, как известно, работает до сих пор, но может быть и больше.Итак, обновление более целесообразно: |

2 голосов
/ 05 января 2011

Как сказал Марког, это арифметическая ошибка с плавающей точкой в ​​математике x87.Если вы хотите узнать больше об этом, проверьте ошибку GCC, Ссылка

1 голос
/ 05 января 2011

Недостаточно просто найти float, поскольку вы ищете код, который явно преобразует значение переменной в float, но вы не найдете ни одного случая, когда приведение будет неявным.

$d = '2.2250738585072011e-308';
$f = float($d);

- явное приведение, но как насчет кода вроде:

$d = '2.2250738585072011e-308';
$f = $d + 0.1;

или

$d = '2.2250738585072011e-308';
if ($d == 0.5) {

Я считаю, что эта ошибка также была исправлена ​​в последнем коде сборки PHP, хотя пакеты, такие как xampp, все еще затрагиваются.

1 голос
/ 05 января 2011

поиск явных float-приведений вам не поможет - в php переменная обрабатывается как то, для чего она используется.Небольшой пример:

$mystring = "123.45"; //mystring is a string here
$myvalue = $mystring * 4; // mystring is a float here
                          // and there's no explicit float-cast

, как вы можете видеть: обновить / исправить вашу php-установку - единственный способ сохранить мертвый сервер.

РЕДАКТИРОВАТЬ: вВаш комментарий:

плавает на самом деле не так просто.даже простые числа, такие как 0,7 или 0,8, не могут быть точно сохранены, и поэтому может случиться, что 0,8, после некоторых вычислений, будет 0,799999999789 ... с еще большим количеством этого дерьма, это просто вопрос времени, пока у вас не возникнут проблемы.

просто в качестве примера (и если вы пользователь Windows):

  1. открыть калькулятор Windows
  2. вычислить корень квадратный из 4 (долженбыть 2)
  3. вычесть 2 из результата (должно быть 0, но ... woooow;))

эта ошибка в калькуляторе Windows с тех пор ... когда-либо - иэто показывает, что даже большие компании могут потерпеть неудачу, используя float, но калькулятор не убивает вашу систему - если такой баг может убить вашу систему (как этот php-баг), вам придется обновить / исправить это, без исключений.

0 голосов
/ 06 января 2011

Чтобы перехватить все возможные обозначения числа, необходимо использовать поиск по подстроке.

См. http://www.aircraft24.com/en/info/php-float-dos-quickfix.htm для нашего последнего обходного пути.

0 голосов
/ 06 января 2011

Если вы не можете исправить вашу установку php, вы можете использовать следующее: Любые проблемы со следующим обходным путем для php bug # 53632

Это просто временное решение, пока вы не сможетена самом деле патч вашей PHP установки

...