Сейчас на форуме: zds (+5 невидимых)

 [email protected] —› Программирование —› Затирание переменных, объявленных в куче
Посл.ответ Сообщение

Ранг: 17.4 (новичок)
Активность: 0.010
Статус: Участник

Создано: 19 февраля 2014 13:25 · Поправил: Wagos
· Личное сообщение · #1

Добрый день.
Проблема следующая - иногда при вызове библиотечных функций (MessageBox, ShowMessage и тд), а также - при динамическом выделении памяти (new, delete), затираются значения в структурах и массивах, также, объявленных в куче. Код не выкладываю, т. к. проект здоровый и затирание данных образуется в местах, никак не связанных друг с другом. Т. е. вызывается функция, в которой присутствуют вышеуказанные вызовы и после выполнения, к примеру, вызова TStringList* strList = new TStringList(); могут рандомно измениться значения в другой ранее объявленной структуре. Оперативной памяти с запасом. У кого-нибудь возникали подобные проблемы?
Среда разработки: Embarcadero C++ Builder XE2.




Ранг: 72.3 (постоянный), 133thx
Активность: 0.380
Статус: Участник

Создано: 19 февраля 2014 13:27
· Личное сообщение · #2

Отследить момент затирания мы получим затирающий код



Ранг: 17.4 (новичок)
Активность: 0.010
Статус: Участник

Создано: 19 февраля 2014 13:30
· Личное сообщение · #3

Dr0p, Момент затирания - в функции выделения памяти. Не понятно, почему она выделяет память в уже выделенной области. Думаю, что-то с настройками компилятора. Хотя, пока не знаю.




Ранг: 1053.6 (!!!!), 1078thx
Активность: 1.060.81
Статус: Участник

Создано: 19 февраля 2014 13:32
· Личное сообщение · #4

вам нужен отладчик использованой памяти
--> Link <--
выбирайте любой

| Сообщение посчитали полезным: Wagos

Ранг: 17.4 (новичок)
Активность: 0.010
Статус: Участник

Создано: 19 февраля 2014 13:38
· Личное сообщение · #5

reversecode, Спасибо, посмотрим, что получится.



Ранг: 488.1 (мудрец), 272thx
Активность: 0.350
Статус: Участник

Создано: 19 февраля 2014 14:45 · Поправил: VodoleY
· Личное сообщение · #6

Wagos могу сказать точно. в делфи/билдере очень большие проблемы с динамическим выделением памяти, часто все сыпится.. либо переписывайте код на статик переменные.. либо следите за стеком.. либо юзайте др. либу FastMM вроде.. типа альтернатива
то... что происходит с динамическими переменными.. вообще шоу.. типа попробуйте сделать в цикле SetLength переменной .. массиву.. раз 50... с рандомным значением.. и прозреете

-----
Наша работа во тьме, Мы делаем, что умеем. Мы отдаем, что имеем, Наша работа во тьме....


| Сообщение посчитали полезным: Wagos, dosprog

Ранг: 17.4 (новичок)
Активность: 0.010
Статус: Участник

Создано: 19 февраля 2014 15:53 · Поправил: Wagos
· Личное сообщение · #7

VodoleY, Спасибо, а со стеком что? Динамическая память-же выделяется вне стека




Ранг: 72.3 (постоянный), 133thx
Активность: 0.380
Статус: Участник

Создано: 19 февраля 2014 16:15
· Личное сообщение · #8

Dr0p

Какие аргументы в функции, видимо указатель кривой ?



Ранг: 488.1 (мудрец), 272thx
Активность: 0.350
Статус: Участник

Создано: 19 февраля 2014 16:19
· Личное сообщение · #9

Wagos ну давай логически.. MessageBox, ShowMessage в конце концов АПИ вызывают.. еслиб проблемы были в них.. сыпалась бы винда. если сыпяться они, значит не правильно кним параметры приходят.. самая первая проблема.. это гдето у тебя идет нескомпенсированный стек.. и этим функам приходит на вход мусор.

-----
Наша работа во тьме, Мы делаем, что умеем. Мы отдаем, что имеем, Наша работа во тьме....




Ранг: 17.4 (новичок)
Активность: 0.010
Статус: Участник

Создано: 19 февраля 2014 16:24 · Поправил: Wagos
· Личное сообщение · #10

Dr0p, Самое забавное, что после удаления нескольких вызовов функций, проблемы исчезли (инструкции по выделению памяти работают корректно).
Кстати, забыл, сказать - до этого была ещё одна проблема. Данные в динамической памяти менялись даже после простого вызова функции. В отладчике было видно, что после выполнения call'a (помещения в стек адреса возврата), шустро менялись некоторые переменные в структуре. Чем это объяснить, я не знаю.

VodoleY, Это да, но функции корректно отрабатывают. Иначе бы я имел эксепшен, я думаю (в большинстве случаев).



Ранг: 488.1 (мудрец), 272thx
Активность: 0.350
Статус: Участник

Создано: 19 февраля 2014 17:21
· Личное сообщение · #11

Wagos пишет:
Иначе бы я имел эксепшен, я думаю (в большинстве случаев).

конкретно на этих функах редко

-----
Наша работа во тьме, Мы делаем, что умеем. Мы отдаем, что имеем, Наша работа во тьме....




Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 19 февраля 2014 18:14 · Поправил: F_a_u_s_t
· Личное сообщение · #12

Гейзенбаги довольно частое явление, падает в одном месте, ошибка совершенно в другом.
Пользуйтесь логирами, что то типа eurekalog и какой нибудь утилитой для детекта утечек памяти.
Скорее всего дело в инвалидных параметрах и стек\указатель летит к еб@ням.

| Сообщение посчитали полезным: Wagos

Ранг: 112.9 (ветеран), 186thx
Активность: 0.090.01
Статус: Участник

Создано: 19 февраля 2014 19:39 · Поправил: vden
· Личное сообщение · #13

Wagos пишет:
Момент затирания - в функции выделения памяти. Не понятно, почему она выделяет память в уже выделенной области.

Скорее всего выделяет память правильно, а старая область уже освобождена. Указатель, естественно, неправильный. Лучше использовать FreeAndNil (обнулять указатель после освобождения класса), тогда будет легче найти обращение к NULL.



Ранг: 17.4 (новичок)
Активность: 0.010
Статус: Участник

Создано: 19 февраля 2014 20:06
· Личное сообщение · #14

F_a_u_s_t, Спасибо!
vden, Дело в том, что старая - не освобождена, а содержит данные, которыми нужно оперировать. При динамическом выделении часть этой области памяти заполняется мусором, что приводит к краху приложения.



Ранг: 431.7 (мудрец), 390thx
Активность: 0.730.32
Статус: Участник

Создано: 19 февраля 2014 21:22 · Поправил: dosprog
· Личное сообщение · #15

Wagos,
MessageBox() ничего не пишет, поэтому, думаю, не в самих аргументах дело.
Попробуйте убрать всякую оптимизацию при компиляции, попробуйте другую версию того же компилятора...

Правда, есть у меня старинная программка, так та глючит после компиляции на всей линейке MSVC 2..6, если не указать определённые опции компиляции (подбиралось втыком). Глючит при входе в одну из процедур. Я нашёл это место в .EXE - там явный косяк компилятора.
Проявлялется похожим образом, как у вас.

До сих пор у меня в makefile лежит пояснение:
Code:
  1. # GOOD!CODE ("-Od")                  
  2. ------------------          
  3. xor eax,eax
  4. mov al,[ebp][8]                    
  5. mov ecx,eax
  6. lea eax,[eax][eax]*4               
  7. lea eax,[ecx][eax]*2               
  8. mov eax,[00049CC20][eax]*8 ;OK!
  9. #
  10. #
  11. # BAD!CODE     ("-Ox")
  12. ---------------------
  13. xor ecx,ecx        ;BAD!!! Must be EAX,EAX !!!
  14. mov cl,[ebp][8]
  15. mov al,cl
  16. lea edx,[ecx][ecx]*4
  17. lea ecx,[eax][edx]*2
  18. mov ebx,[000471C20][ecx]*8 ;BAD!!!!!!!!!
  19. #
  20. -----------------------------------------
  21. # Use "-O1" option (optimize for size only)
Так что, бывает всяко...



| Сообщение посчитали полезным: Wagos

Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 19 февраля 2014 21:56
· Личное сообщение · #16

dosprog пишет: так та глючит после компиляции на всей линейке MSVC 2..6

Отладка студийных приложений и отладка делфи\билдер сильно отличается, во втором все проще из за информативности самого компилятора.
Лично мне для отладки таких багов хватает EurekaLog и AQtime, остальную мелочь показывает сам компиль.
В какой то версии студии был баг с разбором свитча, часть выкидывалось, нормально работало только с выключенным оптимизатором.
Хотя такие баги компиля редкость, зачастую ошибки алгоритмические, если в цикле приходится выделять и освобождать память, то стоит пересмотреть алгоритм, так ли это обязательно, поскольку довольно дорогая операция и довольно легко сделать баги.
У многих патологическое пристрастие экономить на спичках, при этом не замечая бревен.
Часто вижу вопрос - какой выбрать алгоритм хеширования, что бы избежать коллизий ( хэши для файлов ), пилять, какая тут разница, если подсчет хэша ничто по сравнению с чтением файла в память.
Это к тому, что иногда полезно пересмотреть алгоритмы, а не подпирать костылями из дефайнов и хаков.



Ранг: 431.7 (мудрец), 390thx
Активность: 0.730.32
Статус: Участник

Создано: 19 февраля 2014 22:03 · Поправил: dosprog
· Личное сообщение · #17

F_a_u_s_t,
Билдер вообще меня доводил до исступления своими багами. Там их половина из-за ilink.exe.
Поэтому лежит у меня BC 5.1 (не 5.2!) . А билдера нету вовсе.
MSVC корректнее в разы работает, как трактор. Но бывают и там чудеса (как в примере выше).
Согласен, что зачастую помогает исправление или изменение алгоритма.
Всё это хорошо работает, если нет глюков при компиляции/трансляции. А у меня уже патологическая боязнь их.



Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 19 февраля 2014 22:09
· Личное сообщение · #18

dosprog пишет: Билдер вообще меня доводил до исступления своими багами.

Старого билдера уже нет, сейчас clang с хаками для vcl, которые по прежнему с багами, которые никто не правит, кроме комьюнити.
Политика борланда\кодегира\эмбарко мне чем то напоминает политику Ильфака, с той лишь разницей, что в жопу не посылают прямым текстом, баглисты годами весят в неизменном виде и по большей части правятся компоненто писателями ( если VCL ), а так, появляются новые фичи, но толку с поддержки iOS если компилятор говно и приложение не пройдет ревью, фич много, а работает все через жопу, хороший пример хорошей идеи с хреновой реализацией.



Ранг: 17.4 (новичок)
Активность: 0.010
Статус: Участник

Создано: 20 февраля 2014 07:30 · Поправил: Wagos
· Личное сообщение · #19

Установка FastMM результата не дала. CodeGuard молчит. Попробую что-нибудь увидеть с помощью Eurekalog (пока не получается включить опцию "утечки памяти", но решение есть). Ещё есть мысль использовать __fastcall'ы - попробую - отпишусь.
Любопытства ради посмотрел через PEiD версию компилятора. "Borland C++ 1999". Может, конечно, подмена сигнатур, но иногда действительно кажется, что компилятор не обновлялся 15 лет.



Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 20 февраля 2014 08:14 · Поправил: F_a_u_s_t
· Личное сообщение · #20

Wagos пишет: Eurekalog (пока не получается включить опцию "утечки памяти", но решение есть).
Статья Ищем утечки памяти.

Wagos пишет: Любопытства ради посмотрел через PEiD версию компилятора. "Borland C++ 1999".
Сигнатура кривая, компилятор обновлялся, но кодогенератор это не особо затронуло, а в самом же компиляторе обновлений много, в первую очередь это поддержка стандарта, хотя сам компилятор старый, на базе Clang только x64 версия.
Пруф: хоть бы свежим GCC собрали, версия 4.2 древняя, как говно мамонта.




Ранг: 17.4 (новичок)
Активность: 0.010
Статус: Участник

Создано: 21 февраля 2014 19:15 · Поправил: Wagos
· Личное сообщение · #21

F_a_u_s_t, Спасибо за статью. Хорошая. Пока решил проблему уменьшением количества функций - скоро проект сдавать. Если ещё что-нибудь надумаю, напишу здесь.

Цикл вызова функций (Класс TStringList): Create -> NewInstance -> GetMem -> FastGetMem (Функция FMM. Здесь, видимо, получается разрешение на использование ранее выделенной памяти) -> InitInstance (Окончательно забивается моя память всякой не нужной мне х@@нёй с помощью инструкции rep stosd).

Ещё раз проштудировал код. Затираемый элемент находится в массиве структур, выделенный с помощью malloc и дальнейшим realloc (Векторы ненавижу, а для расширения массива не хотелось производить махинации с new - delete). Возможно, проблема в том, что данная память не заблокирована Виндой.

Ещё одно наблюдение. При выделении памяти в конструкторе класса, все идет нормально. Если выделять память в методе данного класса, начинается волшебство.

Увеличение размера кучи и стека - также не дало эффекта. Любит менеджер памяти выделять память в моей структуре.



Ранг: 17.4 (новичок)
Активность: 0.010
Статус: Участник

Создано: 23 февраля 2014 23:05
· Личное сообщение · #22

Ребята, проблема решена! Решением является выделение памяти в глобальной куче с помощью функций GlobalAlloc, GlobalLock, GlobalReAlloc и GlobalFree. В этом случае все работает корректно.


 [email protected] —› Программирование —› Затирание переменных, объявленных в куче
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати