2017-02-01 6 views
1

Следующий код является упрощенным выпиской из части нашего производственного кода. Он вычисляет SHA256 хэш файла и возвращает его в виде строки, или возвращает null, если файл не доступен:Исключительный фильтр вызывает CA2000, несмотря на использование оператора

private static string CalculateHash(string fileName) 
{ 
    try 
    { 
     string result; 
     using (SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider()) 
     { 
      byte[] data = File.ReadAllBytes(fileName); 
      result = BitConverter.ToString(sha256.ComputeHash(data)); 
     } 

     Debug.WriteLine("Calculated hash for '" + fileName + "': " + result, 3); 
     return result; 
    } 
    catch (UnauthorizedAccessException ex) 
    { 
     Debug.WriteLine("The hash calculation failed: " + ex.Message, 3); 
     return null; 
    } 
    catch (IOException ex) 
    { 
     Debug.WriteLine("The hash calculation failed: " + ex.Message, 3); 
     return null; 
    } 
} 

Один из наших разработчиков недавно переработан код, используя фильтр исключений для уменьшения дубликатов catch блоков , так что теперь выглядит следующим образом:

private static string CalculateHash(string fileName) 
{ 
    try 
    { 
     string result; 
     using (SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider()) 
     { 
      byte[] data = File.ReadAllBytes(fileName); 
      result = BitConverter.ToString(sha256.ComputeHash(data)); 
     } 

     Debug.WriteLine("Calculated hash for '" + fileName + "': " + result, 3); 
     return result; 
    } 
    catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException) 
    { 
     Debug.WriteLine("The hash calculation failed: " + ex.Message, 3); 
     return null; 
    } 
} 

Однако теперь мы получаем предупреждение анализа кода:

CA2000 - в методе 'CalculateHash (строка)', вызовите System.IDisposable. Утилизируйте объект «sha256» до того, как все ссылки на него выходят за рамки.

Как я вижу, здесьнаходится здесь правильно, и это произойдет, если исключение поймает фильтр или нет.

Является ли этот CA2000 ложным положительным или имеет фильтр исключений, созданный сценарий, в котором удаление не произойдет?

+0

Я также получаю 'CA2202' с' when' в вашем примере (комментируя это устранит все предупреждения). Кажется, проблема с анализом кода. 'finally' (из [' using'] (https://msdn.microsoft.com/en-us/library/yh598w02.aspx)) гарантированно будет выполняться перед любым ** внешним ** 'catch'. – Sinatr

ответ

0

Похоже, что это ложноположительный и может быть безопасно подавлен.

Я сравнивал промежуточный язык для обеих версий метода. Оба они показывают оператор using как блок try/finally, который правильно удаляет объект. Фактически IL идентичен для обоих методов, за исключением секции внешнего фильтра catch/exception.

.try 
{ 
    IL_0000: newobj  instance void [System.Core]System.Security.Cryptography.SHA256CryptoServiceProvider::.ctor() 
    IL_0005: stloc.1 V_1 
    .try 
    { 
    IL_0006: ldarg.0 fileName 
    IL_0007: call   unsigned int8[] [mscorlib]System.IO.File::ReadAllBytes(string) 
    IL_000c: stloc.2 'buffer [Range(Instruction(IL_000c stloc.2)-Instruction(IL_000e ldloc.2))]' 
    IL_000d: ldloc.1 V_1 
    IL_000e: ldloc.2 'buffer [Range(Instruction(IL_000c stloc.2)-Instruction(IL_000e ldloc.2))]' 
    IL_000f: callvirt  instance unsigned int8[] [mscorlib]System.Security.Cryptography.HashAlgorithm::ComputeHash(unsigned int8[]) 
    IL_0014: call   string [mscorlib]System.BitConverter::ToString(unsigned int8[]) 
    IL_0019: stloc.0 'string [Range(Instruction(IL_0019 stloc.0)-Instruction(IL_0026 ldloc.0))]' 
    IL_001a: leave.s  IL_0026 
    } // end of .try 
    finally 
    { 
    IL_001c: ldloc.1 V_1 
    IL_001d: brfalse.s IL_0025 
    IL_001f: ldloc.1 V_1 
    IL_0020: callvirt  instance void [mscorlib]System.IDisposable::Dispose() 
         /* ^^ here we can see the Dipose method being called 
         * in the finally block 
         */ 
    IL_0025: endfinally 
    } // end of finally 
    IL_0026: ldloc.0 'string [Range(Instruction(IL_0019 stloc.0)-Instruction(IL_0026 ldloc.0))]' 
    IL_0027: stloc.3 V_3 
    IL_0028: leave.s  IL_0034 
} // end of .try 
// ... catch or exception filter IL code then appears here ... 
Смежные вопросы