Skip to content

Register Dependency Arcs for Extension Members #36099

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

Merged
merged 7 commits into from
Feb 27, 2021

Conversation

CodaFi
Copy link
Contributor

@CodaFi CodaFi commented Feb 23, 2021

Built on top of #36096


This was a hole in the existing dependency tracking infrastructure. David managed to discover a way to exploit this bug to get a miscompile in rdar://74583179. There, members of extensions were not counted towards the interface hash of a type and so mutating them could lead to e.g. the wrong declaration being selected in an overload set.

To start tracking extensions, we need to add two new kinds of arcs:

  1. A nominal arc to the extension
  2. A member arc to the extension

Unfortunately, extensions are also non-nominal in Swift: they do not have a name to allow us to unique them. Luckily, we do have a way of identifying extensions: their fingerprint. These arcs are therefore emitted with the extended nominal type and the fingerprint of the extension as their context. This effectively invents a new nominal type for every extension.

@CodaFi CodaFi requested a review from davidungar February 23, 2021 01:11
@CodaFi
Copy link
Contributor Author

CodaFi commented Feb 23, 2021

@swift-ci smoke test

@davidungar
Copy link
Contributor

. These arcs are therefore emitted with the extended nominal type and the fingerprint of the extension as their context. This effectively invents a new nominal type for every extension.

Fascinating! What happens when one adds a member? The fingerprint changes and the key changes. It might be--have to think about it--as if the old extension were removed and replaced by the new one. It just might work. Or it might be somewhat pessimal. I'm not sure.

@davidungar
Copy link
Contributor

This will be much easier to review after the other PR is landed and this one is rebased. We'll need to think about the transitivity. If I change an extension, the arcs will propagate to the nominal and potential member nodes. Then, is there a transitive closure from there?

@davidungar
Copy link
Contributor

Now, I'm wondering why these things need names at all. What about a new kind of dependency?

This was a hole in the existing dependency tracking infrastructure. David managed to discover a way to exploit this bug to get a miscompile in rdar://74583179. There, members of extensions were not counted towards the interface hash of a type and so mutating them could lead to e.g. the wrong declaration being selected in an overload set.

To start tracking extensions, we need to add two new kinds of arcs:
1) A nominal arc to the extension
2) A member arc to the extension

Unfortunately, extensions are also unique in Swift in that they do not have a name to allow us to unique them. Luckily, we do have a way of identifying extensions: their fingerprint. These arcs are therefore emitted with the extended nominal type and the fingerprint of the extension as their context. This effectively invents a new nominal type for every extension.
@CodaFi
Copy link
Contributor Author

CodaFi commented Feb 23, 2021

@swift-ci smoke test

Copy link
Contributor

@davidungar davidungar left a comment

Choose a reason for hiding this comment

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

Very nicely done! I'd only ask for a little more explanation in the comments. Some of this stuff is--by its nature--subtle and tricky. Although the code is as clear as can be, future maintainers will need all the help they can get!

return Builder{kind, aspect, cast<NominalTypeDecl>(D), name};
const DeclContext *context = dyn_cast<NominalTypeDecl>(D);
if (!context) {
context = cast<ExtensionDecl>(D);
Copy link
Contributor

Choose a reason for hiding this comment

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

Not new with this PR, and a nit: When I saw the "cast" I realized that withContext will fail an assert when the D parameter is the wrong kind of Decl. Perhaps the declaration of withContext in the header file would benefit from a comment stating the required types of that parameter?

.build();

// If the subject of this dependency is not the nominal type itself,
// record another arc for the extension this member came from.
Copy link
Contributor

Choose a reason for hiding this comment

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

This comment needs another sentence or two explaining the "why".

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, it ought to explain why just the interface and not the implementation for the sake of future maintainers.

Comment on lines +308 to +311
// Add used members from the perspective of
// 1) The decl context they are found in
// 2) The decl context of the request
// This gets us a dependency not just on `Foo.bar` but on `extension Foo.bar`.
Copy link
Contributor

Choose a reason for hiding this comment

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

Excellent!

@CodaFi CodaFi closed this Feb 26, 2021
@CodaFi CodaFi reopened this Feb 26, 2021
@CodaFi
Copy link
Contributor Author

CodaFi commented Feb 26, 2021

@swift-ci smoke test

Copy link
Contributor

@davidungar davidungar left a comment

Choose a reason for hiding this comment

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

Looks good. There is one comment that could use a bit more "why".

@davidungar
Copy link
Contributor

@swift-ci please smoke test macos platform

@davidungar
Copy link
Contributor

Looks like the test failed for an irrelevant reason. Starting another.

@davidungar davidungar merged commit bc7eb59 into swiftlang:main Feb 27, 2021
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.

2 participants