Bug in file version parsing for GAC file replacement in .NET Framework 1.1

I was on a mail thread this week about a bug in the .NET Framework 1.1. There was a logic problem within Fusion that causes assemblies in the GAC to not be updated by Windows Installer if an assembly with the same assembly version but different file version is already present and if the string length of the file version is greater than the string length of the assembly version.

Our setup team found an instance of this problem immediately before shipping the .NET Framework 1.1 and Visual Studio .NET 2003 in this scenario: some internal customers had an RC (release candidate) version of the .NET Framework 1.1 and Visual Studio .NET 2003 installed, then uninstalled them in order to install the final build. Some folks uninstalled the .NET Framework 1.1 first, and if they had no other version of the .NET Framework on their machine there was no longer any version of fusion on the machine so uninstalling Visual Studio or the J# redistributable pack would leave behind assemblies in the GAC. When we attempted to validate the installation of the final build we found that some of the assemblies in the GAC were still the RC version.

At any rate, I found out this week that there was supposed to be a knowledge base article written for this issue but it ended up not being published, so I wanted to post the contents here. Note that this issue has been fixed in the .NET Framework 1.1 SP1 and in the upcoming version 2.0.

Title:

FileVersion attribute in assembly name table is not honored during install and uninstall of assemblies

Description:

.NET Framework v1.1 has a feature that allows MSI authors to specify an attribute called FileVersion in the assembly name table. During installs, MSI takes all the attributes in the assembly name table, and concatenates them together to form an assembly display name. This display name is used to query to see if the assembly is already in the GAC or not (to know whether or not it needs to do the installed). The FileVersion attribute was added so that MSI could query whether or not the assembly in the GAC has an older file version than what the MSI is carrying, so in-place patches can be installed properly.

There is a bug parsing the FileVersion=w.x.y.z attribute in the display name. Briefly, the parsing code takes a pointer to the attribute value and a size field. The size field passed in is the size of the assembly version rather than the file version. So, if the file version ends up being longer in length (string length) than the assembly version, we prematurely terminate parsing of the file version, and end up comparing the wrong file version. This could cause patches to not get installed when you think they should.

Workaround:

In the assembly name table, pad the Version field with leading zeros to workaround this problem. For example, if your assembly name is "Foo, Version=1.0.0.0, culture=neutral, publickeytoken=123456abcdef, FileVersion=1.0.3500.0" you would hit this problem since length of FileVersion field is longer than length of Version field. Modify assembly name to contain Version=00001.0.0.0 to workaround the problem.