Comments (15)
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 new string instances could break in the future.
Right. The runtime has investigated automatic string interning and reserves the right to enable it in any release.
Strings are immutable, by design, and attempting to mutate them (particularly literals) can result in weird behaviors.
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 Jello, World!
.
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.
In some cases (such as on more locked down platforms) this may even be the default scenario. Apple Silicon, the ARM64 variant, for example requires that executable code not be writable and so we had to add such support and begin enforcing it for that platform.
If you really must mutate a string, such as for efficient allocation, we provide String.Create which provides a SpanAction
callback allowing you to safely mutate before the memory becomes "immutable" and is open to being placed in readonly memory or subject to string interning.
from cswin32.
For reference, we also block [Out] string
(which is distinct from out string
or [Out] out string
) as of recent .NET Core: dotnet/coreclr#21513
https://docs.microsoft.com/en-us/dotnet/standard/native-interop/best-practices should be up to date with the modern best practices
from cswin32.
If you have links to share, I'd love to learn what is planned around new string that you mention.
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 new string
instances could break in the future.
from cswin32.
@jnm2 Let's follow up on the span discussion over at #144
from cswin32.
in this case mutating what was expected to be an immutable string.
Yikes! This is definitely a must-fix.
from cswin32.
This should apply to any [Out] string
(anything documented as mutating the string)
from cswin32.
@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.
from cswin32.
@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.
from cswin32.
@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*. 😑
from cswin32.
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 notImmutableIconLocation
is not an immutable string? Is there another pattern I'm missing here?
from cswin32.
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 new string
overloads return existing pooled instances.
Using a char array is more semantically correct in my understanding.var notImmutableIconLocation = "icon.dll,1".ToCharArray();
from cswin32.
the runtime interns (deduplicates) string instances
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.
@jnm2 If you have links to share, I'd love to learn what is planned around new string
that you mention.
@riverar no, don't pass string
into a mutable function. That defeats the point of the change. What @jnm2 suggests is counter to the docs, which require a string of MAX_PATH
in length in this case. Here is what I would do:
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);
}
}
from cswin32.
If the friendly overload accepted a StringBuilder
, the code could look like this:
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.
from cswin32.
See #144
from cswin32.
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.
from cswin32.
Related Issues (20)
- Pointers to native classes should _not_ be dereferenced by C# HOT 1
- Allow turning off "friendly" P/Invoke overloads
- GdiPlus Color struct is generating with statics as fields
- Source generated files are added to compilation with SHA1 algorithm HOT 5
- Failed to open generated code in Visual Studio Code HOT 1
- IAudioSessionManager2::GetSessionEnumerator missing parameter HOT 4
- Bug: CONNECT_UPDATE_PROFILE cannot be found HOT 3
- CredUIPromptForCredentials should not emit `ref` on `ref Span<char>` parameter
- Access violation writing location when calling DirectX APIs. HOT 1
- Use System.Runtime.InteropServices.ComTypes.IStream instead of generating the interface HOT 1
- Enable generating IID_IDispatch constant
- Accessing property IShellFolderViewDual.Application causes InvalidOleVariantTypeException "Specified OLE variant is invalid" HOT 1
- No consistent definitions in some Com interface methods
- Generate overload that sets `dwLength`? HOT 2
- Missing compiler required member HOT 2
- CA1416: is only supported on: 'windows' 5.1.2600 and later HOT 3
- Can't import Windows.Win32.System.Threading HOT 1
- Regression with `ReadFile` and `WriteFile` for `SafeHandle` HOT 1
- when wideCharOnly is true (default) specifying explicit ascii prefixed functions in NativeMethods.txt will result in it silently ignored
- IncludeAssets=all advice causes problems with NuGet packages HOT 7
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from cswin32.