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

Во всех современных интерпретаторов вёдра багов, я обычно и внимания на них не обращаю, но свежезаведённый баг в ПХП какой-то забавный:
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.

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

SunChaser (sunchaser.info)
23 февраля 2012, 23:01

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

bolk (bolknote.ru)
23 февраля 2012, 23:03, ответ предназначен SunChaser (sunchaser.info):

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

SunChaser (sunchaser.info)
23 февраля 2012, 23:06, ответ предназначен bolk (bolknote.ru):

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

bolk (bolknote.ru)
23 февраля 2012, 23:15, ответ предназначен SunChaser (sunchaser.info):

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

SunChaser (sunchaser.info)
23 февраля 2012, 23:21, ответ предназначен bolk (bolknote.ru):

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

bolk (bolknote.ru)
23 февраля 2012, 23:26, ответ предназначен SunChaser (sunchaser.info):

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

bolk (bolknote.ru)
23 февраля 2012, 23:28

Я понял!

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

SunChaser (sunchaser.info)
23 февраля 2012, 23:45, ответ предназначен bolk (bolknote.ru):

python-style?

bolk (bolknote.ru)
23 февраля 2012, 23:52, ответ предназначен SunChaser (sunchaser.info):

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

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

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

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

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

bolk (bolknote.ru)
23 февраля 2012, 23:53, ответ предназначен SunChaser (sunchaser.info):

python-style?
Ага :)
что не проверяется, что число не кончилось
тут у меня опечатка — «не проверяется, что число кончилось» должно быть.

SunChaser (sunchaser.info)
24 февраля 2012, 01:46, ответ предназначен bolk (bolknote.ru):

действительно,
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 одинаковый
почему раньше это работало? :)

Павел Власов (инкогнито)
24 февраля 2012, 04:09

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

bolk (bolknote.ru)
24 февраля 2012, 08:11, ответ предназначен SunChaser (sunchaser.info):

почему раньше это работало? :)
Фиг его знает, разбираться уже лень :)

SunChaser (sunchaser.info)
24 февраля 2012, 14:36, ответ предназначен Павлу Власову

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

Ваше имя или адрес блога (можно OpenID):

Текст вашего комментария, не HTML:

Кому бы вы хотели ответить (или кликните на его аватару)