Mongodb 通过解组得到堆栈溢出
Mongodb got stack overflow by unmarshal
我想在golang中使用mongodb,写了一个示例应用:
package main
import (
"fmt"
"labix.org/v2/mgo"
"labix.org/v2/mgo/bson"
"os"
)
type Session struct {
Id bson.ObjectId `bson:"_id"`
Data map[string]interface{} `bson:"data"`
}
func (rcv *Session) SetBSON(raw bson.Raw) error {
return raw.Unmarshal(rcv)
}
type Authen struct {
Name string `bson:"name"`
Email string `bson:"email"`
}
func main() {
uri := "mongodb://localhost/"
if uri == "" {
fmt.Println("no connection string provided")
os.Exit(1)
}
sess, err := mgo.Dial(uri)
if err != nil {
fmt.Printf("Can't connect to mongo, go error %v\n", err)
os.Exit(1)
}
defer sess.Close()
sess.SetSafe(&mgo.Safe{})
collection := sess.DB("test").C("sess")
a := &Authen{Name: "Cormier", Email: "cormier@example.com"}
s := &Session{}
s.Id = bson.NewObjectId()
s.Data = make(map[string]interface{})
s.Data["logged"] = a
err = collection.Insert(s)
if err != nil {
fmt.Printf("Can't insert document: %v\n", err)
os.Exit(1)
}
c := &Session{}
c.Id = bson.NewObjectId()
c.Data = make(map[string]interface{})
err = sess.DB("test").C("sess").Find(bson.M{}).One(c)
if err != nil {
fmt.Printf("got an error finding a doc %v\n")
os.Exit(1)
}
}
插入 mongodb 就像一个魅力,但解编回引用我有以下恐慌:
runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow
runtime stack:
runtime.throw(0x6d84d9)
c:/go/src/runtime/panic.go:491 +0xad
runtime.newstack()
c:/go/src/runtime/stack.c:784 +0x5ef
runtime.morestack()
c:/go/src/runtime/asm_amd64.s:324 +0x86
我做错了什么?
这个逻辑引入了无限递归:
func (rcv *Session) SetBSON(raw bson.Raw) error {
return raw.Unmarshal(rcv)
}
Session
实现了 Setter 接口,这意味着它的解组是通过它的 SetBSON
方法发生的,该方法是通过要求 bson
包解组自身来实现的,这将通过调用它的 SetBSON
方法来做到这一点。这永远不会结束,直到堆栈 space 结束。
当然,解决方案是不通过仅要求 bson
包再次解组来实现 Session
的自定义解组。
我想在golang中使用mongodb,写了一个示例应用:
package main
import (
"fmt"
"labix.org/v2/mgo"
"labix.org/v2/mgo/bson"
"os"
)
type Session struct {
Id bson.ObjectId `bson:"_id"`
Data map[string]interface{} `bson:"data"`
}
func (rcv *Session) SetBSON(raw bson.Raw) error {
return raw.Unmarshal(rcv)
}
type Authen struct {
Name string `bson:"name"`
Email string `bson:"email"`
}
func main() {
uri := "mongodb://localhost/"
if uri == "" {
fmt.Println("no connection string provided")
os.Exit(1)
}
sess, err := mgo.Dial(uri)
if err != nil {
fmt.Printf("Can't connect to mongo, go error %v\n", err)
os.Exit(1)
}
defer sess.Close()
sess.SetSafe(&mgo.Safe{})
collection := sess.DB("test").C("sess")
a := &Authen{Name: "Cormier", Email: "cormier@example.com"}
s := &Session{}
s.Id = bson.NewObjectId()
s.Data = make(map[string]interface{})
s.Data["logged"] = a
err = collection.Insert(s)
if err != nil {
fmt.Printf("Can't insert document: %v\n", err)
os.Exit(1)
}
c := &Session{}
c.Id = bson.NewObjectId()
c.Data = make(map[string]interface{})
err = sess.DB("test").C("sess").Find(bson.M{}).One(c)
if err != nil {
fmt.Printf("got an error finding a doc %v\n")
os.Exit(1)
}
}
插入 mongodb 就像一个魅力,但解编回引用我有以下恐慌:
runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow
runtime stack:
runtime.throw(0x6d84d9)
c:/go/src/runtime/panic.go:491 +0xad
runtime.newstack()
c:/go/src/runtime/stack.c:784 +0x5ef
runtime.morestack()
c:/go/src/runtime/asm_amd64.s:324 +0x86
我做错了什么?
这个逻辑引入了无限递归:
func (rcv *Session) SetBSON(raw bson.Raw) error {
return raw.Unmarshal(rcv)
}
Session
实现了 Setter 接口,这意味着它的解组是通过它的 SetBSON
方法发生的,该方法是通过要求 bson
包解组自身来实现的,这将通过调用它的 SetBSON
方法来做到这一点。这永远不会结束,直到堆栈 space 结束。
当然,解决方案是不通过仅要求 bson
包再次解组来实现 Session
的自定义解组。