You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Internal CLR error. (0x80131506) from CompileFast when a custom equality operator's returns non bool value #561
CompileFast emtis a delegate for expression tree whose body BinaryExpression has a non-bool result for user-defined operator == returning ICustomObject. The delegate returns a reference that passes a null check but is currupt - invoking direct call on this member such as ToString produces NullReferenceException, invoking virtual member like Ping() terminates the process with a fatal CLR error (0x80131506). built-in Compile() handles the same tree correctly.
Because this is a memory safety failure, it cannot be caught with try/catch and takes down the whole process.
Repro
FastExpressionCompiler 5.4.1, .NET 10 (SDK 10.0.112), Windows 11 x64.
bug occurs in latest FCE 6.0.0 too
usingSystem.Linq.Expressions;usingFastExpressionCompiler;Expression<Func<ICustomObject>>lambda=()=>1==newCustomObject();Console.WriteLine($"lambda: {lambda}");Console.WriteLine("Baseline path prints pong on following line");lambda.Compile().Invoke().Ping();varfunc=lambda.CompileFast(ifFastFailedReturnNull:false);try{varresult=func();if(resultisnull){Console.WriteLine($"the result is null while it should have been not null");return;}Console.WriteLine($"Calling ping on broken object.");// virtual call ends on faultresult.Ping();}catch(Exceptionex){Console.WriteLine($"Caught managed exception: {ex}");}internalinterfaceICustomObject{voidPing();}internalclassCustomObject:ICustomObject{publicstaticICustomObjectoperator==(doubleleft,CustomObjectright)=>newCustomObject();publicstaticICustomObjectoperator!=(doubleleft,CustomObjectright)=>newCustomObject();publicvoidPing(){Console.WriteLine("pong");}}
Output
lambda: () => (1 == new CustomObject())
Baseline path prints pong on following line
pong
Calling ping on broken object.
Fatal error.
Internal CLR error. (0x80131506)
Expected
Same behavior as Expression.Compile(): prints pong and exists normally
Verified against current dadhi/master (3aefb5e5): I reproduced the reported fatal CLR error (0x80131506) using the x64 .NET 10.0.9 host. The emitted IL uses ceq and returns its integer result as ICustomObject; it never calls the interface-returning op_Equality. With reversed operands it can instead emit an invalid object.Equals call.
Draft PR #558 already fixes the reported case, tested at its current head ae4d9a55. It honors BinaryExpression.Method before primitive comparison handling and preserves the method's actual return type. The relevant existing change is e37ba300.
I added a local regression covering ==, !=, both operand orders, and Default / NoInvocationLambdaInlining / EnableDelegateDebugInfo. It fails against current master and passes against #558 for both Standard and LightExpression on .NET 8/10, ARM64/x64. The isolated original repro also crashes against master in the 64-bit Framework process and succeeds with #558. The modern regression checks the selected operator call before invocation so a corrupt delegate cannot terminate the normal test runner.
These checks used Windows 11 ARM64 with the installed x64 .NET host under emulation, SDK 10.0.301 and runtime 10.0.9, rather than the reporter's exact SDK. Strict CompileFast(true) was used to ensure passing results came from FEC rather than System fallback. This is a valid expression, so it should be fixed upstream; Expression.Compile() remains a working workaround while #558 is pending.
Created a separate, focused fix for this issue: draft PR #562 — #562.
It is based directly on current master (3aefb5e5) and does not depend on the broader #558 changes. The fix honors the selected non-lifted comparison method and its actual return type, with regression coverage for the reported interface-returning operators, both operand orders, evaluation order, ignored results, and explicit comparison methods. Production changes are limited to 36 added lines, without context-layout changes or a broad refactoring.
The targeted checks pass for Standard and LightExpression on .NET 8/10 with ARM64 and x64 hosts, and the isolated original repro passes on .NET Framework. Full .NET 10 ARM64, .NET 8 x64, and Framework suites also pass. The full .NET 8 ARM64 suite still encounters an unrelated float post-increment crash, reproduced with identical IL on clean master and the fix; this is documented in the PR.
Activity
jogibear9988 commentedon Oct 22, 2026
Verified against current
dadhi/master(3aefb5e5): I reproduced the reported fatal CLR error (0x80131506) using the x64 .NET 10.0.9 host. The emitted IL usesceqand returns its integer result asICustomObject; it never calls the interface-returningop_Equality. With reversed operands it can instead emit an invalidobject.Equalscall.Draft PR #558 already fixes the reported case, tested at its current head
ae4d9a55. It honorsBinaryExpression.Methodbefore primitive comparison handling and preserves the method's actual return type. The relevant existing change is e37ba300.I added a local regression covering
==,!=, both operand orders, and Default / NoInvocationLambdaInlining / EnableDelegateDebugInfo. It fails against current master and passes against #558 for both Standard and LightExpression on .NET 8/10, ARM64/x64. The isolated original repro also crashes against master in the 64-bit Framework process and succeeds with #558. The modern regression checks the selected operator call before invocation so a corrupt delegate cannot terminate the normal test runner.These checks used Windows 11 ARM64 with the installed x64 .NET host under emulation, SDK 10.0.301 and runtime 10.0.9, rather than the reporter's exact SDK. Strict
CompileFast(true)was used to ensure passing results came from FEC rather than System fallback. This is a valid expression, so it should be fixed upstream;Expression.Compile()remains a working workaround while #558 is pending.jogibear9988 commentedon Oct 22, 2026
Created a separate, focused fix for this issue: draft PR #562 — #562.
It is based directly on current master (
3aefb5e5) and does not depend on the broader #558 changes. The fix honors the selected non-lifted comparison method and its actual return type, with regression coverage for the reported interface-returning operators, both operand orders, evaluation order, ignored results, and explicit comparison methods. Production changes are limited to 36 added lines, without context-layout changes or a broad refactoring.The targeted checks pass for Standard and LightExpression on .NET 8/10 with ARM64 and x64 hosts, and the isolated original repro passes on .NET Framework. Full .NET 10 ARM64, .NET 8 x64, and Framework suites also pass. The full .NET 8 ARM64 suite still encounters an unrelated float post-increment crash, reproduced with identical IL on clean master and the fix; this is documented in the PR.
Merge pull request #562 from jogibear9988/test/issue-561-non-bool-equ…