]> Cypherpunks.ru repositories - gostls13.git/commitdiff
time: fix zoneinfo.zip locating logic when built with -trimpath
authorBryan C. Mills <bcmills@google.com>
Thu, 10 Mar 2022 05:19:05 +0000 (00:19 -0500)
committerBryan Mills <bcmills@google.com>
Fri, 18 Mar 2022 20:57:35 +0000 (20:57 +0000)
When the test binary is built with the -trimpath flag,
runtime.GOROOT() is invalid, and must not be used to locate
GOROOT/lib/time/zoneinfo.zip. (We can use other sources instead.)

However, the test for the package expects zoneinfo.zip to definitely
exist. 'go test' runs the test binary in the directory containing its
source code — in this case GOROOT/src/time — so we can use that
information to find the zoneinfo.zip file when runtime.GOROOT isn't
available.

For #51483

Change-Id: I9de35252a988d146b5d746794323214d400e64e5
Reviewed-on: https://go-review.googlesource.com/c/go/+/391814
Trust: Bryan Mills <bcmills@google.com>
Run-TryBot: Bryan Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>

17 files changed:
src/time/export_android_test.go
src/time/export_test.go
src/time/format_test.go
src/time/internal_test.go
src/time/time_test.go
src/time/tzdata_test.go
src/time/zoneinfo.go
src/time/zoneinfo_android.go
src/time/zoneinfo_android_test.go
src/time/zoneinfo_goroot.go [new file with mode: 0644]
src/time/zoneinfo_ios.go
src/time/zoneinfo_js.go
src/time/zoneinfo_plan9.go
src/time/zoneinfo_read.go
src/time/zoneinfo_test.go
src/time/zoneinfo_unix.go
src/time/zoneinfo_windows.go

index f80e7da717660f320dde6c40c594181350cdf40c..17e021923cc45a5f609dc80261951314b401c684 100644 (file)
@@ -4,9 +4,13 @@
 
 package time
 
