Mongodb在反序列化时出现堆栈溢出错误。

huangapple go评论79阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2015年3月6日 23:06:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/28901604.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定