与 CryptoStream 一起使用时,嵌套 "using" 会导致 .net 运行时崩溃

Nested "using" crashes .net runtime when used with CryptoStream

我们有这个简单的代码,它是从 vb.net 转换而来的,它不是使用 using/end using 构建的。在转换过程中,我们在 c# 中使用了 using

using (var memStream = new MemoryStream() { Position = 0L })
using (ICryptoTransform cryptoTransfrom = (new TripleDESCryptoServiceProvider()).CreateDecryptor(_key, _iv))
{
    using (var cryptStream = new CryptoStream(memStream, cryptoTransfrom, CryptoStreamMode.Write))
    {
        // <-- here used to be try
        string convertedValue = ConvertHexToDec(value);
        byte[] decryptBytes = Convert.FromBase64String(convertedValue); //<-- Error line
        // <-- here used to be catch/throw
        cryptStream.Write(decryptBytes, 0, decryptBytes.Length);
        cryptStream.FlushFinalBlock();
        cryptStream.Close();
    }
    decodedVal = Encoding.ASCII.GetString(memStream.ToArray());
}

但是 Convert.FromBase64String(convertedValue) 周围有 try/catch(见评论)。我们没有意识到的是,value 有时会以普通的、非 base64 编码的值的形式出现。因此,当未编码的值命中 "Error line" - try/catch 时,会重新抛出。但是,当您查看上面的代码时,当该值在该行导致异常时 - .NET 运行时崩溃。这是事件日志

.NET Runtime version 2.0.50727.5485 - Fatal Execution Engine Error (000007FEE581600A) (80131506)

当然也有例外,只是正常

Invalid character in a Base-64 string.

我通过移除内部 using

修复了它
using (var memStream = new MemoryStream() { Position = 0L })
using (ICryptoTransform cryptoTransfrom = (new TripleDESCryptoServiceProvider()).CreateDecryptor(_key, _iv))
{
    var cryptStream = new CryptoStream(memStream, cryptoTransfrom, CryptoStreamMode.Write);
    string convertedValue = ConvertHexToDec(value);
    byte[] decryptBytes = Convert.FromBase64String(convertedValue); //<-- Error line      
    cryptStream.Write(decryptBytes, 0, decryptBytes.Length);
    cryptStream.FlushFinalBlock();
    cryptStream.Close();
    decodedVal = Encoding.ASCII.GetString(memStream.ToArray());
}

现在,错误当然仍然会发生,但它不会使 .NET 运行时崩溃,因此运行正常。此外,将 try/catch-rethrow 放在之前的位置也可以防止此类崩溃。

我怀疑,它与嵌套using有关。内部 using 并不是真正需要的,因为 CryptoStream 只是包装了内存流和转换。如果错误发生在大括号内,它将首先传播到转换的try/catch,然后传播到内存流。

但是考虑到这只发生在为 x64 构建的程序集运行并在 x64 ASP.NET 池中运行时,有人可以解释这种行为吗?当应用程序为 x86 编译并在 32 位池中运行时,不会发生这种情况。

毫无疑问是运行时的bug。由于您使用的运行时版本非常旧,我的建议是升级。

But can someone explain such behavior considering that this only happens when assembly runs built for x64 and runs in x64 ASP.NET pool? When application compiled for x86 and runs in 32-bit pool, it doesn't happen.

x64 和 x86 抖动是该版本中完全不同的代码库。一个严重到足以导致运行时崩溃的错误涉及嵌套 try-finally 块中奇怪的代码生成错误几乎肯定是特定抖动所独有的。