Повреждение кучи при возврате из функции внутри dll

У меня есть функция с прототипом, как показано ниже:

void function(std::string str);

Эта функция вызывается в моей основной функции в другой программе, которая загружает и использует эту DLL.

function("some string value here");

При возврате из этой функции я получаю ошибку повреждения кучи:

Windows запустила точку останова в program.exe.

Это может быть связано с повреждением кучи, что указывает на ошибку в
program.exe или любая из загруженных библиотек.

Это также может быть связано с тем, что пользователь нажимает клавишу F12, пока
Программа.exe имеет фокус.

Окно вывода может иметь больше диагностической информации.

Играя с моим кодом, я заметил несколько странных наблюдений:
1. Когда длина передаваемой строки меньше 11 символов, я не получаю ошибок, как только я добавляю больше символов, появляется ошибка.
2. При изменении типа параметра с std::string в std::string& ошибка исчезает. Идея передачи ссылки пришла от Вот.
3. Я закомментировал тело функции. Операции там не имеют ничего общего с произведенным исключением.
4. Изменение типа параметра с std::string в char* также решает проблему.
Что может быть причиной этой ошибки? Как мне это решить?

7

Решение

Скорее всего, вы видите сбои из-за того, что в Windows DLL имеют свою собственную кучу.

Когда вы скомпилировали свою функцию, компилятор сгенерировал некоторый код для std::stringДеструктор, чтобы очистить свои аргументы. Этот код освобождает выделенную память в куче DLL. Тем не менее, приложение EXE также генерирует свой собственный код для std::stringконструктор, который размещает код в куче программы. Когда вы выделяете одну кучу, а свободную — другую, возникает неопределенное поведение, и вы вылетаете.

Что касается того, почему маленькие строки не вызывают ошибку — многие std::string Реализации встраивают небольшие строки в саму структуру, чтобы избежать накладных расходов. Когда ваша строка достаточно мала, чтобы уместиться, не требуется выделять память, и, таким образом, она, кажется, работает … до тех пор, пока вы используете одну и ту же версию STL для EXE и DLL, и порог для встраивания никогда не меняется.

Чтобы избежать этой проблемы, не передавайте объекты по значению в DLL (если они не POD объекты) и не освобождайте объект в другой DLL или EXE, чем он был создан. Избегайте передачи объектов библиотеки STL или C ++, так как их реализация может отличаться в разных версиях компилятора C ++. Передавать объекты POD или C примитивные типы, такие как const char * вместо.

8

Другие решения

При экспорте функций DLL лучше всего, если они принимают только целочисленные типы данных, т. Е. Int или указатели (не уверенны относительно float и double).

Когда вам нужно передать строку, передайте ее как const char *, когда вам нужна функция DLL для возврата строки, передайте в DLL char * указатель на предварительно выделенный буфер, в который DLL записывает строку.

Никогда не используйте память, выделенную DLL за пределами собственных функций DLL, и никогда не передавайте структуры значений, которые имеют свой собственный конструктор / деструктор.

6

Возможно, вы связали со статической версией среды выполнения C, никогда не стоит создавать DLL, связанную со статической версией среды исполнения C. Это может вызвать много проблем, например, в вашей программе ваш EXE выделяет память из частной кучи статической среды выполнения C, с которой он связан, затем в вашей DLL вы хотите удалить эту кучу и создать новую кучу (так как вы хотите добавить некоторые данные для входной строки, и он должен увеличить свой буфер), так что это приведет к ошибке. Простейший подход к этому состоит в том, чтобы связать все части вашей программы (EXE и DLL) с DLL-версией среды выполнения C, чтобы они все использовали одну и ту же кучу из MSVCRTXX.dll.

5
По вопросам рекламы [email protected]