The golang/go tree put 62 commits on master in this review window, across 206 files with 5112 insertions and 1665 deletions. Compiler ports and SSA work ate most of that diff. The pieces that change how production services behave sit in net/http, the Go DNS resolver, and runtime.Pinner.
HTTP/2 idle connections cancelled every request context ¶
Parking the HTTP/2 serve goroutine made conn.serve return as soon as the connection went idle. The deferred cancel then ran while the connection was still being served. The unencrypted HTTP/2 path handed that cancelable context to the HTTP/2 server, so every request on the connection saw ctx.Done(). The TLS ALPN path already passed the parent connection context. The follow up does the same for the unencrypted case.
This shows up as handlers aborting on keep alive connections, not as a panic. If you terminate HTTP/2 without TLS in front of a proxy or a local sidecar, check whether request contexts have been firing on idle.
// HTTP/2 may outlive this goroutine, so it gets the uncancelable ctx.
connCtx := ctx
ctx, cancelCtx := context.WithCancel(ctx)
c.cancelCtx = cancelCtx
defer cancelCtx()
if c.tlsState == nil && protos.UnencryptedHTTP2() {
if c.maybeServeUnencryptedHTTP2(connCtx) {
return
}
}
src/net/http/server.go also stops pinning bufio buffers on connections handed to HTTP/2. HTTP/2 does not use net/http’s bufio.Reader and bufio.Writer. The reader now goes back to the pool before the handoff, and the 4KiB writer is allocated only on the HTTP/1.x path.
A later change in src/net/http/internal/http2/server.go replaces the park mutex with one atomic word that packs the pending send count and the parked flag. That is a scheduler win on idle connections. It is not a behavior change.
Localhost no longer walks search domains ¶
The Go resolver now answers localhost locally. RFC 6761 section 6.3 reserves localhost and any name under .localhost for the loopback interface. The Go resolver ignored that. It read the hosts file and otherwise sent the query to DNS, first expanded with search domains.
Unix boxes hid this because /etc/hosts already lists localhost. Windows ships that file with the localhost lines commented out and expects the resolver to special case the name the way GetAddrInfoW does. A binary built with the netgo tag on Windows sent the query to DNS and often got NXDOMAIN. Search domain expansion was worse than a lookup failure. localhost has no dots, so localhost.corp.example went out first and whatever A record it returned won. That is issue 32017, open since 2019.
Address queries now return ::1 and 127.0.0.1 after the hosts file is consulted and before any DNS machinery runs. An explicit hosts entry still overrides. Loopback is also returned when the lookup order is files only and the hosts file has no localhost line. Returning both addresses lets the dialer do its usual dual stack fallback for services bound to only one loopback address. SRV, MX, NS, and TXT queries for localhost names get a local negative response instead of a wire query.
Chrome, Firefox, and curl already hard code this. If tests or local ETL jobs depend on localhost resolving through a corporate search domain to something that is not loopback, that path is gone on tip.
runtime.Pinner drops the specials lock on the hot path ¶
runtime.Pinner keeps Go memory still while C holds a pointer. cgo, database drivers, and compression libraries that pin slices all pay for that. The pin counter lived behind the global specials allocator lock.
Caching one unused pin counter per P lets a repeated pin and unpin cycle skip that lock. Misses, full caches, and calls without a P still go through the allocator. On Windows arm64 the parallel double pin bench went from 391.60 ns to 86.54 ns, about 78 percent. The single thread double pin case dropped 21 percent. The single pin bench was a wash.
Batching unpin in src/runtime/pinner.go then groups consecutive references in the same span under one sweep check and one specials lock. Each batch is capped at 64 references so the work cannot run forever without preemption. Batch unpin fell 38 percent. Unpin of 100 refs fell 35 percent.
If a pipeline pins buffers for Arrow, parquet, or a C codec, these numbers are the ones that matter. If you never call runtime.Pinner, the change is invisible.
Stdlib accuracy and cmd/go exit status ¶
go mod why now exits 1 when any requested package or module is not referenced from the main module. Output is unchanged. Scripts that grepped the (main module does not need ...) stanza and ignored the status will start failing. That is the intended behavior. Issue 30721 has been open since 2019.
math/big.Float.Uint64 reported Exact for fractional values whose MinPrec fit in 64 bits, such as 1.5. It now compares MinPrec with the exponent the way Float.Int64 and Float.IsInt already do, so truncation reports Below. Anyone feeding money or metrics through big.Float and trusting the accuracy flag should recheck.
compress/flate dropped extra bounds checks in loadLE32, loadLE64, and matchLen. loadLE64 had compiled to 10 bounds checks on arm64. Reslicing with b[i:] and checking the last index compiles to two checks and a combined load. Default level encode on an M1 Max is about 5 percent faster on the Digits and Newton benches. Huffman and max compression barely moved. Gzip in HTTP handlers and in ETL spill files picks this up with no API change.
The testing package was doubling ESC bytes in t.Log under plain -test.v. Framing marker escape now happens only in test2json mode. Colored log lines in verbose tests stop looking corrupted.
The rest of the window is loong64 clobberdead, riscv64 compressed jumps, compiler walkstate caches, and export data plumbing. Useful if you maintain those ports. Not a reason to rebuild a fleet.
What to watch ¶
Rebuild services that speak unencrypted HTTP/2 before you assume keep alive request contexts are stable. The cancel bug is on master, not in a tagged release yet.
Treat go mod why as a failing command in CI once this lands in a release. The text did not change. The status did.
Do not expect localhost to follow search domains. If a job used that as cheap service discovery, it will start talking to loopback.