8000 Add CmdletInfo to Command Clone() by TylerLeonhardt · Pull Request #12301 · PowerShell/PowerShell · GitHub
[go: up one dir, main page]

Skip to content

Conversation

@TylerLeonhardt
Copy link
Member
@TylerLeonhardt TylerLeonhardt commented Apr 11, 2020

PR Summary

fixes #12297

This adds copying CmdletInfo to the Command class's Clone(). I also added a few tests for the PSCommand type (more should be added for coverage as it seems that this type is not tested at all it seems...) which includes a test that covers the code change.

PR Context

PowerShell Editor Services uses the PSCommand type everywhere. For whatever reason, there's an PowerShell.AddCommand(CmdletInfo cmdletInfo) but not a PSCommand.AddCommand(CmdletInfo cmdletInfo). To work around this, we have an extension method that does:

PowerShell.AddCommand(new Command(cmdletInfo))... however, this exposed another bug as we take the PSCommand type and set it directly on the PowerShell instance:

powerShell.Commands = psCommand

This would trigger cmdlet discovery for commands regardless of if they had a CmdletInfo associated with it because deep down, the CmdletInfo property on the underlying Command object would not get cloned...

This PR makes sure it also gets cloned. Take a look at the very last test added which fails before this change, but passes after it.

PSES could take advantage of this if it was backported to PS 7.0. In the meantime, we have to copy commands manually... (naturally this is what we will have to do for Windows PowerShell... but for PS7 we can use this.

cc @SeeminglyScience

PR Checklist

@ghost ghost assigned daxian-dbw Apr 11, 2020
@iSazonov iSazonov added the CL-General Indicates that a PR should be marked as a general cmdlet change in the Change Log label Apr 12, 2020
@iSazonov iSazonov added this to the 7.0.x-Servicing-Consider milestone Apr 12, 2020
@iSazonov
Copy link
Collaborator

Will we fix #12295 here too?

@TylerLeonhardt
Copy link
Member Author

I can, but I wasn't sure if that change was worthy of making servicing.

But I did think this one was worthy.

Copy link
Collaborator
@rjmholt rjmholt left a comment

Choose a reason for hiding this comment

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

This looks good. Before I sign off, I want to directly ask if this introduces the possibility of cloning a command, running on a different thread and then corrupting command info state somehow due to thread safety issues? I've read through the discussion above, but want to get a better understanding of whether there are implications for leaking a CommandInfo reference with a clone, specifically if there's a behaviour that we're confident today is threadsafe and may not be in future

@daxian-dbw
Copy link
Member

I want to directly ask if this introduces the possibility of cloning a command, running on a different thread and then corrupting command info state somehow due to thread safety issues

The answer is: yes, it could cause thread safe issue when using FunctionInfo, FilterInfo, ScriptInfo and maybe ExternalScriptInfo in a different Runspace because the ScriptBlock associated with those CommandInfo object has Runspace affiliation to the Runspace they come from. The Runspace affiliation will cause the execution of them be marshaled back to the original Runspace, which could potentially cause deadlock or corruption of the original Runspace. We have an issue on this ( #4003) that was observed by using a PowerShell class instance in a different Runspace.

However, the public API PowerShell.AddCommand(CommandInfo commandInfo) already make it possible to add a CommandInfo object from Runspace A to the PowerShell instance that will be invoked on Runspace B. From that perspective, making this change doesn't expose a new issue, but just make the existing issue easier to be hit by users 😅

Given that, I'm fine making this change, but hesitating if this change should be serviced (will leave that decision to @SteveL-MSFT)

@TylerLeonhardt
Copy link
Member Author
TylerLeonhardt commented Apr 16, 2020

Just to clarify, I'm totally fine also adding a Clone() to CommandInfo so that Command.Clone() also clones the CommandInfo if you think this will alleviate the issue a bit.

Most *Info classes already have a "clone constructor".

@daxian-dbw
Copy link
Member
daxian-dbw commented Apr 16, 2020

adding a Clone() to CommandInfo so that Command.Clone()

That won't solve the problem. You will have to create a script block because FunctionInfo has a ScriptBlock property. There is no way to guarantee that script block is created in the target Runspace where the cloned FunctionInfo is going to be invoked.
The thread safe issue needs to be solved in the engine, it's essentially a bug in the event processing code.

@TylerLeonhardt
Copy link
Member Author

if this doesn't go back to servicing I'll maybe try to add #12295 to it. It'd be a shame to have the silly workaround in PSES for PS7 though...

@rjmholt
Copy link
Collaborator
rjmholt commented Apr 16, 2020

However, the public API PowerShell.AddCommand(CommandInfo commandInfo) already make it possible to add a CommandInfo object from Runspace A to the PowerShell instance that will be invoked on Runspace B. From that perspective, making this change doesn't expose a new issue, but just make the existing issue easier to be hit by users 😅

Right, that's what I was thinking and just wanted to check that my understanding was ok. In that case, I'm happy.

@iSazonov
Copy link
Collaborator
iSazonov commented Apr 17, 2020

The thread safe issue needs to be solved in the engine, it's essentially a bug in the event processing code.

Do you mean that API proposed in the PR will fixed too?
If no I'd add Obsolete() warning to prevent users from erroneous use.

@daxian-dbw
Copy link
Member

I'll maybe try to add #12295 to it

@TylerLeonhardt Please don't. This PR has been reviewed and let's keep the scope as is. You can submit a new PR for that work.

@daxian-dbw
Copy link
Member

@iSazonov The issue can be exposed in other ways beyond those APIs.

@daxian-dbw
Copy link
Member

@PoshChan please retry macos

@PoshChan
Copy link
Collaborator

@daxian-dbw, successfully started retry of PowerShell-CI-macOS

@daxian-dbw daxian-dbw merged commit 1bf5cc9 into PowerShell:master May 11, 2020
@TylerLeonhardt TylerLeonhardt deleted the add-cmdletinfo-to-command-clone branch May 11, 2020 20:23
@ghost
Copy link
ghost commented May 19, 2020

🎉v7.1.0-preview.3 has been released which incorporates this pull request.:tada:

Handy links:

@TravisEz13
Copy link
Member

@iSazonov Please don't mark something for backport without discussing using the teams channel.

@iSazonov
Copy link
Collaborator
iSazonov commented Jun 5, 2020

@TravisEz13 I expect that "Consider" in "7.0.x-Servicing-Consider" says that the label is for the discussion. And "approved" in label is for already discussed commits. Yes?

@TravisEz13
Copy link
Member

@iSazonov But, you have been marking issue that clearly don't need to be back ported and often we don't have much time to triage once a release has been declared. I though using the teams channel would be a good way to discuss the bar.

On this one, it's for PSES and they don't need it back ported.

@TravisEz13 TravisEz13 removed this from the 7.0.x-Servicing-Consider milestone Jun 5, 2020
@TylerLeonhardt
Copy link
Member Author

I'm saying no to the backport because @daxian-dbw showed concern here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CL-General Indicates that a PR should be marked as a general cmdlet change in the Change Log

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PSCommand.Clone strips CommandInfo from inner Command objects

7 participants

0