Подтвердить что ты не робот

Ошибка отладки! Выражение: _pFirstBlock == pHead

Я вызываю статически связанную DLL, и я вижу эту ошибку:

enter image description here

Я написал как .dll, так и код вызова. Эта ошибка не должна возникать. Мне интересно, встречался ли кто-нибудь еще раньше? Файл .dll содержит только около 10 строк кода, это всего лишь тестовая .dll, чтобы увидеть, как работают dll в целом. Он взрывается, когда я передаю std::string обратно из .dll.

Я использую Visual Studio 2012 и С++.

Что я буду делать дальше

От Утверждение отладки... _pFirstBlock == pHead:

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

Завтра я попробую перекомпилировать статические библиотеки Boost в многопоточном режиме (мой .dll установлен в многопоточный статический режим).

Что я буду делать дальше

См. Использование строк в объекте, экспортированном из DLL, вызывает ошибку времени выполнения:

Вам нужно сделать одну из двух вещей

  • Сделайте как DLL, так и клиент, которые используют его как ссылку на DLL-версию CRT (например, не статически).
  • ИЛИ Вам необходимо убедиться, что вы не передаете динамически выделенную память (например, содержащуюся в строковых объектах) через границы DLL. Другими словами, не имеют DLL-экспортированных функций, возвращающих строку объекты.

Джо

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

См. Передача ссылки на вектор STL через границу dll.

Что я буду делать дальше

См. Невозможно передать std:: wstring через DLL.

Решение

У меня есть хорошее решение, см. ответ ниже.

4b9b3361

Ответ 1

В этом случае проблема заключается в том, что я передавал std::string обратно через границу .dll.

Конфигурация библиотеки времени выполнения

  • Если для MSVC Runtime library установлено значение Multi-threaded Debug DLL (/MDd), то это не проблема (он отлично работает).

  • Если для MSVC Runtime library установлено значение Multi-threaded Debug (/MTd), тогда он будет вызывать эту ошибку, которая может быть исправлена ​​с помощью следующих инструкций.

Память, выделенная в диспетчере памяти A и освобожденная в диспетчере памяти B...

Проблема в том, что память выделяется на стороне .dll, тогда эта же память освобождается на стороне приложения. Это означает, что диспетчер памяти A выделяет память, а диспетчер памяти B освобождает ту же память, которая генерирует ошибки.

Решение состоит в том, чтобы гарантировать, что вся память, переданная обратно, не распределена в DLL. Другими словами, память всегда выделяется на стороне приложения и освобождается на стороне приложения.

Конечно, DLL может выделять/освобождать внутреннюю память, но не может выделять память, которая позже освобождается приложением.

Примеры

Это будет не:

// Memory is allocated on the .dll side, and freed on the app side, which throws error.
DLL std::string GetString(); 

Это будет работать:

// Memory is allocated/freed on the application side, and never allocated in the .dll.
DLL int GetString(std::string& text); 

Однако этого недостаточно.

На стороне приложения строка должна быть предварительно выделена:

std::string text("");
text.reserve(1024);     // Reserves 1024 bytes in the string "text".

На стороне .dll текст должен быть скопирован в исходный буфер (вместо того, чтобы перезаписывать память, выделенную на стороне .dll):

text.assign("hello");

Иногда С++ будет настаивать на распределении памяти в любом случае. Дважды проверьте, что предварительное выделение по-прежнему совпадает с тем, что было:

if (text.capacity < 1024)
{
   cout << "Memory was allocated on the .dll side. This will eventually throw an error.";
}

Другим способом, который работает, является использование std::shared_ptr<std::string>, поэтому даже если память выделена в .dll, она освобождается .dll(а не стороной приложения).

Еще один способ - принять char * и длину, которая указывает количество предварительно выделенной памяти. Если текст, который мы хотим передать назад, длиннее длины предварительно выделенной памяти, верните ошибку.

Ответ 2

Это то, что assert() выглядит, когда его аргумент выражения оценивается как false. Это утверждение существует в сборке Debug библиотеки времени выполнения C, предназначенной для проверки проблем с распределением. Функция free() в вашем случае. В сборке Debug добавляются дополнительные проверки, чтобы убедиться, что вы правильно пишете свой код. И скажите, когда он обнаружит проблему. Как и вызов free() на выделение, которое уже было освобождено, простой случай. Или вызов free(), передающий неправильное значение указателя, более сложный случай. Или вызов free(), когда куча была повреждена более ранним кодом, гораздо сложнее.

Это только, насколько они могут это понять, они действительно не знают, почему ваш код ошибочно. Нет никакого способа, чтобы они могли помещать большую красную стрелку на код, который испортил кучу, например. Легкий случай покрывается окном отладки Debug + Windows + Call Stack, он переводит вас в код в вашей программе, который называется free(). Или std::operator delete для программы на С++. Более трудный случай очень, очень тяжелый, куча коррупции часто является Гейзенбугом. Получение повторяемости для утверждения, чтобы вы могли установить точку останова данных на указанном адресе, является основной стратегией. Пересечение пальцев для легкого случая, удача с ним!


После редактирования: да, проблемы с кросс-модулем с классом С++, например std::string, безусловно, являются одной из проблем, которые он может поймать. Не Гейзенбуг, хорошая проблема. Две основные проблемы:

  • Модули могут иметь свою собственную копию ЭЛТ, объекты, выделенные одной копией ЭЛТ, не могут быть выпущены другой копией ЭЛТ. У каждого из них есть своя куча, от которой они выделяются. Проблема, которая была решена в VS2012, теперь CRT выделяет из процесса глобальную кучу.
  • Модули могут не использовать ту же реализацию std::string. С макетом объекта, который не соответствует. Легко вызвано наличием модулей, скомпилированных с разными версиями библиотеки С++, особенно с изменениями в С++ 11. Или разные настройки сборки, макрос _HAS_ITERATOR_DEBUGGING довольно известен.

Единственное лекарство от этой проблемы - убедиться, что вы создадите все модули в своей программе с помощью той же самой версии компилятора, используя те же самые настройки сборки. Использование /MD является обязательным, это гарантирует, что CRT будет общим, поэтому в программе будет только один.

Ответ 3

Вероятная причина: привязка к неправильной версии Qt DLL, особенно при перемещении проекта из VS2010 в VS2012.

Это связано с различными версиями стандартной библиотеки и связанными с ней проблемами динамического распределения.

Ответ 4

У меня была такая же проблема после переустановки Windows. В моей библиотеке Runtime была многопоточная Debug DLL (/MDd).

Моим решением было удалить файл *.user проекта visual studio, удалить папку отладки и перестроить проект.