Не должно ли это произойти сбой ошибки процессора AMD Fusion? - PullRequest
68 голосов
/ 10 августа 2011

Моя компания начала звонить нескольким клиентам, потому что наша программа дает сбой из-за нарушения прав доступа в их системах.

Сбой происходит в SQLite 3.6.23.1, который мы поставляем как часть нашего приложения. (Мы поставляем пользовательскую сборку, чтобы использовать те же библиотеки VC ++, что и остальную часть приложения, но это стандартный код SQLite.)

Сбой происходит, когда pcache1Fetch выполняет call 00000000, как показано в стеке вызовов WinDbg:

0b50e5c4 719f9fad 06fe35f0 00000000 000079ad 0x0
0b50e5d8 719f9216 058d1628 000079ad 00000001 SQLite_Interop!pcache1Fetch+0x2d [sqlite3.c @ 31530]
0b50e5f4 719fd581 000079ad 00000001 0b50e63c SQLite_Interop!sqlite3PcacheFetch+0x76 [sqlite3.c @ 30651]
0b50e61c 719fff0c 000079ad 0b50e63c 00000000 SQLite_Interop!sqlite3PagerAcquire+0x51 [sqlite3.c @ 36026]
0b50e644 71a029ba 0b50e65c 00000001 00000e00 SQLite_Interop!getAndInitPage+0x1c [sqlite3.c @ 40158]
0b50e65c 71a030f8 000079ad 0aecd680 071ce030 SQLite_Interop!moveToChild+0x2a [sqlite3.c @ 42555]
0b50e690 71a0c637 0aecd6f0 00000000 0001edbe SQLite_Interop!sqlite3BtreeMovetoUnpacked+0x378 [sqlite3.c @ 43016]
0b50e6b8 71a109ed 06fd53e0 00000000 071ce030 SQLite_Interop!sqlite3VdbeCursorMoveto+0x27 [sqlite3.c @ 50624]
0b50e824 71a0db76 071ce030 0b50e880 071ce030 SQLite_Interop!sqlite3VdbeExec+0x14fd [sqlite3.c @ 55409]
0b50e850 71a0dcb5 0b50e880 21f9b4c0 00402540 SQLite_Interop!sqlite3Step+0x116 [sqlite3.c @ 51744]
0b50e870 00629a30 071ce030 76897ff4 70f24970 SQLite_Interop!sqlite3_step+0x75 [sqlite3.c @ 51806]

Соответствующая строка кода C:

if( createFlag==1 ) sqlite3BeginBenignMalloc();

Компилятор встраивает sqlite3BeginBenignMalloc, который определяется как:

typedef struct BenignMallocHooks BenignMallocHooks;
static SQLITE_WSD struct BenignMallocHooks {
  void (*xBenignBegin)(void);
  void (*xBenignEnd)(void);
} sqlite3Hooks = { 0, 0 };

# define wsdHooksInit
# define wsdHooks sqlite3Hooks

SQLITE_PRIVATE void sqlite3BeginBenignMalloc(void){
  wsdHooksInit;
  if( wsdHooks.xBenignBegin ){
    wsdHooks.xBenignBegin();
  }
}

И сборка для этого:

719f9f99    mov     esi,dword ptr [esp+1Ch]
719f9f9d    cmp     esi,1
719f9fa0    jne     SQLite_Interop!pcache1Fetch+0x2d (719f9fad)
719f9fa2    mov     eax,dword ptr [SQLite_Interop!sqlite3Hooks (71a7813c)]
719f9fa7    test    eax,eax
719f9fa9    je      SQLite_Interop!pcache1Fetch+0x2d (719f9fad)
719f9fab    call    eax ; *** CRASH HERE ***
719f9fad    mov     ebx,dword ptr [esp+14h]

Регистры:

eax=00000000 ebx=00000001 ecx=000013f0 edx=fffffffe esi=00000001 edi=00000000
eip=00000000 esp=0b50e5c8 ebp=000079ad iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202

Если eax равно 0 (что и есть), флаг нуля должен быть установлен на test eax, eax, но это ненулевое значение. Поскольку нулевой флаг не установлен, je не прыгает, а затем приложение падает, пытаясь выполнить call eax (00000000).

Обновление : eax всегда должно быть 0 здесь, потому что sqlite3Hooks.xBenignBegin не установлено в нашей сборке кода. Я мог бы перестроить SQLite с определением SQLITE_OMIT_BUILTIN_TEST, что включило бы #define sqlite3BeginBenignMalloc() в коде и полностью пропустило бы этот путь кода. Это может решить проблему, но это не похоже на «реальное» исправление; что могло бы остановить это в каком-то другом пути кода?

Пока что общий фактор заключается в том, что все клиенты используют «Windows 7 Home Premium 64-bit (6.1, Build 7601) с пакетом обновления 1» и имеют один из следующих процессоров (согласно DxDiag):

  • AMD A6-3400M APU с HD-графикой Radeon (tm) (4 процессора), ~ 1,4 ГГц
  • AMD A8-3500M APU с HD-графикой Radeon (tm) (4 процессора), ~ 1,5 ГГц
  • AMD A8-3850 APU с HD-графикой Radeon (tm) (4 процессора), ~ 2,9 ГГц

Согласно статье Wikipedia AMD Fusion, все это чипы AMD Fusion модели "Llano" на базе ядра K10, выпущенные в июне 2011 года, когда мы впервые начали получать отчеты.

Самой распространенной клиентской системой является Toshiba Satellite L775D, но у нас также есть отчеты о сбоях в системах HP Pavilion dv6 и dv7 и Gateway.

Может ли этот сбой быть вызван ошибкой процессора (см. Ошибки для процессоров семейства AMD 12h ) или есть какое-то другое возможное объяснение, которое я пропускаю? (По словам Раймонда, он может разгоняться , но странно, что это влияет только на эту конкретную модель процессора.)

Честно говоря, не представляется возможным, что это действительно ошибка процессора или ОС, потому что клиенты не получают синего экрана или сбоев в других приложениях. Должно быть какое-то другое, более вероятное объяснение - но что?

Обновление 15 августа: Я приобрел ноутбук Toshiba L745D с процессором AMD A6-3400M и могу постоянно отображать сбой при запуске программы. Авария всегда по одной и той же инструкции; .time сообщает от 1 до 30 минут пользовательского времени до сбоя. Один факт (который может иметь отношение к проблеме), о котором я не упомянул в исходном посте, состоит в том, что приложение является многопоточным и имеет высокую загрузку ЦП и ввода-вывода. Приложение порождает четыре рабочих потока по умолчанию и сообщает об использовании ЦП на уровне 80% (некоторые блокируются как для ввода-вывода, так и для мьютексов в коде SQLite), пока не произойдет сбой. Я изменил приложение, чтобы использовать только два потока, и оно все еще падало (хотя это заняло больше времени). Сейчас я запускаю тест только с одним потоком, и он еще не завершился.

Обратите внимание, что это не является проблемой загрузки процессора; Я могу запустить Prime95 без ошибок в системе, и это повысит температуру процессора до> 70 ° C, в то время как мое приложение едва достигает температуры выше 50 ° C во время работы.

Обновление 16 августа: Небольшое нарушение инструкций заставляет проблему «уйти».Например, замена загрузки памяти (mov eax,dword ptr [SQLite_Interop!sqlite3Hooks (71a7813c)]) на xor eax, eax предотвращает сбой.Изменение исходного кода C для добавления дополнительной проверки в оператор if( createFlag==1 ) изменяет относительные смещения различных переходов в скомпилированном коде (а также расположение операторов test eax, eax и call eax), а также, по-видимому, предотвращаетпроблема.

Самый странный результат, который я нашел до сих пор, состоит в том, что изменение jne at 719f9fa0 на две nop инструкции (так, чтобы управление всегда падало до *Инструкция 1082 *, независимо от значения createFlag / esi), позволяет запускать программу без сбоев.

Ответы [ 3 ]

27 голосов
/ 04 октября 2011

Я поговорил с инженером AMD на конференции Microsoft Build об этой ошибке и показал ему мое воспроизведение. Он послал мне по электронной почте этим утром:

Мы исследовали и обнаружили, что это связано с известными ошибками в семья Llano APU. Это можно исправить с помощью обновления BIOS в зависимости от OEM - если возможно, пожалуйста, порекомендуйте его своим клиентам (даже хотя у вас есть обходной путь).

В случае, если вам интересно, количество ошибок в семье составляет 665 Руководство по редакции (см. Стр. 45): http://support.amd.com/TechDocs/44739_12h_Rev_Gd.pdf#page=45

Вот описание этой ошибки:

665 Инструкция по целочисленному делению может вызвать непредсказуемое поведение

Описание

При очень специфическом и подробном наборе внутренних условий синхронизации процессорное ядро ​​может прервать спекулятивную инструкцию целочисленного деления DIV или IDIV (из-за перенаправления спекулятивного выполнения, например, из-за неправильно предсказанной ветви), но может зависнуть или преждевременно завершите первую инструкцию не спекулятивного пути.

Потенциальное влияние на систему

Непредсказуемое поведение системы, обычно приводящее к зависанию системы.

Предлагаемое решение

BIOS должен установить MSRC001_1029 [31].

Этот обходной путь изменяет задержку инструкций DIV / IDIV, указанную в Руководстве по оптимизации программного обеспечения для процессоров семейства 10h и 12h AMD , заказ № 40546. После применения этого временного решения задержка DIV / IDIV для семейства AMD 12h Процессоры аналогичны задержке DIV / IDIV для процессоров AMD Family 10h.

Исправлено Запланировано

нет

Нет

1 голос
/ 10 августа 2011

Я немного обеспокоен тем, что код, сгенерированный для if (wsdHooks.xBenignBegin), не очень общий. Предполагается, что единственным истинным значением является 1, в то время как оно действительно должно проверять любое ненулевое значение. Тем не менее, MSVC иногда сбивает с толку таким образом. Это, вероятно, ничего. Не берите в голову: эти инструкции для C код не представлен.

Учитывая, что бит eflag Z сброшен и EAX равен нулю, код не попал сюда при выполнении инструкции

719f9fa7    test    eax,eax

Должен быть переход откуда-то еще к следующей инструкции (719f9fa9 je SQLite_Interop!pcache1Fetch+0x2d) или даже самой инструкции call.

Еще одним осложнением является то, что в семействе x86 обычно недопустимая цель перехода (например, второй байт инструкции JE) выполняет невозмущенный (без ошибок) целый ряд инструкций, часто в конечном итоге возвращаясь к правильное выравнивание команд. Иными словами, вы можете не искать переход к началу какой-либо из этих инструкций: переход может быть в середине их байтов, что приводит к выполнению непримечательных операций, таких как add [al+ebp],al, которые, как правило, не замечаются.

Я предсказываю, что точка останова в инструкции test не будет достигнута за исключением. Единственный способ найти такие причины - либо быть очень удачливым, либо подозревать все и доказывать их невиновность поодиночке.

0 голосов
/ 15 августа 2011

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

  1. Другой кодовый путь к инструкции вызова. Используйте команду uf для дизассемблирования функции и поиска других переходов / ветвей в инструкции вызова

  2. Перейти / вызвать 0 из функции ловушки. dps SQLite_Interop!sqlite3Hooks l 2 и убедитесь, что он показывает нули.

...