ezus
Опытный
Offline
|
|
« : 13-06-2011 13:52 » |
|
Добрый день.
Есть DLL, обращение к которой выполняется через LoadLibrary и GetProcAddress. И DLL, и программа написаны на С++ 6.0.
Вопросы: 1. Тело DLL размещается в своем адресном пространстве или в адресном пространстве вызывающей программы? 2. Может ли вызывающая программа в процессе подготовки данных испортить тело DLL?
Спасибо.
|
|
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #1 : 13-06-2011 14:38 » |
|
Код DLL размешается в расшаренной памяти. Т.е. для всех процессов Dll загружается только 1 раз. Потом система только расшаривает код. Ты с юзер мода не сможеш что либо затереть в коде DLL. Вот область переменных для каждого процесса своя.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
ezus
Опытный
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
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #3 : 13-06-2011 15:14 » |
|
ezus, А что есть str2. Что возвращает Conditions->GetAt(j). Ну и что есть LEN_FM_DESCRIP?
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #4 : 13-06-2011 20:43 » |
|
Для DLL, хотя она находится в адресном пространстве процесса, есть ньюансы с выделением и освобождением памяти. Кратко всё сводится к правилу: где выделил память, там и освободи. На выделенную в основной программе память можно передать указатель в DLL, чтобы та могла читать или писать в эту память. Но освобождать память должна также основная программа. Если DLL выделяет память, она может передать указатель в основную программу, чтобы та могла читать или писать в эту память. Но освобождать память должна также DLL.
А в случае memcpy может банальный выход за границы принимающего буфера, который меньше размера копируемых данных.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Ochkarik
|
|
« Ответ #5 : 14-06-2011 00:17 » |
|
Dimka, серьезно? по поводу выделения-освобождения памяти? всегда считал что разницы не должно быть - кто выделяет а кто освобождает.... почему так? где почитать можно?
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
Антон (LogRus)
|
|
« Ответ #6 : 14-06-2011 03:03 » |
|
Ochkarik, потому, что аллокаторы, умные указали, буфер на стеке и т.д. и т.п. Тоже может касаться не только dll, но и статик библиотек и даже классов с функциями Ты не знаешь, какием способом была выделена память и выделялась ли вообще, может это был malloc, а не new или библиотека заранее создала 10 элементов одним массивом и отдала тебе только один элемент, а ты решил, что его можно грохнуть через delete
|
|
|
Записан
|
Странно всё это....
|
|
|
Dimka
Деятель
Команда клуба
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
Опытный
Offline
|
|
« Ответ #8 : 14-06-2011 05:25 » |
|
А в случае memcpy может банальный выход за границы принимающего буфера, который меньше размера копируемых данных.
Это действительно банальный, но действенный вывод, хотя я считал, что memcpy не проверяет выход за границу, а сбой на нем может быть только при залезании в запретные зоны, кратные страницам памяти. Поэтому размер принимающего буфера тут неважен.
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #9 : 14-06-2011 05:47 » |
|
ezus, очень наивно. Это как кидать мусор из окна, считая, что до своего этажа куча еще не скоро дорастет. Размер нужно высчитывать точно, или брать с запасом. Либо проверять перед копированием - сравнивать длину данных и размер буфера. Если это действительно строка, то добавь еще место для терминирующего нуля.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
ezus
Опытный
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
Пол:
|
|
« Ответ #11 : 14-06-2011 06:13 » |
|
Если в поле под 10 символов я запишу 20, то программа от этого не упадет на операторе записи. Она может упасть потом(дай б-г), когда затертая память будет использоваться, но не в момент записи, как у меня. Ну-ну. Удачной охоты за багами.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
ezus
Опытный
Offline
|
|
« Ответ #12 : 14-06-2011 06:30 » |
|
Если в поле под 10 символов я запишу 20, то программа от этого не упадет на операторе записи. Она может упасть потом(дай б-г), когда затертая память будет использоваться, но не в момент записи, как у меня. Ну-ну. Удачной охоты за багами. Я был не прав? Программа упадет в момент выхода за границы?
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #13 : 14-06-2011 07:16 » |
|
Какая разница?! Она будет функционировать не верно и это главное. А если она не упадет сразу, то результат работы дальнейшей работы будет непредсказуем.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
ezus
Опытный
Offline
|
|
« Ответ #14 : 14-06-2011 07:22 » |
|
Какая разница?! Она будет функционировать не верно и это главное. А если она не упадет сразу, то результат работы дальнейшей работы будет непредсказуем.
Да, большая разница!!! В данный момент у меня цель другая, не написать программу без ошибок, а НАЙТИ УЖЕ существующую ошибку, чтобы исправивь ее получить "предсказуемую" программу. Я ищу причину, по которой программа падает. Поэтому, если превышение размеров буфера не приводит к мгновенному падению, то это не моя ошибка, надо искать, что-то другое.
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #15 : 14-06-2011 07:52 » |
|
Проверь: 1. Размер буфера назначения. 2. Корректность указателя источника.
Поставь в отладчике точку останова и просмотри память источника.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #16 : 14-06-2011 08:09 » |
|
ezus, ты привёл одну строчку кода. Больше мы ничего не знаем. Тебе говорят о том, что в этой строчке может быть проблемным. Кроме сказанного, в ней ничего другого проблемного нет и быть не может. Не хочешь проверять, не хочешь разбираться - чего тогда спрашиваешь?
Или вся тема - не просьба помочь, а способ пожаловаться на трудную жизнь? Ну тогда я лично сочувствую, скорблю и т.д.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Ochkarik
|
|
« Ответ #17 : 14-06-2011 08:47 » |
|
Антон (LogRus), Dimka, понял) каждый раз забываю, что память можно не только через API выделять
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
ezus
Опытный
Offline
|
|
« Ответ #18 : 14-06-2011 10:31 » |
|
Всем спасибо и за помощь и за сочувствие. Код не мой, поэтому не сразу обратил внимание, что источник CString.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #19 : 14-09-2011 18:55 » |
|
прошёлся по дурацким граблям, часа 2 выяснял причину Есть программа на C++ и DLL на C++ передавал в DLL из программы указатель на std::string , функция в DLL заполняла контейнер. А в дебаге , в деструкторе контейнера программа валилась (в релизе не валилась) Оказалось, что если в контейнере, принадлежащем программе, после передачи указателя в DLL производилась переаллокация, то вот тогда этот падёж и возникал. Если зарезервировать нужный объём, а в DLL не переступать границу capacity , то всё ок
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #20 : 14-09-2011 19:46 » |
|
Это частный случай другой темы - о выделении и освобождении памяти в DLL и EXE.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #21 : 14-09-2011 20:04 » |
|
Dimka, где почитать ?
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #22 : 14-09-2011 20:47 » |
|
Так а что тут читать? При линковке dll получает свою копию функций аллокации, а exe - свою. В общем случае, версии этих функций могут различаться, и в релизе будет валиться тоже. Валиться будет и в том случае, если функции имеют side-effect - то есть, аллокация/освобождение памяти сопровождаются изменением каких-то глобальных переменных: собственно, в debug так и происходит, поскольку там есть дополнительные проверки насчёт того, выделялась ли вообще освобождаемая память, и нужно ли по этому поводу вызывать деструктор(ы).
Вообще, экспорт типов (в том числе, и std::string) из dll должен помогать. По крайней мере, мне, помнится, приходилось подобным образом решать проблему работы контейнеров через границу модуля: наследовал какой-то стандартный контейнер и делал экспорт/импорт (если не ошибаюсь, можно и напрямую экспортировать). Как результат, весь код компилируется в составе dll, и методы контейнера (в их числе, разумеется, и производящие аллокацию) вызываются из кода dll. Хотя это может быть не очень удобно в общем случае.
|
|
« Последнее редактирование: 14-09-2011 20:52 от Вад »
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #23 : 15-09-2011 04:38 » |
|
Вад, ну суть то я понял, почему так произошло )
>>экспорт типов (в том числе, и std::string) из dll должен помогать. а это как делается ?
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #24 : 15-09-2011 08:13 » |
|
>>экспорт типов (в том числе, и std::string) из dll должен помогать. а это как делается ?
http://support.microsoft.com/kb/168958/en-us (не люблю майкрософтовский автоматический перевод на suppot-е, он корявый какой-то)
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #25 : 15-09-2011 08:25 » |
|
Вад, спасибо, щас почитаю. А перевод - это да, вечная там подстава, и не всегда сразу найдёшь, как инглиш переключить ))
хотя, я заметил, если ссылка оканчивается на "en-us" , то насильного перевода не происходит
|
|
|
Записан
|
|
|
|
|