调试断言失败!表达式:__ acrt_first_block == header

时间:2016-02-10 08:29:58

标签: c++ visual-studio-2015

我正在尝试测试我用GoogleTest编写的dll,当我调用其中一个测试时它会抛出这个错误:

enter image description here

我得出结论,问题在于为向量分配内存,但我不知道如何解决这个问题,因为我对C ++编程很新。代码如下:

#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;
}

6 个答案:

答案 0 :(得分:33)

由于这是一个DLL,问题可能在于用于分配和释放的不同堆(尝试静态构建库并检查它是否有效)。

问题是,DLL和模板不能很好地达成一致。通常,根据MSVC运行时的链接,如果内存在可执行文件中分配并在DLL中解除分配,反之亦然(因为它们可能具有不同的堆),则可能会出现问题。这很容易发生在模板上,例如:push_back()到DLL中removeWhiteSpaces()内的向量,因此向量内存在DLL内部分配。然后在可执行文件中使用输出向量,一旦它超出范围,它就会被释放,但在可执行文件中,其堆不知道有关它已分配的堆的任何内容。砰,你死了。

如果DLL和可执行文件都使用相同的堆,则可以解决此问题。为了确保这一点,DLL和可执行文件都必须使用动态MSVC运行时 - 因此请确保它们都动态链接到运行时,而不是静态链接。特别是,exe应该与/ MD [d]和带有/ LD [d]或/ MD [d]的库一起编译和链接,两者都没有/ MT [d]。请注意,之后运行应用程序的计算机将需要运行MSVC运行时库(例如,通过为特定的MSVC版本安装“Visual C ++ Redistributable”)。

即使使用/ 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)

编辑:最终解决方案实际上是在多线程调试DLL(/ MDd)中构建所有项目(exe,dll和整个googleTest项目) /强> (默认情况下,GoogleTest项目是在多线程调试(/ MTd)中构建的)

答案 1 :(得分:2)

我遇到了类似的问题,事实证明我的unittest项目设置为不同的代码生成运行时库 - 因此通过将其设置为与DLL项目相同,则没有堆异常

答案 2 :(得分:1)

我也看到了此错误,就我而言,我正确排列了所有内存模型设置。但是最近将项目从vs2013升级到vs2015,我在.exe和.dll之间有过时的引用,因此实际上我使用的是由2013内置的旧DLL。我必须删除.exe和.dll之间的引用,然后重新-添加它以更新exe链接所针对的.lib的名称。 (右键单击.exe项目的“ References”子项,然后单击“ Add”,但同时也使您难以删除引用)。

答案 3 :(得分:1)

该验证是很早以前由Microsoft软件开发人员在 1992-1993 中实施的,它不再有效,因为在异构或MPI编程的情况下,可能无法从本地分配新的内存堆。

当应用程序使用OpenCL或CUDA API获取内存时,GPU驱动程序会执行所有内存分配,当然,它不会使用应用程序的本地堆。但是,应用程序应在退出之前释放内存。那时,Microsoft的Memory Leaks Detection API可以检测到它并显示该断言。

请查看有关该验证来源的视频技术报告:

MS Visual Studio 2015声明__acrt_first_block ==标头(VTR-010)的来源 https://www.youtube.com/watch?v=NJeA_YkLzxc

注意:自从我上传了经过更正的视频以来,与youtube视频的网络链接已更新。

答案 4 :(得分:1)

我遇到了相同的错误,我找到了一种获取有关问题原因的更多信息的方法:可以在Visual Studio上设置引发此错误的行上的breakpoint condition(以便调试器之前出现错误消息)。

有必要打开相应的文件(debug_heap.cpp,在“ C:\ Program Files(x86)\ Windows Kits \ 10 \ Source”中的某个位置)并编写以下条件:

enter image description here

然后,我们可以继续调试,并在遇到断点时,可以观察到引发错误的块的地址(包含断点的“ free_dbg_nolock”函数的“ block”自变量)。

从那里,您可以通过将地址复制到内存窗口(Debug-> Windows-> Memory)中来观察块的内存内容。如果幸运的话,它可能是字符串或易于识别的变量。

然后您可以识别导致该错误的变量并尝试对其进行修复。

在我的情况下,这是在一个dll中创建并在另一个dll中删除的变量。为了更正它,我用一个dll中指向这些对象的指针替换了所有对象。

答案 5 :(得分:1)

我在 Microsoft Visual Studio 2019 中遇到了同样的问题,只需将“运行时库”更改为“多线程调试 DLL (/MDd)”即可解决

<块引用> <块引用>

右键单击“解决方案资源管理器”->“属性”->“C/C++”->“代码生成”,将“运行时库”更改为“多线程调试DLL(/MDd)”< /p>