From 06c9756333bb506dcbf322be77af85b3162b6345 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 5 Apr 2021 12:12:25 -0700 Subject: [release-branch.go1.15] time: use offset and isDST when caching zone from extend string If the current time is computed from extend string and the zone file contains multiple zones with the same name, the lookup by name might find incorrect zone. This happens for example with the slim Europe/Dublin time zone file in the embedded zip. This zone file has last transition in 1996 and rest is covered by extend string. tzset returns IST as the zone name to use, but there are two records with IST name. Lookup by name finds the wrong one. We need to check offset and isDST too. In case we can't find an existing zone, we allocate a new zone so that we use correct offset and isDST. I have renamed zone variable to zones as it shadowed the zone type that we need to allocate the cached zone. Backport note: this change also incorporates portions of CL 264077. For #45370 Fixes #45384 Change-Id: I43d416d009e20878261156c821a5784e2407ed1f Reviewed-on: https://go-review.googlesource.com/c/go/+/307212 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Emmanuel Odeke --- src/time/zoneinfo.go | 27 ++++++++++++++++----------- src/time/zoneinfo_read.go | 44 +++++++++++++++++++++++++++----------------- src/time/zoneinfo_test.go | 37 +++++++++++++++++++++++++------------ 3 files changed, 68 insertions(+), 40 deletions(-) diff --git a/src/time/zoneinfo.go b/src/time/zoneinfo.go index 6db9443474..57052338d0 100644 --- a/src/time/zoneinfo.go +++ b/src/time/zoneinfo.go @@ -178,7 +178,7 @@ func (l *Location) lookup(sec int64) (name string, offset int, start, end int64) // If we're at the end of the known zone transitions, // try the extend string. if lo == len(tx)-1 && l.extend != "" { - if ename, eoffset, estart, eend, ok := tzset(l.extend, end, sec); ok { + if ename, eoffset, estart, eend, _, ok := tzset(l.extend, end, sec); ok { return ename, eoffset, estart, eend } } @@ -244,7 +244,7 @@ func (l *Location) firstZoneUsed() bool { // We call this a tzset string since in C the function tzset reads TZ. // The return values are as for lookup, plus ok which reports whether the // parse succeeded. -func tzset(s string, initEnd, sec int64) (name string, offset int, start, end int64, ok bool) { +func tzset(s string, initEnd, sec int64) (name string, offset int, start, end int64, isDST, ok bool) { var ( stdName, dstName string stdOffset, dstOffset int @@ -255,7 +255,7 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in stdOffset, s, ok = tzsetOffset(s) } if !ok { - return "", 0, 0, 0, false + return "", 0, 0, 0, false, false } // The numbers in the tzset string are added to local time to get UTC, @@ -265,7 +265,7 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in if len(s) == 0 || s[0] == ',' { // No daylight savings time. - return stdName, stdOffset, initEnd, omega, true + return stdName, stdOffset, initEnd, omega, false, true } dstName, s, ok = tzsetName(s) @@ -278,7 +278,7 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in } } if !ok { - return "", 0, 0, 0, false + return "", 0, 0, 0, false, false } if len(s) == 0 { @@ -287,19 +287,19 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in } // The TZ definition does not mention ';' here but tzcode accepts it. if s[0] != ',' && s[0] != ';' { - return "", 0, 0, 0, false + return "", 0, 0, 0, false, false } s = s[1:] var startRule, endRule rule startRule, s, ok = tzsetRule(s) if !ok || len(s) == 0 || s[0] != ',' { - return "", 0, 0, 0, false + return "", 0, 0, 0, false, false } s = s[1:] endRule, s, ok = tzsetRule(s) if !ok || len(s) > 0 { - return "", 0, 0, 0, false + return "", 0, 0, 0, false, false } year, _, _, yday := absDate(uint64(sec+unixToInternal+internalToAbsolute), false) @@ -313,10 +313,15 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in startSec := int64(tzruleTime(year, startRule, stdOffset)) endSec := int64(tzruleTime(year, endRule, dstOffset)) + dstIsDST, stdIsDST := true, false + // Note: this is a flipping of "DST" and "STD" while retaining the labels + // This happens in southern hemispheres. The labelling here thus is a little + // inconsistent with the goal. if endSec < startSec { startSec, endSec = endSec, startSec stdName, dstName = dstName, stdName stdOffset, dstOffset = dstOffset, stdOffset + stdIsDST, dstIsDST = dstIsDST, stdIsDST } // The start and end values that we return are accurate @@ -324,11 +329,11 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in // just the start and end of the year. That suffices for // the only caller that cares, which is Date. if ysec < startSec { - return stdName, stdOffset, abs, startSec + abs, true + return stdName, stdOffset, abs, startSec + abs, stdIsDST, true } else if ysec >= endSec { - return stdName, stdOffset, endSec + abs, abs + 365*secondsPerDay, true + return stdName, stdOffset, endSec + abs, abs + 365*secondsPerDay, stdIsDST, true } else { - return dstName, dstOffset, startSec + abs, endSec + abs, true + return dstName, dstOffset, startSec + abs, endSec + abs, dstIsDST, true } } diff --git a/src/time/zoneinfo_read.go b/src/time/zoneinfo_read.go index 22a60f3211..f7fe59c385 100644 --- a/src/time/zoneinfo_read.go +++ b/src/time/zoneinfo_read.go @@ -247,8 +247,8 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) { // This also avoids a panic later when we add and then use a fake transition (golang.org/issue/29437). return nil, badData } - zone := make([]zone, nzone) - for i := range zone { + zones := make([]zone, nzone) + for i := range zones { var ok bool var n uint32 if n, ok = zonedata.big4(); !ok { @@ -257,22 +257,22 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) { if uint32(int(n)) != n { return nil, badData } - zone[i].offset = int(int32(n)) + zones[i].offset = int(int32(n)) var b byte if b, ok = zonedata.byte(); !ok { return nil, badData } - zone[i].isDST = b != 0 + zones[i].isDST = b != 0 if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) { return nil, badData } - zone[i].name = byteString(abbrev[b:]) + zones[i].name = byteString(abbrev[b:]) if runtime.GOOS == "aix" && len(name) > 8 && (name[:8] == "Etc/GMT+" || name[:8] == "Etc/GMT-") { // There is a bug with AIX 7.2 TL 0 with files in Etc, // GMT+1 will return GMT-1 instead of GMT+1 or -01. if name != "Etc/GMT+0" { // GMT+0 is OK - zone[i].name = name[4:] + zones[i].name = name[4:] } } } @@ -295,7 +295,7 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) { } } tx[i].when = n - if int(txzones[i]) >= len(zone) { + if int(txzones[i]) >= len(zones) { return nil, badData } tx[i].index = txzones[i] @@ -314,7 +314,7 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) { } // Committed to succeed. - l := &Location{zone: zone, tx: tx, name: name, extend: extend} + l := &Location{zone: zones, tx: tx, name: name, extend: extend} // Fill in the cache with information about right now, // since that will be the most common lookup. @@ -323,26 +323,27 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) { if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) { l.cacheStart = tx[i].when l.cacheEnd = omega - zoneIdx := tx[i].index + l.cacheZone = &l.zone[tx[i].index] if i+1 < len(tx) { l.cacheEnd = tx[i+1].when } else if l.extend != "" { // If we're at the end of the known zone transitions, // try the extend string. - if name, _, estart, eend, ok := tzset(l.extend, l.cacheEnd, sec); ok { + if name, offset, estart, eend, isDST, ok := tzset(l.extend, l.cacheEnd, sec); ok { l.cacheStart = estart l.cacheEnd = eend - // Find the zone that is returned by tzset, - // the last transition is not always the correct zone. - for i, z := range l.zone { - if z.name == name { - zoneIdx = uint8(i) - break + // Find the zone that is returned by tzset to avoid allocation if possible. + if zoneIdx := findZone(l.zone, name, offset, isDST); zoneIdx != -1 { + l.cacheZone = &l.zone[zoneIdx] + } else { + l.cacheZone = &zone{ + name: name, + offset: offset, + isDST: isDST, } } } } - l.cacheZone = &l.zone[zoneIdx] break } } @@ -350,6 +351,15 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) { return l, nil } +func findZone(zones []zone, name string, offset int, isDST bool) int { + for i, z := range zones { + if z.name == name && z.offset == offset && z.isDST == isDST { + return i + } + } + return -1 +} + // loadTzinfoFromDirOrZip returns the contents of the file with the given name // in dir. dir can either be an uncompressed zip file, or a directory. func loadTzinfoFromDirOrZip(dir, name string) ([]byte, error) { diff --git a/src/time/zoneinfo_test.go b/src/time/zoneinfo_test.go index d043e1e9f1..7ba1229741 100644 --- a/src/time/zoneinfo_test.go +++ b/src/time/zoneinfo_test.go @@ -186,6 +186,7 @@ func TestMalformedTZData(t *testing.T) { var slimTests = []struct { zoneName string tzData string + date func(*time.Location) time.Time wantName string wantOffset int }{ @@ -193,6 +194,7 @@ var slimTests = []struct { // 2020b slim tzdata for Europe/Berlin. zoneName: "Europe/Berlin", tzData: "TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffo\xa2a\xf8\xff\xff\xff\xff\x9b\f\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9cٮ\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\tq\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xffͩ\x17\x90\xff\xff\xff\xff\u03a2C\x10\xff\xff\xff\xffϒ4\x10\xff\xff\xff\xffЂ%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xffѶ\x96\x00\xff\xff\xff\xff\xd2X\xbe\x80\xff\xff\xff\xffҡO\x10\xff\xff\xff\xff\xd3c\x1b\x90\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd59\xd1 \xff\xff\xff\xff\xd5g\xe7\x90\xff\xff\xff\xffըs\x00\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\t\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13ܐ\x00\x00\x00\x00\x17\x03͐\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18㯐\x00\x00\x00\x00\x19Ӡ\x90\x00\x00\x00\x00\x1aÑ\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\\c\x10\x00\x00\x00\x00\"LT\x10\x00\x00\x00\x00#3<-02>,M3.5.0/-2,M10.5.0/-1\n", + date: func(loc *time.Location) time.Time { return time.Date(2020, time.October, 29, 15, 30, 0, 0, loc) }, wantName: "-03", wantOffset: -10800, }, @@ -207,9 +210,18 @@ var slimTests = []struct { // 2021a slim tzdata for Asia/Gaza. zoneName: "Asia/Gaza", tzData: "TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xff}\xbdJ\xb0\xff\xff\xff\xff\xc8Y\xcf\x00\xff\xff\xff\xff\xc8\xfa\xa6\x00\xff\xff\xff\xff\xc98\x9c\x80\xff\xff\xff\xff\xcc\xe5\xeb\x80\xff\xff\xff\xffͬ\xfe\x00\xff\xff\xff\xff\xce\xc7\x1f\x00\xff\xff\xff\xffϏ\x83\x00\xff\xff\xff\xffЩ\xa4\x00\xff\xff\xff\xffф}\x00\xff\xff\xff\xffҊ׀\xff\xff\xff\xff\xd3e\xb0\x80\xff\xff\xff\xff\xd4l\v\x00\xff\xff\xff\xff\xe86c`\xff\xff\xff\xff\xe8\xf4-P\xff\xff\xff\xff\xea\v\xb9`\xff\xff\xff\xff\xea\xd5`\xd0\xff\xff\xff\xff\xeb\xec\xfa\xf0\xff\xff\xff\xff\xec\xb5m\x00\xff\xff\xff\xff\xed\xcf\u007f\xf0\xff\xff\xff\xff\xee\x97\xf2\x00\xff\xff\xff\xffﰳp\xff\xff\xff\xff\xf0y%\x80\xff\xff\xff\xff\xf1\x91\xe6\xf0\xff\xff\xff\xff\xf2ZY\x00\xff\xff\xff\xff\xf3s\x1ap\xff\xff\xff\xff\xf4;\x8c\x80\xff\xff\xff\xff\xf5U\x9fp\xff\xff\xff\xff\xf6\x1e\x11\x80\xff\xff\xff\xff\xf76\xd2\xf0\xff\xff\xff\xff\xf7\xffE\x00\xff\xff\xff\xff\xf9\x18\x06p\xff\xff\xff\xff\xf9\xe1\xca\x00\xff\xff\xff\xff\xfa\xf99\xf0\xff\xff\xff\xff\xfb'BP\x00\x00\x00\x00\b|\x8b\xe0\x00\x00\x00\x00\b\xfd\xb0\xd0\x00\x00\x00\x00\t\xf6\xea`\x00\x00\x00\x00\n\xa63\xd0\x00\x00\x00\x00\x13\xe9\xfc`\x00\x00\x00\x00\x14![`\x00\x00\x00\x00\x1a\xfa\xc6`\x00\x00\x00\x00\x1b\x8en`\x00\x00\x00\x00\x1c\xbe\xf8\xe0\x00\x00\x00\x00\x1dw|\xd0\x00\x00\x00\x00\x1e\xcc\xff`\x00\x00\x00\x00\x1f`\x99P\x00\x00\x00\x00 \x82\xb1`\x00\x00\x00\x00!I\xb5\xd0\x00\x00\x00\x00\"^\x9e\xe0\x00\x00\x00\x00# ]P\x00\x00\x00\x00$Z0`\x00\x00\x00\x00%\x00?P\x00\x00\x00\x00&\v\xed\xe0\x00\x00\x00\x00&\xd6\xe6\xd0\x00\x00\x00\x00'\xeb\xcf\xe0\x00\x00\x00\x00(\xc0\x03P\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xa9\x1f\xd0\x00\x00\x00\x00+\xbbe\xe0\x00\x00\x00\x00,\x89\x01\xd0\x00\x00\x00\x00-\x9bG\xe0\x00\x00\x00\x00._\xa9P\x00\x00\x00\x00/{)\xe0\x00\x00\x00\x000H\xc5\xd0\x00\x00\x00\x000\xe7\a\xe0\x00\x00\x00\x001dF`\x00\x00\x00\x002A\xc2`\x00\x00\x00\x003D(`\x00\x00\x00\x004!\xa4`\x00\x00\x00\x005$\n`\x00\x00\x00\x006\x01\x86`\x00\x00\x00\x007\x16a`\x00\x00\x00\x008\x06DP\x00\x00\x00\x008\xff}\xe0\x00\x00\x00\x009\xef`\xd0\x00\x00\x00\x00:\xdf_\xe0\x00\x00\x00\x00;\xcfB\xd0\x00\x00\x00\x00<\xbfA\xe0\x00\x00\x00\x00=\xaf$\xd0\x00\x00\x00\x00>\x9f#\xe0\x00\x00\x00\x00?\x8f\x06\xd0\x00\x00\x00\x00@\u007f\x05\xe0\x00\x00\x00\x00A\\\x81\xe0\x00\x00\x00\x00B^\xe7\xe0\x00\x00\x00\x00CA\xb7\xf0\x00\x00\x00\x00D-\xa6`\x00\x00\x00\x00E\x12\xfdP\x00\x00\x00\x00F\x0e\xd9\xe0\x00\x00\x00\x00F\xe8op\x00\x00\x00\x00G\xec\x18\xe0\x00\x00\x00\x00H\xb7\x11\xd0\x00\x00\x00\x00I\xcb\xfa\xe0\x00\x00\x00\x00J\xa0<`\x00\x00\x00\x00K\xad.\x9c\x00\x00\x00\x00La\xbd\xd0\x00\x00\x00\x00M\x94\xf9\x9c\x00\x00\x00\x00N5\xc2P\x00\x00\x00\x00Ot\xdb`\x00\x00\x00\x00P[\x91\xe0\x00\x00\x00\x00QT\xbd`\x00\x00\x00\x00RD\xa0P\x00\x00\x00\x00S4\x9f`\x00\x00\x00\x00TIlP\x00\x00\x00\x00U\x15\xd2\xe0\x00\x00\x00\x00V)\\`\x00\x00\x00\x00V\xf5\xc2\xf0\x00\x00\x00\x00X\x13\xca`\x00\x00\x00\x00Xդ\xf0\x00\x00\x00\x00Y\xf3\xac`\x00\x00\x00\x00Z\xb5\x86\xf0\x00\x00\x00\x00[ӎ`\x00\x00\x00\x00\\\x9dC\xe0\x00\x00\x00\x00]\xb3bP\x00\x00\x00\x00^~w`\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00 P\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\t\x00\x00*0\x01\r\x00\x00\x1c \x00\x11LMT\x00EEST\x00EET\x00IDT\x00IST\x00\nEET-2EEST,M3.4.4/48,M10.4.4/49\n", + date: func(loc *time.Location) time.Time { return time.Date(2020, time.October, 29, 15, 30, 0, 0, loc) }, wantName: "EET", wantOffset: 7200, }, + { + // 2021a slim tzdata for Europe/Dublin. + zoneName: "Europe/Dublin", + tzData: "TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x91\x00\x00\x00\x08\x00\x00\x00\x14\xff\xff\xff\xffW\xd1\n\xdc\xff\xff\xff\xff\x9b&\xb3\x91\xff\xff\xff\xff\x9b\xd6\x0b\x11\xff\xff\xff\xff\x9c\xcf0\xa0\xff\xff\xff\xff\x9d\xa4\xc3\xa0\xff\xff\xff\xff\x9e\x9c\x9d\xa0\xff\xff\xff\xff\x9f\x97\x1a\xa0\xff\xff\xff\xff\xa0\x85\xba\x20\xff\xff\xff\xff\xa1v\xfc\xa0\xff\xff\xff\xff\xa2e\x9c\x20\xff\xff\xff\xff\xa3{\xc8\xa0\xff\xff\xff\xff\xa4N\xb8\xa0\xff\xff\xff\xff\xa5?\xfb\x20\xff\xff\xff\xff\xa6%`\x20\xff\xff\xff\xff\xa7'\xc6\x20\xff\xff\xff\xff\xa8*,\x20\xff\xff\xff\xff\xa8\xeb\xf8\xa0\xff\xff\xff\xff\xaa\x00\xd3\xa0\xff\xff\xff\xff\xaa\xd5\x15\x20\xff\xff\xff\xff\xab\xe9\xf0\x20\xff\xff\xff\xff\xac\xc7l\x20\xff\xff\xff\xff\xad\xc9\xd2\x20\xff\xff\xff\xff\xae\xa7N\x20\xff\xff\xff\xff\xaf\xa0y\xa0\xff\xff\xff\xff\xb0\x870\x20\xff\xff\xff\xff\xb1\x92\xd0\xa0\xff\xff\xff\xff\xb2pL\xa0\xff\xff\xff\xff\xb3r\xb2\xa0\xff\xff\xff\xff\xb4P.\xa0\xff\xff\xff\xff\xb5IZ\x20\xff\xff\xff\xff\xb60\x10\xa0\xff\xff\xff\xff\xb72v\xa0\xff\xff\xff\xff\xb8\x0f\xf2\xa0\xff\xff\xff\xff\xb9\x12X\xa0\xff\xff\xff\xff\xb9\xef\xd4\xa0\xff\xff\xff\xff\xba\xe9\x00\x20\xff\xff\xff\xff\xbb\xd8\xf1\x20\xff\xff\xff\xff\xbc\xdbW\x20\xff\xff\xff\xff\xbd\xb8\xd3\x20\xff\xff\xff\xff\xbe\xb1\xfe\xa0\xff\xff\xff\xff\xbf\x98\xb5\x20\xff\xff\xff\xff\xc0\x9b\x1b\x20\xff\xff\xff\xff\xc1x\x97\x20\xff\xff\xff\xff\xc2z\xfd\x20\xff\xff\xff\xff\xc3Xy\x20\xff\xff\xff\xff\xc4Q\xa4\xa0\xff\xff\xff\xff\xc58[\x20\xff\xff\xff\xff\xc6:\xc1\x20\xff\xff\xff\xff\xc7X\xd6\xa0\xff\xff\xff\xff\xc7\xda\x09\xa0\xff\xff\xff\xff\xd4I\xe0\x20\xff\xff\xff\xff\xd5\x1e!\xa0\xff\xff\xff\xff\xd6N\xac\x20\xff\xff\xff\xff\xd7,(\x20\xff\xff\xff\xff\xd8.\x8e\x20\xff\xff\xff\xff\xd8\xf9\x95\x20\xff\xff\xff\xff\xda\x0ep\x20\xff\xff\xff\xff\xda\xeb\xec\x20\xff\xff\xff\xff\xdb\xe5\x17\xa0\xff\xff\xff\xff\xdc\xcb\xce\x20\xff\xff\xff\xff\xdd\xc4\xf9\xa0\xff\xff\xff\xff\xde\xb4\xea\xa0\xff\xff\xff\xff\xdf\xae\x16\x20\xff\xff\xff\xff\xe0\x94\xcc\xa0\xff\xff\xff\xff\xe1rH\xa0\xff\xff\xff\xff\xe2kt\x20\xff\xff\xff\xff\xe3R*\xa0\xff\xff\xff\xff\xe4T\x90\xa0\xff\xff\xff\xff\xe52\x0c\xa0\xff\xff\xff\xff\xe6=\xad\x20\xff\xff\xff\xff\xe7\x1b)\x20\xff\xff\xff\xff\xe8\x14T\xa0\xff\xff\xff\xff\xe8\xfb\x0b\x20\xff\xff\xff\xff\xe9\xfdq\x20\xff\xff\xff\xff\xea\xda\xed\x20\xff\xff\xff\xff\xeb\xddS\x20\xff\xff\xff\xff\xec\xba\xcf\x20\xff\xff\xff\xff\xed\xb3\xfa\xa0\xff\xff\xff\xff\xee\x9a\xb1\x20\xff\xff\xff\xff\xef\x81g\xa0\xff\xff\xff\xff\xf0\x9f}\x20\xff\xff\xff\xff\xf1aI\xa0\xff\xff\xff\xff\xf2\x7f_\x20\xff\xff\xff\xff\xf3Jf\x20\xff\xff\xff\xff\xf4_A\x20\xff\xff\xff\xff\xf5!\x0d\xa0\xff\xff\xff\xff\xf6?#\x20\xff\xff\xff\xff\xf7\x00\xef\xa0\xff\xff\xff\xff\xf8\x1f\x05\x20\xff\xff\xff\xff\xf8\xe0\xd1\xa0\xff\xff\xff\xff\xf9\xfe\xe7\x20\xff\xff\xff\xff\xfa\xc0\xb3\xa0\xff\xff\xff\xff\xfb\xe8\x03\xa0\xff\xff\xff\xff\xfc{\xab\xa0\xff\xff\xff\xff\xfd\xc7\xbbp\x00\x00\x00\x00\x03p\xc6\x20\x00\x00\x00\x00\x04)X\x20\x00\x00\x00\x00\x05P\xa8\x20\x00\x00\x00\x00\x06\x09:\x20\x00\x00\x00\x00\x070\x8a\x20\x00\x00\x00\x00\x07\xe9\x1c\x20\x00\x00\x00\x00\x09\x10l\x20\x00\x00\x00\x00\x09\xc8\xfe\x20\x00\x00\x00\x00\n\xf0N\x20\x00\x00\x00\x00\x0b\xb2\x1a\xa0\x00\x00\x00\x00\x0c\xd00\x20\x00\x00\x00\x00\x0d\x91\xfc\xa0\x00\x00\x00\x00\x0e\xb0\x12\x20\x00\x00\x00\x00\x0fq\xde\xa0\x00\x00\x00\x00\x10\x99.\xa0\x00\x00\x00\x00\x11Q\xc0\xa0\x00\x00\x00\x00\x12y\x10\xa0\x00\x00\x00\x00\x131\xa2\xa0\x00\x00\x00\x00\x14X\xf2\xa0\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x168\xc6\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x18\x18\xa8\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xf8\x8a\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xe1\xa7\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\xc1\x89\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f\xa1k\x10\x00\x00\x00\x00\x20lr\x10\x00\x00\x00\x00!\x81M\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#a/\x10\x00\x00\x00\x00$,6\x10\x00\x00\x00\x00%JK\x90\x00\x00\x00\x00&\x0c\x18\x10\x00\x00\x00\x00'*-\x90\x00\x00\x00\x00'\xf54\x90\x00\x00\x00\x00)\n\x0f\x90\x00\x00\x00\x00)\xd5\x16\x90\x00\x00\x00\x00*\xe9\xf1\x90\x00\x00\x00\x00+\xb4\xf8\x90\x00\x00\x00\x00,\xc9\xd3\x90\x00\x00\x00\x00-\x94\xda\x90\x00\x00\x00\x00.\xa9\xb5\x90\x00\x00\x00\x00/t\xbc\x90\x00\x00\x00\x000\x89\x97\x90\x00\x00\x00\x001]\xd9\x10\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\xff\xff\xfa$\x00\x00\xff\xff\xfa\x0f\x00\x04\x00\x00\x08\x1f\x01\x08\x00\x00\x0e\x10\x01\x0c\x00\x00\x00\x00\x00\x10\x00\x00\x0e\x10\x01\x08\x00\x00\x00\x00\x01\x10\x00\x00\x0e\x10\x00\x08LMT\x00DMT\x00IST\x00BST\x00GMT\x00\nIST-1GMT0,M10.5.0,M3.5.0/1\n", + date: func(loc *time.Location) time.Time { return time.Date(2021, time.April, 2, 11, 12, 13, 0, loc) }, + wantName: "IST", + wantOffset: 3600, + }, } func TestLoadLocationFromTZDataSlim(t *testing.T) { @@ -219,7 +231,7 @@ func TestLoadLocationFromTZDataSlim(t *testing.T) { t.Fatal(err) } - d := time.Date(2020, time.October, 29, 15, 30, 0, 0, reference) + d := test.date(reference) tzName, tzOffset := d.Zone() if tzName != test.wantName { t.Errorf("Zone name == %s, want %s", tzName, test.wantName) @@ -239,20 +251,21 @@ func TestTzset(t *testing.T) { off int start int64 end int64 + isDST bool ok bool }{ - {"", 0, 0, "", 0, 0, 0, false}, - {"PST8PDT,M3.2.0,M11.1.0", 0, 2159200800, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true}, - {"PST8PDT,M3.2.0,M11.1.0", 0, 2152173599, "PST", -8 * 60 * 60, 2145916800, 2152173600, true}, - {"PST8PDT,M3.2.0,M11.1.0", 0, 2152173600, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true}, - {"PST8PDT,M3.2.0,M11.1.0", 0, 2152173601, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true}, - {"PST8PDT,M3.2.0,M11.1.0", 0, 2172733199, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true}, - {"PST8PDT,M3.2.0,M11.1.0", 0, 2172733200, "PST", -8 * 60 * 60, 2172733200, 2177452800, true}, - {"PST8PDT,M3.2.0,M11.1.0", 0, 2172733201, "PST", -8 * 60 * 60, 2172733200, 2177452800, true}, + {"", 0, 0, "", 0, 0, 0, false, false}, + {"PST8PDT,M3.2.0,M11.1.0", 0, 2159200800, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true, true}, + {"PST8PDT,M3.2.0,M11.1.0", 0, 2152173599, "PST", -8 * 60 * 60, 2145916800, 2152173600, false, true}, + {"PST8PDT,M3.2.0,M11.1.0", 0, 2152173600, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true, true}, + {"PST8PDT,M3.2.0,M11.1.0", 0, 2152173601, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true, true}, + {"PST8PDT,M3.2.0,M11.1.0", 0, 2172733199, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true, true}, + {"PST8PDT,M3.2.0,M11.1.0", 0, 2172733200, "PST", -8 * 60 * 60, 2172733200, 2177452800, false, true}, + {"PST8PDT,M3.2.0,M11.1.0", 0, 2172733201, "PST", -8 * 60 * 60, 2172733200, 2177452800, false, true}, } { - name, off, start, end, ok := time.Tzset(test.inStr, test.inEnd, test.inSec) - if name != test.name || off != test.off || start != test.start || end != test.end || ok != test.ok { - t.Errorf("tzset(%q, %d, %d) = %q, %d, %d, %d, %t, want %q, %d, %d, %d, %t", test.inStr, test.inEnd, test.inSec, name, off, start, end, ok, test.name, test.off, test.start, test.end, test.ok) + name, off, start, end, isDST, ok := time.Tzset(test.inStr, test.inEnd, test.inSec) + if name != test.name || off != test.off || start != test.start || end != test.end || isDST != test.isDST || ok != test.ok { + t.Errorf("tzset(%q, %d, %d) = %q, %d, %d, %d, %t, %t, want %q, %d, %d, %d, %t, %t", test.inStr, test.inEnd, test.inSec, name, off, start, end, isDST, ok, test.name, test.off, test.start, test.end, test.isDST, test.ok) } } } -- cgit v1.2.3-54-g00ecf From 5aed4ce3c854bdbbb6dd5c1ccfa15c23d4b6c989 Mon Sep 17 00:00:00 2001 From: Katie Hockman Date: Wed, 28 Apr 2021 14:47:48 -0400 Subject: [release-branch.go1.15] std: update golang.org/x/net to 20210428183841-261fb518b1ed Steps: go get -d golang.org/x/net@release-branch.go1.15 go mod tidy go mod vendor This http2 bundle does not need to be updated. Fixes #45711 Change-Id: I085ca592dfc8d5d9c328a7979142e88e7130a813 Reviewed-on: https://go-review.googlesource.com/c/go/+/314790 Trust: Katie Hockman Run-TryBot: Katie Hockman Reviewed-by: Dmitri Shuralyov --- src/go.mod | 2 +- src/go.sum | 4 ++-- src/vendor/golang.org/x/net/http/httpguts/httplex.go | 10 ++++++---- src/vendor/modules.txt | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/go.mod b/src/go.mod index 6b97366bbe..dfcba7a1c8 100644 --- a/src/go.mod +++ b/src/go.mod @@ -4,7 +4,7 @@ go 1.15 require ( golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 - golang.org/x/net v0.0.0-20201008223702-a5fa9d4b7c91 + golang.org/x/net v0.0.0-20210428183841-261fb518b1ed golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect golang.org/x/text v0.3.3-0.20200430171850-afb9336c4530 // indirect ) diff --git a/src/go.sum b/src/go.sum index fbd3279aad..47e918848c 100644 --- a/src/go.sum +++ b/src/go.sum @@ -2,8 +2,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20201008223702-a5fa9d4b7c91 h1:zd7kl5i5PDM0OnFbRWVM6B8mXojzv8LOkHN9LsOrRf4= -golang.org/x/net v0.0.0-20201008223702-a5fa9d4b7c91/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210428183841-261fb518b1ed h1:aunM0N/jnRHvQgZo3kYkfaAGet2kIMFOPIbopG5BhYw= +golang.org/x/net v0.0.0-20210428183841-261fb518b1ed/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/src/vendor/golang.org/x/net/http/httpguts/httplex.go b/src/vendor/golang.org/x/net/http/httpguts/httplex.go index e7de24ee64..c79aa73f28 100644 --- a/src/vendor/golang.org/x/net/http/httpguts/httplex.go +++ b/src/vendor/golang.org/x/net/http/httpguts/httplex.go @@ -137,11 +137,13 @@ func trimOWS(x string) string { // contains token amongst its comma-separated tokens, ASCII // case-insensitively. func headerValueContainsToken(v string, token string) bool { - v = trimOWS(v) - if comma := strings.IndexByte(v, ','); comma != -1 { - return tokenEqual(trimOWS(v[:comma]), token) || headerValueContainsToken(v[comma+1:], token) + for comma := strings.IndexByte(v, ','); comma != -1; comma = strings.IndexByte(v, ',') { + if tokenEqual(trimOWS(v[:comma]), token) { + return true + } + v = v[comma+1:] } - return tokenEqual(v, token) + return tokenEqual(trimOWS(v), token) } // lowerASCII returns the ASCII lowercase version of b. diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt index 03ca3c3ae4..dd2296b694 100644 --- a/src/vendor/modules.txt +++ b/src/vendor/modules.txt @@ -8,7 +8,7 @@ golang.org/x/crypto/curve25519 golang.org/x/crypto/hkdf golang.org/x/crypto/internal/subtle golang.org/x/crypto/poly1305 -# golang.org/x/net v0.0.0-20201008223702-a5fa9d4b7c91 +# golang.org/x/net v0.0.0-20210428183841-261fb518b1ed ## explicit golang.org/x/net/dns/dnsmessage golang.org/x/net/http/httpguts -- cgit v1.2.3-54-g00ecf From 72ccabc99449b2cb5bb1438eb90244d55f7b02f5 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Wed, 10 Mar 2021 16:06:47 -0500 Subject: [release-branch.go1.15] runtime, time: disable preemption in addtimer The timerpMask optimization updates a mask of Ps (potentially) containing timers in pidleget / pidleput. For correctness, it depends on the assumption that new timers can only be added to a P's own heap. addtimer violates this assumption if it is preempted after computing pp. That G may then run on a different P, but adding a timer to the original P's heap. Avoid this by disabling preemption while pp is in use. Other uses of doaddtimer should be OK: * moveTimers: always moves to the current P's heap * modtimer, cleantimers, addAdjustedTimers, runtimer: does not add net new timers to the heap while locked For #44868 Fixes #45731 Change-Id: I4a5d080865e854931d0a3a09a51ca36879101d72 Reviewed-on: https://go-review.googlesource.com/c/go/+/300610 Trust: Michael Pratt Run-TryBot: Michael Pratt Reviewed-by: Michael Knyszek Reviewed-by: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-on: https://go-review.googlesource.com/c/go/+/313129 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor Reviewed-by: Michael Pratt --- src/runtime/time.go | 5 +++++ src/time/sleep_test.go | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/runtime/time.go b/src/runtime/time.go index ec3eae9cca..de7468d129 100644 --- a/src/runtime/time.go +++ b/src/runtime/time.go @@ -254,6 +254,9 @@ func addtimer(t *timer) { when := t.when + // Disable preemption while using pp to avoid changing another P's heap. + mp := acquirem() + pp := getg().m.p.ptr() lock(&pp.timersLock) cleantimers(pp) @@ -261,6 +264,8 @@ func addtimer(t *timer) { unlock(&pp.timersLock) wakeNetPoller(when) + + releasem(mp) } // doaddtimer adds t to the current P's heap. diff --git a/src/time/sleep_test.go b/src/time/sleep_test.go index f5678020b9..ea253f8709 100644 --- a/src/time/sleep_test.go +++ b/src/time/sleep_test.go @@ -501,3 +501,19 @@ func TestZeroTimerStopPanics(t *testing.T) { var tr Timer tr.Stop() } + +// Test that zero duration timers aren't missed by the scheduler. Regression test for issue 44868. +func TestZeroTimer(t *testing.T) { + if testing.Short() { + t.Skip("-short") + } + + for i := 0; i < 1000000; i++ { + s := Now() + ti := NewTimer(0) + <-ti.C + if diff := Since(s); diff > 2*Second { + t.Errorf("Expected time to get value from Timer channel in less than 2 sec, took %v", diff) + } + } +} -- cgit v1.2.3-54-g00ecf From c0a7ecfae775a9d50d338e8123fac32a5d04308c Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Fri, 9 Apr 2021 17:01:45 -0400 Subject: [release-branch.go1.15] runtime: non-strict InlTreeIndex lookup in expandFinalInlineFrame This is a follow-up to golang.org/cl/301369, which made the same change in Frames.Next. The same logic applies here: a profile stack may have been truncated at an invalid PC provided by cgoTraceback. expandFinalInlineFrame will then try to lookup the inline tree and crash. The same fix applies as well: upon encountering a bad PC, simply leave it as-is and move on. For #44971 For #45480 Fixes #45481 Change-Id: I2823c67a1f3425466b05384cc6d30f5fc8ee6ddc Reviewed-on: https://go-review.googlesource.com/c/go/+/309109 Reviewed-by: Michael Knyszek Trust: Michael Pratt (cherry picked from commit aad13cbb749d1e6c085ff0556d306de1a2d5d063) Reviewed-on: https://go-review.googlesource.com/c/go/+/309550 Run-TryBot: Michael Pratt Reviewed-by: Cherry Zhang TryBot-Result: Go Bot --- src/runtime/symtab.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index c77d513e74..75772f4fd8 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -185,7 +185,9 @@ func runtime_expandFinalInlineFrame(stk []uintptr) []uintptr { var cache pcvalueCache inltree := (*[1 << 20]inlinedCall)(inldata) for { - ix := pcdatavalue(f, _PCDATA_InlTreeIndex, tracepc, &cache) + // Non-strict as cgoTraceback may have added bogus PCs + // with a valid funcInfo but invalid PCDATA. + ix := pcdatavalue1(f, _PCDATA_InlTreeIndex, tracepc, &cache, false) if ix < 0 { break } -- cgit v1.2.3-54-g00ecf From ba7cac469b399b36e8d3e40ac57eb11688c53e00 Mon Sep 17 00:00:00 2001 From: Clément Chigot Date: Thu, 1 Apr 2021 10:06:05 +0200 Subject: [release-branch.go1.15] runtime/pprof: skip tests for AIX Most of the time, the pprof tests are passing, except for the builder. The reason is still unknown but I'd rather release the builder to avoid missing other more important bugs. Updates #45170 Change-Id: I667543ee1ae309b7319c5b3676a0901b4d0ecf2e Reviewed-on: https://go-review.googlesource.com/c/go/+/306489 Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Cherry Zhang Trust: Lynn Boger (cherry picked from commit 7bfd681c2f11918c6245ad2906b2efc12eda2914) Reviewed-on: https://go-review.googlesource.com/c/go/+/317369 Reviewed-by: Heschi Kreinick Trust: Dmitri Shuralyov Run-TryBot: Dmitri Shuralyov --- src/runtime/pprof/pprof_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go index 7149bfb31f..9c1c097206 100644 --- a/src/runtime/pprof/pprof_test.go +++ b/src/runtime/pprof/pprof_test.go @@ -280,7 +280,8 @@ func testCPUProfile(t *testing.T, matches matchFunc, need []string, avoid []stri broken := false switch runtime.GOOS { - case "darwin", "dragonfly", "netbsd", "illumos", "solaris": + // See https://golang.org/issue/45170 for AIX. + case "darwin", "dragonfly", "netbsd", "illumos", "solaris", "aix": broken = true case "openbsd": if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" { -- cgit v1.2.3-54-g00ecf From 07d8cba9e15f5c5a3b0462a9215dbeac0cebf027 Mon Sep 17 00:00:00 2001 From: Heschi Kreinick Date: Thu, 6 May 2021 10:16:50 -0400 Subject: [release-branch.go1.15] go1.15.12 Change-Id: I2d5e242a8324ae76e9d78b94cbc2825561b0c2de Reviewed-on: https://go-review.googlesource.com/c/go/+/317650 Run-TryBot: Heschi Kreinick TryBot-Result: Go Bot Reviewed-by: Carlos Amedee Trust: Carlos Amedee Trust: Heschi Kreinick --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c25f9907d4..1a6490f14b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -go1.15.11 \ No newline at end of file +go1.15.12 \ No newline at end of file -- cgit v1.2.3-54-g00ecf