Description
Brief Description
I couldn't find a way to setup the generator so it correctly generates a function that allocates the memory and returns it as an out parameter.
OS: Windows
Used headers
#define CS_OUT
typedef struct test_struct_t test_struct_t;
typedef struct test_pool_t test_pool_t;
void create_test_struct(CS_OUT test_struct_t** result, test_pool_t* pool);
The function create_test_struct
allocates a new test_struct_t
from the pool
, and returns pointer to this struct to the caller -- so result
is a pointer to a pointer.
Used settings
Target: MSVC (I think)
public void Setup(Driver driver)
{
driver.Options.GeneratorKind = GeneratorKind.CSharp;
var module = driver.Options.AddModule("TestModule");
module.IncludeDirs.Add(Environment.CurrentDirectory);
module.Headers.Add("TestHeader.h");
}
public void SetupPasses(Driver driver)
{
driver.AddTranslationUnitPass(new CheckMacroPass());
}
Stack trace or incompilable generated code
public unsafe partial class TestHeader
{
public partial struct __Internal
{
[SuppressUnmanagedCodeSecurity]
[DllImport("TestModule", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.Cdecl,
EntryPoint="?create_test_struct@@YAXPEAPEAUtest_struct_t@@PEAUtest_pool_t@@@Z")]
internal static extern void CreateTestStruct(global::System.IntPtr result, global::System.IntPtr pool);
}
public static void CreateTestStruct(out global::TestModule.TestStructT result, out global::TestModule.TestPoolT pool)
{
result = new global::TestModule.TestStructT();
var __arg0 = ReferenceEquals(result, null) ? global::System.IntPtr.Zero : result.__Instance;
pool = new global::TestModule.TestPoolT();
var __arg1 = ReferenceEquals(pool, null) ? global::System.IntPtr.Zero : pool.__Instance;
__Internal.CreateTestStruct(__arg0, __arg1);
global::TestModule.TestStructT __result0;
if (__arg0 == IntPtr.Zero) __result0 = null;
else if (global::TestModule.TestStructT.NativeToManagedMap.ContainsKey(__arg0))
__result0 = (global::TestModule.TestStructT) global::TestModule.TestStructT.NativeToManagedMap[__arg0];
else __result0 = global::TestModule.TestStructT.__CreateInstance(__arg0);
result = __result0;
global::TestModule.TestPoolT __result0;
if (__arg1 == IntPtr.Zero) __result0 = null;
else if (global::TestModule.TestPoolT.NativeToManagedMap.ContainsKey(__arg1))
__result0 = (global::TestModule.TestPoolT) global::TestModule.TestPoolT.NativeToManagedMap[__arg1];
else __result0 = global::TestModule.TestPoolT.__CreateInstance(__arg1);
pool = __result0;
}
}
The problem with this code is that it doesn't treat the result
parameter as a pointer to pointer, e.g. an out parameter of the native function. So it passes it to NativeToManagedMap
and __CreateInstance
as is instead of dereferencing it first.
This code is also incompilable because of this:
global::TestModule.TestStructT __result0;
if (__arg0 == IntPtr.Zero) __result0 = null;
...
result = __result0;
global::TestModule.TestPoolT __result0;
if (__arg1 == IntPtr.Zero) __result0 = null;
...
pool = __result0;
In this case, two variables with the same name __result0
are declared. This of course leads to a compilation error. The second variable should have been called __result1
here.