avva: (moose)
[personal profile] avva
Прикольно - оказывается, инструкция idiv, деление со знаком, на x86 кидает исключение не только при делении на ноль, но и когда результат не помещается в регистр. А этого очень легко добиться, написав в C например INT_MIN / -1. Как мы помним, INT_MIN по модулю на единицу больше, чем INT_MAX; например, в 32-битных числах INT_MIN равно -2147483648, а INT_MAX равно 2147483647. Поэтому когда INT_MIN делят на -1, положительный результат не вмещается в 32 бита.

Само по себе это не катастрофа - ну кидает исключение, ну и подумаешь. Дело в том, однако, что про деление на ноль все знают и помнят, и проверяют перед попыткой делить. А против INT_MIN/-1 никто практически не защищается. Поэтому можно, например:

- крэшнуть компилятор (правда, игрушечный), PostgreSQL (не игрушечную) или антивирус;
- подвесить Windows 8;
- убить bash
Page 1 of 3 << [1] [2] [3] >>

Date: 2013-01-29 11:24 pm (UTC)
From: [identity profile] cema.livejournal.com
А ты черт! :-)

Date: 2013-01-29 11:39 pm (UTC)
From: [identity profile] http://users.livejournal.com/_zlot_/
Стоп сигнал
idiv берет два параметра когда первый параметр имеет в два раза больше битов чем второй, так что даже деление на два, при неправильных параметрах выдаст overflow

http://pdos.csail.mit.edu/6.828/2011/readings/i386/IDIV.htm

Date: 2013-01-29 11:42 pm (UTC)
From: [identity profile] spamsink.livejournal.com
Это они зря. Microcode patch был бы полезен.

Date: 2013-01-29 11:45 pm (UTC)
From: [identity profile] avva.livejournal.com
Такое поведение во всех процессорах семьи начиная с 8086.

Date: 2013-01-29 11:49 pm (UTC)
From: [identity profile] spamsink.livejournal.com
Я не говорю, что это регрессия; я говорю, что это хорошо бы, наконец, поправить. Сочетание INT_MIN и -1 - единственный случай, когда результат не помещается в регистр, но он эквивалентен умножению на -1, которое прерывания не вызывает. Не вижу причин, по которым одна и та же операция с математической точки зрения должна вести себя по-разному в зависимости от команды.

Date: 2013-01-29 11:55 pm (UTC)
From: [identity profile] ahaxopet.livejournal.com
bash не падает, хотя версия вроде та же:

$ ($((-2**63/-1)))
-9223372036854775808: command not found
$ bash -version
GNU bash, version 4.2.37(1)-release (i686-pc-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.


Доктор, что я делаю не так? :-)

Date: 2013-01-29 11:58 pm (UTC)
From: [identity profile] archaicos.livejournal.com
Это так, но код на C(++) и не только на нём всегда фактически делит N бит на N бит (т.е. в [e|r]dx оказывается только знак делиМОГО).
Edited Date: 2013-01-30 03:41 am (UTC)

Date: 2013-01-30 12:01 am (UTC)
From: [identity profile] archaicos.livejournal.com
Можно и вовсе отменить все проверки. MIPS сгенерит мусор (или не совсем мусор, не важно), если не сможет поделить, не вызывая исключений.

Date: 2013-01-30 12:05 am (UTC)
From: [identity profile] ygam.livejournal.com
У меня Windows 8 не падает. Версия ядра 6.2.9200.16384 .

Date: 2013-01-30 12:07 am (UTC)
From: [identity profile] avva.livejournal.com
это верно, но при обычном делении int такая ситуация обычно не возникает, потому что первый аргумент, хоть и два раза длиннее с точки зрения инструкции, всего лишь исходный int, расширенный со знаком в дополнительный регистр. Поэтому INT_MIN/-1 - единственная возможность получить исключение при делении int-переменных.

Date: 2013-01-30 12:08 am (UTC)
From: [identity profile] gdt.livejournal.com
у вас 32 бита, почитайте последний коммент по ссылке про bash.

Date: 2013-01-30 12:09 am (UTC)
From: [identity profile] avva.livejournal.com
Запускаете на 32-битной системе (а они на 64-битной).

Date: 2013-01-30 12:09 am (UTC)
From: [identity profile] ahaxopet.livejournal.com
И верно, не заметил.

Date: 2013-01-30 12:16 am (UTC)
From: [identity profile] rezkiy.livejournal.com
у них 32 разрядная.

// Product: WinNt, suite: TerminalServer SingleUserTS
// Built by: 9200.16384.x86fre.win8_rtm.120725-1247

Date: 2013-01-30 12:23 am (UTC)
From: [identity profile] spamsink.livejournal.com
Как это практически сделать? sigset(SIGFPE, SIG_IGN); к успеху не приводит, а в gdb "handle SIGFPE ignore; handle SIGFPE nostop" приводит к зацикливанию на "Program received signal SIGFPE, Arithmetic exception."

Бардак везде.

Date: 2013-01-30 12:38 am (UTC)
From: [identity profile] archaicos.livejournal.com
Как я понимаю, обработчики исключений в C обычно не включают в себя дизассемблера, а на стеке обработчика сохраняется адрес проблематичной инструкции, т.е. перепрыгнуть через инструкцию деления они сами не смогут без сторонней помощи, могут только к ней вернуться или пойти куда-то ещё. Т.е. надо будет или самим разбирать код в обработчике, или самим вставлять проверку перед делением.

Date: 2013-01-30 01:00 am (UTC)
From: [identity profile] spamsink.livejournal.com
Логично было бы, чтобы ядро реализовывало игнорирование исключения, вызванного машинной командой (в отличие от внешнего сигнала), путем перепрыгивания через вызвавшую исключение команду.

Date: 2013-01-30 01:07 am (UTC)
From: [identity profile] archaicos.livejournal.com
Во всех случаях это вредно. Зачем нам перепрыгивать через чтение несуществующей страницы по адресу 0, например? Пусть сдохнет прямо там, чем живёт как зомби. Но именно тут в принципе можно было бы сделать битик, управляемый пользователем - генерить исключения при делении или нет, как это было в x87 сделано.

Date: 2013-01-30 01:12 am (UTC)
From: [identity profile] spamsink.livejournal.com
При чем тут "все случаи"? Я о том, что по (явному) запросу SIG_IGN ядро должно реализовывать полезное поведение, раз уж битика игнорировать исключения при целочисленном делении не предусмотрено.

Date: 2013-01-30 01:34 am (UTC)
From: [identity profile] archaicos.livejournal.com
При беглом взгляде на описание signal() и SIG_IGN в нескольких местах (С99, http://www.cplusplus.com/reference/csignal/signal/, http://pubs.opengroup.org/onlinepubs/7908799/xsh/signal.h.html, http://linux.die.net/man/2/signal) я не увидел ничего явно обязывающее перепрыгнуть через, например, инструкцию деления. Ты можешь замаскировать и не получить сигнал - да. Что будет дальше - про это как-то не очень написано.

Если есть нормативный документ, требующий перепрыгивающего поведения, имеем ошибку реализации, которую можно донести реализаторам, чтобы те её исправили.

Если это всё чепуха, тогда имеет смысл надавить на документаторов, чтобы они чётче определили поведение в данной ситуации.

Кстати, на странице по последней ссылке вообще написано следующее: Integer division by zero has undefined result. On some architectures it will generate a SIGFPE signal. (Also dividing the most negative integer by -1 may generate SIGFPE.) Ignoring this signal might lead to an endless loop.

Сейчас это можно практически трактовать только как то, что искомое поведение не является гарантированным на практике.

Date: 2013-01-30 02:14 am (UTC)
From: [identity profile] bolk.livejournal.com
bolk@Bolk /$ ($((-2**63/-1)))
Floating point exception: 8
bolk@Bolk /$ bash --version
GNU bash, version 4.2.42(2)-release (i386-apple-darwin12.2.0)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Date: 2013-01-30 03:09 am (UTC)
From: [identity profile] meshko.livejournal.com
Не факт, что придумать полезное поведение, когда такое исключение происходит внутри ядра, просто.

Date: 2013-01-30 04:31 am (UTC)
From: [identity profile] ircicq.livejournal.com
Поправить осмысленно нельзя просто потому, что CPU не имеет инструкции деления 32-bit на 32-bit.

IDIV всегда делит 64-bit на 32-bit (или 32 на 16, 16 на 8)
и overflow в таком случае обычное явление. Правильный компилятор не использует IDIV напрямую, всегда вызывается функция, проверяющая делимое и делитель на допустимый диапазон.
Edited Date: 2013-01-30 04:32 am (UTC)

Date: 2013-01-30 05:27 am (UTC)
From: [identity profile] spamsink.livejournal.com
Про "внутри ядра" тоже никто не говорил.
Page 1 of 3 << [1] [2] [3] >>

December 2025

S M T W T F S
  123 4 56
78 9 10 11 1213
1415 1617181920
21 22 23 24 2526 27
28293031   

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Dec. 29th, 2025 04:05 am
Powered by Dreamwidth Studios