Основной дамп с SIGFPE для ненулевого деления
У меня есть подозрительное ядро процесса qemu-kvm, выгруженное с помощью SIGFPE:
Program terminated with signal 8, Arithmetic exception.
#0 bdrv_exceed_io_limits (bs=0x7f75916b7270, is_write=false, nb_sectors=1)
at /usr/src/debug/qemu-kvm-0.12.1.2/block.c:3730
3730 elapsed_time /= (NANOSECONDS_PER_SECOND);
куда elapsed_time
является double
(значение в выводе gdb ниже) и NANOSECONDS_PER_SECOND
это макрос:
#define NANOSECONDS_PER_SECOND 1000000000.0
Я не могу придумать причину, как может вызвать SIGFPE. Любая подсказка?
Сценарий: я использую RHEL-6.5 в качестве хоста и пытаюсь запустить гостевую систему Windows. Он устойчиво воспроизводится с помощью одной и той же команды.
Полная обратная трассировка:
(gdb) bt
#0 bdrv_exceed_io_limits (bs=0x7ffff86f9270, is_write=false, nb_sectors=1) at /usr/src/debug/qemu-kvm-0.12.1.2/block.c:3730
#1 bdrv_io_limits_intercept (bs=0x7ffff86f9270, is_write=false, nb_sectors=1) at /usr/src/debug/qemu-kvm-0.12.1.2/block.c:181
#2 0x00007ffff7e0bf6d in bdrv_co_do_readv (bs=0x7ffff86f9270, sector_num=0, nb_sectors=1, qiov=0x7fffe8000ab8, flags=<value optimized out>)
at /usr/src/debug/qemu-kvm-0.12.1.2/block.c:2136
#3 0x00007ffff7e0c293 in bdrv_co_do_rw (opaque=0x7fffe8000b00) at /usr/src/debug/qemu-kvm-0.12.1.2/block.c:3880
#4 0x00007ffff7e125eb in coroutine_trampoline (i0=<value optimized out>, i1=<value optimized out>)
at /usr/src/debug/qemu-kvm-0.12.1.2/coroutine-ucontext.c:129
#5 0x00007ffff5718ba0 in ?? () from /lib64/libc.so.6
#6 0x00007fffffffbf60 in ?? ()
#7 0x0000000000000000 in ?? ()
(gdb) disass
0x00007ffff7e0b6ae <+190>: mov 0x8a0(%rbx),%rax
0x00007ffff7e0b6b5 <+197>: test %rax,%rax
=> 0x00007ffff7e0b6b8 <+200>: divsd 0x170660(%rip),%xmm0 # 0x7ffff7f7bd20
0x00007ffff7e0b6c0 <+208>: je 0x7ffff7e0b950 <bdrv_io_limits_intercept+864>
0x00007ffff7e0b6c6 <+214>: mov 0x888(%rbx),%rsi
(gdb) x/gf 0x7ffff7f7bd20
0x7ffff7f7bd20: 1000000000
(gdb) p elapsed_time
$3 = 919718
(gdb) p $_siginfo
$1 = {si_signo = 8, si_errno = 0, si_code = 6, _sifields = {_pad = {-136186690, 32767, 4244976, 0, -560757824, 32767, -
-560757344, 32767, 0, 0, 0, 0, 0, 0, 34884976, 0, -136186690, 32767, 34884976, 0, 4258127, 0, 0, 0, -55876128, 3265
-136186690, si_uid = 32767}, _timer = {si_tid = -136186690, si_overrun = 32767, si_sigval = {sival_int = 4244976, s
_rt = {si_pid = -136186690, si_uid = 32767, si_sigval = {sival_int = 4244976, sival_ptr = 0x40c5f0}}, _sigchld = {s
si_uid = 32767, si_status = 4244976, si_utime = -2408436515056123904, si_stime = -584917379700457473}, _sigfault
0x7ffff7e1f4be}, _sigpoll = {si_band = 140737352168638, si_fd = 4244976}}}
Итак, что может быть не так с этим divsd
инструкция? Любое предложение о том, как его отладить?
Ответь сам: это ошибка ядра, которая случайно устанавливает mxcsr в какое-то неправильное значение, ядро Linux запускает код SIGFPE INEXACT, когда бит не маскируется должным образом.
2 ответа
SIGFPE в вашем коде не из-за деления на ноль, а из-за некоторых из следующих причин:
FPE_FLTOVF_TRAP: Плавающая ловушка переполнения.
FPE_FLTUND_TRAP: Плавающая ловушка недостаточного потока. (Отлов на плавающий нижний поток обычно не включен.)
Сигнал SIGFPE сообщает о фатальной арифметической ошибке. Хотя имя получено из "исключения с плавающей точкой", этот сигнал фактически покрывает все арифметические ошибки, включая деление на ноль и переполнение. Если программа хранит целочисленные данные в местоположении, которое затем используется в операции с плавающей запятой, это часто вызывает исключение "недопустимая операция", поскольку процессор не может распознать данные как число с плавающей запятой.
Фактические исключения с плавающей точкой являются сложным предметом, потому что существует много типов исключений с едва различимым значением, и сигнал SIGFPE не различает их. Стандарт IEEE для двоичной арифметики с плавающей точкой (ANSI/IEEE Std 754-1985) определяет различные исключения с плавающей точкой и требует, чтобы соответствующие компьютерные системы сообщали об их возникновении. Однако в этом стандарте не указывается, как сообщается об исключениях, или какие виды обработки и контроля операционная система может предложить программисту.
Так как: NANOSECONDS_PER_SECOND
знак равно 1000000000.0
а также elapsed_time
знак равно 919718
так elapsed_time /= (NANOSECONDS_PER_SECOND);
=> 919718 / 100 0000 000.0
== 0.0000919718
Уверен, это вызывает Floating underflow trap
эта причина SIGFPF.
Плавающая ловушка переполнения не может иметь место, потому что операция делится.
SIGFPE необязательно можно увидеть до некоторого времени после инструкции, вызывающей его. Это сбивает с толку конечно.
См. /questions/32414952/rabota-s-isklyucheniyami-s-plavayuschej-tochkoj/32414975#32414975