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 serialization of exceptions by BinaryFormatter in .NET Framework #5054

Merged
merged 5 commits into from
Feb 18, 2025

Conversation

nohwnd
Copy link
Member

@nohwnd nohwnd commented Feb 18, 2025

The change adds protected constructors that binary formatter needs to deserialize exceptions. All added api targets .NET Framework, and .NET Standard 2.0, to avoid bringing the new apis to .NET.

All those apis are obsoleted the same way they are obsoleted in .NET.

Fix #5048

@Evangelink
Copy link
Member

/backport to rel/3.8

@Evangelink Evangelink enabled auto-merge (squash) February 18, 2025 09:25
Copy link
Contributor

Started backporting to rel/3.8: https://github.com/microsoft/testfx/actions/runs/13387310059

@codecov-commenter
Copy link

Codecov Report

Attention: Patch coverage is 0% with 12 lines in your changes missing coverage. Please review.

Project coverage is 66.67%. Comparing base (26b73a4) to head (0690eaa).
Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
.../TestFramework/Exceptions/AssertFailedException.cs 0.00% 3 Missing ⚠️
...ramework/Exceptions/AssertInconclusiveException.cs 0.00% 3 Missing ⚠️
...amework/Exceptions/InternalTestFailureException.cs 0.00% 3 Missing ⚠️
...estFramework/Exceptions/UnitTestAssertException.cs 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5054      +/-   ##
==========================================
- Coverage   66.79%   66.67%   -0.12%     
==========================================
  Files         603      603              
  Lines       36243    36279      +36     
==========================================
- Hits        24207    24189      -18     
- Misses      12036    12090      +54     
Flag Coverage Δ
Debug 66.67% <0.00%> (-0.12%) ⬇️
integration 66.66% <0.00%> (-0.13%) ⬇️
production 66.67% <0.00%> (-0.12%) ⬇️
unit 66.67% <0.00%> (-0.12%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
.../TestFramework/Exceptions/AssertFailedException.cs 16.66% <0.00%> (-16.67%) ⬇️
...ramework/Exceptions/AssertInconclusiveException.cs 16.66% <0.00%> (-16.67%) ⬇️
...amework/Exceptions/InternalTestFailureException.cs 0.00% <0.00%> (ø)
...estFramework/Exceptions/UnitTestAssertException.cs 16.66% <0.00%> (-16.67%) ⬇️

... and 7 files with indirect coverage changes

Copy link
Member

@Evangelink Evangelink left a comment

Choose a reason for hiding this comment

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

Reviewing the link dotnet/docs#34893, I think we should be really following the advices there and add the protected ctor always and make it obsolete for NET8.0+:

#if NET8_0_OR_GREATER
    [Obsolete(DiagnosticId = "SYSLIB0051")]
#endif

@nohwnd
Copy link
Member Author

nohwnd commented Feb 18, 2025

As I read it that recommendation does not address the case where we did not have the serialization apis before we decided to Obsolete them. So the recommendation does not apply here.

They recommend to not rely on binary formatter first and foremost. This we cannot influence, but we can avoid people using the new constructor by accident, hance the obsoletion and browsable Never.

They recommend to remove the serialization constructor if we can, which we effectively do in .NET, by having compiler condition.

If we cannot remove in .net (which is not our case) we should obsolete it. For that they recommend to conditionally obsolete it in .NET 8.

So afaik my code is correct.

@nohwnd
Copy link
Member Author

nohwnd commented Feb 18, 2025

I am referring to:

If you're creating a custom System.Exception-derived type

Consider whether you truly need your custom exception type to be serializable. Chances are you do not need it to be serializable, ... <- yup we don't need that in .net.

Consider simply removing the [Serializable] attribute, the serialization constructor, and the GetObjectData method override, as shown below. <- done by not defining them for .NET

There may be some cases where you cannot remove these APIs from your custom exception types. This might occur if you produce a library constrained by API compatibility requirements. <- we did not have them till now so we don't need to keep compatibility.

@Youssef1313
Copy link
Member

Youssef1313 commented Feb 18, 2025

I'd prefer to have consistent behavior. If we want to support .NET Framework, let's support everywhere with obsolete on net8.0+ as suggested by the docs.

My second preference is to only support .NET Framework, and not include the serialization constructor on netstandard2.0.

In all cases, it feels wrong to have a publicly visible API on netstandard2.0 but not on net6.0+.

Consider a library that only targets netstandard2.0 and uses such API. That library is then consumed in net6.0+ app, then we are welcoming a MissingMethodException.

To me, generally an API contract of netstandard should be compatible with both .NET Core and .NET Framework

@nohwnd
Copy link
Member Author

nohwnd commented Feb 18, 2025

amary will continue here on the suggestion above, with having the api everywhere and only conditional obsolete. Thanks

@Evangelink I took the obsolete message from here:

internal const string LegacyFormatterImplMessage = "This API supports obsolete formatter-based serialization. It should not be called or extended by application code.";

internal const string LegacyFormatterImplDiagId = "SYSLIB0051";

internal const string SharedUrlFormat = "https://aka.ms/dotnet-warnings/{0}";

https://github.com/dotnet/runtime/blob/main/src/libraries/Common/src/System/Obsoletions.cs#L8

@Evangelink
Copy link
Member

/backport to rel/3.8

Copy link
Contributor

Started backporting to rel/3.8: https://github.com/microsoft/testfx/actions/runs/13393573124

Copy link
Contributor

@Evangelink backporting to rel/3.8 failed, the patch most likely resulted in conflicts:

$ git am --3way --empty=keep --ignore-whitespace --keep-non-patch changes.patch

Applying: Add tests
Applying: Fix binary formatter serialization for .NET Framework
Applying: Add obsolete to test using obsolete api
Applying: Address review feedback
Using index info to reconstruct a base tree...
M	src/TestFramework/TestFramework/PublicAPI/PublicAPI.Unshipped.txt
Falling back to patching base and 3-way merge...
Removing src/TestFramework/TestFramework/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt
Removing src/TestFramework/TestFramework/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt
Removing src/TestFramework/TestFramework/PublicAPI/netframework/PublicAPI.Unshipped.txt
Removing src/TestFramework/TestFramework/PublicAPI/netframework/PublicAPI.Shipped.txt
Auto-merging src/TestFramework/TestFramework/PublicAPI/PublicAPI.Unshipped.txt
CONFLICT (content): Merge conflict in src/TestFramework/TestFramework/PublicAPI/PublicAPI.Unshipped.txt
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
hint: When you have resolved this problem, run "git am --continue".
hint: If you prefer to skip this patch, run "git am --skip" instead.
hint: To restore the original branch and stop patching, run "git am --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Patch failed at 0004 Address review feedback
Error: The process '/usr/bin/git' failed with exit code 128

NOTE: A PR will be created, but needs to be revised manually!**

@Evangelink Evangelink merged commit fc63e5d into main Feb 18, 2025
7 of 8 checks passed
@Evangelink Evangelink deleted the exception-serialization branch February 18, 2025 16:00
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.

AssertException is not compatible with BinaryFormatter
4 participants