В мою компанию начали звонить несколько клиентов, потому что наша программа дает сбой из-за нарушения прав доступа в их системах.
Сбой происходит в 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) Service Pack 1» и имеют один из следующих ЦП (согласно DxDiag):
Согласно статье 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 до 7 минут пользовательского времени до сбоя. Один факт (который может иметь отношение к проблеме), который я не упомянул в исходном сообщении, заключается в том, что приложение является многопоточным и имеет высокую загрузку ЦП и операций ввода-вывода. Приложение по умолчанию порождает четыре рабочих потока и сообщает об использовании ЦП 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
и вызывают операторы eax
) и, кажется, также предотвращают проблему.
Самым странным результатом, который я обнаружил до сих пор, является изменение jne
в ] 719f9fa0
на две инструкции nop
(так что управление всегда попадает в команду test eax, eax
, независимо от значения ] createFlag
/ esi
is) позволяет программе работать без сбоев.