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

Avoid StringBuilder parameters for P/Invokes #35693

Closed
elinor-fung opened this issue May 1, 2020 · 8 comments
Closed

Avoid StringBuilder parameters for P/Invokes #35693

elinor-fung opened this issue May 1, 2020 · 8 comments
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime.InteropServices code-analyzer Marks an issue that suggests a Roslyn analyzer
Milestone

Comments

@elinor-fung
Copy link
Member

elinor-fung commented May 1, 2020

Marshalling for StringBuilder always creates a native buffer copy and can thus be very inefficient. Consider using a char buffer from ArrayPool instead.

// Flag StringBuilder parameter
[DllImport("MyLibrary")]
private static extern void Foo(StringBuilder buffer);

Category: Performance
Default: Disabled

Since each instance of this violation would require user intervention to determine if it makes sense to address and how to address it, this would be off-by-default and up to the user to enable for code where perf is a concern.

cc @terrajobst @stephentoub @AaronRobinsonMSFT @jkoritzinsky

@elinor-fung elinor-fung added api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Runtime.InteropServices code-analyzer Marks an issue that suggests a Roslyn analyzer labels May 1, 2020
@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added the untriaged New issue has not been triaged by the area owner label May 1, 2020
@stephentoub
Copy link
Member

stephentoub commented May 1, 2020

I'm no fan of using StringBuilder in P/Invokes, and previously did a sweep through dotnet/runtime to remove almost all of it, but we do still have a few cases left, in particular where StringBuilders are passed [In] and with CharSet.Unicode; in such situations, if you already have a StringBuilder, it's a reasonable thing to use in a P/Invoke. As such I'm a little concerned this could be fairly noisy, though I agree it's a valuable thing to warn about in general in perf-sensitive code bases (maybe an IdeSuggestion, maybe off by default and folks can turn it in if desired). For code that doesn't care as much about absolute throughput, this could just be annoying.

@GrabYourPitchforks
Copy link
Member

I get the spirit of the rule, but I'm concerned that adherence to this rule significantly increases the concept count over what the original code looked like. If this rule triggers over your code and you try to address it, then in addition to understanding how StringBuilder behaves across a marshaling boundary, you also need to understand:

  1. How the array pool works, including best practices for using it
  2. How to move data between StringBuilder and a rented array
  3. Null terminator behavior when marshaling strings

And you'll need to account for these effects in your code manually.

@elinor-fung
Copy link
Member Author

Yeah, I think it would fall under the IdeSuggestion level.

There would definitely be some additional concepts tied to addressing a violation. I think it still makes sense to provide a suggestion about things like that, since it gives an immediate practical application for those concepts. Do you think documentation for a new rule pointing out and explaining (or linking to other resources) all those would not be enough help?

@stephentoub
Copy link
Member

I think part of the problem here is we can't reasonably provide an auto-fix. So we'd be saying "Consider alternatives to StringBuilder", but without a) knowing whether that actually makes sense for how they're using it, and b) with potentially non-trivial re-work required for them to address it.

@GrabYourPitchforks
Copy link
Member

Do you think documentation for a new rule pointing out and explaining (or linking to other resources) all those would not be enough help?

There is something already along these lines at https://docs.microsoft.com/en-us/dotnet/standard/native-interop/best-practices#string-parameters. It mentions the downsides of using StringBuilder but doesn't demonstrate how to work around them in your own code. If there were samples there showing best practice, we could link to it.

@elinor-fung
Copy link
Member Author

So we'd be saying "Consider alternatives to StringBuilder", but without a) knowing whether that actually makes sense for how they're using it, and b) with potentially non-trivial re-work required for them to address it.

Perhaps mitigated if it were off by default, so people would have had to choose to be warned about this specific rule (or performance rules)?

@stephentoub
Copy link
Member

Yup.

@AaronRobinsonMSFT AaronRobinsonMSFT removed the untriaged New issue has not been triaged by the area owner label Jun 8, 2020
@AaronRobinsonMSFT AaronRobinsonMSFT added this to the 5.0 milestone Jun 8, 2020
@elinor-fung elinor-fung added api-ready-for-review and removed api-suggestion Early API idea and discussion, it is NOT ready for implementation labels Jun 24, 2020
@carlossanlop carlossanlop added api-ready-for-review API is ready for review, it is NOT ready for implementation and removed api-ready-for-review labels Jul 6, 2020
@terrajobst terrajobst added api-approved API was approved in API review, it can be implemented and removed api-ready-for-review API is ready for review, it is NOT ready for implementation labels Jul 16, 2020
@terrajobst
Copy link
Member

terrajobst commented Jul 16, 2020

Video

Shipping this as a warning and off by default makes sense. Setting the severity as suggestion would likely mean that nobody will ever see this.

@ghost ghost locked as resolved and limited conversation to collaborators Dec 9, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime.InteropServices code-analyzer Marks an issue that suggests a Roslyn analyzer
Projects
None yet
Development

No branches or pull requests

7 participants