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

moved to List from ImmutableArray on json return type. #21395

Merged
merged 5 commits into from
Aug 14, 2017

Conversation

heejaechang
Copy link
Contributor

ImmutableArray is causing isssue on Json lib. use regular List since we don't actually need immutable array here.

fixing this
https://devdiv.visualstudio.com/DevDiv/_workitems/edit/473979

no heap, but callstack shows that immutable array is default, but we are getting it from json.net lib. we could check isDefault, but I dont want to get into hassle until I know newston.json supports immutable array reliably. moving back to non immutable collection when crossing json.

ImmutableArray is causing isssue on Json lib. use regular List since we don't actually need immutable array here.
@heejaechang
Copy link
Contributor Author

@dotnet/roslyn-analysis @dotnet/roslyn-ide can I get code review?

@heejaechang
Copy link
Contributor Author

adding @jinujoseph and @mavasani

@CyrusNajmabadi
Copy link
Member

What about:

IRemoteAddImportFeatureService.GetFixesAsync?
IRemoteDocumentHighlights.GetDocumentHighlightsAsync?
IRemoteNavigateToSearchService.SearchDocumentAsync?
IRemoteNavigateToSearchService.SearchProjectAsync?
IRemoteSymbolFinder.*?

These all have APIs that return immutable arrays.

@sharwell
Copy link
Member

sharwell commented Aug 9, 2017

@CyrusNajmabadi Do we have the ability to register a JSON deserializer for a generic type?

@CyrusNajmabadi
Copy link
Member

Do we have the ability to register a JSON deserializer for a generic type?

I imagine we would, as long as json.net didn't overrule us. All we need to override is:

http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_JsonConverter_CanConvert.htm

@sharwell
Copy link
Member

sharwell commented Aug 9, 2017

📝 I confirmed through WinDbg analysis of the crash that this was caused by JamesNK/Newtonsoft.Json#652. Possible solutions:

  1. Provide a patch to Json.NET that enables light-up for immutable collections, and update to use that version.
  2. Find a way to ensure that we do not load the .NET 4.0 version of Json.NET in Visual Studio.
  3. Provide a compatible serializer so if Json.NET is not able to serialize these collections automatically, the implementation is still provided by us.

@CyrusNajmabadi
Copy link
Member

@AArnott @AlexEyler Is there a way we can get VS to prevent overriding of json.net? it seems like that may be a problem for many parts of VS that expect to be getting the redirected 9.0 version of json.net?

@heejaechang
Copy link
Contributor Author

unless there is real reason that we must use ImmutableArray, I think we should just make them to use regular collection for now.

@heejaechang
Copy link
Contributor Author

@sharwell I will remove ImmutableArray usage from json.net for now. we can consider using ImmutableArray later once we are sure that it is supported reliably.

@CyrusNajmabadi
Copy link
Member

@heejaechang @sharwell I'm ok with that. @heejaechang Please take a look at teh full surface area of both CodeAnalysisService and RemoteSymbolSearchUpdateEngine

@AArnott
Copy link
Contributor

AArnott commented Aug 9, 2017

@CyrusNajmabadi @AlexEyler I filed this to track on the VS side:

Bug 476064: Protect certain platform assemblies from loading from extensions

@AlexEyler
Copy link
Contributor

@AArnott @CyrusNajmabadi thanks - we were talking about this recently as well, others on the team (including myself) share the same concern.

@heejaechang
Copy link
Contributor Author

ping, can I get some code review?

@heejaechang
Copy link
Contributor Author

actually, IReadOnlyList is in 4.5 as well. so probably only choice I have is either IList or IEnumerable.

return SpecializedCollections.EmptyReadOnlyList<DesignerAttributeDocumentData>();
}

return data.Values.ToList();
Copy link
Member

Choose a reason for hiding this comment

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

I feel like i should be seeing more of this in the code. Basically, all the places where we return an immutable array (even casted to an IReadOnlyList) would need to actually be converted to a List. THat's because json.net isn't going to see or care that this is IReadOnlyList. It's going to look at the real underlying type and will decide what to do with it. If that underlying type is stilL IMmutableArray, things will still not work.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@sharwell
Copy link
Member

sharwell commented Aug 10, 2017

