-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
BadImageFormatException when loading valid assembly #63639
Comments
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. |
Tagging subscribers to this area: @vitek-karas, @agocke, @VSadov Issue DetailsDescriptionI am currently writing an experimental .NET compiler framework, and I've reached the point where I can write full ECMA-335-compliant DLLs to disk. However, when attempting to run my output with
Frustratingly, this provides no meaningful error message as to what the incorrect format actually is. Enabling I've run this DLL through Reproduction Steps
{
"runtimeOptions": {
"tfm": "net6.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
},
"configProperties": {
"System.GC.Concurrent": false,
"System.Threading.ThreadPool.MinThreads": 4,
"System.Threading.ThreadPool.MaxThreads": 25
}
}
}
Expected behaviorThe assembly should be run without issues and print Actual behaviorThe assembly fails to load with the exception shown above, and Regression?No response Known WorkaroundsNo response ConfigurationOutput from
Other informationThe Rust function generating the file is available here. The output from
|
Have you done a byte-for-byte comparison with what csc produces here? There may be an encoding error that wouldn't show up in the verification tools or ildasm |
Well, looking at the two side-by-side, there are definitely differences. However, the PE headers appear sane, and while I can't immediately spot any encoding mistakes by eye, the intent is not to mirror exactly what Ideally, I would like to step into |
Yeah, debugging with coreclr is the next best option, I think. You should build with the debug configuration, and then you should be able to open the |
I can quickly run it under corerun if you can attach the DLL to the issue. The runtime will throw a C++ exception so the key is to have the runtime under the debugger in a way that you can break in when the exception is thrown. I know where the checkbox is in VS, but I also see you're running a Unix-y system. If you want to try yourself, corerun instructions are here: https://github.com/dotnet/runtime/blob/f3c705ef291ff89b53220a31d8321355471d1937/docs/workflow/testing/using-corerun.md. Corerun doesn't need runtimeconfig.json; it picks up assemblies from paths described in the linked doc. |
Sure, I've uploaded the DLL here. In the meantime, I'll try my best to get |
There are two problems with this:
You can fix this by just not generating the import table, relocs, or the jump thunk. The thunk to jump to |
Interesting - I was just going off of standards text, so good to know those are not strictly required. However, even after removing those, I get the same |
Yeah, we should remove it from the standard, it's just unused junk at this point. ILAsm has a Can you send the DLL with the fix? I skipped over those two checks with a debugger and the library loaded, but I didn't test anything else. |
Sure, here's the fixed version. Confirmed in |
It works on Windows, doesn't on Linux. On Windows, PE files are loaded by the OS. On Linux, CoreCLR comes with its own PE loader. Hard to say what it's unhappy about. These loaders are very hardened against untrusted inputs (it was used in Silverlight) so they check things very thoroughly to avoid something surprising getting through. I'm not set up to debug on Linux right now, so I'll have to leave it to you. Generally, you would build the repo, run this under corerun, under a debugger, and in the debugger (I assume gdb), you would do |
Good news - I figured it out! At first I couldn't get Once I started investigating, it turned out that even though I did remove the import table/thunks, at first I still had the optional PE header entry point RVA set to the thunk address...which was no longer there, of course. In the process of debugging after figuring that out, I had re-enabled the import table, reloc, and thunk generation, and as soon as I added your fixes from #63639 (comment), it worked! Thank you so much! I imagine you don't get people building their own assemblies from scratch very often, so I really appreciate your patience and willingness to help. |
I'm glad you figured it out! Always happy to see people building new things on top of .NET! |
Description
I am currently writing an experimental .NET compiler framework, and I've reached the point where I can write full ECMA-335-compliant DLLs to disk. However, when attempting to run my output with
dotnet
, I receive the following error:Frustratingly, this provides no meaningful error message as to what the incorrect format actually is. Enabling
COREHOST_TRACE
adds no other useful information.I've run this DLL through
ildasm
,dotnet-ilverify
, and evenmono
, all of which have worked without issues. Any advice would be greatly appreciated!Reproduction Steps
cargo test write_all
to generate thetest.dll
file.test.runtimeconfig.json
. I used the following, based on the official template:dotnet test.dll
.Expected behavior
The assembly should be run without issues and print
Hello, world!
to standard output.Actual behavior
The assembly fails to load with the exception shown above, and
dotnet
exits with error code 134.Regression?
No response
Known Workarounds
No response
Configuration
Output from
dotnet --info
:Other information
The Rust function generating the file is available here.
The output from
ildasm
:The text was updated successfully, but these errors were encountered: