-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
MemoryStream should be serializable in .NET Core 3 #13349
Comments
cc: @ViktorHofer, @ericstj |
Not exactly: we never used Binary Serialization for MemoryStream. Streams have a primitive representation in resources that just stores the raw backing data. At runtime we hand back an UnmanagedMemoryStream over the backing embedded bytes in the embedded resources: no copies. https://github.com/dotnet/coreclr/blob/6e1b160523db1c6e7d96aa3c9244a0baf8edb06a/src/System.Private.CoreLib/shared/System/Resources/ResourceReader.cs#L698-L725 We wouldn't want folks to rely more on binary serialization for this. Let alone the security implications of that technology, it would likely result in extra copies of the data to get back to a MemoryStream, at least one from the backing data to a managed array, perhaps more in the process. You'd also need to change designers to write that format to the resx file. This scenario should be fixed in a source-compatible manner with dotnet/msbuild#4420 / dotnet/msbuild#2221. Have you tried this out? |
Dear Eric, Thank you for your reply. I'm afraid I wasn't detailed enough about the issue. I admit it's a bit complicated and even I was a bit confused and corrected my post once.
Not exactly. We are talking about slightly different scenarios. But now I try to make it as clear as possible: Scenario 1 (working): I believe this is what you are talking about. If you add a linked binary resource it will be usually a When you obtain this resource by This scenario is handled well both by Microsoft's Scenario 2 (the issue I'm talking about): On the other hand, if you create an embedded In .NET Core this resource cannot be deserialized anymore.
|
Sure, if you're explicitly storing something as a MemoryStream type then that will no longer deserialize.
You can get further if you use ResourceManager with an assembly-based constructor. In .NETCore we minimize the use of BinaryFormatter except for cases where you've already trusted the code you're loading (eg: by loading an assembly). Even so, if you did that and got ResourceManager to deserialize your embedded type, you'd still fail on deserialization in the same way you mentioned for ResXResourceReader, since the MemoryStream type itself is not serializable. In most cases it will be more efficient to store it as the stream primitive and only convert it to a MemoryStream if you require that type specifically. Even so, it might even be more efficient to just go from the UMS to an array so that you don't walk through growing a MemoryStream up to final size. If you own the code consuming the MemoryStream, I'd recommend this rather than storing as binary-formatted MemoryStream. Do you have a user scenario that actually serializes something as a MemoryStream with binary formatted mimetype in ResX? Your sample showed a test case that did this, but how did you create that ResX file? I know @dreddy-work and @rainersigwald tried to examine all the cases where the resx and winforms designer would write common types and ensure that we had support for those types in .NETCore. There's an open-ended case where a user control might expose a localizable property of any type, but I don't recall any cases we saw of folks using MemoryStream. It's possible we missed something here. @GrabYourPitchforks can probably better comment on the implications of adding [Serializable] to |
Apart from my test cases, no. And unless compatible format is enforced on saving I use my own binary serialization rather than
Ok, let's go philosophical. :) I think that is not a problem either. That's why Btw, I basically agree that binary serialization is not the best idea for transferring data between different platforms and versions (that's the case also for resources). But I also believe that removing the |
Thank you for the repro scenario. I'm able to produce this using the resource editor. I'll follow up with the folks who own the resource editor to see if we can get this written in a slightly different manner in the future that will avoid writing a serialized MemoryStream. Instead the resource editor should be writing as a byte-array and indicating it's a stream type, that way it gets stored using the stream primitive same as it would if it were an external file. That won't fix existing usage. For assemblies out there that already contain a serialized a MemoryStream they'll fail to deserialize on .NETCore. So far the data we've gathered from assemblies we've analyzed hasn't shown instances of this, but we're open to more feedback if folks are blocked. |
A little addendum for the newly released .NET Core 3.0, which works differently in some cases compared to .NET Core 2.x:
|
Can you share a snippet of your resx for issue 1? I tested this previously and it was working, but your callstack indicates that MSBuild is writing this intead as an activator resource instead of stream primitive. @rainersigwald that might be a regression. Issue 2 is clear and what we've been discussing here. I think for this we'd really need the security & IO folks to weigh in on security risk of adding back serializable to MemoryStream, and IO folks to weigh in on the compat burden of doing so. @GrabYourPitchforks and @JeremyKuhne can you share your opinion? For issue 3 I opened https://github.com/dotnet/coreclr/issues/26951. |
@koszeggy Also please include a description of your build process--are you using |
This was discussed in https://github.com/dotnet/coreclr/issues/17460 |
From a security perspective, if we added
|
@ericstj, @rainersigwald: Just execute
|
@jkotas: I also referenced #10106 in my opening post. I opened this issue because I found another issue where this is a problem. The main reasoning in #10106 was that serializing a While this is true please also take the compatibility issues into consideration. That's why I've written in the OP:
|
@GrabYourPitchforks: And if someone wants to create a serializable derived type without including the byte array buffer and other things from the base, then they still can add |
@koszeggy We are taking multiple factors into consideration:
|
@koszeggy, I really appreciate the link and the repro, but I'm uncertain about the license on the repository you linked. Do you think it would be possible to share an isolated repro? I did try to ad-hoc test the scenario you mentioned and found it was working for me. From the callstack you shared it really looks like you're hitting dotnet/msbuild#4581 which was fixed with dotnet/msbuild#4607 which should be in the GA release for .NETCore 3.0. Make sure you have updated the SDK and do a clean build to see the fix. Here's my adhoc testing of the scenario: https://github.com/ericstj/repros/tree/master/testMemStreamResXFileRef |
If you want to read a payload serialized by .NET Framework, that payload will contain a bunch of irrelevant fields aside from just the |
|
To be frank, I still not get it. Here are the fields of the I believe all of them are needed (except the one marked by
Of course, these fields can be unnecessary in a derived class (eg.
|
I was able to reproduce the problem you were seeing in your unit test. Here's an isolated repro: https://github.com/ericstj/repros/tree/master/testMemStreamResXFileRef Let this issue only track the discussion around binary serialization. |
I am not interested in preserving full fidelity of private fields being serialized between .NET Core and .NET Framework, both for forward-compatibility purposes and for security purposes. I'm willing to allow just the raw |
The current plan of record is to not mark any more inbox .NET types as @ericstj Should this work item be instead used for tracking an arbitrary binary blob storage mechanism in .resx files? Otherwise I'll close the issue as a dupe of #10106. |
From my side the issue can be closed. In the meantime I implemented the needed workarounds to provide compatibility between the Framework and .NET Core. It's just a bit odd that one needs 3rd party solutions for it. For anyone who struggles with such issues:
The project is open source and is available on GitHub |
Releated Issue: This one complains about broken WCF services but was closed as will not be fixed.
Now here is another issue if
MemoryStream
is not serializable: The .NET Framework serializesMemoryStream
instances for embedded binary resources. Now the unit tests of my custom ResXResourceReader class are failing in .NET Core because the binary resources cannot be deserialized from .resx files anymore.This could be relevant for .NET Core 3 where the WinForms version of
ResXResourceReader
will be available again.Instead of arguing that serializing a
byte[]
is more reasonable (which I basically agree with) wouldn't it just possible to reintroduce the[Serializable]
attribute forMemoryStream
? It is essentially abyte[]
along with a few integers so nothing as dangerous as a delegate or something.Of course, I could use a prepared
ISurrogateSelector
in my deserializer but that would not cure the same issue in the system version. But I prefer compatibility over nasty hacks. Especially when the fix is that simple.The text was updated successfully, but these errors were encountered: