Go 1.15 發行說明

Go 1.15 簡介

最新的 Go 發行,1.15 版,在 Go 1.14 之後六個月登場。其大多數的異動在於工具鏈、執行時期環境和函式庫的實作。一如往常,本發行版本維持 Go 1 相容性的承諾。我們預期幾乎所有 Go 程式都能像以前一樣繼續編譯和執行。

Go 1.15 包含 大幅改善連結器,增進 小物件在高核心數的配置,以及將 X.509 CommonName 標示為已不建議使用。GOPROXY 現在支援跳過會傳回錯誤的代理伺服器,而且已新增一個新的 內嵌 tzdata 套件

語言的異動

語言未有異動。

移植

Darwin

就像在 Go 1.14 發行說明中 宣布,Go 1.15 要求 macOS 10.12 Sierra 或之後的版本;已經終止支援先前的版本。

公告 所述,Go 1.15 不再支援 macOS、iOS、iPadOS、watchOS 和 tvOS 的 32 位元二進制檔案(darwin/386darwin/arm 埠)。Go 仍舊支援 64 位元的 darwin/amd64darwin/arm64 埠。

Windows

如果提供 -buildmode=pie 指令碼/連結標記,Go 現在會產生 Windows ASLR 可執行檔。預設情況下,Go 指令碼會在 Windows 上使用 -buildmode=pie

-race-msan 標記現在會一律啟用 -d=checkptr,用於檢查 unsafe.Pointer 的用法。以前只有 Windows 之外的所有作業系統才會執行這個動作。

Go 建置的 DLL 不再會導致該程序在收到訊號(例如,終端的 Ctrl-C)時結束運作。

Android

在為 Android 連結二進制檔案時,Go 1.15 會明確選取 NDK 最近版本中可用的 lld 連結器。lld 連結器可避免發生某些裝置的崩潰,計畫在未來的 NDK 版本中成為預設的 NDK 連結器。

OpenBSD

Go 1.15 在 GOARCH=armGOARCH=arm64 中新增 OpenBSD 6.7 支援。之前版本的 Go 已在 GOARCH=386GOARCH=amd64 中支援 OpenBSD 6.7。

RISC-V

對於 Linux 上的 64 位元 RISC-V 埠(GOOS=linuxGOARCH=riscv64),在穩定性和效能方面均有顯著進步。現在也支援非同步先占。

386

Go 1.15 是最後一個支援 x87 專用浮點硬體(GO386=387)的版本。未來的版本將至少需要 386 上的 SSE2 支援,將 Go 最低 GOARCH=386 需求提高到 2000 年發行的 Intel Pentium 4 或 2003 年發行的 AMD Opteron/Athlon 64。

工具

Go 指令碼

GOPROXY 環境變數現在支援略過會傳回錯誤的代理伺服器。現在可以逗號 (,) 或垂直線字元 (|) 來分隔代理伺服器網址。如果代理伺服器網址後面接著逗號,go 指令碼只會在 404 或 410 HTTP 回應後嘗試清單中的下一個代理伺服器。如果代理伺服器網址後面接著垂直線字元,go 指令碼會在發生任何錯誤後嘗試清單中的下一個代理伺服器。請注意,GOPROXY 的預設值仍維持 https://proxy.golang.org,direct,此值在發生錯誤時不會備援到 direct

go test

變更 -timeout 標記現在會使快取的測試結果失效。對於使用長時間延遲執行測試的快取結果,在 go test 再次使用較短延遲重新喚醒時,將不再統計為通過結果。

標記剖析

各種 go testgo vet 中的 flag 分析問題已經修復。特別是,以 GOFLAGS 指定的 flag 被更一致地處理,而 -outputdir flag 現在會將相對路徑解譯為相對應於 go 命令的工作目錄(而非每個個別測試的工作目錄)。

模組快取

模組快取的位置現在可以使用 GOMODCACHE 環境變數設定。GOMODCACHE 的預設值是 GOPATH[0]/pkg/mod,即在本次變更之前的模組快取位置。

