2 minutes
[Go] unsafe.Pointerを使うのをやめた
お世話になっております。
しゃまとんです😊
少し前にmsgpackとmsgpackgenを更新しました。
(個人的に)内部に割と大きめの変更点を入れました。これまでstringのdecodeを行うときにunsafe.Pointerによるキャストを利用していたのですが それをやめて通常のキャストを行うようにしました。
たしかに世の中ではどんな使われ方するかわからないし、少し速度落ちても安全に使えるほうが大事かなーとhttps://t.co/f0ROpA32Qr
— shamaton != nil (@shamaton) August 5, 2021
ことの発端はmsgpackに立ったissueによるものです。
msgpackを作っていた際に、パフォーマンスを意識して作っていたのですがstringに関する処理を早くできないかというところで、
unsafe.Pointerを使ったキャストを使うことにしました。
これは知っていればいいのですが、Playgroundで試してみてわかるようにバイト配列に変更を加えるとstringも変わってしまうのです。
package main
import (
"encoding/hex"
"fmt"
"os"
"github.com/shamaton/msgpack"
)
func main() {
type Struct struct {
String string
}
v := Struct{String: "msgpack"}
d, err := msgpack.Marshal(v)
if err != nil {
panic(err)
}
r := Struct{}
err = msgpack.Unmarshal(d, &r)
if err != nil {
panic(err)
}
os.Stderr.WriteString(hex.Dump(d))
fmt.Println(r)
d[len(d)-4] = '!'
fmt.Println(r)
}
結果がこうなります。
00000000 81 a6 53 74 72 69 6e 67 a7 6d 73 67 70 61 63 6b |..String.msgpack|
{msgpack}
{msg!ack}
これって、結構危ない可能性あるなぁと。 基本いじることはないんだけど、いじらない可能性がないし、利用者から見たときにわけのわからない挙動になるかもしれないと。 パフォーマンスは大事なんだけど、安心して使えるのはもっと大事だよなぁということで変更することにしました。
でも変更するだけなのも尺だったので、少し改善もしました。 mapフォーマットを使った際のパフォーマンスの影響が大きかったので、そこに手をいれて遅くなるのを軽減しました。頭をひねれば出るもんだ。
そしてunsafeを使うなら、どこかにパッケージ名とかに明記しておくべきだなーと思いました。
ということでどちらもパッケージも安心してお使いいただけるはず!ということで引き続きよろしくお願いいたします🙇🙇🙇
以上です〜👋
(まだmsgpackgenはmsgpackの中では一番やで) 🚀