Это" не должно произойти " сбой ошибки процессора AMD Fusion?


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

сбой происходит в 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();

компилятор inlines 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-бит (6.1, сборка 7601) пакет обновления 1" и имеют один из следующих процессоров (в соответствии с DxDiag):

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

согласно Википедии AMD Fusion article, эти все обломоки сплавливания АМД модели" Ллано " основанные на К10 ядро и были выпущены в июне 2011 года, когда мы начали получать отчеты.

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

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

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

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

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

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

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

3 68

3 ответа:

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

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

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

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

665 Целочисленное Деление Инструкция Может Вызвать Непредсказуемое Поведение

описание

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

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

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

Предложенный Обходной Путь

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

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

Исправить Запланировано

нет

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

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

719f9fa7    test    eax,eax

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

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

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

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

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

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