When encoding a byte array into a base64 byte array, the below code produces a runtime index out of range
error. How can this be resolved?
package main
import (
"fmt"
"encoding/base64"
)
func main() {
data := []byte("string of data")
var encodedData []byte
base64.StdEncoding.Encode(encodedData, data)
fmt.Println(encodedData)
}
The error is:
panic: runtime error: index out of range
goroutine 1 [running]:
encoding/base64.(*Encoding).Encode(0xc420056000, 0x0, 0x0, 0x0, 0xc42003bf30, 0xe, 0x20)
/usr/lib/go/src/encoding/base64/base64.go:113 +0x27b
main.main()
/home/martin/a.go:11 +0x9b
exit status 2
shell returned 1
If we look at /usr/lib/go/src/encoding/base64/base64.go
line 113, we see (abbreviated):
n := (len(src) / 3) * 3
for si < n {
// [..]
dst[di+0] = enc.encode[val>>18&0x3F]
dst[di+0] = enc.encode[val>>18&0x3F]
dst[di+1] = enc.encode[val>>12&0x3F]
// [..]
}
In other words, this function directly sets the index of dst
. The length of var encodedData []byte
is zero, so you get the index out of range
error.
One way to fix it would be to change the line to:
encodedData := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
Which will make an array of the size in the second argument. Base64 encoded data is larger than the input, hence the base64.StdEncoding.EncodedLen()
.
However, this is hardly the best way to fix it. The documentation mentions:
Encode is not appropriate for use on individual blocks of a large data stream. Use NewEncoder() instead.
Rewriting the code to NewEncoder()
looks like:
func main() {
data := []byte("string of data")
encodedData := &bytes.Buffer{}
encoder := base64.NewEncoder(base64.StdEncoding, encodedData)
defer encoder.Close()
encoder.Write(data)
fmt.Println(encodedData)
}
There also some other useful functions, such as EncodeToString()
which make the above a bit shorter and more convenient: encodedData := base64.StdEncoding.EncodeToString(data)
.
Allocate space for the output. For example,
package main
import (
"encoding/base64"
"fmt"
)
func main() {
data := []byte("string of data")
encodedData := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
base64.StdEncoding.Encode(encodedData, data)
fmt.Println(encodedData)
}
Output:
[99 51 82 121 97 87 53 110 73 71 57 109 73 71 82 104 100 71 69 61]
var encodedData []byte
is zero bytes. Therefore, index out of range
Because Encode expects the dst
slice to be allocated to the correct length.
Encode encodes src using the encoding enc, writing EncodedLen(len(src)) bytes to dst.