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

Я пытаюсь протестировать DLL, которую я написал в GoogleTest, и когда я вызываю один из тестов, он вызывает эту ошибку:

enter image description here

Я пришел к выводу, что проблема заключается в назначении памяти для векторов, но я не знаю, как это решить, поскольку я довольно новичок в программировании на С++. Код выглядит следующим образом:

#ArraysCPP11.h
#ifdef ARRAYSCP11_EXPORTS
#define ARRAYSCP11_API __declspec(dllexport)
#else
#define ARRAYSCP11_API __declspec(dllimport)
#endif

__declspec(dllexport) void removeWhiteSpaces(std::vector<std::string> v, std::vector<std::string> &output);
#ArraysCPP11.cpp
void removeWhiteSpaces(std::vector<std::string> v, std::vector<std::string> &output) { //odstranjevanje presledkov iz vector-ja (vsak drugi element je bil presledek)
    for (std::vector<std::string>::iterator it = v.begin(); it != v.end(); it++) {
        std::string buffer = *it;
        if (isdigit(buffer[0])){;
            output.push_back(*it);
        }
    }
}
#TestTemp.h

template<class T> 
class TestTemp
{
public:
   TestTemp();
   void SetValue(T obj_i);
   T GetValue();
   bool alwaysTrue();
   bool TestTemp<T>::formattingTest(std::string input, std::vector<std::string> realVector, std::vector<std::string> formattedInput);
private:
   T m_Obj;
};

template<class T>
inline bool TestTemp<T>::formattingTest(std::string input, std::vector<std::string> realVector, std::vector<std::string> formattedVector) {
std::string input2 = input;
//  std::vector<std::string> fResult;
std::string first;
std::string second;
bool endResult = true;
std::vector<std::string> end;
//std::vector<std::string> result = split(input2, ' ');
removeWhiteSpaces(formattedVector,end);
std::vector<std::string>::iterator yt = realVector.begin();
for (std::vector<std::string>::iterator it = end.begin(); it != end.end(); it++, yt++) {
    first = *it;
    second = *yt;
    if (first.compare(second) != 0) {
        endResult = false;
        break;
    }
}
return endResult;
}
   #ArraysCPP11-UnitTest.cpp
struct formattingTesting{
   //   formattingTesting* test;
   std::string start;
   std::vector<std::string> endResult;
   formattingTesting() {
   }
   explicit formattingTesting(const std::string start, const std::vector<std::string> endResult)
    : start{start}, endResult{endResult} 
   {
   }
};

struct fTest : testing::Test {
   formattingTesting* test;
   fTest() {
      test = new formattingTesting;
   }
   ~fTest() {
      delete test;
   }
};

struct format {
   std::string start;
   std::vector<std::string> end;
};

struct formTest : fTest, testing::WithParamInterface<format> {
   formTest() {
      test->start = GetParam().start;
      test->endResult = GetParam().end;
   }
};

TEST_P(formTest, test1) {
   bool endResult = true;
   TestTemp<int> TempObj;
   std::string first;
   std::string second;
   //std::string start ("1  2 3 4 5 6 7 8 9 10");
   //std::vector<std::string> end = { "1","2","3","4","5","6","7","8","9","10" };
   std::vector<std::string> start2 = { "1","","2","3","4","5","6","7","8","9","10" };
   std::string start = GetParam().start;
   std::vector<std::string> end = GetParam().end;
   bool result = TempObj.formattingTest(start,end,start2);      
   EXPECT_TRUE(result);
}

INSTANTIATE_TEST_CASE_P(Default, formTest, testing::Values(
   format{ "1", {"1"} },
   format{ " ", {} },
   format{ "1 2 3 4 5",{"1","2","3","4","5"} },
   format{ "1  2 3 4 5  6", {"1","2","3","4","5","6"} }
));


int main(int argc, char** argv)
{
   testing::InitGoogleTest(&argc, argv);
   RUN_ALL_TESTS();
   return 0;
}

Ответ 1

Поскольку это DLL, проблема может заключаться в разных кучах, используемых для распределения и освобождения (попробуйте построить библиотеку статически и проверить, будет ли это работать).

Проблема в том, что библиотеки DLL и шаблоны не очень хорошо согласуются друг с другом. В общем, в зависимости от привязки среды выполнения MSVC это может быть проблемой, если память выделена в исполняемом файле и освобождена в DLL и наоборот (потому что у них могут быть разные кучи). И это может произойти с шаблонами очень легко, например: вы push_back() в вектор внутри removeWhiteSpaces() в DLL, поэтому векторная память выделяется внутри DLL. Затем вы используете выходной вектор в исполняемом файле, и как только он выходит из области видимости, он освобождается, но внутри исполняемого файла, чья куча ничего не знает о куче, из которой она была выделена. Банг, ты мертв.

Это можно обойти, если и DLL, и исполняемый файл используют одну и ту же кучу. Чтобы обеспечить это, DLL и исполняемый файл должны использовать динамическую среду выполнения MSVC, поэтому убедитесь, что обе они связаны с динамической динамикой, а не статически. В частности, exe должен быть скомпилирован и связан с /MD [d] и библиотекой с /LD [d] или /MD [d], а также с /MT [d]. Обратите внимание, что впоследствии компьютеру, на котором будет запущено приложение, потребуется запустить исполняемую библиотеку MSVC (например, путем установки "Visual C++" Распространяемый "для конкретной версии MSVC).

Вы можете получить эту работу даже с /MT, но это сложнее - вам нужно будет предоставить некоторый интерфейс, который позволит также освободить объекты, выделенные в DLL. Например, что-то вроде:

__declspec(dllexport) void deallocVector(std::vector<std::string> &x);

void deallocVector(std::vector<std::string> &x) {
    std::vector<std::string> tmp;
    v.swap(tmp);
}

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


EDIT: окончательное решение состояло в том, чтобы иметь все проекты (exe, dll и весь проект googleTest), встроенный в многопоточную DLL Debug (/MDd) (проекты GoogleTest построены в многопоточной отладке (/MTd ) по умолчанию)

Ответ 2

У меня была аналогичная проблема, и оказалось, что мой unittest-проект был настроен на другую библиотеку времени исполнения кода, поэтому, установив ее так же, как проект DLL, тогда исключение кучи

Ответ 3

Я тоже видел эту ошибку, и в моем случае у меня были все настройки модели памяти. Однако, недавно обновив проекты от vs2013 до vs2015, у меня были устаревшие ссылки между.exe и.dll, поэтому на самом деле я использовал старую DLL, построенную с 2013 года. Мне пришлось удалить ссылку между.exe и.dll и re -add, чтобы обновить имя.lib, с которым exe ссылался. (Щелкните правой кнопкой мыши на дочернем элементе "Ссылки" проекта.exe и "Добавить", в то время как смутно также позволяет удалить ссылку).

Ответ 4

Эта проверка была реализована разработчиками программного обеспечения Microsoft давным-давно в 1992 - 1993 гг., и она больше не действительна, поскольку в случае гетерогенного или MPI-программирования новая память может быть выделена не из локальной кучи.

Когда приложение получает память с помощью API-интерфейсов OpenCL или CUDA, драйвер графического процессора выполняет все выделения памяти и, конечно же, не использует локальную кучу приложения. Тем не менее, приложение должно освободить память до его выхода. В это время API обнаружения утечек памяти в Microsoft обнаруживает его, и отображается это утверждение.

Ознакомьтесь с техническим отчетом о происхождении этой проверки:

Происхождение MS Visual Studio 2015 Assert __acrt_first_block == заголовок (VTR-010) https://www.youtube.com/watch?v=NJeA_YkLzxc

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