Безопасно ли выделять память для буферов на внешней DLL и использовать ее в основном приложении? - PullRequest
3 голосов
/ 28 января 2010

Как в теме .. Я нашел что-то подобное в одном приложении. В основном приложении C у нас есть объявление:

void* buff = NULL;

и позже есть звонок:

ReadData(&buff);
SaveToFile(buff);

SaveToFile() - это функция C из основной функции.

ReadData(void* * ) - это функция C ++ из внешней библиотеки DLL. В этой функции память для буфера выделяется функцией malloc и заполняется данными.

Так вот мой вопрос: это правильно?

Ответы [ 6 ]

12 голосов
/ 28 января 2010

Все модули в работающем процессе имеют одно и то же адресное пространство (не важно, Windows вы или Linux или что-то еще, это общий принцип). Однако будьте осторожны: чтение или запись из модуля A в буфер, принадлежащий модулю B, в порядке, но освобождение буфера, вероятно, плохо.

В Windows это зависит от библиотеки времени выполнения, с которой связано приложение. Если это не среда выполнения DLL ( 'многопоточная DLL' ), каждый модуль поддерживает свою собственную копию менеджера кучи. Таким образом, модуль, который выделил область памяти, также должен отвечать за ее уничтожение, поскольку об этом знает только его собственный менеджер кучи. Если вы будете следовать этому руководству, у вас не возникнет проблем (связывание со средой выполнения DLL позволяет избежать этой проблемы, поскольку все модули работают с одним и тем же менеджером кучи, находящимся где-то в msvXXXnnn.dll, но порождают другие проблемы).

Edit:

ReadData (void * *) - это функция C ++ из внешней библиотеки DLL. В этой функции память для буфера выделяется функцией malloc и заполняется данными.

Это может столкнуться с вышеупомянутой проблемой распределителя. Либо добавьте еще одну функцию к этой DLL (FreeData), которая явно отвечает за освобождение буфера (как предложил Нил Баттерворт) и просто вызывает свою собственную free(). Или вы добавляете функцию DLL, чтобы запросить размер буфера, выделить его заранее и передать его в ReadData (это самый чистый выбор imo).

2 голосов
/ 28 января 2010

Это безопасно. Тем не менее, вы всегда должны проверять:

  • если один и тот же распределитель используется как для выделения, так и для освобождения
  • кто отвечает за освобождение (так что никаких сюрпризов)
  • следите за любым видом автоматического запоминания памяти (если это простой C / C ++, тогда это не проблема).
2 голосов
/ 28 января 2010

Если и DLL, и основной исполняемый файл были связаны с одной и той же средой выполнения C, это нормально, и вы можете вызвать free () для указателя, чтобы освободить его. Однако в DLL лучше использовать функцию FreeData (void *), которая освобождает данные. Таким образом, все управление памятью осуществляется в контексте DLL.

1 голос
/ 28 января 2010

Это зависит от замысла проекта и пользователей, на которых ориентирована библиотека. Лучший способ - взять буфер определенного размера, заполнить его и вернуть. Но вы должны быть осторожны при освобождении буфера. Лучше вызывать бесплатную функцию (если таковая имеется), предоставляемую самой сторонней DLL, а не вызывать free из основного.

В случае окон, если сторонняя DLL использует другую кучу и если ваше приложение использует другую кучу, это может привести к неопределенному поведению. Например: если сторонняя DLL создается с использованием VC8, а ваше приложение - с использованием VC6, то если вы освободите память, выделенную вашей внешней DLL, это приведет к проблемам.

0 голосов
/ 28 января 2010

Да, с этим проблем нет.

0 голосов
/ 28 января 2010

Да, это правильно. Память в процессе одинаково доступна всем модулям (EXE и DLL) в этом процессе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...