Здравствуйте, Tom, Вы писали:
A>>А много ноликов? Может проще найти места где пишется много ноликов? Все ZeroMemory для начала? Tom>Нереально, обьём кода огромный, да и написан при помощи spagetti style
Нет, просто пусть ZeroMemory не только обнуляет память но и журналирует адрес/размер облулённого участка. Учитывая что это макрос, "перехватить" его можно простым #define.
Здравствуйте, adontz, Вы писали:
A>Здравствуйте, Tom, Вы писали:
A>>>А много ноликов? Может проще найти места где пишется много ноликов? Все ZeroMemory для начала? Tom>>Нереально, обьём кода огромный, да и написан при помощи spagetti style
A>Нет, просто пусть ZeroMemory не только обнуляет память но и журналирует адрес/размер облулённого участка. Учитывая что это макрос, "перехватить" его можно простым #define.
Простого дефайна скорее всего не хватит, потому как эта функция(на самом деле это макрос) может вызыватся откуда угодно.
Здравствуйте, Plutonia Experiment, Вы писали:
PE>Простого дефайна скорее всего не хватит, потому как эта функция(на самом деле это макрос) может вызыватся откуда угодно.
Ну, во-первых, можно ключик /D компилятора использовать, а, во-вторых, ради такого и windows.h подправить не жалко.
Здравствуйте, adontz, Вы писали:
A>Здравствуйте, Plutonia Experiment, Вы писали:
PE>>Простого дефайна скорее всего не хватит, потому как эта функция(на самом деле это макрос) может вызыватся откуда угодно.
A>Ну, во-первых, можно ключик /D компилятора использовать, а, во-вторых, ради такого и windows.h подправить не жалко.
Здравствуйте, Tom, Вы писали:
Tom>Уж незнаю в какой этот форум, модераторы если что поправят.
Tom>Опишу ситуацию, есть некоторое распределённое/клиент серверное приложение, и живёт в нём хитрый и злой мега баг. Хитрый мега баг проявляется тем, что иногда срёт в чужую память нулями (любя мы называем его засранцем ). А хитрый и злой он потому, что мы только видим его последствия — испорченная память, и НИКОГДА не видим кто именно какает. В приложении при каждом системном исключении создаются дампы памяти, так что мы контролируем каждый AV (создаём дампы внутри Vectored Exceptions Handler-а). Много гоняли под Application Verifier, не очень много под Dev Partner-ом, под Dev Partner-ом не можем сильно гонять, так как он убивает всю производительность. Собсно нужны какие то принципиальные идеи как его может быть и как енту каку выловить.
А можно подробности. А то я тут две недели ловил схожэий баг (правдо, "везло" не КОМу).
Дело было в связке. многопоточность + stl от 6-й стидии (дело было под виндой).
Если окружение схожее — свисти, расскажу.
Возможно, некая ошибка вызывает порчу стека и точек возврата из функций соответственно. После чего, код начинает "гулять" по произвольным местам... Поэтому, не можете заловить, кто это делает (может не раскручиваться стек функций или не вызываться какие-то catch-блоки).
Например, из-за того, что где-то аргументы для форматирования строк неправильные?
Здравствуйте, rus blood, Вы писали:
RB>Здравствуйте, Tom, Вы писали:
RB>Возможно, некая ошибка вызывает порчу стека и точек возврата из функций соответственно. После чего, код начинает "гулять" по произвольным местам... Поэтому, не можете заловить, кто это делает (может не раскручиваться стек функций или не вызываться какие-то catch-блоки).
Ого, гуляющий код, это круто! Я вообще склоняюсь к мысли, что надо всё переписать под .Net
P.S. Кажется я опять отнял чей-то хлеб
Здравствуйте, adontz, Вы писали:
A>Ого, гуляющий код, это круто! Я вообще склоняюсь к мысли, что надо всё переписать под .Net A>P.S. Кажется я опять отнял чей-то хлеб
Поверь, буквально недавно такое наблюдал.
Можешь сам попробовать. Пример сделать несложно.
RB>>Поверь, буквально недавно такое наблюдал. RB>>Можешь сам попробовать. Пример сделать несложно.
Tom>Ээээ а разве возможно порчей стека добиться того, что "Vectored Exceptions Handler" будет не вызываться? Мне кажется он к стеку совсем не относится...
Порчей стека можно добиться теоретически чего угодно. Например, есть шанс, что стек попортится, сформировав валидный с\с++ компилятор + код драйвера, все это дело откомпилится, установится и будет писать нолики куда захочет. Вероятность подобного события оставляю посчитать вам
А вообще, конечно, если серьезно, самый лучший вариант в таких случаях — дихотомия. Как говорится, гильотина — лучее средство от головной боли. Располовинивать, пока не выявится хотя бы модуль, ответственный за баг. Впрочем, и этот метод часто не приносит никаких результатов. Сам недавно общался с таким проектом
Здравствуйте, Tom, Вы писали:
Tom>Хитрый мега баг проявляется тем, что иногда срёт в чужую память нулями
Мне в свое время подобные глюки удалось свести практически к нулю таким вот комплексом мер:
Собственный менеджер динамической памяти (я делал переопределением new/delete, но может оказаться проще сделать библиотеку со своими xxxAlloc/xxxFree и подсунуть при линковке). Менеджер создает классические обрамляющие поля вокруг каждого блока, расписывая их известными константами, а сами блоки забивает мусором с установленным старшим битом, чтобы проще ловились неинциализированные указатели.[/*]
В начало конструктора каждого класса, если объекты создаются не динамически, вставляется забивание всего объекта таким же мусором.[/*]
В каждом классе имеется функция Check, вызываемая из каждого мало-мальски важного метода, и проверяющая целостность объекта.[/*]
По коду раскиданы Assert'ы, регулярно проверяющие как условия выполнения, так и целостность кучи, основных списков, ключевых объектов и т.п.[/*]
Таким образом практически сразу ловятся всяческие недоинициализации и порчи, без контроля приводящие к отдаленным эффектам типа Вашего. Собственно, многое из этого есть в перечисленных сторонних тулзах, но мне было удобнее реализовать гибкий встроенный контроль, введя переменную для глубины контроля, чтобы понапрасну не тормозило.
Еще имеет смысл проверить функции на побочные эффекты. Я как-то около месяца не мог найти, отчего портились некоторые поля в двухпроцессорной конфигурации, но только в отладочной сборке — релиз работал безупречно. В итоге выяснилось, что IsBadWritePtr, который я на автомате пользовал еще с 16-разрядного кода, проверяет тупой перезаписью, и при отсутствии синхронизации может испортить данные, которые меняет параллельный поток.
Хотя заниматься всем перечисленным в спагетти-коде — врагу не пожелаю
Здравствуйте, Tom, Вы писали:
Tom>Ээээ а разве возможно порчей стека добиться того, что "Vectored Exceptions Handler" будет не вызываться? Мне кажется он к стеку совсем не относится...
Ну представь, вызвался твой handler, а на выходе из него команда ret переносит исполнение кода не обратно в систему и на вызов следующего handler-а, а куда-то в [censored]. И другие handler-ы могут не вызываться...
Ну вот пример. На коленке и работает только под отладкой, но м.б. будет понятно, что я хочу сказать...
Если модификацию стека в VectoredHandler2 не делать, то вызываются оба хандлера.
Если испортить стек в VectoredHandler2, то можно сделать так, чтобы VectoredHandler1 не вызовется.
long WINAPI VectoredHandler1(PEXCEPTION_POINTERS pstEI)
{
// не вызывается...return EXCEPTION_CONTINUE_SEARCH;
}
long WINAPI VectoredHandler2(PEXCEPTION_POINTERS pstEI)
{
// Пример для отладки - типа меняем адрес возврата на мусор.
// В моем случае точка 0x00416B75 - вызов первой RemoveVectoredExceptionHandler в main.
DWORD dw;
__asm mov dw, ebp;
dw += sizeof(DWORD);
*(DWORD*)(void*)dw = 0x00416B75;
return EXCEPTION_CONTINUE_SEARCH;
}
int _tmain(int argc, _TCHAR* argv[])
{
void* p1 = AddVectoredExceptionHandler(1, VectoredHandler1);
void* p2 = AddVectoredExceptionHandler(2, VectoredHandler2);
__try
{
int x = 1;
int y = 0;
int z = x / y;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
RemoveVectoredExceptionHandler(p1);
RemoveVectoredExceptionHandler(p2);
return 0;
}
Здравствуйте, Andrew S, Вы писали:
AS>Порчей стека можно добиться теоретически чего угодно. Например, есть шанс, что стек попортится, сформировав валидный с\с++ компилятор + код драйвера, все это дело откомпилится, установится и будет писать нолики куда захочет. Вероятность подобного события оставляю посчитать вам
Ну я не про причину появления ноликов, а про то, что поймать не удается...
Да и вообще, м.б. где-то есть ошибка, не связананная с ноликами, а появление ноликов — результат перехвата этой ошибки.
ЕМ>Собственный менеджер динамической памяти (я делал переопределением new/delete, но может оказаться проще сделать библиотеку со своими xxxAlloc/xxxFree и подсунуть при линковке). Менеджер создает классические обрамляющие поля вокруг каждого блока, расписывая их известными константами, а сами блоки забивает мусором с установленным старшим битом, чтобы проще ловились неинциализированные указатели.[/*] ЕМ>В начало конструктора каждого класса, если объекты создаются не динамически, вставляется забивание всего объекта таким же мусором.[/*] ЕМ>В каждом классе имеется функция Check, вызываемая из каждого мало-мальски важного метода, и проверяющая целостность объекта.[/*] ЕМ>По коду раскиданы Assert'ы, регулярно проверяющие как условия выполнения, так и целостность кучи, основных списков, ключевых объектов и т.п.[/*] ЕМ>
ага и добавлю, что все это в настоящее время делает Driver Verifier & Application Verifier
так что городить все вышеприведенное имеет смысл на ОС раньше 2000, где еще такого счастья не было
да и App Verifier автору топика не помог, он сразу это написал
PS отмечу что подобные "свои" или стянутые у Руссиновича verifiers (MemAllocatePool and other MemXxx wrappers кто помнит) были практически у всех разработчиков в то время...
... << RSDN@Home 1.2.0 alpha rev. 648>>
Valery A. Boronin, RSDN Team, linkedin.com\in\boronin
R&D Mgmt & Security. AppSec & SDL. Data Protection and Systems Programming. FDE, DLP, Incident Management. Windows Filesystems and Drivers.
Здравствуйте, Tom, Вы писали:
Tom>Опишу ситуацию, есть некоторое распределённое/клиент серверное приложение, и живёт в нём хитрый и злой мега баг. Хитрый мега баг проявляется тем, что иногда срёт в чужую память нулями (любя мы называем его засранцем ). А хитрый и злой он потому, что мы только видим его последствия — испорченная память, и НИКОГДА не видим кто именно какает. В приложении при каждом системном исключении создаются дампы памяти, так что мы контролируем каждый AV (создаём дампы внутри Vectored Exceptions Handler-а). Много гоняли под Application Verifier, не очень много под Dev Partner-ом, под Dev Partner-ом не можем сильно гонять, так как он убивает всю производительность. Собсно нужны какие то принципиальные идеи как его может быть и как енту каку выловить.
если известна область памяти которая затирается — если повезет и она одна и та же иногда, то есть решение
— подключите к машине отладчик удаленный (WinDbg + VM Ware сгодится)
— путем проигрывания проблемного сценария в виртуалке (чтобы шансы на воспроизведение были выше, лучше заснапшотить поближе к моменту падения и одно и тоже состояние проигрывать в надежде на те же адреса и т.п.), можно сделать так:
— сначала падаем и смотрим по какому адресу проблема, адрес-диапазон запоминаем
— перезапуск виртуалки и в отладчике ставим бряки на запись по этому адресу
— удим рыбу
... << RSDN@Home 1.2.0 alpha rev. 648>>
Valery A. Boronin, RSDN Team, linkedin.com\in\boronin
R&D Mgmt & Security. AppSec & SDL. Data Protection and Systems Programming. FDE, DLP, Incident Management. Windows Filesystems and Drivers.
Ага, щаз Их не иначе, как телепаты писали, и научили догадываться, как проверять целостность каждого объекта И статически размещенные объекты они тоже мусором прописывают, чтобы правильность инициализации в конструкторе проверить?
VAB>PS отмечу что подобные "свои" или стянутые у Руссиновича verifiers (MemAllocatePool and other MemXxx wrappers кто помнит) были практически у всех разработчиков в то время...
Только блоки памяти проверять — это меньшая часть заботы...
Может поможет
Помню такую эпопею
Немодальный диалог созданый через new -> PostNcDestroy-> в нем delete this;
И в каком-то обработчике (сейчас хоть убей не помню толи WM_TIMER) без проверки на
::IsWindow(m_hWnd) модифицировалось int поле класса диалога уже после delete this;
Причем этот адрес был уже другим блоком (хотя не всегда)
Тоесть как ты говорищ какало в другие блоки
[Skip]
VAB>если известна область памяти которая затирается — если повезет и она одна и та же иногда, то есть решение
VAB>- подключите к машине отладчик удаленный (WinDbg + VM Ware сгодится) VAB>- путем проигрывания проблемного сценария в виртуалке (чтобы шансы на воспроизведение были выше, лучше заснапшотить поближе к моменту падения и одно и тоже состояние проигрывать в надежде на те же адреса и т.п.), можно сделать так: VAB>- сначала падаем и смотрим по какому адресу проблема, адрес-диапазон запоминаем VAB>- перезапуск виртуалки и в отладчике ставим бряки на запись по этому адресу VAB>- удим рыбу
Могу предложить даже готовое решение как выловить такое место.
Есть такой продукт SmartHeap, который реализует скоростной менеджер кучи (подменяются все New, Alloc, etc.). В нем есть Debug DLL со множествами способов отладки таких ситуаций:
1. К каждому выделенному указателю присобачивается вначале и в конце дополнительные контрольные байты. Если их кто то перетер то через секунд 5 (настривается) выскакивает диалжг "Типа AAA указатель такой то был перетерт" — типа переполнение буфера, с дикой информацией Время выделения, CallStack выделения, Поток, иеще куча всего.
2. Некоторые указатели можна поставить на мониторинг, система буте следить что бы в них ничего не изменилось, случайно Работает по принципу чеканья области памяти на CRC через определенное время
3. DeferFree — интересная штука. Вы освобождаете указатель, но система не отдает его обратно в кучу, а держит его определенное время, забивает его специальными символами и следит что бы в него никто не записал.
4. Может и не все вспомнил... Читайте что можна тут: HeapAgent. Если заинтересовало, могу для теста выслать (продукт совсем и даже очень не бесплатный)
Здравствуйте, Danchik, Вы писали:
D>Здравствуйте, Valery A. Boronin, Вы писали:
D>[Skip]
VAB>>если известна область памяти которая затирается — если повезет и она одна и та же иногда, то есть решение
VAB>>- подключите к машине отладчик удаленный (WinDbg + VM Ware сгодится) VAB>>- путем проигрывания проблемного сценария в виртуалке (чтобы шансы на воспроизведение были выше, лучше заснапшотить поближе к моменту падения и одно и тоже состояние проигрывать в надежде на те же адреса и т.п.), можно сделать так: VAB>>- сначала падаем и смотрим по какому адресу проблема, адрес-диапазон запоминаем VAB>>- перезапуск виртуалки и в отладчике ставим бряки на запись по этому адресу VAB>>- удим рыбу
D>Могу предложить даже готовое решение как выловить такое место. D>Есть такой продукт SmartHeap, который реализует скоростной менеджер кучи (подменяются все New, Alloc, etc.). В нем есть Debug DLL со множествами способов отладки таких ситуаций:
D>1. К каждому выделенному указателю присобачивается вначале и в конце дополнительные контрольные байты. Если их кто то перетер то через секунд 5 (настривается) выскакивает диалжг "Типа AAA указатель такой то был перетерт" — типа переполнение буфера, с дикой информацией Время выделения, CallStack выделения, Поток, иеще куча всего.
D>2. Некоторые указатели можна поставить на мониторинг, система буте следить что бы в них ничего не изменилось, случайно Работает по принципу чеканья области памяти на CRC через определенное время
D>3. DeferFree — интересная штука. Вы освобождаете указатель, но система не отдает его обратно в кучу, а держит его определенное время, забивает его специальными символами и следит что бы в него никто не записал.
D>4. Может и не все вспомнил... Читайте что можна тут: HeapAgent. Если заинтересовало, могу для теста выслать (продукт совсем и даже очень не бесплатный)
Если можно — вышли
PS:
А чем вышеописанные действия отличаются от того, что делает DevPartner? Просто с ним воспроизвести данный баг — нереально, из за огромного падения производительности