---
title: "Const strings are not so const after all"
description: "We know the `const` keyword with strings - but are they really constant after all? Or can we use some tricks to modify them? Let's see."
updated: 2024-01-10
tags: ["C#", ".NET"]
canonical: "https://steven-giesel.com/blogPost/544c33da-be2e-4d96-99c9-9313f48548bd/const-strings-are-not-so-const-after-all"
---

# Const strings are not so const after all

We know the `const` keyword with strings - but are they really constant after all? Or can we use some tricks to modify them? Let's see.

## The `const` keyword
The way the `const` keyword works is that the compiler will put the string in the read-only memory, and then the compiler will replace all the references to the string with the address of the string in the read-only memory. So code like this:

```csharp
const string foo = "bar";

Console.WriteLine(foo);
Console.WriteLine(foo);
```

Will be [lowered](https://steven-giesel.com/blogPost/69dc05d1-9c8a-4002-9d0a-faf4d2375bce)/replaced by the compiler like this:
```csharp
Console.WriteLine("bar");
Console.WriteLine("bar");
```

There is no occurrence of the `foo` variable in the compiled code! So they are kind of "burnt" in into the code. This is why you can't use `const` strings with variables or stuff that isn't "known" at compile time. But can we modify them? Let's see.

## String interning

Sure - somewhere in the memory the string has to be stored. The mechanism here in place is called: **string interning**. The compiler will check all `const` strings in your code and will put them into a special table in the read-only memory. If you have two `const` strings with the same value, they will be put into the same table entry. So if you have this code:

```csharp
const string foo = "bar";
const string other_foo = "bar";

Console.WriteLine(foo);
Console.WriteLine(other_foo);

Console.WriteLine(ReferenceEquals(foo, other_foo));
```

Will be lowered to this:
```csharp
Console.WriteLine("bar");
Console.WriteLine("bar");

Console.WriteLine((object)"bar" == "bar"); // This will print "True"
```

So the compiler will replace all references to the `foo` and `other_foo` variables with the string `"bar"` and will check if the references are equal. And since the strings are interned, they will be equal. So if you have two `const` strings with the same value, they will be put into the same table entry. 

Okay - we are getting closer to changing strings. The last thing we have to do is getting exactly that table entry.

## Unsafe code to the rescue

The basic premise is that:
```csharp
const string foo = "bar";

ModifyString(foo);
Console.WriteLine(foo);
```

After `ModifyString` is called, the string `foo` should be `bar`. So how to do that: Well, let's get the memory address and change what is there:

```csharp
unsafe void ModifyString(string foo)
{
    fixed(char* f = foo)
    {
        f[0] = 'F';
        f[1] = 'o';
        f[2] = 'o';
    }
}
```

With that we get the following output: *Foo*. The funny part is that it also works with `var foo = "bar";` as the compiler still sees that this expression is constant! So the basic principle is that we can't change the string (in the sense of its address), but we can change the content of the string. 

What if we write more than the string is long? Well, the compiler will put the string into a buffer with a length of the string + 1. So if we write more than the string is long, we will overwrite the next string in the buffer. So if we have this code:

```csharp
unsafe void ModifyString(string foo)
{
    fixed(char* f = foo)
    {
        f[0] = 'F';
        f[1] = 'o';
        f[2] = 'o';
        f[3] = 'o';
    }
}
```

It still prints *Foo* as the metadata of the object holds it's length - so our string is still 3 characters long. You might think, wait, what if there is anything on the next memory-block, can I overwrite stuff there? Short answer, no: You will get a `System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'` exception.

Before we call it a day, one last thing regarding string interning: If we "construct" the string like this:
```csharp
Console.WriteLine(string.Concat("b", "ar"));
```

What do you think will be printed to the console: **foo** or **bar**? It is: **bar**, as "dynamic" strings are not interened and therefore in our case, the string created from `string.Concat` lives on a different address in the memory.

## Conclusion
We saw that `const` strings are not so const after all (well with many tricks, but still). You most probable (I hope) have no use for this, but understanding the internals can be interesting and helpful! Here is a [sharplab.io](https://sharplab.io/#v2:C4LgTgrgdgPgAgJgIwFgBQ6DGB7KBnYAAjiQAZCAzbbQgXkICIAjAQzAYG510BZbAEwCWFAJ4BlYGEFQA5gAoq2AJRc0JAJwLqK9BrnM2DHWqSaSpAHQBhXJhbB9TBgBpGhpcfTQ8LCgFNiABZCPiFRCSlZOXNKbXQAb3RCZMpBAA8/fjlMAAs2ACpKOljlJJTEtBSqygBtUgBdYoByADEm1WqUihqkRvom7Hayzu6EPsIBocrO2oBmccmOlIBfdGWgA) link, if you want to directly play around with the code.