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

fsc 4.0 Unhandled Exception: System.AccessViolationException #517

Closed
marklam opened this issue Jun 27, 2015 · 10 comments
Closed

fsc 4.0 Unhandled Exception: System.AccessViolationException #517

marklam opened this issue Jun 27, 2015 · 10 comments
Labels

Comments

@marklam
Copy link

marklam commented Jun 27, 2015

Creating an empty F# class library in Visual Studio 2015 RC with F# 4 installed, and referencing the NuGet package Xaml.MapControl 2.4.12, then building produces the following crash (with MSBuild set to detailed).

        C:\Program Files (x86)\Microsoft SDKs\F#\4.0\Framework\v4.0\fsc.exe -o:obj\Debug\Library1.dll -g --debug:full --noframework --define:DEBUG --define:TRACE --doc:bin\Debug\Library1.XML --optimize- --tailcalls- -r:C:\Temp\bugdemoproject\Library1\packages\XAML.MapControl.2.4.12\lib\net45\FileDb.dll -r:C:\Temp\bugdemoproject\Library1\packages\XAML.MapControl.2.4.12\lib\net45\FileDbCache.WPF.dll -r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.4.0.0\FSharp.Core.dll" -r:C:\Temp\bugdemoproject\Library1\packages\XAML.MapControl.2.4.12\lib\net45\ImageFileCache.WPF.dll -r:C:\Temp\bugdemoproject\Library1\packages\XAML.MapControl.2.4.12\lib\net45\MapControl.WPF.dll -r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2\mscorlib.dll" -r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2\System.Core.dll" -r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2\System.dll" -r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2\System.Numerics.dll" --target:library --warn:3 --warnaserror:76 --vserrors --validate-type-providers --LCID:1033 --utf8output --fullpaths --flaterrors --subsystemversion:6.00 --highentropyva+ --sqmsessionguid:efd8954f-ca0f-4d2a-97d3-b1613775e1cf "C:\Users\Mark\AppData\Local\Temp\.NETFramework,Version=v4.5.2.AssemblyAttributes.fs" AssemblyInfo.fs Library1.fs 
        Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
           at Microsoft.FSharp.Compiler.AbstractIL.ILBinaryReader.MMapChannel.InputByte()
           at Microsoft.FSharp.Compiler.AbstractIL.ILBinaryReader.readByte(InputChannel is)
           at Microsoft.FSharp.Compiler.AbstractIL.ILBinaryReader.readCompressedUInt32(InputChannel is)
           at Microsoft.FSharp.Compiler.AbstractIL.ILBinaryReader.readBlobHeapUncached(FSharpRef`1 ctxtH, Int32 idx)
           at Microsoft.FSharp.Compiler.AbstractIL.ILBinaryReader.mkCacheInt32@873-1.Invoke(FSharpFunc`2 f, Int32 idx)
           at Microsoft.FSharp.Compiler.AbstractIL.ILBinaryReader.readBlobHeapOption(ILReaderContext ctxt, Int32 idx)
           at Microsoft.FSharp.Compiler.AbstractIL.ILBinaryReader.seekReadAssemblyRefUncached(FSharpRef`1 ctxtH, Int32 idx)
           at Microsoft.FSharp.Compiler.AbstractIL.ILBinaryReader.ctxt@3987-11.Invoke(Int32 idx)
           at Microsoft.FSharp.Compiler.AbstractIL.ILBinaryReader.mkCacheInt32@873-1.Invoke(FSharpFunc`2 f, Int32 idx)
           at Microsoft.FSharp.Compiler.AbstractIL.ILBinaryReader.genOpenBinaryReader@4059-4.GenerateNext(IEnumerable`1& next)
           at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1.MoveNextImpl()
           at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1.System-Collections-IEnumerator-MoveNext()
           at Microsoft.FSharp.Collections.SeqModule.ToList[T](IEnumerable`1 source)
           at System.Lazy`1.CreateValue()
           at System.Lazy`1.LazyInitValue()
           at System.Lazy`1.get_Value()
           at Microsoft.FSharp.Compiler.Build.TcImports.OpenILBinaryModule(String filename, range m)
           at Microsoft.FSharp.Compiler.Build.TcImports.RegisterAndPrepareToImportReferencedDll(FSharpList`1 tpApprovals, FSharpOption`1 displayPSTypeProviderSecurityDialogBlockingUI, AssemblyResolution r)
           at Microsoft.FSharp.Compiler.Build.RegisterAndImportReferencedAssemblies@4165.Invoke(AssemblyResolution nm)
           at Microsoft.FSharp.Primitives.Basics.List.map[T,TResult](FSharpFunc`2 mapping, FSharpList`1 x)
           at Microsoft.FSharp.Compiler.Build.TcImports.RegisterAndImportReferencedAssemblies(FSharpOption`1 displayPSTypeProviderSecurityDialogBlockingUI, FSharpList`1 nms)
           at Microsoft.FSharp.Compiler.Build.TcImports.BuildNonFrameworkTcImports(FSharpOption`1 displayPSTypeProviderSecurityDialogBlockingUI, TcConfigProvider tcConfigP, TcGlobals tcGlobals, TcImports baseTcImports, FSharpList`1 nonFrameworkReferences, FSharpList`1 knownUnresolved)
           at Microsoft.FSharp.Compiler.Driver.getTcImportsFromCommandLine$cont@443(Exiter exiter, DelayedDisposables disposables, FSharpOption`1 displayPSTypeProviderSecurityDialogBlockingUI, LexResourceManager lexResourceManager, FSharpList`1 sourceFiles, String assemblyName, TcConfig tcConfig, ErrorLogger errorLogger, Unit unitVar)
           at Microsoft.FSharp.Compiler.Driver.getTcImportsFromCommandLine(FSharpOption`1 displayPSTypeProviderSecurityDialogBlockingUI, String[] argv, String defaultFSharpBinariesDir, String directoryBuildingFrom, FSharpOption`1 lcidFromCodePage, FSharpFunc`2 setProcessThreadLocals, FSharpFunc`2 displayBannerIfNeeded, Boolean optimizeForMemory, Exiter exiter, ErrorLoggerProvider errorLoggerProvider, DelayedDisposables disposables)
           at Microsoft.FSharp.Compiler.Driver.main0(String[] argv, Boolean bannerAlreadyPrinted, Exiter exiter, ErrorLoggerProvider errorLoggerProvider, DelayedDisposables disposables)
           at Microsoft.FSharp.Compiler.Driver.typecheckAndCompile(String[] argv, Boolean bannerAlreadyPrinted, Exiter exiter, ErrorLoggerProvider errorLoggerProvider)
           at Microsoft.FSharp.Compiler.Driver.mainCompile(String[] argv, Boolean bannerAlreadyPrinted, Exiter exiter)
           at Microsoft.FSharp.Compiler.CommandLineMain.Driver.main(String[] argv)
           at Microsoft.FSharp.Compiler.CommandLineMain.main(String[] argv)
C:\Program Files (x86)\Microsoft SDKs\F#\4.0\Framework\v4.0\Microsoft.FSharp.Targets(155,9): error MSB6006: "fsc.exe" exited with code -1073741819.
Target "_CheckForCompileOutputs" in file "C:\Program Files (x86)\MSBuild\14.0\bin\Microsoft.Common.CurrentVersion.targets" from project "C:\temp\bugdemoproject\Library1\Library1\Library1.fsproj" (target "_CleanGetCurrentAndPriorFileWrites" depends on it):
Target "_CleanGetCurrentAndPriorFileWrites" in file "C:\Program Files (x86)\MSBuild\14.0\bin\Microsoft.Common.CurrentVersion.targets" from project "C:\temp\bugdemoproject\Library1\Library1\Library1.fsproj" (target "_CleanRecordFileWrites" depends on it):
    Task "ReadLinesFromFile"
    Task "ConvertToAbsolutePath"
    Task "FindUnderPath"
    Task "FindUnderPath"
    Task "FindUnderPath"
    Task "RemoveDuplicates"
Target "_CleanRecordFileWrites" in file "C:\Program Files (x86)\MSBuild\14.0\bin\Microsoft.Common.CurrentVersion.targets" from project "C:\temp\bugdemoproject\Library1\Library1\Library1.fsproj" (target "CoreBuild" depends on it):
    Task "RemoveDuplicates"
    Task "MakeDir"
    Task "WriteLinesToFile"
Done building project "Library1.fsproj" -- FAILED.

@marklam
Copy link
Author

marklam commented Jun 27, 2015

Doing the same thing with a C# class library builds OK, so I don't think the NuGet package can be completely smashed.

@latkin
Copy link
Contributor

latkin commented Jun 27, 2015

Some quick findings:

  • Repros with F# 3.1, so not a 4.0 regression
  • The library FileDb.dll does not pass PEVerify:
Microsoft (R) .NET Framework PE Verifier.  Version  4.0.30319.33440
Copyright (c) Microsoft Corporation.  All rights reserved.

[MD]: Error (Structural): Table=0x00000000, Col=0x00000004, Row=0x00000001, has an invalid GUID offset.
[MD]: Error (Structural): Table=0x00000000, Col=0x00000004, Row=0x00000002, has an invalid GUID offset.
[MD]: Error (Structural): Table=0x00000001, Col=0x00000000, Row=0x00000073, has coded rid out of range.
[MD]: Error (Structural): Table=0x00000001, Col=0x00000000, Row=0x00000074, has coded rid out of range.
[MD]: Error (Structural): Table=0x00000023, Col=0x00000008, Row=0x00000004, has an invalid BLOB offset.
5 Error(s) Verifying packages\XAML.MapControl.2.4.12\lib\net45\FileDb.dll
  • Removing the reference to FileDb.dll resolves the problem

So root cause is something in FileDb.dll, though it's quite possible we should still be able to handle it (I wonder what C# is doing?).

@vladima
Copy link
Contributor

vladima commented Jun 28, 2015

from symptoms I would say that FileDb.dll is obfuscated

@marklam
Copy link
Author

marklam commented Jun 28, 2015

You're right, it's obfuscated - I just checked with ILSpy.

It's a free database with an option to buy the source, so I guess that's why the obfuscation.
http://www.eztools-software.com/tools/filedb/

Presumably the bogus metadata is designed by the obfuscator to crash decompilers but not C#, VB or the assembly loader. It would be nice if F# coped too but it's also fair enough if it doesn't.

@vladima
Copy link
Contributor

vladima commented Jun 29, 2015

Ok, I can see what is going on.
Obfuscated assembly has a bogus extra reference to mscorlib which has incorrect index in Blob heap for HashValue - index value was out of range of the heap.I guess the assumption was that compiler will not try to realize the whole set of information for this AssemblyRef entry but decompiler will try to do. The problem was that F# compiler is eagerly trying to populate information about referenced assemblies for the given assembly so it crashes during the attempt to read this malformed entry.

As a fix we can either defer reading information about referenced assemblies or make IL reading facilities more resilient to invalid metadata. Former change will be more invasive, the latter one seems more surgical - I've implemented it (https://github.com/Microsoft/visualfsharp/compare/fsharp4...vladima:blobHeapSize?expand=1), seems to be small enough. Not sure what is the best way to add a regression test for this case, putting 'FileDb.dll' as a test asset does not seem right to me, pinging @latkin for better ideas :)

@latkin
Copy link
Contributor

latkin commented Jun 29, 2015

@vladima - do I understand right that this would require manual byte tweaking, i.e. couldn't be reproduced through ilasm? Might not be so bad to have small checked-in repro binary, as long as we also include backing source code and instructions on how to create/modify the binary.

What is the result of your fix, does the compile now succeed or just fail more gracefully? Looks like empty array returned from readBlobHeap winds up triggering failure here?

@vladima
Copy link
Contributor

vladima commented Jun 29, 2015

@latkin yes, this is correct.
I'm only tried to reference FIleDb.dll and compile simple .fs file that looks like this

[<EntryPoint>]
let main _ =
    0

Prior to my fix it failed and now compilation passes successfully

AFAIR Cecil also returns empty array in case if requested index is out of the range of the Blob heap

@vladima
Copy link
Contributor

vladima commented Jun 30, 2015

@latkin did you actually get the crash in this place or you just assuming that it might fail there? in the former case can you share a repro?

@latkin
Copy link
Contributor

latkin commented Jun 30, 2015

No, I just tried to follow the path of execution through the source and I thought that's where it would end up.

@vladima
Copy link
Contributor

vladima commented Jun 30, 2015

no, in general this bogus reference should not ever be used and is present to trick the decompiler.

@vladima vladima mentioned this issue Jul 1, 2015
@latkin latkin added this to the F# 4.0 Update 1 milestone Aug 4, 2015
latkin pushed a commit that referenced this issue Aug 7, 2015
Obfuscated assemblies can have a bogus extra reference to mscorlib which
has incorrect index in Blob heap for HashValue - index value was out
of range of the heap.I guess the assumption was that compiler will not
try to realize the whole set of information for this AssemblyRef entry
but decompiler will try to do. The problem was that F# compiler is
eagerly trying to populate information about referenced assemblies for the
given assembly so it crashes during the attempt to read this malformed entry.

fixes #517
closes #519

commit 326a7fc
Author: Vladimir Matveev <[email protected]>
Date:   Wed Jul 1 00:27:11 2015 -0700

    added tests

commit 1d8dd07
Author: Vladimir Matveev <[email protected]>
Date:   Mon Jun 29 00:14:27 2015 -0700

    fix incorrect condition

commit 0c0c696
Author: Vladimir Matveev <[email protected]>
Date:   Sun Jun 28 23:30:38 2015 -0700

    added range check to readBlobHeapUncached
@latkin latkin added the fixed label Aug 7, 2015
@latkin latkin closed this as completed Aug 7, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants