> Второй день ломаю голову, над тем почему приложение работает очень не стабильно. Наткнулся вот на это: > > [img] > http://files.rsdn.ru/19745/channel.gif > [/img] > > Подскажите, пожалуйста, что именно это значит, а самое главное как это вылечить.
Означает это, что dll собиралась для загрузки по одному адресу (скорее всего, по дефолтовому 10000000), а на самом деле ее пришлось загрузить по другому адресу. Как правило, это приводит к незначительному замедлению процесса запуска программы. Проблемы может вызвать только в сочетании с различными хитрыми приемами типа самомодифицируещегося кода и т.п. — т.е., при написании протекторов, exe-пакеров и подобных программ, когда работу линкера по созданию таблицы relocations и операционки по перемещению кода на другое место приходится выполнять самостоятельно. В общем, ищите причину нестабильной работы в другом месте.
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[2]: dll грузиться в не верное адрессное пространство
Здравствуйте, Sergey, Вы писали:
S> ... В общем, ищите причину нестабильной работы в другом месте.
Ищу, но найти не могу. Поиск самым стандартным способом (через точки останова и анализ содержимого блоков памяти) картину не проясняет. Приложение и DLL использует код (класс для работы с блоками памяти) из одно итого же lib файла. Ошибка возникает в классе при выделении блока памяти, но это уже следствие установить причину не получается. Из выше сказанного можно было бы предположить, что проблема в классе, но нет так как само приложение, активно используя класс, исправно работает и dll также исправно работает вне этого приложения т.е. если приложение не использует класс. Получается, что источник проблемы это совместное использование одного и того же класса разными потоками (функции dll, использующее класс, вызываются в отдельном потоке). Это утверждение было бы верным если бы два разных потока использовали бы одну и туже переменную объявленную этим классом так? Но в данном случае всё совсем не так. Каждый поток работает со своим экземпляром класса и они между собой ни как не пересекаются или я не до конца понимаю механизм меж-потокового взаимодействия?
Тогда у меня вопрос в следующем: Нужно ли применять критические секции в том случае если два разных потока создают и используют собственные экземпляры одно и того же класса и тем самым обращаются к одному и тому же участку кода?
-= The Alien//Ufocomp =-
Re[3]: dll грузиться в не верное адрессное пространство
> Ошибка возникает в классе при выделении блока памяти, но это уже следствие установить причину не получается.
Можно взглянуть на текст ошибки? И в output окно отладчика оно что-нибудь при возникновении ошибки пишет?
> Тогда у меня вопрос в следующем: Нужно ли применять критические секции в том случае если два разных потока создают и используют собственные экземпляры одно и того же класса и тем самым обращаются к одному и тому же участку кода?
Не нужно.
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[4]: dll грузиться в не верное адрессное пространство
Здравствуйте, Sergey, Вы писали:
S>Можно взглянуть на текст ошибки? И в output окно отладчика оно что-нибудь при возникновении ошибки пишет?
[15.08.2007 15:12:08] [ 127.0.0.1:03650] [<] [3084] 002 22 00
[15.08.2007 15:12:08] [ 127.0.0.1:03650] [>] [3084] 004:013 22 08 16 00
[15.08.2007 15:12:08] [ 213.87.86.60:10024] [<] [1248] 006 22 08 16 00 85 FE
First-chance exception at 0x77e4bee7 in decsrv.exe: Microsoft C++ exception: ufoException::EStreamError @ 0x00d5f980.
[15.08.2007 15:12:08] [ 127.0.0.1:03650] [E] Ошибка сокета: Out of memory while expanding memory stream
First-chance exception at 0x77e4bee7 in decsrv.exe: Microsoft C++ exception: [rethrow] @ 0x00000000.
[15.08.2007 15:12:08] [ 127.0.0.1:03650] [M] Отключение.
[15.08.2007 15:12:08] [M] [2088] Устройство закрыто.
PtUskLib: DLL_PROCESS_DETACH'decsrv.exe': Unloaded 'C:\DevSrc\(.NET)\(Vc7)\Configurator\decsrv\Debug\PtUskVC.dll'
'decsrv.exe': Unloaded 'C:\WINDOWS\system32\wsock32.dll'
The thread 'Win32 Thread' (0x828) has exited with code 0 (0x0).
[15.08.2007 15:12:08] [M] [3084] Устройство закрыто.
The thread 'Win32 Thread' (0xc0c) has exited with code 0 (0x0).
[15.08.2007 15:12:08] [M] [3312] Устройство закрыто.
The thread 'Win32 Thread' (0xcf0) has exited with code 0 (0x0).
The thread 'Win32 Thread' (0x408) has exited with code 0 (0x0).
First-chance exception at 0x77e4bee7 in decsrv.exe: Microsoft C++ exception: ufoException::EStreamError @ 0x00edd820.
[15.08.2007 15:12:09] [ 213.87.86.111:05793] [M] Out of memory while expanding memory stream
First-chance exception at 0x77e4bee7 in decsrv.exe: Microsoft C++ exception: ufoException::EStreamError @ 0x00fdd820.
[15.08.2007 15:12:09] [ 213.87.86.60:10024] [M] Out of memory while expanding memory stream
First-chance exception at 0x77e4bee7 in decsrv.exe: Microsoft C++ exception: ufoException::EStreamError @ 0x00edd820.
[15.08.2007 15:13:11] [ 213.87.86.111:05793] [M] Out of memory while expanding memory stream
First-chance exception at 0x77e4bee7 in decsrv.exe: Microsoft C++ exception: ufoException::EStreamError @ 0x00fdd820.
[15.08.2007 15:13:11] [ 213.87.86.60:10024] [M] Out of memory while expanding memory stream
First-chance exception at 0x71bb30d1 in decsrv.exe: 0xC0000005: Access violation reading location 0x71bb30d1.
Unhandled exception at 0x71bb30d1 in decsrv.exe: 0xC0000005: Access violation reading location 0x71bb30d1.
Сейчас я выделяю блоки памяти через GlobalAlloc, и именно здесь возникает ошибка:
Pointer CMemoryStream::Realloc(int &NewCapacity)
{
if ( (NewCapacity > 0) && (NewCapacity != m_Size) )
NewCapacity = (NewCapacity + (MemoryDelta - 1)) & ~(MemoryDelta - 1);
Pointer P = Memory;
if ( NewCapacity != m_Capacity )
{
if ( NewCapacity == 0 )
{
GlobalFreePtr(Memory);
P = NULL;
}
else
{
if ( m_Capacity == 0 )
P = GlobalAllocPtr(GMEM_MOVEABLE, NewCapacity);
else
P = GlobalReallocPtr(Memory, NewCapacity, GMEM_MOVEABLE);
if ( P == NULL )
throw EStreamError(_T("Out of memory while expanding memory stream"));
}
}
return P;
};
A> Ошибка возникает в классе при выделении блока памяти, но это уже следствие установить причину не получается. Из выше сказанного можно было бы предположить, что проблема в классе, но нет так как само приложение, активно используя класс, исправно работает и dll также исправно работает вне этого приложения т.е. если приложение не использует класс.
Похоже на порчу кучи.
Проверьте выход за границы, удаление delete вместо delete [], повторный delete итд
Re[5]: dll грузиться в не верное адрессное пространство
> то в Output предварительно писалось heap corruption detected.
Ну вот с этого и надо было начинать. Собственно, искать надо где у вас в программе осуществляется запись за границы выделенной области памяти. Если вернетесь обратно на использование хипа, то по крайней мере в Output будет писаться адрес попорченной памяти — этого, конечно, мало, но все же лучше чем ничего.
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[6]: dll грузиться в не верное адрессное пространство
Здравствуйте, dip_2000, Вы писали:
A>> Ошибка возникает в классе при выделении блока памяти, но это уже следствие установить причину не получается. Из выше сказанного можно было бы предположить, что проблема в классе, но нет так как само приложение, активно используя класс, исправно работает и dll также исправно работает вне этого приложения т.е. если приложение не использует класс. _>Похоже на порчу кучи. _>Проверьте выход за границы, удаление delete вместо delete [], повторный delete итд
Спасибо за ответ, буду продолжать поиски.
-= The Alien//Ufocomp =-
Re[6]: dll грузиться в не верное адрессное пространство
>> то в Output предварительно писалось heap corruption detected.
S>Ну вот с этого и надо было начинать. Собственно, искать надо где у вас в программе осуществляется запись за границы выделенной области памяти. Если вернетесь обратно на использование хипа, то по крайней мере в Output будет писаться адрес попорченной памяти — этого, конечно, мало, но все же лучше чем ничего.
А что мне даст этот адрес, вернее как его использовать в дальнейшем для анализа? Может есть наработки в этой области? В дебагере отловить это практически не возможно т.к. кода не одна тысяча строк, плюс множество потоков которые практически все используют этот класс в добавок сама ошибка проявляется не сразу, а минут через 5-10.
-= The Alien//Ufocomp =-
Re[7]: dll грузиться в не верное адрессное пространство
NS>>2. Что говорит GetLastError при ошибке? A>The handle is invalid.
>>>return ::GlobalLock(::GlobalReAlloc(P, (SIZE_T) Bytes, (UINT) Flags));
Это ошибка после выполнения GlobalReAlloc или после GlobalLock?
Re: dll грузиться в не верное адрессное пространство
Здравствуйте, alienufo, Вы писали:
A>Подскажите, пожалуйста, что именно это значит, а самое главное как это вылечить.
Чтобы долго не искать можно заюзать Bounds Checker и посмотреть в чём дело, может всё тут же и разрешиться.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[8]: dll грузиться в не верное адрессное пространство
Здравствуйте, NailS, Вы писали:
NS>>>2. Что говорит GetLastError при ошибке? A>>The handle is invalid.
>>>>return ::GlobalLock(::GlobalReAlloc(P, (SIZE_T) Bytes, (UINT) Flags)); NS>Это ошибка после выполнения GlobalReAlloc или после GlobalLock?
GlobalReAlloc возвращает NULL вместо хендла на что GlobalLock резонно замечает — The handle is invalid.
Ошибка при вызове GlobalReAlloc
Re[9]: dll грузиться в не верное адрессное пространство
NS>>>>2. Что говорит GetLastError при ошибке? A>>>The handle is invalid.
>>>>>return ::GlobalLock(::GlobalReAlloc(P, (SIZE_T) Bytes, (UINT) Flags)); NS>>Это ошибка после выполнения GlobalReAlloc или после GlobalLock?
_>GlobalReAlloc возвращает NULL вместо хендла на что GlobalLock резонно замечает — The handle is invalid. _>Ошибка при вызове GlobalReAlloc
Собственно, этот момент я и хочу уточнить у автора.
Какая нам польза от ошибки выполнения GlobalLock при диагностике проблемы?
К тому же, ИМХА, The handle is invalid. может случиться и при вызове GlobalReAlloc с кривым хендлом.
Re[8]: dll грузиться в не верное адрессное пространство
Здравствуйте, NailS, Вы писали:
NS>>>2. Что говорит GetLastError при ошибке? A>>The handle is invalid.
>>>>return ::GlobalLock(::GlobalReAlloc(P, (SIZE_T) Bytes, (UINT) Flags)); NS>Это ошибка после выполнения GlobalReAlloc или после GlobalLock?
Последний Output:
[15.08.2007 17:41:16] [ 127.0.0.1:04364] [>] [1280] 004:017 34 05 00 00
[15.08.2007 17:41:16] [ 213.87.86.103:39850] [<] [1980] 006 34 05 00 00 1E 15
[1600] GlobalAllocPtr::GlobalAlloc: Not enough storage is available to process this command.
[1600] GlobalAllocPtr::GlobalLock: The handle is invalid.
First-chance exception at 0x77e4bee7 in decsrv.exe: Microsoft C++ exception: ufoException::EStreamError @ 0x00d677b0.
[1228] GlobalAllocPtr::GlobalAlloc: Not enough storage is available to process this command.
[1228] GlobalAllocPtr::GlobalLock: The handle is invalid.
First-chance exception at 0x77e4bee7 in decsrv.exe: Microsoft C++ exception: ufoException::EStreamError @ 0x00edd820.
[15.08.2007 17:41:17] [ 213.87.86.122:39943] [M] Out of memory while expanding memory stream
[1980] GlobalAllocPtr::GlobalAlloc: Not enough storage is available to process this command.
[1980] GlobalAllocPtr::GlobalLock: The handle is invalid.
First-chance exception at 0x77e4bee7 in decsrv.exe: Microsoft C++ exception: ufoException::EStreamError @ 0x0139d820.
[15.08.2007 17:41:17] [ 213.87.86.103:39850] [M] Out of memory while expanding memory stream
[1980] GlobalAllocPtr::GlobalAlloc: Not enough storage is available to process this command.
[1980] GlobalAllocPtr::GlobalLock: The handle is invalid.
First-chance exception at 0x77e4bee7 in decsrv.exe: Microsoft C++ exception: ufoException::EStreamError @ 0x0139d820.
[15.08.2007 17:42:19] [ 213.87.86.103:39850] [M] Out of memory while expanding memory stream
[1228] GlobalAllocPtr::GlobalAlloc: Not enough storage is available to process this command.
[1228] GlobalAllocPtr::GlobalLock: The handle is invalid.
First-chance exception at 0x77e4bee7 in decsrv.exe: Microsoft C++ exception: ufoException::EStreamError @ 0x00edd820.
[15.08.2007 17:42:19] [ 213.87.86.122:39943] [M] Out of memory while expanding memory stream
[1980] GlobalAllocPtr::GlobalAlloc: Not enough storage is available to process this command.
[1980] GlobalAllocPtr::GlobalLock: The handle is invalid.
First-chance exception at 0x77e4bee7 in decsrv.exe: Microsoft C++ exception: ufoException::EStreamError @ 0x0139d820.
[15.08.2007 17:43:19] [ 213.87.86.103:39850] [M] Out of memory while expanding memory stream
[1228] GlobalAllocPtr::GlobalAlloc: Not enough storage is available to process this command.
[1228] GlobalAllocPtr::GlobalLock: The handle is invalid.
First-chance exception at 0x77e4bee7 in decsrv.exe: Microsoft C++ exception: ufoException::EStreamError @ 0x00edd820.
[15.08.2007 17:43:19] [ 213.87.86.122:39943] [M] Out of memory while expanding memory stream
>>> то в Output предварительно писалось heap corruption detected. > > S>Ну вот с этого и надо было начинать. Собственно, искать надо где у вас в программе осуществляется запись за границы выделенной области памяти. Если вернетесь обратно на использование хипа, то по крайней мере в Output будет писаться адрес попорченной памяти — этого, конечно, мало, но все же лучше чем ничего. > > А что мне даст этот адрес, вернее как его использовать в дальнейшем для анализа? Может есть наработки в этой области? В дебагере отловить это практически не возможно т.к. кода не одна тысяча строк, плюс множество потоков которые практически все используют этот класс в добавок сама ошибка проявляется не сразу, а минут через 5-10.
При чем здесь какой-то "этот класс"? У вас в некоторый момент времени портится память, через некоторое время этот факт замечает менеджер хипа, который сообщает вам, по какому конкретно адресу память была испорчена. Код, который осуществил туда запись, может вообще располагаться в другом модуле. Если есть возможность, можно попробовать воспользоваться автоматическими средствами диагностики, навроде BounsChecker, которые иногда могут самостоятельно обнаружить ошибочный код (а могут и не обнаружить). Если такой возможности нет, придется искать это место самому.
Если пользоваться функциями выделения памяти из CRT (new/delete/malloc/free), то можно поставить опцию _CRTDBG_CHECK_ALWAYS_DF и весь хип будет проверять при каждом выделении памяти — что сильно замедлит работу приложения, но позволит минимизировать время между порчей хипа и ее обнаружением. Осталось догадаться, какой конкретно код портит память. В детерминированных приложениях это просто — при каждом запуске адреса будут одними и теми же, в вашем случае все гораздо сложнее. Но, для начала можно просто глянуть, что за данные лежат по указанному адресу — вдруг сразу опознаете. Если не опознаете — попробуйте временно превратить приложение в одно-двух поточное с детерминированным поведением и обеспечить повторяемость ошибки при этих условиях. Не выйдет — пишите в логи call stack при каждом выделении памяти, потом найдете ближайший меньший адрес и узнаете, что именно испорчено. Если удасться найти закономерность — дальше можно будет попробовать расставлять (скриптом, не руками) бряки на изменение памяти. Ну в общем есть способы, но трудоемкие.
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[9]: dll грузиться в не верное адрессное пространство
Сложно удаленно сказать в чем ошибка, видя только часть кода.
Если работа с выделенной памятью идет только через класс CMemoryStream то выход за границы области можно попробовать проанализировать по коду доступа к памяти, который в исходных сообщениях отсутствует.
Дополнительно пара рекомендаций:
1. Ошибка Not enough storage is available to process this command может означать именно нехватку памяти, так что при ошибке хотелось бы видеть в логе размер запрашиваемой памяти, а так же не только текст ошибки, но еще и ее код.
2. Тот же MSDN рекомендует использовать вместо Global* функций Heap* функции
3. Встречались советы заменить GlobalReAlloc комбинацией вызовов GlobalFree + GlobalAlloc
4. Обработка ошибок:
Pointer GlobalReallocPtr(Pointer P, unsigned long Bytes, int Flags)
{
HGLOBAL hGlobal = ::GlobalHandle(P);
if ( hGlobal == NULL )
DebugSystemError(_T("GlobalReallocPtr::GlobalHandle"));
// Хендл невалиден изначально. Дальнейшие действия бессмысленны
::GlobalUnlock(hGlobal);
// Неплохо бы проверять результат GlobalUnlock и предпринимать действия если память
// осталась залоченной
hGlobal = ::GlobalReAlloc(P, (SIZE_T) Bytes, (UINT) Flags);
if ( hGlobal == NULL )
DebugSystemError(_T("GlobalReallocPtr::GlobalReAlloc"));
// Новый хендл (hGlobal) невалиден. Но при этом старый хендл остается валидным,
// где и как это обрабатывается невидно, как минимум старому хендлу
// надо сказать GlobalLock, я бы в этом случае попробовал бы выделить память повторно через
// через GlobalFree() GlobalAlloc и если была бы неудача вызвал бы исключение
// так же не видно как именно обрабатывается исключение и что происходит с Memory
Pointer Ptr = ::GlobalLock(hGlobal);
if ( Ptr == NULL )
DebugSystemError(_T("GlobalReallocPtr::GlobalLock"));
return Ptr;
};
Re[8]: dll грузиться в не верное адрессное пространство
Спасибо за рекомендации. Вы развеяли мои сомнения. Я понимал, что происходит крушение кучи, но мне казалось, что при возникновение такой ситуации должное сообщение должно происходить незамедлительно, а как выяснялось нет. До этого подобные ошибки проявлялись сразу и в одном и том же месте. Поэтому я грешил на потоки, предполагал, что один поток портит кучу другому. В общем буду анализировать код.
P.S.
Только что пообщался с Адамом Червински из COMPUWARE Europe B.V. . Качаю DevPartner for Visual C++ BoundsChecker Suite 8.2, надеюсь поможет.
-= The Alien//Ufocomp =-
Re[10]: dll грузиться в не верное адрессное пространство
Здравствуйте, NailS, Вы писали:
A>>Последний Output: NS>[skip][/skip]
NS>Сложно удаленно сказать в чем ошибка, видя только часть кода. NS>Если работа с выделенной памятью идет только через класс CMemoryStream то выход за границы области можно попробовать проанализировать по коду доступа к памяти, который в исходных сообщениях отсутствует.
Я могу поделиться исходниками библиотеки, собственно весь "проблемный" код в ней, но как мне кажеться Вам будет мало приятно копаться в тысяче строк кода.