Загадочный баг в ПХП
Во всех современных интерпретаторов вёдра багов, я обычно и внимания на них не обращаю, но свежезаведённый баг в ПХП
bolk@Bolk ~ $ php -r 'var_dump(0x0 + 2); var_dump(0x0+2); var_dump(0x0 +10);'
int(2)
int(4)
int(26)Как видно, ПХП (у меня на 5.3.8 работает) считает сложение с шестадцатеричным нулём (обязательно слева и обязательно без пробела перед вторым слагаемым)
С чем связано пока непонятно, я посмотрел какие токены выдаёт интерпретатор на парсинге, ничего подозрительного не увидел.
Добавлено позднее: с минусом тоже работает. Например «0x0 -10» даёт -26.
Добавлено ещё позднее: разобрался что это за интересная операция.
Читайте также
POSIX-регулярки в PCRE
Для меня это просто открытие какое-то, что POSIX regexp работают внутри PCRE: bolk.dev ~ $ php <<PHP
2009
PCRE 8.10
2010
Комментарии 14
Смысл покопаться в коде есть, но я бы не рискнул предположить что там не так, не глядя. Все числа до 10 умножаются на два, дальше
с переходом на следующую
Я назвал это «кашей» потому что знание о правиле «с переходом на следующую
Так ребята, пишущие ПХП, заставляют ребят пишущих на ПХП правильно форматировать свой код!
Посмотрел в код, вот что там происходит.
Когда ПХП встречает «0x…» он пропускает два байта («0x»), потом пропускает ведущие нули и передаёт остаток на конвертацию в функцию strtol (из stdlib). strtol применяется для преобразования строкового представления числа к long с указанным основанием системы счисления. ПХП вызывает её с параметром 16.
Ошибка в том, что не проверяется, что число не кончилось. В итоге в strtol попадает « +2», т.е. само число, которое переводится функцией strtol в шестнадцатеричный вид. Т.е. до десятки числа будут как бы умножаться на два, а дальше число будет складываться само с собой, но переведёным в шестнадцатеричный вид.
Например из десятки получится 26, так как складывается 10 + 0x10. Из сотни — 356 (100 + 0x100) и так далее.
Почему это работает только с пробелом не разбирался, спать пойду, завтра в Челябинск лететь ещё.
Комментарий для sunchaser.info:
Ага :)
тут у меня опечатка — «не проверяется, что число кончилось» должно быть.
Комментарий для Евгения Степанищева:
действительно,
тогда там анализируется и преобразуется строка '+' (или'-'), из которой получается 0
вот еще интересно:
код {HNUM} {}
в 5.2 и 5.3 одинаковый
почему раньше это работало? :)
Комментарий для sunchaser.info:
Фиг его знает, разбираться уже лень :)