Skip to content

Can't find a way to generate a function that allocates memory #1121

Open
@Alovchin91

Description

@Alovchin91
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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions