Какова обычная причина такой ошибки «незаконной инструкции» и как я мог отлаживать?

#debugging #gcc #undefined-behavior #illegal-instruction

#отладка #gcc #неопределенное поведение #незаконная инструкция

Вопрос:

Я работаю над программой, использующей научную библиотеку GNU. Он выдает «незаконную инструкцию (дамп ядра)» после решения нелинейного уравнения пополам. Смотрите ниже. Какова обычная причина такой ошибки «незаконной инструкции» и как я мог отлаживать в таких ситуациях?

 ...
iter  0: A = 1.0000, lambda = 1.0000, b = 0.0000, cond(J) =   6.0000, |f(x)| = 101.0200
iter  1: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) =  92.8216, |f(x)| = -nan
iter  2: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) =      nan, |f(x)| = -nan
iter  3: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) =      nan, |f(x)| = -nan
iter  4: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) =      nan, |f(x)| = -nan
Illegal instruction (core dumped)
 

С gdb помощью я получил немного дополнительной информации.

 Program received signal SIGILL, Illegal instruction.
0x00000000004d1030 in nielsen_reject (nu=<optimized out>, mu=<optimized out>) at nielsen.c:98
98    *nu <<= 1;
(gdb) p nu
$1 = <optimized out>
(gdb) x/i $pc
 => 0x4d1030 <trust_iterate 8912>:  ud2 
 

Выше nielsen.c98 выглядит так

 ...
static int
nielsen_reject(double * mu, long * nu)
{
  *mu *= (double) *nu;

  /* nu := 2*nu */
  *nu <<= 1;

  return GSL_SUCCESS;
}
 

Процессор — x86_64 в соответствии с uname -m . ОС — Ubuntu 16.04 VirtualMachine на Mac (хосте). Версия GCC — 5.4.

 gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 

Код компилируется с помощью gcc, с включенным средством очистки адресов и неопределенным средством очистки ( -fsanitize=address,undefined ).

Кажется, что компилятор выдает инструкцию «ud2» при включении дезинфицирующих средств. Я хотел бы знать, является ли эта ошибка ошибкой компилятора, ошибкой дезинфицирующего средства или ошибкой кода?

Комментарии:

1. Одна из возможных причин заключается в том, что вы выполняете данные, например, из-за неправильного использования указателей на функции. Другое дело, что либо ваш код, либо библиотека неправильно скомпилированы или настроены для вашего процессора и используют инструкции, которые он не поддерживает. Числовой код, такой как gsl, Вероятно, использует расширения SIMD, такие как SSE, AVX и т. Д., Которые требуют достаточно нового процессора.

2. Один из способов проверки — запустить код в отладчике, таком как gdb, и при его сбое использовать x/i $pc для разборки инструкции с ошибкой. Проверьте руководство по архитектуре процессора на предмет того, какой набор функций требуется для этой инструкции, а затем посмотрите, есть ли у вашего процессора этот набор функций (с его руководством или / proc / cpuinfo или что-то еще).

3. @NateEldredge Спасибо. Я обновил вопрос дополнительной информацией. В частности, кажется, что компилятор выдает инструкцию «ud2» при включении дезинфицирующих средств. Я хотел бы знать, является ли это ошибкой компилятора, ошибкой дезинфицирующего средства или ошибкой кода?

4. «Ошибка кода» обычно является разумной догадкой. Компилятор вставил бы инструкции ud2, когда какая-либо проверка на неопределенное поведение завершилась неудачей, или какой-либо путь кода никогда не должен быть достигнут. Учитывая код ошибки, моим первым предположением было бы *nu переполнение. Возможно, вам будет легче отлаживать это, если вы перекомпилируете без оптимизации.

5. Вы также используете довольно старое программное обеспечение. Тестирование с более новыми версиями может помочь двумя способами: (1) это может быть ошибка в GSL, которая с тех пор была исправлена; (2) средство дезинфекции в более новом компиляторе может быть более полезным и с меньшей вероятностью иметь собственные ошибки.