Initial commit: Go 1.23 release state
This commit is contained in:
75
doc/README.md
Normal file
75
doc/README.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Release Notes
|
||||
|
||||
The `initial` and `next` subdirectories of this directory are for release notes.
|
||||
|
||||
## For developers
|
||||
|
||||
Release notes should be added to `next` by editing existing files or creating
|
||||
new files. **Do not add RELNOTE=yes comments in CLs.** Instead, add a file to
|
||||
the CL (or ask the author to do so).
|
||||
|
||||
At the end of the development cycle, the files will be merged by being
|
||||
concatenated in sorted order by pathname. Files in the directory matching the
|
||||
glob "*stdlib/*minor" are treated specially. They should be in subdirectories
|
||||
corresponding to standard library package paths, and headings for those package
|
||||
paths will be generated automatically.
|
||||
|
||||
Files in this repo's `api/next` directory must have corresponding files in
|
||||
`doc/next/*stdlib/*minor`.
|
||||
The files should be in the subdirectory for the package with the new
|
||||
API, and should be named after the issue number of the API proposal.
|
||||
For example, if the directory `6-stdlib/99-minor` is present,
|
||||
then an `api/next` file with the line
|
||||
|
||||
pkg net/http, function F #12345
|
||||
|
||||
should have a corresponding file named `doc/next/6-stdlib/99-minor/net/http/12345.md`.
|
||||
At a minimum, that file should contain either a full sentence or a TODO,
|
||||
ideally referring to a person with the responsibility to complete the note.
|
||||
|
||||
If your CL addresses an accepted proposal, mention the proposal issue number in
|
||||
your release note in the form `/issue/NUMBER`. A link to the issue in the text
|
||||
will have this form (see below). If you don't want to mention the issue in the
|
||||
text, add it as a comment:
|
||||
```
|
||||
<!-- go.dev/issue/12345 -->
|
||||
```
|
||||
If an accepted proposal is mentioned in a CL but not in the release notes, it will be
|
||||
flagged as a TODO by the automated tooling. That is true even for proposals that add API.
|
||||
|
||||
Use the following forms in your markdown:
|
||||
|
||||
[http.Request] # symbol documentation; auto-linked as in Go doc strings
|
||||
[Request] # short form, for symbols in the package being documented
|
||||
[net/http] # package link
|
||||
[#12345](/issue/12345) # GitHub issues
|
||||
[CL 6789](/cl/6789) # Gerrit changelists
|
||||
|
||||
To preview `next` content in merged form using a local instance of the website, run:
|
||||
|
||||
```
|
||||
go run golang.org/x/website/cmd/golangorg@latest -goroot=..
|
||||
```
|
||||
|
||||
Then open http://localhost:6060/doc/next. Refresh the page to see your latest edits.
|
||||
|
||||
## For the release team
|
||||
|
||||
The `relnote` tool, at `golang.org/x/build/cmd/relnote`, operates on the files
|
||||
in `doc/next`.
|
||||
|
||||
As a release cycle nears completion, run `relnote todo` to get a list of
|
||||
unfinished release note work.
|
||||
|
||||
To prepare the release notes for a release, run `relnote generate`.
|
||||
That will merge the `.md` files in `next` into a single file.
|
||||
Atomically (as close to it as possible) add that file to `_content/doc` directory
|
||||
of the website repository and remove the `doc/next` directory in this repository.
|
||||
|
||||
To begin the next release development cycle, populate the contents of `next`
|
||||
with those of `initial`. From the repo root:
|
||||
|
||||
> cd doc
|
||||
> cp -r initial/* next
|
||||
|
||||
Then edit `next/1-intro.md` to refer to the next version.
|
||||
1073
doc/asm.html
Normal file
1073
doc/asm.html
Normal file
File diff suppressed because it is too large
Load Diff
6864
doc/go1.17_spec.html
Normal file
6864
doc/go1.17_spec.html
Normal file
File diff suppressed because it is too large
Load Diff
977
doc/go_mem.html
Normal file
977
doc/go_mem.html
Normal file
@@ -0,0 +1,977 @@
|
||||
<!--{
|
||||
"Title": "The Go Memory Model",
|
||||
"Subtitle": "Version of June 6, 2022",
|
||||
"Path": "/ref/mem"
|
||||
}-->
|
||||
|
||||
<style>
|
||||
p.rule {
|
||||
font-style: italic;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h2 id="introduction">Introduction</h2>
|
||||
|
||||
<p>
|
||||
The Go memory model specifies the conditions under which
|
||||
reads of a variable in one goroutine can be guaranteed to
|
||||
observe values produced by writes to the same variable in a different goroutine.
|
||||
</p>
|
||||
|
||||
|
||||
<h3 id="advice">Advice</h3>
|
||||
|
||||
<p>
|
||||
Programs that modify data being simultaneously accessed by multiple goroutines
|
||||
must serialize such access.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To serialize access, protect the data with channel operations or other synchronization primitives
|
||||
such as those in the <a href="/pkg/sync/"><code>sync</code></a>
|
||||
and <a href="/pkg/sync/atomic/"><code>sync/atomic</code></a> packages.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you must read the rest of this document to understand the behavior of your program,
|
||||
you are being too clever.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Don't be clever.
|
||||
</p>
|
||||
|
||||
<h3 id="overview">Informal Overview</h3>
|
||||
|
||||
<p>
|
||||
Go approaches its memory model in much the same way as the rest of the language,
|
||||
aiming to keep the semantics simple, understandable, and useful.
|
||||
This section gives a general overview of the approach and should suffice for most programmers.
|
||||
The memory model is specified more formally in the next section.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A <em>data race</em> is defined as
|
||||
a write to a memory location happening concurrently with another read or write to that same location,
|
||||
unless all the accesses involved are atomic data accesses as provided by the <code>sync/atomic</code> package.
|
||||
As noted already, programmers are strongly encouraged to use appropriate synchronization
|
||||
to avoid data races.
|
||||
In the absence of data races, Go programs behave as if all the goroutines
|
||||
were multiplexed onto a single processor.
|
||||
This property is sometimes referred to as DRF-SC: data-race-free programs
|
||||
execute in a sequentially consistent manner.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
While programmers should write Go programs without data races,
|
||||
there are limitations to what a Go implementation can do in response to a data race.
|
||||
An implementation may always react to a data race by reporting the race and terminating the program.
|
||||
Otherwise, each read of a single-word-sized or sub-word-sized memory location
|
||||
must observe a value actually written to that location (perhaps by a concurrent executing goroutine)
|
||||
and not yet overwritten.
|
||||
These implementation constraints make Go more like Java or JavaScript,
|
||||
in that most races have a limited number of outcomes,
|
||||
and less like C and C++, where the meaning of any program with a race
|
||||
is entirely undefined, and the compiler may do anything at all.
|
||||
Go's approach aims to make errant programs more reliable and easier to debug,
|
||||
while still insisting that races are errors and that tools can diagnose and report them.
|
||||
</p>
|
||||
|
||||
<h2 id="model">Memory Model</h2>
|
||||
|
||||
<p>
|
||||
The following formal definition of Go's memory model closely follows
|
||||
the approach presented by Hans-J. Boehm and Sarita V. Adve in
|
||||
“<a href="https://www.hpl.hp.com/techreports/2008/HPL-2008-56.pdf">Foundations of the C++ Concurrency Memory Model</a>”,
|
||||
published in PLDI 2008.
|
||||
The definition of data-race-free programs and the guarantee of sequential consistency
|
||||
for race-free programs are equivalent to the ones in that work.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The memory model describes the requirements on program executions,
|
||||
which are made up of goroutine executions,
|
||||
which in turn are made up of memory operations.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A <i>memory operation</i> is modeled by four details:
|
||||
</p>
|
||||
<ul>
|
||||
<li>its kind, indicating whether it is an ordinary data read, an ordinary data write,
|
||||
or a <i>synchronizing operation</i> such as an atomic data access,
|
||||
a mutex operation, or a channel operation,</li>
|
||||
<li>its location in the program,</li>
|
||||
<li>the memory location or variable being accessed, and</li>
|
||||
<li>the values read or written by the operation.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Some memory operations are <i>read-like</i>, including read, atomic read, mutex lock, and channel receive.
|
||||
Other memory operations are <i>write-like</i>, including write, atomic write, mutex unlock, channel send, and channel close.
|
||||
Some, such as atomic compare-and-swap, are both read-like and write-like.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A <i>goroutine execution</i> is modeled as a set of memory operations executed by a single goroutine.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Requirement 1</b>:
|
||||
The memory operations in each goroutine must correspond to a correct sequential execution of that goroutine,
|
||||
given the values read from and written to memory.
|
||||
That execution must be consistent with the <i>sequenced before</i> relation,
|
||||
defined as the partial order requirements set out by the <a href="/ref/spec">Go language specification</a>
|
||||
for Go's control flow constructs as well as the <a href="/ref/spec#Order_of_evaluation">order of evaluation for expressions</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A Go <i>program execution</i> is modeled as a set of goroutine executions,
|
||||
together with a mapping <i>W</i> that specifies the write-like operation that each read-like operation reads from.
|
||||
(Multiple executions of the same program can have different program executions.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Requirement 2</b>:
|
||||
For a given program execution, the mapping <i>W</i>, when limited to synchronizing operations,
|
||||
must be explainable by some implicit total order of the synchronizing operations
|
||||
that is consistent with sequencing and the values read and written by those operations.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <i>synchronized before</i> relation is a partial order on synchronizing memory operations,
|
||||
derived from <i>W</i>.
|
||||
If a synchronizing read-like memory operation <i>r</i>
|
||||
observes a synchronizing write-like memory operation <i>w</i>
|
||||
(that is, if <i>W</i>(<i>r</i>) = <i>w</i>),
|
||||
then <i>w</i> is synchronized before <i>r</i>.
|
||||
Informally, the synchronized before relation is a subset of the implied total order
|
||||
mentioned in the previous paragraph,
|
||||
limited to the information that <i>W</i> directly observes.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <i>happens before</i> relation is defined as the transitive closure of the
|
||||
union of the sequenced before and synchronized before relations.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Requirement 3</b>:
|
||||
For an ordinary (non-synchronizing) data read <i>r</i> on a memory location <i>x</i>,
|
||||
<i>W</i>(<i>r</i>) must be a write <i>w</i> that is <i>visible</i> to <i>r</i>,
|
||||
where visible means that both of the following hold:
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li><i>w</i> happens before <i>r</i>.</li>
|
||||
<li><i>w</i> does not happen before any other write <i>w'</i> (to <i>x</i>) that happens before <i>r</i>.</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
A <i>read-write data race</i> on memory location <i>x</i>
|
||||
consists of a read-like memory operation <i>r</i> on <i>x</i>
|
||||
and a write-like memory operation <i>w</i> on <i>x</i>,
|
||||
at least one of which is non-synchronizing,
|
||||
which are unordered by happens before
|
||||
(that is, neither <i>r</i> happens before <i>w</i>
|
||||
nor <i>w</i> happens before <i>r</i>).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A <i>write-write data race</i> on memory location <i>x</i>
|
||||
consists of two write-like memory operations <i>w</i> and <i>w'</i> on <i>x</i>,
|
||||
at least one of which is non-synchronizing,
|
||||
which are unordered by happens before.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that if there are no read-write or write-write data races on memory location <i>x</i>,
|
||||
then any read <i>r</i> on <i>x</i> has only one possible <i>W</i>(<i>r</i>):
|
||||
the single <i>w</i> that immediately precedes it in the happens before order.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
More generally, it can be shown that any Go program that is data-race-free,
|
||||
meaning it has no program executions with read-write or write-write data races,
|
||||
can only have outcomes explained by some sequentially consistent interleaving
|
||||
of the goroutine executions.
|
||||
(The proof is the same as Section 7 of Boehm and Adve's paper cited above.)
|
||||
This property is called DRF-SC.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The intent of the formal definition is to match
|
||||
the DRF-SC guarantee provided to race-free programs
|
||||
by other languages, including C, C++, Java, JavaScript, Rust, and Swift.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Certain Go language operations such as goroutine creation and memory allocation
|
||||
act as synchronization operations.
|
||||
The effect of these operations on the synchronized-before partial order
|
||||
is documented in the “Synchronization” section below.
|
||||
Individual packages are responsible for providing similar documentation
|
||||
for their own operations.
|
||||
</p>
|
||||
|
||||
<h2 id="restrictions">Implementation Restrictions for Programs Containing Data Races</h2>
|
||||
|
||||
<p>
|
||||
The preceding section gave a formal definition of data-race-free program execution.
|
||||
This section informally describes the semantics that implementations must provide
|
||||
for programs that do contain races.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Any implementation can, upon detecting a data race,
|
||||
report the race and halt execution of the program.
|
||||
Implementations using ThreadSanitizer
|
||||
(accessed with “<code>go</code> <code>build</code> <code>-race</code>”)
|
||||
do exactly this.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A read of an array, struct, or complex number
|
||||
may by implemented as a read of each individual sub-value
|
||||
(array element, struct field, or real/imaginary component),
|
||||
in any order.
|
||||
Similarly, a write of an array, struct, or complex number
|
||||
may be implemented as a write of each individual sub-value,
|
||||
in any order.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A read <i>r</i> of a memory location <i>x</i>
|
||||
holding a value
|
||||
that is not larger than a machine word must observe
|
||||
some write <i>w</i> such that <i>r</i> does not happen before <i>w</i>
|
||||
and there is no write <i>w'</i> such that <i>w</i> happens before <i>w'</i>
|
||||
and <i>w'</i> happens before <i>r</i>.
|
||||
That is, each read must observe a value written by a preceding or concurrent write.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Additionally, observation of acausal and “out of thin air” writes is disallowed.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Reads of memory locations larger than a single machine word
|
||||
are encouraged but not required to meet the same semantics
|
||||
as word-sized memory locations,
|
||||
observing a single allowed write <i>w</i>.
|
||||
For performance reasons,
|
||||
implementations may instead treat larger operations
|
||||
as a set of individual machine-word-sized operations
|
||||
in an unspecified order.
|
||||
This means that races on multiword data structures
|
||||
can lead to inconsistent values not corresponding to a single write.
|
||||
When the values depend on the consistency
|
||||
of internal (pointer, length) or (pointer, type) pairs,
|
||||
as can be the case for interface values, maps,
|
||||
slices, and strings in most Go implementations,
|
||||
such races can in turn lead to arbitrary memory corruption.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Examples of incorrect synchronization are given in the
|
||||
“Incorrect synchronization” section below.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Examples of the limitations on implementations are given in the
|
||||
“Incorrect compilation” section below.
|
||||
</p>
|
||||
|
||||
<h2 id="synchronization">Synchronization</h2>
|
||||
|
||||
<h3 id="init">Initialization</h3>
|
||||
|
||||
<p>
|
||||
Program initialization runs in a single goroutine,
|
||||
but that goroutine may create other goroutines,
|
||||
which run concurrently.
|
||||
</p>
|
||||
|
||||
<p class="rule">
|
||||
If a package <code>p</code> imports package <code>q</code>, the completion of
|
||||
<code>q</code>'s <code>init</code> functions happens before the start of any of <code>p</code>'s.
|
||||
</p>
|
||||
|
||||
<p class="rule">
|
||||
The completion of all <code>init</code> functions is synchronized before
|
||||
the start of the function <code>main.main</code>.
|
||||
</p>
|
||||
|
||||
<h3 id="go">Goroutine creation</h3>
|
||||
|
||||
<p class="rule">
|
||||
The <code>go</code> statement that starts a new goroutine
|
||||
is synchronized before the start of the goroutine's execution.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For example, in this program:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var a string
|
||||
|
||||
func f() {
|
||||
print(a)
|
||||
}
|
||||
|
||||
func hello() {
|
||||
a = "hello, world"
|
||||
go f()
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
calling <code>hello</code> will print <code>"hello, world"</code>
|
||||
at some point in the future (perhaps after <code>hello</code> has returned).
|
||||
</p>
|
||||
|
||||
<h3 id="goexit">Goroutine destruction</h3>
|
||||
|
||||
<p>
|
||||
The exit of a goroutine is not guaranteed to be synchronized before
|
||||
any event in the program.
|
||||
For example, in this program:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var a string
|
||||
|
||||
func hello() {
|
||||
go func() { a = "hello" }()
|
||||
print(a)
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
the assignment to <code>a</code> is not followed by
|
||||
any synchronization event, so it is not guaranteed to be
|
||||
observed by any other goroutine.
|
||||
In fact, an aggressive compiler might delete the entire <code>go</code> statement.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If the effects of a goroutine must be observed by another goroutine,
|
||||
use a synchronization mechanism such as a lock or channel
|
||||
communication to establish a relative ordering.
|
||||
</p>
|
||||
|
||||
<h3 id="chan">Channel communication</h3>
|
||||
|
||||
<p>
|
||||
Channel communication is the main method of synchronization
|
||||
between goroutines. Each send on a particular channel
|
||||
is matched to a corresponding receive from that channel,
|
||||
usually in a different goroutine.
|
||||
</p>
|
||||
|
||||
<p class="rule">
|
||||
A send on a channel is synchronized before the completion of the
|
||||
corresponding receive from that channel.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This program:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var c = make(chan int, 10)
|
||||
var a string
|
||||
|
||||
func f() {
|
||||
a = "hello, world"
|
||||
c <- 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
go f()
|
||||
<-c
|
||||
print(a)
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
is guaranteed to print <code>"hello, world"</code>. The write to <code>a</code>
|
||||
is sequenced before the send on <code>c</code>, which is synchronized before
|
||||
the corresponding receive on <code>c</code> completes, which is sequenced before
|
||||
the <code>print</code>.
|
||||
</p>
|
||||
|
||||
<p class="rule">
|
||||
The closing of a channel is synchronized before a receive that returns a zero value
|
||||
because the channel is closed.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In the previous example, replacing
|
||||
<code>c <- 0</code> with <code>close(c)</code>
|
||||
yields a program with the same guaranteed behavior.
|
||||
</p>
|
||||
|
||||
<p class="rule">
|
||||
A receive from an unbuffered channel is synchronized before the completion of
|
||||
the corresponding send on that channel.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This program (as above, but with the send and receive statements swapped and
|
||||
using an unbuffered channel):
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var c = make(chan int)
|
||||
var a string
|
||||
|
||||
func f() {
|
||||
a = "hello, world"
|
||||
<-c
|
||||
}
|
||||
|
||||
func main() {
|
||||
go f()
|
||||
c <- 0
|
||||
print(a)
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
is also guaranteed to print <code>"hello, world"</code>. The write to <code>a</code>
|
||||
is sequenced before the receive on <code>c</code>, which is synchronized before
|
||||
the corresponding send on <code>c</code> completes, which is sequenced
|
||||
before the <code>print</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If the channel were buffered (e.g., <code>c = make(chan int, 1)</code>)
|
||||
then the program would not be guaranteed to print
|
||||
<code>"hello, world"</code>. (It might print the empty string,
|
||||
crash, or do something else.)
|
||||
</p>
|
||||
|
||||
<p class="rule">
|
||||
The <i>k</i>th receive on a channel with capacity <i>C</i> is synchronized before the completion of the <i>k</i>+<i>C</i>th send from that channel completes.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This rule generalizes the previous rule to buffered channels.
|
||||
It allows a counting semaphore to be modeled by a buffered channel:
|
||||
the number of items in the channel corresponds to the number of active uses,
|
||||
the capacity of the channel corresponds to the maximum number of simultaneous uses,
|
||||
sending an item acquires the semaphore, and receiving an item releases
|
||||
the semaphore.
|
||||
This is a common idiom for limiting concurrency.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This program starts a goroutine for every entry in the work list, but the
|
||||
goroutines coordinate using the <code>limit</code> channel to ensure
|
||||
that at most three are running work functions at a time.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var limit = make(chan int, 3)
|
||||
|
||||
func main() {
|
||||
for _, w := range work {
|
||||
go func(w func()) {
|
||||
limit <- 1
|
||||
w()
|
||||
<-limit
|
||||
}(w)
|
||||
}
|
||||
select{}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h3 id="locks">Locks</h3>
|
||||
|
||||
<p>
|
||||
The <code>sync</code> package implements two lock data types,
|
||||
<code>sync.Mutex</code> and <code>sync.RWMutex</code>.
|
||||
</p>
|
||||
|
||||
<p class="rule">
|
||||
For any <code>sync.Mutex</code> or <code>sync.RWMutex</code> variable <code>l</code> and <i>n</i> < <i>m</i>,
|
||||
call <i>n</i> of <code>l.Unlock()</code> is synchronized before call <i>m</i> of <code>l.Lock()</code> returns.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This program:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var l sync.Mutex
|
||||
var a string
|
||||
|
||||
func f() {
|
||||
a = "hello, world"
|
||||
l.Unlock()
|
||||
}
|
||||
|
||||
func main() {
|
||||
l.Lock()
|
||||
go f()
|
||||
l.Lock()
|
||||
print(a)
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
is guaranteed to print <code>"hello, world"</code>.
|
||||
The first call to <code>l.Unlock()</code> (in <code>f</code>) is synchronized
|
||||
before the second call to <code>l.Lock()</code> (in <code>main</code>) returns,
|
||||
which is sequenced before the <code>print</code>.
|
||||
</p>
|
||||
|
||||
<p class="rule">
|
||||
For any call to <code>l.RLock</code> on a <code>sync.RWMutex</code> variable <code>l</code>,
|
||||
there is an <i>n</i> such that the <i>n</i>th call to <code>l.Unlock</code>
|
||||
is synchronized before the return from <code>l.RLock</code>,
|
||||
and the matching call to <code>l.RUnlock</code> is synchronized before the return from call <i>n</i>+1 to <code>l.Lock</code>.
|
||||
</p>
|
||||
|
||||
<p class="rule">
|
||||
A successful call to <code>l.TryLock</code> (or <code>l.TryRLock</code>)
|
||||
is equivalent to a call to <code>l.Lock</code> (or <code>l.RLock</code>).
|
||||
An unsuccessful call has no synchronizing effect at all.
|
||||
As far as the memory model is concerned,
|
||||
<code>l.TryLock</code> (or <code>l.TryRLock</code>)
|
||||
may be considered to be able to return false
|
||||
even when the mutex <i>l</i> is unlocked.
|
||||
</p>
|
||||
|
||||
<h3 id="once">Once</h3>
|
||||
|
||||
<p>
|
||||
The <code>sync</code> package provides a safe mechanism for
|
||||
initialization in the presence of multiple goroutines
|
||||
through the use of the <code>Once</code> type.
|
||||
Multiple threads can execute <code>once.Do(f)</code> for a particular <code>f</code>,
|
||||
but only one will run <code>f()</code>, and the other calls block
|
||||
until <code>f()</code> has returned.
|
||||
</p>
|
||||
|
||||
<p class="rule">
|
||||
The completion of a single call of <code>f()</code> from <code>once.Do(f)</code>
|
||||
is synchronized before the return of any call of <code>once.Do(f)</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In this program:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var a string
|
||||
var once sync.Once
|
||||
|
||||
func setup() {
|
||||
a = "hello, world"
|
||||
}
|
||||
|
||||
func doprint() {
|
||||
once.Do(setup)
|
||||
print(a)
|
||||
}
|
||||
|
||||
func twoprint() {
|
||||
go doprint()
|
||||
go doprint()
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
calling <code>twoprint</code> will call <code>setup</code> exactly
|
||||
once.
|
||||
The <code>setup</code> function will complete before either call
|
||||
of <code>print</code>.
|
||||
The result will be that <code>"hello, world"</code> will be printed
|
||||
twice.
|
||||
</p>
|
||||
|
||||
<h3 id="atomic">Atomic Values</h3>
|
||||
|
||||
<p>
|
||||
The APIs in the <a href="/pkg/sync/atomic/"><code>sync/atomic</code></a>
|
||||
package are collectively “atomic operations”
|
||||
that can be used to synchronize the execution of different goroutines.
|
||||
If the effect of an atomic operation <i>A</i> is observed by atomic operation <i>B</i>,
|
||||
then <i>A</i> is synchronized before <i>B</i>.
|
||||
All the atomic operations executed in a program behave as though executed
|
||||
in some sequentially consistent order.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The preceding definition has the same semantics as C++’s sequentially consistent atomics
|
||||
and Java’s <code>volatile</code> variables.
|
||||
</p>
|
||||
|
||||
<h3 id="finalizer">Finalizers</h3>
|
||||
|
||||
<p>
|
||||
The <a href="/pkg/runtime/"><code>runtime</code></a> package provides
|
||||
a <code>SetFinalizer</code> function that adds a finalizer to be called when
|
||||
a particular object is no longer reachable by the program.
|
||||
A call to <code>SetFinalizer(x, f)</code> is synchronized before the finalization call <code>f(x)</code>.
|
||||
</p>
|
||||
|
||||
<h3 id="more">Additional Mechanisms</h3>
|
||||
|
||||
<p>
|
||||
The <code>sync</code> package provides additional synchronization abstractions,
|
||||
including <a href="/pkg/sync/#Cond">condition variables</a>,
|
||||
<a href="/pkg/sync/#Map">lock-free maps</a>,
|
||||
<a href="/pkg/sync/#Pool">allocation pools</a>,
|
||||
and
|
||||
<a href="/pkg/sync/#WaitGroup">wait groups</a>.
|
||||
The documentation for each of these specifies the guarantees it
|
||||
makes concerning synchronization.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Other packages that provide synchronization abstractions
|
||||
should document the guarantees they make too.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="badsync">Incorrect synchronization</h2>
|
||||
|
||||
<p>
|
||||
Programs with races are incorrect and
|
||||
can exhibit non-sequentially consistent executions.
|
||||
In particular, note that a read <i>r</i> may observe the value written by any write <i>w</i>
|
||||
that executes concurrently with <i>r</i>.
|
||||
Even if this occurs, it does not imply that reads happening after <i>r</i>
|
||||
will observe writes that happened before <i>w</i>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In this program:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var a, b int
|
||||
|
||||
func f() {
|
||||
a = 1
|
||||
b = 2
|
||||
}
|
||||
|
||||
func g() {
|
||||
print(b)
|
||||
print(a)
|
||||
}
|
||||
|
||||
func main() {
|
||||
go f()
|
||||
g()
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
it can happen that <code>g</code> prints <code>2</code> and then <code>0</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This fact invalidates a few common idioms.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Double-checked locking is an attempt to avoid the overhead of synchronization.
|
||||
For example, the <code>twoprint</code> program might be
|
||||
incorrectly written as:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var a string
|
||||
var done bool
|
||||
|
||||
func setup() {
|
||||
a = "hello, world"
|
||||
done = true
|
||||
}
|
||||
|
||||
func doprint() {
|
||||
if !done {
|
||||
once.Do(setup)
|
||||
}
|
||||
print(a)
|
||||
}
|
||||
|
||||
func twoprint() {
|
||||
go doprint()
|
||||
go doprint()
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
but there is no guarantee that, in <code>doprint</code>, observing the write to <code>done</code>
|
||||
implies observing the write to <code>a</code>. This
|
||||
version can (incorrectly) print an empty string
|
||||
instead of <code>"hello, world"</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Another incorrect idiom is busy waiting for a value, as in:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var a string
|
||||
var done bool
|
||||
|
||||
func setup() {
|
||||
a = "hello, world"
|
||||
done = true
|
||||
}
|
||||
|
||||
func main() {
|
||||
go setup()
|
||||
for !done {
|
||||
}
|
||||
print(a)
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
As before, there is no guarantee that, in <code>main</code>,
|
||||
observing the write to <code>done</code>
|
||||
implies observing the write to <code>a</code>, so this program could
|
||||
print an empty string too.
|
||||
Worse, there is no guarantee that the write to <code>done</code> will ever
|
||||
be observed by <code>main</code>, since there are no synchronization
|
||||
events between the two threads. The loop in <code>main</code> is not
|
||||
guaranteed to finish.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
There are subtler variants on this theme, such as this program.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type T struct {
|
||||
msg string
|
||||
}
|
||||
|
||||
var g *T
|
||||
|
||||
func setup() {
|
||||
t := new(T)
|
||||
t.msg = "hello, world"
|
||||
g = t
|
||||
}
|
||||
|
||||
func main() {
|
||||
go setup()
|
||||
for g == nil {
|
||||
}
|
||||
print(g.msg)
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Even if <code>main</code> observes <code>g != nil</code> and exits its loop,
|
||||
there is no guarantee that it will observe the initialized
|
||||
value for <code>g.msg</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In all these examples, the solution is the same:
|
||||
use explicit synchronization.
|
||||
</p>
|
||||
|
||||
<h2 id="badcompiler">Incorrect compilation</h2>
|
||||
|
||||
<p>
|
||||
The Go memory model restricts compiler optimizations as much as it does Go programs.
|
||||
Some compiler optimizations that would be valid in single-threaded programs are not valid in all Go programs.
|
||||
In particular, a compiler must not introduce writes that do not exist in the original program,
|
||||
it must not allow a single read to observe multiple values,
|
||||
and it must not allow a single write to write multiple values.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
All the following examples assume that `*p` and `*q` refer to
|
||||
memory locations accessible to multiple goroutines.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Not introducing data races into race-free programs means not moving
|
||||
writes out of conditional statements in which they appear.
|
||||
For example, a compiler must not invert the conditional in this program:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
*p = 1
|
||||
if cond {
|
||||
*p = 2
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
That is, the compiler must not rewrite the program into this one:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
*p = 2
|
||||
if !cond {
|
||||
*p = 1
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If <code>cond</code> is false and another goroutine is reading <code>*p</code>,
|
||||
then in the original program, the other goroutine can only observe any prior value of <code>*p</code> and <code>1</code>.
|
||||
In the rewritten program, the other goroutine can observe <code>2</code>, which was previously impossible.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Not introducing data races also means not assuming that loops terminate.
|
||||
For example, a compiler must in general not move the accesses to <code>*p</code> or <code>*q</code>
|
||||
ahead of the loop in this program:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
n := 0
|
||||
for e := list; e != nil; e = e.next {
|
||||
n++
|
||||
}
|
||||
i := *p
|
||||
*q = 1
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If <code>list</code> pointed to a cyclic list,
|
||||
then the original program would never access <code>*p</code> or <code>*q</code>,
|
||||
but the rewritten program would.
|
||||
(Moving `*p` ahead would be safe if the compiler can prove `*p` will not panic;
|
||||
moving `*q` ahead would also require the compiler proving that no other
|
||||
goroutine can access `*q`.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Not introducing data races also means not assuming that called functions
|
||||
always return or are free of synchronization operations.
|
||||
For example, a compiler must not move the accesses to <code>*p</code> or <code>*q</code>
|
||||
ahead of the function call in this program
|
||||
(at least not without direct knowledge of the precise behavior of <code>f</code>):
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
f()
|
||||
i := *p
|
||||
*q = 1
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If the call never returned, then once again the original program
|
||||
would never access <code>*p</code> or <code>*q</code>, but the rewritten program would.
|
||||
And if the call contained synchronizing operations, then the original program
|
||||
could establish happens before edges preceding the accesses
|
||||
to <code>*p</code> and <code>*q</code>, but the rewritten program would not.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Not allowing a single read to observe multiple values means
|
||||
not reloading local variables from shared memory.
|
||||
For example, a compiler must not discard <code>i</code> and reload it
|
||||
a second time from <code>*p</code> in this program:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
i := *p
|
||||
if i < 0 || i >= len(funcs) {
|
||||
panic("invalid function index")
|
||||
}
|
||||
... complex code ...
|
||||
// compiler must NOT reload i = *p here
|
||||
funcs[i]()
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If the complex code needs many registers, a compiler for single-threaded programs
|
||||
could discard <code>i</code> without saving a copy and then reload
|
||||
<code>i = *p</code> just before
|
||||
<code>funcs[i]()</code>.
|
||||
A Go compiler must not, because the value of <code>*p</code> may have changed.
|
||||
(Instead, the compiler could spill <code>i</code> to the stack.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Not allowing a single write to write multiple values also means not using
|
||||
the memory where a local variable will be written as temporary storage before the write.
|
||||
For example, a compiler must not use <code>*p</code> as temporary storage in this program:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
*p = i + *p/2
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
That is, it must not rewrite the program into this one:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
*p /= 2
|
||||
*p += i
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If <code>i</code> and <code>*p</code> start equal to 2,
|
||||
the original code does <code>*p = 3</code>,
|
||||
so a racing thread can read only 2 or 3 from <code>*p</code>.
|
||||
The rewritten code does <code>*p = 1</code> and then <code>*p = 3</code>,
|
||||
allowing a racing thread to read 1 as well.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that all these optimizations are permitted in C/C++ compilers:
|
||||
a Go compiler sharing a back end with a C/C++ compiler must take care
|
||||
to disable optimizations that are invalid for Go.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that the prohibition on introducing data races
|
||||
does not apply if the compiler can prove that the races
|
||||
do not affect correct execution on the target platform.
|
||||
For example, on essentially all CPUs, it is valid to rewrite
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
n := 0
|
||||
for i := 0; i < m; i++ {
|
||||
n += *shared
|
||||
}
|
||||
</pre>
|
||||
|
||||
into:
|
||||
|
||||
<pre>
|
||||
n := 0
|
||||
local := *shared
|
||||
for i := 0; i < m; i++ {
|
||||
n += local
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
provided it can be proved that <code>*shared</code> will not fault on access,
|
||||
because the potential added read will not affect any existing concurrent reads or writes.
|
||||
On the other hand, the rewrite would not be valid in a source-to-source translator.
|
||||
</p>
|
||||
|
||||
<h2 id="conclusion">Conclusion</h2>
|
||||
|
||||
<p>
|
||||
Go programmers writing data-race-free programs can rely on
|
||||
sequentially consistent execution of those programs,
|
||||
just as in essentially all other modern programming languages.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When it comes to programs with races,
|
||||
both programmers and compilers should remember the advice:
|
||||
don't be clever.
|
||||
</p>
|
||||
8828
doc/go_spec.html
Normal file
8828
doc/go_spec.html
Normal file
File diff suppressed because it is too large
Load Diff
363
doc/godebug.md
Normal file
363
doc/godebug.md
Normal file
@@ -0,0 +1,363 @@
|
||||
---
|
||||
title: "Go, Backwards Compatibility, and GODEBUG"
|
||||
layout: article
|
||||
---
|
||||
|
||||
<!--
|
||||
This document is kept in the Go repo, not x/website,
|
||||
because it documents the full list of known GODEBUG settings,
|
||||
which are tied to a specific release.
|
||||
-->
|
||||
|
||||
## Introduction {#intro}
|
||||
|
||||
Go's emphasis on backwards compatibility is one of its key strengths.
|
||||
There are, however, times when we cannot maintain complete compatibility.
|
||||
If code depends on buggy (including insecure) behavior,
|
||||
then fixing the bug will break that code.
|
||||
New features can also have similar impacts:
|
||||
enabling the HTTP/2 use by the HTTP client broke programs
|
||||
connecting to servers with buggy HTTP/2 implementations.
|
||||
These kinds of changes are unavoidable and
|
||||
[permitted by the Go 1 compatibility rules](/doc/go1compat).
|
||||
Even so, Go provides a mechanism called GODEBUG to
|
||||
reduce the impact such changes have on Go developers
|
||||
using newer toolchains to compile old code.
|
||||
|
||||
A GODEBUG setting is a `key=value` pair
|
||||
that controls the execution of certain parts of a Go program.
|
||||
The environment variable `GODEBUG`
|
||||
can hold a comma-separated list of these settings.
|
||||
For example, if a Go program is running in an environment that contains
|
||||
|
||||
GODEBUG=http2client=0,http2server=0
|
||||
|
||||
then that Go program will disable the use of HTTP/2 by default in both
|
||||
the HTTP client and the HTTP server.
|
||||
It is also possible to set the default `GODEBUG` for a given program
|
||||
(discussed below).
|
||||
|
||||
When preparing any change that is permitted by Go 1 compatibility
|
||||
but may nonetheless break some existing programs,
|
||||
we first engineer the change to keep as many existing programs working as possible.
|
||||
For the remaining programs,
|
||||
we define a new GODEBUG setting that
|
||||
allows individual programs to opt back in to the old behavior.
|
||||
A GODEBUG setting may not be added if doing so is infeasible,
|
||||
but that should be extremely rare.
|
||||
|
||||
GODEBUG settings added for compatibility will be maintained
|
||||
for a minimum of two years (four Go releases).
|
||||
Some, such as `http2client` and `http2server`,
|
||||
will be maintained much longer, even indefinitely.
|
||||
|
||||
When possible, each GODEBUG setting has an associated
|
||||
[runtime/metrics](/pkg/runtime/metrics/) counter
|
||||
named `/godebug/non-default-behavior/<name>:events`
|
||||
that counts the number of times a particular program's
|
||||
behavior has changed based on a non-default value
|
||||
for that setting.
|
||||
For example, when `GODEBUG=http2client=0` is set,
|
||||
`/godebug/non-default-behavior/http2client:events`
|
||||
counts the number of HTTP transports that the program
|
||||
has configured without HTTP/2 support.
|
||||
|
||||
## Default GODEBUG Values {#default}
|
||||
|
||||
When a GODEBUG setting is not listed in the environment variable,
|
||||
its value is derived from three sources:
|
||||
the defaults for the Go toolchain used to build the program,
|
||||
amended to match the Go version listed in `go.mod`,
|
||||
and then overridden by explicit `//go:debug` lines in the program.
|
||||
|
||||
The [GODEBUG History](#history) gives the exact defaults for each Go toolchain version.
|
||||
For example, Go 1.21 introduces the `panicnil` setting,
|
||||
controlling whether `panic(nil)` is allowed;
|
||||
it defaults to `panicnil=0`, making `panic(nil)` a run-time error.
|
||||
Using `panicnil=1` restores the behavior of Go 1.20 and earlier.
|
||||
|
||||
When compiling a work module or workspace that declares
|
||||
an older Go version, the Go toolchain amends its defaults
|
||||
to match that older Go version as closely as possible.
|
||||
For example, when a Go 1.21 toolchain compiles a program,
|
||||
if the work module's `go.mod` or the workspace's `go.work`
|
||||
says `go` `1.20`, then the program defaults to `panicnil=1`,
|
||||
matching Go 1.20 instead of Go 1.21.
|
||||
|
||||
Because this method of setting GODEBUG defaults was introduced only in Go 1.21,
|
||||
programs listing versions of Go earlier than Go 1.20 are configured to match Go 1.20,
|
||||
not the older version.
|
||||
|
||||
To override these defaults, starting in Go 1.23, the work module's `go.mod`
|
||||
or the workspace's `go.work` can list one or more `godebug` lines:
|
||||
|
||||
godebug (
|
||||
default=go1.21
|
||||
panicnil=1
|
||||
asynctimerchan=0
|
||||
)
|
||||
|
||||
The special key `default` indicates a Go version to take unspecified
|
||||
settings from. This allows setting the GODEBUG defaults separately
|
||||
from the Go language version in the module.
|
||||
In this example, the program is asking for Go 1.21 semantics and
|
||||
then asking for the old pre-Go 1.21 `panic(nil)` behavior and the
|
||||
new Go 1.23 `asynctimerchan=0` behavior.
|
||||
|
||||
Only the work module's `go.mod` is consulted for `godebug` directives.
|
||||
Any directives in required dependency modules are ignored.
|
||||
It is an error to list a `godebug` with an unrecognized setting.
|
||||
(Toolchains older than Go 1.23 reject all `godebug` lines, since they do not
|
||||
understand `godebug` at all.)
|
||||
|
||||
The defaults from the `go` and `godebug` lines apply to all main
|
||||
packages that are built. For more fine-grained control,
|
||||
starting in Go 1.21, a main package's source files
|
||||
can include one or more `//go:debug` directives at the top of the file
|
||||
(preceding the `package` statement).
|
||||
The `godebug` lines in the previous example would be written:
|
||||
|
||||
//go:debug default=go1.21
|
||||
//go:debug panicnil=1
|
||||
//go:debug asynctimerchan=0
|
||||
|
||||
Starting in Go 1.21, the Go toolchain treats a `//go:debug` directive
|
||||
with an unrecognized GODEBUG setting as an invalid program.
|
||||
Programs with more than one `//go:debug` line for a given setting
|
||||
are also treated as invalid.
|
||||
(Older toolchains ignore `//go:debug` directives entirely.)
|
||||
|
||||
The defaults that will be compiled into a main package
|
||||
are reported by the command:
|
||||
|
||||
{{raw `
|
||||
go list -f '{{.DefaultGODEBUG}}' my/main/package
|
||||
`}}
|
||||
|
||||
Only differences from the base Go toolchain defaults are reported.
|
||||
|
||||
When testing a package, `//go:debug` lines in the `*_test.go`
|
||||
files are treated as directives for the test's main package.
|
||||
In any other context, `//go:debug` lines are ignored by the toolchain;
|
||||
`go` `vet` reports such lines as misplaced.
|
||||
|
||||
## GODEBUG History {#history}
|
||||
|
||||
This section documents the GODEBUG settings introduced and removed in each major Go release
|
||||
for compatibility reasons.
|
||||
Packages or programs may define additional settings for internal debugging purposes;
|
||||
for example,
|
||||
see the [runtime documentation](/pkg/runtime#hdr-Environment_Variables)
|
||||
and the [go command documentation](/cmd/go#hdr-Build_and_test_caching).
|
||||
|
||||
### Go 1.23
|
||||
|
||||
Go 1.23 changed the channels created by package time to be unbuffered
|
||||
(synchronous), which makes correct use of the [`Timer.Stop`](/pkg/time/#Timer.Stop)
|
||||
and [`Timer.Reset`](/pkg/time/#Timer.Reset) method results much easier.
|
||||
The [`asynctimerchan` setting](/pkg/time/#NewTimer) disables this change.
|
||||
There are no runtime metrics for this change,
|
||||
This setting may be removed in a future release, Go 1.27 at the earliest.
|
||||
|
||||
Go 1.23 changed the mode bits reported by [`os.Lstat`](/pkg/os#Lstat) and [`os.Stat`](/pkg/os#Stat)
|
||||
for reparse points, which can be controlled with the `winsymlink` setting.
|
||||
As of Go 1.23 (`winsymlink=1`), mount points no longer have [`os.ModeSymlink`](/pkg/os#ModeSymlink)
|
||||
set, and reparse points that are not symlinks, Unix sockets, or dedup files now
|
||||
always have [`os.ModeIrregular`](/pkg/os#ModeIrregular) set. As a result of these changes,
|
||||
[`filepath.EvalSymlinks`](/pkg/path/filepath#EvalSymlinks) no longer evaluates
|
||||
mount points, which was a source of many inconsistencies and bugs.
|
||||
At previous versions (`winsymlink=0`), mount points are treated as symlinks,
|
||||
and other reparse points with non-default [`os.ModeType`](/pkg/os#ModeType) bits
|
||||
(such as [`os.ModeDir`](/pkg/os#ModeDir)) do not have the `ModeIrregular` bit set.
|
||||
|
||||
Go 1.23 changed [`os.Readlink`](/pkg/os#Readlink) and [`filepath.EvalSymlinks`](/pkg/path/filepath#EvalSymlinks)
|
||||
to avoid trying to normalize volumes to drive letters, which was not always even possible.
|
||||
This behavior is controlled by the `winreadlinkvolume` setting.
|
||||
For Go 1.23, it defaults to `winreadlinkvolume=1`.
|
||||
Previous versions default to `winreadlinkvolume=0`.
|
||||
|
||||
Go 1.23 enabled the experimental post-quantum key exchange mechanism
|
||||
X25519Kyber768Draft00 by default. The default can be reverted using the
|
||||
[`tlskyber` setting](/pkg/crypto/tls/#Config.CurvePreferences).
|
||||
|
||||
Go 1.23 changed the behavior of
|
||||
[crypto/x509.ParseCertificate](/pkg/crypto/x509/#ParseCertificate) to reject
|
||||
serial numbers that are negative. This change can be reverted with
|
||||
the [`x509negativeserial` setting](/pkg/crypto/x509/#ParseCertificate).
|
||||
|
||||
Go 1.23 re-enabled support in html/template for ECMAScript 6 template literals by default.
|
||||
The [`jstmpllitinterp` setting](/pkg/html/template#hdr-Security_Model) no longer has
|
||||
any effect.
|
||||
|
||||
Go 1.23 changed the default TLS cipher suites used by clients and servers when
|
||||
not explicitly configured, removing 3DES cipher suites. The default can be reverted
|
||||
using the [`tls3des` setting](/pkg/crypto/tls/#Config.CipherSuites).
|
||||
|
||||
Go 1.23 changed the behavior of [`tls.X509KeyPair`](/pkg/crypto/tls#X509KeyPair)
|
||||
and [`tls.LoadX509KeyPair`](/pkg/crypto/tls#LoadX509KeyPair) to populate the
|
||||
Leaf field of the returned [`tls.Certificate`](/pkg/crypto/tls#Certificate).
|
||||
This behavior is controlled by the `x509keypairleaf` setting. For Go 1.23, it
|
||||
defaults to `x509keypairleaf=1`. Previous versions default to
|
||||
`x509keypairleaf=0`.
|
||||
|
||||
Go 1.23 changed
|
||||
[`net/http.ServeContent`](/pkg/net/http#ServeContent),
|
||||
[`net/http.ServeFile`](/pkg/net/http#ServeFile), and
|
||||
[`net/http.ServeFS`](/pkg/net/http#ServeFS) to
|
||||
remove Cache-Control, Content-Encoding, Etag, and Last-Modified headers
|
||||
when serving an error. This behavior is controlled by
|
||||
the [`httpservecontentkeepheaders` setting](/pkg/net/http#ServeContent).
|
||||
Using `httpservecontentkeepheaders=1` restores the pre-Go 1.23 behavior.
|
||||
|
||||
### Go 1.22
|
||||
|
||||
Go 1.22 adds a configurable limit to control the maximum acceptable RSA key size
|
||||
that can be used in TLS handshakes, controlled by the [`tlsmaxrsasize` setting](/pkg/crypto/tls#Conn.Handshake).
|
||||
The default is tlsmaxrsasize=8192, limiting RSA to 8192-bit keys. To avoid
|
||||
denial of service attacks, this setting and default was backported to Go
|
||||
1.19.13, Go 1.20.8, and Go 1.21.1.
|
||||
|
||||
Go 1.22 made it an error for a request or response read by a net/http
|
||||
client or server to have an empty Content-Length header.
|
||||
This behavior is controlled by the `httplaxcontentlength` setting.
|
||||
|
||||
Go 1.22 changed the behavior of ServeMux to accept extended
|
||||
patterns and unescape both patterns and request paths by segment.
|
||||
This behavior can be controlled by the
|
||||
[`httpmuxgo121` setting](/pkg/net/http/#ServeMux).
|
||||
|
||||
Go 1.22 added the [Alias type](/pkg/go/types#Alias) to [go/types](/pkg/go/types)
|
||||
for the explicit representation of [type aliases](/ref/spec#Type_declarations).
|
||||
Whether the type checker produces `Alias` types or not is controlled by the
|
||||
[`gotypesalias` setting](/pkg/go/types#Alias).
|
||||
For Go 1.22 it defaults to `gotypesalias=0`.
|
||||
For Go 1.23, `gotypesalias=1` will become the default.
|
||||
This setting will be removed in a future release, Go 1.27 at the earliest.
|
||||
|
||||
Go 1.22 changed the default minimum TLS version supported by both servers
|
||||
and clients to TLS 1.2. The default can be reverted to TLS 1.0 using the
|
||||
[`tls10server` setting](/pkg/crypto/tls/#Config).
|
||||
|
||||
Go 1.22 changed the default TLS cipher suites used by clients and servers when
|
||||
not explicitly configured, removing the cipher suites which used RSA based key
|
||||
exchange. The default can be reverted using the [`tlsrsakex` setting](/pkg/crypto/tls/#Config).
|
||||
|
||||
Go 1.22 disabled
|
||||
[`ConnectionState.ExportKeyingMaterial`](/pkg/crypto/tls/#ConnectionState.ExportKeyingMaterial)
|
||||
when the connection supports neither TLS 1.3 nor Extended Master Secret
|
||||
(implemented in Go 1.21). It can be reenabled with the [`tlsunsafeekm`
|
||||
setting](/pkg/crypto/tls/#ConnectionState.ExportKeyingMaterial).
|
||||
|
||||
Go 1.22 changed how the runtime interacts with transparent huge pages on Linux.
|
||||
In particular, a common default Linux kernel configuration can result in
|
||||
significant memory overheads, and Go 1.22 no longer works around this default.
|
||||
To work around this issue without adjusting kernel settings, transparent huge
|
||||
pages can be disabled for Go memory with the
|
||||
[`disablethp` setting](/pkg/runtime#hdr-Environment_Variable).
|
||||
This behavior was backported to Go 1.21.1, but the setting is only available
|
||||
starting with Go 1.21.6.
|
||||
This setting may be removed in a future release, and users impacted by this issue
|
||||
should adjust their Linux configuration according to the recommendations in the
|
||||
[GC guide](/doc/gc-guide#Linux_transparent_huge_pages), or switch to a Linux
|
||||
distribution that disables transparent huge pages altogether.
|
||||
|
||||
Go 1.22 added contention on runtime-internal locks to the [`mutex`
|
||||
profile](/pkg/runtime/pprof#Profile). Contention on these locks is always
|
||||
reported at `runtime._LostContendedRuntimeLock`. Complete stack traces of
|
||||
runtime locks can be enabled with the [`runtimecontentionstacks`
|
||||
setting](/pkg/runtime#hdr-Environment_Variable). These stack traces have
|
||||
non-standard semantics, see setting documentation for details.
|
||||
|
||||
Go 1.22 added a new [`crypto/x509.Certificate`](/pkg/crypto/x509/#Certificate)
|
||||
field, [`Policies`](/pkg/crypto/x509/#Certificate.Policies), which supports
|
||||
certificate policy OIDs with components larger than 31 bits. By default this
|
||||
field is only used during parsing, when it is populated with policy OIDs, but
|
||||
not used during marshaling. It can be used to marshal these larger OIDs, instead
|
||||
of the existing PolicyIdentifiers field, by using the
|
||||
[`x509usepolicies` setting.](/pkg/crypto/x509/#CreateCertificate).
|
||||
|
||||
|
||||
### Go 1.21
|
||||
|
||||
Go 1.21 made it a run-time error to call `panic` with a nil interface value,
|
||||
controlled by the [`panicnil` setting](/pkg/builtin/#panic).
|
||||
|
||||
Go 1.21 made it an error for html/template actions to appear inside of an ECMAScript 6
|
||||
template literal, controlled by the
|
||||
[`jstmpllitinterp` setting](/pkg/html/template#hdr-Security_Model).
|
||||
This behavior was backported to Go 1.19.8+ and Go 1.20.3+.
|
||||
|
||||
Go 1.21 introduced a limit on the maximum number of MIME headers and multipart
|
||||
forms, controlled by the
|
||||
[`multipartmaxheaders` and `multipartmaxparts` settings](/pkg/mime/multipart#hdr-Limits)
|
||||
respectively.
|
||||
This behavior was backported to Go 1.19.8+ and Go 1.20.3+.
|
||||
|
||||
Go 1.21 adds the support of Multipath TCP but it is only used if the application
|
||||
explicitly asked for it. This behavior can be controlled by the
|
||||
[`multipathtcp` setting](/pkg/net#Dialer.SetMultipathTCP).
|
||||
|
||||
There is no plan to remove any of these settings.
|
||||
|
||||
### Go 1.20
|
||||
|
||||
Go 1.20 introduced support for rejecting insecure paths in tar and zip archives,
|
||||
controlled by the [`tarinsecurepath` setting](/pkg/archive/tar/#Reader.Next)
|
||||
and the [`zipinsecurepath` setting](/pkg/archive/zip/#NewReader).
|
||||
These default to `tarinsecurepath=1` and `zipinsecurepath=1`,
|
||||
preserving the behavior of earlier versions of Go.
|
||||
A future version of Go may change the defaults to
|
||||
`tarinsecurepath=0` and `zipinsecurepath=0`.
|
||||
|
||||
Go 1.20 introduced automatic seeding of the
|
||||
[`math/rand`](/pkg/math/rand) global random number generator,
|
||||
controlled by the [`randautoseed` setting](/pkg/math/rand/#Seed).
|
||||
|
||||
Go 1.20 introduced the concept of fallback roots for use during certificate verification,
|
||||
controlled by the [`x509usefallbackroots` setting](/pkg/crypto/x509/#SetFallbackRoots).
|
||||
|
||||
Go 1.20 removed the preinstalled `.a` files for the standard library
|
||||
from the Go distribution.
|
||||
Installations now build and cache the standard library like
|
||||
packages in other modules.
|
||||
The [`installgoroot` setting](/cmd/go#hdr-Compile_and_install_packages_and_dependencies)
|
||||
restores the installation and use of preinstalled `.a` files.
|
||||
|
||||
There is no plan to remove any of these settings.
|
||||
|
||||
### Go 1.19
|
||||
|
||||
Go 1.19 made it an error for path lookups to resolve to binaries in the current directory,
|
||||
controlled by the [`execerrdot` setting](/pkg/os/exec#hdr-Executables_in_the_current_directory).
|
||||
There is no plan to remove this setting.
|
||||
|
||||
Go 1.19 started sending EDNS0 additional headers on DNS requests.
|
||||
This can reportedly break the DNS server provided on some routers,
|
||||
such as CenturyLink Zyxel C3000Z.
|
||||
This can be changed by the [`netedns0` setting](/pkg/net#hdr-Name_Resolution).
|
||||
This setting is available in Go 1.21.12, Go 1.22.5, Go 1.23, and later.
|
||||
There is no plan to remove this setting.
|
||||
|
||||
### Go 1.18
|
||||
|
||||
Go 1.18 removed support for SHA1 in most X.509 certificates,
|
||||
controlled by the [`x509sha1` setting](/pkg/crypto/x509#InsecureAlgorithmError).
|
||||
This setting will be removed in a future release, Go 1.22 at the earliest.
|
||||
|
||||
### Go 1.10
|
||||
|
||||
Go 1.10 changed how build caching worked and added test caching, along
|
||||
with the [`gocacheverify`, `gocachehash`, and `gocachetest` settings](/cmd/go/#hdr-Build_and_test_caching).
|
||||
There is no plan to remove these settings.
|
||||
|
||||
### Go 1.6
|
||||
|
||||
Go 1.6 introduced transparent support for HTTP/2,
|
||||
controlled by the [`http2client`, `http2server`, and `http2debug` settings](/pkg/net/http/#hdr-HTTP_2).
|
||||
There is no plan to remove these settings.
|
||||
|
||||
### Go 1.5
|
||||
|
||||
Go 1.5 introduced a pure Go DNS resolver,
|
||||
controlled by the [`netdns` setting](/pkg/net/#hdr-Name_Resolution).
|
||||
There is no plan to remove this setting.
|
||||
14
doc/initial/1-intro.md
Normal file
14
doc/initial/1-intro.md
Normal file
@@ -0,0 +1,14 @@
|
||||
<!--
|
||||
NOTE: In this document and others in this directory, the convention is to
|
||||
set fixed-width phrases with non-fixed-width spaces, as in
|
||||
`hello` `world`.
|
||||
-->
|
||||
|
||||
<style>
|
||||
main ul li { margin: 0.5em 0; }
|
||||
</style>
|
||||
|
||||
## DRAFT RELEASE NOTES — Introduction to Go 1.N {#introduction}
|
||||
|
||||
**Go 1.N is not yet released. These are work-in-progress release notes.
|
||||
Go 1.N is expected to be released in {Month} {Year}.**
|
||||
3
doc/initial/2-language.md
Normal file
3
doc/initial/2-language.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## Changes to the language {#language}
|
||||
|
||||
|
||||
6
doc/initial/3-tools.md
Normal file
6
doc/initial/3-tools.md
Normal file
@@ -0,0 +1,6 @@
|
||||
## Tools {#tools}
|
||||
|
||||
### Go command {#go-command}
|
||||
|
||||
### Cgo {#cgo}
|
||||
|
||||
1
doc/initial/4-runtime.md
Normal file
1
doc/initial/4-runtime.md
Normal file
@@ -0,0 +1 @@
|
||||
## Runtime {#runtime}
|
||||
7
doc/initial/5-toolchain.md
Normal file
7
doc/initial/5-toolchain.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## Compiler {#compiler}
|
||||
|
||||
## Assembler {#assembler}
|
||||
|
||||
## Linker {#linker}
|
||||
|
||||
|
||||
2
doc/initial/6-stdlib/0-heading.md
Normal file
2
doc/initial/6-stdlib/0-heading.md
Normal file
@@ -0,0 +1,2 @@
|
||||
## Standard library {#library}
|
||||
|
||||
3
doc/initial/6-stdlib/99-minor/0-heading.md
Normal file
3
doc/initial/6-stdlib/99-minor/0-heading.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Minor changes to the library {#minor_library_changes}
|
||||
|
||||
|
||||
1
doc/initial/6-stdlib/99-minor/README
Normal file
1
doc/initial/6-stdlib/99-minor/README
Normal file
@@ -0,0 +1 @@
|
||||
API changes and other small changes to the standard library go here.
|
||||
2
doc/initial/7-ports.md
Normal file
2
doc/initial/7-ports.md
Normal file
@@ -0,0 +1,2 @@
|
||||
## Ports {#ports}
|
||||
|
||||
Reference in New Issue
Block a user