Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: DLL и память  (Прочитано 32448 раз)
0 Пользователей и 5 Гостей смотрят эту тему.
ezus
Опытный

il
Offline Offline

« : 13-06-2011 13:52 » 

Добрый день.

Есть DLL, обращение к которой выполняется через  LoadLibrary и GetProcAddress.
И DLL, и программа написаны на С++ 6.0.

Вопросы:
1. Тело DLL размещается в своем адресном пространстве или в адресном пространстве вызывающей программы?
2. Может ли вызывающая программа в процессе подготовки данных испортить тело  DLL?

Спасибо.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #1 : 13-06-2011 14:38 » 

Код DLL размешается в расшаренной памяти. Т.е. для всех процессов Dll загружается только 1 раз. Потом система только расшаривает код. Ты с юзер мода не сможеш что либо затереть в коде DLL. Вот область переменных для каждого процесса своя.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
ezus
Опытный

il
Offline Offline

« Ответ #2 : 13-06-2011 15:10 » 

Тогда, что может быть причиной падения?
Программа падает на операторе
Код:
           memcpy(str2,Conditions->GetAt(j),LEN_FM_DESCRIP);
что в кодах
Код:
     102198F1   jb          CopyUnwindUp (1021991c)
=>   102198F3   rep movs    dword ptr [edi],dword ptr [esi]
     102198F5   jmp         dword ptr [edx*4+10219A08h]
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #3 : 13-06-2011 15:14 » 

ezus, А что есть str2. Что возвращает Conditions->GetAt(j). Ну и что есть LEN_FM_DESCRIP?
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 13-06-2011 20:43 » 

Для DLL, хотя она находится в адресном пространстве процесса, есть ньюансы с выделением и освобождением памяти. Кратко всё сводится к правилу: где выделил память, там и освободи. На выделенную в основной программе память можно передать указатель в DLL, чтобы та могла читать или писать в эту память. Но освобождать память должна также основная программа. Если DLL выделяет память, она может передать указатель в основную программу, чтобы та могла читать или писать в эту память. Но освобождать память должна также DLL.

А в случае memcpy может банальный выход за границы принимающего буфера, который меньше размера копируемых данных.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Ochkarik
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 14-06-2011 00:17 » 

Dimka, серьезно? по поводу выделения-освобождения памяти?
всегда считал что разницы не должно быть - кто выделяет а кто освобождает....
почему так? где почитать можно?
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #6 : 14-06-2011 03:03 » 

Ochkarik, потому, что аллокаторы, умные указали, буфер на стеке и т.д. и т.п. Улыбаюсь
Тоже может касаться не только dll, но и статик библиотек и даже классов с функциями

Ты не знаешь, какием способом была выделена память и выделялась ли вообще, может это был malloc, а не new или библиотека заранее создала 10 элементов одним массивом и отдала тебе только один элемент, а ты решил, что его можно грохнуть через delete
Записан

Странно всё это....
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 14-06-2011 04:35 » 

Ochkarik, где почитать - не знаю. "И опыт - сын ошибок трудных..." Устное предание Улыбаюсь

Если основная программа собрана, допустим, в Debug, а DLL - в Release, то в этих режимах сборки выделение памяти происходит по-разному (в Debug память выделяется с запасом). Поэтому такой невинный на первый взгляд подход, как выделение памяти в программе, а освобождение - в DLL, приводит к access violation. EXE и DLL - разные исполняемые файлы, и в них влинкованы собственные экземпляры стандартной и прочих статических библиотек, или же идёт обращение к разным версиям DLL из Microsoft'овских библиотека (с суффиксом D и без оного).
« Последнее редактирование: 14-06-2011 08:03 от Dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #8 : 14-06-2011 05:25 » 

А в случае memcpy может банальный выход за границы принимающего буфера, который меньше размера копируемых данных.

Это действительно банальный, но действенный вывод, хотя я считал, что memcpy не проверяет выход за границу, а сбой на нем может быть только при залезании в запретные зоны, кратные страницам памяти. Поэтому размер принимающего буфера тут неважен.
Записан
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #9 : 14-06-2011 05:47 » 

ezus, очень наивно. Это как кидать мусор из окна, считая, что до своего этажа куча еще не скоро дорастет.
Размер нужно высчитывать точно, или брать с запасом. Либо проверять перед копированием - сравнивать длину данных и размер буфера. Если это действительно строка, то добавь еще место для терминирующего нуля.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
ezus
Опытный

il
Offline Offline

« Ответ #10 : 14-06-2011 05:50 » 

А что есть str2. Что возвращает Conditions->GetAt(j). Ну и что есть LEN_FM_DESCRIP?
Я знал, что такие вопросы возникнут, но не хотел пудрить мозги уважаемому сообществу всякими мелочами, надеялся, что ответа на основной вопрос мне хватит.
Но видимо придется поподробничать.

Большая программа, множество DLLs и LIBs.
Моя проблема возникает в следующей ситуации:
Выполняется два шага, каждый из которых запускается независимо своими пунктами в меню.

1-ый - это расчет. Большой, может продолжаться часами и жрать море памяти. Результаты сохраняет в MS Access. Комментировать:fie:.Решение не мое.

2-ой - это отчет по результатам расчета. Исходные данные читает из MS Access.

Расчет расположен в головной программе, а отчет в DLL.

Программа падает, если запускать отчет после расчета.
По отдельности все работает. Т.е., если запускать отчет после рестарта программы, то все ОК.

Сам сбой возникает только при работе с одним из 30 проектов, с остальными все нормально. Причем и с этим чертовым проектом не все однозначно, играясь с данными можно заставить его напечататься.

Загрузка DLL выполняется непосредственно перед вызовом функции печати на втором шаге.

У меня уже крыша едет. Я никак не могу нашупать идеи.

Буду благодарен любым подсказкам, мыслям, ассоциациям.

Добавлено через 3 минуты и 49 секунд:
очень наивно. Это как кидать мусор из окна, считая, что до своего этажа куча еще не скоро дорастет.
Размер нужно высчитывать точно, или брать с запасом. Либо проверять перед копированием - сравнивать длину данных и размер буфера. Если это действительно строка, то добавь еще место для терминирующего нуля.
Все верно, но проблема ведь не в этом.
Если в поле под 10 символов я запишу 20, то программа от этого не упадет на операторе записи. Она может упасть потом(дай б-г), когда затертая память будет использоваться, но не в момент записи, как у меня.
« Последнее редактирование: 14-06-2011 05:54 от ezus » Записан
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #11 : 14-06-2011 06:13 » 

Цитата
Если в поле под 10 символов я запишу 20, то программа от этого не упадет на операторе записи. Она может упасть потом(дай б-г), когда затертая память будет использоваться, но не в момент записи, как у меня.

Ну-ну. Удачной охоты за багами.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
ezus
Опытный

il
Offline Offline

« Ответ #12 : 14-06-2011 06:30 » 

Цитата
Если в поле под 10 символов я запишу 20, то программа от этого не упадет на операторе записи. Она может упасть потом(дай б-г), когда затертая память будет использоваться, но не в момент записи, как у меня.

Ну-ну. Удачной охоты за багами.
Не понял Я был не прав?
Программа упадет в момент выхода за границы?
Записан
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #13 : 14-06-2011 07:16 » 

Какая разница?! Она будет функционировать не верно и это главное. А если она не упадет сразу, то результат работы дальнейшей работы будет непредсказуем.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
ezus
Опытный

il
Offline Offline

« Ответ #14 : 14-06-2011 07:22 » 

Какая разница?! Она будет функционировать не верно и это главное. А если она не упадет сразу, то результат работы дальнейшей работы будет непредсказуем.
Да, большая разница!!!
В данный момент у меня цель другая, не написать программу без ошибок, а НАЙТИ УЖЕ существующую ошибку, чтобы исправивь ее получить "предсказуемую" программу.
Я ищу причину, по которой программа падает. Поэтому, если превышение размеров буфера не приводит к мгновенному падению, то это не моя ошибка, надо искать, что-то другое.
Записан
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #15 : 14-06-2011 07:52 » 

Проверь:
1. Размер буфера назначения.
2. Корректность указателя источника.

Поставь в отладчике точку останова и просмотри память источника.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #16 : 14-06-2011 08:09 » 

ezus, ты привёл одну строчку кода. Больше мы ничего не знаем. Тебе говорят о том, что в этой строчке может быть проблемным. Кроме сказанного, в ней ничего другого проблемного нет и быть не может. Не хочешь проверять, не хочешь разбираться - чего тогда спрашиваешь?

Или вся тема - не просьба помочь, а способ пожаловаться на трудную жизнь? Ну тогда я лично сочувствую, скорблю и т.д.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Ochkarik
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #17 : 14-06-2011 08:47 » 

Антон (LogRus), Dimka, понял)
каждый раз забываю, что память можно не только через API выделять Жжешь
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
ezus
Опытный

il
Offline Offline

« Ответ #18 : 14-06-2011 10:31 » 

Всем спасибо и за помощь и за сочувствие.
Код не мой, поэтому не сразу обратил внимание, что источник CString.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #19 : 14-09-2011 18:55 » 

прошёлся по дурацким граблям, часа 2 выяснял причину Жаль

Есть программа на C++ и DLL на C++

передавал в DLL из программы указатель на std::string , функция в DLL заполняла контейнер. А в дебаге , в деструкторе контейнера программа валилась (в релизе не валилась)

Оказалось, что если в контейнере, принадлежащем программе, после передачи указателя в DLL производилась переаллокация, то вот тогда этот падёж и возникал. Если зарезервировать нужный объём, а в DLL не переступать границу capacity , то всё ок
Записан

Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #20 : 14-09-2011 19:46 » 

Это частный случай другой темы - о выделении и освобождении памяти в DLL и EXE.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #21 : 14-09-2011 20:04 » 

Dimka, где почитать ?
Записан

Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #22 : 14-09-2011 20:47 » 

Так а что тут читать? При линковке dll получает свою копию функций аллокации, а exe - свою. В общем случае, версии этих функций могут различаться, и в релизе будет валиться тоже. Валиться будет и в том случае, если функции имеют side-effect - то есть, аллокация/освобождение памяти сопровождаются изменением каких-то глобальных переменных: собственно, в debug так и происходит, поскольку там есть дополнительные проверки насчёт того, выделялась ли вообще освобождаемая память, и нужно ли по этому поводу вызывать деструктор(ы).

Вообще, экспорт типов (в том числе, и std::string) из dll должен помогать. По крайней мере, мне, помнится, приходилось подобным образом решать проблему работы контейнеров через границу модуля: наследовал какой-то стандартный контейнер и делал экспорт/импорт (если не ошибаюсь, можно и напрямую экспортировать). Как результат, весь код компилируется в составе dll, и методы контейнера (в их числе, разумеется, и производящие аллокацию) вызываются из кода dll. Хотя это может быть не очень удобно в общем случае.
« Последнее редактирование: 14-09-2011 20:52 от Вад » Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #23 : 15-09-2011 04:38 » 

Вад, ну суть то я понял, почему так произошло )

>>экспорт типов (в том числе, и std::string) из dll должен помогать.
а это как делается ?
Записан

Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #24 : 15-09-2011 08:13 » 

>>экспорт типов (в том числе, и std::string) из dll должен помогать.
а это как делается ?
http://support.microsoft.com/kb/168958/en-us (не люблю майкрософтовский автоматический перевод на suppot-е, он корявый какой-то)
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #25 : 15-09-2011 08:25 » 

Вад, спасибо, щас почитаю. А перевод - это да, вечная там подстава, и не всегда сразу найдёшь, как инглиш переключить ))

хотя, я заметил, если ссылка оканчивается на "en-us" , то насильного перевода не происходит
Записан

Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines