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

Initial draft for a capability-based analyzer #261

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

terrajobst
Copy link
Member

No description provided.

@terrajobst terrajobst marked this pull request as draft April 12, 2022 03:13
{
}

[RequiresDynamicCode]
Copy link
Member

Choose a reason for hiding this comment

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

We typically only mark the constructor or factory to limit number of places that need to be annotated.


She immediately gets a diagnostic:

CAXXXX: The API 'Thread.Start()' requires the capability 'ThreadCreation'. Either mark the consumer with `[RequiresThreadCreation]` or check by calling 'Thread.IsCreationSupported'.
Copy link
Member

@jkotas jkotas Apr 12, 2022

Choose a reason for hiding this comment

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

Are there other platform APIs except Thread.Start that would be marked as requiring the thread create capability?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think Task.WaitAll could be in the bucket

Copy link
Member

Choose a reason for hiding this comment

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

I see that Task.WaitAll is marked as supported on browser, but Task.Wait is not. Why is that?

I would expect Task.WaitAll to be just a more efficient version of foreach (Task t in tasks) t.Wait().

Are both Task.Wait and Task.WaitAll going to be marked with this capability?

Copy link
Contributor

Choose a reason for hiding this comment

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

I believe the idea behind is that if you are in a single-threaded setup Task.WaitAll will never return as you wait on more than 1 concurrent thing (yeah there are some exceptions). Therefore if you are calling it you are doing something wrong.

/cc @lewing

Copy link
Member

Choose a reason for hiding this comment

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

I believe the idea behind is that if you are in a single-threaded setup Task.WaitAll will never return as you wait on more than 1 concurrent thing (yeah there are some exceptions).

That should not be the case. As Jan suggested, behaviorally there shouldn't be a difference between using Task.WaitAll on multiple things and using Task.Wait on each of those multiple things.

Further, both WaitAll and Wait can "inline" the thing they're waiting on if it's backed by a delegate to be executed (e.g. Task.Run(action)), so if you are in a single-threaded environment and you're waiting on such tasks, they should both "just work". If they don't in such cases, that suggests we're missing handling of this case in browser.

Copy link
Member

@lewing lewing Apr 12, 2022

Choose a reason for hiding this comment

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

I'm surprised WaitAll isn't marked. There are definitely certain circumstances where it can block. I suspect it got overlooked.

Further, both WaitAll and Wait can "inline" the thing they're waiting on if it's backed by a delegate to be executed (e.g. Task.Run(action)), so if you are in a single-threaded environment and you're waiting on such tasks, they should both "just work". If they don't in such cases, that suggests we're missing handling of this case in browser.

In the browser we have tasks (e.g. any JS interop involving a Promise) that cannot complete without yielding execution back to the browser main loop, so they won't "just work". Wait and WaitAll can work under many circumstances but in practice they can and do break in confusing ways.

Copy link
Member

Choose a reason for hiding this comment

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

so they won't "just work"

Right, that's the category I mentioned where they're not backed by delegates.

Both WaitAll and Wait would have the same issue there; WaitAll isn't special in that regard.

Copy link
Member

Choose a reason for hiding this comment

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

agreed

// - ILGenerator
}
```

Copy link
Member

@jkotas jkotas Apr 12, 2022

Choose a reason for hiding this comment

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

We also have RequiresAssemblyFilesAttribute and RequiresUnreferencedCodeAttribute and associated analyzers. Are these attributes in scope or out of scope for this proposal?

Copy link
Member Author

Choose a reason for hiding this comment

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

Depends on whether what they track can be mapped to the capability analyzer. The goal wasn't to replace the existing linker analyzers as much as it was to replace the [UnsupportedOSPlatform("browser")] annotations with something more scoped/future proof. I merely added the dynamic code capability because it was a recent example of a capability-based API that this design should be able to accommodate as well.


[AttributeUsage(AttributeTargets.Method |
AttributeTargets.Property |
AttributeTargets.Field,
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you have an example of which capability would be controlled by field?

Copy link
Member Author

Choose a reason for hiding this comment

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

We have done this for [UnsupportedOSPlatformGuard], for example here. The intent is to cache the result of the call.

@agocke
Copy link
Member

agocke commented Apr 13, 2022

FYI, we're doing a lot of this with RequiresUnreferencedCode, RequiresAssemblyFiles, and RequiresDynamicCode for the runtime. I love this direction and I think it would be great if we had a system like this for generalizing the concept of capability semantics and defining the APIs necessary for recognizing the patterns.

I haven't read through the proposal yet, but I hope the semantics would be compatible with what we've come up with for the above attributes.

@marek-safar marek-safar requested a review from vitek-karas April 21, 2022 09:05
@vitek-karas
Copy link
Member

Is there any connection to build properties?
If I'm building an app for net7.0-windows threading is always available and so I should not need to add any attributes or runtime checks to my app code. As described though, the analyzer would still warn.
There should be some connection to some MSBuild property which should enable/disable specific capability checks.

@terrajobst terrajobst marked this pull request as ready for review May 9, 2022 20:40

[RequiresThreadCreation]
public void Start();
}
Copy link
Contributor

@buyaa-n buyaa-n May 10, 2022

Choose a reason for hiding this comment

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

This example makes sense to me, @terrajobst could you add example of CapabilityGuardAttribute usage? Not sure if that was supposed to be added to IsCreationSupported property or we should know that it is the guard by the 2nd constructor argument of CapabilityCheck attribute

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.

8 participants