@heejaechang Unless you plan to retarget this to 15.4 or earlier, I would recommend waiting until we establish a timeline on JamesNK/Newtonsoft.Json#652 getting fixed. If that gets fixed and released early enough, we can update the dependency and no longer be negatively influenced.

Edit: It's already fixed.

@AArnott
Copy link
Contributor

AArnott commented Aug 10, 2017

@sharwell is the fix going to be shipped in a 9.x release? If it's only for 10.x releases, that won't help you for a while yet, since VS ships 9.x. Even when VS ships 10.x, it will be a SXS deployment with 9.0 rather than a binding redirect to 10 since 10 has breaking changes.

@sharwell
Copy link
Member

@JamesNK Can you answer @AArnott's previous question?

To be more specific, will this patch appear in a 9.x release for which the strong name changed (version increment relative to the one we currently reference)?

Thanks!

@heejaechang
Copy link
Contributor Author

@sharwell I would rather be in safe side until things are settled down and verified. we can always go back to immutablearray when needed. it won't affect any public API or functionality.

@JamesNK
Copy link
Member

JamesNK commented Aug 10, 2017

It will be a 10 release

@heejaechang
Copy link
Contributor Author

moved all interface that uses json.net to use IList (safest one to use for now). we will move it to immutable array once we are sure all issues around using immutable array in json.net in vs is resolved.

@heejaechang
Copy link
Contributor Author

can I get some code review?

{
return (succeeded: false, ImmutableArray<DocumentHighlights>.Empty);
}

return (true, result.SelectAsArray(h => h.Rehydrate(document.Project.Solution)));
return (true, result.Select(h => h.Rehydrate(document.Project.Solution)).ToImmutableArray());
Copy link
Member

Choose a reason for hiding this comment

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

does this need to be SelectAsArray?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes. let me update.

@AArnott
Copy link
Contributor

AArnott commented Aug 10, 2017

@JamesNK A 10 release will mean we can't benefit for a while yet.
Also, @sharwell's other question remains relevant: will you change the assembly version for the release that contains this version? I'm guessing not since your versioning scheme seems to keep the assembly version constant across minor version updates. But without an assembly version bump, the fix is ineffective in protecting against this problem we're having.

@JamesNK
Copy link
Member

JamesNK commented Aug 10, 2017

You can update to 11 when it is eventually released.

Alternatively you could write a JsonConverter to manually serialize/deserialize immutable collections if you want to fix the issue today.

@sharwell
Copy link
Member

Alternatively you could write a JsonConverter to manually serialize/deserialize immutable collections if you want to fix the issue today.

In my mind this is the most robust approach, because it ensures we won't hit this bug in the future. Currently ImmutableArray<T> is the most natural type to use where it's allowed, and we have no regression tests in place to validate that we avoid this case.

@AArnott
Copy link
Contributor

AArnott commented Aug 11, 2017

Another feature team was just bitten by this bug as well yesterday. So having each individual feature have to learn that they need to write JsonConverters to replace functionality that is built into the library doesn't sound very robust, IMO. This is not a dig against the library actually, but rather the reason I really want to see the vs platform guarantee the version of the assembly that gets loaded is the desktop one.
Another thing I've thought about: VS artificially build newtonsoft.json with a 9.1 assembly version, update our binding redirect, and then ship the 9.1 version. That should shield us from anyone GAC'ing 9.0.

@sharwell
Copy link
Member

sharwell commented Aug 11, 2017

VS artificially build newtonsoft.json with a 9.1 assembly version, update our binding redirect, and then ship the 9.1 version

This would work, but IIRC the strong name key isn't public so either we public sign it (definitely keeps it out of the GAC), or we request a build of latest 9.x with assembly version set to 9.1 from @JamesNK, and only release the .NET 4.5 build (or 4.6, whichever one it is VS needs). This would be a "VS specific build" sent directly to MS and not published to NuGet.

For StyleCop Analyzers we ended up switching to embedded LightJson to deal with various woes, but those were mostly related to distribution across multiple platforms (not always Windows).

@heejaechang
Copy link
Contributor Author

I just would like to use IList, there is no actual reason where we must use ImmutableArray here. we can move to using ImmutableArray when we are confident or figure out what to do here. before we moved to ImmutableArray all code was written to use either array or IList anyway.

