Skip to content

Block the use of IForegroundNotificationService when there is no foreground thread#25938

Merged
sharwell merged 1 commit intodotnet:masterfrom
sharwell:notification-service
Apr 10, 2018
Merged

Block the use of IForegroundNotificationService when there is no foreground thread#25938
sharwell merged 1 commit intodotnet:masterfrom
sharwell:notification-service

Conversation

@sharwell
Copy link
Copy Markdown
Contributor

@sharwell sharwell commented Apr 4, 2018

Customer scenario

A correctly-written test could incorrectly fail during a build.

Bugs this fixes

Fixes #25930

Workarounds, if any

None

Risk

Low. The conditions under which behavior is changed do not occur in production environments.

Performance impact

Low. A new assertion is added on a code path that is only called when work is being queued on a different thread.

Is this a regression from a previous update?

Yes.

Root cause analysis

This is a race condition where the following sequence occurs:

  1. A test uses [UseExportProvider] but does not use IForegroundNotificationService
  2. The test does not use [WpfFact]
  3. During UseExportProviderAttribute.After, an instance of ForegroundNotificationService is constructed here, which queues a background task
  4. UseExportProviderAttribute.After is executed on a background thread, and reaches this join operation before the task starts running
  5. The task starts running on the current thread, which results in an assertion because the "foreground thread" is also a thread pool thread

This change prevents the IForegroundNotificationService from being used to schedule foreground operations when there is no foreground thread, and then resolves the source of the crash in this case by avoiding the creation of the background operation.

How was the bug found?

Automated testing

Test documentation updated?

N/A

@sharwell sharwell requested a review from a team as a code owner April 4, 2018 21:25
@sharwell sharwell added this to the 15.7 milestone Apr 4, 2018
@sharwell sharwell mentioned this pull request Apr 5, 2018
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes we should remove that but it's still on the backlog.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

so. we no longer use mock on tests? is that it?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is it safe to silently discard these? Maybe a non-fatal error could be logged.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

cc @KirillOsenkov we used to have no logging for these notifications and we had them silently discarded. We need to verify we're doing the right thing here if this patch goes in.

Copy link
Copy Markdown
Contributor Author

@sharwell sharwell Apr 5, 2018

Choose a reason for hiding this comment

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

@Therzok I'm not sure what the specific concern is here. With this change, it is impossible to queue work without a foreground thread, hence why I didn't start the task.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

From what I see, the fallback thread data will not queue work. The concern is needing to know which things need to be setup to properly function.

We had code throwing in this service, that was masked, because we didn't have FatalError handlers setup.

Maybe it's worth notifying the consumer that the setup is not properly done?

As another point, I was thinking about filing a bug about FatalError not saying no handler is registered. Maybe ForehroundNotificationService should report that no thread handler is set?

Copy link
Copy Markdown
Contributor Author

@sharwell sharwell Apr 5, 2018

Choose a reason for hiding this comment

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

From what I see, the fallback thread data will not queue work.

Correct. It will now throw a synchronous exception immediately upon attempting to schedule the work.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ohhhh, I just noticed the Contract.ThrowIfTrue calls below. No worries from my side anymore!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I am changing this test to wait for semantic change processor. leave the fix to me.

@sharwell sharwell force-pushed the notification-service branch from 63d638d to cdb05e1 Compare April 5, 2018 16:40
@heejaechang
Copy link
Copy Markdown
Contributor

so I guess when testing features that require foreground thread in unit test, we need to mark the unit test WpfTest or something?

@heejaechang
Copy link
Copy Markdown
Contributor

heejaechang commented Apr 9, 2018

@sharwell I am fine with change. but if unit test that require certain attribute if it needs foreground thread for whatever reason, it would be nice if there is some doc or wiki people can learn about our unit test magics.

@sharwell
Copy link
Copy Markdown
Contributor Author

sharwell commented Apr 9, 2018

so I guess when testing features that require foreground thread in unit test, we need to mark the unit test WpfTest or something?

This was already the case, but breaking the rule in the past would typically just make for a flaky test.

@Pilchie
Copy link
Copy Markdown
Member

Pilchie commented Apr 9, 2018

I'm hesitant about treating this as a test only change considering the number of times changes like this have broken scenarios like devenv /build.

@heejaechang
Copy link
Copy Markdown
Contributor

@sharwell shouldn't it then explicitly crash or throw with message saying [WpfTest] should be marked on test that require UI?

@sharwell
Copy link
Copy Markdown
Contributor Author

sharwell commented Apr 9, 2018

shouldn't it then explicitly crash or throw with message saying [WpfTest] should be marked on test that require UI?

Technically this isn't the requirement. The requirement is that a "main thread" of some form be available which is not also a thread pool thread. Generally code which violates this will hit a different problem much earlier by accessing a foreground thread affinitized object that asserts in the constructor. This service is a special case because it needs to support construction when no foreground thread is available, provided work is not queued in it.

@heejaechang
Copy link
Copy Markdown
Contributor

wouldn't it be safer to just asking any tests that require main thread to just always marked as [WpfFact] rather than one to know all these details whether [WpfFact] is okay to omitted in certain case?

if (ForegroundKind != ForegroundThreadDataKind.Unknown)

not sure how many people in our team actually know all the implication of ThreaddataKind being different ones.

@sharwell sharwell changed the base branch from dev15.7.x to master April 9, 2018 22:49
@sharwell sharwell modified the milestones: 15.7, 15.8 Apr 9, 2018
@sharwell
Copy link
Copy Markdown
Contributor Author

@heejaechang The general approach is adding a call to WpfTestCase.RequireWpfFact whenever it's required. It's a bit more challenging in this case because the assertion lives in test code but the ForegroundNotificationService implementation lives in production code.

Improved messaging around this is something we can add in the future, perhaps as part of #25805. Also, keep in mind that it's quite possible other tests that use IForegroundNotificationService already call RequireWpfFact as part of their use of some other type.

@sharwell sharwell merged commit 20a1122 into dotnet:master Apr 10, 2018
@sharwell sharwell deleted the notification-service branch April 10, 2018 11:57
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.

[xUnit] [ERROR] - The result file Roslyn.Services.Editor.UnitTests.dll.xml for the metric 'xUnit.Net' is empty.

5 participants