Skip to content

Commit 9465878

Browse files
author
Bryan C. Mills
committed
time: fix zoneinfo.zip locating logic when built with -trimpath
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 <[email protected]> Run-TryBot: Bryan Mills <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-by: Russ Cox <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent a682a5c commit 9465878

17 files changed

+98
-62
lines changed

src/time/export_android_test.go

+8-4
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@
44

55
package time
66

7-
func ForceAndroidTzdataForTest(tzdata bool) {
8-
forceZipFileForTesting(false)
9-
if tzdata {
10-
zoneSources = zoneSources[:len(zoneSources)-1]
7+
func ForceAndroidTzdataForTest() (undo func()) {
8+
allowGorootSource = false
9+
origLoadFromEmbeddedTZData := loadFromEmbeddedTZData
10+
loadFromEmbeddedTZData = nil
11+
12+
return func() {
13+
allowGorootSource = true
14+
loadFromEmbeddedTZData = origLoadFromEmbeddedTZData
1115
}
1216
}

src/time/export_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ func ResetZoneinfoForTesting() {
2828
}
2929

3030
var (
31-
ForceZipFileForTesting = forceZipFileForTesting
31+
DisablePlatformSources = disablePlatformSources
32+
GorootZoneSource = gorootZoneSource
3233
ParseTimeZone = parseTimeZone
3334
SetMono = (*Time).setMono
3435
GetMono = (*Time).mono

src/time/format_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -408,8 +408,8 @@ func TestParseInLocation(t *testing.T) {
408408
}
409409

410410
func TestLoadLocationZipFile(t *testing.T) {
411-
ForceZipFileForTesting(true)
412-
defer ForceZipFileForTesting(false)
411+
undo := DisablePlatformSources()
412+
defer undo()
413413

414414
_, err := LoadLocation("Australia/Sydney")
415415
if err != nil {

src/time/internal_test.go

+13-8
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,31 @@
55
package time
66

77
func init() {
8-
// force US/Pacific for time zone tests
8+
// Force US/Pacific for time zone tests.
99
ForceUSPacificForTesting()
1010
}
1111

1212
func initTestingZone() {
13-
z, err := loadLocation("America/Los_Angeles", zoneSources[len(zoneSources)-1:])
13+
// For hermeticity, use only tzinfo source from the test's GOROOT,
14+
// not the system sources and not whatever GOROOT may happen to be
15+
// set in the process's environment (if any).
16+
// This test runs in GOROOT/src/time, so GOROOT is "../..",
17+
// but it is theoretically possible
18+
sources := []string{"../../lib/time/zoneinfo.zip"}
19+
z, err := loadLocation("America/Los_Angeles", sources)
1420
if err != nil {
1521
panic("cannot load America/Los_Angeles for testing: " + err.Error() + "; you may want to use -tags=timetzdata")
1622
}
1723
z.name = "Local"
1824
localLoc = *z
1925
}
2026

21-
var OrigZoneSources = zoneSources
27+
var origPlatformZoneSources []string = platformZoneSources
2228

23-
func forceZipFileForTesting(zipOnly bool) {
24-
zoneSources = make([]string, len(OrigZoneSources))
25-
copy(zoneSources, OrigZoneSources)
26-
if zipOnly {
27-
zoneSources = zoneSources[len(zoneSources)-1:]
29+
func disablePlatformSources() (undo func()) {
30+
platformZoneSources = nil
31+
return func() {
32+
platformZoneSources = origPlatformZoneSources
2833
}
2934
}
3035

src/time/time_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -1557,8 +1557,8 @@ func TestConcurrentTimerResetStop(t *testing.T) {
15571557
}
15581558

15591559
func TestTimeIsDST(t *testing.T) {
1560-
ForceZipFileForTesting(true)
1561-
defer ForceZipFileForTesting(false)
1560+
undo := DisablePlatformSources()
1561+
defer undo()
15621562

15631563
tzWithDST, err := LoadLocation("Australia/Sydney")
15641564
if err != nil {
@@ -1619,8 +1619,8 @@ func TestTimeAddSecOverflow(t *testing.T) {
16191619

16201620
// Issue 49284: time: ParseInLocation incorrectly because of Daylight Saving Time
16211621
func TestTimeWithZoneTransition(t *testing.T) {
1622-
ForceZipFileForTesting(true)
1623-
defer ForceZipFileForTesting(false)
1622+
undo := DisablePlatformSources()
1623+
defer undo()
16241624

16251625
loc, err := LoadLocation("Asia/Shanghai")
16261626
if err != nil {

src/time/tzdata_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ var zones = []string{
1717
}
1818

1919
func TestEmbeddedTZData(t *testing.T) {
20-
time.ForceZipFileForTesting(true)
21-
defer time.ForceZipFileForTesting(false)
20+
undo := time.DisablePlatformSources()
21+
defer undo()
2222

2323
for _, zone := range zones {
2424
ref, err := time.LoadLocation(zone)

src/time/zoneinfo.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,7 @@ func LoadLocation(name string) (*Location, error) {
665665
firstErr = err
666666
}
667667
}
668-
if z, err := loadLocation(name, zoneSources); err == nil {
668+
if z, err := loadLocation(name, platformZoneSources); err == nil {
669669
return z, nil
670670
} else if firstErr == nil {
671671
firstErr = err

src/time/zoneinfo_android.go

+10-3
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,12 @@ package time
1010

1111
import (
1212
"errors"
13-
"runtime"
1413
"syscall"
1514
)
1615

17-
var zoneSources = []string{
16+
var platformZoneSources = []string{
1817
"/system/usr/share/zoneinfo/tzdata",
1918
"/data/misc/zoneinfo/current/tzdata",
20-
runtime.GOROOT() + "/lib/time/zoneinfo.zip",
2119
}
2220

2321
func initLocal() {
@@ -29,6 +27,15 @@ func init() {
2927
loadTzinfoFromTzdata = androidLoadTzinfoFromTzdata
3028
}
3129

30+
var allowGorootSource = true
31+
32+
func gorootZoneSource(goroot string) (string, bool) {
33+
if goroot == "" || !allowGorootSource {
34+
return "", false
35+
}
36+
return goroot + "/lib/time/zoneinfo.zip", true
37+
}
38+
3239
func androidLoadTzinfoFromTzdata(file, name string) ([]byte, error) {
3340
const (
3441
headersize = 12 + 3*4

src/time/zoneinfo_android_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import (
1010
)
1111

1212
func TestAndroidTzdata(t *testing.T) {
13-
ForceAndroidTzdataForTest(true)
14-
defer ForceAndroidTzdataForTest(false)
13+
undo := ForceAndroidTzdataForTest()
14+
defer undo()
1515
if _, err := LoadLocation("America/Los_Angeles"); err != nil {
1616
t.Error(err)
1717
}

src/time/zoneinfo_goroot.go

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2022 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build !ios && !android
6+
7+
package time
8+
9+
func gorootZoneSource(goroot string) (string, bool) {
10+
if goroot == "" {
11+
return "", false
12+
}
13+
return goroot + "/lib/time/zoneinfo.zip", true
14+
}

src/time/zoneinfo_ios.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,20 @@
77
package time
88

99
import (
10-
"runtime"
1110
"syscall"
1211
)
1312

14-
var zoneSources = []string{
15-
getZoneRoot() + "/zoneinfo.zip",
16-
}
13+
var platformZoneSources []string // none on iOS
1714

18-
func getZoneRoot() string {
15+
func gorootZoneSource(goroot string) (string, bool) {
1916
// The working directory at initialization is the root of the
2017
// app bundle: "/private/.../bundlename.app". That's where we
2118
// keep zoneinfo.zip for tethered iOS builds.
2219
// For self-hosted iOS builds, the zoneinfo.zip is in GOROOT.
23-
roots := []string{runtime.GOROOT() + "/lib/time"}
20+
var roots []string
21+
if goroot != "" {
22+
roots = append(roots, goroot+"/lib/time")
23+
}
2424
wd, err := syscall.Getwd()
2525
if err == nil {
2626
roots = append(roots, wd)
@@ -33,10 +33,10 @@ func getZoneRoot() string {
3333
}
3434
defer syscall.Close(fd)
3535
if err := syscall.Fstat(fd, &st); err == nil {
36-
return r
36+
return r + "/zoneinfo.zip", true
3737
}
3838
}
39-
return "/XXXNOEXIST"
39+
return "", false
4040
}
4141

4242
func initLocal() {

src/time/zoneinfo_js.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,13 @@
77
package time
88

99
import (
10-
"runtime"
1110
"syscall/js"
1211
)
1312

14-
var zoneSources = []string{
13+
var platformZoneSources = []string{
1514
"/usr/share/zoneinfo/",
1615
"/usr/share/lib/zoneinfo/",
1716
"/usr/lib/locale/TZ/",
18-
runtime.GOROOT() + "/lib/time/zoneinfo.zip",
1917
}
2018

2119
func initLocal() {

src/time/zoneinfo_plan9.go

+1-4
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,10 @@
77
package time
88

99
import (
10-
"runtime"
1110
"syscall"
1211
)
1312

14-
var zoneSources = []string{
15-
runtime.GOROOT() + "/lib/time/zoneinfo.zip",
16-
}
13+
var platformZoneSources []string // none on Plan 9
1714

1815
func isSpace(r rune) bool {
1916
return r == ' ' || r == '\t' || r == '\n'

src/time/zoneinfo_read.go

+14-3
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ func loadTzinfo(name string, source string) ([]byte, error) {
528528
// and parsed is returned as a Location.
529529
func loadLocation(name string, sources []string) (z *Location, firstErr error) {
530530
for _, source := range sources {
531-
var zoneData, err = loadTzinfo(name, source)
531+
zoneData, err := loadTzinfo(name, source)
532532
if err == nil {
533533
if z, err = LoadLocationFromTZData(name, zoneData); err == nil {
534534
return z, nil
@@ -539,9 +539,20 @@ func loadLocation(name string, sources []string) (z *Location, firstErr error) {
539539
}
540540
}
541541
if loadFromEmbeddedTZData != nil {
542-
zonedata, err := loadFromEmbeddedTZData(name)
542+
zoneData, err := loadFromEmbeddedTZData(name)
543543
if err == nil {
544-
if z, err = LoadLocationFromTZData(name, []byte(zonedata)); err == nil {
544+
if z, err = LoadLocationFromTZData(name, []byte(zoneData)); err == nil {
545+
return z, nil
546+
}
547+
}
548+
if firstErr == nil && err != syscall.ENOENT {
549+
firstErr = err
550+
}
551+
}
552+
if source, ok := gorootZoneSource(runtime.GOROOT()); ok {
553+
zoneData, err := loadTzinfo(name, source)
554+
if err == nil {
555+
if z, err = LoadLocationFromTZData(name, zoneData); err == nil {
545556
return z, nil
546557
}
547558
}

src/time/zoneinfo_test.go

+13-9
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ func TestLoadLocationValidatesNames(t *testing.T) {
6666
}
6767

6868
func TestVersion3(t *testing.T) {
69-
time.ForceZipFileForTesting(true)
70-
defer time.ForceZipFileForTesting(false)
69+
undo := time.DisablePlatformSources()
70+
defer undo()
7171
_, err := time.LoadLocation("Asia/Jerusalem")
7272
if err != nil {
7373
t.Fatal(err)
@@ -78,8 +78,8 @@ func TestVersion3(t *testing.T) {
7878
// transition time. To do this we explicitly check early dates in a
7979
// couple of specific timezones.
8080
func TestFirstZone(t *testing.T) {
81-
time.ForceZipFileForTesting(true)
82-
defer time.ForceZipFileForTesting(false)
81+
undo := time.DisablePlatformSources()
82+
defer undo()
8383

8484
const format = "Mon, 02 Jan 2006 15:04:05 -0700 (MST)"
8585
var tests = []struct {
@@ -128,16 +128,20 @@ func TestLocationNames(t *testing.T) {
128128
}
129129

130130
func TestLoadLocationFromTZData(t *testing.T) {
131-
time.ForceZipFileForTesting(true)
132-
defer time.ForceZipFileForTesting(false)
131+
undo := time.DisablePlatformSources()
132+
defer undo()
133133

134134
const locationName = "Asia/Jerusalem"
135135
reference, err := time.LoadLocation(locationName)
136136
if err != nil {
137137
t.Fatal(err)
138138
}
139139

140-
tzinfo, err := time.LoadTzinfo(locationName, time.OrigZoneSources[len(time.OrigZoneSources)-1])
140+
gorootSource, ok := time.GorootZoneSource("../..")
141+
if !ok {
142+
t.Fatal("Failed to locate tzinfo source in GOROOT.")
143+
}
144+
tzinfo, err := time.LoadTzinfo(locationName, gorootSource)
141145
if err != nil {
142146
t.Fatal(err)
143147
}
@@ -153,8 +157,8 @@ func TestLoadLocationFromTZData(t *testing.T) {
153157

154158
// Issue 30099.
155159
func TestEarlyLocation(t *testing.T) {
156-
time.ForceZipFileForTesting(true)
157-
defer time.ForceZipFileForTesting(false)
160+
undo := time.DisablePlatformSources()
161+
defer undo()
158162

159163
const locName = "America/New_York"
160164
loc, err := time.LoadLocation(locName)

src/time/zoneinfo_unix.go

+2-4
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,15 @@
1212
package time
1313

1414
import (
15-
"runtime"
1615
"syscall"
1716
)
1817

1918
// Many systems use /usr/share/zoneinfo, Solaris 2 has
2019
// /usr/share/lib/zoneinfo, IRIX 6 has /usr/lib/locale/TZ.
21-
var zoneSources = []string{
20+
var platformZoneSources = []string{
2221
"/usr/share/zoneinfo/",
2322
"/usr/share/lib/zoneinfo/",
2423
"/usr/lib/locale/TZ/",
25-
runtime.GOROOT() + "/lib/time/zoneinfo.zip",
2624
}
2725

2826
func initLocal() {
@@ -57,7 +55,7 @@ func initLocal() {
5755
return
5856
}
5957
} else if tz != "" && tz != "UTC" {
60-
if z, err := loadLocation(tz, zoneSources); err == nil {
58+
if z, err := loadLocation(tz, platformZoneSources); err == nil {
6159
localLoc = *z
6260
return
6361
}

src/time/zoneinfo_windows.go

+1-4
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,10 @@ package time
77
import (
88
"errors"
99
"internal/syscall/windows/registry"
10-
"runtime"
1110
"syscall"
1211
)
1312

14-
var zoneSources = []string{
15-
runtime.GOROOT() + "/lib/time/zoneinfo.zip",
16-
}
13+
var platformZoneSources []string // none: Windows uses system calls instead
1714

1815
// TODO(rsc): Fall back to copy of zoneinfo files.
1916

0 commit comments

Comments
 (0)