@heejaechang
Copy link
Contributor Author

regardless of discussion where we should have ImmutableArray or not, I would like to get some code review on this change. basically it removes usage of ImmutableArray from json.net and use the safest collection (IList) in json.net.

tagging @dotnet/roslyn-analysis @dotnet/roslyn-ide

Copy link
Member

@sharwell sharwell left a comment

Choose a reason for hiding this comment

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

This looks fine to me on the condition that it will ship to customers (referring to a stable update release, not a pre-release) prior to any alternative solution being made available by a VS platform team. ImmutableArray<T> makes for a better API, and we should exhaust our options related to its preservation prior to resorting to this approach.

If this does gets merged, a bug should be filed to revert it as soon as the VS platform offers a solution which no longer requires it.

@@ -242,6 +244,19 @@ public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T> source)
return source.Where((Func<T, bool>)s_notNullTest);
}

public static ImmutableArray<TResult> SelectAsArray<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
Copy link
Member

Choose a reason for hiding this comment

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

💭 I thought we already had this extension method. Maybe not accessible here though?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

that's between ImmutalbArray to ImmutableArray . this is IEnumerable to ImmutableArray

public static T Last<T>(this IReadOnlyList<T> list)
{
return list[list.Count - 1];
}

private class ReadOnlyList<T> : IReadOnlyList<T>
Copy link
Member

Choose a reason for hiding this comment

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

❓ Why not ReadOnlyCollection<T>?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

IReadOnlyList has indexer which is drop in replacement for ImmutebleArray, IreadOnlyCollection doesn't have indexer.

Copy link
Member

Choose a reason for hiding this comment

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

@heejaechang I'm talking about the ReadOnlyCollection<T> class, not the IReadOnlyCollection<T> interface.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

are you talking about existing ReadOnlyCollection type. I dont know why it is using ICollection rather than IReadOnlyCollection.

@heejaechang
Copy link
Contributor Author

@sharwell sure, I like using ImmutableArray as well. as long as It don't cause any issue. I will open an issue.

@AArnott
Copy link
Contributor

AArnott commented Aug 11, 2017

Certainly I don't mean to hold up the PR. It's just a relevant and interesting discussion. :)
@heejaechang if this has public API impact, can you use IReadOnlyList<T> instead of IList<T> so you're communicating that the reference holder cannot mutate it?

@heejaechang
Copy link
Contributor Author

tagging issue #21498

@heejaechang
Copy link
Contributor Author

@AArnott they are not related to public API and IReadOnlyList is also only supported in 4.5 version. so for now, I am just going to use most safe collection.

@heejaechang heejaechang merged commit 932e424 into dotnet:master Aug 14, 2017
@AArnott
Copy link
Contributor

AArnott commented Aug 14, 2017

IReadOnlyList is also only supported in 4.5 version

Is that a problem for you? Does Roslyn build to run on something older than that?

@heejaechang
Copy link
Contributor Author

@AArnott isn't the immutableArray issue we are having is due to json.net that doesn't support ImmutableArray is loaded? I believe IReadOnlyList has same issue?

@AArnott
Copy link
Contributor

AArnott commented Aug 14, 2017

I don't think that would be an issue if your field is typed as List<T> or whatever you want there. I meant to suggest that you use IReadOnlyList<T> for your method parameter types.

@AArnott
Copy link
Contributor

AArnott commented Aug 17, 2017

@JamesNK we tried going with a private build of 9.0 with 9.0.0.153 as an assembly version, and that worked, except because we public signed it, it can't be ngen'd. Can you spin a build of 9.0.1 with an assembly version of 9.0.0.153 that is signed with your private key?
If it's helpful, you can use my work which builds everything the way we need, but is missing your private key.

@JamesNK
Copy link
Member

JamesNK commented Aug 18, 2017

Fixing bugs that could effect anyone is fine - I've fixed this issue so it won't be a problem in future versions of Json.NET - but I don't have enough time to spend it on creating custom builds for individual people. Json.NET is something I work on my limited own time.

@AArnott
Copy link
Contributor

AArnott commented Aug 18, 2017

Understood, @JamesNK. To be fair, I'd be able to build it myself if you chose to expose your private key for strong name signing. But I'm sure you have your reasons.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants