Search

PasswordDeriveBytes and RijndaelManaged don't dispose resources by pmackay

Closed
as Fixed Help for as Fixed

1
Sign in to vote
0
Sign in to vote
Sign in
to vote
Type: Bug
ID: 254236
Opened: 1/27/2007 9:16:41 AM
Access Restriction: Public
0
Workaround(s)
0
User(s) can reproduce this bug
The use of PasswordDeriveBytes and RijndaelManaged produces .net memory leaks in the application.

This occurs in .net 1.1 and 2.0, but 1.1 has more issues than 2.0.

Doing a test with 5000 iterations over a function that does encryption, and after calling every Dispose, Clear or Close method available, some objects still remain in memory.

Using psscor !dumpheap -stat on the dump after the processing, the results were:

        MT     Count     TotalSize Class Name
0x79be5180     4,335        52,020 System.Security.Cryptography.RNGCryptoServiceProvider
0x79c01c20     4,335        86,700 System.Security.Cryptography.__HashHandleProtector
0x79bfde14     4,335     156,060 System.Security.Cryptography.MD5CryptoServiceProvider
0x79c21764     4,335     225,420 System.Security.Cryptography.PasswordDeriveBytes
0x79be5384     8,671     242,788 System.Security.Cryptography.CspParameters
0x00150340     2,490     710,996     Free
0x00a726b0     39,017     764,564 System.Byte[]
0x79c209ac     13,002     832,128 System.Security.Cryptography.CryptoStream

After checking the code of PasswordDeriveBytes and RijndaelManager with netreflector, I detected 4 problems in PasswordDeriveBytes and 1 in RijndaelManager.

The 4 problems in PasswordDeriveBytes are.
Method ComputeBaseValue, CryptoStream object not disposed (1.1)
Method ComputeBytes, two CryptoStream objects not disposed (1.1 and 2.0)
Method CryptDeriveKey, SymmetricAlgorithm object not disposed (1.1)
And the HashAlgorithm internal variable is never disposed when the PasswordDeriveBytes object is Disposed (1.1) or Finalized (2.0)

After implementing my own PasswordDeriveByte class using .netreflector to get the code, and implementing the changes I'm suggesting, including a new dispose method, dumpheap -stat returned:

0x00a7209c         13        10,776 System.Object[]
0x00a72964         24        17,096 System.Int32[]
0x79b925c8        325        24,312 System.String
0x00150340         67        47,972     Free
0x79be5180     4,335        52,020 System.Security.Cryptography.RNGCryptoServiceProvider

After digging more code, I found that the RijndaelManaged never disposed the private variable _rng when it's being disposed and that has a reference to RNGCryptoServiceProvider. That variable holds the 4335 objects in memory..
Details (expand)
Product Language
English

Version

.NET Framework 2.0
Operating System
Windows XP Professional
Operating System Language
English
Steps to Reproduce
1.- Create a function that encrypts and use passwordderivebytes
2.- Try to dispose/clear/close as many as you can
3.- call it repeteadly
4.- take a dump
5.- check the memory with windbg+psscor looking for objects that are still in memory.

All the objects are in gen 2, without root and cosuming it.
Actual Results
Objects remain in memory, consuming it from a server. There's no way to remove that objects due to the lack of calling the Dispose methods in classes where is needed/expected.
Expected Results
That the memory used by PasswordDeriveBytes and RijndaelManajed were disposed without the need of restart the epplication.
TAP Code (if applicable)
 
      You can indicate your satisfaction with how Microsoft handled this issue by completing this quick 3 question survey. [Details]

 

File Attachments
0 attachments
Sign in to post a comment.
Posted by Microsoft on 2/8/2007 at 4:18 PM
Thank you for reporting this. I've confirmed some of the disposing issues that you've pointed out, and they will be fixed in an upcoming release of the CLR. The RNGCryptoServiceProvider instance is actually stored as a static for the AppDomain, as we will reuse it for various operations during the life of the domain.

-Shawn Farkas [MS]
Posted by pmackay on 2/9/2007 at 6:42 AM
Shawn, thank you for the confirmation you gave.

I have some doubts regarding the _rng variable and the domain. What could be a workaround if I have to do many encryptions? Creating a new domain, executing the code inside it and then unload it? That will be very expensive.
Posted by Microsoft on 2/9/2007 at 8:01 AM
There should only be one instance created in each AppDomain, so if you stay within the domain, then you should not see multiple _rng's created. In fact creating multiple AppDomains would make things worse because each domain gets its own _rng.

-Shawn
Posted by pmackay on 2/9/2007 at 8:28 AM
You're right. I was confused because I thought that that variable (_rng) was the one was leaking the 4335 items in my demo, but checking the RNG property, there could be only one instance.

That's makes me wonder, who created those 4335 or 4334 items that are left in memory.
Posted by pmackay on 2/10/2007 at 4:11 PM
Shawn, I was thinking about what you told me about the _rng variable in RijndaelManaged and the 4335 objects that are still in memory.
I did further analysis and I determined that those objects are still in memory because they’re never disposed. Please note that I’m referring to 1.1 RijndaelManaged’s implementation. Version 2.0 doesn’t seem to have that variable.
I get a dump after my demo finished working and 25 RijndaelManaged objects where still in memory. What I want to prove is that each version of RijndaelManaged has its own instance of RNGCryptoServiceProvider, and they are no domain-shared.

I hope that this help.


0:000> !dumpheap -stat
..cut for brevity ....
0x00a6209c         27        11,016 System.Object[]
0x00a626b0        373        15,176 System.Byte[]
0x00a62964        193        27,844 System.Int32[]
0x79b925c8        371        29,832 System.String
0x79be5180     4,335        52,020 System.Security.Cryptography.RNGCryptoServiceProvider
Total 5,780 objects, Total size: 166,824



0:000> !dumpheap -mt 0x79c0054c        
Address         MT     Size Gen
0x01183d2c 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x01184348 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x01184d40 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x01185418 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x011864c0 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x01186e80 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x01187558 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x01188600 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x01188fc0 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x01189698 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x0118a740 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x0118b100 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x0118b7d8 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x0118c880 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x0118d240 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x0118d918 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x0118e9c0 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x0118f380 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x0118fa58 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x01190b00 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x011914c0 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x01191b98 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x01192c40 0x79c0054c     48    1 System.Security.Cryptography.RijndaelManaged
0x01193814 0x79c0054c     48    0 System.Security.Cryptography.RijndaelManaged
0x01194430 0x79c0054c     48    0 System.Security.Cryptography.RijndaelManaged




0:000> !do 0x01183d2c
Name: System.Security.Cryptography.RijndaelManaged
MethodTable 0x79c0054c
EEClass 0x79c00604
Size 48(0x30) bytes
GC Generation: 1
mdToken: 0x02000264 (c:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll)
FieldDesc*: 0x79c00668
        MT     Field     Offset                 Type     Attr     Value Name
0x79bf98a4 0x4000b27     0x14         System.Int32 instance 128 BlockSizeValue
0x79bf98a4 0x4000b28     0x18         System.Int32 instance 128 FeedbackSizeValue
0x79bf98a4 0x4000b29     0x4                CLASS instance 0x00000000 IVValue
0x79bf98a4 0x4000b2a     0x8                CLASS instance 0x00000000 KeyValue
0x79bf98a4 0x4000b2b     0xc                CLASS instance 0x01179548 LegalBlockSizesValue
0x79bf98a4 0x4000b2c     0x10                CLASS instance 0x01179570 LegalKeySizesValue
0x79bf98a4 0x4000b2d     0x1c         System.Int32 instance 256 KeySizeValue
0x79bf98a4 0x4000b2e     0x20         System.Int32 instance 1 ModeValue
0x79bf98a4 0x4000b2f     0x24         System.Int32 instance 2 PaddingValue
0x79c003ac 0x4000bdb        0                CLASS     shared static s_legalBlockSizes
    >> Domain:Value 0x001695b0:0x01179548 <<
0x79c003ac 0x4000bdc     0x4                CLASS     shared static s_legalKeySizes
    >> Domain:Value 0x001695b0:0x01179570 <<
0x79c0054c 0x4000bdd     0x28                CLASS instance 0x01183d88 _rng



0:000> .foreach ( o {!dumpheap -mt 0x79c0054c -short} ) { dd poi(${o}+28) L1}
01183d88 79be5180
011843a4 79be5180
01184d9c 79be5180
01185474 79be5180
0118651c 79be5180
01186edc 79be5180
011875b4 79be5180
0118865c 79be5180
0118901c 79be5180
011896f4 79be5180
0118a79c 79be5180
0118b15c 79be5180
0118b834 79be5180
0118c8dc 79be5180
0118d29c 79be5180
0118d974 79be5180
0118ea1c 79be5180
0118f3dc 79be5180
0118fab4 79be5180
01190b5c 79be5180
0119151c 79be5180
01191bf4 79be5180
01192c9c 79be5180
01193870 79be5180
0119448c 79be5180


0:000> !do 01183d88
Name: System.Security.Cryptography.RNGCryptoServiceProvider
MethodTable 0x79be5180
EEClass 0x79be51ec
Size 12(0xc) bytes
GC Generation: 1
mdToken: 0x02000258 (c:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll)
FieldDesc*: 0x79be5250
        MT     Field     Offset                 Type     Attr     Value Name
0x79be5180 0x4000b9f     0x4         System.Int32 instance 1650464 _hCSP
0x79be5180 0x4000ba0        0                CLASS     shared static _cspDefParams
    >> Domain:Value 0x001695b0:0x01179598 <<



0:000> !do 0118d974
Name: System.Security.Cryptography.RNGCryptoServiceProvider
MethodTable 0x79be5180
EEClass 0x79be51ec
Size 12(0xc) bytes
GC Generation: 1
mdToken: 0x02000258 (c:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll)
FieldDesc*: 0x79be5250
        MT     Field     Offset                 Type     Attr     Value Name
0x79be5180 0x4000b9f     0x4         System.Int32 instance 1650464 _hCSP
0x79be5180 0x4000ba0        0                CLASS     shared static _cspDefParams
    >> Domain:Value 0x001695b0:0x01179598 <<

Posted by Microsoft on 2/13/2007 at 8:02 AM
You are correct, I was looking at only the v2.0 implementation. In v1.x _rng was an instance member. This change does not currently meet the bar for a v1.1 servicing release however, but I will fix the other issues in a future release of the framework.

Thank you again for reporting these issues.

-Shawn