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