英文:
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("未提供连接字符串")
os.Exit(1)
}
sess, err := mgo.Dial(uri)
if err != nil {
fmt.Printf("无法连接到MongoDB,错误:%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("无法插入文档:%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("查找文档时出错:%v\n", err)
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
我做错了什么?
英文:
I want to use mongodb in golang and wrote an sample application:
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)
}
}
Insert into mongodb works like a charm, but to unmarshal back to reference I've got following panic:
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
What am I doing wrong?
答案1
得分: 4
这个逻辑引入了无限递归:
func (rcv *Session) SetBSON(raw bson.Raw) error {
return raw.Unmarshal(rcv)
}
Session
实现了 Setter 接口,这意味着它的反序列化是通过它的 SetBSON
方法进行的,而该方法通过调用 bson
包的 Unmarshal
方法来实现,而该方法又会调用它自己的 SetBSON
方法。这个过程永远不会结束,直到栈空间耗尽。
解决方案当然是不要通过再次调用 bson
包来实现 Session
的自定义反序列化。
英文:
This logic introduces an infinite recursion:
func (rcv *Session) SetBSON(raw bson.Raw) error {
return raw.Unmarshal(rcv)
}
Session
implements the Setter interface, which means its unmarshaling happens via its SetBSON
method, which is implemented by asking the bson
package to unmarshal itself, which will do that by calling its SetBSON
method. This never ends, until the stack space is over.
The solution is, of course, to not implement custom unmarshaling of Session
by just asking the bson
package to unmarshal it again.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论