From b9895c96568cb38ac90b807b1be085eed6e22dda Mon Sep 17 00:00:00 2001 From: Fan Yang <52458914+fanyang-mono@users.noreply.github.com> Date: Tue, 5 Sep 2023 10:55:06 -0400 Subject: [PATCH] [release/6.0-staging] [Mono] Fix offset calculation for nested struct, when pinvoke is enabled (#91424) * Fix offset calculation for nested struct, when pinvoke is enabled * Fix test failure --- src/mono/mono/mini/mini-amd64.c | 4 +- .../PInvoke/GameControllerButtonBind.cs | 63 +++++++++++++++++++ .../PInvoke/MarshalStructAsParamDLL.cpp | 5 ++ .../PInvoke/MarshalStructAsParamDLL.h | 23 +++++++ .../StructMarshalling/PInvoke/NestedStruct.cs | 27 ++++++++ .../PInvoke/NestedStruct.csproj | 14 +++++ src/tests/issues.targets | 6 ++ 7 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 src/tests/Interop/StructMarshalling/PInvoke/GameControllerButtonBind.cs create mode 100644 src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.cs create mode 100644 src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.csproj diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 4bcbcd9caa917..b615bc37060c0 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -363,7 +363,7 @@ collect_field_info_nested (MonoClass *klass, GArray *fields_array, int offset, g g_assert(info); for (i = 0; i < info->num_fields; ++i) { if (MONO_TYPE_ISSTRUCT (info->fields [i].field->type)) { - collect_field_info_nested (mono_class_from_mono_type_internal (info->fields [i].field->type), fields_array, info->fields [i].offset, pinvoke, unicode); + collect_field_info_nested (mono_class_from_mono_type_internal (info->fields [i].field->type), fields_array, (offset + info->fields [i].offset), pinvoke, unicode); } else { guint32 align; StructFieldInfo f; @@ -373,7 +373,7 @@ collect_field_info_nested (MonoClass *klass, GArray *fields_array, int offset, g info->fields [i].mspec, &align, TRUE, unicode); f.offset = offset + info->fields [i].offset; - if (i == info->num_fields - 1 && f.size + f.offset < info->native_size) { + if ((i == info->num_fields - 1) && ((f.size + f.offset) < (info->native_size))) { /* This can happen with .pack directives eg. 'fixed' arrays */ if (MONO_TYPE_IS_PRIMITIVE (f.type)) { /* Replicate the last field to fill out the remaining place, since the code in add_valuetype () needs type information */ diff --git a/src/tests/Interop/StructMarshalling/PInvoke/GameControllerButtonBind.cs b/src/tests/Interop/StructMarshalling/PInvoke/GameControllerButtonBind.cs new file mode 100644 index 0000000000000..a65994f2307a3 --- /dev/null +++ b/src/tests/Interop/StructMarshalling/PInvoke/GameControllerButtonBind.cs @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Text; + +public unsafe partial struct GameControllerButtonBind +{ + public GameControllerButtonBind + ( + GameControllerBindType? bindType = null, + GameControllerButtonBindValue? value = null + ) : this() + { + if (bindType is not null) + { + BindType = bindType.Value; + } + + if (value is not null) + { + Value = value.Value; + } + } + + public GameControllerBindType BindType; + + public GameControllerButtonBindValue Value; +} + +public enum GameControllerBindType : int +{ + ControllerBindtypeNone = 0x0, + ControllerBindtypeButton = 0x1, + ControllerBindtypeAxis = 0x2, + ControllerBindtypeHat = 0x3, + None = 0x0, + Button = 0x1, + Axis = 0x2, + Hat = 0x3, +} + +[StructLayout(LayoutKind.Explicit)] +public unsafe partial struct GameControllerButtonBindValue +{ + [FieldOffset(0)] + public int Button; + + [FieldOffset(0)] + public int Axis; + + [FieldOffset(0)] + public GameControllerButtonBindValueHat Hat; +} + +public unsafe partial struct GameControllerButtonBindValueHat +{ + public int Hat; + + public int HatMask; +} diff --git a/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp b/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp index 9278650d20dce..e19eec7feb073 100644 --- a/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp +++ b/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp @@ -1297,3 +1297,8 @@ extern "C" DLL_EXPORT Int32CLongStruct STDMETHODCALLTYPE AddCLongs(Int32CLongStr { return { lhs.i + rhs.i, lhs.l + rhs.l }; } + +extern "C" DLL_EXPORT SDL_GameControllerBindType STDMETHODCALLTYPE getBindType(SDL_GameControllerButtonBind button) +{ + return button.bindType; +} diff --git a/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h b/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h index 4a74572717890..cb59b80bf0988 100644 --- a/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h +++ b/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h @@ -974,3 +974,26 @@ struct Int32CLongStruct int32_t i; long l; }; + +typedef enum +{ + SDL_CONTROLLER_BINDTYPE_NONE = 0, + SDL_CONTROLLER_BINDTYPE_BUTTON, + SDL_CONTROLLER_BINDTYPE_AXIS, + SDL_CONTROLLER_BINDTYPE_HAT +} SDL_GameControllerBindType; + +typedef struct SDL_GameControllerButtonBind +{ + SDL_GameControllerBindType bindType; + union + { + int button; + int axis; + struct { + int hat; + int hat_mask; + } hat; + } value; + +} SDL_GameControllerButtonBind; diff --git a/src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.cs b/src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.cs new file mode 100644 index 0000000000000..870e75bff6252 --- /dev/null +++ b/src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; +using Xunit; + +public class Managed +{ + [DllImport("MarshalStructAsParam")] + static extern GameControllerBindType getBindType (GameControllerButtonBind button); + + public static int Main() + { + GameControllerButtonBind button = new GameControllerButtonBind(GameControllerBindType.ControllerBindtypeAxis, null); + if (getBindType(button) == GameControllerBindType.ControllerBindtypeAxis) + { + Console.WriteLine("\nTEST PASSED!"); + return 100; + } + else + { + Console.WriteLine("\nTEST FAILED!"); + return 1; + } + } +} diff --git a/src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.csproj b/src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.csproj new file mode 100644 index 0000000000000..1cfbdf526f377 --- /dev/null +++ b/src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.csproj @@ -0,0 +1,14 @@ + + + exe + true + + + + + + + + + + diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 31a054303b509..62d7c3e233593 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -2912,6 +2912,12 @@ + + + https://github.com/dotnet/runtime/issues/64127 + + + missing assembly