From c0a69565bf0c426df8c96fd435607719ed891f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joan=20L=C3=B3pez=20de=20la=20Franca=20Beltran?= Date: Thu, 29 Aug 2024 10:58:06 +0200 Subject: [PATCH] Update Sobek: numeric literal separators --- go.mod | 2 +- go.sum | 2 + .../grafana/sobek/builtin_regexp.go | 4 +- .../github.com/grafana/sobek/parser/lexer.go | 20 +++--- .../github.com/grafana/sobek/parser/regexp.go | 17 +++-- vendor/github.com/grafana/sobek/regexp.go | 7 +- .../github.com/grafana/sobek/string_ascii.go | 69 ++++++++++++------- vendor/modules.txt | 2 +- 8 files changed, 78 insertions(+), 45 deletions(-) diff --git a/go.mod b/go.mod index d7acc2227b3b..dfd499de8dea 100644 --- a/go.mod +++ b/go.mod @@ -77,7 +77,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/google/pprof v0.0.0-20230728192033-2ba5b33183c6 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/grafana/sobek v0.0.0-20240823144814-3c582bfdac82 + github.com/grafana/sobek v0.0.0-20240829081756-447e8c611945 github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect diff --git a/go.sum b/go.sum index e81f55f25036..b0bae07ec1ba 100644 --- a/go.sum +++ b/go.sum @@ -91,6 +91,8 @@ github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/ github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/grafana/sobek v0.0.0-20240823144814-3c582bfdac82 h1:bOg9X3uXuOSjQmIhxefNpClq0pA8C4T+bzHpE6DuaOk= github.com/grafana/sobek v0.0.0-20240823144814-3c582bfdac82/go.mod h1:FmcutBFPLiGgroH42I4/HBahv7GxVjODcVWFTw1ISes= +github.com/grafana/sobek v0.0.0-20240829081756-447e8c611945 h1:rxyoc2Ee/iKcm5EYNU/dEO0GcMZDN5vaDGyIo7pt804= +github.com/grafana/sobek v0.0.0-20240829081756-447e8c611945/go.mod h1:FmcutBFPLiGgroH42I4/HBahv7GxVjODcVWFTw1ISes= github.com/grafana/xk6-browser v1.7.1 h1:RKCcoFyKT97iGgbnK76WwxcXnkB23ijlO1LghqjHQ0E= github.com/grafana/xk6-browser v1.7.1/go.mod h1:sZO7cT7/XQf2mz+rXkp6poswhOCA0JKA8isj3fQrfaU= github.com/grafana/xk6-dashboard v0.7.5 h1:TcILyffT/Ea/XD7xG1jMA5lwtusOPRbEQsQDHmO30Mk= diff --git a/vendor/github.com/grafana/sobek/builtin_regexp.go b/vendor/github.com/grafana/sobek/builtin_regexp.go index d0be2decf272..8344b1cecd2a 100644 --- a/vendor/github.com/grafana/sobek/builtin_regexp.go +++ b/vendor/github.com/grafana/sobek/builtin_regexp.go @@ -241,7 +241,7 @@ func compileRegexp(patternStr, flags string) (p *regexpPattern, err error) { patternStr = convertRegexpToUtf16(patternStr) } - re2Str, err1 := parser.TransformRegExp(patternStr, dotAll) + re2Str, err1 := parser.TransformRegExp(patternStr, dotAll, unicode) if err1 == nil { re2flags := "" if multiline { @@ -268,7 +268,7 @@ func compileRegexp(patternStr, flags string) (p *regexpPattern, err error) { err = err1 return } - wrapper2, err = compileRegexp2(patternStr, multiline, dotAll, ignoreCase) + wrapper2, err = compileRegexp2(patternStr, multiline, dotAll, ignoreCase, unicode) if err != nil { err = fmt.Errorf("Invalid regular expression (regexp2): %s (%v)", patternStr, err) return diff --git a/vendor/github.com/grafana/sobek/parser/lexer.go b/vendor/github.com/grafana/sobek/parser/lexer.go index 1d7de1becfdf..b7dab723fb1c 100644 --- a/vendor/github.com/grafana/sobek/parser/lexer.go +++ b/vendor/github.com/grafana/sobek/parser/lexer.go @@ -633,9 +633,13 @@ func (self *_parser) skipWhiteSpace() { } } -func (self *_parser) scanMantissa(base int) { - for digitValue(self.chr) < base { +func (self *_parser) scanMantissa(base int, allowSeparator bool) { + for digitValue(self.chr) < base || (allowSeparator && self.chr == '_') { + afterUnderscore := self.chr == '_' self.read() + if afterUnderscore && !isDigit(self.chr, base) { + self.error(self.chrOffset, "Only one underscore is allowed as numeric separator") + } } } @@ -1140,7 +1144,7 @@ func (self *_parser) scanNumericLiteral(decimalPoint bool) (token.Token, string) if decimalPoint { offset-- - self.scanMantissa(10) + self.scanMantissa(10, true) } else { if self.chr == '0' { self.read() @@ -1156,7 +1160,7 @@ func (self *_parser) scanNumericLiteral(decimalPoint bool) (token.Token, string) // no-op default: // legacy octal - self.scanMantissa(8) + self.scanMantissa(8, false) goto end } if base > 0 { @@ -1164,15 +1168,15 @@ func (self *_parser) scanNumericLiteral(decimalPoint bool) (token.Token, string) if !isDigit(self.chr, base) { return token.ILLEGAL, self.str[offset:self.chrOffset] } - self.scanMantissa(base) + self.scanMantissa(base, true) goto end } } else { - self.scanMantissa(10) + self.scanMantissa(10, true) } if self.chr == '.' { self.read() - self.scanMantissa(10) + self.scanMantissa(10, true) } } @@ -1183,7 +1187,7 @@ func (self *_parser) scanNumericLiteral(decimalPoint bool) (token.Token, string) } if isDecimalDigit(self.chr) { self.read() - self.scanMantissa(10) + self.scanMantissa(10, true) } else { return token.ILLEGAL, self.str[offset:self.chrOffset] } diff --git a/vendor/github.com/grafana/sobek/parser/regexp.go b/vendor/github.com/grafana/sobek/parser/regexp.go index 72bb3c7fecb1..0ea9b9d745ae 100644 --- a/vendor/github.com/grafana/sobek/parser/regexp.go +++ b/vendor/github.com/grafana/sobek/parser/regexp.go @@ -41,7 +41,8 @@ type _RegExp_parser struct { goRegexp strings.Builder passOffset int - dotAll bool // Enable dotAll mode + dotAll bool // Enable dotAll mode + unicode bool } // TransformRegExp transforms a JavaScript pattern into a Go "regexp" pattern. @@ -57,16 +58,17 @@ type _RegExp_parser struct { // // If the pattern is invalid (not valid even in JavaScript), then this function // returns an empty string and a generic error. -func TransformRegExp(pattern string, dotAll bool) (transformed string, err error) { +func TransformRegExp(pattern string, dotAll, unicode bool) (transformed string, err error) { if pattern == "" { return "", nil } parser := _RegExp_parser{ - str: pattern, - length: len(pattern), - dotAll: dotAll, + str: pattern, + length: len(pattern), + dotAll: dotAll, + unicode: unicode, } err = parser.parse() if err != nil { @@ -292,7 +294,7 @@ func (self *_RegExp_parser) scanEscape(inClass bool) { case 'u': self.read() - if self.chr == '{' { + if self.chr == '{' && self.unicode { self.read() length, base = 0, 16 } else { @@ -392,7 +394,8 @@ func (self *_RegExp_parser) scanEscape(inClass bool) { digit := uint32(digitValue(self.chr)) if digit >= base { // Not a valid digit - goto skip + self.error(true, "Invalid Unicode escape") + return } self.read() } diff --git a/vendor/github.com/grafana/sobek/regexp.go b/vendor/github.com/grafana/sobek/regexp.go index 3da1fc4add7c..ca28ccccaf1e 100644 --- a/vendor/github.com/grafana/sobek/regexp.go +++ b/vendor/github.com/grafana/sobek/regexp.go @@ -67,7 +67,7 @@ type regexpPattern struct { regexp2Wrapper *regexp2Wrapper } -func compileRegexp2(src string, multiline, dotAll, ignoreCase bool) (*regexp2Wrapper, error) { +func compileRegexp2(src string, multiline, dotAll, ignoreCase, unicode bool) (*regexp2Wrapper, error) { var opts regexp2.RegexOptions = regexp2.ECMAScript if multiline { opts |= regexp2.Multiline @@ -78,6 +78,9 @@ func compileRegexp2(src string, multiline, dotAll, ignoreCase bool) (*regexp2Wra if ignoreCase { opts |= regexp2.IgnoreCase } + if unicode { + opts |= regexp2.Unicode + } regexp2Pattern, err1 := regexp2.Compile(src, opts) if err1 != nil { return nil, fmt.Errorf("Invalid regular expression (regexp2): %s (%v)", src, err1) @@ -90,7 +93,7 @@ func (p *regexpPattern) createRegexp2() { if p.regexp2Wrapper != nil { return } - rx, err := compileRegexp2(p.src, p.multiline, p.dotAll, p.ignoreCase) + rx, err := compileRegexp2(p.src, p.multiline, p.dotAll, p.ignoreCase, p.unicode) if err != nil { // At this point the regexp should have been successfully converted to re2, if it fails now, it's a bug. panic(err) diff --git a/vendor/github.com/grafana/sobek/string_ascii.go b/vendor/github.com/grafana/sobek/string_ascii.go index f83b3d584219..63c92ada0345 100644 --- a/vendor/github.com/grafana/sobek/string_ascii.go +++ b/vendor/github.com/grafana/sobek/string_ascii.go @@ -103,8 +103,8 @@ func stringToInt(ss string) (int64, error) { return strconv.ParseInt(ss, 10, 64) } -func (s asciiString) _toInt() (int64, error) { - return stringToInt(strings.TrimSpace(string(s))) +func (s asciiString) _toInt(trimmed string) (int64, error) { + return stringToInt(trimmed) } func isRangeErr(err error) bool { @@ -114,18 +114,36 @@ func isRangeErr(err error) bool { return false } -func (s asciiString) _toFloat() (float64, error) { - ss := strings.ToLower(strings.TrimSpace(string(s))) - if ss == "" { +func (s asciiString) _toFloat(trimmed string) (float64, error) { + if trimmed == "" { return 0, nil } - if ss == "-0" { + if trimmed == "-0" { var f float64 return -f, nil } - f, err := strconv.ParseFloat(ss, 64) + // Go allows underscores in numbers, when parsed as floats, but ECMAScript expect them to be interpreted as NaN. + if strings.ContainsRune(trimmed, '_') { + return 0, strconv.ErrSyntax + } + + // Hexadecimal floats are not supported by ECMAScript. + if len(trimmed) >= 2 { + var prefix string + if trimmed[0] == '-' || trimmed[0] == '+' { + prefix = trimmed[1:] + } else { + prefix = trimmed + } + if len(prefix) >= 2 && prefix[0] == '0' && (prefix[1] == 'x' || prefix[1] == 'X') { + return 0, strconv.ErrSyntax + } + } + + f, err := strconv.ParseFloat(trimmed, 64) if err == nil && math.IsInf(f, 0) { + ss := strings.ToLower(trimmed) if strings.HasPrefix(ss, "inf") || strings.HasPrefix(ss, "-inf") || strings.HasPrefix(ss, "+inf") { // We handle "Infinity" separately, prevent from being parsed as Infinity due to strconv.ParseFloat() permissive syntax return 0, strconv.ErrSyntax @@ -138,18 +156,19 @@ func (s asciiString) _toFloat() (float64, error) { } func (s asciiString) ToInteger() int64 { - if s == "" { + ss := strings.TrimSpace(string(s)) + if ss == "" { return 0 } - if s == "Infinity" || s == "+Infinity" { + if ss == "Infinity" || ss == "+Infinity" { return math.MaxInt64 } - if s == "-Infinity" { + if ss == "-Infinity" { return math.MinInt64 } - i, err := s._toInt() + i, err := s._toInt(ss) if err != nil { - f, err := s._toFloat() + f, err := s._toFloat(ss) if err == nil { return int64(f) } @@ -170,18 +189,19 @@ func (s asciiString) String() string { } func (s asciiString) ToFloat() float64 { - if s == "" { + ss := strings.TrimSpace(string(s)) + if ss == "" { return 0 } - if s == "Infinity" || s == "+Infinity" { + if ss == "Infinity" || ss == "+Infinity" { return math.Inf(1) } - if s == "-Infinity" { + if ss == "-Infinity" { return math.Inf(-1) } - f, err := s._toFloat() + f, err := s._toFloat(ss) if err != nil { - i, err := s._toInt() + i, err := s._toInt(ss) if err == nil { return float64(i) } @@ -195,21 +215,22 @@ func (s asciiString) ToBoolean() bool { } func (s asciiString) ToNumber() Value { - if s == "" { + ss := strings.TrimSpace(string(s)) + if ss == "" { return intToValue(0) } - if s == "Infinity" || s == "+Infinity" { + if ss == "Infinity" || ss == "+Infinity" { return _positiveInf } - if s == "-Infinity" { + if ss == "-Infinity" { return _negativeInf } - if i, err := s._toInt(); err == nil { + if i, err := s._toInt(ss); err == nil { return intToValue(i) } - if f, err := s._toFloat(); err == nil { + if f, err := s._toFloat(ss); err == nil { return floatToValue(f) } @@ -230,7 +251,7 @@ func (s asciiString) Equals(other Value) bool { } if o, ok := other.(valueInt); ok { - if o1, e := s._toInt(); e == nil { + if o1, e := s._toInt(strings.TrimSpace(string(s))); e == nil { return o1 == int64(o) } return false @@ -241,7 +262,7 @@ func (s asciiString) Equals(other Value) bool { } if o, ok := other.(valueBool); ok { - if o1, e := s._toFloat(); e == nil { + if o1, e := s._toFloat(strings.TrimSpace(string(s))); e == nil { return o1 == o.ToFloat() } return false diff --git a/vendor/modules.txt b/vendor/modules.txt index d4e22a51aa07..23509ce42517 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -163,7 +163,7 @@ github.com/google/uuid # github.com/gorilla/websocket v1.5.1 ## explicit; go 1.20 github.com/gorilla/websocket -# github.com/grafana/sobek v0.0.0-20240823144814-3c582bfdac82 +# github.com/grafana/sobek v0.0.0-20240829081756-447e8c611945 ## explicit; go 1.20 github.com/grafana/sobek github.com/grafana/sobek/ast