diff --git a/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp b/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp index 8b18ce74e7..a5dec028f6 100644 --- a/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp +++ b/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp @@ -193,19 +193,27 @@ angle::Result Image11::recoverFromAssociatedStorage(const gl::Context *context) { if (mRecoverFromStorage) { - ANGLE_TRY(createStagingTexture(context)); + // Disassociate up front. This function is called from + // TextureStorage11_*::onDestroy and ::releaseAssociatedImage; in both + // cases the storage is about to either be deleted or have this slot + // overwritten, so the association MUST be broken regardless of whether + // the recovery operations below succeed. Snapshot the storage pointer + // first so we can still copy from it. Without this, an ANGLE_TRY + // early-return below leaves mAssociatedStorage dangling after the + // caller frees the storage, and ~Image11 -> disassociateStorage() + // performs a virtual call on freed memory. + TextureStorage11 *storage = mAssociatedStorage; + gl::ImageIndex imageIndex = mAssociatedImageIndex; + disassociateStorage(); - mAssociatedStorage->verifyAssociatedImageValid(mAssociatedImageIndex, this); + ANGLE_TRY(createStagingTexture(context)); // CopySubResource from the Storage to the Staging texture gl::Box region(0, 0, 0, mWidth, mHeight, mDepth); - ANGLE_TRY(mAssociatedStorage->copySubresourceLevel( - context, mStagingTexture, mStagingSubresource, mAssociatedImageIndex, region)); + ANGLE_TRY(storage->copySubresourceLevel(context, mStagingTexture, mStagingSubresource, + imageIndex, region)); mRecoveredFromStorageCount += 1; - // Reset all the recovery parameters, even if the texture storage association is broken. - disassociateStorage(); - markDirty(); }