1
2
3
4
5
6
7 package work
8
9 import (
10 "bytes"
11 "internal/testenv"
12 "strings"
13 "testing"
14 "unicode"
15 )
16
17 func FuzzSplitPkgConfigOutput(f *testing.F) {
18 testenv.MustHaveExecPath(f, "/bin/sh")
19
20 f.Add([]byte(`$FOO`))
21 f.Add([]byte(`\$FOO`))
22 f.Add([]byte(`${FOO}`))
23 f.Add([]byte(`\${FOO}`))
24 f.Add([]byte(`$(/bin/false)`))
25 f.Add([]byte(`\$(/bin/false)`))
26 f.Add([]byte(`$((0))`))
27 f.Add([]byte(`\$((0))`))
28 f.Add([]byte(`unescaped space`))
29 f.Add([]byte(`escaped\ space`))
30 f.Add([]byte(`"unterminated quote`))
31 f.Add([]byte(`'unterminated quote`))
32 f.Add([]byte(`unterminated escape\`))
33 f.Add([]byte(`"quote with unterminated escape\`))
34 f.Add([]byte(`'quoted "double quotes"'`))
35 f.Add([]byte(`"quoted 'single quotes'"`))
36 f.Add([]byte(`"\$0"`))
37 f.Add([]byte(`"\$\0"`))
38 f.Add([]byte(`"\$"`))
39 f.Add([]byte(`"\$ "`))
40
41
42
43
44 f.Add([]byte(`-r:foo -L/usr/white\ space/lib -lfoo\ bar -lbar\ baz`))
45 f.Add([]byte(`-lextra\ fun\ arg\\`))
46 f.Add([]byte("\textra whitespace\r"))
47 f.Add([]byte(" \r "))
48 f.Add([]byte(`"-r:foo" "-L/usr/white space/lib" "-lfoo bar" "-lbar baz"`))
49 f.Add([]byte(`"-lextra fun arg\\"`))
50 f.Add([]byte(`" \r\n\ "`))
51 f.Add([]byte(`""`))
52 f.Add([]byte(``))
53 f.Add([]byte(`"\\"`))
54 f.Add([]byte(`"\x"`))
55 f.Add([]byte(`"\\x"`))
56 f.Add([]byte(`'\\'`))
57 f.Add([]byte(`'\x'`))
58 f.Add([]byte(`"\\x"`))
59 f.Add([]byte("\\\n"))
60 f.Add([]byte(`-fPIC -I/test/include/foo -DQUOTED='"/test/share/doc"'`))
61 f.Add([]byte(`-fPIC -I/test/include/foo -DQUOTED="/test/share/doc"`))
62 f.Add([]byte(`-fPIC -I/test/include/foo -DQUOTED=\"/test/share/doc\"`))
63 f.Add([]byte(`-fPIC -I/test/include/foo -DQUOTED='/test/share/doc'`))
64 f.Add([]byte(`-DQUOTED='/te\st/share/d\oc'`))
65 f.Add([]byte(`-Dhello=10 -Dworld=+32 -DDEFINED_FROM_PKG_CONFIG=hello\ world`))
66 f.Add([]byte(`"broken\"" \\\a "a"`))
67
68
69 f.Add([]byte(`" \r\n `))
70 f.Add([]byte(`"-r:foo" "-L/usr/white space/lib "-lfoo bar" "-lbar baz"`))
71 f.Add([]byte(`"-lextra fun arg\\`))
72 f.Add([]byte(`broken flag\`))
73 f.Add([]byte(`extra broken flag \`))
74 f.Add([]byte(`\`))
75 f.Add([]byte(`"broken\"" "extra" \`))
76
77 f.Fuzz(func(t *testing.T, b []byte) {
78 t.Parallel()
79
80 if bytes.ContainsAny(b, "*?[#~%\x00{}!") {
81 t.Skipf("skipping %#q: contains a sometimes-quoted character", b)
82 }
83
84
85
86 for _, c := range b {
87 if c > unicode.MaxASCII {
88 t.Skipf("skipping %#q: contains a non-ASCII character %q", b, c)
89 }
90 if !unicode.IsGraphic(rune(c)) && !unicode.IsSpace(rune(c)) {
91 t.Skipf("skipping %#q: contains non-graphic character %q", b, c)
92 }
93 }
94
95 args, err := splitPkgConfigOutput(b)
96 if err != nil {
97
98
99
100 t.Logf("%#q: %v", b, err)
101 return
102 }
103 t.Logf("splitPkgConfigOutput(%#q) = %#q", b, args)
104 if len(args) == 0 {
105 t.Skipf("skipping %#q: contains no arguments", b)
106 }
107
108 var buf strings.Builder
109 for _, arg := range args {
110 buf.WriteString(arg)
111 buf.WriteString("\n")
112 }
113 wantOut := buf.String()
114
115 if strings.Count(wantOut, "\n") != len(args)+bytes.Count(b, []byte("\n")) {
116
117
118 t.Skipf("skipping %#q: contains a bare newline", b)
119 }
120
121
122
123
124
125 cmd := testenv.Command(t, "/bin/sh", "-c", "printf '%s\n' "+string(b))
126 cmd.Env = append(cmd.Environ(), "LC_ALL=POSIX", "POSIXLY_CORRECT=1")
127 cmd.Stderr = new(strings.Builder)
128 out, err := cmd.Output()
129 if err != nil {
130 t.Fatalf("%#q: %v\n%s", cmd.Args, err, cmd.Stderr)
131 }
132
133 if string(out) != wantOut {
134 t.Logf("%#q:\n%#q", cmd.Args, out)
135 t.Logf("want:\n%#q", wantOut)
136 t.Errorf("parsed args do not match")
137 }
138 })
139 }
140
View as plain text