Go 1.21.6 repairs map cloning and runtime diagnostics
Go 1.21.6 fixes aliasing in maps.Clone and failures in runtime diagnostics. The fixes show why implementation details must preserve the language's value semantics.
A map containing a large struct should obey the same assignment rules as a map containing a small one. That expectation failed in maps.Clone. A report against Go 1.21.4 showed that replacing a value in the original map could also change the clone, even though the struct contained an integer and an array, with no application-level pointers. Go 1.21.6, released on January 9, includes the repair alongside compiler and runtime fixes. The interesting part of this maintenance release is how ordinary library operations exposed assumptions inside the implementation.
I value Go's readability because it usually lets a reader reason about a program without reconstructing its author's private conventions. A clone that changes when another map changes breaks that reasoning. The defect deserves attention even though its reproducer is small and the release adds no new language syntax.
A shallow copy still copies values
The original report, issue 64474, uses a struct with an integer field and a padding array of 100 integers. Its program stores a value whose field is 1, clones the map, then replaces the original entry with a value whose field is 2. Correct output would show an original entry containing 2 and a cloned entry containing 1. The reported result was 2 in both maps.
The package implementation at the release tag documents Clone as a shallow copy using ordinary assignment for keys and values. Shallow copying permits sharing that follows from the value's own contents. If a value contains a pointer, copying that pointer leaves both copies referring to the same object. The reported struct has different semantics. Copying its array copies the array's elements, so the program does not request shared mutable storage.
This distinction matters when a map represents a snapshot. An application may clone the map to retain a previous set of values while constructing an update. Shared objects inside those values remain the application's responsibility. Unexpected sharing introduced below the assignment semantics defeats the snapshot even when the application has chosen value types precisely to avoid it.
The issue discussion traces the regression to moving cloning into the runtime. A fast path copied an entire bucket when the source map used a single bucket. For indirectly stored values, that bucket copy could preserve references to storage belonging to the source. The distinction between copying a representation and copying a language value becomes observable at the next assignment.
The fixed runtime implementation restricts that quick copy. Its condition excludes indirectly stored elements and also accounts for indirect keys that need updating. Other cases use the entry-copying path. This preserves a fast path for suitable maps while making the choice depend on the representation's actual copying requirements.
The correction does not turn Clone into a recursive deep-copy operation. Its contract remains ordinary assignment. That is the useful boundary for callers, because it lets them derive sharing from their declared types. The runtime can change storage strategies without changing which application values alias.
Reading memory statistics could terminate a program
Another fix concerns a diagnostic operation with a more immediate failure. Issue 64401 reports programs crashing while collecting memory statistics through expvar and runtime.ReadMemStats. The fatal check compared the runtime's mappedReady accounting with other memory statistics. The reported totals differed by 64 KiB.
The discussion connects that difference to execution-trace buffers. Stopping the world did not make every possible source of trace activity stop. A system-monitor thread could emit an event and affect the accounting while the statistics code was checking agreement. The runtime maintainer identified a transient skew as a plausible consequence and moved the assertions behind a double-check mode. The backport request explicitly describes crashes in correct programs with no workaround.
There is a design tradeoff here. Internal consistency assertions can expose runtime defects that otherwise remain hidden. Making such an assertion fatal also turns any mistaken assumption about synchronization into an application failure. In this case, a metrics read reached an assertion whose view of a stopped runtime was too strong for the tracing machinery.
I consider diagnostics part of a service's operational behavior. A memory-statistics endpoint that can terminate a correct process makes the monitoring arrangement itself relevant to availability. This fix matters to programs that collect those statistics while tracing, even when their request-processing code needs no change.
Race reports depend on runtime annotations
The runtime also needed to describe its synchronization correctly to the race detector. Issue 64649 reports failures involving parallel tests, panic(nil), and compatibility behavior. The reported conflict involved initialization of an internal GODEBUG setting and a read of that setting while counting non-default behavior.
The discussion identifies an internal atomic publication operation that lacked race annotations. Synchronization inside the runtime is not necessarily visible to the detector in the same way as synchronization in instrumented application code. The repair adds annotations so the detector can account for the ordering. The backport request connects this to the compatibility machinery introduced with Go 1.21.
This is a specific explanation for a specific runtime report. It supplies no general reason to dismiss race-detector findings. Its practical significance is that correct runtime synchronization and the detector's model of that synchronization must agree. Otherwise a compatibility path can make a parallel test suite fail even when the relevant ordering exists.
The map fix and these diagnostic fixes affect different operations, but each restores an existing expectation. Map values retain assignment semantics despite indirect storage. Collecting memory statistics no longer encounters this fatal diagnostic assertion by default. Race instrumentation can recognize the runtime publication operation involved in non-default behavior counting. Go 1.21.6 makes those existing operations dependable without asking application code to adopt a new abstraction.