Profile Registry Leak

This document describes a proposed solution to the registry leak problem that we could not fix for Windows 2000.  Bugs 173929 and 435236 are partly caused by the registry leak.  Here is one example of the problem.  When a user logs off, userenv tries to unload the user's profile.  Sometimes some process has a key open in the registry.  This prevents userenv from unloading the hive.  The spreadsheet below lists most of the known causes of the bug.

 

This bug has three symptoms that affect users.  First, if userenv cannot unload the profile when the user logs off, userenv does not save the user's profile to the server.  Second, since such profiles never get unloaded, they end up using a lot of memory on a terminal server that has lots of users logging in.  Third, if the profile is still loaded the next time the user logs in, any changes stored on the server are not loaded and are lost.

I have a separate solution for each symptom.  Currently when a user logs off, if the profile is locked we poll the profile for 60 seconds before giving up.  I would change the code to use RegSaveKey to save the hive at the end of the 60 second delay rather then giving up.

To solve the second symptom, the memory leak, I propose using a new API that will soon be checked in.  With this API we can tell the registry to set an event when no one is using the specified hive.  At that point we can unload the hive.  Our code would change so that after waiting 60 seconds for a hive to be unlocked, we would use the new API to receive notice when the hive was finally free.  We would have to add a thread to wait for each group of 64 hives (WaitForMultipleObjects can only wait for 64 events).  We would have to add code to tell the helper thread which hives to wait for.  We would have to add code to synchronize the helper thread and LoadUserProfile in the case where the user logs back in before the hive gets unloaded.  This does not completely solve the problem because wininet never releases some of the keys that it uses.  However it makes sure that we behave correctly should wininet ever get fixed.  We can show the terminal server team what dlls are leaking registry keys and they can spend the time getting the dlls fixed.

NtUnloadKeyEx(

    IN POBJECT_ATTRIBUTES TargetKey,

    IN HANDLE Event OPTIONAL

    )

It is unclear if we should solve the last symptom.  Currently userenv does not handle overlapped logon sessions well.  Userenv will lose one set of changes.  A solution to that problem would probably solve this problem.  We could solve this problem by using another new API.  This API will let us rename a key even when it is in use.  If a user logs on and his hive is loaded because the user has another logon session on the machine, we will use the loaded hive and lose any changes on the server.  If a user logs on and his hive is loaded because some program still has a key open from the last logon session (or some program has loaded the hive for its own use), then we will rename the key and load the profile from the server.  This requires that we change our code as described above.  Unfortunately, since the name ntuser.dat is already taken, we need to use a new name for the hive from the server and remember that when the user logs out.  At that time we need to make sure we copy the new hive and attempt to delete the old hive.  We need to handle the case where the user has multiple hives leaked simultaneously.

NTSTATUS

NtRenameKey(

    IN HANDLE           KeyHandle,

    IN PUNICODE_STRING  NewName

    )