現在有一個對策可以解決 go 命令在訪問模組快取時產生的 Windows「存取遭拒」錯誤,這是因為外部程式同時掃描檔案系統而造成的(請參閱 第 36568 號問題)。此對策並非預設啟用,因為當低於 1.14.2 和 1.13.10 的 Go 版本會同時與相同的模組快取執行時,使用這個對策並不安全。可以透過明確設定環境變數 GODEBUG=modcacheunzipinplace=1 來啟用。

Vet

針對 string(x) 發出新的警告

Vet 工具現在會針對格式為 string(x) 的轉換發出警告,其中 x 具有 runebyte 以外的整數類型。根據 Go 的經驗顯示,許多這種形式的轉換錯誤假設 string(x) 會評估為整數 x 的字串表示方式。它實際上會評估為包含 x 值的 UTF-8 編碼的字串。例如,string(9786) 不會評估為字串 "9786";它會評估為字串 "\xe2\x98\xba",即 "☺"

正確使用 string(x) 的程式碼可以改寫為 string(rune(x))。或者,在某些情況下,使用適當的 byte 區塊 buf 呼叫 utf8.EncodeRune(buf, x) 也許是可行的解決方案。其他程式碼最有可能會使用 strconv.Itoafmt.Sprint

使用 go test 時,預設會啟用這個新的 vet 檢查。

我們正在考慮在未來的 Go 版本中禁止此轉換。換句話說,語言將會變更為只允許 xrunebyte 時,才能將 x 整數用於 string(x)。此類語言變更無法向後相容。我們使用這個 vet 檢查作為朝向變更語言邁出的第一步。

針對不可能的介面轉換發出新的警告

只要型別斷言總是會失敗,vet 工具現在會對從一個介面型別到另一個介面型別的型別斷言發出警告。這將會發生在兩個介面型別實作了相同名稱的方法,但簽章型別不同時。

沒有理由要寫一個會總是失敗的型別斷言,因此觸發這個 vet 檢查的任何程式碼都應該重寫。

使用 go test 時,預設會啟用這個新的 vet 檢查。

我們正在考慮在未來的 Go 版本中禁止不可能的介面型別斷言。這樣的語言變更不會向後相容。我們使用這個 vet 檢查作為朝語言變更邁出的第一步。

執行階段

如果使用型別來自下列任何一項的值來呼叫 panicboolcomplex64complex128float32float64intint8int16int32int64stringuintuint8uint16uint32uint64uintptr,則會印出該值,而不會只是印出它的位址。之前,只有這些精確型別的值才會這樣。

在 Unix 系統上,如果使用 kill 指令或 kill 系統呼叫來將 SIGSEGVSIGBUSSIGFPE 訊號傳送給 Go 程式,而且訊號不是透過 os/signal.Notify 來處理,那麼 Go 程式現在會可靠地使用堆疊追蹤進行崩潰。在較早的版本中,行為是不可預測的。

在高核心數時配置小型物件現在成效大幅提升,而且最差情況的延遲時間更低。

將小型整數值轉換為介面值不再會造成配置。

非封閉通道上的非封鎖接收現在與開啟通道上的非封鎖接收表現一樣好。

編譯器

套件 unsafe安全規則 允許在呼叫特定函式時將 unsafe.Pointer 轉換為 uintptr。先前,編譯器有時允許多重串接轉換(例如 syscall.Syscall(…, uintptr(uintptr(ptr)), …))。編譯器現在只要求進行一次轉換。使用多重轉換的程式碼應更新以滿足這些安全規則。

藉由移除特定類型的 GC 超資料並更積極地移除未使用的類型的超資料,Go 1.15 相較於 Go 1.14 縮減了大約5% 的一般二進位檔案大小。

GOARCH=amd64 上,工具鏈現在緩解了 Intel CPU 錯誤 SKX102,方法是將函式對齊到 32 位元組的邊界並填補跳躍指令。儘管此填補會增加二進位檔案大小,但上述的二進位檔案大小改進已超過了這個缺點。

Go 1.15 在編譯器和組譯器中新增 -spectre 旗標,以啟用 Spectre 緩解程式。這些幾乎不需要用到,主要是作為一種「縱深防禦」機制。詳細資訊請參閱 Spectre Wiki 頁面

編譯器現在會拒絕對它們所應用的宣告沒有任何意義的 //go: 編譯器指令,並產生「放錯位置的編譯器指令」錯誤。這些放錯位置的指令在先前會損壞,但會被編譯器靜默忽略。

編譯器的 -json 最佳化記錄現在會報告大型 (>= 128 位元組) 的拷貝,並包含逸出分析決定的說明。

連結器

此版本包含對 Go 連結器的重大改進,可減少連結器資源用量 (時間和記憶體) 並提高程式碼健全性/可維護性。

對於一組具有代表性的大型 Go 程式,連結的速度快了 20%,在運作於 amd64 架構的基於 ELF 的 OS (Linux、FreeBSD、NetBSD、OpenBSD、Dragonfly 和 Solaris) 上平均需要的記憶體少了 30%,而其他架構/OS 組合則有更顯著的改進。

連結器效能改善的主要因素是重新設計的物件檔格式,以及重新調整內部階段以增加並行性 (例如,同時將重定位套用到符號)。Go 1.15 中的物件檔比 1.14 版本的等效檔略大。

這些變更是多版本專案中 現代化 Go 連結器 的一部分,表示未來版本預期會有其他連結器改進。

連結器現在預設 -buildmode=pie 的內部連結模式為 linux/amd64linux/arm64,因此這些組態不再需要 C 連結器。外部連結模式 (在 Go 1.14 中是 -buildmode=pie 的預設值) 仍可透過 -ldflags=-linkmode=external 旗標來要求。

Objdump

objdump 工具現在支援使用 -gnu 旗標以 GNU 組譯語法進行反組譯。

標準函式庫

新的 embedded tzdata 套件

Go 1.15 包含新套件 time/tzdata,它允許將時區資料庫內嵌到程式中。匯入此套件 (例如 import _ "time/tzdata") 可讓程式找到時區資訊,即使在本地系統上沒有時區資料庫時也是如此。您也可以使用 -tags timetzdata 進行建置以內嵌時區資料庫。任一種方式都會增加程式大約 800 KB 的大小。

Cgo

Go 1.15 會將 C 型別 EGLConfig 轉譯到 Go 型別 uintptr。此變更是類似 Go 1.12 及更新版本處理 EGLDisplay、Darwin 的 CorFoundation 和 Java 的 JNI 型別的方式。請參閱 cgo 文件 以取得更多資訊。

在 Go 1.15.3 及之後的版本中,cgo 將不允許 Go 程式碼在堆疊或記憶體區塊中配置未定義的結構體型別(一個僅定義為 struct S; 或類似形式的 C 結構體)。Go 程式碼僅會被允許使用指向那些型別的指標。配置此類結構體的執行個體和傳遞指標或完整的結構體值給 C 程式碼一直是不安全的且不太可能正確執行;現在已禁止此類行為。修正方式是重新編寫 Go 程式碼以僅使用指標或確保 Go 程式碼會看到結構體的完整定義(包括適當的 C 標頭檔)。

X.509 CommonName 遭棄用

現在會在預設情況下停用過時的 X.509 憑證在沒有主旨另類名稱的情況下將 `CommonName` 欄位當作主機名稱的過時傳統行為。它可以透過將值 `x509ignoreCN=0` 新增到 `GODEBUG` 環境變數來暫時重新啟用它。

請注意,如果 `CommonName` 是無效的主機名稱,則會一律忽略它,與 `GODEBUG` 設定無關。無效名稱包含包含字母、數字、連字號和底線以外的任何字元以及帶有空標籤或尾隨點的名稱。

函式庫的細微變更

一如往常,函式庫有各種細微的變更和更新,並考量到 Go 1 相容性承諾

bufio

Scanner 搭配無效的 io.Reader 使用,而該無效的讀取器對 `Read` 傳回負數時,Scanner 將不再發生恐慌,而改為傳回新錯誤 ErrBadReadCount

context

建立使用空父項的派生 `Context` 現在明確遭到禁止。嘗試以 WithValueWithDeadlineWithCancel 函式這樣做會造成恐慌。

crypto

crypto/rsacrypto/ecdsacrypto/ed25519 套件中的 PrivateKeyPublicKey 型別現在有一個 Equal 方法,以比較鍵是否相等或建立公鑰類型安全的介面。方法簽章與 go-cmp 的相等性定義相容

Hash 現在實作 fmt.Stringer

crypto/ecdsa

新的 SignASN1VerifyASN1 函式允許以標準的 ASN.1 DER 編碼產生和驗證 ECDSA 簽章。

crypto/elliptic

新的 MarshalCompressedUnmarshalCompressed 函式允許以壓縮的格式進行編碼和解碼 NIST 橢圓曲線點。

crypto/rsa

根據 RFC 8017,VerifyPKCS1v15 現在拒絕無效的較短簽章,其中缺少前導零。

crypto/tls

新的 Dialer 類型及其 DialContext 方法允許使用 context 連線並與 TLS 伺服器進行交握。

新的 VerifyConnectionConfig 類型的回呼允許自訂驗證邏輯,以應付每個連線。它可以存取 ConnectionState,其中包含同儕憑證、SCT 和已釘選的 OSCP 回應。

自動產生的工作階段票證金鑰現在會每 24 小時自動替換一次,保存期限為 7 天,以限制其對前進機密性的衝擊。

在 TLS 1.2 和較早版本中,工作階段票證保存期限(會在復原的連線中重複使用工作階段金鑰)現在限制為 7 天,也同樣是為了限制其對前進機密性的衝擊。

現在強制實施 RFC 8446 中規定的用戶端端級降級防護檢查。這有可能會對使用類似未授權降級攻擊行為的中介盒子的用戶端造成連線錯誤。

SignatureSchemeCurveIDClientAuthType 現在實作 fmt.Stringer

在用戶端端的復原連線中,OCSPResponseSignedCertificateTimestampsConnectionState 欄位現在會重新填入資料。

tls.Conn 現在會針對永久已中斷的連線傳回一個不透明的錯誤,對臨時的 net.Error 進行包裝。若要存取原始的 net.Error,請使用 errors.As(或 errors.Unwrap),而不是類型斷言。

crypto/x509

若憑證上的名稱或正在驗證的名稱(使用 VerifyOptions.DNSNameVerifyHostname)無效,則現在將以不區分大小寫的方式進行比對,而不會執行進一步的處理作業(不會遵照通配符或移除尾端的點)。無效的名稱包括含有字母、數字、連字號和底線以外的其他字元的字串、標籤為空白的字串,以及尾端有點的憑證名稱。

新的 CreateRevocationList 函數和 RevocationList 類型允許建立符合 RFC 5280 的 X.509 v2 證書撤銷清單。

CreateCertificate 現在如果範本是 CA 且沒有明確指定,就會自動產生 SubjectKeyId

CreateCertificate 現在如果範本指定 MaxPathLen 但不是 CA,就會傳回錯誤。

在除 macOS 以外的 Unix 系統中,SSL_CERT_DIR 環境變數現在可以是使用冒號分隔的清單。

在 macOS 中,二進位檔現在永遠都連結到 Security.framework 以萃取出系統信任根,無關乎 cgo 是否可用。目前的行為應該和 OS 校驗器相容性更高。

crypto/x509/pkix

Name.String 現在會印出非標準屬性從 Names 如果 ExtraNames 是空值。

database/sql

新的 DB.SetConnMaxIdleTime 方法允許在一段時間都沒有使用後從連線池中移除連線,與連線的總使用時間無關。 DBStats.MaxIdleTimeClosed 欄位會顯示由於 DB.SetConnMaxIdleTime 而關閉的總連線數。

新的 Row.Err setter 允許在不呼叫 Row.Scan 的情況下檢查查詢錯誤。

database/sql/driver

新的 Validator 介面可以由 Conn 實作,以允許驅動程式判斷連線是否有效或應當被捨棄。

debug/pe

這個套件現在定義了由 PE 檔案格式使用的常數:IMAGE_FILEIMAGE_SUBSYSTEMIMAGE_DLLCHARACTERISTICS

encoding/asn1

Marshal 現在根據 X.690 DER 來排組 SET OF 的組成部分。

Unmarshal 現在拒絕未根據 X.690 DER 以最小化編碼的標籤和物件識別碼。

encoding/json

這個套件現在有內部限制來限制在編碼時嵌套的最大深度。這降低了深度嵌套的輸入使用大量堆疊記憶體,甚至會導致「goroutine 堆疊超過限制」異常狀況的可能性。

flag

flag 套件看到 -h-help,且這些標記沒有被定義時,它現在會印出使用方式訊息。如果 FlagSet 是使用 ExitOnError 建立,FlagSet.Parse 接下來會退出並傳回狀態 2。在此版本中,-h-help 的退出狀態已變更為 0。特別是,這適用於命令列標記的預設處理方式。

fmt

列印動詞 %#g%#G 現在會保留浮點數值的尾數零。

go/format

Source」和「Node」函式現在會在格式化 Go 原始碼過程中,標準化數字字面值前置詞及指數。此動作符合「gofmt」指令行為,如下所述 自 Go 1.13

html/template

此套件現在會在所有 JavaScript 和 JSON 背景中使用 Unicode 逃逸字元 (\uNNNN)。這能修復「application/ld+json」和「application/json」背景中的逃逸字元錯誤。

io/ioutil

TempDirTempFile 現在會拒絕含有路徑分隔符號的樣式。亦即,類似 ioutil.TempFile("/tmp", "../base*") 的呼叫將不再成功。此動作能避免意外的目錄橫向瀏覽。

math/big

新的 Int.FillBytes 方法允許序列化至固定大小的預先配置位元組切片。

math/cmplx

已更新此套件中函式,以符合 C99 標準(依據 IEC 60559,處理特殊引數,例如無限大、NaN 和符號零)。

net

如果 I/O 執行超過由 Conn.SetDeadlineConn.SetReadDeadlineConn.SetWriteDeadline 方法設定的截止時間,現在會傳回 os.ErrDeadlineExceeded 錯誤,或封裝它。這可協助可靠偵測錯誤是否因超過截止時間所引起。早期版本建議針對錯誤呼叫 Timeout 方法,但 I/O 執行可能會傳回錯誤,即使截止時間尚未超過,Timeout 也會傳回 true

新的 Resolver.LookupIP 方法支援特定網路和接受內容的 IP 查詢。

net/http

解析現在更為嚴格,做為針對請求走私攻擊的強化措施:不再修剪非 ASCII 空白(例如 SP 和 HTAB),且已移除對「identityTransfer-Encoding 的支援。

net/http/httputil

當傳入 Request.Header 地圖項目 nil 時,ReverseProxy 現在支援不修改 X-Forwarded-For 標頭。

當由 ReverseProxy 處理的交換通訊協定 (例如 WebSocket) 請求遭取消時,現在會正確關閉後端連線。

net/http/pprof

所有剖析端點現在都支援「seconds」參數。當參數存在時,端點會針對指定秒數執行剖析,並回報差異。cpu 剖析和追蹤端點中「seconds」參數的意義未變。

net/url

新的 URL 欄位 RawFragment 和方法 EscapedFragment 能提供特定片段的詳細編碼資訊,並控制這些編碼。這類似於 RawPathEscapedPath

URL方法Redacted會以字串格式傳回 URL,任何密碼都會以xxxxx取代。

os

如果 I/O 作業超過 File.SetDeadlineFile.SetReadDeadlineFile.SetWriteDeadline 方法設定的期限,作業現在會傳回錯誤,或包住os.ErrDeadlineExceeded錯誤。這可用於可靠地偵測錯誤是否因為超過期限造成。早期版本建議對錯誤呼叫Timeout方法,但 I/O 作業可能會傳回錯誤,其中即使沒有超過期限,Timeout也會傳回true

套件osnet現在會自動重試會失敗並顯示EINTR的系統呼叫。先前這會導致虛假的失敗,在加入非同步搶佔功能的 Go 1.14 中變得更常見。現在會透明地處理這個部分。

os.File類別現在支援ReadFrom方法。這允許在使用io.Copy將資料從一個os.File複製到另一個時,能在某些系統上使用copy_file_range系統呼叫。其後果是io.CopyBuffer在複製到os.File時,不會總是用指定的緩衝區。如果程式要強制使用指定的緩衝區,可以撰寫io.CopyBuffer(struct{ io.Writer }{dst}, src, buf)

plugin

現在於 macOS 上的-buildmode=plugin支援 DWARF 產生 (且預設啟用)。

現在於freebsd/amd64上支援使用-buildmode=plugin建置。

reflect

套件reflect現在不允許存取所有未外傳欄位的 method,而之前它可以存取未外傳的內嵌欄位的 method。依賴先前行為的程式碼應更新為改存取封裝變數對應的提升 method。

regexp

新的Regexp.SubexpIndex方法會傳回正規表示式中具備指定名稱的第一個子表達式的索引。

runtime

包含ReadMemStatsGoroutineProfile在內的某些函式,如果在進行垃圾回收,就不會再遭到阻擋。

runtime/pprof

goroutine 簡介現在包括在設定簡介時與每個 goroutine 相關的簡介標籤。這個功能尚未於使用debug=2報告的簡介中實作。

strconv

加入FormatComplexParseComplex以用於處理複數。

FormatComplex會將複數轉換成 (a+bi) 型式的字串,其中 a 和 b 分別是實部和虛部。

ParseComplex 將字串轉換為具有指定精度的複數。ParseComplex 接受格式為 N+Ni 的複數。

sync

新方法 Map.LoadAndDelete 會自動刪除金鑰,並在有值時傳回前一個值。

方法 Map.Delete 更有效率。

syscall

在 Unix 系統中,使用 SysProcAttr 的函式現在會拒絕同時設定 SetcttyForeground 欄位的嘗試,因為兩者都使用 Ctty 欄位,但以不相容的方式使用它們。我們預計很少現有程式同時設定這兩個欄位。

設定 Setctty 欄位現在需要將 Ctty 欄位設為子處理序中的檔案描述符號碼,而這是由 ProcAttr.Files 欄位決定的。使用子處理程序述符總是有效的,但在某些情況下,使用父檔案描述符也湊巧有效。某些設定 Setctty 的程式必須變更 Ctty 的值,以使用子處理程序描述符號碼。

現在有可能windows/amd64 上呼叫傳回浮點值的系統呼叫。

testing

testing.T 類型現在有一個 Deadline 方法,用來報告測試二進位檔超過其逾時限制的時間。

TestMain 函式不再需要呼叫 os.Exit。如果 TestMain 函式傳回,測試二進位檔會以 m.Run 傳回的值呼叫 os.Exit

新方法 T.TempDirB.TempDir 傳回暫時目錄,而這些目錄會在測試結束時自動清除。

go test -v 現在會依測試名稱將輸出分組,而不是在每一行列印測試名稱。

text/template

JSEscape 現在一致使用與 JSON 相容的 Unicode 逸出字元 (\u00XX)。

time

新方法 Ticker.Reset 支援變更指示器的持續時間。

傳回錯誤時,ParseDuration 現在會加上引號引述原始值。