Тем не менее проблема «множественного удаления», хотя и решена - PullRequest
0 голосов
/ 05 ноября 2018

В некоторых моих проектах я использовал пару проверенных и надежных методов шифрования / дешифрования данных (метод шифрования приведен ниже). Но я всегда преследовал это ноющее предупреждение CA2202 («Не удаляйте объекты несколько раз») об объекте memoryStream. Я считаю, что справляюсь с этим надлежащим образом, но я все равно получаю предупреждение всякий раз, когда запускаю анализ в Visual Studio. Это никогда не вызывает исключений в производственном коде, но я все же хотел бы избавиться от предупреждения раз и навсегда. Это возможно? Или я должен просто игнорировать это? Заранее спасибо.

public static string Encrypt(string clearText, string passPhrase, string saltValue)
{
    byte[] clearTextBytes = Encoding.UTF8.GetBytes(clearText);
    byte[] saltValueBytes = Encoding.UTF8.GetBytes(saltValue);

    Rfc2898DeriveBytes passPhraseDerviedBytes = new Rfc2898DeriveBytes(passPhrase, saltValueBytes);
    byte[] keyBytes = passPhraseDerviedBytes.GetBytes(32);
    byte[] initVectorBytes = passPhraseDerviedBytes.GetBytes(16);

    RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC };
    ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);

    byte[] cipherTextBytes = null;
    MemoryStream memoryStream = null;
    try
    {
        memoryStream = new MemoryStream();
        using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
        {
            cryptoStream.Write(clearTextBytes, 0, clearTextBytes.Length);
            cryptoStream.FlushFinalBlock();
            cipherTextBytes = memoryStream.ToArray();
        }
    }
    finally
    {
        if (memoryStream != null)
        {
            memoryStream.Dispose();
        }
    }

    return Convert.ToBase64String(cipherTextBytes);
}

Ответы [ 2 ]

0 голосов
/ 05 ноября 2018

Проблема заключается в том, что вызов CryptoStream.Dispose может вызвать избавиться от заданного потока:

protected override void Dispose(bool disposing) 
{
    try 
    {
        if (disposing) 
        {
            if (!_finalBlockTransformed) 
            {
                FlushFinalBlock();
            }
            if (!_leaveOpen) 
            {
                _stream.Close();
            }
        }
    }
    ...
}

Если вы используете конструктор, который принимает 4 параметра:

CryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode, bool leaveOpen)

Последний аргумент определяет, является ли поток закрытым или нет. Вызов Close(), в свою очередь, по умолчанию также вызывает Dispose:

public virtual void Close()
{
    /* These are correct, but we'd have to fix PipeStream & NetworkStream very carefully.
    Contract.Ensures(CanRead == false);
    Contract.Ensures(CanWrite == false);
    Contract.Ensures(CanSeek == false);
    */

    Dispose(true);
    GC.SuppressFinalize(this);
}

Таким образом, похоже, что проверка не может правильно определить, будет ли конкретная реализация Stream удалена или нет, и вернется к мысли, что так и будет, - вот этот случай.

Обратите внимание, однако, что в большинстве случаев удаление дважды, один или ноль раз MemoryStream не имеет большого значения.

0 голосов
/ 05 ноября 2018

Это потому что CryptoStream закрывает memoryStream

Вы используете конструктор

public CryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode)
    : this(stream, transform, mode, false) {
}

который звонит

public CryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode, bool leaveOpen) {
    _stream = stream;
    _leaveOpen = leaveOpen;
    //...
}

_leaveOpen и _stream позже используются в Dispose

protected override void Dispose(bool disposing) {
    try {
        if (!_leaveOpen) {
            _stream.Close();
        }
        //...
    }
}

Вы можете удалить memoryStream.Dispose(); или передать true в качестве параметра CryptoStream конструктору

using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write, true)) { }

ссылка на исходный код github

...