We have this simple code that was converted from vb.net where it wasn't constructed using using/end using
. During conversion we utilized using
in c#.
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());
}
But there was try/catch
(see comments) surrounding Convert.FromBase64String(convertedValue)
. What we didn't realize, is that value
sometimes came as plain, un-base64-encoded value. So, when un-encoded value hit "Error line" - try/catch
did the business of re-throw. But, when you look at the code above, when such value causes exception at that line - .NET Runtime crashes. Here is event log
.NET Runtime version 2.0.50727.5485 - Fatal Execution Engine Error (000007FEE581600A) (80131506)
And exception, of cource, just normal
Invalid character in a Base-64 string.
I fixed it buy removing inner 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());
}
Now, error, of course still, occurs but it doesn't crash .NET Runtime, therefore acts normal. Also, placing try/catch-rethrow
where it was before would prevent such crash as well.
I suspect, it has something to do with nested using
. Inner using
is not really needed because CryptoStream
simply wraps memory stream and transformation. And if error occurs inside curly brackets, it will be propagated to try/catch
of transformation first and then memory stream.
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.
It is undoubtedly a bug in the runtime. Since you are using an extremely old version of the runtime, my advice is to upgrade.
The x64 and x86 jitters were completely different codebases in that version. A bug severe enough to crash the runtime involving weird codegen bugs in nested try-finally blocks will almost certainly be unique to a particular jitter.