Improve parameter verification logic in HookVerifier

Refactor HookVerifier to enhance parameter type checking and add utility methods for size calculations.
This commit is contained in:
wolfcomp 2026-01-27 14:43:39 +01:00 committed by GitHub
parent 8f8f4faa12
commit 678a13d517
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,8 +1,11 @@
using System.Linq;
using System.Runtime.CompilerServices;
using Dalamud.Game;
using Dalamud.Logging.Internal;
using InteropGenerator.Runtime;
namespace Dalamud.Hooking.Internal.Verification;
/// <summary>
@ -19,11 +22,14 @@ internal static class HookVerifier
new(
"ActorControlSelf",
"E8 ?? ?? ?? ?? 0F B7 0B 83 E9 64",
typeof(ActorControlSelfDelegate),
typeof(ActorControlSelfDelegate), // TODO: change this to CS delegate
"Signature changed in Patch 7.4") // 7.4 (new parameters)
];
private delegate void ActorControlSelfDelegate(uint category, uint eventId, uint param1, uint param2, uint param3, uint param4, uint param5, uint param6, uint param7, uint param8, ulong targetId, byte param9);
private static readonly string ClientStructsInteropNamespacePrefix = string.Join(".", nameof(FFXIVClientStructs), nameof(FFXIVClientStructs.Interop));
private delegate void ActorControlSelfDelegate(uint category, uint eventId, uint param1, uint param2, uint param3, uint param4, uint param5, uint param6, uint param7, uint param8, ulong targetId, byte param9); // TODO: change this to CS delegate
/// <summary>
/// Initializes a new instance of the <see cref="HookVerifier"/> class.
@ -86,7 +92,7 @@ internal static class HookVerifier
// Compare Parameter Types
for (var i = 0; i < passedParams.Length; i++)
{
if (passedParams[i].ParameterType != enforcedParams[i].ParameterType)
if (CheckParam(passedParams[i].ParameterType, enforcedParams[i].ParameterType))
{
mismatch = true;
break;
@ -100,6 +106,35 @@ internal static class HookVerifier
}
}
private bool CheckParam(Type paramLeft, Type paramRight)
{
var sameType = paramLeft == paramRight;
return sameType || SizeOf(paramLeft) == SizeOf(paramRight);
int SizeOf(Type type) {
return type switch {
_ when type == typeof(sbyte) || type == typeof(byte) || type == typeof(bool) => 1,
_ when type == typeof(char) || type == typeof(short) || type == typeof(ushort) || type == typeof(Half) => 2,
_ when type == typeof(int) || type == typeof(uint) || type == typeof(float) => 4,
_ when type == typeof(long) || type == typeof(ulong) || type == typeof(double) || type.IsPointer || type.IsFunctionPointer || type.IsUnmanagedFunctionPointer || (type.Name == "Pointer`1" && type.Namespace.AsSpan().SequenceEqual(ClientStructsInteropNamespacePrefix)) || type == typeof(CStringPointer) => 8,
_ when type.Name.StartsWith("FixedSizeArray") => type.GetGenericArguments()[0].SizeOf() * int.Parse(type.Name[14..type.Name.IndexOf('`')]),
_ when type.GetCustomAttribute<InlineArrayAttribute>() is { Length: var length } => type.GetGenericArguments()[0].SizeOf() * length,
_ when type.IsStruct() && !type.IsGenericType && (type.StructLayoutAttribute?.Value ?? LayoutKind.Sequential) != LayoutKind.Sequential => type.StructLayoutAttribute?.Size ?? (int?)typeof(Unsafe).GetMethod("SizeOf")?.MakeGenericMethod(type).Invoke(null, null) ?? 0,
_ when type.IsEnum => Enum.GetUnderlyingType(type).SizeOf(),
_ when type.IsGenericType => Marshal.SizeOf(Activator.CreateInstance(type)!),
_ => GetSizeOf(type)
};
}
int GetSizeOf(Type type) {
try {
return Marshal.SizeOf(Activator.CreateInstance(type)!);
} catch {
return 0;
}
}
}
private record VerificationEntry(string Name, string Signature, Type TargetDelegateType, string Message)
{
public nint Address { get; set; }