Bug in LiteralElement.EmitLoad method

Nov 15, 2011 at 3:50 PM

There is a bug in the int64 specific method:

Protected Shared Sub EmitLoad(ByVal value As Int64, ByVal ilg As FleeILGenerator)

Reproduction:

Try evaluating a datetime expression with the following expression: > #11/14/2011# + ##00:07:00#

Result:

The expression compilation fails with the following error:

An error occurred with the following error message: "System.OverflowException: Arithmetic operation resulted in an overflow.
at Ciloci.Flee.LiteralElement.EmitLoad(Int64 value, FleeILGenerator ilg)
at Ciloci.Flee.TimeSpanLiteralElement.Emit(FleeILGenerator ilg, IServiceProvider services)
at Ciloci.Flee.BinaryExpressionElement.EmitOverloadedOperatorCall(MethodInfo method, FleeILGenerator ilg, IServiceProvider services)
at Ciloci.Flee.ArithmeticElement.Emit(FleeILGenerator ilg, IServiceProvider services)
at Ciloci.Flee.BinaryExpressionElement.EmitOverloadedOperatorCall(MethodInfo method, FleeILGenerator ilg, IServiceProvider services)
at Ciloci.Flee.CompareElement.Emit(FleeILGenerator ilg, IServiceProvider services)
at Ciloci.Flee.RootExpressionElement.Emit(FleeILGenerator ilg, IServiceProvider services)
at Ciloci.Flee.Expression`1.Compile(String expression, ExpressionOptions options)
at Ciloci.Flee.Expression`1..ctor(String expression, ExpressionContext context, Boolean isGeneric)
at Ciloci.Flee.ExpressionContext.CompileGeneric[TResultType](String expression)

Expected Result:

The expression should evaluate properly.

Explanation:

The code tries to optimize the emitted instruction by detecting the value can fit in UInt32. However the method handling the optimized generation is the method for handling Int32. This can overflow and in fact it that what happens.

Resolution:

1. I modified the method as follows:

Protected Shared Sub EmitLoad(ByVal value As Int64, ByVal ilg As FleeILGenerator)
If value >= Int32.MinValue And value <= Int32.MaxValue Then
EmitLoad(CInt(value), ilg)
ilg.Emit(OpCodes.Conv_I8)
ElseIf value >= 0 And value <= UInt32.MaxValue Then
EmitLoad(CUInt(value), ilg)
ilg.Emit(OpCodes.Conv_U8)
Else
ilg.Emit(OpCodes.Ldc_I8, value)
End If
End Sub

2. Included one additional method:

Private Shared Sub EmitLoad(ByVal value As UInt32, ByVal ilg As FleeILGenerator)
If value >= 0 And value <= 8 Then
EmitSuperShort(value, ilg)
ElseIf value >= 0 And value <= SByte.MaxValue Then
ilg.Emit(OpCodes.Ldc_I4_S, CSByte(value))
Else
ilg.Emit(OpCodes.Ldc_I4, value)
End If
End Sub