Sealad
Sealad

Reputation: 92

Why is modifying this String also modifying the content of another, seperate String?

In my static main function I have the following code:

string str1 = "aaaaaaaaa";
pointerTest();
Console.WriteLine( "str1 is: " + str1 );

The static pointerTest-method, which is declared as unsafe, contains the following:

string str2 = "aaaaaaaaa";
fixed( char* ptr = str2 )
{
    for( int i = 0; i < str2.Length / 3; ++i )
        ptr[i] = 'z';
}

Console.WriteLine( "str2 is: " + str2 );

Notice how str1 and str2 are independently declared, but do have the same content.

The expected output of this program would be:

str2 is: zzzaaaaaa
str1 is: aaaaaaaaa

When I run the program the actual output shows this:

str2 is: zzzaaaaaa
str1 is: zzzaaaaaa

When I change str2 or str1 to not have the exact same content (for example by adding one more 'a' at the end of str2) the program acts like expected.
If have found this behaviour to exist both in .Net Core 3.1 and Mono (unsure about the exact version, I used Repl.It)

My question is why this behaviour happens and what can be done to get around it.

Upvotes: 0

Views: 59

Answers (1)

Sealad
Sealad

Reputation: 92

My theory is that this happens because of compiler optimization, specifically a process called string interning:

The compiler recognises that it would be unnecessary to allocate str2 by itself, since there already is the exact same sequence of chars in memory, allocated with the initialization of str1. So instead of allocating it anew, it makes str2 a reference to the location that str1 is already pointing to. More about this can be read here.

Strings are considered immutable in C#, so - under normal circumstances - it shouldn't be possible to modify their content in any way, shape or form.

Since this code is using the unsafe keyword and pointer-logic it is not guaranteed to not cause undefined behaviour, which leads to the sursprising result.

The only way to get around this "problem" is to adhere to the C#'s specifications and treat Strings as immutable.

Upvotes: 1

Related Questions