У меня есть сбой, который меня озадачил и который я до сих пор считал невозможным постоянно воспроизводить.Код скомпилирован с Visual Studio 2008.
(упрощенный, конечно) исходный код выглядит следующим образом:
class AbstractParentClass
{
private:
/* data members */
public:
AbstractParentClass();
/*
virtual functions ...
*/
};
class ChildClass : public AbstractParentClass
{
private:
/* data members */
public:
ChildClass();
/*
overridden/implemented virtual functions ...
*/
};
void DifferentClass::func(const char ** strs)
{
ChildClass child_class;
int i = 0;
[...]
}
Разборка из аварийного дампа выглядит следующим образом:
Library!DifferentClass::func:
612cab20 83ec58 sub esp,58h
612cab23 56 push esi
612cab24 57 push edi
612cab25 8bf9 mov edi,ecx
612cab27 8d4c2420 lea ecx,[esp+20h]
612cab2b e8e053403f call a06cff10
612cab30 8b742464 mov esi,dword ptr [esp+64h]
[...]
Сопоставляя источник функции func () с разборкой, он выглядит примерно так:
Library!DifferentClass::func:
void DifferentClass::func(const char ** strs)
{
612cab20 83ec58 sub esp,58h
612cab23 56 push esi
612cab24 57 push edi
612cab25 8bf9 mov edi,ecx
ChildClass child_class;
612cab27 8d4c2420 lea ecx,[esp+20h]
612cab2b e8e053403f call a06cff10
int i = 0;
612cab30 8b742464 mov esi,dword ptr [esp+64h]
[...]
}
При успешном запуске (на другой машине, хотя даже на той же машине происходит сбой)не является надежно воспроизводимым), единственное отличие в разборке - это инструкция вызова, которая корректно отображает адрес конструктора по умолчанию ChildClass, например:
00404e8b call ChildClass::ChildClass (40a3d0h)
, а не как:
612cab2b call a06cff10
Таким образом, в аварийном прогоне тот адрес a06cff10, который служит параметром инструкции вызова, кажется, приходит от who-знает-где и не отображается ни на что конкретно.И поэтому, как и следовало ожидать, попытка доступа к этому адресу (чтобы получить конструктор по умолчанию ChildClass) приводит к нарушению доступа:
EXCEPTION_RECORD: 0012f688 -- (.exr 0x12f688)
ExceptionAddress: a06cff10
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000000
Parameter[1]: a06cff10
Attempt to read from address a06cff10
Любая попытка просмотреть этот адрес в дампе сбоя действительно указывает на то, что адреснаходится за пределами процесса.
ОБНОВЛЕНИЕ: Таким образом, после прочтения приведенного ниже ответа от zvrba и дальнейшего его изучения проблемный вызов представляется первым из дюжины или около того вызовов функций в статической библиотеке (которая в свою очередь загружается библиотекой DLL).) что все имеют неправильное смещение функции.Они не все функции в одном классе.Существует три или четыре разных класса с затронутыми функциями, хотя все классы (как вызывающие, так и вызываемые) живут в одной и той же статической библиотеке.В этом первом вызове, в котором произошел сбой, инструкция была e8e053403f, а смещение 3F4053E0 в этой инструкции должно было быть смещением всего 53E0.Все остальные экземпляры имеют одинаковую проблему смещения.Смещение в инструкции составляет 3F40XXXX, когда оно должно быть просто XXXX.Дополнительный 3F400000, конечно, отправляет вещи в Never Never Land.До сих пор я не определил, какие адреса функций в разборке действительны, а какие - нет.Одна функция-член DifferentClass в библиотеке будет иметь все свои вызовы ChildClass как плохие, тогда как другая функция-член DifferentClass будет иметь другой вызов в ChildClass, выглядят просто отлично.
Кто-нибудь там видел что-то подобное / есть мысли о вероятных причинах этого?