C++向C#返回enum时出现double free tcache 2错误
问题:C++与C# enum跨语言传递导致退出时double free错误
在Linux .NET6环境下,实现C++与C#之间的enum双向传递时,程序功能正常,但退出时会触发free(): double free detected in tcache 2错误并产生核心转储。经排查:
- 仅在C向C#返回enum时出现问题,C#向C传递enum无异常
- 将C++的
Test函数改为void返回值后,程序可正常退出 - 疑惑enum本质是int类型,仅值拷贝无动态内存操作,为何会出现内存错误
相关代码
C++头文件(编译为.so)
enum class Example : int { Item0 = 0, Item1 = 1, Item2 = 2 }; extern "C" Example Test(Example ex);
C++源文件
#include "header.h" #include <iostream> extern "C" { Example Test(Example ex) { std::cout << "Received enum: " << static_cast<int>(ex) << std::endl; return Example::Item2; // 返回enum会触发问题 } }
C#代码(控制台程序)
[DllImport(DLL, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Test")] static extern Example Test(Example ex); Example ex = Test(Example.Item0); Console.WriteLine("Enum: " + ex.ToString()); enum Example : int { Item0 = 0, Item1 = 1, Item2 = 2 }
程序输出
$ dotnet test.dll Received enum: 0 Enum: Item2 free(): double free detected in tcache 2 Aborted (core dumped)
原因分析与解决方案
问题核心是C++强类型枚举enum class的ABI与.NET P/Invoke的处理逻辑不匹配:虽然enum class底层是int,但它属于C++强类型,部分编译器会将其视为非POD(Plain Old Data)类型,返回值通过栈传递;而.NET P/Invoke默认假设返回值是通过寄存器传递的int,这会导致栈内存被错误地重复释放,触发double free。
解决方案1:显式传递int类型
将C++返回值转换为int,C#接收后再转为本地enum:
- C++修改:
extern "C" int Test(Example ex) { std::cout << "Received enum: " << static_cast<int>(ex) << std::endl; return static_cast<int>(Example::Item2); } - C#修改:
[DllImport(DLL, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Test")] static extern int Test(Example ex); // 调用时转换 int resultInt = Test(Example.Item0); Example ex = (Example)resultInt; Console.WriteLine("Enum: " + ex.ToString());
解决方案2:改用C风格枚举
去掉C++中的class关键字,使用兼容C的普通枚举,此时编译器会将其视为int兼容的POD类型,P/Invoke可正确处理:
- C++头文件修改:
原C#代码无需修改,即可正常运行且无内存错误。enum Example : int { Item0 = 0, Item1 = 1, Item2 = 2 };
内容的提问来源于stack exchange,提问作者user2205930
相关产品推荐
相关产品推荐

