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

Throw exception or log warning upon drive enumeration glob anomaly detection #7029

Merged

Conversation

mruxmohan4
Copy link
Contributor

@mruxmohan4 mruxmohan4 commented Nov 9, 2021

Context

Glob anomalies drive enumeration issue: #3642 (comment). Properties that evaluate to empty result in drive enumeration.

Changes Made

Logs an error via ProjectFileErrorUtilities.ThrowInvalidProject(...) with the resource name WildcardResultsInDriveEnumeration when \**, <drive>:\**, or <drive>:<any number of slashes>** are detected on the leftmost side while parsing and the environment variable MSBUILDFAILONDRIVEENUMERATINGWILDCARD is set to 1 (with the exception of one case listed in "Notes" below which simply logs an error). Note that a warning is logged (rather than an error) with the same resource name when the environment variable is set to 0.

Regarding more recent changes, logging a warning/throwing an InvalidProjectFileException has become more unified and placed in EngineFileUtilities.cs. Logging a warning/throwing an exception with the resource name requires extra information, including a SearchAction and ExcludeFileSpec, which are returned from FileMatcher into various codepaths (CreateItem & EngineFileUtilities), which obtain additional parameters from other codepaths, such as Evaluator, Expander, ItemGroupIntrinsicTask, LazyItemEvaluator.IncludeOperation, etc., to better identify the logging mechanism and attributes that should be passed to EngineFileUtilities.cs upon logging a warning/throwing an exception. There is no custom exception that is caught and then converted into an InvalidProjectFileException (all of the functionality that came with a custom exception has been removed with a prior commit for these changes). When the env var is set to 1, a nearly immediate return from functions occurs, as we want the build to fail and throw upon detection of a drive enumerating wildcard.

Testing

Larger integration tests with empty properties/imports were created to trigger the issue in targets. Smaller tests in FileMatcher_Tests.cs were created to check for particular wildcard patterns that should result in the custom exception being thrown.

Unit tests were added to: FileMatcher_Tests.cs, ProjectItem_Tests.cs, CreateItem_Tests.cs, and ProjectItemInstance_Tests.cs.

Notes

  1. Uses MSB5029 error code (see shared resx).
  2. For CreateItem, an error is logged instead of using ProjectFileErrorUtilities.ThrowInvalidProject(...)
  3. The resource name used was WildcardResultsInDriveEnumeration to pass on element locations to InvalidProjectFileException.

@dnfadmin
Copy link

dnfadmin commented Nov 9, 2021

CLA assistant check
All CLA requirements met.

@dnfadmin
Copy link

dnfadmin commented Nov 9, 2021

CLA assistant check
Thank you for your submission, we really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.

❌ mruxmohan-msft sign now
You have signed the CLA already but the status is still pending? Let us recheck it.

@mruxmohan4 mruxmohan4 marked this pull request as draft November 9, 2021 21:54
src/Tasks/CreateItem.cs Outdated Show resolved Hide resolved
src/Build/AssemblyInfo.cs Outdated Show resolved Hide resolved
@Forgind Forgind added the WIP label Nov 10, 2021
@mruxmohan4 mruxmohan4 force-pushed the dev/mruxmohan/addGlobAnomalyDiagnostics branch 3 times, most recently from 227c2d8 to 67a278b Compare November 11, 2021 02:04
@mruxmohan4 mruxmohan4 marked this pull request as ready for review November 11, 2021 03:40
@mruxmohan4 mruxmohan4 force-pushed the dev/mruxmohan/addGlobAnomalyDiagnostics branch from 67a278b to dd3c05d Compare November 11, 2021 17:48
@Forgind
Copy link
Member

Forgind commented Nov 11, 2021

I hadn't really properly looked at what you were trying to do here before, but @ladipro made a similar PR here that prevented drive enumerations when the condition was false specifically. It would probably be easy to glom onto that to achieve what you're trying to do here—but although drive enumerations are probably not intended, this might be a bit much of a breaking change for 17.1. Might be good enough with a change wave? Not sure.

@Forgind Forgind removed the WIP label Nov 11, 2021
@mruxmohan4
Copy link
Contributor Author

mruxmohan4 commented Nov 11, 2021

@Forgind @ladipro Right, that PR did alleviate drive enumerations, according to #3642 (comment), but this was an attempt to improve logging and surface an exception. Is this necessary given the following that was already completed in #5669, or does the existing logging below not surface all the way to the user?

                            if (MSBuildEventSource.Log.IsEnabled())
                            {
                                MSBuildEventSource.Log.ExpandGlobStop(_rootDirectory, glob, string.Join(", ", excludePatternsForGlobs));
                            }

@Forgind
Copy link
Member

Forgind commented Nov 15, 2021

Users can get that information, but they have to specifically ask for it and almost always will not. I doubt anyone would find it unless they specifically looked.

@ladipro
Copy link
Member

ladipro commented Nov 15, 2021

@mruxmohan-msft I'm afraid that requiring an opt-in via the MsBuildCheckWildcardDriveEnumeration environment variable is not going to be very helpful. The user has to be notified even if they don't expect this issue, i.e. they have not explicitly opted in.

We should try to come up with a solution which we can enable by default, while causing little-to-no pain to users who enumerate full drives intentionally. Perhaps a build warning would be acceptable as along as it:

  • Is surfaced under default logging verbosity in both command line build (msbuild and dotnet build) and in Visual Studio.
  • Can be easily disabled.

@rainersigwald rainersigwald mentioned this pull request Nov 29, 2021
@mruxmohan4 mruxmohan4 marked this pull request as draft November 29, 2021 16:35
src/Shared/FileMatcher.cs Outdated Show resolved Hide resolved
@mruxmohan4 mruxmohan4 force-pushed the dev/mruxmohan/addGlobAnomalyDiagnostics branch from 1c53298 to 9163404 Compare December 1, 2021 19:17
src/Tasks/CreateItem.cs Outdated Show resolved Hide resolved
src/Tasks/CreateItem.cs Outdated Show resolved Hide resolved
src/Shared/FileMatcher.cs Outdated Show resolved Hide resolved
src/Shared/Resources/Strings.shared.resx Outdated Show resolved Hide resolved
src/Shared/FileMatcher.cs Outdated Show resolved Hide resolved
src/Shared/FileMatcher.cs Outdated Show resolved Hide resolved
src/Shared/UnitTests/FileMatcher_Tests.cs Outdated Show resolved Hide resolved
src/Shared/FileMatcher.cs Outdated Show resolved Hide resolved
src/Shared/FileMatcher.cs Show resolved Hide resolved
src/Shared/FileMatcher.cs Outdated Show resolved Hide resolved
src/Shared/FileMatcher.cs Outdated Show resolved Hide resolved
@mruxmohan4 mruxmohan4 changed the title Throw custom exception upon drive enumeration glob anomaly detection Throw exception or log warning upon drive enumeration glob anomaly detection Jan 20, 2022
Copy link
Member

@rainersigwald rainersigwald left a comment

Choose a reason for hiding this comment

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

I think this is starting to look great! I pointed out many smaller nits.

src/Build/Utilities/EngineFileUtilities.cs Outdated Show resolved Hide resolved
src/Build/Utilities/EngineFileUtilities.cs Outdated Show resolved Hide resolved
src/Build/Utilities/EngineFileUtilities.cs Outdated Show resolved Hide resolved
src/Build/Utilities/EngineFileUtilities.cs Outdated Show resolved Hide resolved
src/Shared/FileMatcher.cs Outdated Show resolved Hide resolved
src/Tasks.UnitTests/CreateItem_Tests.cs Outdated Show resolved Hide resolved
src/Tasks/CreateItem.cs Show resolved Hide resolved
src/Build/Evaluation/Expander.cs Outdated Show resolved Hide resolved
src/Build/Evaluation/LazyItemEvaluator.IncludeOperation.cs Outdated Show resolved Hide resolved
src/Shared/Resources/Strings.shared.resx Outdated Show resolved Hide resolved
src/Build/Evaluation/Expander.cs Outdated Show resolved Hide resolved
src/Shared/FileMatcher.cs Outdated Show resolved Hide resolved
src/Shared/FileMatcher.cs Outdated Show resolved Hide resolved
src/Shared/FileMatcher.cs Show resolved Hide resolved
Copy link
Member

@ladipro ladipro left a comment

Choose a reason for hiding this comment

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

I have not reviewed all files yet but I may not have more time today so publishing what I have. Overall I think the changes look great.

src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs Outdated Show resolved Hide resolved
src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs Outdated Show resolved Hide resolved
src/Build/Utilities/EngineFileUtilities.cs Outdated Show resolved Hide resolved
src/Shared/FileMatcher.cs Outdated Show resolved Hide resolved
src/Shared/FileMatcher.cs Outdated Show resolved Hide resolved
src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs Outdated Show resolved Hide resolved
src/Shared/UnitTests/FileMatcher_Tests.cs Outdated Show resolved Hide resolved
bool excludeFileSpecIsUnusable = string.IsNullOrWhiteSpace(excludeFileSpec);
string fileSpec = excludeFileSpecIsUnusable ? filespecUnescaped : excludeFileSpec;

switch (action)
Copy link
Contributor Author

@mruxmohan4 mruxmohan4 Jan 26, 2022

Choose a reason for hiding this comment

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

Is there a more optimal way to clean up the logic within these switch statements? I tried to reduce as many lines of code as possible.

Also, are the conditions correct? I want to make certain that I'm not causing any false positive/negative warnings or errors (in spite of test coverage), in addition to having the wrong attributes and elements associated with the warnings/errors (are there preferred ways to include specific metadata in tests without checking for particular messages contained in logs, as those may change over time?). This section might be more clear once I complete test cleanup and add more inline data in ProjectItem_Tests.cs and ProjectItemInstance_Tests.cs.

Copy link
Member

Choose a reason for hiding this comment

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

Is there a more optimal way to clean up the logic within these switch statements? I tried to reduce as many lines of code as possible.

Just a few random ideas:

  1. You could try to flatten the code to have only one switch with pattern matching. Something like: https://dotnetfiddle.net/DUHvNn
  2. Or maybe it would be better to refactor the inner switches into their own helper method each.

Copy link
Member

Choose a reason for hiding this comment

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

IIRC I started experimenting with approach 1 for this problem and didn't like where I wound up, so I think I'd lean toward approach 2, @mruxmohan4. In the general case I like 1 better though.

Copy link
Member

Choose a reason for hiding this comment

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

I haven't looked to see if this is viable in this case, but it can sometimes be fairly clean to have two separate switches, one to select relevant arguments and one to select a delegate to apply to them. Then you can just apply it at the end.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I went ahead with approach 2 to make it less clunky in the inner switch statements.

@Forgind Forgind self-requested a review February 7, 2022 18:49
Copy link
Member

@ladipro ladipro left a comment

Choose a reason for hiding this comment

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

I've left a few comments inline, mostly nits.

src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs Outdated Show resolved Hide resolved
src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs Outdated Show resolved Hide resolved
src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs Outdated Show resolved Hide resolved
src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs Outdated Show resolved Hide resolved
bool excludeFileSpecIsUnusable = string.IsNullOrWhiteSpace(excludeFileSpec);
string fileSpec = excludeFileSpecIsUnusable ? filespecUnescaped : excludeFileSpec;

switch (action)
Copy link
Member

Choose a reason for hiding this comment

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

Is there a more optimal way to clean up the logic within these switch statements? I tried to reduce as many lines of code as possible.

Just a few random ideas:

  1. You could try to flatten the code to have only one switch with pattern matching. Something like: https://dotnetfiddle.net/DUHvNn
  2. Or maybe it would be better to refactor the inner switches into their own helper method each.

src/Build/Utilities/EngineFileUtilities.cs Outdated Show resolved Hide resolved
src/Shared/FileMatcher.cs Outdated Show resolved Hide resolved
src/Shared/FileMatcher.cs Outdated Show resolved Hide resolved
src/Tasks/CreateItem.cs Outdated Show resolved Hide resolved
src/Tasks/CreateItem.cs Outdated Show resolved Hide resolved
bool excludeFileSpecIsUnusable = string.IsNullOrWhiteSpace(excludeFileSpec);
string fileSpec = excludeFileSpecIsUnusable ? filespecUnescaped : excludeFileSpec;

switch (action)
Copy link
Member

Choose a reason for hiding this comment

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

IIRC I started experimenting with approach 1 for this problem and didn't like where I wound up, so I think I'd lean toward approach 2, @mruxmohan4. In the general case I like 1 better though.

src/Build/Utilities/EngineFileUtilities.cs Outdated Show resolved Hide resolved
Copy link
Member

@Forgind Forgind left a comment

Choose a reason for hiding this comment

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

This is really more of a quick pass than a full review, but it sounded like rainersigwald gave more complete comments.

src/Tasks/CreateItem.cs Show resolved Hide resolved
src/Shared/FileMatcher.cs Outdated Show resolved Hide resolved
src/Shared/FileMatcher.cs Show resolved Hide resolved
src/Build/Utilities/EngineFileUtilities.cs Outdated Show resolved Hide resolved
src/Build/Utilities/EngineFileUtilities.cs Show resolved Hide resolved
src/Build/Utilities/EngineFileUtilities.cs Outdated Show resolved Hide resolved
src/Build/Utilities/EngineFileUtilities.cs Outdated Show resolved Hide resolved
@rainersigwald rainersigwald added the merge-when-branch-open PRs that are approved, except that there is a problem that means we are not merging stuff right now. label Feb 28, 2022
@rainersigwald rainersigwald added this to the VS 17.2 milestone Feb 28, 2022
@mruxmohan4 mruxmohan4 force-pushed the dev/mruxmohan/addGlobAnomalyDiagnostics branch 2 times, most recently from e1dfd32 to 6d537b8 Compare March 1, 2022 20:28
@mruxmohan4 mruxmohan4 force-pushed the dev/mruxmohan/addGlobAnomalyDiagnostics branch from 0018d75 to ad7ab8d Compare March 2, 2022 20:59
@mruxmohan4 mruxmohan4 force-pushed the dev/mruxmohan/addGlobAnomalyDiagnostics branch from ad7ab8d to afdbfc1 Compare March 2, 2022 21:23
@benvillalobos benvillalobos merged commit 931ff51 into dotnet:main Mar 11, 2022
AR-May pushed a commit that referenced this pull request May 11, 2022
Fixes #7029 by associating a file location string with the WildcardResultsInDriveEnumeration resource name.

Context
For https://github.com/dotnet/project-system/blob/main/build/import/Workarounds.targets#L8, it was difficult to detect the location at which the drive enumerating wildcard pattern was occurring even though a warning was logged, since 1) there was no location string added to the warning, and 2) the Exclude rather than the Remove element was shown in the warning. To resolve 1), it would be better to associate the location string with the WildcardResultsInDriveEnumeration resource name.

Changes Made
Added location string to the WildcardResultsInDriveEnumeration resource name in order to view the location for drive enumerating wildcard warnings and errors.

Testing
Modified ProjectItem, ObjectModelHelper (for ProjectItemInstance), and CreateItem unit tests to ensure that the project file location was placed in the warning or error message.

Notes
Any <i Remove=<drive enumerating wildcard> /> will still be considered as an Exclude attribute in the warning or error message, since is treated as equivalent to <Foo Include=... Exclude=... />, which still makes the warning or error message slightly unclear for drive enumerating wildcard used in Remove cases. However, the wildcarded value will still be caught and logged/thrown based on whether the environment variable is set.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merge-when-branch-open PRs that are approved, except that there is a problem that means we are not merging stuff right now.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants