gounmarshallingbolt

Getting unexpected fault address error when unmarshalling json from bolt database in external function


I am currently working on storing/retrieving characters from a Bolt Database in Go.
I wrote this function here to retrieve every character stored and it worked fine.

//this works fine
func GetAllCharacters() []Character {
    var charList []Character
    var char Character

    db, err := bolt.Open("./savedata/database.db", 0600, nil)
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    err = db.View(func(tx *bolt.Tx) error {
        c := tx.Bucket([]byte("DB")).Bucket([]byte("Characters")).Cursor()

        for k, v := c.First(); k != nil; k, v = c.Next() {
            err := json.Unmarshal(v, &char)
            if err != nil {
                log.Fatal(err)
            }
            charList = append(charList, char)
        }

        return nil
    })

    if err != nil {
        log.Fatal(err)
    }

    return charList
}

Then I wanted to clean up my code a bit and moved a part of the function to a different file, like this:

utils file:

package utils

func GetAllCharactersFromDB() [][]byte {
    var charList [][]byte

    db, err := bolt.Open("./savedata/database.db", 0600, nil)
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    err = db.View(func(tx *bolt.Tx) error {
        c := tx.Bucket([]byte("DB")).Bucket([]byte("Characters")).Cursor()

        for k, v := c.First(); k != nil; k, v = c.Next() {
            charList = append(charList, v)
        }

        return nil
    })

    if err != nil {
        log.Fatal(err)
    }

    return charList
}

main file:

func GetAllCharacters() []Character {
    var charList []Character
    var char Character

    allChars := utils.GetAllCharactersFromDB()

    for _, v := range allChars {
        err := json.Unmarshal(v, &char)
        if err != nil {
            log.Fatal(err)
        }
        charList = append(charList, char)
    }

    return charList
}

And now when I try to run this code, I get a this cryptic error message that I cannot really decrypt:

unexpected fault address 0x20d5607405f
fatal error: fault
[signal 0xc0000005 code=0x0 addr=0x20d5607405f pc=0xa4ba35]

goroutine 1 [running]:
runtime.throw({0xa93ef9, 0x20d30d50108})
        C:/Program Files/Go/src/runtime/panic.go:1198 +0x76 fp=0xc0001096a0 sp=0xc000109670 pc=0x9b4b16
runtime.sigpanic()
        C:/Program Files/Go/src/runtime/signal_windows.go:260 +0x10c fp=0xc0001096e8 sp=0xc0001096a0 pc=0x9c606c
encoding/json.checkValid({0x20d5607405f, 0x27a, 0x1}, 0xc00011c0b8)
        C:/Program Files/Go/src/encoding/json/scanner.go:32 +0xb5 fp=0xc000109710 sp=0xc0001096e8 pc=0xa4ba35
encoding/json.Unmarshal({0x20d5607405f, 0xac2ec0, 0xc000006010}, {0xa8b400, 0xc000118120})
        C:/Program Files/Go/src/encoding/json/decode.go:101 +0x5a fp=0xc000109758 sp=0xc000109710 pc=0xa3cc9a
github.com/my_name/gotestgame/game.GetAllCharacters()
        C:/Users/my_name/Documents/Golang/simplegame/game/characters.go:164 +0xcc fp=0xc000109808 sp=0xc000109758 pc=0xa63b4c
github.com/my_name/gotestgame/game.Leaderboard()
        C:/Users/my_name/Documents/Golang/simplegame/game/level.go:125 +0xab fp=0xc000109d20 sp=0xc000109808 pc=0xa6782b
github.com/my_name/gotestgame/game.MainMenu()
        C:/Users/my_name/Documents/Golang/simplegame/game/menu.go:58 +0x3ba fp=0xc000109f60 sp=0xc000109d20 pc=0xa699da
main.main()
        C:/Users/my_name/Documents/Golang/simplegame/main.go:16 +0x4a fp=0xc000109f80 sp=0xc000109f60 pc=0xa6d4ea
runtime.main()
        C:/Program Files/Go/src/runtime/proc.go:255 +0x217 fp=0xc000109fe0 sp=0xc000109f80 pc=0x9b70d7
runtime.goexit()
        C:/Program Files/Go/src/runtime/asm_amd64.s:1581 +0x1 fp=0xc000109fe8 sp=0xc000109fe0 pc=0x9df7e1
exit status 2

Can anyone tell me why the new approach does not work? And what I could do to make it work? I thought the json.Unmarshal would be unmarshalling the same []byte in both cases, or am I wrong there? When I print out the content of string(v) in the GetAllCharactersFromDB() function I get a readable json string. It is not very urgent as the first code snippet works, but it bothers me that I cannot figure out why the second approach does not work. Sorry if this is a stupid question, I am fairly new to Go.

EDIT:

In response to the comment, heres how a Character looks:

type Character struct {
    Name         string `json:"name"`
    Hardcore     bool   `json:"hardcore"`
    Default      bool   `json:"default"`
    Level        int    `json:"level"`
    XP           int    `json:"xp"`
    Class        string `json:"class"`
    Max_HP       int    `json:"max_hp"`
    Current_HP   int    `json:"current_hp"`
    Strength     int    `json:"str"`
    Dexterity    int    `json:"dex"`
    Intelligence int    `json:"int"`
    Gold         int    `json:"gold"`
    Weapon       Weapon `json:"weapon"`
    Items        []Item `json:"items"`
}

And here's how the data stored looks:

{"name":"Test1","hardcore":true,"default":true,"level":1,"xp":1,"class":"Barbarian","max_hp":150,"current_hp":150,"str":30,"dex":15,"int":5,"gold":0,"weapon":{"Name":"Rusty Club","Description":"Starter Weapon for the Barbarian.","Rarity":{"Common":1,"Uncommon":0,"Rare":0,"Epic":0,"Legendary":0},"LowAttack":15,"HighAttack":40,"AttackSpeed":1.2,"CritChance":5,"Accuracy":95,"Range":10,"ReqStr":15,"ReqDex":5,"ReqInt":0,"BuyPrice":30,"SellPrice":1},"items":[{"Name":"Small Healing Potion","Description":"Heals you for 20 HP","Tag":"Heal","Rarity":{"Common":1,"Uncommon":0,"Rare":0,"Epic":0,"Legendary":0},"BuyPrice":25,"SellPrice":1}]}

Solution

  • Please try to replace the following line:

    charList = append(charList, v)
    

    with

    vc := make([]byte, len(v))
    copy(vc,v)
    charList = append(charList, vc)