Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issue producing metadata references in VS #73345

Merged
merged 22 commits into from
May 6, 2024

Conversation

CyrusNajmabadi
Copy link
Member

Regression introduced in #73115.

@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner May 6, 2024 02:39
@dotnet-issue-labeler dotnet-issue-labeler bot added Area-IDE untriaged Issues and PRs which have not yet been triaged by a lead labels May 6, 2024
@@ -303,34 +303,24 @@ bool TryGetFileMappingFromMetadataImporter(FileKey fileKey, [NotNullWhen(true)]
FileKey fileKey,
Func<FileKey, (ModuleMetadata moduleMetadata, TemporaryStorageStreamHandle? storageHandle)> moduleMetadataFactory)
{
var (manifestModule, manifestHandle) = moduleMetadataFactory(fileKey);
Copy link
Member Author

@CyrusNajmabadi CyrusNajmabadi May 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the core bug was that we were not doing anything with this manifestHandle in the case where this was a multi-module assembly. I'll doc how this happened.

First, we would get the handle here. Now go to https://github.com/dotnet/roslyn/pull/73345/files#r1590487986

moduleBuilder.Add(metadata);
storageHandles.Add(metadataStorageHandle);
}

if (moduleBuilder.Count == 0)
Copy link
Member Author

@CyrusNajmabadi CyrusNajmabadi May 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second, if there were no submodules, we'd add the primary module here and the handle. But if there were submodules, then the handle for the primary module was dropped.

Now go to https://github.com/dotnet/roslyn/pull/73345/files#r1590488780

if (assemblyDir is null)
{
moduleBuilder.Add(manifestModule);
assemblyDir = Path.GetDirectoryName(fileKey.FullPath);
Copy link
Member Author

@CyrusNajmabadi CyrusNajmabadi May 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Third: the core place i originally missed was here. Specifically, we would go in here and add the primary module to the modulebuilder, but totally lose the handle.

--

However, this code is entirely overwrought. The logic was:

  1. Do not add the primary items to the collections.
  2. if we have sub modules, add the primary items to the collections, then add hte sub modules. However, the logic here to add the primary items didn't add the handle.
  3. if we had no sub modules, add the primary items to the collections.

so the entire logic was convoluted, and always wanted to add the primary items as the first items. So that's just what the new logic does.

--

The reason this wasn't totally broken for everything was that case '3' is hte normal case. So for almost all users we would add the primary module and handle and be ok. It was only when we went into case '2' that things blew up.

this hit with C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.EnterpriseServices.dll which has a submodule.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the new logic is trivial and sane. We get the info abotu the primary module and add to the builders. Then we ge tthe info about the sub-modules, and add to hte builders. That's it :)

@CyrusNajmabadi
Copy link
Member Author

@ToddGrun please review asap. Note: this manifests as an assert in debug, and inefficiency in release. but it's still not good, and was a PITA to track down why the assert was firing.

@CyrusNajmabadi
Copy link
Member Author

Working on a test now.

@@ -139,32 +138,30 @@ internal Metadata GetMetadata(string fullPath, DateTime snapshotTimestamp)
if (_metadataCache.TryGetMetadata(key, out var metadata))
return metadata;

var newMetadata = GetMetadataWorker();
// here, we don't care about timestamp since all those bits should be part of Fx. and we assume that
// it won't be changed in the middle of VS running.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment moved.

{
if (VsSmartScopeCandidate(key.FullPath))
{
var newMetadata = CreateAssemblyMetadataFromMetadataImporter(key);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed to stop passing hte full key, and just pass hte file path instead. only the file path was needed through all descendent codepaths, so this simpified things (and made it easier to test).


' We should have two handles as this assembly has two modules (itself, and one submodule for
' System.EnterpriseServices.Wrapper.dll)
Assert.Equal(2, tuple.handles.Count)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assert fails without the fix.

Dim checksum2 = SerializerService.CreateChecksum(deserialized, cancellationToken:=Nothing)

' Serializing the original reference and the deserialized reference should produce the same checksum
Assert.Equal(checksum1, checksum2)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As does this.


if (!_metadataCache.GetOrAddMetadata(key, newMetadata, out metadata))
newMetadata.Dispose();

return metadata;
if (handles != null)
s_metadataToStorageHandles.Add(newMetadata, handles);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pulled the logic up to here for populating the caches. it simplified the lower code (imo).

private static AssemblyMetadata CreateAssemblyMetadata(
FileKey fileKey,
Func<FileKey, (ModuleMetadata moduleMetadata, TemporaryStorageStreamHandle? storageHandle)> moduleMetadataFactory)
private static (AssemblyMetadata assemblyMetadata, IReadOnlyList<TemporaryStorageStreamHandle>? handles) CreateAssemblyMetadata(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made static to make this easy to unit test. this now returns both the metadta and handles to make this easy to unit tests.

Copy link
Contributor

@ToddGrun ToddGrun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@CyrusNajmabadi CyrusNajmabadi enabled auto-merge May 6, 2024 15:16
@CyrusNajmabadi CyrusNajmabadi disabled auto-merge May 6, 2024 16:52
@CyrusNajmabadi CyrusNajmabadi enabled auto-merge May 6, 2024 17:15
@CyrusNajmabadi CyrusNajmabadi merged commit a20e169 into dotnet:main May 6, 2024
25 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone May 6, 2024
@CyrusNajmabadi CyrusNajmabadi deleted the vsMetadataReferences branch May 6, 2024 20:45
@CyrusNajmabadi
Copy link
Member Author

@jasonmalinowski For review when you get back.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-IDE untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants