Repository navigation
BadImageFormatException : Bad IL format when using base #13926
Description
Using base.XXX to call a base method causes a BadImageFormatException to be raised.
EDIT: it looks like F# allowing me to call an abstract method, as the base class is abstract. This, I believe, should not be allowed and JIT therefore throws a BadImageFormatException. If you try to write code in F# with an AbstractClass and a derived class, you'd receive a normal compile-time error.
Repro steps
The following code (requires Giraffe and FsUnit to run the test) throws a BadImageFormatException
namespace Test
open Giraffe
open Xunit
open FsUnit.Xunit
open System.Text.Json
open System.Text.Json.Serialization
type StringTrimJsonSerializer(o: JsonSerializerOptions) =
inherit JsonConverter<string>()
override this.Read(reader, _, _) =
match reader.TokenType with
| JsonTokenType.String -> reader.GetString().Trim()
| _ -> JsonException("Type is not a string") |> raise
/// This causes a BadImageFormatException
override this.Write(writer, objectToWrite, options) = base.Write(writer, objectToWrite, options)
module SerializationTests =
type SomeType = { Amount: decimal; Currency: string }
let serialize item =
let options = SystemTextJson.Serializer.DefaultOptions
StringTrimJsonSerializer options |> options.Converters.Add
JsonSerializer.Serialize(item, options)
let deserialize<'T> (stringValue: string) =
let options = SystemTextJson.Serializer.DefaultOptions
StringTrimJsonSerializer options |> options.Converters.Add
JsonSerializer.Deserialize<'T>(stringValue, options)
[<Fact>]
let ``Roundtip type should trim currency whitespace`` () =
{ Amount = 42.99M; Currency = " USD " }
|> serialize
|> deserialize<SomeType>
|> should equal { Amount = 42.99M; Currency = "USD" }
Expected behavior
Should call the base method or give compile error if such method doesn't exist.
Actual behavior
Throws:
BadImageFormatException : Bad IL format.
Known workarounds
Don't use base in a derived method.
Related information
On dotnet 6, using System.Text.Json serialization BCL classes, Windows 10/11.
EDIT, the IL of the offending code looks as follows (Release build):
.method public hidebysig virtual
instance void Write (
class [System.Text.Json]System.Text.Json.Utf8JsonWriter writer,
string objectToWrite,
class [System.Text.Json]System.Text.Json.JsonSerializerOptions options
) cil managed
{
// Method begins at RVA 0x316c
// Header size: 1
// Code size: 10 (0xa)
.maxstack 8
// base.Write(writer, objectToWrite, options);
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: ldarg.3
IL_0004: call instance void class [System.Text.Json]System.Text.Json.Serialization.JsonConverter`1<string>::Write(class [System.Text.Json]System.Text.Json.Utf8JsonWriter, !0, class [System.Text.Json]System.Text.Json.JsonSerializerOptions)
// }
IL_0009: ret
}
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
vzarytovskii commentedon Sep 19, 2022
Reproduces on
Does not reproduce on:
Both release and debug
abelbraaksma commentedon Sep 19, 2022
@vzarytovskii The latter never calls the
StringTrimJsonSerializer.Writemethod (there's no string in the type), so it makes sense that it doesn't fail. The JIT never has to emit the method, so you won't get theBadImageFormatException.The problem seems to be that
basehere is an abstract class and theWritemethod itself is alsoabstract. In other words, it should never compile. If you try this with F# classes (abstract A, concrete B derives from A) then ifBusesbase.Fooit'll give a compile error saying that you cannot call an abstract method.The same is true here, but for some reason, F# doesn't consider it an abstract method.
Fix dotnet#13926 - BadImageFormatException : Bad IL format when using…
Fix 13926 - Disallow using base to invoke an abstract base method. (#…