Пишу, по большей части, про историю, свою жизнь и немного про программирование.

Загадочный баг в ПХП

Во всех современных интерпретаторов вёдра багов, я обычно и внимания на них не обращаю, но свежезаведённый баг в ПХП какой-то забавный:

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.

Добавлено ещё позднее: разобрался что это за интересная операция.

14 комментариев
SunChaser (sunchaser.info) 2012

может он считает его указателем?

Евгений Степанищев (bolknote.ru) 2012

Комментарий для sunchaser.info:

Указателем на что?

SunChaser (sunchaser.info) 2012

Комментарий для Евгения Степанищева:

Судя по арифметике, на двухбайтовое значение + какое-то странное выравнивание после 10 смещений. есть смысл покопаться в коде

Евгений Степанищев (bolknote.ru) 2012

Комментарий для sunchaser.info:

Смысл покопаться в коде есть, но я бы не рискнул предположить что там не так, не глядя. Все числа до 10 умножаются на два, дальше какая-то каша, не пытался разобраться.

SunChaser (sunchaser.info) 2012

Комментарий для Евгения Степанищева:

с переходом на следующую 10-ку добавляется 8, дальше опять добавляется по 2

Евгений Степанищев (bolknote.ru) 2012

Комментарий для sunchaser.info:

Я назвал это «кашей» потому что знание о правиле «с переходом на следующую 10-ку добавляется 8, дальше опять добавляется по 2» не даёт ни понимания почему так происходит, ни сколько добавится при переходе с «0x0 +99» к «0x0 +100».

Евгений Степанищев (bolknote.ru) 2012

Я понял!

Так ребята, пишущие ПХП, заставляют ребят пишущих на ПХП правильно форматировать свой код!

SunChaser (sunchaser.info) 2012

Комментарий для Евгения Степанищева:

python-style?

Евгений Степанищев (bolknote.ru) 2012

Комментарий для sunchaser.info:

Посмотрел в код, вот что там происходит.

Когда ПХП встречает «0x…» он пропускает два байта («0x»), потом пропускает ведущие нули и передаёт остаток на конвертацию в функцию strtol (из stdlib). strtol применяется для преобразования строкового представления числа к long с указанным основанием системы счисления. ПХП вызывает её с параметром 16.

Ошибка в том, что не проверяется, что число не кончилось. В итоге в strtol попадает « +2», т. е. само число, которое переводится функцией strtol в шестнадцатеричный вид. Т. е. до десятки числа будут как бы умножаться на два, а дальше число будет складываться само с собой, но переведёным в шестнадцатеричный вид.

Например из десятки получится 26, так как складывается 10 + 0x10. Из сотни — 356 (100 + 0x100) и так далее.

Почему это работает только с пробелом не разбирался, спать пойду, завтра в Челябинск лететь ещё.

Евгений Степанищев (bolknote.ru) 2012

Комментарий для sunchaser.info:

python-style?

Ага :)

что не проверяется, что число не кончилось

тут у меня опечатка — «не проверяется, что число кончилось» должно быть.

SunChaser (sunchaser.info) 2012

Комментарий для Евгения Степанищева:

действительно,

if (len == 0) {
zendlval->value.lval = 0;
zendlval->type = IS_LONG;
return T_LNUMBER;
} else if (len < SIZEOF_LONG * 2 || (len == SIZEOF_LONG * 2 && *hex <= ’7’)) {

исправляет багу

Почему это работает только с пробелом не разбирался

тогда там анализируется и преобразуется строка ’+’ (или ’-’), из которой получается 0

вот еще интересно:

[sunchaser@maritropa cli]$ ./php -r ’var_dump(0x0 + 2); var_dump(0x0+2); var_dump(0x0 +10);’
int(2)
int(2)
int(10)
[sunchaser@maritropa cli]$ ./php -v
PHP 5.2.17 (cli) (built: Feb 24 2012 01:01:50)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2010 Zend Technologies

код <ST_IN_SCRIPTING>{HNUM} {}
в 5.2 и 5.3 одинаковый
почему раньше это работало? :)

Павел Власов 2012

Что же заставило пэхапистов писать глючный лексический анализ самостоятельно... Буду надеяться что нечто серьёзное.

Евгений Степанищев (bolknote.ru) 2012

Комментарий для sunchaser.info:

почему раньше это работало? :)

Фиг его знает, разбираться уже лень :)

SunChaser (sunchaser.info) 2012

Комментарий для Павел Власов:

там bison / re2c стандартные, никаких костылей