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

Unsafe code crashes with System.BadImageFormatException when built with latest .NET 7 preview SDK #74306

Closed
NoahStolk opened this issue Aug 21, 2022 · 12 comments
Assignees
Milestone

Comments

@NoahStolk
Copy link

NoahStolk commented Aug 21, 2022

Description

The following sample program crashes with System.BadImageFormatException when built with the latest .NET 7 preview SDK (7.0.100-preview.7.22377.5). It runs fine when built with the previous preview version (7.0.100-preview.6.22352.1).

I've been using .NET 7 for a while and recently pushed an update for my package. Previous versions were built with version 7.0.100-preview.6.22352.1 and worked fine. When using version 7.0.100-preview.7.22377.5, a call to an unsafe method crashed with System.BadImageFormatException. I tried to narrow down the problem and came up with a minimal sample that consistently crashes when built with the latest version.

Reproduction Steps

  1. Create the following app:

Program.cs

Test();

static unsafe void Test()
{
  byte*[] test = new byte*[] { };
}

Test.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework> <!--or net7.0-->
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
  </PropertyGroup>

</Project>

global.json

{
  "sdk": {
    "version": "7.0.100-preview.7.22377.5"
  }
}
  1. Run it with dotnet run.

It crashes with:

Unhandled exception. System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (0x8007000B)
   at Program.<<Main>$>g__Test|0_0()
   at Program.<Main>$(String[] args) in C:\Users\NOAH\source\repos\Test\Test\Program.cs:line 1

When changing the SDK version to 6.0.400 or 7.0.100-preview.6.22352.1 (the previous preview version) in global.json, the program runs fine.

The configuration (debug/release) and architecture (x64/x86) do not seem to matter.

Expected behavior

I expect no runtime errors when running this application. Am I missing a breaking change? I checked the breaking changes for .NET 7 but none of them stood out to me.

Actual behavior

The program crashes with System.BadImageFormatException.

Regression?

No response

Known Workarounds

No response

Configuration

SDK version

7.0.100-preview.7.22377.5

OS

Windows 10 Pro 19044.1889 64-bit

Architecture

x64

Other information

No response

@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Aug 21, 2022
@jeffschwMSFT
Copy link
Member

@mangod9

@danmoseley
Copy link
Member

@NoahStolk Do you get the same results with later daily builds? You can download from the dotnet/installer repo.

Also, is it possible to get a stack with a native debugger?

@NoahStolk
Copy link
Author

I installed 7.0.100-rc.2.22419.24 and everything works as expected. 🙂 Thanks! Is further investigation still necessary or can we close the issue?

@AraHaan
Copy link
Member

AraHaan commented Aug 22, 2022

perhaps it was an issue that later fixed itself in newer daily builds?

@mangod9 mangod9 removed the untriaged New issue has not been triaged by the area owner label Aug 22, 2022
@mangod9 mangod9 added this to the 7.0.0 milestone Aug 22, 2022
@mangod9
Copy link
Member

mangod9 commented Aug 22, 2022

we will investigate if this was an interim bug which was fixed recently. Thanks

@ivdiazsa
Copy link
Member

This bug has indeed been fixed. Tested it out with several builds, and the latest I could get it to repro was the newest Preview 7 build (7.0.100-preview.7.22411.2). After that, it no longer repros and the app exits successfully, as expected. Closing now.

@jakobbotsch
Copy link
Member

Maybe this was dotnet/roslyn#62392? It was reverted but made it into preview 7 -- perhaps the IL produced is invalid.

@ivdiazsa
Copy link
Member

Maybe this was dotnet/roslyn#62392? It was reverted but made it into preview 7 -- perhaps the IL produced is invalid.

I read through this PR and it sounds reasonable. Whenever I run this failing test, it only loads System.Private.CoreLib.dll, the test's dll, and System.Runtime.dll, then throws the exception. This points to it encountering some weird stuff while attempting to load whichever dll comes next (it differs from app to app).

The other thing is I wasn't able to get a managed stack trace. The native stack trace looks like this:

* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
  * frame #0: 0x00000001bd82ed98 libsystem_kernel.dylib`__pthread_kill + 8
    frame #1: 0x00000001bd863ee0 libsystem_pthread.dylib`pthread_kill + 288
    frame #2: 0x00000001bd79e340 libsystem_c.dylib`abort + 168
    frame #3: 0x0000000101ed6198 libcoreclr.dylib`PROCAbort + 44
    frame #4: 0x0000000101ed5dcc libcoreclr.dylib`PROCEndProcess(void*, unsigned int, int) + 972
    frame #5: 0x0000000101ed5ec0 libcoreclr.dylib`TerminateProcess + 216
    frame #6: 0x0000000101fcd940 libcoreclr.dylib`CrashDumpAndTerminateProcess(unsigned int) + 28
    frame #7: 0x000000010238f1f0 libcoreclr.dylib`UnwindManagedExceptionPass1(PAL_SEHException&, _CONTEXT*) + 1636
    frame #8: 0x000000010238f658 libcoreclr.dylib`DispatchManagedException(PAL_SEHException&, bool) + 448
    frame #9: 0x00000001020b5ae8 libcoreclr.dylib`PreStubWorker + 1436
    frame #10: 0x00000001024a7038 libcoreclr.dylib`ThePreStub + 80
    frame #11: 0x00000001195917d0
    frame #12: 0x00000001024a7af8 libcoreclr.dylib`CallDescrWorkerInternal + 132
    frame #13: 0x000000010216f664 libcoreclr.dylib`CallDescrWorkerWithHandler(CallDescrData*, int) + 316
    frame #14: 0x00000001021701d8 libcoreclr.dylib`MethodDescCallSite::CallTargetWorker(unsigned long const*, unsigned long*, int) + 1748
    frame #15: 0x0000000101f001e4 libcoreclr.dylib`MethodDescCallSite::Call(unsigned long const*) + 40
    frame #16: 0x0000000101f275d8 libcoreclr.dylib`RunMainInternal(Param*) + 524
    frame #17: 0x0000000101f27398 libcoreclr.dylib`RunMain(MethodDesc*, short, int*, REF<PtrArray>*)::$_1::operator()(Param*) const::'lambda'(Param*)::operator()(Param*) const + 28
    frame #18: 0x0000000101f2241c libcoreclr.dylib`RunMain(MethodDesc*, short, int*, REF<PtrArray>*)::$_1::operator()(Param*) const + 76
    frame #19: 0x0000000101f22220 libcoreclr.dylib`RunMain(MethodDesc*, short, int*, REF<PtrArray>*) + 440
    frame #20: 0x0000000101f2273c libcoreclr.dylib`Assembly::ExecuteMainMethod(REF<PtrArray>*, int) + 372
    frame #21: 0x0000000101f935a8 libcoreclr.dylib`CorHost2::ExecuteAssembly(unsigned int, char16_t const*, int, char16_t const**, unsigned int*) + 1720
    frame #22: 0x0000000101eeee70 libcoreclr.dylib`coreclr_execute_assembly + 276
    frame #23: 0x000000010000603c corerun`run(config=0x000000016fdff388) at corerun.cpp:368:18
    frame #24: 0x0000000100003b64 corerun`main(argc=2, argv=0x000000016fdff5c8) at corerun.cpp:563:21
    frame #25: 0x00000001000a508c dyld`start + 520

The exception is being cast as the worker attempts to do its job of running the app. Is there a way to know when that Roslyn change made it to the runtime and sdk? Just out of curiosity, it would be nice to confirm this is indeed the case :)

@jakobbotsch
Copy link
Member

Can you check the IL for at Program.<<Main>$>g__Test|0_0() with dnSpy or ILSpy? What does it look like? Is it trying to instantiate GC.AllocateUninitializedArray<T> with byte*?

@ivdiazsa
Copy link
Member

Yes that's what it's doing. This is how the Main method looks once compiled (direct output from ILSpy):

// Program
using System;

private static void <Main>$(string[] args)
{
    Test();
    unsafe static void Test()
    {
        byte*[] test = GC.AllocateUninitializedArray<byte*>(0, pinned: false);
    }
}

@jakobbotsch
Copy link
Member

Ok, looks like that was the issue then.

@ghost ghost locked as resolved and limited conversation to collaborators Sep 24, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants