egametang/ET · error · Exception

WRANING: method [{methodName}] must has a Attribute `MethodI

Error message

WRANING: method [{methodName}] must has a Attribute `MethodImpl(MethodImplOptions.NoOptimization)` to prevent code call to this optimized by compiler(pass args by shared stack)

What it means

Thrown by MethodHook.CheckMethod() on Unity versions older than 2020.3 when the proxy (call-forwarding) method lacks the [MethodImpl(MethodImplOptions.NoOptimization)] attribute. The proxy method preserves the original method's call semantics so the hook can call through to the original code. Without NoOptimization, the IL2CPP or JIT compiler may optimize argument passing via shared stack slots, which breaks the trampoline and causes random crashes in release builds.

Source

Thrown at Packages/cn.etetet.hybridclr/Scripts/Editor/Share/3rds/UnityHook/MethodHook.cs:214

            {
                if ((targetMethod.MethodImplementationFlags & MethodImplAttributes.InternalCall) != MethodImplAttributes.InternalCall)
                {
                    int codeSize = targetMethod.GetMethodBody().GetILAsByteArray().Length; // GetMethodBody can not call on il2cpp
                    if (codeSize < minMethodBodySize)
                        UnityEngine.Debug.LogWarning($"WRANING: you can not hook method [{methodName}], cause its method body is too short({codeSize}), will random crash on IL2CPP release mode");
                }
            }

            if(proxyMethod != null)
            {
                methodName = $"{proxyMethod.DeclaringType.Name}.{proxyMethod.Name}";
                int codeSize = proxyMethod.GetMethodBody().GetILAsByteArray().Length;
                if (codeSize < minMethodBodySize)
                    UnityEngine.Debug.LogWarning($"WRANING: size of method body[{methodName}] is too short({codeSize}), will random crash on IL2CPP release mode, please fill some dummy code inside");

                if ((proxyMethod.MethodImplementationFlags & MethodImplAttributes.NoOptimization) != MethodImplAttributes.NoOptimization)
                    throw new Exception($"WRANING: method [{methodName}] must has a Attribute `MethodImpl(MethodImplOptions.NoOptimization)` to prevent code call to this optimized by compiler(pass args by shared stack)");
            }
#endif
        }

        private void CreateCodePatcher()
        {
            long addrOffset = Math.Abs(_targetPtr.ToInt64() - _proxyPtr.ToInt64());
            
            if(_proxyPtr != IntPtr.Zero)
                addrOffset = Math.Max(addrOffset, Math.Abs(_targetPtr.ToInt64() - _proxyPtr.ToInt64()));

            if (LDasm.IsARM())
            {
                if (IntPtr.Size == 8)
                    _codePatcher = new CodePatcher_arm64_near(_targetPtr, _replacementPtr, _proxyPtr);
                else if (addrOffset < ((1 << 25) - 1))
                    _codePatcher = new CodePatcher_arm32_near(_targetPtr, _replacementPtr, _proxyPtr);
                else if (addrOffset < ((1 << 27) - 1))

View on GitHub (pinned to 5cab01f7a8)

Solutions

  1. Add [MethodImpl(MethodImplOptions.NoOptimization)] to the proxy method declaration.
  2. Upgrade to Unity 2020.3 or newer where this check is compiled out.
  3. Ensure the attribute import is present: using System.Runtime.CompilerServices.
  4. Add a build-time Roslyn analyzer or code review checklist to verify the attribute on all proxy methods.

Example fix

// before
public static IntPtr OriginalMethodProxy(IntPtr self, int param)
{
    return OriginalMethod(self, param);
}

// after
[MethodImpl(MethodImplOptions.NoOptimization)]
public static IntPtr OriginalMethodProxy(IntPtr self, int param)
{
    return OriginalMethod(self, param);
}
Defensive patterns

Strategy: validation

Validate before calling

#if UNITY_EDITOR && !UNITY_2020_3_OR_NEWER
if (proxyMethod != null)
{
    var implFlags = proxyMethod.GetCustomAttribute<MethodImplAttribute>();
    if (implFlags == null || (implFlags.Value & (int)MethodImplOptions.NoOptimization) == 0)
    {
        Debug.LogError($"Proxy method '{proxyMethod.Name}' must have [MethodImpl(MethodImplOptions.NoOptimization)] " +
            "to prevent IL2CPP release-mode crashes.");
    }
}
#endif

Type guard

#if UNITY_EDITOR && !UNITY_2020_3_OR_NEWER
static bool HasNoOptimizationAttribute(MethodInfo method)
{
    if (method == null) return true; // proxy is optional
    return (method.MethodImplementationFlags & MethodImplAttributes.NoOptimization)
        == MethodImplAttributes.NoOptimization;
}
#endif

Try / catch

try
{
    hook.CheckMethod();
}
catch (Exception ex) when (ex.Message.Contains("NoOptimization"))
{
    Debug.LogError($"Proxy method '{proxyMethod.Name}' is missing [MethodImpl(MethodImplOptions.NoOptimization)]. " +
        "Add the attribute or upgrade to Unity 2020.3+.");
}

Prevention

When it happens

Trigger: CheckMethod() runs under #if UNITY_EDITOR && !UNITY_2020_3_OR_NEWER. If proxyMethod is set and its MethodImplementationFlags does not include NoOptimization, the exception fires. This only affects older Unity versions; 2020.3+ skips this check.

Common situations: Writing a proxy method for a hook on Unity 2019 or earlier without adding [MethodImpl(MethodImplOptions.NoOptimization)]; updating from a newer Unity where the attribute wasn't required to an older target; copy-pasting a proxy method from a sample that omitted the attribute.

Related errors


AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13). Data as JSON: /api/errors/610d2fa9d6b173e5. Report an issue: GitHub.