Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpCode not supported: Ckfinite #3344

Open
tiagocrizanto opened this issue Dec 3, 2024 · 2 comments
Open

OpCode not supported: Ckfinite #3344

tiagocrizanto opened this issue Dec 3, 2024 · 2 comments
Labels
Bug Decompiler The decompiler engine itself

Comments

@tiagocrizanto
Copy link

tiagocrizanto commented Dec 3, 2024

Input code

I'm trying to decompile a very old assembly that I guess is in the dotnet framework 4 or lower. A lot of methods was not decompiled and ILSpy added this comment on all methods: /OpCode not supported: Ckfinite/

Here is the IL code

.method public final newslot virtual 
		instance float32 ToSingle (
			class [mscorlib]System.IFormatProvider AProvider
		) cil managed 
	{
		.override method instance float32 [mscorlib]System.IConvertible::ToSingle(class [mscorlib]System.IFormatProvider)
		// Method begins at RVA 0x2cec
		// Header size: 12
		// Code size: 11 (0xb)
		.maxstack 1
		.locals init (
			[0] float32 Result
		)

		// float num = (float)ToOADate();
		IL_0000: ldarg.0
		IL_0001: call instance float64 Borland.Delphi.TDateTime::ToOADate()
		IL_0006: conv.r4
		// /*OpCode not supported: Ckfinite*/;
		IL_0007: ckfinite
		// return num;
		IL_0008: stloc.0
		IL_0009: ldloc.0
		IL_000a: ret
	} // end of method TDateTime::ToSingle

Erroneous output

// This is the c# code generated:

public float ToSingle(IFormatProvider AProvider)
{
  float num = (float)ToOADate();
  /*OpCode not supported: Ckfinite*/;
  return num;
}

I thought that could be some missing old dll, so I created a windows XP VM, installed dotnet framework 3.5 and 4.0 and downloaded the first version of ILSpy and it displayed the same error (OpCode not supported: Ckfinite)

Unfortunately I'm not authorized to upload the complete assembly due to company copyrights. I'm not sure if I provided all necessary information but I'm trying to get any advice to get all assembly decompiled.

@tiagocrizanto tiagocrizanto added Bug Decompiler The decompiler engine itself labels Dec 3, 2024
@dgrunwald
Copy link
Member

This is the first time I've seen the ckfinite opcode being actually used.
I'm not aware of any compilers using this opcode, so I wonder how your old assembly was created.

By the way, the meaning of this opcode is essentially:

num = float.IsFinite(num) ? num : throw new ArithmeticException();

It should not be too hard to implement support in the decompiler (using a non-inlinable argument slot to deal with the duplicate num mention); it just never came up until now.
Though I guess if we need to support .NET 4.x it's more complicated (can't use float.IsFinite and probably shouldn't require throw-in-conditional-expr).

@tiagocrizanto
Copy link
Author

tiagocrizanto commented Dec 3, 2024

Hi dgrunwald! Thanks for your comment!

The code are really weird with a lot of custom code like operators and attributes and everything I know about the code is that it was a migration from Delphi 6 to dotnet and the original dotnet code was gone (It is a class library that simulate a soccer match). When I searched the internet for ckfinite, I saw that it is a very unusual use (as you said).

Before looking at this code I didn't know that is possible create custom operators to allow something like ClassA + ClassB

// Custom operators
public static TDateTime operator +([In][TTime] TDateTime Left, [In] TDateTime Right)
{
  double num = Left.ToOADate() + Right.ToOADate();
  /*OpCode not supported: Ckfinite*/;
  return num;
}

public static double operator -([In] TDateTime Left, [In] TDateTime Right)
{
  double num = Left.ToOADate() - Right.ToOADate();
  /*OpCode not supported: Ckfinite*/;
  return num;
}

public static TDateTime operator -([In] TDateTime Left, [In] double Right)
{
  TDateTime Result = default(TDateTime);
  Result.FValue = Left.FValue - TimeSpan.FromDays(Right);
  return Result;
}

public static TDateTime operator -([In] double Left, [In] TDateTime Right)
{
  double num = Left - (double)Right;
  /*OpCode not supported: Ckfinite*/;
  TDateTime Result = default(TDateTime);
  Result.FValue = (TDateTime)num;
  return Result;
}

public static double operator *([In] TDateTime Left, int Right)
{
  double num = Left.ToOADate() * (double)Right;
  /*OpCode not supported: Ckfinite*/;
  return num;
}

public static double operator /([In] TDateTime Left, [In] TDateTime Right)
{
  double num = Left.ToOADate() / Right.ToOADate();
  /*OpCode not supported: Ckfinite*/;
  return num;
}

And here are some use of the custom operator

public static bool TryStrToDateTime([In] string S, out TDateTime Value)
{
    bool Result = true;
    int Pos = 1;
    TDateTime Time = 0;
    TDateTime Date = default(TDateTime);
    if (!ScanDate(S, ref Pos, ref Date) || (Pos <= (S?.Length ?? 0) && !ScanTime(S, ref Pos, ref Time)))
    {
        Result = TryStrToTime(S, out Value);
    }
    else if (Date >= 0)
    {
        Value = Date + Time; // error here
    }
    else
    {
        Value = Date - Time; // and here because the ILSpy was not able to decompile the custom operators due to ckfinite.
    }
    return Result;
}

And here the IL of some custom operators with ckfinite error.

.method public hidebysig specialname static 
valuetype Borland.Delphi.TDateTime op_Addition (
	[in] valuetype Borland.Delphi.TDateTime Left,
	[in] valuetype Borland.Delphi.TDateTime modopt(Borland.Delphi.TTime) Right
) cil managed 
{
  .param [2]
	  .custom instance void Borland.Delphi.TTime::.ctor() = (
		  01 00 00 00
	  )
  // Method begins at RVA 0x2824
  // Header size: 12
  // Code size: 24 (0x18)
  .maxstack 2
  .locals init (
	  [0] valuetype Borland.Delphi.TDateTime Result
  )
  
  IL_0000: ldarga.s Left
  IL_0002: call instance float64 Borland.Delphi.TDateTime::ToOADate()
  IL_0007: ldarga.s Right
  IL_0009: call instance float64 Borland.Delphi.TDateTime::ToOADate()
  IL_000e: add
  IL_000f: ckfinite
  IL_0010: call valuetype Borland.Delphi.TDateTime Borland.Delphi.TDateTime::op_Implicit(float64)
  IL_0015: stloc.0
  IL_0016: ldloc.0
  IL_0017: ret
} // end of method TDateTime::op_Addition

.method public hidebysig specialname static 
		valuetype Borland.Delphi.TDateTime op_Subtraction (
			[in] valuetype Borland.Delphi.TDateTime Left,
			[in] valuetype Borland.Delphi.TDateTime modopt(Borland.Delphi.TDate) Right
		) cil managed 
{
.param [2]
	.custom instance void Borland.Delphi.TDate::.ctor() = (
		01 00 00 00
	)
  // Method begins at RVA 0x2930
  // Header size: 12
  // Code size: 24 (0x18)
  .maxstack 2
  .locals init (
	  [0] valuetype Borland.Delphi.TDateTime Result
  )
  
  IL_0000: ldarga.s Left
  IL_0002: call instance float64 Borland.Delphi.TDateTime::ToOADate()
  IL_0007: ldarga.s Right
  IL_0009: call instance float64 Borland.Delphi.TDateTime::ToOADate()
  IL_000e: sub
  IL_000f: ckfinite
  IL_0010: call valuetype Borland.Delphi.TDateTime Borland.Delphi.TDateTime::op_Implicit(float64)
  IL_0015: stloc.0
  IL_0016: ldloc.0
  IL_0017: ret
} // end of method TDateTime::op_Subtraction

I just trying to compile the project without update the code to prevent change any business rule and then create a new library with new code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Decompiler The decompiler engine itself
Projects
None yet
Development

No branches or pull requests

2 participants