-
Notifications
You must be signed in to change notification settings - Fork 94
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
[In, Out] char*
parameter MUST NOT generate string
as a friendly overload
#64
Comments
Yikes! This is definitely a must-fix. |
[In, Out] char*
parameter MUST NOT generate string
as a friendly overload
This should apply to any |
@AArnott How do I consume the bleeding edge to test this fix? There was talk about [Out] strings but that isn't applicable to this API so want to take the fix for a spin. |
@riverar Testing this would be great. Thank you. The readme includes the link and instructions to consume our daily builds. You'll want to look for a package version of 0.1.372 or later to test this fix. The daily build that includes this change will come out in about 5 hours. |
@AArnott Well I verified the string overload is gone, so bug fixed I suppose. But now there's just an incredibly difficult to use PWSTR in its place that I can't seem to initialize to a value without tainting my code with a char*. 😑 |
I guess the scenario is now: var notImmutableIconLocation = "icon.dll,1";
unsafe
{
fixed (char* ptr = notImmutableIconLocation)
{
PInvoke.PathParseIconLocation(ptr);
}
} And the user just has to remember |
I believe it is never safe to mutate a string because the runtime interns (deduplicates) string instances and IIRC there are plans in the works to make even
|
I've never heard that it does. And some substantial libraries I know go to lengths to intern strings themselves which wouldn't be necessary if the CLR did it. The BCL itself has a public interning method. @riverar no, don't pass private unsafe (string Path, int Index) PathParseIconLocation(string pathAndIndex)
{
const int MAX_PATH = 260;
Span<char> szIconFile = stackalloc char[MAX_PATH];
pathAndIndex.AsSpan().CopyTo(szIconFile);
fixed (char* pszIconFile = szIconFile)
{
int index = PInvoke.PathParseIconLocation(pszIconFile);
return (new string(pszIconFile), index);
}
} |
If the friendly overload accepted a private unsafe (string Path, int Index) PathParseIconLocation(string pathAndIndex)
{
const int MAX_PATH = 260;
var szIconFile = new StringBuilder(pathAndIndex, MAX_PATH);
int index = PInvoke.PathParseIconLocation(szIconFile);
return (szIconFile.ToString(), index);
} That would incur an extra allocation, but that's a common cost of the friendly overloads, so probably an ok cost. |
See #144 |
https://github.com/dotnet/runtime/blob/master/docs/design/features/StringDeduplication.md I've seen warnings in various discussion places (maybe by Tanner and others if I remember right) that made me realize my code that mutates |
So we've come full circle to my original report more or less 😄 Opinion: I'm also starting to wonder if all this hoop jumping truly helps anyone. Without a documented problem and supporting data, it really feels like we are micro-optimizing perf over language safety features and C# developer sanity. |
Right. The runtime has investigated automatic string interning and reserves the right to enable it in any release. My favorite example is: using System;
PseudoNativeCall("Hello, World!");
Console.WriteLine("Hello, World!");
unsafe static void PseudoNativeCall(string s)
{
fixed (char* c = s)
{
c[0] = 'J';
}
} which prints Likewise, there is no guarantee the mutation will succeed. The runtime is free to place literals and the IL, etc in read only memory in which case mutating it may result in an AccessViolationException. If you really must mutate a string, such as for efficient allocation, we provide String.Create which provides a |
For reference, we also block https://docs.microsoft.com/en-us/dotnet/standard/native-interop/best-practices should be up to date with the modern best practices |
This API takes in a
LPWStr
, scribbles a NUL on it, and returns the numeric component.Shlwapi!PathParseIconLocationW per headers is defined as such:
Win32 metadata describes it as such:
CsWin32 generated:
A simpler, safer approach:
We might be able to get away with using StringBuilder in all cases where metadata describes a parameter as
[In, Out] char *
. But I haven't had my coffee yet to say so definitively.This is also a great example of how these wrappers dangerously hide the side effects of
unsafe
, in this case mutating what was expected to be an immutable string.The text was updated successfully, but these errors were encountered: