Mutating immutable strings in Go

As most Go programmers probably know, strings are immutable in Go. This has its advantages, but there are times when one might want to make changes to a string. Using reflection, we can obtain the underlying StringHeader struct of strings and modify the contents.

There are a few caveats though. This doesn’t work on string literals, as those are typically stored in read-only memory. Trying to modify a string located in read-only memory would result in a segfault. Another downside is the fact that the ‘unsafe’ package we’ll be using is not covered by the Go 1 compatibility guarantee, so keep that in mind.

In the following code example we obtain the StringHeader of a string, pretend it’s a byte slice, zero it out and set its length to 0:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
    "fmt"
    "reflect"
    "unsafe"
)

func zero(s *string) {
    str := (*reflect.StringHeader)(unsafe.Pointer(s))
    slice := reflect.SliceHeader{
        Data: str.Data,
        Len: str.Len,
        Cap: str.Len,
    }

    copy(*(*[]byte)(unsafe.Pointer(&slice)), make([]byte, slice.Len))
    str.Len = 0
}

func main() {
    password := string([]byte("supersecretpassword"))

    fmt.Printf("value: %q\n", password)
    zero(&password)
    fmt.Printf("value: %q\n", password)
}

You can test this yourself here. Here’s the output:

1
2
3
$ go run main.go
value: "supersecretpassword"
value: ""

It’s important to note that this trick should not be relied upon for security to zero out sensitive memory. Because Go uses a GC, there is no guarantee that the string hasn’t been copied around without giving us a chance to clear it.