-func ForceAndroidTzdataForTest(tzdata bool) {
-       forceZipFileForTesting(false)
-       if tzdata {
-               zoneSources = zoneSources[:len(zoneSources)-1]
+func ForceAndroidTzdataForTest() (undo func()) {
+       allowGorootSource = false
+       origLoadFromEmbeddedTZData := loadFromEmbeddedTZData
+       loadFromEmbeddedTZData = nil
+
+       return func() {
+               allowGorootSource = true
+               loadFromEmbeddedTZData = origLoadFromEmbeddedTZData
        }
 }
index 9baad60a92aaf3f7078936cc7009384295e388a5..b450aec01f9bec556ffecf33eaec4f4ce365b370 100644 (file)
@@ -28,7 +28,8 @@ func ResetZoneinfoForTesting() {
 }
 
 var (
-       ForceZipFileForTesting = forceZipFileForTesting
+       DisablePlatformSources = disablePlatformSources
+       GorootZoneSource       = gorootZoneSource
        ParseTimeZone          = parseTimeZone
        SetMono                = (*Time).setMono
        GetMono                = (*Time).mono
index db95536390040ba692271eef48f0bf5078c57672..ab72fae32318191a834957c1c925f07559dd553e 100644 (file)
@@ -408,8 +408,8 @@ func TestParseInLocation(t *testing.T) {
 }
 
 func TestLoadLocationZipFile(t *testing.T) {
-       ForceZipFileForTesting(true)
-       defer ForceZipFileForTesting(false)
+       undo := DisablePlatformSources()
+       defer undo()
 
        _, err := LoadLocation("Australia/Sydney")
        if err != nil {
index f0dddb737350045a89317ad5c33a1ca1075c3db7..4c4a720f74e4e2a1db067b1be0ae8890a93ed543 100644 (file)
@@ -5,12 +5,18 @@
 package time
 
 func init() {
-       // force US/Pacific for time zone tests
+       // Force US/Pacific for time zone tests.
        ForceUSPacificForTesting()
 }
 
 func initTestingZone() {
-       z, err := loadLocation("America/Los_Angeles", zoneSources[len(zoneSources)-1:])
+       // For hermeticity, use only tzinfo source from the test's GOROOT,
+       // not the system sources and not whatever GOROOT may happen to be
+       // set in the process's environment (if any).
+       // This test runs in GOROOT/src/time, so GOROOT is "../..",
+       // but it is theoretically possible
+       sources := []string{"../../lib/time/zoneinfo.zip"}
+       z, err := loadLocation("America/Los_Angeles", sources)
        if err != nil {
                panic("cannot load America/Los_Angeles for testing: " + err.Error() + "; you may want to use -tags=timetzdata")
        }
@@ -18,13 +24,12 @@ func initTestingZone() {
        localLoc = *z
 }
 
-var OrigZoneSources = zoneSources
+var origPlatformZoneSources []string = platformZoneSources
 
-func forceZipFileForTesting(zipOnly bool) {
-       zoneSources = make([]string, len(OrigZoneSources))
-       copy(zoneSources, OrigZoneSources)
-       if zipOnly {
-               zoneSources = zoneSources[len(zoneSources)-1:]
+func disablePlatformSources() (undo func()) {
+       platformZoneSources = nil
+       return func() {
+               platformZoneSources = origPlatformZoneSources
        }
 }
 
index 6a4049617cb640703835d7b36c82eaae4682f099..ea13ffe3c9470dc5d90c5936b6374855d8f158d2 100644 (file)
@@ -1557,8 +1557,8 @@ func TestConcurrentTimerResetStop(t *testing.T) {
 }
 
 func TestTimeIsDST(t *testing.T) {
-       ForceZipFileForTesting(true)
-       defer ForceZipFileForTesting(false)
+       undo := DisablePlatformSources()
+       defer undo()
 
        tzWithDST, err := LoadLocation("Australia/Sydney")
        if err != nil {
@@ -1619,8 +1619,8 @@ func TestTimeAddSecOverflow(t *testing.T) {
 
 // Issue 49284: time: ParseInLocation incorrectly because of Daylight Saving Time
 func TestTimeWithZoneTransition(t *testing.T) {
-       ForceZipFileForTesting(true)
-       defer ForceZipFileForTesting(false)
+       undo := DisablePlatformSources()
+       defer undo()
 
        loc, err := LoadLocation("Asia/Shanghai")
        if err != nil {
index eb6d6c98a861bc80add17ba5c86c91cd183ecc7b..33c6589d0d7f4b5067612fc74533cce5f15f15ef 100644 (file)
@@ -17,8 +17,8 @@ var zones = []string{
 }
 
 func TestEmbeddedTZData(t *testing.T) {
-       time.ForceZipFileForTesting(true)
-       defer time.ForceZipFileForTesting(false)
+       undo := time.DisablePlatformSources()
+       defer undo()
 
        for _, zone := range zones {
                ref, err := time.LoadLocation(zone)
index 7b39f869e644fb62d90345d5741c861fa40dcb75..b460b9e6c5e964cdfd7c2c28eba790b7ba570d46 100644 (file)
@@ -665,7 +665,7 @@ func LoadLocation(name string) (*Location, error) {
                        firstErr = err
                }
        }
-       if z, err := loadLocation(name, zoneSources); err == nil {
+       if z, err := loadLocation(name, platformZoneSources); err == nil {
                return z, nil
        } else if firstErr == nil {
                firstErr = err
index 237ff202f913ff2566688b7c516a65b7e1c72f47..e4f688dcec5939406d738a87fcc5eb243cf21c3f 100644 (file)
@@ -10,14 +10,12 @@ package time
 
 import (
        "errors"
-       "runtime"
        "syscall"
 )
 
-var zoneSources = []string{
+var platformZoneSources = []string{
        "/system/usr/share/zoneinfo/tzdata",
        "/data/misc/zoneinfo/current/tzdata",
-       runtime.GOROOT() + "/lib/time/zoneinfo.zip",
 }
 
 func initLocal() {
@@ -29,6 +27,15 @@ func init() {
        loadTzinfoFromTzdata = androidLoadTzinfoFromTzdata
 }
 
+var allowGorootSource = true
+
+func gorootZoneSource(goroot string) (string, bool) {
+       if goroot == "" || !allowGorootSource {
+               return "", false
+       }
+       return goroot + "/lib/time/zoneinfo.zip", true
+}
+
 func androidLoadTzinfoFromTzdata(file, name string) ([]byte, error) {
        const (
                headersize = 12 + 3*4
index ba065d10a654814d0c10d3a76b8a3128b8de94d2..f8bd7f7674a0eebbd86338eee3042ff5e71f5019 100644 (file)
@@ -10,8 +10,8 @@ import (
 )
 
 func TestAndroidTzdata(t *testing.T) {
-       ForceAndroidTzdataForTest(true)
-       defer ForceAndroidTzdataForTest(false)
+       undo := ForceAndroidTzdataForTest()
+       defer undo()
        if _, err := LoadLocation("America/Los_Angeles"); err != nil {
                t.Error(err)
        }
diff --git a/src/time/zoneinfo_goroot.go b/src/time/zoneinfo_goroot.go
new file mode 100644 (file)
index 0000000..92bdcf4
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !ios && !android
+
+package time
+
+func gorootZoneSource(goroot string) (string, bool) {
+       if goroot == "" {
+               return "", false
+       }
+       return goroot + "/lib/time/zoneinfo.zip", true
+}
index 7eccabf24924309dfc053dbbb302bd22e34e8997..d6ad073e85dfd959e2fb3a42bebfb5bcac2d11de 100644 (file)
@@ -7,20 +7,20 @@
 package time
 
 import (
-       "runtime"
        "syscall"
 )
 
-var zoneSources = []string{
-       getZoneRoot() + "/zoneinfo.zip",
-}
+var platformZoneSources []string // none on iOS
 
-func getZoneRoot() string {
+func gorootZoneSource(goroot string) (string, bool) {
        // The working directory at initialization is the root of the
        // app bundle: "/private/.../bundlename.app". That's where we
        // keep zoneinfo.zip for tethered iOS builds.
        // For self-hosted iOS builds, the zoneinfo.zip is in GOROOT.
-       roots := []string{runtime.GOROOT() + "/lib/time"}
+       var roots []string
+       if goroot != "" {
+               roots = append(roots, goroot+"/lib/time")
+       }
        wd, err := syscall.Getwd()
        if err == nil {
                roots = append(roots, wd)
@@ -33,10 +33,10 @@ func getZoneRoot() string {
                }
                defer syscall.Close(fd)
                if err := syscall.Fstat(fd, &st); err == nil {
-                       return r
+                       return r + "/zoneinfo.zip", true
                }
        }
-       return "/XXXNOEXIST"
+       return "", false
 }
 
 func initLocal() {
index d0aefb908898f930b5bfe68948fbd03571e502c2..06306cfd54d160f0fc7fc1b0aa08ea54fdf5e82e 100644 (file)
@@ -7,15 +7,13 @@
 package time
 
 import (
-       "runtime"
        "syscall/js"
 )
 
-var zoneSources = []string{
+var platformZoneSources = []string{
        "/usr/share/zoneinfo/",
        "/usr/share/lib/zoneinfo/",
        "/usr/lib/locale/TZ/",
-       runtime.GOROOT() + "/lib/time/zoneinfo.zip",
 }
 
 func initLocal() {
index 4ae718c59e1fc0abc2f7bf13782e9885920f3b16..5d432fe297dd9eaa664cc151dd35a3a97fc7fb9b 100644 (file)
@@ -7,13 +7,10 @@
 package time
 
 import (
-       "runtime"
        "syscall"
 )
 
-var zoneSources = []string{
-       runtime.GOROOT() + "/lib/time/zoneinfo.zip",
-}
+var platformZoneSources []string // none on Plan 9
 
 func isSpace(r rune) bool {
        return r == ' ' || r == '\t' || r == '\n'
index b9830265e12b70f9e18ff171b34e54e6a4bb9882..90814ad36a1ad437e91c105ee74ba90c091954e5 100644 (file)
@@ -528,7 +528,7 @@ func loadTzinfo(name string, source string) ([]byte, error) {
 // and parsed is returned as a Location.
 func loadLocation(name string, sources []string) (z *Location, firstErr error) {
        for _, source := range sources {
-               var zoneData, err = loadTzinfo(name, source)
+               zoneData, err := loadTzinfo(name, source)
                if err == nil {
                        if z, err = LoadLocationFromTZData(name, zoneData); err == nil {
                                return z, nil
@@ -539,9 +539,20 @@ func loadLocation(name string, sources []string) (z *Location, firstErr error) {
                }
        }
        if loadFromEmbeddedTZData != nil {
-               zonedata, err := loadFromEmbeddedTZData(name)
+               zoneData, err := loadFromEmbeddedTZData(name)
                if err == nil {
-                       if z, err = LoadLocationFromTZData(name, []byte(zonedata)); err == nil {
+                       if z, err = LoadLocationFromTZData(name, []byte(zoneData)); err == nil {
+                               return z, nil
+                       }
+               }
+               if firstErr == nil && err != syscall.ENOENT {
+                       firstErr = err
+               }
+       }
+       if source, ok := gorootZoneSource(runtime.GOROOT()); ok {
+               zoneData, err := loadTzinfo(name, source)
+               if err == nil {
+                       if z, err = LoadLocationFromTZData(name, zoneData); err == nil {
                                return z, nil
                        }
                }
index f032aa7924ddba766911d8f79fbfc1c39f27e345..0a5ce6d7325d597260e428bb93daee5c57350ee3 100644 (file)
@@ -66,8 +66,8 @@ func TestLoadLocationValidatesNames(t *testing.T) {
 }
 
 func TestVersion3(t *testing.T) {
-       time.ForceZipFileForTesting(true)
-       defer time.ForceZipFileForTesting(false)
+       undo := time.DisablePlatformSources()
+       defer undo()
        _, err := time.LoadLocation("Asia/Jerusalem")
        if err != nil {
                t.Fatal(err)
@@ -78,8 +78,8 @@ func TestVersion3(t *testing.T) {
 // transition time. To do this we explicitly check early dates in a
 // couple of specific timezones.
 func TestFirstZone(t *testing.T) {
-       time.ForceZipFileForTesting(true)
-       defer time.ForceZipFileForTesting(false)
+       undo := time.DisablePlatformSources()
+       defer undo()
 
        const format = "Mon, 02 Jan 2006 15:04:05 -0700 (MST)"
        var tests = []struct {
@@ -128,8 +128,8 @@ func TestLocationNames(t *testing.T) {
 }
 
 func TestLoadLocationFromTZData(t *testing.T) {
-       time.ForceZipFileForTesting(true)
-       defer time.ForceZipFileForTesting(false)
+       undo := time.DisablePlatformSources()
+       defer undo()
 
        const locationName = "Asia/Jerusalem"
        reference, err := time.LoadLocation(locationName)
@@ -137,7 +137,11 @@ func TestLoadLocationFromTZData(t *testing.T) {
                t.Fatal(err)
        }
 
-       tzinfo, err := time.LoadTzinfo(locationName, time.OrigZoneSources[len(time.OrigZoneSources)-1])
+       gorootSource, ok := time.GorootZoneSource("../..")
+       if !ok {
+               t.Fatal("Failed to locate tzinfo source in GOROOT.")
+       }
+       tzinfo, err := time.LoadTzinfo(locationName, gorootSource)
        if err != nil {
                t.Fatal(err)
        }
@@ -153,8 +157,8 @@ func TestLoadLocationFromTZData(t *testing.T) {
 
 // Issue 30099.
 func TestEarlyLocation(t *testing.T) {
-       time.ForceZipFileForTesting(true)
-       defer time.ForceZipFileForTesting(false)
+       undo := time.DisablePlatformSources()
+       defer undo()
 
        const locName = "America/New_York"
        loc, err := time.LoadLocation(locName)
index 23f8b3cdb4af2b81852a24168a09f29a10dcb2ff..6414be3879af495a5dcd05bc308b1065949a23c7 100644 (file)
 package time
 
 import (
-       "runtime"
        "syscall"
 )
 
 // Many systems use /usr/share/zoneinfo, Solaris 2 has
 // /usr/share/lib/zoneinfo, IRIX 6 has /usr/lib/locale/TZ.
-var zoneSources = []string{
+var platformZoneSources = []string{
        "/usr/share/zoneinfo/",
        "/usr/share/lib/zoneinfo/",
        "/usr/lib/locale/TZ/",
-       runtime.GOROOT() + "/lib/time/zoneinfo.zip",
 }
 
 func initLocal() {
@@ -57,7 +55,7 @@ func initLocal() {
                                return
                        }
                } else if tz != "" && tz != "UTC" {
-                       if z, err := loadLocation(tz, zoneSources); err == nil {
+                       if z, err := loadLocation(tz, platformZoneSources); err == nil {
                                localLoc = *z
                                return
                        }
index ba66f90ffeaf20cf6cdfee762f3782a4be97f73e..76d79759f7de9cde67bfc22beea3954046882a50 100644 (file)
@@ -7,13 +7,10 @@ package time
 import (
        "errors"
        "internal/syscall/windows/registry"
-       "runtime"
        "syscall"
 )
 
-var zoneSources = []string{
-       runtime.GOROOT() + "/lib/time/zoneinfo.zip",
-}
+var platformZoneSources []string // none: Windows uses system calls instead
 
 // TODO(rsc): Fall back to copy of zoneinfo files.