sdk: BadImageFormatException when PlatformTarget architecture is different than current SDK

Steps to reproduce

  1. Install x86 and x64 .NET Core SDKs
  2. Create new dotnet console app (dotnet new console)
  3. Set the PlatformTarget in explicit way to architecture different than your current SDK
  4. dotnet run
using System;

namespace report
{
    class Program
    {
        static void Main(string[] args) => Console.WriteLine($"IntPtr.Size={IntPtr.Size}");
    }
}
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <PlatformTarget>x64</PlatformTarget>
  </PropertyGroup>
</Project>

Expected behavior

dotnetcli runs the program for given platform target

Actual behavior

Program crashes:

Unhandled Exception: System.BadImageFormatException: Could not load file or assembly 'C:\temp\report\bin\Debug\netcoreapp2.0\report.dll'. An attempt was made to load a program with an incorrect format.

Environment data

dotnet --info output:

.NET Command Line Tools (2.1.0-preview1-007074)

Product Information:
 Version:            2.1.0-preview1-007074
 Commit SHA-1 hash:  ee5c02de77

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.14393
 OS Platform: Windows
 RID:         win10-x86
 Base Path:   C:\Program Files (x86)\dotnet\sdk\2.1.0-preview1-007074\

Microsoft .NET Core Shared Framework Host

  Version  : 2.1.0-preview2-25615-02
  Build    : 2d818e87081bfe71f9a3f2cbba43cb279e79b265

Why do I need that

In BenchmarkDotNet we generate, build and run new project for every benchmark. We use dotnet cli to do that. I would like to allow our users to compare the performance of x64 vs x86 with single config. I can imagine that dotnet cli team is busy. Could you at least give me some workaround?

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 8
  • Comments: 16 (7 by maintainers)

Commits related to this issue

Most upvoted comments

By default, VS (and dotnet run) will just use the dotnet.exe that comes first on your PATH to run the application. If that is the x64 version of dotnet.exe, then you will not be able to debug x86 apps, and vice versa.

However, you can override the default run command. I suggest the following approach:

  1. Install both the x86 and x64 .NET Core 2.0 SDKs from https://www.microsoft.com/net/download/core
  2. Put the following in a file named Directory.Build.targets that is somewhere above your project file (e.g. the root of the source repository). MSBuild will pick it up automatically for all projects.
<Project>
  <PropertyGroup 
      Condition="'$(OS)' == 'Windows_NT' and
                 '$(TargetFrameworkIdentifier)' == '.NETCoreApp' and
                 '$(SelfContained)' != 'true'"
                  >
    <RunCommand Condition="'$(PlatformTarget)' == 'x86'">$(MSBuildProgramFiles32)\dotnet\dotnet</RunCommand>
    <RunCommand Condition="'$(PlatformTarget)' == 'x64'">$(ProgramW6432)\dotnet\dotnet</RunCommand>
  </PropertyGroup>
</Project>

What this does is the following:

  • If I’m building a .NET Core application on Windows and it is not self-contained (does not carry its own copy of the .NET Core runtime), then:
    • If it targets x86, use dotnet from C:\Program Files(x86)\dotnet
    • If it targets x64, use dotnet from C:\Program Files\dotnet

I am leaving this open to track making this work automatically without having to customize the RunCommand.

With the change to use an apphost by default, this now comes down to duplicate of dotnet/sdk#2632. We now put the exe that hosts the app into the app folder, so once we put the right one there, we do not need to leak in ProgramFiles (x86 or otherwise) for the appropriate host. The apphost will then find the right shared framework itself.

Closing in favor of dotnet/sdk#2632, this experience should get fixed in 3.0. šŸŽ‰ cc @peterhuene