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
- Add [MethodImpl(MethodImplOptions.NoOptimization)] to the proxy method declaration.
- Upgrade to Unity 2020.3 or newer where this check is compiled out.
- Ensure the attribute import is present: using System.Runtime.CompilerServices.
- 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
- Always decorate proxy methods with [MethodImpl(MethodImplOptions.NoOptimization)] on Unity < 2020.3.
- Upgrade to Unity 2020.3 or newer to eliminate this requirement entirely.
- Add a code review checklist item: verify the attribute on every proxy/trampoline method.
- Use a Roslyn analyzer to enforce the attribute on methods matching a proxy naming convention.
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
- address offset of target and replace must less than ((1 << 2
- address offset of target and replace must larger than ((1 <<
- address offset of target and replace must less than (1 << 26
- none of methods targetMethod or replacementMethod can be nul
- MethodHook:targetMethod and replacementMethod and proxyMetho
AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13).
Data as JSON: /api/errors/610d2fa9d6b173e5.
Report an issue: GitHub.