2014-10-27 17 views
7

Tôi đang gặp sự cố với một số mã tôi duy trì. Mã bên dưới có thành viên private static SHA1 (là IDisposable nhưng vì nó là static, nên không bao giờ được hoàn tất). Tuy nhiên, khi bị căng thẳng mã này ném một ngoại lệ cho thấy nó đã bị đóng cửa:Tại sao SHA1.ComputeHash không hoạt động dưới tải cao với nhiều luồng?

Caught exception. Safe handle has been closed" 
Stack trace: Call stack where exception was thrown 
at System.Runtime.InteropServices.SafeHandle.DangerousAddRef(Boolean& success) 
at System.Security.Cryptography.Utils.HashData(SafeHashHandle hHash, Byte[] data, Int32 cbData, Int32 ibStart, Int32 cbSize) 
at System.Security.Cryptography.Utils.HashData(SafeHashHandle hHash, Byte[] data, Int32 ibStart, Int32 cbSize) 
at System.Security.Cryptography.HashAlgorithm.ComputeHash(Byte[] buffer) 

Mã này trong câu hỏi là:

internal class TokenCache 
{ 
    private static SHA1 _sha1 = SHA1.Create(); 

    private string ComputeHash(string password) 
    { 
     byte[] passwordBytes = UTF8Encoding.UTF8.GetBytes(password); 
     return UTF8Encoding.UTF8.GetString(_sha1.ComputeHash(passwordBytes)); 
    } 

Câu hỏi của tôi rõ ràng là những gì có thể gây ra vấn đề này. Có thể gọi tới số SHA1.Create không thành công (có bao nhiêu tài nguyên mã hóa)? Điều này có thể được gây ra bởi appdomain đi xuống?

Bất kỳ lý thuyết nào khác?

+0

gì này có liên quan gì với Vứt bỏ? Ngoài ra, lớp "SHA1" là gì? –

+1

Bạn có chắc chắn lớp SHA1 là chủ đề an toàn không? Bạn có thể lấy mật khẩu được băm khi nó không thành công? – Rob

+0

@John Saunders, xin lỗi bạn đã đúng. Điều này không liên quan gì đến Vứt bỏ. Tôi nghĩ rằng finalizer trên System.Security.Cryptography.SHA1CryptoServiceProvider có thể đã được kích hoạt bằng cách nào đó. http://msdn.microsoft.com/en-us/library/e7hyyd4e(v=vs.110).aspx – MvdD

Trả lời

23

Theo the documentation cho lớp HashAlgorithm cơ sở

Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

Bạn không nên chia sẻ những lớp giữa các chủ đề mà chủ đề khác nhau cố gắng và gọi ComputeHash trên cùng một ví dụ cùng một lúc.

EDIT Đây là nguyên nhân gây ra lỗi của bạn. Bài kiểm tra căng thẳng dưới đây cho ra nhiều lỗi do nhiều chủ đề gọi ComputeHash trên cùng một cá thể thuật toán băm. Lỗi của bạn là một trong số đó.

Cụ thể, tôi đã thấy các lỗi sau đây với kiểm tra căng thẳng này:

  • System.Security.Cryptography.CryptographicException: Hash không hợp lệ để sử dụng trong nhà nước quy định.
  • System.ObjectDisposedException: xử lý an toàn đã bị đóng cửa

Căng thẳng mã kiểm tra mẫu:

const int threadCount = 2; 
var sha1 = SHA1.Create(); 
var b = new Barrier(threadCount); 
Action start =() => { 
        b.SignalAndWait(); 
        for (int i = 0; i < 10000; i++) 
        { 
         var pwd = Guid.NewGuid().ToString(); 
         var bytes = Encoding.UTF8.GetBytes(pwd); 
         sha1.ComputeHash(bytes); 
        } 
       }; 
var threads = Enumerable.Range(0, threadCount) 
         .Select(_ => new ThreadStart(start)) 
         .Select(x => new Thread(x)) 
         .ToList(); 
foreach (var t in threads) t.Start(); 
foreach (var t in threads) t.Join(); 
+0

Rủi ro đáng chú ý, tay cầm an toàn có vẻ ổn. Nhưng không thể phủ nhận, câu trả lời tốt. –

+1

@HansPassant. Cảm ơn bạn. Tôi có thể đoán nó có thể là phương thức 'SHA1CryptoServiceProvider.Initialize', có vẻ như không an toàn' Dispose' và sau đó tạo lại trên trường '_safeHashHandle'. –

+0

Hehe, bizarro, Initialize() được gọi là * sau * tính toán hàm băm. Phải là một loại điều an toàn. Bạn hiểu rồi. –

Các vấn đề liên quan