Closed Ikke closed 2 months ago
When parsing this snippet:
: "${v////\\/}"
The following AST is generated:
Repl: *syntax.Replace { . All: true . Orig: nil . With: *syntax.Word { . . Parts: []syntax.WordPart (len = 1) { . . . 0: *syntax.Lit { . . . . ValuePos: 1:10 . . . . ValueEnd: 1:14 . . . . Value: "/\\\\/" . . . } . . } . } }
Note that Orig is nil
Orig
Providing the double quoted parameter expression to expand.Document() then results in a segfault, because paramExp passes a nil Orig to Pattern, which then tries to reference fields from it.
expand.Document()
paramExp
Error:
panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x4bcae6] goroutine 1 [running]: mvdan.cc/sh/v3/expand.Pattern(0x0?, 0x0) /home/kevin/go/pkg/mod/mvdan.cc/sh/v3@v3.8.0/expand/expand.go:214 +0x26 mvdan.cc/sh/v3/expand.(*Config).paramExp(0xc00012c3c0, 0xc00007e1e0) /home/kevin/go/pkg/mod/mvdan.cc/sh/v3@v3.8.0/expand/param.go:204 +0x13fa mvdan.cc/sh/v3/expand.(*Config).wordField(0xc00012c3c0, {0xc000016150?, 0x1, 0x0?}, 0x1) /home/kevin/go/pkg/mod/mvdan.cc/sh/v3@v3.8.0/expand/expand.go:544 +0x4dd mvdan.cc/sh/v3/expand.(*Config).wordField(0xc00012c3c0, {0xc000129f10?, 0x1, 0x10?}, 0x1) /home/kevin/go/pkg/mod/mvdan.cc/sh/v3@v3.8.0/expand/expand.go:535 +0x5df mvdan.cc/sh/v3/expand.Document(0x461506?, 0xc000129f20) /home/kevin/go/pkg/mod/mvdan.cc/sh/v3@v3.8.0/expand/expand.go:197 +0x3f main.main() /home/kevin/tmp/test/main.go:13 +0x25c exit status 2
Running this in other shells (bash/ash) works:
$ v=a/b/c $ echo ${v////\\/} a\/b\/c
Thanks for the detailed report!
When parsing this snippet:
The following AST is generated:
Note that
Orig
is nilFull AST
``` *syntax.File { . Name: "examples/expand_replace.sh" . Stmts: []*syntax.Stmt (len = 1) { . . 0: *syntax.Stmt { . . . Comments: []syntax.Comment (len = 0) {} . . . Cmd: *syntax.CallExpr { . . . . Assigns: []*syntax.Assign (len = 0) {} . . . . Args: []*syntax.Word (len = 2) { . . . . . 0: *syntax.Word { . . . . . . Parts: []syntax.WordPart (len = 1) { . . . . . . . 0: *syntax.Lit { . . . . . . . . ValuePos: 1:1 . . . . . . . . ValueEnd: 1:2 . . . . . . . . Value: ":" . . . . . . . } . . . . . . } . . . . . } . . . . . 1: *syntax.Word { . . . . . . Parts: []syntax.WordPart (len = 1) { . . . . . . . 0: *syntax.DblQuoted { . . . . . . . . Left: 1:3 . . . . . . . . Right: 1:15 . . . . . . . . Dollar: false . . . . . . . . Parts: []syntax.WordPart (len = 1) { . . . . . . . . . 0: *syntax.ParamExp { . . . . . . . . . . Dollar: 1:4 . . . . . . . . . . Rbrace: 1:14 . . . . . . . . . . Short: false . . . . . . . . . . Excl: false . . . . . . . . . . Length: false . . . . . . . . . . Width: false . . . . . . . . . . Param: *syntax.Lit { . . . . . . . . . . . ValuePos: 1:6 . . . . . . . . . . . ValueEnd: 1:7 . . . . . . . . . . . Value: "v" . . . . . . . . . . } . . . . . . . . . . Index: nil . . . . . . . . . . Slice: nil . . . . . . . . . . Repl: *syntax.Replace { . . . . . . . . . . . All: true . . . . . . . . . . . Orig: nil . . . . . . . . . . . With: *syntax.Word { . . . . . . . . . . . . Parts: []syntax.WordPart (len = 1) { . . . . . . . . . . . . . 0: *syntax.Lit { . . . . . . . . . . . . . . ValuePos: 1:10 . . . . . . . . . . . . . . ValueEnd: 1:14 . . . . . . . . . . . . . . Value: "/\\\\/" . . . . . . . . . . . . . } . . . . . . . . . . . . } . . . . . . . . . . . } . . . . . . . . . . } . . . . . . . . . . Names: 0x0 . . . . . . . . . . Exp: nil . . . . . . . . . } . . . . . . . . } . . . . . . . } . . . . . . } . . . . . } . . . . } . . . } . . . Position: 1:1 . . . Semicolon: 0:0 . . . Negated: false . . . Background: false . . . Coprocess: false . . . Redirs: []*syntax.Redirect (len = 0) {} . . } . } . Last: []syntax.Comment (len = 0) {} } ```Providing the double quoted parameter expression to
expand.Document()
then results in a segfault, becauseparamExp
passes a nil Orig to Pattern, which then tries to reference fields from it.Reproducer
```go package main import ( "fmt" "mvdan.cc/sh/v3/expand" "mvdan.cc/sh/v3/syntax" ) func main() { expandConfig := expand.Config{} expanded, _ := expand.Document(&expandConfig, &syntax.Word{ Parts: []syntax.WordPart{ &syntax.DblQuoted{ Parts: []syntax.WordPart{ &syntax.ParamExp{ Param: &syntax.Lit{Value: "v"}, Repl: &syntax.Replace{ All: true, With: &syntax.Word{ Parts: []syntax.WordPart{ &syntax.Lit{ Value: "/\\\\/", }, }, }, }, }, }, }, }, }) fmt.Printf("expanded: %#v\n", expanded) } ```Error:
Running this in other shells (bash/ash) works: