На днях довелось чинить одну из программ которую я поддерживаю. Я знал что код падает в определенном модуле с Access violation ошибкой. Очень выборочно падает. Тоесть тостер не мог мне сказать как повторить этот баг. Вместо этого мне дали имя файла где этот код падает и примерное место где. Также дали:
Состояние регистров
EAX: 0 EBX: 0 ECX: 334068 EDX: 334068 ESI: 38ae908 EDI: 32 ESP: 12e65c EBP: 12e6d8 EIP: 684356a8
Код на ассемблере
6843569e 85c0 test eax,eax
684356a0 6a32 push 0x32
684356a2 5f pop edi
684356a3 7510 jnz 684356b5
684356a5 ff7508 push dword ptr [ebp+0x8]
684356a8 8b0b mov ecx,[ebx]
684356aa e871f5ffff call 68434c20
684356af 84c0 test al,al
684356b1 7409 jz 684356bc
684356b3 8bc1 mov eax,ecx
684356b5 e80af5ffff call 68434bc4
684356ba 8bf8 mov edi,eax
684356bc ff7648 push dword ptr [esi+0x48]
А также строчку на ассемблере где падает
684356a8 8b0b mov ecx,[ebx]
Я давно ничего не писал на ассемблере и было приятно вспомнить. Тем более что баг серьезный и было непонятно как его найти так что надо было использовать все что есть.
Я не помню всех команд но по push 0x32 видно что в стэк занесена константа которая в десятиричной системе представляется как 50. Дальше идет сравнение того что в регистре eax с нулем. И если 0 то идет прыжок на адрес 684356b5 потом сохраняется значение локальной переменной и ... мы падаем на mov ecx,[ebx] Эта строчка копирует содержимое по адресу который находится в регистре ebx в регистр ecx. Смотрим что у нас в евх, ага бинго! 0! Теперь ясно. Нулевой указатель. Поэтому и падаем. Процесс решил залезть в чужое адресное пространство. Дальше я нашел это место в С-шном коде. Оно выглядит примерно так:
void foo(X* pX, Y* pY)
{
if(pX)
{
if (pY)
{
use(pY);
}
else
{
int err = 50;
if (pX->error != 0)
{
err = bar(pX->error);
}
else
{
if(boo(pY->error))
{
err = bar(pY->error);
}
}
}
}
}
Ну, господа, программисты на С. Видите где ошибка?
В резюме добавлю что во многих универах на факультетах информатики перестали преподавать не то что ассемблер а даже С и С++. Теперь один сплошной managed code: Java, .NET и тд. Но это одна сторона медали - темная. Другая, это то что у тех кто знает ассемблер и С - неплохая job security. Или как это по русски? Уверенность в рабочем месте?
4 comments:
Надо отключить комментарии иначе можно будет подсмотреть ответ в комментах
Да это больше риторический вопрос. Там на самом деле очень очевидно. Если бы я посмотрел на эту функцию внимательнее я бы и так увидел но с ассемблером оказалось быстрее.
А я, кстати, только по С коду увидел ушибку, а с Ассемблером ничего не понял. Старею :-)
У нас бывает что ты не знаешь где в С коде ошибка. Только ассемблер и есть и по нему надо искать где.
Post a Comment