Fix isAllowed of escapeStreamer (#22814) (#22837)

Backport #22814.

The use of `sort.Search` is wrong: The slice should be sorted, and
`return >= 0` doen't mean it exists, see the
[manual](https://pkg.go.dev/sort#Search).

Could be fixed like this if we really need it:

```diff
diff --git a/modules/charset/escape_stream.go b/modules/charset/escape_stream.go
index 823b63513..fcf1ffbc1 100644
--- a/modules/charset/escape_stream.go
+++ b/modules/charset/escape_stream.go
@@ -20,6 +20,9 @@ import (
 var defaultWordRegexp = regexp.MustCompile(`(-?\d*\.\d\w*)|([^\` + "`" + `\~\!\@\#\$\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s\x00-\x1f]+)`)

 func NewEscapeStreamer(locale translation.Locale, next HTMLStreamer, allowed ...rune) HTMLStreamer {
+       sort.Slice(allowed, func(i, j int) bool {
+               return allowed[i] < allowed[j]
+       })
        return &escapeStreamer{
                escaped:                 &EscapeStatus{},
                PassthroughHTMLStreamer: *NewPassthroughStreamer(next),
@@ -284,14 +287,8 @@ func (e *escapeStreamer) runeTypes(runes ...rune) (types []runeType, confusables
 }

 func (e *escapeStreamer) isAllowed(r rune) bool {
-       if len(e.allowed) == 0 {
-               return false
-       }
-       if len(e.allowed) == 1 {
-               return e.allowed[0] == r
-       }
-
-       return sort.Search(len(e.allowed), func(i int) bool {
+       i := sort.Search(len(e.allowed), func(i int) bool {
                return e.allowed[i] >= r
-       }) >= 0
+       })
+       return i < len(e.allowed) && e.allowed[i] == r
 }
```

But I don't think so, a map is better to do it.
This commit is contained in:
Jason Song 2023-02-10 11:36:58 +08:00 committed by GitHub
parent 68b908d92a
commit 77c89572e9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -7,7 +7,6 @@ package charset
import ( import (
"fmt" "fmt"
"regexp" "regexp"
"sort"
"strings" "strings"
"unicode" "unicode"
"unicode/utf8" "unicode/utf8"
@ -21,12 +20,16 @@ import (
var defaultWordRegexp = regexp.MustCompile(`(-?\d*\.\d\w*)|([^\` + "`" + `\~\!\@\#\$\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s\x00-\x1f]+)`) var defaultWordRegexp = regexp.MustCompile(`(-?\d*\.\d\w*)|([^\` + "`" + `\~\!\@\#\$\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s\x00-\x1f]+)`)
func NewEscapeStreamer(locale translation.Locale, next HTMLStreamer, allowed ...rune) HTMLStreamer { func NewEscapeStreamer(locale translation.Locale, next HTMLStreamer, allowed ...rune) HTMLStreamer {
allowedM := make(map[rune]bool, len(allowed))
for _, v := range allowed {
allowedM[v] = true
}
return &escapeStreamer{ return &escapeStreamer{
escaped: &EscapeStatus{}, escaped: &EscapeStatus{},
PassthroughHTMLStreamer: *NewPassthroughStreamer(next), PassthroughHTMLStreamer: *NewPassthroughStreamer(next),
locale: locale, locale: locale,
ambiguousTables: AmbiguousTablesForLocale(locale), ambiguousTables: AmbiguousTablesForLocale(locale),
allowed: allowed, allowed: allowedM,
} }
} }
@ -35,7 +38,7 @@ type escapeStreamer struct {
escaped *EscapeStatus escaped *EscapeStatus
locale translation.Locale locale translation.Locale
ambiguousTables []*AmbiguousTable ambiguousTables []*AmbiguousTable
allowed []rune allowed map[rune]bool
} }
func (e *escapeStreamer) EscapeStatus() *EscapeStatus { func (e *escapeStreamer) EscapeStatus() *EscapeStatus {
@ -257,7 +260,7 @@ func (e *escapeStreamer) runeTypes(runes ...rune) (types []runeType, confusables
runeCounts.numBrokenRunes++ runeCounts.numBrokenRunes++
case r == ' ' || r == '\t' || r == '\n': case r == ' ' || r == '\t' || r == '\n':
runeCounts.numBasicRunes++ runeCounts.numBasicRunes++
case e.isAllowed(r): case e.allowed[r]:
if r > 0x7e || r < 0x20 { if r > 0x7e || r < 0x20 {
types[i] = nonBasicASCIIRuneType types[i] = nonBasicASCIIRuneType
runeCounts.numNonConfusingNonBasicRunes++ runeCounts.numNonConfusingNonBasicRunes++
@ -283,16 +286,3 @@ func (e *escapeStreamer) runeTypes(runes ...rune) (types []runeType, confusables
} }
return types, confusables, runeCounts return types, confusables, runeCounts
} }
func (e *escapeStreamer) isAllowed(r rune) bool {
if len(e.allowed) == 0 {
return false
}
if len(e.allowed) == 1 {
return e.allowed[0] == r
}
return sort.Search(len(e.allowed), func(i int) bool {
return e.allowed[i] >= r
}) >= 0
}