WIF: Memory leak issue with WIF 3.5 - Microsoft.IdentityModel.Tokens - SecurityTokenCacheKey

 Issue: Recently we came across a case where memory leak issue is identified within WIF 3.5 DLL inside the "Microsoft.IdentityModel.Tokens" class.

How does this happen: 
The source code has a coding BUG where "SecurityTokenCacheKey" are not getting cleared off properly.

Impacted heap structures seen in memory dumps: 
00007ff97bbb0038   371165     17815920 System.Collections.Generic.LinkedListNode`1[[System.Object, mscorlib]]
00007ff97bba6f48   371230     17819040 Microsoft.IdentityModel.Tokens.SecurityTokenCacheKey
00007ff9d8ebf6c0   454411     49868362 System.String
00007ff9d8ec5140   317533     66612435 System.Byte[]
Root cause: 
These objects are rooted inside the WCF Session
0:000> !gcroot 000000a3d91bd030
Thread 1b7c:
    000000a82549e270 00007ff9d7a23574 System.Runtime.IOThreadTimer+TimerManager.OnWaitCallback(System.Object)
        rbx: 
            ->  000000a65942cc90 System.Runtime.IOThreadTimer+TimerManager
            ->  000000a65942cd08 System.Runtime.IOThreadTimer+TimerGroup
            ->  000000a65942cd80 System.Runtime.IOThreadTimer+TimerQueue
            ->  000000a6596a3bd0 System.Object[]
            ->  000000a65942cc50 System.Runtime.IOThreadTimer
            ->  000000a65942cc10 System.Action`1[[System.Object, mscorlib]]
            ->  000000a659405b50 System.ServiceModel.Security.SecuritySessionServerSettings
             ->  000000a6593f5c60 System.ServiceModel.Security.SessionSymmetricMessageSecurityProtocolFactory  <------------------ 
            ->  000000a659405a78 System.ServiceModel.Security.SecurityStandardsManager
            ->  000000a6594038e8 Microsoft.IdentityModel.Tokens.SecurityTokenSerializerAdapter
            ->  000000a6593c5da0 Microsoft.IdentityModel.Tokens.SecurityTokenHandlerCollection
            ->  000000a6593c5e78 System.Collections.Generic.List`1[[Microsoft.IdentityModel.Tokens.SecurityTokenHandler, Microsoft.IdentityModel]]
            ->  000000a6593c63f8 System.Object[]
            ->  000000a6593bbdc8 Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler
            ->  000000a6593bbec8 Microsoft.IdentityModel.MruSecurityTokenCache
            ->  000000a6593bbf28 System.Collections.Generic.Dictionary`2[[System.Object, mscorlib],[Microsoft.IdentityModel.MruSecurityTokenCache+CacheEntry, Microsoft.IdentityModel]]
            ->  000000a801191038 System.Collections.Generic.Dictionary`2+Entry[[System.Object, mscorlib],[Microsoft.IdentityModel.MruSecurityTokenCache+CacheEntry, Microsoft.IdentityModel]][]
            ->  000000a5da531be8 System.Collections.Generic.LinkedListNode`1[[System.Object, mscorlib]]
            ->  000000a6593c5d70 System.Collections.Generic.LinkedList`1[[System.Object, mscorlib]]
            ->  000000a65b0f25b8 System.Collections.Generic.LinkedListNode`1[[System.Object, mscorlib]]
            ->  000000a4d91b2a98 System.Collections.Generic.LinkedListNode`1[[System.Object, mscorlib]]
            ->  000000a4d91cfbe8 System.Collections.Generic.LinkedListNode`1[[System.Object, mscorlib]]
            ->  000000a4d91cfd10 System.Collections.Generic.LinkedListNode`1[[System.Object, mscorlib]]


0:000> !gcroot 000000a3d9eac378
Thread 1b7c:
    000000a82549e270 00007ff9d7a23574 System.Runtime.IOThreadTimer+TimerManager.OnWaitCallback(System.Object)
        rbx: 
            ->  000000a65942cc90 System.Runtime.IOThreadTimer+TimerManager
            ->  000000a65942cd08 System.Runtime.IOThreadTimer+TimerGroup
            ->  000000a65942cd80 System.Runtime.IOThreadTimer+TimerQueue
            ->  000000a6596a3bd0 System.Object[]
            ->  000000a65942cc50 System.Runtime.IOThreadTimer
            ->  000000a65942cc10 System.Action`1[[System.Object, mscorlib]]
            ->  000000a659405b50 System.ServiceModel.Security.SecuritySessionServerSettings
            ->  000000a6593f5c60 System.ServiceModel.Security.SessionSymmetricMessageSecurityProtocolFactory
            ->  000000a659405a78 System.ServiceModel.Security.SecurityStandardsManager
            ->  000000a6594038e8 Microsoft.IdentityModel.Tokens.SecurityTokenSerializerAdapter
            ->  000000a6593c5da0 Microsoft.IdentityModel.Tokens.SecurityTokenHandlerCollection
            ->  000000a6593c5e78 System.Collections.Generic.List`1[[Microsoft.IdentityModel.Tokens.SecurityTokenHandler, Microsoft.IdentityModel]]
            ->  000000a6593c63f8 System.Object[]
             ->  000000a6593bbdc8 Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler   <---------------- 
             ->  000000a6593bbec8 Microsoft.IdentityModel.MruSecurityTokenCache   <--------------------------------- 
            ->  000000a6593bbf28 System.Collections.Generic.Dictionary`2[[System.Object, mscorlib],[Microsoft.IdentityModel.MruSecurityTokenCache+CacheEntry, Microsoft.IdentityModel]]
            ->  000000a801191038 System.Collections.Generic.Dictionary`2+Entry[[System.Object, mscorlib],[Microsoft.IdentityModel.MruSecurityTokenCache+CacheEntry, Microsoft.IdentityModel]][]
            ->  000000a5da531be8 System.Collections.Generic.LinkedListNode`1[[System.Object, mscorlib]]
            ->  000000a6593c5d70 System.Collections.Generic.LinkedList`1[[System.Object, mscorlib]]
            ->  000000a65b0f25b8 System.Collections.Generic.LinkedListNode`1[[System.Object, mscorlib]]
            ->  000000a4d91b2a98 System.Collections.Generic.LinkedListNode`1[[System.Object, mscorlib]]
            ->  000000a4d91cfbe8 System.Collections.Generic.LinkedListNode`1[[System.Object, mscorlib]]
            ->  000000a4d91cfd10 System.Collections.Generic.LinkedListNode`1[[System.Object, mscorlib]]


Relevant call stack: 
0:046> !clrstack
OS Thread Id: 0x3770 (46)
        Child SP               IP Call Site
000000a826d7cdc0 00007ff9d836ef84 System.Collections.Generic.LinkedList`1[[System.__Canon, mscorlib]].Find(System.__Canon)
000000a826d7ce20 00007ff97bc84f10 Microsoft.IdentityModel.MruSecurityTokenCache.TryRemoveAllEntries(System.Object)
000000a826d7cf70 00007ff9d69700e9 System.ServiceModel.Security.SecuritySessionServerSettings+ServerSecuritySessionChannel.CloseCore(System.TimeSpan)
000000a826d7cff0 00007ff9d696df41 System.ServiceModel.Security.SecuritySessionServerSettings+ServerSecurityDuplexSessionChannel.CloseCore(System.TimeSpan)
000000a826d7d030 00007ff9d696e28c System.ServiceModel.Security.SecuritySessionServerSettings+ServerSecurityDuplexSessionChannel.OnClose(System.TimeSpan)
000000a826d7d0a0 00007ff9d5ce38d8 System.ServiceModel.Channels.CommunicationObject.Close(System.TimeSpan)
000000a826d7d1e0 00007ff9d5cf75d6 System.ServiceModel.Channels.ServiceChannel.OnClose(System.TimeSpan)
000000a826d7d240 00007ff9d5ce38d8 System.ServiceModel.Channels.CommunicationObject.Close(System.TimeSpan)  <---------- 


So eventually all the TokenCacheKey object are actually referenced by:
public class MruSecurityTokenCache : SecurityTokenCache<br>{<br>}<br>Solution: 


After discussing with WIF PG, we confirmed that it was identified as internal BUG long time back and already fixed in latest framework release (4.6.2).
With new release, WIF is tightly integrated with framework and issue does not happen.


Hope this helps! 

Thanks
Saurabh Somani