Skip to content

Crash in IWICImagingFactory.CreateStream #137

Closed

Description

@sa-exe

Calling IWICImagingFactory.CreateStream simply never succeeds: it crashes with either an access violation or a null reference exception. This might be a regression, since I don't remember having issues like that with an earlier version of Vortice (it was probably 1.8.x).

Here is a repro project, but really it's just 3 lines of code:

using FileStream stream = File.OpenRead("LuLu.png");
using var wicFactory = new IWICImagingFactory();
using IWICStream wicStream = wicFactory.CreateStream(stream);

Activity

  1. amerkoleci commented on Apr 13, 2021

    @amerkoleci
    Owner

    Not sure why.

    In the example here works:

    https://github.com/amerkoleci/Vortice.Windows/blob/main/src/samples/HelloDirect3D11/Program.cs#L167

    But I'm writing there, not reading

  2. amerkoleci commented on Apr 13, 2021

    @amerkoleci
    Owner

    @andrew-boyarshin can there be any issue with ComStreamProxy?

  3. andrew-boyarshin commented on Apr 13, 2021

    @andrew-boyarshin
    Contributor

    @amerkoleci I'll take a look tomorrow.

  4. amerkoleci commented on Apr 14, 2021

    @amerkoleci
    Owner

    @amerkoleci I'll take a look tomorrow.

    Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
       at System.Runtime.InteropServices.GCHandle.get_Target()
       at SharpGen.Runtime.CppObjectShadow.ToShadow[[System.__Canon, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](IntPtr)
       at SharpGen.Runtime.CppObjectVtbl.ToShadow[[System.__Canon, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](IntPtr)
       at SharpGen.Runtime.ComObjectVtbl.AddRefImpl(IntPtr)
       at Vortice.WIC.IWICStream.InitializeFromIStream(SharpGen.Runtime.Win32.IStream)
       at Vortice.WIC.IWICStream.Initialize(System.IO.Stream)
       at Vortice.WIC.IWICImagingFactory.CreateStream(System.IO.Stream)
    

    Issue seams here:
    https://github.com/SharpGenTools/SharpGen.Runtime.COM/blob/558c63e1f90c3464d7a5947cae5d54e111940d05/ComObjectVtbl.cs#L59

  5. andrew-boyarshin commented on Apr 14, 2021

    @andrew-boyarshin
    Contributor

    This will likely require new SharpGen release. I'll have time to debug and fix this issue ~6 hours from now.

  6. andrew-boyarshin commented on Apr 14, 2021

    @andrew-boyarshin
    Contributor

    Yeah. I've got the whole pack (using custom Checked runtime):

    Assert failure(PID 26896 [0x00006910], Thread: 24364 [0x5f2c]): !CREATE_CHECK_STRING(!"Detected use of a corrupted OBJECTREF. Possible GC hole.")
    
    CORECLR! `Object::ValidateInner'::`1'::catch$12 + 0x137 (0x00007ffc`1ff0ddd7)
    CORECLR! CallSettingFrame_LookupContinuationIndex + 0x20 (0x00007ffc`1fe6b840)
    CORECLR! _FrameHandler4::CxxCallCatchBlock + 0x1DE (0x00007ffc`1fe697be)
    NTDLL! RtlCaptureContext2 + 0x4A6 (0x00007ffc`e8247a96)
    CORECLR! Object::ValidateInner + 0xEE (0x00007ffc`1f7d993e)
    CORECLR! Object::Validate + 0xB9 (0x00007ffc`1f7d9819)
    CORECLR! OBJECTREF::OBJECTREF + 0xA6 (0x00007ffc`1f7d26a6)
    CORECLR! MarshalNative::GCHandleInternalGet + 0xD8 (0x00007ffc`1f9d1928)
    <no module>! <no symbol> + 0x0 (0x00007ffb`c0780ed3)
    <no module>! <no symbol> + 0x0 (0x000001e7`6d3c82c0)
    File: D:\dev\dotnet\runtime\src\coreclr\vm\object.cpp Line: 591
    Image: D:\dev\vortice-wic-crash\bin\Debug\net6.0\vortice-wic-crash.exe
    Fatal error. Internal CLR error. (0x80131506 (COR_E_EXECUTIONENGINE))
    at Vortice.WIC.IWICStream.InitializeFromIStream(SharpGen.Runtime.Win32.IStream)
    at Vortice.WIC.IWICStream.Initialize(System.IO.Stream)
    at Vortice.WIC.IWICImagingFactory.CreateStream(System.IO.Stream)
    at <Program>$.<Main>$(System.String[])
    
    000000290C5CE178 00007FFCE8232C5E ntdll!LdrpDispatchUserCallTarget + 14
    000000290C5CE180 00007FFCDD68A6FB windowscodecs!CExternalStream::HrInit + 151
    000000290C5CE250 00007FFCDD74002C windowscodecs!CMILStream::InitializeFromIStream + 268
    000000290C5CE290 00007FFBC7A2605B 
    000000290C5CE2C0                  [InlinedCallFrame: 000000290c5ce2c0] 
    000000290C5CE2C0                  [InlinedCallFrame: 000000290c5ce2c0] 
    000000290C5CE290 00007ffbc7a2605b Vortice.Direct2D1.dll!Vortice.WIC.IWICStream.InitializeFromIStream(SharpGen.Runtime.Win32.IStream) + 235 [/_/src/Vortice.Direct2D1/obj/Release/netstandard2.0/SharpGen/Generated/Interfaces.cs @ 18494]
        PARAMETERS:
            this (0x000000290C5CE380) = 0x000001d14d47fd60
            iStreamRef (0x000000290C5CE388) = 0x000001d14d47fe00
        LOCALS:
            0x000000290C5CE330 = 0x000001d16d9f97d0
            0x000000290C5CE328 = 0x0000000000000000
            
    000000290C5CE380 00007ffbc7a25e53 Vortice.Direct2D1.dll!Vortice.WIC.IWICStream.Initialize(System.IO.Stream) + 99 [/_/src/Vortice.Direct2D1/WIC/IWICStream.cs @ 46]
        PARAMETERS:
            this (0x000000290C5CE3C0) = 0x000001d14d47fd60
            stream (0x000000290C5CE3C8) = 0x000001d14d47f190
    
    000000290C5CE3C0 00007ffbc7a25a74 Vortice.Direct2D1.dll!Vortice.WIC.IWICImagingFactory.CreateStream(System.IO.Stream) + 52 [/_/src/Vortice.Direct2D1/WIC/IWICImagingFactory.cs @ 61]
        PARAMETERS:
            this (0x000000290C5CE400) = 0x000001d14d47f5e8
            stream (0x000000290C5CE408) = 0x000001d14d47f190
    
    000000290C5CE400 00007ffbc7a1a6d4 vortice-wic-crash.dll!$.$(System.String[]) + 132 [D:\dev\vortice-wic-crash\Program.cs @ 6]
        PARAMETERS:
            args (0x000000290C5CE470) = 0x000001d14d47d740
        LOCALS:
            0x000000290C5CE458 = 0x000001d14d47f190
            0x000000290C5CE450 = 0x000001d14d47f5e8
            0x000000290C5CE448 = 0x0000000000000000
    

    What is worse, my initial theory has been disproved. I'll need to rethink my approach to debug this issue.

  7. andrew-boyarshin commented on Apr 14, 2021

    @andrew-boyarshin
    Contributor

    windowscodecs crashes when trying to dereference the location of AddRef (vtbl[1]) method in ComStreamProxy Vtbl. The memory where the vtbl is supposed to be located is not mapped into memory (possibly already released to Windows NT kernel or never valid in the first place). One of the last SharpGen.Runtime methods to execute is the following stack:

            Child SP               IP Call Site
    000000F897B7DA10 00007ffbd4538370 SharpGen.Runtime.dll!SharpGen.Runtime.CppObjectShadow.ToShadow[[System.__Canon, System.Private.CoreLib]](IntPtr) + 32 [/_/SharpGen.Runtime/CppObjectShadow.cs @ 76]
        PARAMETERS:
            thisPtr (<CLR reg>) = 0x000002655042f190
        LOCALS:
            0x000000F897B7DA40 = 0x0000000000000000
    
    000000F897B7DA18 000000F897B7DE20 
    000000F897B7DA20 00000265503E3A70 
    000000F897B7DA28 000002655E331DC8 
    000000F897B7DA30 00007FFC33994A85 coreclr!ThePreStub + 85
    000000F897B7DA60 00007ffbd453832b SharpGen.Runtime.dll!SharpGen.Runtime.CppObjectVtbl.ToShadow[[System.__Canon, System.Private.CoreLib]](IntPtr) + 91 [/_/SharpGen.Runtime/CppObjectVtbl.cs @ 58]
        PARAMETERS:
            thisPtr (0x000000F897B7DAA8) = 0x000002655042f190
    
    000000F897B7DAA0 00007ffbd453b66b SharpGen.Runtime.COM.dll!SharpGen.Runtime.ComObjectVtbl.ReleaseImpl(IntPtr) + 43
        PARAMETERS:
            thisObject (0x000000F897B7DAE0) = 0x000002655042f190
    
    000000F897B7DAE0 00007ffbd453b5ba SharpGen.Runtime.COM.dll!ILStubClass.IL_STUB_ReversePInvoke(Int64) + 138
        PARAMETERS:
            <no data>
    
    000000F897B7DAE8 000002655042F190 
    000000F897B7DAF0 000002655042F190 
    000000F897B7DAF8 FFFFFFFFFFFFFF7F 
    000000F897B7DB00 00007FFC33C9F0F8 coreclr!`string'
    000000F897B7DB08 000000F897B7DAE0 
    000000F897B7DB10 0000026550444020 
    000000F897B7DB18 00007FFBD3E03290 
    000000F897B7DB20 0000026550444020 
    000000F897B7DB28 00007FFBD45C4968 
    000000F897B7DB30 0065007600000000 
    000000F897B7DB38 0000026500013CB0 
    000000F897B7DB40 00007FFBD3E0D290 
    000000F897B7DBE0                  [InlinedCallFrame: 000000f897b7dbe0] 
    000000F897B7DBE0                  [InlinedCallFrame: 000000f897b7dbe0] 
    000000F897B7DBB0 00007ffbd3f860db Vortice.Direct2D1.dll!Vortice.WIC.IWICStream.InitializeFromIStream(SharpGen.Runtime.Win32.IStream) + 235 [/_/src/Vortice.Direct2D1/obj/Release/netstandard2.0/SharpGen/Generated/Interfaces.cs @ 18494]
        PARAMETERS:
            this (0x000000F897B7DCA0) = 0x000002650000fd60
            iStreamRef (0x000000F897B7DCA8) = 0x000002650000fe00
        LOCALS:
            0x000000F897B7DC50 = 0x000002655042f190
            0x000000F897B7DC48 = 0x0000000000000000
    

    It takes place during execution of native InitializeFromIStream, before call to CExternalStream::HrInit. Before the call to Release, SharpGen.Runtime.Win32.IStreamShadow for GUID 0000000c-0000-0000-C000-000000000046 is valid (_nativePointer != null, Callback == iStreamRef), IsDisposed is false. After that Release call finishes, it is invalid (_nativePointer is null, IsDisposed is true).

    I think I've found the point when everything goes wrong, but I'm yet to figure out why exactly is that wrong and how to fix that.

  8. amerkoleci commented on Apr 14, 2021

    @amerkoleci
    Owner

    What changed? Why it worked before?

  9. andrew-boyarshin commented on Apr 14, 2021

    @andrew-boyarshin
    Contributor

    That's a question I'm now trying to figure out an answer to. :)

  10. andrew-boyarshin commented on Apr 14, 2021

    @andrew-boyarshin
    Contributor

    Extra AddRef to _streamProxy in IWICStream is a workaround (and doesn't cause leaks). I don't think it's a correct solution. I continue figuring out how to fix it.

  11. andrew-boyarshin commented on Apr 14, 2021

    @andrew-boyarshin
    Contributor

    Using SharpGen.Runtime.COM version 1.2.0 with current 2.0 codegen results in the crash even with extra AddRef.

  12. andrew-boyarshin commented on Apr 14, 2021

    @andrew-boyarshin
    Contributor

    The same codegen with the last Vortice.Runtime.COM works fine without AddRef. Unfortunately, I've run out of time today. I will continue working on this issue tomorrow.

  13. andrew-boyarshin commented on Apr 15, 2021

    @andrew-boyarshin
    Contributor

    Last Vortice.Runtime.COM works fine without AddRef with 2.0 beta 6 codegen using 1.2.1 SharpGen.Runtime, crashes with 2.0 SharpGen.Runtime.

  14. amerkoleci commented on Apr 15, 2021

    @amerkoleci
    Owner

    Last Vortice.Runtime.COM works fine without AddRef with 2.0 beta 6 codegen using 1.2.1 SharpGen.Runtime, crashes with 2.0 SharpGen.Runtime.

    Why that? Maybe you changed IStream shadow generation code?

  15. andrew-boyarshin commented on Apr 15, 2021

    @andrew-boyarshin
    Contributor

    I don't think the problem is in Runtime.COM. It's likely in SharpGen.Runtime (or the code generated for it).

  16. 12 remaining items

  17. amerkoleci commented on Apr 16, 2021

    @amerkoleci
    Owner

    @amerkoleci are you sure this is the right way forward? IStream is pretty generic and should support fetching data on-the-fly. I'd postpone such changes until I can assess if the current behavior is intended.

    Ok, for now I saw you cannot create decoder from IStream initialized from file, thats why you have:
    https://docs.microsoft.com/en-us/windows/win32/api/wincodec/nf-wincodec-iwicimagingfactory-createdecoderfromfilehandle
    https://docs.microsoft.com/en-us/windows/win32/api/wincodec/nf-wincodec-iwicimagingfactory-createdecoderfromfilename

  18. sa-exe commented on Apr 16, 2021

    @sa-exe
    ContributorAuthor

    Just FYI, this is how you would do this using SharpDX. Needless to say, it doesn't crash.

     using var wicStream = new WICStream(_wicFactory, stream);
     using var decoder = new BitmapDecoder(_wicFactory, wicStream, DecodeOptions.CacheOnDemand);
  19. amerkoleci commented on Apr 16, 2021

    @amerkoleci
    Owner

    Well, not sure then, @andrew-boyarshin probably another marshal issue in SharpGen.Runtime

  20. andrew-boyarshin commented on Apr 16, 2021

    @andrew-boyarshin
    Contributor

    Nullptr dereference on write happens in CExternalStream::HrSeek when calling m_pIStream->Seek(nMove, seekOrigin, pnPosition).

  21. andrew-boyarshin commented on Apr 16, 2021

    @andrew-boyarshin
    Contributor

    MS Docs defines Seek parameter plibNewPosition to be optional. SharpGen is aware of that (at least in C++ model). However, it has generated the following code for Shadow Vtbl:

    private static unsafe int Seek_(System.IntPtr thisObject, long _dlibMove, uint _origin, void *_plibNewPosition)
    {
        try
        {
            // ...
            ref ulong plibNewPosition = ref System.Runtime.CompilerServices.Unsafe.AsRef<ulong>(_plibNewPosition);
            IStream @this = (IStream)ToShadow<SharpGen.Runtime.Win32.IStreamShadow>(thisObject).Callback;
            plibNewPosition = @this.Seek(dlibMove, origin);
            return SharpGen.Runtime.Result.Ok.Code;
        }
        catch (System.Exception __exception__)
        {
            // ...
        }
    }

    As you can see, when passed NULL as plibNewPosition it will create nullref (yay unsafe), and will attempt to assign the value there regardless of the fact that is is null. Access violation.

  22. amerkoleci commented on Apr 16, 2021

    @amerkoleci
    Owner

    Can we expect quick fix for this as well?

  23. andrew-boyarshin commented on Apr 16, 2021

    @andrew-boyarshin
    Contributor

    SharpDX does check for null. The code was removed in SharpGen.Runtime.COM 1.1.0 and the codegen for that became automatic (and wrong). I'll see if I can fix it fast enough.

  24. amerkoleci commented on Apr 16, 2021

    @amerkoleci
    Owner

    This has to be fixed on automatic shadow codegen as there can be different automatic callback shadows doing so

  25. andrew-boyarshin commented on Apr 16, 2021

    @andrew-boyarshin
    Contributor

    Unfortunately, this will take a full day to fix. I want to do it right (in marshallers), instead of doing a hack in a single place (in reverse callback codegen).

  26. amerkoleci commented on Apr 16, 2021

    @amerkoleci
    Owner

    Unfortunately, this will take a full day to fix. I want to do it right (in marshallers), instead of doing a hack in a single place (in reverse callback codegen).

    Ok don't worry, take your time :) and thanks for your effort

  27. andrew-boyarshin commented on Apr 18, 2021

    @andrew-boyarshin
    Contributor

    This turned out to depend a lot on implementation details of different marshallers. The variable allocation is chaotic and not specified. The upcoming week I'm very busy and I will be unable to finish the work I've started in my branch. Sorry. For now this is a known regression from SharpDX, but the previous regression from SharpGen 1.2 was fixed, so this isn't really high priority.

  28. amerkoleci commented on Apr 18, 2021

    @amerkoleci
    Owner

    Okay, no problem, take your time and keep me updated when new SharpGen beta is out! Thanks again.

  29. amerkoleci commented on Apr 28, 2021

    @amerkoleci
    Owner

    Any news here @andrew-boyarshin?

  30. andrew-boyarshin commented on Apr 28, 2021

    @andrew-boyarshin
    Contributor

    @amerkoleci I work on this almost every day. The changes are huge, I'm trying to simplify logic without breaking anything.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions