Skip to content

Conversation

@jkurdek
Copy link
Contributor

@jkurdek jkurdek commented Jul 13, 2022

Problem description and potential solution overview.

@vitek-karas

@jkurdek jkurdek requested a review from marek-safar as a code owner July 13, 2022 19:31
@@ -0,0 +1,93 @@
# Redundant Warning Suppression Detection
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure about the name, could not think about anything better though. If you have any better ideas, let me know!

@vitek-karas
Copy link
Member

@agocke @sbomer @tlakollo @eerhardt @MichalStrehovsky
If you could take a quick look - mainly that the problem/approach makes sense to you...


```

In order to detect the warning suppression not tied to any trimmer-incompatible pattern we should run the `dotnet publish` command and pass the `--check-suppressions` option.
Copy link
Member

Choose a reason for hiding this comment

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

I think this option should be on by default, and developers would need to turn it off if they don't want it.

Copy link
Member

Choose a reason for hiding this comment

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

I think for now we should start with opt-in. There are rough edges we need to figure out first. But eventually I definitely agree - the value is there for sure :-)

Copy link
Member

Choose a reason for hiding this comment

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

Could we make it opt-in by adding the new warning code(s) to NoWarn for now, or use a new warning wave that won't be on by default until .NET 8? I don't see why this warning should get its own flag to disable it.

This would also give us additional validation by at least running the relevant code, even if the warnings are ultimately suppressed.

Copy link
Member

Choose a reason for hiding this comment

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

For now we're going with producing a new warning - in which case I agree with @sbomer that using either NoWarn or warning levels would be a great way to do this.

I think we should leave out the exact mechanics our of this document - we'll figure them out later on. It obviously has to be a toggle - and if it's on by default is a discussion for a time when we have much better understanding of the impact/UX of this.

Co-authored-by: Eric Erhardt <[email protected]>
Copy link
Member

@sbomer sbomer left a comment

Choose a reason for hiding this comment

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

Nice write-up, I left some nits but LGTM!


```

In order to detect the warning suppression not tied to any trimmer-incompatible pattern we should run the `dotnet publish` command and pass the `--check-suppressions` option.
Copy link
Member

Choose a reason for hiding this comment

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

Could we make it opt-in by adding the new warning code(s) to NoWarn for now, or use a new warning wave that won't be on by default until .NET 8? I don't see why this warning should get its own flag to disable it.

This would also give us additional validation by at least running the relevant code, even if the warnings are ultimately suppressed.


The proposed solution operates by extending the functionality of the linker tool. On one hand, this allows for reusing the existing components leading to a simple implementation, on the other hand this may lead to potential problems. The linker sees only a part of code which is actually used, that means that the solution would not be able to identify the warning suppressions on the code which is trimmed away. Also, the linker may visit parts of the code which were not authored by the developer (e.g. used libraries) and look for the redundant suppressions there. This may cause the output warnings to be noisy and not useful to the developer. Moreover, the dependencies identified by the linker may be different depending on the environment the tool is run in. Hence, the proposed solution may report different redundant suppressions on different environments.

Alternatively, we could make the analyzer do the unused warning suppressions detection. The analyzer operates on a single assembly level but it has a full view of the processed assembly, as opposed to the linker which only sees the code which is actually used within the assembly. Making the solution part of the analyzer, would allow us then to detect the unused warning suppression on assembly level with higher precision. Also, an advantage of such solution would be a shorter feedback loop; we would learn about the redundant suppressions way before we run the publish command. The drawback of this approach is the added complexity. We would not be able to reuse the existing components. What is more, the analyzer has a different view of the code than the linker. We may not be able to identify the same set of trimmer-incompatible patterns using the analyzer as we do using the linker.
Copy link
Member

Choose a reason for hiding this comment

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

I think we should eventually do both, since each tool has its own strengths.

Copy link
Contributor

@tlakollo tlakollo Jul 14, 2022

Choose a reason for hiding this comment

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

I would be worried that the analyzer can recommend removing a suppression just because doesn't have the full picture. Non-actionable code and code that either way is going to be removed seems less worrying to me.
On the linker side of things, I would be worried if implementing the linker tooling is going to recommend removing a suppression because of something we annotated using a feature that the analyzer knows best (like backtracking).

Copy link
Member

Choose a reason for hiding this comment

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

Great point, we will need to be very careful about the redundant suppression warning in areas where we don't have parity between the liker and analyzer.

Related, maybe we should specify that the "redundant suppression warning" suppression itself will never be reported as a redundant suppression - that way it can be used to temporarily work around any cases where we get it wrong? 😆 Although if this becomes common it will recreate the original problem.

Copy link
Contributor

Choose a reason for hiding this comment

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

Since we are already talking about things that are blurry in the document here:
What's the scope of this feature? my guess is that it should be restricted to a certain amount of warnings and attributes. For example, if it's implemented in the linker we wouldn't be able to detect a redundant UnconditionalSuppressMessage originated by RequiresDynamicCode or RequiresAssemblyFiles, or what is worse it will be flagged always as redundant just because Linker doesn't analyze it.
Also, is this feature going to be supported by NativeAOT?

Copy link
Member

Choose a reason for hiding this comment

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

All good questions. My take:

  • We should scope the linker implementation to "linker" - just like we do with Requires* stuff. So this should only react to linker produced warnings (and their respective suppressions). @jkurdek could you please add this to the doc? - only suppressions for warnings produced by linker should be checked - other suppressions should be completely ignored.
  • I imagine we would port this to NativeAOT (once we have proper sharing of linker->AOT it should almost come for free), but it's not a priority. In that case the set of recognized warnings codes would grow to the set which can be produced by NativeAOT.

I think a guiding principal of this (at least for now) should be "best effort" and "reduce noise". Unfortunately this feature comes with some amount of noise which is effectively by-design and there's little we can do about it. So eventually we should start thinking about an escape hatch - like suppressing the new warning itself :-), but as @sbomer notes this can lead to problems on its own.

I see this as a good starting point - also why it should be opt-in by default.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a note that only suppressions produced by the linker will be checked.


## Other solutions

The proposed solution operates by extending the functionality of the linker tool. On one hand, this allows for reusing the existing components leading to a simple implementation, on the other hand this may lead to potential problems. The linker sees only a part of code which is actually used, that means that the solution would not be able to identify the warning suppressions on the code which is trimmed away. Also, the linker may visit parts of the code which were not authored by the developer (e.g. used libraries) and look for the redundant suppressions there. This may cause the output warnings to be noisy and not useful to the developer. Moreover, the dependencies identified by the linker may be different depending on the environment the tool is run in. Hence, the proposed solution may report different redundant suppressions on different environments.
Copy link
Member

Choose a reason for hiding this comment

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

Illink also does a bunch of optimizations that may render a suppression that was necessary at source compilation time look unnecessary. E.g. if constant propagation figures out a codepath is unreachable and suddenly the suppression looks unnecessary. but it's just unnecessary for that specific deployment mode.

The analyzer has a better view of the code from this perspective.

Copy link
Member

Choose a reason for hiding this comment

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

We're running into this in the framework (around feature switches). Overall I agree that the tool should be able to "See" this (analyzer will, it's really hard to make that work for linker).
That said, especially in framework I would tend to refactor the code to avoid this altogether. Basically what this points to is the inability to target a specific line of code with the suppression because it has to be on IL level (so no pragmas). A way to workaround that limitation is to extract the offending call into a local function and suppress at the local function level. This has other benefits:

  • The suppression is very specific and self-documenting from that point of view - otherwise it's actually rather difficult to tell what exact method call the suppression is targeted at, unless it mentions it in comment.
  • If the code is changed to add a new call which causes the same warning code again, it will get suppressed automagically due to the presence of the suppression on the method - this can lead to trimming holes.
  • It allows even linker to reason abut unnecessary suppressions.

It's not ideal, but for framework the benefits of very targeted suppressions outweighs the added complexity.

MichalStrehovsky added a commit to dotnet/docs that referenced this pull request Jul 15, 2022
Inspired by the suppression justification from dotnet/linker#2891.
Comment on lines 63 to 64
The said functionality can be implemented as an optional feature, triggered by passing a `
--check-suppressions` command line argument to the linker. Running the tool with this option will report all of the warning suppressions which do not suppress any warnings.
Copy link
Member

Choose a reason for hiding this comment

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

I would remove this - or maybe just say "The way to turn this on is TBD" or something like that.
Mainly because it's actually unlikely we will do it as a command line switch after the discussion.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done


```

In order to detect the warning suppression not tied to any trimmer-incompatible pattern we should run the `dotnet publish` command and pass the `--check-suppressions` option.
Copy link
Member

Choose a reason for hiding this comment

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

For now we're going with producing a new warning - in which case I agree with @sbomer that using either NoWarn or warning levels would be a great way to do this.

I think we should leave out the exact mechanics our of this document - we'll figure them out later on. It obviously has to be a toggle - and if it's on by default is a discussion for a time when we have much better understanding of the impact/UX of this.

Comment on lines 80 to 82
```shell
dotnet publish -r win-x64 -p:PublishTrimmed=True -p:_ExtraTrimmerArgs="--check-suppressions"
```
Copy link
Member

Choose a reason for hiding this comment

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

I would probably remove this - just say, running the linker with the detection enabled will produce a new warning.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Copy link
Member

@vitek-karas vitek-karas left a comment

Choose a reason for hiding this comment

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

Nice writeup!

@vitek-karas vitek-karas merged commit e981e95 into dotnet:main Jul 21, 2022
vitek-karas pushed a commit that referenced this pull request Aug 2, 2022
Implementation of the feature described in #2891.
IEvangelist pushed a commit to dotnet/docs that referenced this pull request Aug 3, 2022
* Add note on suppressing trimming warnings

Inspired by the suppression justification from dotnet/linker#2891.

* Apply suggestions from code review

Co-authored-by: Eric Erhardt <[email protected]>
Co-authored-by: Sven Boemer <[email protected]>

Co-authored-by: Eric Erhardt <[email protected]>
Co-authored-by: Sven Boemer <[email protected]>
agocke pushed a commit to dotnet/runtime that referenced this pull request Nov 16, 2022
* Created first draft of unused suppressions detection doc.

* design doc improvements

* Fix redundant suppressions design doc wording

* Fix typos

Co-authored-by: Eric Erhardt <[email protected]>

* Apply suggestions from code review

Co-authored-by: Sven Boemer <[email protected]>

* Changed example and added review suggestions.

* Apply suggestions from code review

Co-authored-by: Vitek Karas <[email protected]>

* removed implementation details

Co-authored-by: Eric Erhardt <[email protected]>
Co-authored-by: Sven Boemer <[email protected]>
Co-authored-by: Vitek Karas <[email protected]>

Commit migrated from dotnet/linker@e981e95
agocke pushed a commit to dotnet/runtime that referenced this pull request Nov 16, 2022
Implementation of the feature described in dotnet/linker#2891. 

Commit migrated from dotnet/linker@04290eb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants