Skip to content

Commit 64ab8c4

Browse files
committed
Bot: Fixed trailing backticks causing out of bound panic
1 parent 5acf9f3 commit 64ab8c4

File tree

2 files changed

+45
-23
lines changed

2 files changed

+45
-23
lines changed

bot/extras/shellwords/shellwords.go

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,45 @@ import (
55
"strings"
66
)
77

8+
// WordOffset is the offset from the position cursor to print on the error.
9+
const WordOffset = 7
10+
11+
var escaper = strings.NewReplacer(
12+
"`", "\\`",
13+
"@", "\\@",
14+
"\\", "\\\\",
15+
)
16+
817
type ErrParse struct {
918
Position int
10-
ErrorStart,
11-
ErrorPart,
12-
ErrorEnd string
19+
Words string // joined
1320
}
1421

1522
func (e ErrParse) Error() string {
16-
return fmt.Sprintf(
17-
"Unexpected quote or escape: %s__%s__%s",
18-
e.ErrorStart, e.ErrorPart, e.ErrorEnd,
23+
// Magic number 5.
24+
var a = max(0, e.Position-WordOffset)
25+
var b = min(len(e.Words), e.Position+WordOffset)
26+
var word = e.Words[a:b]
27+
var uidx = e.Position - a
28+
29+
errstr := strings.Builder{}
30+
errstr.WriteString("Unexpected quote or escape")
31+
32+
// Do a bound check.
33+
if uidx+1 > len(word) {
34+
// Invalid.
35+
errstr.WriteString(".")
36+
return errstr.String()
37+
}
38+
39+
// Write the pre-underline part.
40+
fmt.Fprintf(
41+
&errstr, ": %s__%s__",
42+
escaper.Replace(word[:uidx]),
43+
escaper.Replace(string(word[uidx:])),
1944
)
45+
46+
return errstr.String()
2047
}
2148

2249
// Parse parses the given text to a slice of words.
@@ -76,11 +103,6 @@ func Parse(line string) ([]string, error) {
76103
got = true
77104
}
78105

79-
// // If this is a backtick, then write it.
80-
// if r == '`' {
81-
// buf.WriteByte('`')
82-
// }
83-
84106
singleQuoted = !singleQuoted
85107
continue
86108
}
@@ -95,19 +117,9 @@ func Parse(line string) ([]string, error) {
95117
}
96118

97119
if escaped || singleQuoted || doubleQuoted {
98-
// the number of characters to highlight
99-
var (
100-
pos = cursor + 5
101-
start = string(runes[max(cursor-100, 0) : pos-1])
102-
end = string(runes[pos+1 : min(cursor+100, len(runes))])
103-
part = string(runes[max(pos-1, 0):min(len(runes), pos+2)])
104-
)
105-
106120
return args, &ErrParse{
107-
Position: cursor,
108-
ErrorStart: start,
109-
ErrorPart: part,
110-
ErrorEnd: end,
121+
Position: cursor + buf.Len(),
122+
Words: strings.Join(args, " "),
111123
}
112124
}
113125

bot/extras/shellwords/shellwords_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ func TestParse(t *testing.T) {
3838
[]string{"how", "about", "a", "go\npackage main\n", "go", "code?"},
3939
false,
4040
},
41+
{
42+
"this should not crash `",
43+
[]string{"this", "should", "not", "crash"},
44+
true,
45+
},
46+
{
47+
"this should not crash '",
48+
[]string{"this", "should", "not", "crash"},
49+
true,
50+
},
4151
}
4252

4353
for _, test := range tests {

0 commit comments

Comments
 (0)