Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow recursive references #215

Open
purpleidea opened this issue Oct 22, 2016 · 0 comments
Open

Allow recursive references #215

purpleidea opened this issue Oct 22, 2016 · 0 comments

Comments

@purpleidea
Copy link

YAML has this excellent anchor/reference syntax to identify two parts of the YAML syntax that refer to the same element. This maps perfectly to a language that has pointers! Unfortunately there is a bug and the values are copied over instead of copying the pointer value! This is the correct behaviour if we're using a string, but not when it's a *string.

Here is some reproducing code:

package main

import (
    "errors"
    "log"

    "gopkg.in/yaml.v2"
)

type NoopRes struct {
    Path    string  `yaml:"path"`
    Content *string `yaml:"content"` // XXX *string
}

type GraphConfig struct {
    Graph     string `yaml:"graph"`
    Resources struct {
        Noop []*NoopRes `yaml:"noop"`
    } `yaml:"resources"`
    Comment string `yaml:"comment"`
}

func (c *GraphConfig) Parse(data []byte) error {
    if err := yaml.Unmarshal(data, c); err != nil {
        return err
    }
    if c.Graph == "" {
        return errors.New("Graph config: invalid `graph`")
    }
    return nil
}

func main() {
    log.Printf("Hello!")
    str :=
        `

---
graph: mygraph
comment: my comment
resources:
  noop:
  - name: noop1
    path: foo
    content: &ptr "hello"
  - name: noop2
    path: bar
    content: *ptr
  - name: noop3
    path: baz
    content: *ptr
  unused:
  - foo: bar
`

    data := []byte(str)
    var config GraphConfig
    if err := config.Parse(data); err != nil {
        log.Printf("Config: Error: ParseConfigFromFile: Parse: %v", err)
        return
    }

    log.Printf("Success!")
    log.Printf("%+v", &config)
    log.Printf("%+v", config.Resources.Noop[0].Content)
    if x := config.Resources.Noop[0].Content; x != nil {
        log.Printf("inside: %+v", *config.Resources.Noop[0].Content)
    }

    log.Printf("================")

    log.Printf("%+v", config.Resources.Noop[1].Content)
    if x := config.Resources.Noop[1].Content; x != nil {
        log.Printf("inside: %+v", *x)
    } else {
        log.Printf("nothing inside!")
    }

    if config.Resources.Noop[0].Content != config.Resources.Noop[1].Content {
        log.Printf("different pointers! :(")
    } else {
        log.Printf("same pointers! :)")
    }

    log.Printf("================")

    log.Printf("%+v", config.Resources.Noop[2].Content)
    if x := config.Resources.Noop[2].Content; x != nil {
        log.Printf("inside: %+v", *x)
    } else {
        log.Printf("nothing inside!")
    }

    if config.Resources.Noop[1].Content != config.Resources.Noop[2].Content {
        log.Printf("different pointers! :(")
    } else {
        log.Printf("same pointers! :)")
    }
}

Sample output is:

$ go run yamlptrtest4.go
2016/10/22 13:16:46 Hello!
2016/10/22 13:16:46 Success!
2016/10/22 13:16:46 &{Graph:mygraph Resources:{Noop:[0xc82000ea80 0xc82000eaa0 0xc82000eac0]} Comment:my comment}
2016/10/22 13:16:46 0xc82000ae30
2016/10/22 13:16:46 inside: hello
2016/10/22 13:16:46 ================
2016/10/22 13:16:46 0xc82000aeb0
2016/10/22 13:16:46 inside: hello
2016/10/22 13:16:46 different pointers! :(
2016/10/22 13:16:46 ================
2016/10/22 13:16:46 0xc82000af30
2016/10/22 13:16:46 inside: hello
2016/10/22 13:16:46 different pointers! :(

This is a pretty crucial feature. I don't know the go-yaml code base, but if someone could point me in the right direction, I would like to try to patch this. Obviously, I'd prefer to have help though. :)

Thanks!

vinzenz pushed a commit to vinzenz/yaml that referenced this issue Nov 1, 2016
Signed-off-by: Vinzenz Feenstra <evilissmo@redhat.com>
vinzenz pushed a commit to vinzenz/yaml that referenced this issue Nov 2, 2016
Signed-off-by: Vinzenz Feenstra <evilissmo@redhat.com>
vinzenz pushed a commit to vinzenz/yaml that referenced this issue Nov 2, 2016
Signed-off-by: Vinzenz Feenstra <evilissmo@redhat.com>
vinzenz pushed a commit to vinzenz/yaml that referenced this issue Mar 27, 2017
Signed-off-by: Vinzenz Feenstra <evilissmo@redhat.com>
vinzenz pushed a commit to vinzenz/yaml that referenced this issue Sep 20, 2017
Signed-off-by: Vinzenz Feenstra <evilissmo@redhat.com>
@niemeyer niemeyer changed the title [BUG] anchors don't decode to the same pointer Allow recursive references Mar 26, 2018
laszlocph added a commit to laszlocph/yaml that referenced this issue Nov 14, 2019
* v/fix-for-issue-91: (40 commits)
  Add test cases from go-yaml#184
  Fix for issue go-yaml#91
  Fixes go-yaml#214 - New option to allow setting strict boolean mode
  Fix for issue go-yaml#144
  Always use the pointer mechanism, but only allow recursion per option
  Applied API changes as suggested in another PR and fixed outstanding problems
  Removed introduced shadowing bug
  Make aliases share the same memory address as the anchor ( go-yaml#215 )
  Replace LICENSE text with actual license (go-yaml#274)
  Make tag scanning code slightly cleaner.
  move embedded struct example into godoc
  Add UnmarshalStrict returning error if yaml has fields that do not exist in structure
  correct misspell on yamlh.go
  fix misspell on emmiterc.go
  Remove unreachable code to fix go vet (go-yaml#249)
  Fix dead URL for yaml specification (go-yaml#240)
  Tighten restrictions on float decoding (go-yaml#171)
  Fix decode test for Go 1.8 (go-yaml#217)
  Fix unmarshaler handling of empty strings.
  new license in the README file (go-yaml#189)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant