mirror of
https://github.com/golang/go.git
synced 2026-01-29 15:12:08 +03:00
Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe8a0d12b1 | ||
|
|
4059afb419 | ||
|
|
5feffb4395 | ||
|
|
fce993d1a2 | ||
|
|
8558db9a38 | ||
|
|
28ae82663a | ||
|
|
4aa7bfdce4 | ||
|
|
2bded9dc19 | ||
|
|
48ee689f19 | ||
|
|
09fa131c99 | ||
|
|
fd4fbf6721 | ||
|
|
516f5ccf57 | ||
|
|
f858dbd1f0 | ||
|
|
71bdbf431b | ||
|
|
8cbc2b82e3 | ||
|
|
7c1fca5f75 | ||
|
|
457334d87c | ||
|
|
f26ed07f53 | ||
|
|
5b6ff694bb | ||
|
|
11d7a5a950 | ||
|
|
abccc7a9b5 | ||
|
|
8e1f12f001 | ||
|
|
ac7c0ee26d | ||
|
|
ff5bff8a5f | ||
|
|
76b63aaab9 | ||
|
|
051e204c79 | ||
|
|
e069f90e17 | ||
|
|
04c58320c9 | ||
|
|
67582b1669 | ||
|
|
eef2fd28ca | ||
|
|
4bc847d8c9 | ||
|
|
c917b3c32b | ||
|
|
9f7d0c968f | ||
|
|
4e19a5498d | ||
|
|
df9d6204b9 | ||
|
|
67b6956270 | ||
|
|
8d90bb4b19 | ||
|
|
24879947d5 | ||
|
|
1188eb9c5b | ||
|
|
ee97231599 | ||
|
|
69a7f73de8 | ||
|
|
853155f384 | ||
|
|
b8c62b1a89 | ||
|
|
176900a7b7 | ||
|
|
e1c0834592 | ||
|
|
fe0d248f29 | ||
|
|
b3398f8fa8 | ||
|
|
6936a87ce1 | ||
|
|
678dede7bc | ||
|
|
bf86aec259 | ||
|
|
0b3f04d5f9 | ||
|
|
d1fbe07092 | ||
|
|
c622ec556b | ||
|
|
07a153e0a4 | ||
|
|
65b209897f | ||
|
|
a68e93791d | ||
|
|
419e6f0835 |
@@ -268,6 +268,12 @@ view a wiki page. It will handle URLs prefixed with "/view/".
|
||||
|
||||
{{code "doc/articles/wiki/part2.go" `/^func viewHandler/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
Again, note the use of <code>_</code> to ignore the <code>error</code>
|
||||
return value from <code>loadPage</code>. This is done here for simplicity
|
||||
and generally considered bad practice. We will attend to this later.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First, this function extracts the page title from <code>r.URL.Path</code>,
|
||||
the path component of the request URL.
|
||||
@@ -282,12 +288,6 @@ The function then loads the page data, formats the page with a string of simple
|
||||
HTML, and writes it to <code>w</code>, the <code>http.ResponseWriter</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Again, note the use of <code>_</code> to ignore the <code>error</code>
|
||||
return value from <code>loadPage</code>. This is done here for simplicity
|
||||
and generally considered bad practice. We will attend to this later.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To use this handler, we rewrite our <code>main</code> function to
|
||||
initialize <code>http</code> using the <code>viewHandler</code> to handle
|
||||
|
||||
65
doc/asm.html
65
doc/asm.html
@@ -738,6 +738,13 @@ The other codes are <code>-></code> (arithmetic right shift),
|
||||
The ARM64 port is in an experimental state.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<code>R18</code> is the "platform register", reserved on the Apple platform.
|
||||
<code>R27</code> and <code>R28</code> are reserved by the compiler and linker.
|
||||
<code>R29</code> is the frame pointer.
|
||||
<code>R30</code> is the link register.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Instruction modifiers are appended to the instruction following a period.
|
||||
The only modifiers are <code>P</code> (postincrement) and <code>W</code>
|
||||
@@ -752,11 +759,61 @@ Addressing modes:
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<code>(R5, R6)</code>: Register pair for <code>LDP</code>/<code>STP</code>.
|
||||
<code>R0->16</code>
|
||||
<br>
|
||||
<code>R0>>16</code>
|
||||
<br>
|
||||
<code>R0<<16</code>
|
||||
<br>
|
||||
<code>R0@>16</code>:
|
||||
These are the same as on the 32-bit ARM.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<code>$(8<<12)</code>:
|
||||
Left shift the immediate value <code>8</code> by <code>12</code> bits.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<code>8(R0)</code>:
|
||||
Add the value of <code>R0</code> and <code>8</code>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<code>(R2)(R0)</code>:
|
||||
The location at <code>R0</code> plus <code>R2</code>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<code>R0.UXTB</code>
|
||||
<br>
|
||||
<code>R0.UXTB<<imm</code>:
|
||||
<code>UXTB</code>: extract an 8-bit value from the low-order bits of <code>R0</code> and zero-extend it to the size of <code>R0</code>.
|
||||
<code>R0.UXTB<<imm</code>: left shift the result of <code>R0.UXTB</code> by <code>imm</code> bits.
|
||||
The <code>imm</code> value can be 0, 1, 2, 3, or 4.
|
||||
The other extensions include <code>UXTH</code> (16-bit), <code>UXTW</code> (32-bit), and <code>UXTX</code> (64-bit).
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<code>R0.SXTB</code>
|
||||
<br>
|
||||
<code>R0.SXTB<<imm</code>:
|
||||
<code>SXTB</code>: extract an 8-bit value from the low-order bits of <code>R0</code> and sign-extend it to the size of <code>R0</code>.
|
||||
<code>R0.SXTB<<imm</code>: left shift the result of <code>R0.SXTB</code> by <code>imm</code> bits.
|
||||
The <code>imm</code> value can be 0, 1, 2, 3, or 4.
|
||||
The other extensions include <code>SXTH</code> (16-bit), <code>SXTW</code> (32-bit), and <code>SXTX</code> (64-bit).
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<code>(R5, R6)</code>: Register pair for <code>LDAXP</code>/<code>LDP</code>/<code>LDXP</code>/<code>STLXP</code>/<code>STP</code>/<code>STP</code>.
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Reference: <a href="/pkg/cmd/internal/obj/arm64">Go ARM64 Assembly Instructions Reference Manual</a>
|
||||
</p>
|
||||
|
||||
<h3 id="ppc64">64-bit PowerPC, a.k.a. ppc64</h3>
|
||||
|
||||
<p>
|
||||
@@ -882,6 +939,12 @@ The value of <code>GOMIPS</code> environment variable (<code>hardfloat</code> or
|
||||
<code>GOMIPS_hardfloat</code> or <code>GOMIPS_softfloat</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The value of <code>GOMIPS64</code> environment variable (<code>hardfloat</code> or
|
||||
<code>softfloat</code>) is made available to assembly code by predefining either
|
||||
<code>GOMIPS64_hardfloat</code> or <code>GOMIPS64_softfloat</code>.
|
||||
</p>
|
||||
|
||||
<h3 id="unsupported_opcodes">Unsupported opcodes</h3>
|
||||
|
||||
<p>
|
||||
|
||||
234
doc/conduct.html
234
doc/conduct.html
@@ -13,15 +13,14 @@ ul ul {
|
||||
}
|
||||
</style>
|
||||
|
||||
<h2 id="about">About the Code of Conduct</h2>
|
||||
|
||||
<h3 id="why">Why have a Code of Conduct?</h3>
|
||||
<h2 id="about">About</h2>
|
||||
|
||||
<p>
|
||||
Online communities include people from many different backgrounds.
|
||||
The Go contributors are committed to providing a friendly, safe and welcoming
|
||||
environment for all, regardless of age, disability, gender, nationality,
|
||||
ethnicity, religion, sexuality, or similar personal characteristic.
|
||||
environment for all, regardless of gender identity and expression, sexual orientation,
|
||||
disabilities, neurodiversity, physical appearance, body size, ethnicity, nationality,
|
||||
race, age, religion, or similar personal characteristics.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -44,35 +43,9 @@ contributors and users from all backgrounds.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
With that said, a healthy community must allow for disagreement and debate.
|
||||
The Code of Conduct is not a mechanism for people to silence others with whom
|
||||
they disagree.
|
||||
</p>
|
||||
|
||||
<h3 id="spaces">Where does the Code of Conduct apply?</h3>
|
||||
|
||||
<p>
|
||||
If you participate in or contribute to the Go ecosystem in any way,
|
||||
you are encouraged to follow the Code of Conduct while doing so.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Explicit enforcement of the Code of Conduct applies to the
|
||||
official forums operated by the Go project (“Go spaces”):
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>The official <a href="https://github.com/golang/">GitHub projects</a>
|
||||
and <a href="https://go-review.googlesource.com/">code reviews</a>.
|
||||
<li>The <a href="https://groups.google.com/group/golang-nuts">golang-nuts</a> and
|
||||
<a href="https://groups.google.com/group/golang-dev">golang-dev</a> mailing lists.
|
||||
<li>The #go-nuts IRC channel on Freenode.
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Other Go groups (such as conferences, meetups, and other unofficial forums) are
|
||||
encouraged to adopt this Code of Conduct. Those groups must provide their own
|
||||
moderators and/or working group (see below).
|
||||
We believe that healthy debate and disagreement are essential to a healthy project and community.
|
||||
However, it is never ok to be disrespectful.
|
||||
We value diverse opinions, but we value respectful behavior more.
|
||||
</p>
|
||||
|
||||
<h2 id="values">Gopher values</h2>
|
||||
@@ -129,118 +102,104 @@ Even if the intent was to provoke, do not rise to it.
|
||||
It is the responsibility of <i>all parties</i> to de-escalate conflict when it arises.
|
||||
</p>
|
||||
|
||||
<h2 id="unwelcome_behavior">Unwelcome behavior</h2>
|
||||
<h2 id="code">Code of Conduct</h2>
|
||||
|
||||
<p>
|
||||
These actions are explicitly forbidden in Go spaces:
|
||||
</p>
|
||||
<h3 id="our-pledge">Our Pledge</h3>
|
||||
|
||||
<p>In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of
|
||||
experience, education, socio-economic status, nationality, personal appearance,
|
||||
race, religion, or sexual identity and orientation.</p>
|
||||
|
||||
<h3 id="our-standards">Our Standards</h3>
|
||||
|
||||
<p>Examples of behavior that contributes to creating a positive environment
|
||||
include:</p>
|
||||
|
||||
<ul>
|
||||
<li>Insulting, demeaning, hateful, or threatening remarks.
|
||||
<li>Discrimination based on age, disability, gender, nationality, race,
|
||||
religion, sexuality, or similar personal characteristic.
|
||||
<li>Bullying or systematic harassment.
|
||||
<li>Unwelcome sexual advances.
|
||||
<li>Incitement to any of these.
|
||||
<li>Using welcoming and inclusive language</li>
|
||||
<li>Being respectful of differing viewpoints and experiences</li>
|
||||
<li>Gracefully accepting constructive criticism</li>
|
||||
<li>Focusing on what is best for the community</li>
|
||||
<li>Showing empathy towards other community members</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="moderation">Moderation</h2>
|
||||
|
||||
<p>
|
||||
The Go spaces are not free speech venues; they are for discussion about Go.
|
||||
Each of these spaces have their own moderators.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When using the official Go spaces you should act in the spirit of the “Gopher
|
||||
values”.
|
||||
If a reported conflict cannot be resolved amicably, the CoC Working Group
|
||||
may make a recommendation to the relevant forum moderators.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
CoC Working Group members and forum moderators are held to a higher standard than other community members.
|
||||
If a working group member or moderator creates an inappropriate situation, they
|
||||
should expect less leeway than others, and should expect to be removed from
|
||||
their position if they cannot adhere to the CoC.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Complaints about working group member or moderator actions must be handled
|
||||
using the reporting process below.
|
||||
</p>
|
||||
|
||||
<h2 id="reporting">Reporting issues</h2>
|
||||
|
||||
<p>
|
||||
The Code of Conduct Working Group is a group of people that represent the Go
|
||||
community. They are responsible for handling conduct-related issues.
|
||||
Their purpose is to de-escalate conflicts and try to resolve issues to the
|
||||
satisfaction of all parties. They are:
|
||||
</p>
|
||||
<p>Examples of unacceptable behavior by participants include:</p>
|
||||
|
||||
<ul>
|
||||
<li>Aditya Mukerjee <dev@chimeracoder.net>
|
||||
<li>Andrew Gerrand <adg@golang.org>
|
||||
<li>Peggy Li <peggyli.224@gmail.com>
|
||||
<li>Steve Francia <steve.francia@gmail.com>
|
||||
<li>Verónica López <gveronicalg@gmail.com>
|
||||
<li>The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances</li>
|
||||
<li>Trolling, insulting/derogatory comments, and personal or political attacks</li>
|
||||
<li>Public or private harassment</li>
|
||||
<li>Publishing others’ private information, such as a physical or electronic
|
||||
address, without explicit permission</li>
|
||||
<li>Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
If you encounter a conduct-related issue, you should report it to the
|
||||
Working Group using the process described below.
|
||||
<b>Do not</b> post about the issue publicly or try to rally sentiment against a
|
||||
particular individual or group.
|
||||
</p>
|
||||
<h3 id="our-responsibilities">Our Responsibilities</h3>
|
||||
|
||||
<ul>
|
||||
<li>Mail <a href="mailto:conduct@golang.org">conduct@golang.org</a>.
|
||||
<ul>
|
||||
<li>Your message will reach the Working Group.
|
||||
<li>Reports are confidential within the Working Group.
|
||||
<li>You may contact a member of the group directly if you do not feel
|
||||
comfortable contacting the group as a whole. That member will then raise
|
||||
the issue with the Working Group as a whole, preserving the privacy of the
|
||||
reporter (if desired).
|
||||
<li>If your report concerns a member of the Working Group they will be recused
|
||||
from Working Group discussions of the report.
|
||||
<li>The Working Group will strive to handle reports with discretion and
|
||||
sensitivity, to protect the privacy of the involved parties,
|
||||
and to avoid conflicts of interest.
|
||||
</ul>
|
||||
<li>You should receive a response within 48 hours (likely sooner).
|
||||
(Should you choose to contact a single Working Group member,
|
||||
it may take longer to receive a response.)
|
||||
<li>The Working Group will meet to review the incident and determine what happened.
|
||||
<ul>
|
||||
<li>With the permission of person reporting the incident, the Working Group
|
||||
may reach out to other community members for more context.
|
||||
</ul>
|
||||
<li>The Working Group will reach a decision as to how to act. These may include:
|
||||
<ul>
|
||||
<li>Nothing.
|
||||
<li>Passing the report along to the offender.
|
||||
<li>A recommendation of action to the relevant forum moderators.
|
||||
</ul>
|
||||
<li>The Working Group will reach out to the original reporter to let them know
|
||||
the decision.
|
||||
<li>Appeals to the decision may be made to the Working Group,
|
||||
or to any of its members directly.
|
||||
</ul>
|
||||
<p>Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.</p>
|
||||
|
||||
<p>
|
||||
<b>Note that the goal of the Code of Conduct and the Working Group is to resolve
|
||||
conflicts in the most harmonious way possible.</b>
|
||||
We hope that in most cases issues may be resolved through polite discussion and
|
||||
mutual agreement.
|
||||
</p>
|
||||
<p>Project maintainers have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, or to ban temporarily or permanently any
|
||||
contributor for other behaviors that they deem inappropriate, threatening,
|
||||
offensive, or harmful.</p>
|
||||
|
||||
<p>
|
||||
Changes to the Code of Conduct (including to the members of the Working Group)
|
||||
should be proposed using the
|
||||
<a href="https://golang.org/s/proposal-process">change proposal process</a>.
|
||||
</p>
|
||||
<h3 id="scope">Scope</h3>
|
||||
|
||||
<p>This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.</p>
|
||||
|
||||
<p>This Code of Conduct also applies outside the project spaces when the Project
|
||||
Steward has a reasonable belief that an individual’s behavior may have a
|
||||
negative impact on the project or its community.</p>
|
||||
|
||||
<h3 id="conflict-resolution"></a>Conflict Resolution</h3>
|
||||
|
||||
<p>We do not believe that all conflict is bad; healthy debate and disagreement
|
||||
often yield positive results. However, it is never okay to be disrespectful or
|
||||
to engage in behavior that violates the project’s code of conduct.</p>
|
||||
|
||||
<p>If you see someone violating the code of conduct, you are encouraged to address
|
||||
the behavior directly with those involved. Many issues can be resolved quickly
|
||||
and easily, and this gives people more control over the outcome of their
|
||||
dispute. If you are unable to resolve the matter for any reason, or if the
|
||||
behavior is threatening or harassing, report it. We are dedicated to providing
|
||||
an environment where participants feel welcome and safe.</p>
|
||||
|
||||
<p id="reporting">Reports should be directed to Cassandra Salisbury, the
|
||||
Go Project Steward, at <i>conduct@golang.org</i>.
|
||||
It is the Project Steward’s duty to
|
||||
receive and address reported violations of the code of conduct. They will then
|
||||
work with a committee consisting of representatives from the Open Source
|
||||
Programs Office and the Google Open Source Strategy team. If for any reason you
|
||||
are uncomfortable reaching out the Project Steward, please email
|
||||
the Google Open Source Programs Office at <i>opensource@google.com</i>.</p>
|
||||
|
||||
<p>We will investigate every complaint, but you may not receive a direct response.
|
||||
We will use our discretion in determining when and how to follow up on reported
|
||||
incidents, which may range from not taking action to permanent expulsion from
|
||||
the project and project-sponsored spaces. We will notify the accused of the
|
||||
report and provide them an opportunity to discuss it before any action is taken.
|
||||
The identity of the reporter will be omitted from the details of the report
|
||||
supplied to the accused. In potentially harmful situations, such as ongoing
|
||||
harassment or threats to anyone’s safety, we may take action without notice.</p>
|
||||
|
||||
<h3 id="attribution">Attribution</h3>
|
||||
|
||||
<p>This Code of Conduct is adapted from the Contributor Covenant, version 1.4,
|
||||
available at
|
||||
<a href="https://www.contributor-covenant.org/version/1/4/code-of-conduct.html">https://www.contributor-covenant.org/version/1/4/code-of-conduct.html</a></p>
|
||||
|
||||
<h2 id="summary">Summary</h2>
|
||||
|
||||
@@ -250,10 +209,3 @@ should be proposed using the
|
||||
<li>Don’t be destructive or inflammatory.
|
||||
<li>If you encounter an issue, please mail <a href="mailto:conduct@golang.org">conduct@golang.org</a>.
|
||||
</ul>
|
||||
|
||||
<h3 id="acknowledgements">Acknowledgements</h3>
|
||||
|
||||
<p>
|
||||
Parts of this document were derived from the Code of Conduct documents of the
|
||||
Django, FreeBSD, and Rust projects.
|
||||
</p>
|
||||
|
||||
1780
doc/contribute.html
1780
doc/contribute.html
File diff suppressed because it is too large
Load Diff
@@ -16,11 +16,45 @@ git checkout <i>release-branch</i>
|
||||
|
||||
<p>
|
||||
Each major Go release is supported until there are two newer major releases.
|
||||
For example, Go 1.8 is supported until Go 1.10 is released,
|
||||
and Go 1.9 is supported until Go 1.11 is released.
|
||||
For example, Go 1.5 was supported until the Go 1.7 release, and Go 1.6 was
|
||||
supported until the Go 1.8 release.
|
||||
We fix critical problems, including <a href="/security">critical security problems</a>,
|
||||
in supported releases as needed by issuing minor revisions
|
||||
(for example, Go 1.9.1, Go 1.9.2, and so on).
|
||||
(for example, Go 1.6.1, Go 1.6.2, and so on).
|
||||
</p>
|
||||
|
||||
<h2 id="go1.10">go1.10 (released 2018/02/16)</h2>
|
||||
|
||||
<p>
|
||||
Go 1.10 is a major release of Go.
|
||||
Read the <a href="/doc/go1.10">Go 1.10 Release Notes</a> for more information.
|
||||
</p>
|
||||
|
||||
<h3 id="go1.10.minor">Minor revisions</h3>
|
||||
|
||||
<p>
|
||||
go1.10.1 (released 2018/03/28) includes fixes to the compiler, runtime, and the
|
||||
<code>archive/zip</code>, <code>crypto/tls</code>, <code>crypto/x509</code>,
|
||||
<code>encoding/json</code>, <code>net</code>, <code>net/http</code>, and
|
||||
<code>net/http/pprof</code> packages.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.1">Go
|
||||
1.10.1 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.10.2 (released 2018/05/01) includes fixes to the compiler, linker, and go
|
||||
command.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.2">Go
|
||||
1.10.2 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.10.3 (released 2018/06/05) includes fixes to the go command, and the
|
||||
<code>crypto/tls</code>, <code>crypto/x509</code>, and <code>strings</code> packages.
|
||||
In particular, it adds <a href="https://go.googlesource.com/go/+/d4e21288e444d3ffd30d1a0737f15ea3fc3b8ad9">
|
||||
minimal support to the go command for the vgo transition</a>.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.3">Go
|
||||
1.10.3 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.9">go1.9 (released 2017/08/24)</h2>
|
||||
@@ -63,6 +97,29 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.9.4">Go
|
||||
1.9.4</a> milestone on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.9.5 (released 2018/03/28) includes fixes to the compiler, go command, and
|
||||
<code>net/http/pprof</code> package.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.9.5">Go
|
||||
1.9.5 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.9.6 (released 2018/05/01) includes fixes to the compiler and go command.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.9.6">Go
|
||||
1.9.6 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.9.7 (released 2018/06/05) includes fixes to the go command, and the
|
||||
<code>crypto/x509</code>, and <code>strings</code> packages.
|
||||
In particular, it adds <a href="https://go.googlesource.com/go/+/d4e21288e444d3ffd30d1a0737f15ea3fc3b8ad9">
|
||||
minimal support to the go command for the vgo transition</a>.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.9.7">Go
|
||||
1.9.7 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="go1.8">go1.8 (released 2017/02/16)</h2>
|
||||
|
||||
<p>
|
||||
@@ -114,7 +171,7 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.5">Go
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.8.6 (released 2018/01/22) includes the the same fix in <code>math/big</code>
|
||||
go1.8.6 (released 2018/01/22) includes the same fix in <code>math/big</code>
|
||||
as Go 1.9.3 and was released at the same time.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.6">Go
|
||||
1.8.6 milestone</a> on our issue tracker for details.
|
||||
|
||||
@@ -3588,8 +3588,7 @@ That's left as an exercise for the reader.
|
||||
<p>
|
||||
Let's finish with a complete Go program, a web server.
|
||||
This one is actually a kind of web re-server.
|
||||
Google provides a service at
|
||||
<a href="http://chart.apis.google.com">http://chart.apis.google.com</a>
|
||||
Google provides a service at <code>chart.apis.google.com</code>
|
||||
that does automatic formatting of data into charts and graphs.
|
||||
It's hard to use interactively, though,
|
||||
because you need to put the data into the URL as a query.
|
||||
|
||||
@@ -15,12 +15,7 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
ul li { margin: 0.5em 0; }
|
||||
</style>
|
||||
|
||||
<h2 id="introduction">DRAFT RELEASE NOTES - Introduction to Go 1.10</h2>
|
||||
|
||||
<p><strong>
|
||||
Go 1.10 is not yet released. These are work-in-progress
|
||||
release notes. Go 1.10 is expected to be released in February 2018.
|
||||
</strong></p>
|
||||
<h2 id="introduction">Introduction to Go 1.10</h2>
|
||||
|
||||
<p>
|
||||
The latest Go release, version 1.10, arrives six months after <a href="go1.9">Go 1.9</a>.
|
||||
@@ -35,6 +30,10 @@ adds <a href="#test">caching of successful test results</a>,
|
||||
runs <a href="#test-vet">vet automatically during tests</a>,
|
||||
and
|
||||
permits <a href="#cgo">passing string values directly between Go and C using cgo</a>.
|
||||
A new <a href="#cgo">compiler option whitelist</a> may cause
|
||||
unexpected <a href="https://golang.org/s/invalidflag"><code>invalid
|
||||
flag</code></a> errors in code that built successfully with older
|
||||
releases.
|
||||
</p>
|
||||
|
||||
<h2 id="language">Changes to the language</h2>
|
||||
@@ -44,9 +43,9 @@ There are no significant changes to the language specification.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 60230 -->
|
||||
A corner case involving shifts by untyped constants has been clarified,
|
||||
A corner case involving shifts of untyped constants has been clarified,
|
||||
and as a result the compilers have been updated to allow the index expression
|
||||
<code>x[1.0</code> <code><<</code> <code>s]</code> where <code>s</code> is an untyped constant;
|
||||
<code>x[1.0</code> <code><<</code> <code>s]</code> where <code>s</code> is an unsigned integer;
|
||||
the <a href="/pkg/go/types/">go/types</a> package already did.
|
||||
</p>
|
||||
|
||||
@@ -266,6 +265,18 @@ and the <a href="/cmd/test2json/">test2json documentation</a>.
|
||||
|
||||
<h3 id="cgo">Cgo</h3>
|
||||
|
||||
<p>
|
||||
Options specified by cgo using <code>#cgo CFLAGS</code> and the like
|
||||
are now checked against a whitelist of permitted options.
|
||||
This closes a security hole in which a downloaded package uses
|
||||
compiler options like
|
||||
<span style="white-space: nowrap"><code>-fplugin</code></span>
|
||||
to run arbitrary code on the machine where it is being built.
|
||||
This can cause a build error such as <code>invalid flag in #cgo CFLAGS</code>.
|
||||
For more background, and how to handle this error, see
|
||||
<a href="https://golang.org/s/invalidflag">https://golang.org/s/invalidflag</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Cgo now implements a C typedef like “<code>typedef</code> <code>X</code> <code>Y</code>” using a Go type alias,
|
||||
so that Go code may use the types <code>C.X</code> and <code>C.Y</code> interchangeably.
|
||||
@@ -1214,6 +1225,10 @@ The content-serving handlers also now omit the <code>Content-Type</code> header
|
||||
if passed an invalid (non-3-digit) status code.
|
||||
</p>
|
||||
<p>
|
||||
<!-- CL 46631 -->
|
||||
The <code>Server</code> will no longer add an implicit Content-Type when a <code>Handler</code> does not write any output.
|
||||
</p>
|
||||
<p>
|
||||
<a href="/pkg/net/http/#Redirect"><code>Redirect</code></a> now sets the <code>Content-Type</code> header before writing its HTTP response.
|
||||
</p>
|
||||
</dl>
|
||||
|
||||
@@ -45,7 +45,7 @@ analysis easy and avoids much of the overhead of C-style include files and
|
||||
libraries.
|
||||
<li>
|
||||
Go's type system has no hierarchy, so no time is spent defining the
|
||||
relationships between types. Also, although Go has static types the language
|
||||
relationships between types. Also, although Go has static types, the language
|
||||
attempts to make types feel lighter weight than in typical OO languages.
|
||||
<li>
|
||||
Go is fully garbage-collected and provides fundamental support for
|
||||
@@ -1097,24 +1097,27 @@ The <code>go get</code> command therefore uses HTTPS for safety.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you use <code>git</code> and prefer to push changes through SSH using your existing key
|
||||
it's easy to work around this. For GitHub, try one of these solutions:
|
||||
<code>Git</code> can be configured to authenticate over HTTPS or to use SSH in place of HTTPS.
|
||||
To authenticate over HTTPS, you can add a line
|
||||
to the <code>$HOME/.netrc</code> file that git consults:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Manually clone the repository in the expected package directory:
|
||||
<pre>
|
||||
$ cd src/github.com/username
|
||||
$ git clone git@github.com:username/package.git
|
||||
machine github.com login <i>USERNAME</i> password <i>APIKEY</i>
|
||||
</pre>
|
||||
</li>
|
||||
<li>Force <code>git push</code> to use the <code>SSH</code> protocol by appending
|
||||
these two lines to <code>~/.gitconfig</code>:
|
||||
<p>
|
||||
For GitHub accounts, the password can be a
|
||||
<a href="https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/">personal access token</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<code>Git</code> can also be configured to use SSH in place of HTTPS for URLs matching a given prefix.
|
||||
For example, to use SSH for all GitHub access,
|
||||
add these lines to your <code>~/.gitconfig</code>:
|
||||
</p>
|
||||
<pre>
|
||||
[url "git@github.com:"]
|
||||
pushInsteadOf = https://github.com/
|
||||
[url "ssh://git@github.com/"]
|
||||
insteadOf = https://github.com/
|
||||
</pre>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="get_version">
|
||||
How should I manage package versions using "go get"?</h3>
|
||||
@@ -1852,18 +1855,19 @@ Why is my trivial program such a large binary?</h3>
|
||||
|
||||
<p>
|
||||
The linker in the <code>gc</code> toolchain
|
||||
creates statically-linked binaries by default. All Go binaries therefore include the Go
|
||||
creates statically-linked binaries by default.
|
||||
All Go binaries therefore include the Go
|
||||
run-time, along with the run-time type information necessary to support dynamic
|
||||
type checks, reflection, and even panic-time stack traces.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A simple C "hello, world" program compiled and linked statically using gcc
|
||||
on Linux is around 750 kB,
|
||||
including an implementation of <code>printf</code>.
|
||||
An equivalent Go program using <code>fmt.Printf</code>
|
||||
is around 1.5 MB, but
|
||||
that includes more powerful run-time support and type information.
|
||||
A simple C "hello, world" program compiled and linked statically using
|
||||
gcc on Linux is around 750 kB, including an implementation of
|
||||
<code>printf</code>.
|
||||
An equivalent Go program using
|
||||
<code>fmt.Printf</code> weighs a couple of megabytes, but that includes
|
||||
more powerful run-time support and type and debugging information.
|
||||
</p>
|
||||
|
||||
<h3 id="unused_variables_and_imports">
|
||||
@@ -1931,6 +1935,26 @@ eliminating the unused imports issue in practice.
|
||||
This program is easily connected to most editors to run automatically when a Go source file is written.
|
||||
</p>
|
||||
|
||||
<h3 id="virus">
|
||||
Why does my virus-scanning software think my Go distribution or compiled binary is infected?</h3>
|
||||
|
||||
<p>
|
||||
This is a common occurrence, especially on Windows machines, and is almost always a false positive.
|
||||
Commercial virus scanning programs are often confused by the structure of Go binaries, which
|
||||
they don't see as often as those compiled from other languages.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you've just installed the Go distribution and the system reports it is infected, that's certainly a mistake.
|
||||
To be really thorough, you can verify the download by comparing the checksum with those on the
|
||||
<a href="https://golang.org/dl/">downloads page</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In any case, if you believe the report is in error, please report a bug to the supplier of your virus scanner.
|
||||
Maybe in time virus scanners can learn to understand Go programs.
|
||||
</p>
|
||||
|
||||
<h2 id="Performance">Performance</h2>
|
||||
|
||||
<h3 id="Why_does_Go_perform_badly_on_benchmark_x">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Version of February 1, 2018",
|
||||
"Subtitle": "Version of May 9, 2018",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
@@ -3051,7 +3051,6 @@ used in an <a href="#Assignments">assignment</a> or initialization of the specia
|
||||
v, ok = a[x]
|
||||
v, ok := a[x]
|
||||
var v, ok = a[x]
|
||||
var v, ok T = a[x]
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -4161,11 +4160,6 @@ operands and are evaluated at compile time.
|
||||
Untyped boolean, numeric, and string constants may be used as operands
|
||||
wherever it is legal to use an operand of boolean, numeric, or string type,
|
||||
respectively.
|
||||
Except for shift operations, if the operands of a binary operation are
|
||||
different kinds of untyped constants, the operation and, for non-boolean operations, the result use
|
||||
the kind that appears later in this list: integer, rune, floating-point, complex.
|
||||
For example, an untyped integer constant divided by an
|
||||
untyped complex constant yields an untyped complex constant.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -4175,9 +4169,17 @@ an untyped boolean constant. If the left operand of a constant
|
||||
result is an integer constant; otherwise it is a constant of the same
|
||||
type as the left operand, which must be of
|
||||
<a href="#Numeric_types">integer type</a>.
|
||||
Applying all other operators to untyped constants results in an untyped
|
||||
constant of the same kind (that is, a boolean, integer, floating-point,
|
||||
complex, or string constant).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Any other operation on untyped constants results in an untyped constant of the
|
||||
same kind; that is, a boolean, integer, floating-point, complex, or string
|
||||
constant.
|
||||
If the untyped operands of a binary operation (other than a shift) are of
|
||||
different kinds, the result is of the operand's kind that appears later in this
|
||||
list: integer, rune, floating-point, complex.
|
||||
For example, an untyped integer constant divided by an
|
||||
untyped complex constant yields an untyped complex constant.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
|
||||
@@ -307,7 +307,7 @@ package main
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Printf("hello, world\n")
|
||||
fmt.Printf("hello, world\n")
|
||||
}
|
||||
</pre>
|
||||
|
||||
|
||||
@@ -106,6 +106,14 @@ variable. You can do this by adding this line to your <code>/etc/profile</code>
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<b>Note</b>: changes made to a <code>profile</code> file may not apply until the
|
||||
next time you log into your computer.
|
||||
To apply the changes immediately, just run the shell commands directly
|
||||
or execute them from the profile using a command such as
|
||||
<code>source $HOME/.profile</code>.
|
||||
</p>
|
||||
|
||||
<h4 id="tarball_non_standard">Installing to a custom location</h4>
|
||||
|
||||
<p>
|
||||
@@ -236,7 +244,7 @@ package main
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Printf("hello, world\n")
|
||||
fmt.Printf("hello, world\n")
|
||||
}
|
||||
</pre>
|
||||
|
||||
@@ -278,7 +286,7 @@ If you see the "hello, world" message then your Go installation is working.
|
||||
<p>
|
||||
You can run <code>go</code> <code>install</code> to install the binary into
|
||||
your workspace's <code>bin</code> directory
|
||||
or <code>go</code> <code>clean</code> to remove it.
|
||||
or <code>go</code> <code>clean</code> <code>-i</code> to remove it.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -20,11 +20,11 @@ func viewRecord(w http.ResponseWriter, r *http.Request) {
|
||||
key := datastore.NewKey(c, "Record", r.FormValue("id"), 0, nil)
|
||||
record := new(Record)
|
||||
if err := datastore.Get(c, key, record); err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if err := viewTemplate.Execute(w, record); err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ type appHandler func(http.ResponseWriter, *http.Request) error
|
||||
|
||||
func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if err := fn(w, r); err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ Linux, Mac OS X, Windows, and more.
|
||||
<div class="left">
|
||||
<div id="video">
|
||||
<div class="rootHeading">Featured video</div>
|
||||
<iframe width="415" height="241" src="//www.youtube.com/embed/ytEkHepK08c" frameborder="0" allowfullscreen></iframe>
|
||||
<div class="js-frontpage-video" style="--aspect-ratio-padding: 58.07%;"><iframe width="415" height="241" src="//www.youtube.com/embed/ytEkHepK08c" frameborder="0" allowfullscreen></iframe></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -153,6 +153,10 @@ Linux, Mac OS X, Windows, and more.
|
||||
];
|
||||
var v = videos[Math.floor(Math.random()*videos.length)];
|
||||
$('#video iframe').attr('height', v.h).attr('src', v.s);
|
||||
// Compute the aspect ratio (as a percentage) of the video
|
||||
// using the fixed width 415 and the height of the current video, v.h.
|
||||
var ar = 100*v.h/415;
|
||||
$('.js-frontpage-video').attr('style', '--aspect-ratio-padding: ' + ar + '%;');
|
||||
});
|
||||
|
||||
{{end}}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define fd (100)
|
||||
#define fd (30)
|
||||
|
||||
// Tests libgo2.so, which does not export any functions.
|
||||
// Read a string from the file descriptor and print it.
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
// that the C code can also use.
|
||||
|
||||
const (
|
||||
fd = 100
|
||||
fd = 30
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
21
misc/cgo/testplugin/src/issue24351/main.go
Normal file
21
misc/cgo/testplugin/src/issue24351/main.go
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import "plugin"
|
||||
|
||||
func main() {
|
||||
p, err := plugin.Open("issue24351.so")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
f, err := p.Lookup("B")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c := make(chan bool)
|
||||
f.(func(chan bool))(c)
|
||||
<-c
|
||||
}
|
||||
14
misc/cgo/testplugin/src/issue24351/plugin.go
Normal file
14
misc/cgo/testplugin/src/issue24351/plugin.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func B(c chan bool) {
|
||||
go func() {
|
||||
fmt.Println(1.5)
|
||||
c <- true
|
||||
}()
|
||||
}
|
||||
@@ -85,3 +85,8 @@ GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue22175 src/issue22175/main.
|
||||
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o issue.22295.so issue22295.pkg
|
||||
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue22295 src/issue22295.pkg/main.go
|
||||
./issue22295
|
||||
|
||||
# Test for issue 24351
|
||||
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o issue24351.so src/issue24351/plugin.go
|
||||
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue24351 src/issue24351/main.go
|
||||
./issue24351
|
||||
|
||||
@@ -790,6 +790,7 @@ func TestRebuilding(t *testing.T) {
|
||||
// If the .a file is newer than the .so, the .so is rebuilt (but not the .a)
|
||||
t.Run("newarchive", func(t *testing.T) {
|
||||
resetFileStamps()
|
||||
AssertNotRebuilt(t, "new .a file before build", filepath.Join(gopathInstallDir, "depBase.a"))
|
||||
goCmd(t, "list", "-linkshared", "-f={{.ImportPath}} {{.Stale}} {{.StaleReason}} {{.Target}}", "depBase")
|
||||
AssertNotRebuilt(t, "new .a file before build", filepath.Join(gopathInstallDir, "depBase.a"))
|
||||
cleanup := touch(t, filepath.Join(gopathInstallDir, "depBase.a"))
|
||||
|
||||
@@ -366,7 +366,7 @@ parseExtras:
|
||||
epoch := time.Date(1601, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||
modified = time.Unix(epoch.Unix()+secs, nsecs)
|
||||
}
|
||||
case unixExtraID:
|
||||
case unixExtraID, infoZipUnixExtraID:
|
||||
if len(fieldBuf) < 8 {
|
||||
continue parseExtras
|
||||
}
|
||||
@@ -379,12 +379,6 @@ parseExtras:
|
||||
}
|
||||
ts := int64(fieldBuf.uint32()) // ModTime since Unix epoch
|
||||
modified = time.Unix(ts, 0)
|
||||
case infoZipUnixExtraID:
|
||||
if len(fieldBuf) < 4 {
|
||||
continue parseExtras
|
||||
}
|
||||
ts := int64(fieldBuf.uint32()) // ModTime since Unix epoch
|
||||
modified = time.Unix(ts, 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -414,7 +414,7 @@ var tests = []ZipTest{
|
||||
Name: "test.txt",
|
||||
Content: []byte{},
|
||||
Size: 1<<32 - 1,
|
||||
Modified: time.Date(2017, 10, 31, 21, 17, 27, 0, timeZone(-7*time.Hour)),
|
||||
Modified: time.Date(2017, 10, 31, 21, 11, 57, 0, timeZone(-7*time.Hour)),
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1346,8 +1346,22 @@ func (p *noder) pragma(pos src.Pos, text string) syntax.Pragma {
|
||||
}
|
||||
p.linknames = append(p.linknames, linkname{pos, f[1], f[2]})
|
||||
|
||||
case strings.HasPrefix(text, "go:cgo_import_dynamic "):
|
||||
// This is permitted for general use because Solaris
|
||||
// code relies on it in golang.org/x/sys/unix and others.
|
||||
fields := pragmaFields(text)
|
||||
if len(fields) >= 4 {
|
||||
lib := strings.Trim(fields[3], `"`)
|
||||
if lib != "" && !safeArg(lib) && !isCgoGeneratedFile(pos) {
|
||||
p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("invalid library name %q in cgo_import_dynamic directive", lib)})
|
||||
}
|
||||
p.pragcgobuf += p.pragcgo(pos, text)
|
||||
return pragmaValue("go:cgo_import_dynamic")
|
||||
}
|
||||
fallthrough
|
||||
case strings.HasPrefix(text, "go:cgo_"):
|
||||
// For security, we disallow //go:cgo_* directives outside cgo-generated files.
|
||||
// For security, we disallow //go:cgo_* directives other
|
||||
// than cgo_import_dynamic outside cgo-generated files.
|
||||
// Exception: they are allowed in the standard library, for runtime and syscall.
|
||||
if !isCgoGeneratedFile(pos) && !compiling_std {
|
||||
p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s only allowed in cgo-generated code", text)})
|
||||
@@ -1383,6 +1397,18 @@ func isCgoGeneratedFile(pos src.Pos) bool {
|
||||
return strings.HasPrefix(filepath.Base(filepath.Clean(pos.AbsFilename())), "_cgo_")
|
||||
}
|
||||
|
||||
// safeArg reports whether arg is a "safe" command-line argument,
|
||||
// meaning that when it appears in a command-line, it probably
|
||||
// doesn't have some special meaning other than its own name.
|
||||
// This is copied from SafeArg in cmd/go/internal/load/pkg.go.
|
||||
func safeArg(name string) bool {
|
||||
if name == "" {
|
||||
return false
|
||||
}
|
||||
c := name[0]
|
||||
return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '.' || c == '_' || c == '/' || c >= utf8.RuneSelf
|
||||
}
|
||||
|
||||
func mkname(sym *types.Sym) *Node {
|
||||
n := oldname(sym)
|
||||
if n.Name != nil && n.Name.Pack != nil {
|
||||
|
||||
@@ -1261,6 +1261,13 @@ opswitch:
|
||||
}
|
||||
if cs != nil {
|
||||
cmp := Op(n.Etype)
|
||||
// Our comparison below assumes that the non-constant string
|
||||
// is on the left hand side, so rewrite "" cmp x to x cmp "".
|
||||
// See issue 24817.
|
||||
if Isconst(n.Left, CTSTR) {
|
||||
cmp = brrev(cmp)
|
||||
}
|
||||
|
||||
// maxRewriteLen was chosen empirically.
|
||||
// It is the value that minimizes cmd/go file size
|
||||
// across most architectures.
|
||||
|
||||
@@ -1647,9 +1647,9 @@
|
||||
(SUBQconst (MOVQconst [d]) [c]) -> (MOVQconst [d-c])
|
||||
(SUBQconst (SUBQconst x [d]) [c]) && is32Bit(-c-d) -> (ADDQconst [-c-d] x)
|
||||
(SARQconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
|
||||
(SARLconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
|
||||
(SARWconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
|
||||
(SARBconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
|
||||
(SARLconst [c] (MOVQconst [d])) -> (MOVQconst [int64(int32(d))>>uint64(c)])
|
||||
(SARWconst [c] (MOVQconst [d])) -> (MOVQconst [int64(int16(d))>>uint64(c)])
|
||||
(SARBconst [c] (MOVQconst [d])) -> (MOVQconst [int64(int8(d))>>uint64(c)])
|
||||
(NEGQ (MOVQconst [c])) -> (MOVQconst [-c])
|
||||
(NEGL (MOVLconst [c])) -> (MOVLconst [int64(int32(-c))])
|
||||
(MULQconst [c] (MOVQconst [d])) -> (MOVQconst [c*d])
|
||||
|
||||
@@ -270,22 +270,22 @@ func init() {
|
||||
// Note: x86 is weird, the 16 and 8 byte shifts still use all 5 bits of shift amount!
|
||||
|
||||
{name: "SHRQ", argLength: 2, reg: gp21shift, asm: "SHRQ", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> arg1, shift amount is mod 64
|
||||
{name: "SHRL", argLength: 2, reg: gp21shift, asm: "SHRL", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SHRW", argLength: 2, reg: gp21shift, asm: "SHRW", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SHRB", argLength: 2, reg: gp21shift, asm: "SHRB", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SHRL", argLength: 2, reg: gp21shift, asm: "SHRL", resultInArg0: true, clobberFlags: true}, // unsigned uint32(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SHRW", argLength: 2, reg: gp21shift, asm: "SHRW", resultInArg0: true, clobberFlags: true}, // unsigned uint16(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SHRB", argLength: 2, reg: gp21shift, asm: "SHRB", resultInArg0: true, clobberFlags: true}, // unsigned uint8(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SHRQconst", argLength: 1, reg: gp11, asm: "SHRQ", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-63
|
||||
{name: "SHRLconst", argLength: 1, reg: gp11, asm: "SHRL", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-31
|
||||
{name: "SHRWconst", argLength: 1, reg: gp11, asm: "SHRW", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-15
|
||||
{name: "SHRBconst", argLength: 1, reg: gp11, asm: "SHRB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-7
|
||||
{name: "SHRLconst", argLength: 1, reg: gp11, asm: "SHRL", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned uint32(arg0) >> auxint, shift amount 0-31
|
||||
{name: "SHRWconst", argLength: 1, reg: gp11, asm: "SHRW", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned uint16(arg0) >> auxint, shift amount 0-15
|
||||
{name: "SHRBconst", argLength: 1, reg: gp11, asm: "SHRB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned uint8(arg0) >> auxint, shift amount 0-7
|
||||
|
||||
{name: "SARQ", argLength: 2, reg: gp21shift, asm: "SARQ", resultInArg0: true, clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 64
|
||||
{name: "SARL", argLength: 2, reg: gp21shift, asm: "SARL", resultInArg0: true, clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SARW", argLength: 2, reg: gp21shift, asm: "SARW", resultInArg0: true, clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SARB", argLength: 2, reg: gp21shift, asm: "SARB", resultInArg0: true, clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SARL", argLength: 2, reg: gp21shift, asm: "SARL", resultInArg0: true, clobberFlags: true}, // signed int32(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SARW", argLength: 2, reg: gp21shift, asm: "SARW", resultInArg0: true, clobberFlags: true}, // signed int16(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SARB", argLength: 2, reg: gp21shift, asm: "SARB", resultInArg0: true, clobberFlags: true}, // signed int8(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SARQconst", argLength: 1, reg: gp11, asm: "SARQ", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-63
|
||||
{name: "SARLconst", argLength: 1, reg: gp11, asm: "SARL", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-31
|
||||
{name: "SARWconst", argLength: 1, reg: gp11, asm: "SARW", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-15
|
||||
{name: "SARBconst", argLength: 1, reg: gp11, asm: "SARB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-7
|
||||
{name: "SARLconst", argLength: 1, reg: gp11, asm: "SARL", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed int32(arg0) >> auxint, shift amount 0-31
|
||||
{name: "SARWconst", argLength: 1, reg: gp11, asm: "SARW", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed int16(arg0) >> auxint, shift amount 0-15
|
||||
{name: "SARBconst", argLength: 1, reg: gp11, asm: "SARB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed int8(arg0) >> auxint, shift amount 0-7
|
||||
|
||||
{name: "ROLQ", argLength: 2, reg: gp21shift, asm: "ROLQ", resultInArg0: true, clobberFlags: true}, // arg0 rotate left arg1 bits.
|
||||
{name: "ROLL", argLength: 2, reg: gp21shift, asm: "ROLL", resultInArg0: true, clobberFlags: true}, // arg0 rotate left arg1 bits.
|
||||
|
||||
@@ -1088,7 +1088,7 @@
|
||||
(SUBconst (MOVDconst [d]) [c]) -> (MOVDconst [d-c])
|
||||
(SUBconst (SUBconst x [d]) [c]) && is32Bit(-c-d) -> (ADDconst [-c-d] x)
|
||||
(SRADconst [c] (MOVDconst [d])) -> (MOVDconst [d>>uint64(c)])
|
||||
(SRAWconst [c] (MOVDconst [d])) -> (MOVDconst [d>>uint64(c)])
|
||||
(SRAWconst [c] (MOVDconst [d])) -> (MOVDconst [int64(int32(d))>>uint64(c)])
|
||||
(NEG (MOVDconst [c])) -> (MOVDconst [-c])
|
||||
(NEGW (MOVDconst [c])) -> (MOVDconst [int64(int32(-c))])
|
||||
(MULLDconst [c] (MOVDconst [d])) -> (MOVDconst [c*d])
|
||||
|
||||
@@ -309,15 +309,15 @@ func init() {
|
||||
{name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int8"}, // arg0 << auxint, shift amount 0-31
|
||||
|
||||
{name: "SRD", argLength: 2, reg: sh21, asm: "SRD"}, // unsigned arg0 >> arg1, shift amount is mod 64
|
||||
{name: "SRW", argLength: 2, reg: sh21, asm: "SRW"}, // unsigned arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SRW", argLength: 2, reg: sh21, asm: "SRW"}, // unsigned uint32(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int8"}, // unsigned arg0 >> auxint, shift amount 0-63
|
||||
{name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int8"}, // unsigned arg0 >> auxint, shift amount 0-31
|
||||
{name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int8"}, // unsigned uint32(arg0) >> auxint, shift amount 0-31
|
||||
|
||||
// Arithmetic shifts clobber flags.
|
||||
{name: "SRAD", argLength: 2, reg: sh21, asm: "SRAD", clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 64
|
||||
{name: "SRAW", argLength: 2, reg: sh21, asm: "SRAW", clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SRAW", argLength: 2, reg: sh21, asm: "SRAW", clobberFlags: true}, // signed int32(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int8", clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-63
|
||||
{name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int8", clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-31
|
||||
{name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int8", clobberFlags: true}, // signed int32(arg0) >> auxint, shift amount 0-31
|
||||
|
||||
{name: "RLLGconst", argLength: 1, reg: gp11, asm: "RLLG", aux: "Int8"}, // arg0 rotate left auxint, rotate amount 0-63
|
||||
{name: "RLLconst", argLength: 1, reg: gp11, asm: "RLL", aux: "Int8"}, // arg0 rotate left auxint, rotate amount 0-31
|
||||
@@ -485,8 +485,8 @@ func init() {
|
||||
// Atomic adds.
|
||||
// *(arg0+auxint+aux) += arg1. arg2=mem.
|
||||
// Returns a tuple of <old contents of *(arg0+auxint+aux), memory>.
|
||||
{name: "LAA", argLength: 3, reg: gpstorelaa, asm: "LAA", typ: "(UInt32,Mem)", aux: "SymOff", faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},
|
||||
{name: "LAAG", argLength: 3, reg: gpstorelaa, asm: "LAAG", typ: "(UInt64,Mem)", aux: "SymOff", faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},
|
||||
{name: "LAA", argLength: 3, reg: gpstorelaa, asm: "LAA", typ: "(UInt32,Mem)", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},
|
||||
{name: "LAAG", argLength: 3, reg: gpstorelaa, asm: "LAAG", typ: "(UInt64,Mem)", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},
|
||||
{name: "AddTupleFirst32", argLength: 2}, // arg1=tuple <x,y>. Returns <x+arg0,y>.
|
||||
{name: "AddTupleFirst64", argLength: 2}, // arg1=tuple <x,y>. Returns <x+arg0,y>.
|
||||
|
||||
|
||||
@@ -22080,6 +22080,7 @@ var opcodeTable = [...]opInfo{
|
||||
name: "LAA",
|
||||
auxType: auxSymOff,
|
||||
argLen: 3,
|
||||
clobberFlags: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
symEffect: SymRdWr,
|
||||
@@ -22098,6 +22099,7 @@ var opcodeTable = [...]opInfo{
|
||||
name: "LAAG",
|
||||
auxType: auxSymOff,
|
||||
argLen: 3,
|
||||
clobberFlags: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
symEffect: SymRdWr,
|
||||
|
||||
@@ -34892,7 +34892,7 @@ func rewriteValueAMD64_OpAMD64SARBconst_0(v *Value) bool {
|
||||
}
|
||||
// match: (SARBconst [c] (MOVQconst [d]))
|
||||
// cond:
|
||||
// result: (MOVQconst [d>>uint64(c)])
|
||||
// result: (MOVQconst [int64(int8(d))>>uint64(c)])
|
||||
for {
|
||||
c := v.AuxInt
|
||||
v_0 := v.Args[0]
|
||||
@@ -34901,7 +34901,7 @@ func rewriteValueAMD64_OpAMD64SARBconst_0(v *Value) bool {
|
||||
}
|
||||
d := v_0.AuxInt
|
||||
v.reset(OpAMD64MOVQconst)
|
||||
v.AuxInt = d >> uint64(c)
|
||||
v.AuxInt = int64(int8(d)) >> uint64(c)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -35147,7 +35147,7 @@ func rewriteValueAMD64_OpAMD64SARLconst_0(v *Value) bool {
|
||||
}
|
||||
// match: (SARLconst [c] (MOVQconst [d]))
|
||||
// cond:
|
||||
// result: (MOVQconst [d>>uint64(c)])
|
||||
// result: (MOVQconst [int64(int32(d))>>uint64(c)])
|
||||
for {
|
||||
c := v.AuxInt
|
||||
v_0 := v.Args[0]
|
||||
@@ -35156,7 +35156,7 @@ func rewriteValueAMD64_OpAMD64SARLconst_0(v *Value) bool {
|
||||
}
|
||||
d := v_0.AuxInt
|
||||
v.reset(OpAMD64MOVQconst)
|
||||
v.AuxInt = d >> uint64(c)
|
||||
v.AuxInt = int64(int32(d)) >> uint64(c)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -35467,7 +35467,7 @@ func rewriteValueAMD64_OpAMD64SARWconst_0(v *Value) bool {
|
||||
}
|
||||
// match: (SARWconst [c] (MOVQconst [d]))
|
||||
// cond:
|
||||
// result: (MOVQconst [d>>uint64(c)])
|
||||
// result: (MOVQconst [int64(int16(d))>>uint64(c)])
|
||||
for {
|
||||
c := v.AuxInt
|
||||
v_0 := v.Args[0]
|
||||
@@ -35476,7 +35476,7 @@ func rewriteValueAMD64_OpAMD64SARWconst_0(v *Value) bool {
|
||||
}
|
||||
d := v_0.AuxInt
|
||||
v.reset(OpAMD64MOVQconst)
|
||||
v.AuxInt = d >> uint64(c)
|
||||
v.AuxInt = int64(int16(d)) >> uint64(c)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -37197,7 +37197,7 @@ func rewriteValueS390X_OpS390XSRAW_0(v *Value) bool {
|
||||
func rewriteValueS390X_OpS390XSRAWconst_0(v *Value) bool {
|
||||
// match: (SRAWconst [c] (MOVDconst [d]))
|
||||
// cond:
|
||||
// result: (MOVDconst [d>>uint64(c)])
|
||||
// result: (MOVDconst [int64(int32(d))>>uint64(c)])
|
||||
for {
|
||||
c := v.AuxInt
|
||||
v_0 := v.Args[0]
|
||||
@@ -37206,7 +37206,7 @@ func rewriteValueS390X_OpS390XSRAWconst_0(v *Value) bool {
|
||||
}
|
||||
d := v_0.AuxInt
|
||||
v.reset(OpS390XMOVDconst)
|
||||
v.AuxInt = d >> uint64(c)
|
||||
v.AuxInt = int64(int32(d)) >> uint64(c)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -238,23 +238,28 @@ func (f *File) Visit(node ast.Node) ast.Visitor {
|
||||
// if y {
|
||||
// }
|
||||
// }
|
||||
f.edit.Insert(f.offset(n.Body.End()), "else{")
|
||||
elseOffset := f.findText(n.Body.End(), "else")
|
||||
if elseOffset < 0 {
|
||||
panic("lost else")
|
||||
}
|
||||
f.edit.Delete(elseOffset, elseOffset+4)
|
||||
f.edit.Insert(elseOffset+4, "{")
|
||||
f.edit.Insert(f.offset(n.Else.End()), "}")
|
||||
|
||||
// We just created a block, now walk it.
|
||||
// Adjust the position of the new block to start after
|
||||
// the "else". That will cause it to follow the "{"
|
||||
// we inserted above.
|
||||
pos := f.fset.File(n.Body.End()).Pos(elseOffset + 4)
|
||||
switch stmt := n.Else.(type) {
|
||||
case *ast.IfStmt:
|
||||
block := &ast.BlockStmt{
|
||||
Lbrace: n.Body.End(), // Start at end of the "if" block so the covered part looks like it starts at the "else".
|
||||
Lbrace: pos,
|
||||
List: []ast.Stmt{stmt},
|
||||
Rbrace: stmt.End(),
|
||||
}
|
||||
n.Else = block
|
||||
case *ast.BlockStmt:
|
||||
stmt.Lbrace = n.Body.End() // Start at end of the "if" block so the covered part looks like it starts at the "else".
|
||||
stmt.Lbrace = pos
|
||||
default:
|
||||
panic("unexpected node type in if")
|
||||
}
|
||||
|
||||
@@ -59,6 +59,17 @@ func TestCover(t *testing.T) {
|
||||
for i, line := range lines {
|
||||
lines[i] = bytes.Replace(line, []byte("LINE"), []byte(fmt.Sprint(i+1)), -1)
|
||||
}
|
||||
|
||||
// Add a function that is not gofmt'ed. This used to cause a crash.
|
||||
// We don't put it in test.go because then we would have to gofmt it.
|
||||
// Issue 23927.
|
||||
lines = append(lines, []byte("func unFormatted() {"),
|
||||
[]byte("\tif true {"),
|
||||
[]byte("\t}else{"),
|
||||
[]byte("\t}"),
|
||||
[]byte("}"))
|
||||
lines = append(lines, []byte("func unFormatted2(b bool) {if b{}else{}}"))
|
||||
|
||||
if err := ioutil.WriteFile(coverInput, bytes.Join(lines, []byte("\n")), 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -246,6 +257,7 @@ func TestCoverFunc(t *testing.T) {
|
||||
}
|
||||
|
||||
func run(c *exec.Cmd, t *testing.T) {
|
||||
t.Helper()
|
||||
c.Stdout = os.Stdout
|
||||
c.Stderr = os.Stderr
|
||||
err := c.Run()
|
||||
|
||||
@@ -3233,6 +3233,20 @@ func TestGoVetWithOnlyTestFiles(t *testing.T) {
|
||||
tg.run("vet", "p")
|
||||
}
|
||||
|
||||
// Issue 24193.
|
||||
func TestVetWithOnlyCgoFiles(t *testing.T) {
|
||||
if !canCgo {
|
||||
t.Skip("skipping because cgo not enabled")
|
||||
}
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
tg.tempFile("src/p/p.go", "package p; import \"C\"; func F() {}")
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.run("vet", "p")
|
||||
}
|
||||
|
||||
// Issue 9767, 19769.
|
||||
func TestGoGetDotSlashDownload(t *testing.T) {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
@@ -5060,6 +5074,28 @@ func TestCacheOutput(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCacheListStale(t *testing.T) {
|
||||
tooSlow(t)
|
||||
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
|
||||
t.Skip("GODEBUG gocacheverify")
|
||||
}
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
tg.makeTempdir()
|
||||
tg.setenv("GOCACHE", tg.path("cache"))
|
||||
tg.tempFile("gopath/src/p/p.go", "package p; import _ \"q\"; func F(){}\n")
|
||||
tg.tempFile("gopath/src/q/q.go", "package q; func F(){}\n")
|
||||
tg.tempFile("gopath/src/m/m.go", "package main; import _ \"q\"; func main(){}\n")
|
||||
|
||||
tg.setenv("GOPATH", tg.path("gopath"))
|
||||
tg.run("install", "p", "m")
|
||||
tg.run("list", "-f={{.ImportPath}} {{.Stale}}", "m", "q", "p")
|
||||
tg.grepStdout("^m false", "m should not be stale")
|
||||
tg.grepStdout("^q true", "q should be stale")
|
||||
tg.grepStdout("^p false", "p should not be stale")
|
||||
}
|
||||
|
||||
func TestCacheCoverage(t *testing.T) {
|
||||
tooSlow(t)
|
||||
|
||||
@@ -5740,6 +5776,21 @@ func TestAtomicCoverpkgAll(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 23882.
|
||||
func TestCoverpkgAllRuntime(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
|
||||
tg.tempFile("src/x/x.go", `package x; import _ "runtime"; func F() {}`)
|
||||
tg.tempFile("src/x/x_test.go", `package x; import "testing"; func TestF(t *testing.T) { F() }`)
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.run("test", "-coverpkg=all", "x")
|
||||
if canRace {
|
||||
tg.run("test", "-coverpkg=all", "-race", "x")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadCommandLines(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
@@ -5888,3 +5939,36 @@ func TestBadCgoDirectives(t *testing.T) {
|
||||
tg.run("build", "-n", "x")
|
||||
tg.grepStderr("-D@foo", "did not find -D@foo in commands")
|
||||
}
|
||||
|
||||
func TestTwoPkgConfigs(t *testing.T) {
|
||||
if !canCgo {
|
||||
t.Skip("no cgo")
|
||||
}
|
||||
if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
|
||||
t.Skipf("no shell scripts on %s", runtime.GOOS)
|
||||
}
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
tg.tempFile("src/x/a.go", `package x
|
||||
// #cgo pkg-config: --static a
|
||||
import "C"
|
||||
`)
|
||||
tg.tempFile("src/x/b.go", `package x
|
||||
// #cgo pkg-config: --static a
|
||||
import "C"
|
||||
`)
|
||||
tg.tempFile("pkg-config.sh", `#!/bin/sh
|
||||
echo $* >>`+tg.path("pkg-config.out"))
|
||||
tg.must(os.Chmod(tg.path("pkg-config.sh"), 0755))
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.setenv("PKG_CONFIG", tg.path("pkg-config.sh"))
|
||||
tg.run("build", "x")
|
||||
out, err := ioutil.ReadFile(tg.path("pkg-config.out"))
|
||||
tg.must(err)
|
||||
out = bytes.TrimSpace(out)
|
||||
want := "--cflags --static --static -- a a\n--libs --static --static -- a a"
|
||||
if !bytes.Equal(out, []byte(want)) {
|
||||
t.Errorf("got %q want %q", out, want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,13 @@ func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
|
||||
continue
|
||||
}
|
||||
if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
|
||||
// Ignore VCS type "mod", which is new Go modules.
|
||||
// This code is for old go get and must ignore the new mod lines.
|
||||
// Otherwise matchGoImport will complain about two
|
||||
// different metaImport lines for the same Prefix.
|
||||
if f[1] == "mod" {
|
||||
continue
|
||||
}
|
||||
imports = append(imports, metaImport{
|
||||
Prefix: f[0],
|
||||
VCS: f[1],
|
||||
|
||||
@@ -209,7 +209,7 @@ var downloadRootCache = map[string]bool{}
|
||||
// download runs the download half of the get command
|
||||
// for the package named by the argument.
|
||||
func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) {
|
||||
if mode&load.UseVendor != 0 {
|
||||
if mode&load.ResolveImport != 0 {
|
||||
// Caller is responsible for expanding vendor paths.
|
||||
panic("internal error: download mode has useVendor set")
|
||||
}
|
||||
@@ -217,7 +217,7 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
|
||||
if parent == nil {
|
||||
return load.LoadPackage(path, stk)
|
||||
}
|
||||
return load.LoadImport(path, parent.Dir, parent, stk, nil, mode)
|
||||
return load.LoadImport(path, parent.Dir, parent, stk, nil, mode|load.ResolveModule)
|
||||
}
|
||||
|
||||
p := load1(arg, mode)
|
||||
@@ -346,12 +346,12 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
|
||||
base.Errorf("%s", err)
|
||||
continue
|
||||
}
|
||||
// If this is a test import, apply vendor lookup now.
|
||||
// We cannot pass useVendor to download, because
|
||||
// If this is a test import, apply module and vendor lookup now.
|
||||
// We cannot pass ResolveImport to download, because
|
||||
// download does caching based on the value of path,
|
||||
// so it must be the fully qualified path already.
|
||||
if i >= len(p.Imports) {
|
||||
path = load.VendoredImportPath(p, path)
|
||||
path = load.ResolveImportPath(p, path)
|
||||
}
|
||||
download(path, p, stk, 0)
|
||||
}
|
||||
|
||||
@@ -47,6 +47,20 @@ var parseMetaGoImportsTests = []struct {
|
||||
{"baz/quux", "git", "http://github.com/rsc/baz/quux"},
|
||||
},
|
||||
},
|
||||
{
|
||||
`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
|
||||
<meta name="go-import" content="foo/bar mod http://github.com/rsc/baz/quux">`,
|
||||
[]metaImport{
|
||||
{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
|
||||
},
|
||||
},
|
||||
{
|
||||
`<meta name="go-import" content="foo/bar mod http://github.com/rsc/baz/quux">
|
||||
<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
|
||||
[]metaImport{
|
||||
{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
|
||||
},
|
||||
},
|
||||
{
|
||||
`<head>
|
||||
<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
|
||||
|
||||
@@ -809,8 +809,8 @@ func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*re
|
||||
}
|
||||
}
|
||||
|
||||
if !strings.Contains(mmi.RepoRoot, "://") {
|
||||
return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, mmi.RepoRoot)
|
||||
if err := validateRepoRootScheme(mmi.RepoRoot); err != nil {
|
||||
return nil, fmt.Errorf("%s: invalid repo root %q: %v", urlStr, mmi.RepoRoot, err)
|
||||
}
|
||||
rr := &repoRoot{
|
||||
vcs: vcsByCmd(mmi.VCS),
|
||||
@@ -824,6 +824,36 @@ func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*re
|
||||
return rr, nil
|
||||
}
|
||||
|
||||
// validateRepoRootScheme returns an error if repoRoot does not seem
|
||||
// to have a valid URL scheme. At this point we permit things that
|
||||
// aren't valid URLs, although later, if not using -insecure, we will
|
||||
// restrict repoRoots to be valid URLs. This is only because we've
|
||||
// historically permitted them, and people may depend on that.
|
||||
func validateRepoRootScheme(repoRoot string) error {
|
||||
end := strings.Index(repoRoot, "://")
|
||||
if end <= 0 {
|
||||
return errors.New("no scheme")
|
||||
}
|
||||
|
||||
// RFC 3986 section 3.1.
|
||||
for i := 0; i < end; i++ {
|
||||
c := repoRoot[i]
|
||||
switch {
|
||||
case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
|
||||
// OK.
|
||||
case '0' <= c && c <= '9' || c == '+' || c == '-' || c == '.':
|
||||
// OK except at start.
|
||||
if i == 0 {
|
||||
return errors.New("invalid scheme")
|
||||
}
|
||||
default:
|
||||
return errors.New("invalid scheme")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var fetchGroup singleflight.Group
|
||||
var (
|
||||
fetchCacheMu sync.Mutex
|
||||
|
||||
@@ -408,3 +408,46 @@ func TestMatchGoImport(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRepoRootScheme(t *testing.T) {
|
||||
tests := []struct {
|
||||
root string
|
||||
err string
|
||||
}{
|
||||
{
|
||||
root: "",
|
||||
err: "no scheme",
|
||||
},
|
||||
{
|
||||
root: "http://",
|
||||
err: "",
|
||||
},
|
||||
{
|
||||
root: "a://",
|
||||
err: "",
|
||||
},
|
||||
{
|
||||
root: "a#://",
|
||||
err: "invalid scheme",
|
||||
},
|
||||
{
|
||||
root: "-config://",
|
||||
err: "invalid scheme",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
err := validateRepoRootScheme(test.root)
|
||||
if err == nil {
|
||||
if test.err != "" {
|
||||
t.Errorf("validateRepoRootScheme(%q) = nil, want %q", test.root, test.err)
|
||||
}
|
||||
} else if test.err == "" {
|
||||
if err != nil {
|
||||
t.Errorf("validateRepoRootScheme(%q) = %q, want nil", test.root, test.err)
|
||||
}
|
||||
} else if err.Error() != test.err {
|
||||
t.Errorf("validateRepoRootScheme(%q) = %q, want %q", test.root, err, test.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,8 +218,8 @@ func runList(cmd *base.Command, args []string) {
|
||||
|
||||
for _, pkg := range pkgs {
|
||||
// Show vendor-expanded paths in listing
|
||||
pkg.TestImports = pkg.Vendored(pkg.TestImports)
|
||||
pkg.XTestImports = pkg.Vendored(pkg.XTestImports)
|
||||
pkg.TestImports = pkg.Resolve(pkg.TestImports)
|
||||
pkg.XTestImports = pkg.Resolve(pkg.XTestImports)
|
||||
|
||||
do(&pkg.PackagePublic)
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package load
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// DebugDeprecatedImportcfg is installed as the undocumented -debug-deprecated-importcfg build flag.
|
||||
// It is useful for debugging subtle problems in the go command logic but not something
|
||||
// we want users to depend on. The hope is that the "deprecated" will make that clear.
|
||||
// We intend to remove this flag in Go 1.11.
|
||||
var DebugDeprecatedImportcfg debugDeprecatedImportcfgFlag
|
||||
|
||||
type debugDeprecatedImportcfgFlag struct {
|
||||
enabled bool
|
||||
Import map[string]string
|
||||
Pkg map[string]*debugDeprecatedImportcfgPkg
|
||||
}
|
||||
|
||||
type debugDeprecatedImportcfgPkg struct {
|
||||
Dir string
|
||||
Import map[string]string
|
||||
}
|
||||
|
||||
var (
|
||||
debugDeprecatedImportcfgMagic = []byte("# debug-deprecated-importcfg\n")
|
||||
errImportcfgSyntax = errors.New("malformed syntax")
|
||||
)
|
||||
|
||||
func (f *debugDeprecatedImportcfgFlag) String() string { return "" }
|
||||
|
||||
func (f *debugDeprecatedImportcfgFlag) Set(x string) error {
|
||||
if x == "" {
|
||||
*f = debugDeprecatedImportcfgFlag{}
|
||||
return nil
|
||||
}
|
||||
data, err := ioutil.ReadFile(x)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !bytes.HasPrefix(data, debugDeprecatedImportcfgMagic) {
|
||||
return errImportcfgSyntax
|
||||
}
|
||||
data = data[len(debugDeprecatedImportcfgMagic):]
|
||||
|
||||
f.Import = nil
|
||||
f.Pkg = nil
|
||||
if err := json.Unmarshal(data, &f); err != nil {
|
||||
return errImportcfgSyntax
|
||||
}
|
||||
f.enabled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *debugDeprecatedImportcfgFlag) lookup(parent *Package, path string) (dir, newPath string) {
|
||||
newPath = path
|
||||
if p := f.Import[path]; p != "" {
|
||||
newPath = p
|
||||
}
|
||||
if parent != nil {
|
||||
if p1 := f.Pkg[parent.ImportPath]; p1 != nil {
|
||||
if p := p1.Import[path]; p != "" {
|
||||
newPath = p
|
||||
}
|
||||
}
|
||||
}
|
||||
if p2 := f.Pkg[newPath]; p2 != nil {
|
||||
return p2.Dir, newPath
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
package load
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"go/token"
|
||||
@@ -14,6 +15,7 @@ import (
|
||||
pathpkg "path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
@@ -168,7 +170,7 @@ func (e *NoGoError) Error() string {
|
||||
return "no Go files in " + e.Package.Dir
|
||||
}
|
||||
|
||||
// Vendored returns the vendor-resolved version of imports,
|
||||
// Resolve returns the resolved version of imports,
|
||||
// which should be p.TestImports or p.XTestImports, NOT p.Imports.
|
||||
// The imports in p.TestImports and p.XTestImports are not recursively
|
||||
// loaded during the initial load of p, so they list the imports found in
|
||||
@@ -178,14 +180,14 @@ func (e *NoGoError) Error() string {
|
||||
// can produce better error messages if it starts with the original paths.
|
||||
// The initial load of p loads all the non-test imports and rewrites
|
||||
// the vendored paths, so nothing should ever call p.vendored(p.Imports).
|
||||
func (p *Package) Vendored(imports []string) []string {
|
||||
func (p *Package) Resolve(imports []string) []string {
|
||||
if len(imports) > 0 && len(p.Imports) > 0 && &imports[0] == &p.Imports[0] {
|
||||
panic("internal error: p.vendored(p.Imports) called")
|
||||
panic("internal error: p.Resolve(p.Imports) called")
|
||||
}
|
||||
seen := make(map[string]bool)
|
||||
var all []string
|
||||
for _, path := range imports {
|
||||
path = VendoredImportPath(p, path)
|
||||
path = ResolveImportPath(p, path)
|
||||
if !seen[path] {
|
||||
seen[path] = true
|
||||
all = append(all, path)
|
||||
@@ -380,16 +382,20 @@ func makeImportValid(r rune) rune {
|
||||
|
||||
// Mode flags for loadImport and download (in get.go).
|
||||
const (
|
||||
// UseVendor means that loadImport should do vendor expansion
|
||||
// (provided the vendoring experiment is enabled).
|
||||
// That is, useVendor means that the import path came from
|
||||
// a source file and has not been vendor-expanded yet.
|
||||
// Every import path should be loaded initially with useVendor,
|
||||
// and then the expanded version (with the /vendor/ in it) gets
|
||||
// recorded as the canonical import path. At that point, future loads
|
||||
// of that package must not pass useVendor, because
|
||||
// ResolveImport means that loadImport should do import path expansion.
|
||||
// That is, ResolveImport means that the import path came from
|
||||
// a source file and has not been expanded yet to account for
|
||||
// vendoring or possible module adjustment.
|
||||
// Every import path should be loaded initially with ResolveImport,
|
||||
// and then the expanded version (for example with the /vendor/ in it)
|
||||
// gets recorded as the canonical import path. At that point, future loads
|
||||
// of that package must not pass ResolveImport, because
|
||||
// disallowVendor will reject direct use of paths containing /vendor/.
|
||||
UseVendor = 1 << iota
|
||||
ResolveImport = 1 << iota
|
||||
|
||||
// ResolveModule is for download (part of "go get") and indicates
|
||||
// that the module adjustment should be done, but not vendor adjustment.
|
||||
ResolveModule
|
||||
|
||||
// GetTestDeps is for download (part of "go get") and indicates
|
||||
// that test dependencies should be fetched too.
|
||||
@@ -412,20 +418,17 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
|
||||
importPath := path
|
||||
origPath := path
|
||||
isLocal := build.IsLocalImport(path)
|
||||
var debugDeprecatedImportcfgDir string
|
||||
if isLocal {
|
||||
importPath = dirToImportPath(filepath.Join(srcDir, path))
|
||||
} else if DebugDeprecatedImportcfg.enabled {
|
||||
if d, i := DebugDeprecatedImportcfg.lookup(parent, path); d != "" {
|
||||
debugDeprecatedImportcfgDir = d
|
||||
importPath = i
|
||||
}
|
||||
} else if mode&UseVendor != 0 {
|
||||
// We do our own vendor resolution, because we want to
|
||||
} else if mode&ResolveImport != 0 {
|
||||
// We do our own path resolution, because we want to
|
||||
// find out the key to use in packageCache without the
|
||||
// overhead of repeated calls to buildContext.Import.
|
||||
// The code is also needed in a few other places anyway.
|
||||
path = VendoredImportPath(parent, path)
|
||||
path = ResolveImportPath(parent, path)
|
||||
importPath = path
|
||||
} else if mode&ResolveModule != 0 {
|
||||
path = ModuleImportPath(parent, path)
|
||||
importPath = path
|
||||
}
|
||||
|
||||
@@ -441,26 +444,17 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
|
||||
// Load package.
|
||||
// Import always returns bp != nil, even if an error occurs,
|
||||
// in order to return partial information.
|
||||
var bp *build.Package
|
||||
var err error
|
||||
if debugDeprecatedImportcfgDir != "" {
|
||||
bp, err = cfg.BuildContext.ImportDir(debugDeprecatedImportcfgDir, 0)
|
||||
} else if DebugDeprecatedImportcfg.enabled {
|
||||
bp = new(build.Package)
|
||||
err = fmt.Errorf("unknown import path %q: not in import cfg", importPath)
|
||||
} else {
|
||||
buildMode := build.ImportComment
|
||||
if mode&UseVendor == 0 || path != origPath {
|
||||
// Not vendoring, or we already found the vendored path.
|
||||
buildMode |= build.IgnoreVendor
|
||||
}
|
||||
bp, err = cfg.BuildContext.Import(path, srcDir, buildMode)
|
||||
buildMode := build.ImportComment
|
||||
if mode&ResolveImport == 0 || path != origPath {
|
||||
// Not vendoring, or we already found the vendored path.
|
||||
buildMode |= build.IgnoreVendor
|
||||
}
|
||||
bp, err := cfg.BuildContext.Import(path, srcDir, buildMode)
|
||||
bp.ImportPath = importPath
|
||||
if cfg.GOBIN != "" {
|
||||
bp.BinDir = cfg.GOBIN
|
||||
}
|
||||
if debugDeprecatedImportcfgDir == "" && err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
|
||||
if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
|
||||
!strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") {
|
||||
err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)
|
||||
}
|
||||
@@ -469,7 +463,7 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
|
||||
p = setErrorPos(p, importPos)
|
||||
}
|
||||
|
||||
if debugDeprecatedImportcfgDir == "" && origPath != cleanImport(origPath) {
|
||||
if origPath != cleanImport(origPath) {
|
||||
p.Error = &PackageError{
|
||||
ImportStack: stk.Copy(),
|
||||
Err: fmt.Sprintf("non-canonical import path: %q should be %q", origPath, pathpkg.Clean(origPath)),
|
||||
@@ -482,7 +476,7 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
|
||||
if perr := disallowInternal(srcDir, p, stk); perr != p {
|
||||
return setErrorPos(perr, importPos)
|
||||
}
|
||||
if mode&UseVendor != 0 {
|
||||
if mode&ResolveImport != 0 {
|
||||
if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
|
||||
return setErrorPos(perr, importPos)
|
||||
}
|
||||
@@ -541,31 +535,31 @@ func isDir(path string) bool {
|
||||
return result
|
||||
}
|
||||
|
||||
// VendoredImportPath returns the expansion of path when it appears in parent.
|
||||
// If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path,
|
||||
// x/vendor/path, vendor/path, or else stay path if none of those exist.
|
||||
// VendoredImportPath returns the expanded path or, if no expansion is found, the original.
|
||||
func VendoredImportPath(parent *Package, path string) (found string) {
|
||||
if DebugDeprecatedImportcfg.enabled {
|
||||
if d, i := DebugDeprecatedImportcfg.lookup(parent, path); d != "" {
|
||||
return i
|
||||
}
|
||||
return path
|
||||
// ResolveImportPath returns the true meaning of path when it appears in parent.
|
||||
// There are two different resolutions applied.
|
||||
// First, there is Go 1.5 vendoring (golang.org/s/go15vendor).
|
||||
// If vendor expansion doesn't trigger, then the path is also subject to
|
||||
// Go 1.11 vgo legacy conversion (golang.org/issue/25069).
|
||||
func ResolveImportPath(parent *Package, path string) (found string) {
|
||||
found = VendoredImportPath(parent, path)
|
||||
if found != path {
|
||||
return found
|
||||
}
|
||||
return ModuleImportPath(parent, path)
|
||||
}
|
||||
|
||||
if parent == nil || parent.Root == "" {
|
||||
return path
|
||||
}
|
||||
|
||||
dir := filepath.Clean(parent.Dir)
|
||||
root := filepath.Join(parent.Root, "src")
|
||||
if !str.HasFilePathPrefix(dir, root) || parent.ImportPath != "command-line-arguments" && filepath.Join(root, parent.ImportPath) != dir {
|
||||
// dirAndRoot returns the source directory and workspace root
|
||||
// for the package p, guaranteeing that root is a path prefix of dir.
|
||||
func dirAndRoot(p *Package) (dir, root string) {
|
||||
dir = filepath.Clean(p.Dir)
|
||||
root = filepath.Join(p.Root, "src")
|
||||
if !str.HasFilePathPrefix(dir, root) || p.ImportPath != "command-line-arguments" && filepath.Join(root, p.ImportPath) != dir {
|
||||
// Look for symlinks before reporting error.
|
||||
dir = expandPath(dir)
|
||||
root = expandPath(root)
|
||||
}
|
||||
|
||||
if !str.HasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || parent.ImportPath != "command-line-arguments" && !parent.Internal.Local && filepath.Join(root, parent.ImportPath) != dir {
|
||||
if !str.HasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || p.ImportPath != "command-line-arguments" && !p.Internal.Local && filepath.Join(root, p.ImportPath) != dir {
|
||||
base.Fatalf("unexpected directory layout:\n"+
|
||||
" import path: %s\n"+
|
||||
" root: %s\n"+
|
||||
@@ -573,14 +567,28 @@ func VendoredImportPath(parent *Package, path string) (found string) {
|
||||
" expand root: %s\n"+
|
||||
" expand dir: %s\n"+
|
||||
" separator: %s",
|
||||
parent.ImportPath,
|
||||
filepath.Join(parent.Root, "src"),
|
||||
filepath.Clean(parent.Dir),
|
||||
p.ImportPath,
|
||||
filepath.Join(p.Root, "src"),
|
||||
filepath.Clean(p.Dir),
|
||||
root,
|
||||
dir,
|
||||
string(filepath.Separator))
|
||||
}
|
||||
|
||||
return dir, root
|
||||
}
|
||||
|
||||
// VendoredImportPath returns the vendor-expansion of path when it appears in parent.
|
||||
// If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path,
|
||||
// x/vendor/path, vendor/path, or else stay path if none of those exist.
|
||||
// VendoredImportPath returns the expanded path or, if no expansion is found, the original.
|
||||
func VendoredImportPath(parent *Package, path string) (found string) {
|
||||
if parent == nil || parent.Root == "" {
|
||||
return path
|
||||
}
|
||||
|
||||
dir, root := dirAndRoot(parent)
|
||||
|
||||
vpath := "vendor/" + path
|
||||
for i := len(dir); i >= len(root); i-- {
|
||||
if i < len(dir) && dir[i] != filepath.Separator {
|
||||
@@ -623,6 +631,164 @@ func VendoredImportPath(parent *Package, path string) (found string) {
|
||||
return path
|
||||
}
|
||||
|
||||
var (
|
||||
modulePrefix = []byte("\nmodule ")
|
||||
goModPathCache = make(map[string]string)
|
||||
)
|
||||
|
||||
// goModPath returns the module path in the go.mod in dir, if any.
|
||||
func goModPath(dir string) (path string) {
|
||||
path, ok := goModPathCache[dir]
|
||||
if ok {
|
||||
return path
|
||||
}
|
||||
defer func() {
|
||||
goModPathCache[dir] = path
|
||||
}()
|
||||
|
||||
data, err := ioutil.ReadFile(filepath.Join(dir, "go.mod"))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
var i int
|
||||
if bytes.HasPrefix(data, modulePrefix[1:]) {
|
||||
i = 0
|
||||
} else {
|
||||
i = bytes.Index(data, modulePrefix)
|
||||
if i < 0 {
|
||||
return ""
|
||||
}
|
||||
i++
|
||||
}
|
||||
line := data[i:]
|
||||
|
||||
// Cut line at \n, drop trailing \r if present.
|
||||
if j := bytes.IndexByte(line, '\n'); j >= 0 {
|
||||
line = line[:j]
|
||||
}
|
||||
if line[len(line)-1] == '\r' {
|
||||
line = line[:len(line)-1]
|
||||
}
|
||||
line = line[len("module "):]
|
||||
|
||||
// If quoted, unquote.
|
||||
path = strings.TrimSpace(string(line))
|
||||
if path != "" && path[0] == '"' {
|
||||
s, err := strconv.Unquote(path)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
path = s
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// findVersionElement returns the slice indices of the final version element /vN in path.
|
||||
// If there is no such element, it returns -1, -1.
|
||||
func findVersionElement(path string) (i, j int) {
|
||||
j = len(path)
|
||||
for i = len(path) - 1; i >= 0; i-- {
|
||||
if path[i] == '/' {
|
||||
if isVersionElement(path[i:j]) {
|
||||
return i, j
|
||||
}
|
||||
j = i
|
||||
}
|
||||
}
|
||||
return -1, -1
|
||||
}
|
||||
|
||||
// isVersionElement reports whether s is a well-formed path version element:
|
||||
// v2, v3, v10, etc, but not v0, v05, v1.
|
||||
func isVersionElement(s string) bool {
|
||||
if len(s) < 3 || s[0] != '/' || s[1] != 'v' || s[2] == '0' || s[2] == '1' && len(s) == 3 {
|
||||
return false
|
||||
}
|
||||
for i := 2; i < len(s); i++ {
|
||||
if s[i] < '0' || '9' < s[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ModuleImportPath translates import paths found in go modules
|
||||
// back down to paths that can be resolved in ordinary builds.
|
||||
//
|
||||
// Define “new” code as code with a go.mod file in the same directory
|
||||
// or a parent directory. If an import in new code says x/y/v2/z but
|
||||
// x/y/v2/z does not exist and x/y/go.mod says “module x/y/v2”,
|
||||
// then go build will read the import as x/y/z instead.
|
||||
// See golang.org/issue/25069.
|
||||
func ModuleImportPath(parent *Package, path string) (found string) {
|
||||
if parent == nil || parent.Root == "" {
|
||||
return path
|
||||
}
|
||||
|
||||
// If there are no vN elements in path, leave it alone.
|
||||
// (The code below would do the same, but only after
|
||||
// some other file system accesses that we can avoid
|
||||
// here by returning early.)
|
||||
if i, _ := findVersionElement(path); i < 0 {
|
||||
return path
|
||||
}
|
||||
|
||||
dir, root := dirAndRoot(parent)
|
||||
|
||||
// Consider dir and parents, up to and including root.
|
||||
for i := len(dir); i >= len(root); i-- {
|
||||
if i < len(dir) && dir[i] != filepath.Separator {
|
||||
continue
|
||||
}
|
||||
if goModPath(dir[:i]) != "" {
|
||||
goto HaveGoMod
|
||||
}
|
||||
}
|
||||
// This code is not in a tree with a go.mod,
|
||||
// so apply no changes to the path.
|
||||
return path
|
||||
|
||||
HaveGoMod:
|
||||
// This import is in a tree with a go.mod.
|
||||
// Allow it to refer to code in GOPATH/src/x/y/z as x/y/v2/z
|
||||
// if GOPATH/src/x/y/go.mod says module "x/y/v2",
|
||||
|
||||
// If x/y/v2/z exists, use it unmodified.
|
||||
if bp, _ := cfg.BuildContext.Import(path, "", build.IgnoreVendor); bp.Dir != "" {
|
||||
return path
|
||||
}
|
||||
|
||||
// Otherwise look for a go.mod supplying a version element.
|
||||
// Some version-like elements may appear in paths but not
|
||||
// be module versions; we skip over those to look for module
|
||||
// versions. For example the module m/v2 might have a
|
||||
// package m/v2/api/v1/foo.
|
||||
limit := len(path)
|
||||
for limit > 0 {
|
||||
i, j := findVersionElement(path[:limit])
|
||||
if i < 0 {
|
||||
return path
|
||||
}
|
||||
if bp, _ := cfg.BuildContext.Import(path[:i], "", build.IgnoreVendor); bp.Dir != "" {
|
||||
if mpath := goModPath(bp.Dir); mpath != "" {
|
||||
// Found a valid go.mod file, so we're stopping the search.
|
||||
// If the path is m/v2/p and we found m/go.mod that says
|
||||
// "module m/v2", then we return "m/p".
|
||||
if mpath == path[:j] {
|
||||
return path[:i] + path[j:]
|
||||
}
|
||||
// Otherwise just return the original path.
|
||||
// We didn't find anything worth rewriting,
|
||||
// and the go.mod indicates that we should
|
||||
// not consider parent directories.
|
||||
return path
|
||||
}
|
||||
}
|
||||
limit = i
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// hasGoFiles reports whether dir contains any files with names ending in .go.
|
||||
// For a vendor check we must exclude directories that contain no .go files.
|
||||
// Otherwise it is not possible to vendor just a/b/c and still import the
|
||||
@@ -1081,7 +1247,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
|
||||
if path == "C" {
|
||||
continue
|
||||
}
|
||||
p1 := LoadImport(path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], UseVendor)
|
||||
p1 := LoadImport(path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], ResolveImport)
|
||||
if p.Standard && p.Error == nil && !p1.Standard && p1.Error == nil {
|
||||
p.Error = &PackageError{
|
||||
ImportStack: stk.Copy(),
|
||||
@@ -1206,6 +1372,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
|
||||
// GNU binutils flagfile specifiers, sometimes called "response files").
|
||||
// To be conservative, we reject almost any arg beginning with non-alphanumeric ASCII.
|
||||
// We accept leading . _ and / as likely in file system paths.
|
||||
// There is a copy of this function in cmd/compile/internal/gc/noder.go.
|
||||
func SafeArg(name string) bool {
|
||||
if name == "" {
|
||||
return false
|
||||
@@ -1591,7 +1758,7 @@ func TestPackagesFor(p *Package, forceTest bool) (ptest, pxtest *Package, err er
|
||||
stk.Push(p.ImportPath + " (test)")
|
||||
rawTestImports := str.StringList(p.TestImports)
|
||||
for i, path := range p.TestImports {
|
||||
p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], UseVendor)
|
||||
p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], ResolveImport)
|
||||
if p1.Error != nil {
|
||||
return nil, nil, p1.Error
|
||||
}
|
||||
@@ -1619,7 +1786,7 @@ func TestPackagesFor(p *Package, forceTest bool) (ptest, pxtest *Package, err er
|
||||
pxtestNeedsPtest := false
|
||||
rawXTestImports := str.StringList(p.XTestImports)
|
||||
for i, path := range p.XTestImports {
|
||||
p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], UseVendor)
|
||||
p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], ResolveImport)
|
||||
if p1.Error != nil {
|
||||
return nil, nil, p1.Error
|
||||
}
|
||||
|
||||
@@ -606,10 +606,10 @@ func runTest(cmd *base.Command, args []string) {
|
||||
for _, path := range p.Imports {
|
||||
deps[path] = true
|
||||
}
|
||||
for _, path := range p.Vendored(p.TestImports) {
|
||||
for _, path := range p.Resolve(p.TestImports) {
|
||||
deps[path] = true
|
||||
}
|
||||
for _, path := range p.Vendored(p.XTestImports) {
|
||||
for _, path := range p.Resolve(p.XTestImports) {
|
||||
deps[path] = true
|
||||
}
|
||||
}
|
||||
@@ -668,6 +668,14 @@ func runTest(cmd *base.Command, args []string) {
|
||||
continue
|
||||
}
|
||||
|
||||
// If using the race detector, silently ignore
|
||||
// attempts to run coverage on the runtime
|
||||
// packages. It will cause the race detector
|
||||
// to be invoked before it has been initialized.
|
||||
if cfg.BuildRace && p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal")) {
|
||||
continue
|
||||
}
|
||||
|
||||
if haveMatch {
|
||||
testCoverPkgs = append(testCoverPkgs, p)
|
||||
}
|
||||
|
||||
@@ -62,11 +62,11 @@ func runVet(cmd *base.Command, args []string) {
|
||||
base.Errorf("%v", err)
|
||||
continue
|
||||
}
|
||||
if len(ptest.GoFiles) == 0 && pxtest == nil {
|
||||
if len(ptest.GoFiles) == 0 && len(ptest.CgoFiles) == 0 && pxtest == nil {
|
||||
base.Errorf("go vet %s: no Go files in %s", p.ImportPath, p.Dir)
|
||||
continue
|
||||
}
|
||||
if len(ptest.GoFiles) > 0 {
|
||||
if len(ptest.GoFiles) > 0 || len(ptest.CgoFiles) > 0 {
|
||||
root.Deps = append(root.Deps, b.VetAction(work.ModeBuild, work.ModeBuild, ptest))
|
||||
}
|
||||
if pxtest != nil {
|
||||
|
||||
@@ -229,7 +229,6 @@ func AddBuildFlags(cmd *base.Command) {
|
||||
|
||||
// Undocumented, unstable debugging flags.
|
||||
cmd.Flag.StringVar(&cfg.DebugActiongraph, "debug-actiongraph", "", "")
|
||||
cmd.Flag.Var(&load.DebugDeprecatedImportcfg, "debug-deprecated-importcfg", "")
|
||||
}
|
||||
|
||||
// fileExtSplit expects a filename and returns the name
|
||||
|
||||
@@ -397,15 +397,7 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID
|
||||
// If so, it's up to date and we can reuse it instead of rebuilding it.
|
||||
var buildID string
|
||||
if target != "" && !cfg.BuildA {
|
||||
var err error
|
||||
buildID, err = buildid.ReadFile(target)
|
||||
if err != nil && b.ComputeStaleOnly {
|
||||
if p != nil && !p.Stale {
|
||||
p.Stale = true
|
||||
p.StaleReason = "target missing"
|
||||
}
|
||||
return true
|
||||
}
|
||||
buildID, _ = buildid.ReadFile(target)
|
||||
if strings.HasPrefix(buildID, actionID+buildIDSeparator) {
|
||||
a.buildID = buildID
|
||||
a.built = target
|
||||
@@ -482,7 +474,10 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
// Fall through to update a.buildID from the build artifact cache,
|
||||
// which will affect the computation of buildIDs for targets
|
||||
// higher up in the dependency graph.
|
||||
}
|
||||
|
||||
// Check the build artifact cache.
|
||||
@@ -510,6 +505,10 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID
|
||||
a.built = file
|
||||
a.Target = "DO NOT USE - using cache"
|
||||
a.buildID = buildID
|
||||
if p := a.Package; p != nil {
|
||||
// Clearer than explaining that something else is stale.
|
||||
p.StaleReason = "not installed but available in build cache"
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -520,6 +519,10 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID
|
||||
a.output = []byte{}
|
||||
}
|
||||
|
||||
if b.ComputeStaleOnly {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -934,16 +934,29 @@ func splitPkgConfigOutput(out []byte) []string {
|
||||
|
||||
// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package.
|
||||
func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string, err error) {
|
||||
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
|
||||
if pcargs := p.CgoPkgConfig; len(pcargs) > 0 {
|
||||
// pkg-config permits arguments to appear anywhere in
|
||||
// the command line. Move them all to the front, before --.
|
||||
var pcflags []string
|
||||
var pkgs []string
|
||||
for _, pcarg := range pcargs {
|
||||
if pcarg == "--" {
|
||||
// We're going to add our own "--" argument.
|
||||
} else if strings.HasPrefix(pcarg, "--") {
|
||||
pcflags = append(pcflags, pcarg)
|
||||
} else {
|
||||
pkgs = append(pkgs, pcarg)
|
||||
}
|
||||
}
|
||||
for _, pkg := range pkgs {
|
||||
if !load.SafeArg(pkg) {
|
||||
return nil, nil, fmt.Errorf("invalid pkg-config package name: %s", pkg)
|
||||
}
|
||||
}
|
||||
var out []byte
|
||||
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--cflags", "--", pkgs)
|
||||
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--cflags", pcflags, "--", pkgs)
|
||||
if err != nil {
|
||||
b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --cflags "+strings.Join(pkgs, " "), string(out))
|
||||
b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --cflags "+strings.Join(pcflags, " ")+strings.Join(pkgs, " "), string(out))
|
||||
b.Print(err.Error() + "\n")
|
||||
return nil, nil, errPrintedOutput
|
||||
}
|
||||
@@ -953,15 +966,15 @@ func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string,
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--libs", "--", pkgs)
|
||||
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--libs", pcflags, "--", pkgs)
|
||||
if err != nil {
|
||||
b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --libs "+strings.Join(pkgs, " "), string(out))
|
||||
b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --libs "+strings.Join(pcflags, " ")+strings.Join(pkgs, " "), string(out))
|
||||
b.Print(err.Error() + "\n")
|
||||
return nil, nil, errPrintedOutput
|
||||
}
|
||||
if len(out) > 0 {
|
||||
ldflags = strings.Fields(string(out))
|
||||
if err := checkLinkerFlags("CFLAGS", "pkg-config --cflags", ldflags); err != nil {
|
||||
if err := checkLinkerFlags("LDFLAGS", "pkg-config --libs", ldflags); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
@@ -1080,7 +1093,7 @@ func BuildInstallFunc(b *Builder, a *Action) (err error) {
|
||||
// We want to hide that awful detail as much as possible, so don't
|
||||
// advertise it by touching the mtimes (usually the libraries are up
|
||||
// to date).
|
||||
if !a.buggyInstall {
|
||||
if !a.buggyInstall && !b.ComputeStaleOnly {
|
||||
now := time.Now()
|
||||
os.Chtimes(a.Target, now, now)
|
||||
}
|
||||
|
||||
@@ -34,38 +34,95 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var re = regexp.MustCompile
|
||||
|
||||
var validCompilerFlags = []*regexp.Regexp{
|
||||
re(`-D([A-Za-z_].*)`),
|
||||
re(`-F([^@\-].*)`),
|
||||
re(`-I([^@\-].*)`),
|
||||
re(`-O`),
|
||||
re(`-O([^@\-].*)`),
|
||||
re(`-W`),
|
||||
re(`-W([^@,]+)`), // -Wall but not -Wa,-foo.
|
||||
re(`-Wa,-mbig-obj`),
|
||||
re(`-Wp,-D([A-Za-z_].*)`),
|
||||
re(`-ansi`),
|
||||
re(`-f(no-)?asynchronous-unwind-tables`),
|
||||
re(`-f(no-)?blocks`),
|
||||
re(`-f(no-)builtin-[a-zA-Z0-9_]*`),
|
||||
re(`-f(no-)?common`),
|
||||
re(`-f(no-)?constant-cfstrings`),
|
||||
re(`-fdiagnostics-show-note-include-stack`),
|
||||
re(`-f(no-)?eliminate-unused-debug-types`),
|
||||
re(`-f(no-)?exceptions`),
|
||||
re(`-f(no-)?fast-math`),
|
||||
re(`-f(no-)?inline-functions`),
|
||||
re(`-finput-charset=([^@\-].*)`),
|
||||
re(`-f(no-)?fat-lto-objects`),
|
||||
re(`-f(no-)?keep-inline-dllexport`),
|
||||
re(`-f(no-)?lto`),
|
||||
re(`-fmacro-backtrace-limit=(.+)`),
|
||||
re(`-fmessage-length=(.+)`),
|
||||
re(`-f(no-)?modules`),
|
||||
re(`-f(no-)?objc-arc`),
|
||||
re(`-f(no-)?objc-nonfragile-abi`),
|
||||
re(`-f(no-)?objc-legacy-dispatch`),
|
||||
re(`-f(no-)?omit-frame-pointer`),
|
||||
re(`-f(no-)?openmp(-simd)?`),
|
||||
re(`-f(no-)?permissive`),
|
||||
re(`-f(no-)?(pic|PIC|pie|PIE)`),
|
||||
re(`-f(no-)?plt`),
|
||||
re(`-f(no-)?rtti`),
|
||||
re(`-f(no-)?split-stack`),
|
||||
re(`-f(no-)?stack-(.+)`),
|
||||
re(`-f(no-)?strict-aliasing`),
|
||||
re(`-f(un)signed-char`),
|
||||
re(`-f(no-)?use-linker-plugin`), // safe if -B is not used; we don't permit -B
|
||||
re(`-f(no-)?visibility-inlines-hidden`),
|
||||
re(`-fsanitize=(.+)`),
|
||||
re(`-ftemplate-depth-(.+)`),
|
||||
re(`-fvisibility=(.+)`),
|
||||
re(`-g([^@\-].*)?`),
|
||||
re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`),
|
||||
re(`-m32`),
|
||||
re(`-m64`),
|
||||
re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`),
|
||||
re(`-marm`),
|
||||
re(`-mfloat-abi=([^@\-].*)`),
|
||||
re(`-mfpmath=[0-9a-z,+]*`),
|
||||
re(`-m(no-)?avx[0-9a-z.]*`),
|
||||
re(`-m(no-)?ms-bitfields`),
|
||||
re(`-m(no-)?stack-(.+)`),
|
||||
re(`-mmacosx-(.+)`),
|
||||
re(`-mios-simulator-version-min=(.+)`),
|
||||
re(`-miphoneos-version-min=(.+)`),
|
||||
re(`-mnop-fun-dllimport`),
|
||||
re(`-m(no-)?sse[0-9.]*`),
|
||||
re(`-mthumb(-interwork)?`),
|
||||
re(`-mthreads`),
|
||||
re(`-mwindows`),
|
||||
re(`--param=ssp-buffer-size=[0-9]*`),
|
||||
re(`-pedantic(-errors)?`),
|
||||
re(`-pipe`),
|
||||
re(`-pthread`),
|
||||
re(`-std=([^@\-].*)`),
|
||||
re(`-?-std=([^@\-].*)`),
|
||||
re(`-?-stdlib=([^@\-].*)`),
|
||||
re(`--sysroot=([^@\-].*)`),
|
||||
re(`-w`),
|
||||
re(`-x([^@\-].*)`),
|
||||
}
|
||||
|
||||
var validCompilerFlagsWithNextArg = []string{
|
||||
"-arch",
|
||||
"-D",
|
||||
"-I",
|
||||
"-framework",
|
||||
"-isysroot",
|
||||
"-isystem",
|
||||
"--sysroot",
|
||||
"-target",
|
||||
"-x",
|
||||
}
|
||||
|
||||
@@ -73,29 +130,76 @@ var validLinkerFlags = []*regexp.Regexp{
|
||||
re(`-F([^@\-].*)`),
|
||||
re(`-l([^@\-].*)`),
|
||||
re(`-L([^@\-].*)`),
|
||||
re(`-O`),
|
||||
re(`-O([^@\-].*)`),
|
||||
re(`-f(no-)?(pic|PIC|pie|PIE)`),
|
||||
re(`-f(no-)?openmp(-simd)?`),
|
||||
re(`-fsanitize=([^@\-].*)`),
|
||||
re(`-g([^@\-].*)?`),
|
||||
re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`),
|
||||
re(`-headerpad_max_install_names`),
|
||||
re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`),
|
||||
re(`-mfloat-abi=([^@\-].*)`),
|
||||
re(`-mmacosx-(.+)`),
|
||||
re(`-mios-simulator-version-min=(.+)`),
|
||||
re(`-miphoneos-version-min=(.+)`),
|
||||
re(`-mthreads`),
|
||||
re(`-mwindows`),
|
||||
re(`-(pic|PIC|pie|PIE)`),
|
||||
re(`-pthread`),
|
||||
re(`-rdynamic`),
|
||||
re(`-shared`),
|
||||
re(`-?-static([-a-z0-9+]*)`),
|
||||
re(`-?-stdlib=([^@\-].*)`),
|
||||
|
||||
// Note that any wildcards in -Wl need to exclude comma,
|
||||
// since -Wl splits its argument at commas and passes
|
||||
// them all to the linker uninterpreted. Allowing comma
|
||||
// in a wildcard would allow tunnelling arbitrary additional
|
||||
// linker arguments through one of these.
|
||||
re(`-Wl,-rpath,([^,@\-][^,]+)`),
|
||||
re(`-Wl,--(no-)?allow-multiple-definition`),
|
||||
re(`-Wl,--(no-)?allow-shlib-undefined`),
|
||||
re(`-Wl,--(no-)?as-needed`),
|
||||
re(`-Wl,-Bdynamic`),
|
||||
re(`-Wl,-Bstatic`),
|
||||
re(`-WL,-O([^@,\-][^,]*)?`),
|
||||
re(`-Wl,-d[ny]`),
|
||||
re(`-Wl,--disable-new-dtags`),
|
||||
re(`-Wl,-e[=,][a-zA-Z0-9]*`),
|
||||
re(`-Wl,--enable-new-dtags`),
|
||||
re(`-Wl,--end-group`),
|
||||
re(`-Wl,-framework,[^,@\-][^,]+`),
|
||||
re(`-Wl,-headerpad_max_install_names`),
|
||||
re(`-Wl,--no-undefined`),
|
||||
re(`-Wl,-rpath(-link)?[=,]([^,@\-][^,]+)`),
|
||||
re(`-Wl,-s`),
|
||||
re(`-Wl,-search_paths_first`),
|
||||
re(`-Wl,-sectcreate,([^,@\-][^,]+),([^,@\-][^,]+),([^,@\-][^,]+)`),
|
||||
re(`-Wl,--start-group`),
|
||||
re(`-Wl,-?-static`),
|
||||
re(`-Wl,-?-subsystem,(native|windows|console|posix|xbox)`),
|
||||
re(`-Wl,-syslibroot[=,]([^,@\-][^,]+)`),
|
||||
re(`-Wl,-undefined[=,]([^,@\-][^,]+)`),
|
||||
re(`-Wl,-?-unresolved-symbols=[^,]+`),
|
||||
re(`-Wl,--(no-)?warn-([^,]+)`),
|
||||
re(`-Wl,-z,(no)?execstack`),
|
||||
re(`-Wl,-z,relro`),
|
||||
|
||||
re(`[a-zA-Z0-9_].*\.(o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o)
|
||||
re(`[a-zA-Z0-9_/].*\.(a|o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o)
|
||||
re(`\./.*\.(a|o|obj|dll|dylib|so)`),
|
||||
}
|
||||
|
||||
var validLinkerFlagsWithNextArg = []string{
|
||||
"-arch",
|
||||
"-F",
|
||||
"-l",
|
||||
"-L",
|
||||
"-framework",
|
||||
"-isysroot",
|
||||
"--sysroot",
|
||||
"-target",
|
||||
"-Wl,-framework",
|
||||
"-Wl,-rpath",
|
||||
"-Wl,-undefined",
|
||||
}
|
||||
|
||||
func checkCompilerFlags(name, source string, list []string) error {
|
||||
@@ -147,10 +251,21 @@ Args:
|
||||
i++
|
||||
continue Args
|
||||
}
|
||||
if i+1 < len(list) {
|
||||
return fmt.Errorf("invalid flag in %s: %s %s", source, arg, list[i+1])
|
||||
|
||||
// Permit -Wl,-framework -Wl,name.
|
||||
if i+1 < len(list) &&
|
||||
strings.HasPrefix(arg, "-Wl,") &&
|
||||
strings.HasPrefix(list[i+1], "-Wl,") &&
|
||||
load.SafeArg(list[i+1][4:]) &&
|
||||
!strings.Contains(list[i+1][4:], ",") {
|
||||
i++
|
||||
continue Args
|
||||
}
|
||||
return fmt.Errorf("invalid flag in %s: %s without argument", source, arg)
|
||||
|
||||
if i+1 < len(list) {
|
||||
return fmt.Errorf("invalid flag in %s: %s %s (see https://golang.org/s/invalidflag)", source, arg, list[i+1])
|
||||
}
|
||||
return fmt.Errorf("invalid flag in %s: %s without argument (see https://golang.org/s/invalidflag)", source, arg)
|
||||
}
|
||||
}
|
||||
Bad:
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
var goodCompilerFlags = [][]string{
|
||||
{"-DFOO"},
|
||||
{"-Dfoo=bar"},
|
||||
{"-F/Qt"},
|
||||
{"-I/"},
|
||||
{"-I/etc/passwd"},
|
||||
{"-I."},
|
||||
@@ -62,6 +63,8 @@ var goodCompilerFlags = [][]string{
|
||||
var badCompilerFlags = [][]string{
|
||||
{"-D@X"},
|
||||
{"-D-X"},
|
||||
{"-F@dir"},
|
||||
{"-F-dir"},
|
||||
{"-I@dir"},
|
||||
{"-I-dir"},
|
||||
{"-O@1"},
|
||||
@@ -125,6 +128,7 @@ var goodLinkerFlags = [][]string{
|
||||
{"-Wl,--no-warn-error"},
|
||||
{"foo.so"},
|
||||
{"_世界.dll"},
|
||||
{"./x.o"},
|
||||
{"libcgosotest.dylib"},
|
||||
{"-F", "framework"},
|
||||
{"-l", "."},
|
||||
@@ -132,14 +136,14 @@ var goodLinkerFlags = [][]string{
|
||||
{"-l", "世界"},
|
||||
{"-L", "framework"},
|
||||
{"-framework", "Chocolate"},
|
||||
{"-Wl,-framework", "-Wl,Chocolate"},
|
||||
{"-Wl,-framework,Chocolate"},
|
||||
{"-Wl,-unresolved-symbols=ignore-all"},
|
||||
}
|
||||
|
||||
var badLinkerFlags = [][]string{
|
||||
{"-DFOO"},
|
||||
{"-Dfoo=bar"},
|
||||
{"-O"},
|
||||
{"-O2"},
|
||||
{"-Osmall"},
|
||||
{"-W"},
|
||||
{"-Wall"},
|
||||
{"-fobjc-arc"},
|
||||
@@ -152,7 +156,6 @@ var badLinkerFlags = [][]string{
|
||||
{"-fno-stack-xxx"},
|
||||
{"-mstack-overflow"},
|
||||
{"-mno-stack-overflow"},
|
||||
{"-mmacosx-version"},
|
||||
{"-mnop-fun-dllimport"},
|
||||
{"-std=c99"},
|
||||
{"-xc"},
|
||||
@@ -185,9 +188,14 @@ var badLinkerFlags = [][]string{
|
||||
{"-l", "-foo"},
|
||||
{"-framework", "-Caffeine"},
|
||||
{"-framework", "@Home"},
|
||||
{"-Wl,-framework,-Caffeine"},
|
||||
{"-Wl,-framework", "-Wl,@Home"},
|
||||
{"-Wl,-framework", "@Home"},
|
||||
{"-Wl,-framework,Chocolate,@Home"},
|
||||
{"-x", "--c"},
|
||||
{"-x", "@obj"},
|
||||
{"-Wl,-rpath,@foo"},
|
||||
{"../x.o"},
|
||||
}
|
||||
|
||||
func TestCheckLinkerFlags(t *testing.T) {
|
||||
|
||||
1
src/cmd/go/testdata/modlegacy/src/new/go.mod
vendored
Normal file
1
src/cmd/go/testdata/modlegacy/src/new/go.mod
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module "new/v2"
|
||||
3
src/cmd/go/testdata/modlegacy/src/new/new.go
vendored
Normal file
3
src/cmd/go/testdata/modlegacy/src/new/new.go
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
package new
|
||||
|
||||
import _ "new/v2/p2"
|
||||
7
src/cmd/go/testdata/modlegacy/src/new/p1/p1.go
vendored
Normal file
7
src/cmd/go/testdata/modlegacy/src/new/p1/p1.go
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
package p1
|
||||
|
||||
import _ "old/p2"
|
||||
import _ "new/v2"
|
||||
import _ "new/v2/p2"
|
||||
import _ "new/sub/v2/x/v1/y" // v2 is module, v1 is directory in module
|
||||
import _ "new/sub/inner/x" // new/sub/inner/go.mod overrides new/sub/go.mod
|
||||
1
src/cmd/go/testdata/modlegacy/src/new/p2/p2.go
vendored
Normal file
1
src/cmd/go/testdata/modlegacy/src/new/p2/p2.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package p2
|
||||
1
src/cmd/go/testdata/modlegacy/src/new/sub/go.mod
vendored
Normal file
1
src/cmd/go/testdata/modlegacy/src/new/sub/go.mod
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module new/sub/v2
|
||||
1
src/cmd/go/testdata/modlegacy/src/new/sub/inner/go.mod
vendored
Normal file
1
src/cmd/go/testdata/modlegacy/src/new/sub/inner/go.mod
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module new/sub/inner
|
||||
1
src/cmd/go/testdata/modlegacy/src/new/sub/inner/x/x.go
vendored
Normal file
1
src/cmd/go/testdata/modlegacy/src/new/sub/inner/x/x.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package x
|
||||
1
src/cmd/go/testdata/modlegacy/src/new/sub/x/v1/y/y.go
vendored
Normal file
1
src/cmd/go/testdata/modlegacy/src/new/sub/x/v1/y/y.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package y
|
||||
5
src/cmd/go/testdata/modlegacy/src/old/p1/p1.go
vendored
Normal file
5
src/cmd/go/testdata/modlegacy/src/old/p1/p1.go
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
package p1
|
||||
|
||||
import _ "old/p2"
|
||||
import _ "new/p1"
|
||||
import _ "new"
|
||||
1
src/cmd/go/testdata/modlegacy/src/old/p2/p2.go
vendored
Normal file
1
src/cmd/go/testdata/modlegacy/src/old/p2/p2.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package p2
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -328,3 +329,75 @@ func TestVendor12156(t *testing.T) {
|
||||
tg.grepStderrNot("panic", "panicked")
|
||||
tg.grepStderr(`cannot find package "x"`, "wrong error")
|
||||
}
|
||||
|
||||
// Module legacy support does path rewriting very similar to vendoring.
|
||||
|
||||
func TestModLegacy(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/modlegacy"))
|
||||
tg.run("list", "-f", "{{.Imports}}", "old/p1")
|
||||
tg.grepStdout("new/p1", "old/p1 should import new/p1")
|
||||
tg.run("list", "-f", "{{.Imports}}", "new/p1")
|
||||
tg.grepStdout("new/p2", "new/p1 should import new/p2 (not new/v2/p2)")
|
||||
tg.grepStdoutNot("new/v2", "new/p1 should NOT import new/v2*")
|
||||
tg.grepStdout("new/sub/x/v1/y", "new/p1 should import new/sub/x/v1/y (not new/sub/v2/x/v1/y)")
|
||||
tg.grepStdoutNot("new/sub/v2", "new/p1 should NOT import new/sub/v2*")
|
||||
tg.grepStdout("new/sub/inner/x", "new/p1 should import new/sub/inner/x (no rewrites)")
|
||||
tg.run("build", "old/p1", "new/p1")
|
||||
}
|
||||
|
||||
func TestModLegacyGet(t *testing.T) {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.makeTempdir()
|
||||
tg.setenv("GOPATH", tg.path("d1"))
|
||||
tg.run("get", "vcs-test.golang.org/git/modlegacy1-old.git/p1")
|
||||
tg.run("list", "-f", "{{.Deps}}", "vcs-test.golang.org/git/modlegacy1-old.git/p1")
|
||||
tg.grepStdout("new.git/p2", "old/p1 should depend on new/p2")
|
||||
tg.grepStdoutNot("new.git/v2/p2", "old/p1 should NOT depend on new/v2/p2")
|
||||
tg.run("build", "vcs-test.golang.org/git/modlegacy1-old.git/p1", "vcs-test.golang.org/git/modlegacy1-new.git/p1")
|
||||
|
||||
tg.setenv("GOPATH", tg.path("d2"))
|
||||
|
||||
tg.must(os.RemoveAll(tg.path("d2")))
|
||||
tg.run("get", "github.com/rsc/vgotest5")
|
||||
tg.run("get", "github.com/rsc/vgotest4")
|
||||
tg.run("get", "github.com/myitcv/vgo_example_compat")
|
||||
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
tg.must(os.RemoveAll(tg.path("d2")))
|
||||
tg.run("get", "github.com/rsc/vgotest4")
|
||||
tg.run("get", "github.com/rsc/vgotest5")
|
||||
tg.run("get", "github.com/myitcv/vgo_example_compat")
|
||||
|
||||
tg.must(os.RemoveAll(tg.path("d2")))
|
||||
tg.run("get", "github.com/rsc/vgotest4", "github.com/rsc/vgotest5")
|
||||
tg.run("get", "github.com/myitcv/vgo_example_compat")
|
||||
|
||||
tg.must(os.RemoveAll(tg.path("d2")))
|
||||
tg.run("get", "github.com/rsc/vgotest5", "github.com/rsc/vgotest4")
|
||||
tg.run("get", "github.com/myitcv/vgo_example_compat")
|
||||
|
||||
tg.must(os.RemoveAll(tg.path("d2")))
|
||||
tg.run("get", "github.com/myitcv/vgo_example_compat")
|
||||
tg.run("get", "github.com/rsc/vgotest4", "github.com/rsc/vgotest5")
|
||||
|
||||
pkgs := []string{"github.com/myitcv/vgo_example_compat", "github.com/rsc/vgotest4", "github.com/rsc/vgotest5"}
|
||||
for i := 0; i < 3; i++ {
|
||||
for j := 0; j < 3; j++ {
|
||||
for k := 0; k < 3; k++ {
|
||||
if i == j || i == k || k == j {
|
||||
continue
|
||||
}
|
||||
tg.must(os.RemoveAll(tg.path("d2")))
|
||||
tg.run("get", pkgs[i], pkgs[j], pkgs[k])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,20 +531,22 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
|
||||
p.Link = q
|
||||
p1 = q.Link
|
||||
|
||||
var regOff int16
|
||||
var addrOff int64
|
||||
if c.ctxt.Arch.ByteOrder == binary.BigEndian {
|
||||
regOff = 1 // load odd register first
|
||||
addrOff = 4 // swap load/save order
|
||||
}
|
||||
if p.From.Type == obj.TYPE_MEM {
|
||||
reg := REG_F0 + (p.To.Reg-REG_F0)&^1
|
||||
p.To.Reg = reg + regOff
|
||||
q.To.Reg = reg + 1 - regOff
|
||||
q.From.Offset += 4
|
||||
p.To.Reg = reg
|
||||
q.To.Reg = reg + 1
|
||||
p.From.Offset += addrOff
|
||||
q.From.Offset += 4 - addrOff
|
||||
} else if p.To.Type == obj.TYPE_MEM {
|
||||
reg := REG_F0 + (p.From.Reg-REG_F0)&^1
|
||||
p.From.Reg = reg + regOff
|
||||
q.From.Reg = reg + 1 - regOff
|
||||
q.To.Offset += 4
|
||||
p.From.Reg = reg
|
||||
q.From.Reg = reg + 1
|
||||
p.To.Offset += addrOff
|
||||
q.To.Offset += 4 - addrOff
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
34
src/cmd/internal/objabi/funcid.go
Normal file
34
src/cmd/internal/objabi/funcid.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package objabi
|
||||
|
||||
// A FuncID identifies particular functions that need to be treated
|
||||
// specially by the runtime.
|
||||
// Note that in some situations involving plugins, there may be multiple
|
||||
// copies of a particular special runtime function.
|
||||
// Note: this list must match the list in runtime/symtab.go.
|
||||
type FuncID uint32
|
||||
|
||||
const (
|
||||
FuncID_normal FuncID = iota // not a special function
|
||||
FuncID_goexit
|
||||
FuncID_jmpdefer
|
||||
FuncID_mcall
|
||||
FuncID_morestack
|
||||
FuncID_mstart
|
||||
FuncID_rt0_go
|
||||
FuncID_asmcgocall
|
||||
FuncID_sigpanic
|
||||
FuncID_runfinq
|
||||
FuncID_bgsweep
|
||||
FuncID_forcegchelper
|
||||
FuncID_timerproc
|
||||
FuncID_gcBgMarkWorker
|
||||
FuncID_systemstack_switch
|
||||
FuncID_systemstack
|
||||
FuncID_cgocallback_gofunc
|
||||
FuncID_gogo
|
||||
FuncID_externalthreadhandler
|
||||
)
|
||||
@@ -175,6 +175,7 @@ func (c *converter) handleInputLine(line []byte) {
|
||||
// "=== RUN "
|
||||
// "=== PAUSE "
|
||||
// "=== CONT "
|
||||
actionColon := false
|
||||
origLine := line
|
||||
ok := false
|
||||
indent := 0
|
||||
@@ -196,6 +197,7 @@ func (c *converter) handleInputLine(line []byte) {
|
||||
}
|
||||
for _, magic := range reports {
|
||||
if bytes.HasPrefix(line, magic) {
|
||||
actionColon = true
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
@@ -209,7 +211,10 @@ func (c *converter) handleInputLine(line []byte) {
|
||||
}
|
||||
|
||||
// Parse out action and test name.
|
||||
i := bytes.IndexByte(line, ':') + 1
|
||||
i := 0
|
||||
if actionColon {
|
||||
i = bytes.IndexByte(line, ':') + 1
|
||||
}
|
||||
if i == 0 {
|
||||
i = len(updates[0])
|
||||
}
|
||||
|
||||
14
src/cmd/internal/test2json/testdata/issue23920.json
vendored
Normal file
14
src/cmd/internal/test2json/testdata/issue23920.json
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
{"Action":"run","Test":"TestWithColons"}
|
||||
{"Action":"output","Test":"TestWithColons","Output":"=== RUN TestWithColons\n"}
|
||||
{"Action":"run","Test":"TestWithColons/[::1]"}
|
||||
{"Action":"output","Test":"TestWithColons/[::1]","Output":"=== RUN TestWithColons/[::1]\n"}
|
||||
{"Action":"run","Test":"TestWithColons/127.0.0.1:0"}
|
||||
{"Action":"output","Test":"TestWithColons/127.0.0.1:0","Output":"=== RUN TestWithColons/127.0.0.1:0\n"}
|
||||
{"Action":"output","Test":"TestWithColons","Output":"--- PASS: TestWithColons (0.00s)\n"}
|
||||
{"Action":"output","Test":"TestWithColons/[::1]","Output":" --- PASS: TestWithColons/[::1] (0.00s)\n"}
|
||||
{"Action":"pass","Test":"TestWithColons/[::1]"}
|
||||
{"Action":"output","Test":"TestWithColons/127.0.0.1:0","Output":" --- PASS: TestWithColons/127.0.0.1:0 (0.00s)\n"}
|
||||
{"Action":"pass","Test":"TestWithColons/127.0.0.1:0"}
|
||||
{"Action":"pass","Test":"TestWithColons"}
|
||||
{"Action":"output","Output":"PASS\n"}
|
||||
{"Action":"pass"}
|
||||
7
src/cmd/internal/test2json/testdata/issue23920.test
vendored
Normal file
7
src/cmd/internal/test2json/testdata/issue23920.test
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
=== RUN TestWithColons
|
||||
=== RUN TestWithColons/[::1]
|
||||
=== RUN TestWithColons/127.0.0.1:0
|
||||
--- PASS: TestWithColons (0.00s)
|
||||
--- PASS: TestWithColons/[::1] (0.00s)
|
||||
--- PASS: TestWithColons/127.0.0.1:0 (0.00s)
|
||||
PASS
|
||||
@@ -1265,7 +1265,7 @@ func (ctxt *Link) hostlink() {
|
||||
// does not work, the resulting programs will not run. See
|
||||
// issue #17847. To avoid this problem pass -no-pie to the
|
||||
// toolchain if it is supported.
|
||||
if ctxt.BuildMode == BuildModeExe {
|
||||
if ctxt.BuildMode == BuildModeExe && !ctxt.linkShared {
|
||||
src := filepath.Join(*flagTmpdir, "trivial.c")
|
||||
if err := ioutil.WriteFile(src, []byte("int main() { return 0; }"), 0666); err != nil {
|
||||
Errorf(nil, "WriteFile trivial.c failed: %v", err)
|
||||
|
||||
@@ -312,12 +312,47 @@ func (ctxt *Link) pclntab() {
|
||||
}
|
||||
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), args))
|
||||
|
||||
// frame int32
|
||||
// This has been removed (it was never set quite correctly anyway).
|
||||
// Nothing should use it.
|
||||
// Leave an obviously incorrect value.
|
||||
// TODO: Remove entirely.
|
||||
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), 0x1234567))
|
||||
// funcID uint32
|
||||
funcID := objabi.FuncID_normal
|
||||
switch s.Name {
|
||||
case "runtime.goexit":
|
||||
funcID = objabi.FuncID_goexit
|
||||
case "runtime.jmpdefer":
|
||||
funcID = objabi.FuncID_jmpdefer
|
||||
case "runtime.mcall":
|
||||
funcID = objabi.FuncID_mcall
|
||||
case "runtime.morestack":
|
||||
funcID = objabi.FuncID_morestack
|
||||
case "runtime.mstart":
|
||||
funcID = objabi.FuncID_mstart
|
||||
case "runtime.rt0_go":
|
||||
funcID = objabi.FuncID_rt0_go
|
||||
case "runtime.asmcgocall":
|
||||
funcID = objabi.FuncID_asmcgocall
|
||||
case "runtime.sigpanic":
|
||||
funcID = objabi.FuncID_sigpanic
|
||||
case "runtime.runfinq":
|
||||
funcID = objabi.FuncID_runfinq
|
||||
case "runtime.bgsweep":
|
||||
funcID = objabi.FuncID_bgsweep
|
||||
case "runtime.forcegchelper":
|
||||
funcID = objabi.FuncID_forcegchelper
|
||||
case "runtime.timerproc":
|
||||
funcID = objabi.FuncID_timerproc
|
||||
case "runtime.gcBgMarkWorker":
|
||||
funcID = objabi.FuncID_gcBgMarkWorker
|
||||
case "runtime.systemstack_switch":
|
||||
funcID = objabi.FuncID_systemstack_switch
|
||||
case "runtime.systemstack":
|
||||
funcID = objabi.FuncID_systemstack
|
||||
case "runtime.cgocallback_gofunc":
|
||||
funcID = objabi.FuncID_cgocallback_gofunc
|
||||
case "runtime.gogo":
|
||||
funcID = objabi.FuncID_gogo
|
||||
case "runtime.externalthreadhandler":
|
||||
funcID = objabi.FuncID_externalthreadhandler
|
||||
}
|
||||
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(funcID)))
|
||||
|
||||
if pcln != &pclntabZpcln {
|
||||
renumberfiles(ctxt, pcln.File, &pcln.Pcfile)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"crypto/rand"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@@ -42,6 +43,7 @@ type nameConstraintsTest struct {
|
||||
roots []constraintsSpec
|
||||
intermediates [][]constraintsSpec
|
||||
leaf leafSpec
|
||||
requestedEKUs []ExtKeyUsage
|
||||
expectedError string
|
||||
noOpenSSL bool
|
||||
}
|
||||
@@ -1220,8 +1222,9 @@ var nameConstraintsTests = []nameConstraintsTest{
|
||||
},
|
||||
},
|
||||
|
||||
// #63: A specified key usage in an intermediate forbids other usages
|
||||
// in the leaf.
|
||||
// #63: An intermediate with enumerated EKUs causes a failure if we
|
||||
// test for an EKU not in that set. (ServerAuth is required by
|
||||
// default.)
|
||||
nameConstraintsTest{
|
||||
roots: []constraintsSpec{
|
||||
constraintsSpec{},
|
||||
@@ -1237,11 +1240,11 @@ var nameConstraintsTests = []nameConstraintsTest{
|
||||
sans: []string{"dns:example.com"},
|
||||
ekus: []string{"serverAuth"},
|
||||
},
|
||||
expectedError: "EKU not permitted",
|
||||
expectedError: "incompatible key usage",
|
||||
},
|
||||
|
||||
// #64: A specified key usage in an intermediate forbids other usages
|
||||
// in the leaf, even if we don't recognise them.
|
||||
// #64: an unknown EKU in the leaf doesn't break anything, even if it's not
|
||||
// correctly nested.
|
||||
nameConstraintsTest{
|
||||
roots: []constraintsSpec{
|
||||
constraintsSpec{},
|
||||
@@ -1257,7 +1260,7 @@ var nameConstraintsTests = []nameConstraintsTest{
|
||||
sans: []string{"dns:example.com"},
|
||||
ekus: []string{"other"},
|
||||
},
|
||||
expectedError: "EKU not permitted",
|
||||
requestedEKUs: []ExtKeyUsage{ExtKeyUsageAny},
|
||||
},
|
||||
|
||||
// #65: trying to add extra permitted key usages in an intermediate
|
||||
@@ -1282,24 +1285,25 @@ var nameConstraintsTests = []nameConstraintsTest{
|
||||
},
|
||||
},
|
||||
|
||||
// #66: EKUs in roots are ignored.
|
||||
// #66: EKUs in roots are not ignored.
|
||||
nameConstraintsTest{
|
||||
roots: []constraintsSpec{
|
||||
constraintsSpec{
|
||||
ekus: []string{"serverAuth"},
|
||||
ekus: []string{"email"},
|
||||
},
|
||||
},
|
||||
intermediates: [][]constraintsSpec{
|
||||
[]constraintsSpec{
|
||||
constraintsSpec{
|
||||
ekus: []string{"serverAuth", "email"},
|
||||
ekus: []string{"serverAuth"},
|
||||
},
|
||||
},
|
||||
},
|
||||
leaf: leafSpec{
|
||||
sans: []string{"dns:example.com"},
|
||||
ekus: []string{"serverAuth", "email"},
|
||||
ekus: []string{"serverAuth"},
|
||||
},
|
||||
expectedError: "incompatible key usage",
|
||||
},
|
||||
|
||||
// #67: in order to support COMODO chains, SGC key usages permit
|
||||
@@ -1444,6 +1448,138 @@ var nameConstraintsTests = []nameConstraintsTest{
|
||||
},
|
||||
expectedError: "\"https://example.com/test\" is excluded",
|
||||
},
|
||||
|
||||
// #75: serverAuth in a leaf shouldn't permit clientAuth when requested in
|
||||
// VerifyOptions.
|
||||
nameConstraintsTest{
|
||||
roots: []constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
intermediates: [][]constraintsSpec{
|
||||
[]constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
},
|
||||
leaf: leafSpec{
|
||||
sans: []string{"dns:example.com"},
|
||||
ekus: []string{"serverAuth"},
|
||||
},
|
||||
requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth},
|
||||
expectedError: "incompatible key usage",
|
||||
},
|
||||
|
||||
// #76: However, MSSGC in a leaf should match a request for serverAuth.
|
||||
nameConstraintsTest{
|
||||
roots: []constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
intermediates: [][]constraintsSpec{
|
||||
[]constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
},
|
||||
leaf: leafSpec{
|
||||
sans: []string{"dns:example.com"},
|
||||
ekus: []string{"msSGC"},
|
||||
},
|
||||
requestedEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
|
||||
},
|
||||
|
||||
// An invalid DNS SAN should be detected only at validation time so
|
||||
// that we can process CA certificates in the wild that have invalid SANs.
|
||||
// See https://github.com/golang/go/issues/23995
|
||||
|
||||
// #77: an invalid DNS or mail SAN will not be detected if name constaint
|
||||
// checking is not triggered.
|
||||
nameConstraintsTest{
|
||||
roots: []constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
intermediates: [][]constraintsSpec{
|
||||
[]constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
},
|
||||
leaf: leafSpec{
|
||||
sans: []string{"dns:this is invalid", "email:this @ is invalid"},
|
||||
},
|
||||
},
|
||||
|
||||
// #78: an invalid DNS SAN will be detected if any name constraint checking
|
||||
// is triggered.
|
||||
nameConstraintsTest{
|
||||
roots: []constraintsSpec{
|
||||
constraintsSpec{
|
||||
bad: []string{"uri:"},
|
||||
},
|
||||
},
|
||||
intermediates: [][]constraintsSpec{
|
||||
[]constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
},
|
||||
leaf: leafSpec{
|
||||
sans: []string{"dns:this is invalid"},
|
||||
},
|
||||
expectedError: "cannot parse dnsName",
|
||||
},
|
||||
|
||||
// #79: an invalid email SAN will be detected if any name constraint
|
||||
// checking is triggered.
|
||||
nameConstraintsTest{
|
||||
roots: []constraintsSpec{
|
||||
constraintsSpec{
|
||||
bad: []string{"uri:"},
|
||||
},
|
||||
},
|
||||
intermediates: [][]constraintsSpec{
|
||||
[]constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
},
|
||||
leaf: leafSpec{
|
||||
sans: []string{"email:this @ is invalid"},
|
||||
},
|
||||
expectedError: "cannot parse rfc822Name",
|
||||
},
|
||||
|
||||
// #80: if several EKUs are requested, satisfying any of them is sufficient.
|
||||
nameConstraintsTest{
|
||||
roots: []constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
intermediates: [][]constraintsSpec{
|
||||
[]constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
},
|
||||
leaf: leafSpec{
|
||||
sans: []string{"dns:example.com"},
|
||||
ekus: []string{"email"},
|
||||
},
|
||||
requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageEmailProtection},
|
||||
},
|
||||
|
||||
// #81: EKUs that are not asserted in VerifyOpts are not required to be
|
||||
// nested.
|
||||
nameConstraintsTest{
|
||||
roots: []constraintsSpec{
|
||||
constraintsSpec{},
|
||||
},
|
||||
intermediates: [][]constraintsSpec{
|
||||
[]constraintsSpec{
|
||||
constraintsSpec{
|
||||
ekus: []string{"serverAuth"},
|
||||
},
|
||||
},
|
||||
},
|
||||
leaf: leafSpec{
|
||||
sans: []string{"dns:example.com"},
|
||||
// There's no email EKU in the intermediate. This would be rejected if
|
||||
// full nesting was required.
|
||||
ekus: []string{"email", "serverAuth"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
|
||||
@@ -1512,6 +1648,13 @@ func makeConstraintsLeafCert(leaf leafSpec, key *ecdsa.PrivateKey, parent *Certi
|
||||
}
|
||||
template.IPAddresses = append(template.IPAddresses, ip)
|
||||
|
||||
case strings.HasPrefix(name, "invalidip:"):
|
||||
ipBytes, err := hex.DecodeString(name[10:])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse invalid IP: %s", err)
|
||||
}
|
||||
template.IPAddresses = append(template.IPAddresses, net.IP(ipBytes))
|
||||
|
||||
case strings.HasPrefix(name, "email:"):
|
||||
template.EmailAddresses = append(template.EmailAddresses, name[6:])
|
||||
|
||||
@@ -1781,6 +1924,7 @@ func TestConstraintCases(t *testing.T) {
|
||||
Roots: rootPool,
|
||||
Intermediates: intermediatePool,
|
||||
CurrentTime: time.Unix(1500, 0),
|
||||
KeyUsages: test.requestedEKUs,
|
||||
}
|
||||
_, err = leafCert.Verify(verifyOpts)
|
||||
|
||||
@@ -1972,12 +2116,13 @@ func TestBadNamesInConstraints(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBadNamesInSANs(t *testing.T) {
|
||||
// Bad names in SANs should not parse.
|
||||
// Bad names in URI and IP SANs should not parse. Bad DNS and email SANs
|
||||
// will parse and are tested in name constraint tests at the top of this
|
||||
// file.
|
||||
badNames := []string{
|
||||
"dns:foo.com.",
|
||||
"email:abc@foo.com.",
|
||||
"email:foo.com.",
|
||||
"uri:https://example.com./dsf",
|
||||
"invalidip:0102",
|
||||
"invalidip:0102030405",
|
||||
}
|
||||
|
||||
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
|
||||
@@ -95,6 +95,12 @@ func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) e
|
||||
return nil
|
||||
}
|
||||
|
||||
type _CertChainPolicyPara struct {
|
||||
Size uint32
|
||||
Flags uint32
|
||||
ExtraPolicyPara unsafe.Pointer
|
||||
}
|
||||
|
||||
// checkChainSSLServerPolicy checks that the certificate chain in chainCtx is valid for
|
||||
// use as a certificate chain for a SSL/TLS server.
|
||||
func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error {
|
||||
@@ -108,13 +114,13 @@ func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContex
|
||||
}
|
||||
sslPara.Size = uint32(unsafe.Sizeof(*sslPara))
|
||||
|
||||
para := &syscall.CertChainPolicyPara{
|
||||
ExtraPolicyPara: uintptr(unsafe.Pointer(sslPara)),
|
||||
para := &_CertChainPolicyPara{
|
||||
ExtraPolicyPara: unsafe.Pointer(sslPara),
|
||||
}
|
||||
para.Size = uint32(unsafe.Sizeof(*para))
|
||||
|
||||
status := syscall.CertChainPolicyStatus{}
|
||||
err = syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status)
|
||||
err = syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, (*syscall.CertChainPolicyPara)(unsafe.Pointer(para)), &status)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -6,12 +6,14 @@ package x509
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
@@ -54,8 +56,7 @@ const (
|
||||
// CPU time to verify.
|
||||
TooManyConstraints
|
||||
// CANotAuthorizedForExtKeyUsage results when an intermediate or root
|
||||
// certificate does not permit an extended key usage that is claimed by
|
||||
// the leaf certificate.
|
||||
// certificate does not permit a requested extended key usage.
|
||||
CANotAuthorizedForExtKeyUsage
|
||||
)
|
||||
|
||||
@@ -80,7 +81,7 @@ func (e CertificateInvalidError) Error() string {
|
||||
case TooManyIntermediates:
|
||||
return "x509: too many intermediates for path length constraint"
|
||||
case IncompatibleUsage:
|
||||
return "x509: certificate specifies an incompatible key usage: " + e.Detail
|
||||
return "x509: certificate specifies an incompatible key usage"
|
||||
case NameMismatch:
|
||||
return "x509: issuer name does not match subject from issuing certificate"
|
||||
case NameConstraintsWithoutSANs:
|
||||
@@ -178,10 +179,13 @@ type VerifyOptions struct {
|
||||
Intermediates *CertPool
|
||||
Roots *CertPool // if nil, the system roots are used
|
||||
CurrentTime time.Time // if zero, the current time is used
|
||||
// KeyUsage specifies which Extended Key Usage values are acceptable.
|
||||
// An empty list means ExtKeyUsageServerAuth. Key usage is considered a
|
||||
// constraint down the chain which mirrors Windows CryptoAPI behavior,
|
||||
// but not the spec. To accept any key usage, include ExtKeyUsageAny.
|
||||
// KeyUsage specifies which Extended Key Usage values are acceptable. A leaf
|
||||
// certificate is accepted if it contains any of the listed values. An empty
|
||||
// list means ExtKeyUsageServerAuth. To accept any key usage, include
|
||||
// ExtKeyUsageAny.
|
||||
//
|
||||
// Certificate chains are required to nest these extended key usage values.
|
||||
// (This matches the Windows CryptoAPI behavior, but not the spec.)
|
||||
KeyUsages []ExtKeyUsage
|
||||
// MaxConstraintComparisions is the maximum number of comparisons to
|
||||
// perform when checking a given certificate's name constraints. If
|
||||
@@ -543,41 +547,6 @@ func (c *Certificate) checkNameConstraints(count *int,
|
||||
return nil
|
||||
}
|
||||
|
||||
// ekuPermittedBy returns true iff the given extended key usage is permitted by
|
||||
// the given EKU from a certificate. Normally, this would be a simple
|
||||
// comparison plus a special case for the “any” EKU. But, in order to support
|
||||
// existing certificates, some exceptions are made.
|
||||
func ekuPermittedBy(eku, certEKU ExtKeyUsage) bool {
|
||||
if certEKU == ExtKeyUsageAny || eku == certEKU {
|
||||
return true
|
||||
}
|
||||
|
||||
// Some exceptions are made to support existing certificates. Firstly,
|
||||
// the ServerAuth and SGC EKUs are treated as a group.
|
||||
mapServerAuthEKUs := func(eku ExtKeyUsage) ExtKeyUsage {
|
||||
if eku == ExtKeyUsageNetscapeServerGatedCrypto || eku == ExtKeyUsageMicrosoftServerGatedCrypto {
|
||||
return ExtKeyUsageServerAuth
|
||||
}
|
||||
return eku
|
||||
}
|
||||
|
||||
eku = mapServerAuthEKUs(eku)
|
||||
certEKU = mapServerAuthEKUs(certEKU)
|
||||
|
||||
if eku == certEKU ||
|
||||
// ServerAuth in a CA permits ClientAuth in the leaf.
|
||||
(eku == ExtKeyUsageClientAuth && certEKU == ExtKeyUsageServerAuth) ||
|
||||
// Any CA may issue an OCSP responder certificate.
|
||||
eku == ExtKeyUsageOCSPSigning ||
|
||||
// Code-signing CAs can use Microsoft's commercial and
|
||||
// kernel-mode EKUs.
|
||||
((eku == ExtKeyUsageMicrosoftCommercialCodeSigning || eku == ExtKeyUsageMicrosoftKernelCodeSigning) && certEKU == ExtKeyUsageCodeSigning) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// isValid performs validity checks on c given that it is a candidate to append
|
||||
// to the chain in currentChain.
|
||||
func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
|
||||
@@ -630,8 +599,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
|
||||
name := string(data)
|
||||
mailbox, ok := parseRFC2821Mailbox(name)
|
||||
if !ok {
|
||||
// This certificate should not have parsed.
|
||||
return errors.New("x509: internal error: rfc822Name SAN failed to parse")
|
||||
return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox)
|
||||
}
|
||||
|
||||
if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox,
|
||||
@@ -643,6 +611,10 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
|
||||
|
||||
case nameTypeDNS:
|
||||
name := string(data)
|
||||
if _, ok := domainToReverseLabels(name); !ok {
|
||||
return fmt.Errorf("x509: cannot parse dnsName %q", name)
|
||||
}
|
||||
|
||||
if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name,
|
||||
func(parsedName, constraint interface{}) (bool, error) {
|
||||
return matchDomainConstraint(parsedName.(string), constraint.(string))
|
||||
@@ -689,59 +661,6 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
|
||||
}
|
||||
}
|
||||
|
||||
checkEKUs := certType == intermediateCertificate
|
||||
|
||||
// If no extended key usages are specified, then all are acceptable.
|
||||
if checkEKUs && (len(c.ExtKeyUsage) == 0 && len(c.UnknownExtKeyUsage) == 0) {
|
||||
checkEKUs = false
|
||||
}
|
||||
|
||||
// If the “any” key usage is permitted, then no more checks are needed.
|
||||
if checkEKUs {
|
||||
for _, caEKU := range c.ExtKeyUsage {
|
||||
comparisonCount++
|
||||
if caEKU == ExtKeyUsageAny {
|
||||
checkEKUs = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if checkEKUs {
|
||||
NextEKU:
|
||||
for _, eku := range leaf.ExtKeyUsage {
|
||||
if comparisonCount > maxConstraintComparisons {
|
||||
return CertificateInvalidError{c, TooManyConstraints, ""}
|
||||
}
|
||||
|
||||
for _, caEKU := range c.ExtKeyUsage {
|
||||
comparisonCount++
|
||||
if ekuPermittedBy(eku, caEKU) {
|
||||
continue NextEKU
|
||||
}
|
||||
}
|
||||
|
||||
oid, _ := oidFromExtKeyUsage(eku)
|
||||
return CertificateInvalidError{c, CANotAuthorizedForExtKeyUsage, fmt.Sprintf("EKU not permitted: %#v", oid)}
|
||||
}
|
||||
|
||||
NextUnknownEKU:
|
||||
for _, eku := range leaf.UnknownExtKeyUsage {
|
||||
if comparisonCount > maxConstraintComparisons {
|
||||
return CertificateInvalidError{c, TooManyConstraints, ""}
|
||||
}
|
||||
|
||||
for _, caEKU := range c.UnknownExtKeyUsage {
|
||||
comparisonCount++
|
||||
if caEKU.Equal(eku) {
|
||||
continue NextUnknownEKU
|
||||
}
|
||||
}
|
||||
|
||||
return CertificateInvalidError{c, CANotAuthorizedForExtKeyUsage, fmt.Sprintf("EKU not permitted: %#v", eku)}
|
||||
}
|
||||
}
|
||||
|
||||
// KeyUsage status flags are ignored. From Engineering Security, Peter
|
||||
// Gutmann: A European government CA marked its signing certificates as
|
||||
// being valid for encryption only, but no-one noticed. Another
|
||||
@@ -773,6 +692,18 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
|
||||
return nil
|
||||
}
|
||||
|
||||
// formatOID formats an ASN.1 OBJECT IDENTIFER in the common, dotted style.
|
||||
func formatOID(oid asn1.ObjectIdentifier) string {
|
||||
ret := ""
|
||||
for i, v := range oid {
|
||||
if i > 0 {
|
||||
ret += "."
|
||||
}
|
||||
ret += strconv.Itoa(v)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Verify attempts to verify c by building one or more chains from c to a
|
||||
// certificate in opts.Roots, using certificates in opts.Intermediates if
|
||||
// needed. If successful, it returns one or more chains where the first
|
||||
@@ -830,36 +761,6 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
|
||||
}
|
||||
}
|
||||
|
||||
requestedKeyUsages := make([]ExtKeyUsage, len(opts.KeyUsages))
|
||||
copy(requestedKeyUsages, opts.KeyUsages)
|
||||
if len(requestedKeyUsages) == 0 {
|
||||
requestedKeyUsages = append(requestedKeyUsages, ExtKeyUsageServerAuth)
|
||||
}
|
||||
|
||||
// If no key usages are specified, then any are acceptable.
|
||||
checkEKU := len(c.ExtKeyUsage) > 0
|
||||
|
||||
for _, eku := range requestedKeyUsages {
|
||||
if eku == ExtKeyUsageAny {
|
||||
checkEKU = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if checkEKU {
|
||||
NextUsage:
|
||||
for _, eku := range requestedKeyUsages {
|
||||
for _, leafEKU := range c.ExtKeyUsage {
|
||||
if ekuPermittedBy(eku, leafEKU) {
|
||||
continue NextUsage
|
||||
}
|
||||
}
|
||||
|
||||
oid, _ := oidFromExtKeyUsage(eku)
|
||||
return nil, CertificateInvalidError{c, IncompatibleUsage, fmt.Sprintf("%#v", oid)}
|
||||
}
|
||||
}
|
||||
|
||||
var candidateChains [][]*Certificate
|
||||
if opts.Roots.contains(c) {
|
||||
candidateChains = append(candidateChains, []*Certificate{c})
|
||||
@@ -869,7 +770,29 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
|
||||
}
|
||||
}
|
||||
|
||||
return candidateChains, nil
|
||||
keyUsages := opts.KeyUsages
|
||||
if len(keyUsages) == 0 {
|
||||
keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
|
||||
}
|
||||
|
||||
// If any key usage is acceptable then we're done.
|
||||
for _, usage := range keyUsages {
|
||||
if usage == ExtKeyUsageAny {
|
||||
return candidateChains, nil
|
||||
}
|
||||
}
|
||||
|
||||
for _, candidate := range candidateChains {
|
||||
if checkChainForKeyUsage(candidate, keyUsages) {
|
||||
chains = append(chains, candidate)
|
||||
}
|
||||
}
|
||||
|
||||
if len(chains) == 0 {
|
||||
return nil, CertificateInvalidError{c, IncompatibleUsage, ""}
|
||||
}
|
||||
|
||||
return chains, nil
|
||||
}
|
||||
|
||||
func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
|
||||
@@ -1030,3 +953,65 @@ func (c *Certificate) VerifyHostname(h string) error {
|
||||
|
||||
return HostnameError{c, h}
|
||||
}
|
||||
|
||||
func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
|
||||
usages := make([]ExtKeyUsage, len(keyUsages))
|
||||
copy(usages, keyUsages)
|
||||
|
||||
if len(chain) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
usagesRemaining := len(usages)
|
||||
|
||||
// We walk down the list and cross out any usages that aren't supported
|
||||
// by each certificate. If we cross out all the usages, then the chain
|
||||
// is unacceptable.
|
||||
|
||||
NextCert:
|
||||
for i := len(chain) - 1; i >= 0; i-- {
|
||||
cert := chain[i]
|
||||
if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
|
||||
// The certificate doesn't have any extended key usage specified.
|
||||
continue
|
||||
}
|
||||
|
||||
for _, usage := range cert.ExtKeyUsage {
|
||||
if usage == ExtKeyUsageAny {
|
||||
// The certificate is explicitly good for any usage.
|
||||
continue NextCert
|
||||
}
|
||||
}
|
||||
|
||||
const invalidUsage ExtKeyUsage = -1
|
||||
|
||||
NextRequestedUsage:
|
||||
for i, requestedUsage := range usages {
|
||||
if requestedUsage == invalidUsage {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, usage := range cert.ExtKeyUsage {
|
||||
if requestedUsage == usage {
|
||||
continue NextRequestedUsage
|
||||
} else if requestedUsage == ExtKeyUsageServerAuth &&
|
||||
(usage == ExtKeyUsageNetscapeServerGatedCrypto ||
|
||||
usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
|
||||
// In order to support COMODO
|
||||
// certificate chains, we have to
|
||||
// accept Netscape or Microsoft SGC
|
||||
// usages as equal to ServerAuth.
|
||||
continue NextRequestedUsage
|
||||
}
|
||||
}
|
||||
|
||||
usages[i] = invalidUsage
|
||||
usagesRemaining--
|
||||
if usagesRemaining == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -706,7 +706,9 @@ type Certificate struct {
|
||||
OCSPServer []string
|
||||
IssuingCertificateURL []string
|
||||
|
||||
// Subject Alternate Name values
|
||||
// Subject Alternate Name values. (Note that these values may not be valid
|
||||
// if invalid values were contained within a parsed certificate. For
|
||||
// example, an element of DNSNames may not be a valid DNS domain name.)
|
||||
DNSNames []string
|
||||
EmailAddresses []string
|
||||
IPAddresses []net.IP
|
||||
@@ -1126,17 +1128,9 @@ func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddre
|
||||
err = forEachSAN(value, func(tag int, data []byte) error {
|
||||
switch tag {
|
||||
case nameTypeEmail:
|
||||
mailbox := string(data)
|
||||
if _, ok := parseRFC2821Mailbox(mailbox); !ok {
|
||||
return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox)
|
||||
}
|
||||
emailAddresses = append(emailAddresses, mailbox)
|
||||
emailAddresses = append(emailAddresses, string(data))
|
||||
case nameTypeDNS:
|
||||
domain := string(data)
|
||||
if _, ok := domainToReverseLabels(domain); !ok {
|
||||
return fmt.Errorf("x509: cannot parse dnsName %q", string(data))
|
||||
}
|
||||
dnsNames = append(dnsNames, domain)
|
||||
dnsNames = append(dnsNames, string(data))
|
||||
case nameTypeURI:
|
||||
uri, err := url.Parse(string(data))
|
||||
if err != nil {
|
||||
@@ -1153,7 +1147,7 @@ func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddre
|
||||
case net.IPv4len, net.IPv6len:
|
||||
ipAddresses = append(ipAddresses, data)
|
||||
default:
|
||||
return errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(data)))
|
||||
return errors.New("x509: cannot parse IP address of length " + strconv.Itoa(len(data)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -443,10 +443,25 @@ func (d *decodeState) valueQuoted() interface{} {
|
||||
// if it encounters an Unmarshaler, indirect stops and returns that.
|
||||
// if decodingNull is true, indirect stops at the last pointer so it can be set to nil.
|
||||
func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) {
|
||||
// Issue #24153 indicates that it is generally not a guaranteed property
|
||||
// that you may round-trip a reflect.Value by calling Value.Addr().Elem()
|
||||
// and expect the value to still be settable for values derived from
|
||||
// unexported embedded struct fields.
|
||||
//
|
||||
// The logic below effectively does this when it first addresses the value
|
||||
// (to satisfy possible pointer methods) and continues to dereference
|
||||
// subsequent pointers as necessary.
|
||||
//
|
||||
// After the first round-trip, we set v back to the original value to
|
||||
// preserve the original RW flags contained in reflect.Value.
|
||||
v0 := v
|
||||
haveAddr := false
|
||||
|
||||
// If v is a named type and is addressable,
|
||||
// start with its address, so that if the type has pointer methods,
|
||||
// we find them.
|
||||
if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
|
||||
haveAddr = true
|
||||
v = v.Addr()
|
||||
}
|
||||
for {
|
||||
@@ -455,6 +470,7 @@ func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler,
|
||||
if v.Kind() == reflect.Interface && !v.IsNil() {
|
||||
e := v.Elem()
|
||||
if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
|
||||
haveAddr = false
|
||||
v = e
|
||||
continue
|
||||
}
|
||||
@@ -480,7 +496,13 @@ func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler,
|
||||
}
|
||||
}
|
||||
}
|
||||
v = v.Elem()
|
||||
|
||||
if haveAddr {
|
||||
v = v0 // restore original value after round-trip Value.Addr().Elem()
|
||||
haveAddr = false
|
||||
} else {
|
||||
v = v.Elem()
|
||||
}
|
||||
}
|
||||
return nil, nil, v
|
||||
}
|
||||
|
||||
@@ -2089,10 +2089,14 @@ func TestInvalidStringOption(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test unmarshal behavior with regards to embedded pointers to unexported structs.
|
||||
// If unallocated, this returns an error because unmarshal cannot set the field.
|
||||
// Issue 21357.
|
||||
func TestUnmarshalEmbeddedPointerUnexported(t *testing.T) {
|
||||
// Test unmarshal behavior with regards to embedded unexported structs.
|
||||
//
|
||||
// (Issue 21357) If the embedded struct is a pointer and is unallocated,
|
||||
// this returns an error because unmarshal cannot set the field.
|
||||
//
|
||||
// (Issue 24152) If the embedded struct is given an explicit name,
|
||||
// ensure that the normal unmarshal logic does not panic in reflect.
|
||||
func TestUnmarshalEmbeddedUnexported(t *testing.T) {
|
||||
type (
|
||||
embed1 struct{ Q int }
|
||||
embed2 struct{ Q int }
|
||||
@@ -2119,6 +2123,18 @@ func TestUnmarshalEmbeddedPointerUnexported(t *testing.T) {
|
||||
*embed3
|
||||
R int
|
||||
}
|
||||
S6 struct {
|
||||
embed1 `json:"embed1"`
|
||||
}
|
||||
S7 struct {
|
||||
embed1 `json:"embed1"`
|
||||
embed2
|
||||
}
|
||||
S8 struct {
|
||||
embed1 `json:"embed1"`
|
||||
embed2 `json:"embed2"`
|
||||
Q int
|
||||
}
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
@@ -2154,6 +2170,32 @@ func TestUnmarshalEmbeddedPointerUnexported(t *testing.T) {
|
||||
ptr: new(S5),
|
||||
out: &S5{R: 2},
|
||||
err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed3"),
|
||||
}, {
|
||||
// Issue 24152, ensure decodeState.indirect does not panic.
|
||||
in: `{"embed1": {"Q": 1}}`,
|
||||
ptr: new(S6),
|
||||
out: &S6{embed1{1}},
|
||||
}, {
|
||||
// Issue 24153, check that we can still set forwarded fields even in
|
||||
// the presence of a name conflict.
|
||||
//
|
||||
// This relies on obscure behavior of reflect where it is possible
|
||||
// to set a forwarded exported field on an unexported embedded struct
|
||||
// even though there is a name conflict, even when it would have been
|
||||
// impossible to do so according to Go visibility rules.
|
||||
// Go forbids this because it is ambiguous whether S7.Q refers to
|
||||
// S7.embed1.Q or S7.embed2.Q. Since embed1 and embed2 are unexported,
|
||||
// it should be impossible for an external package to set either Q.
|
||||
//
|
||||
// It is probably okay for a future reflect change to break this.
|
||||
in: `{"embed1": {"Q": 1}, "Q": 2}`,
|
||||
ptr: new(S7),
|
||||
out: &S7{embed1{1}, embed2{2}},
|
||||
}, {
|
||||
// Issue 24153, similar to the S7 case.
|
||||
in: `{"embed1": {"Q": 1}, "embed2": {"Q": 2}, "Q": 3}`,
|
||||
ptr: new(S8),
|
||||
out: &S8{embed1{1}, embed2{2}, 3},
|
||||
}}
|
||||
|
||||
for i, tt := range tests {
|
||||
|
||||
@@ -44,9 +44,9 @@ func New(ctxt *build.Context, fset *token.FileSet, packages map[string]*types.Pa
|
||||
// for a package that is in the process of being imported.
|
||||
var importing types.Package
|
||||
|
||||
// Import(path) is a shortcut for ImportFrom(path, "", 0).
|
||||
// Import(path) is a shortcut for ImportFrom(path, ".", 0).
|
||||
func (p *Importer) Import(path string) (*types.Package, error) {
|
||||
return p.ImportFrom(path, "", 0)
|
||||
return p.ImportFrom(path, ".", 0) // use "." rather than "" (see issue #24441)
|
||||
}
|
||||
|
||||
// ImportFrom imports the package with the given import path resolved from the given srcDir,
|
||||
@@ -60,23 +60,10 @@ func (p *Importer) ImportFrom(path, srcDir string, mode types.ImportMode) (*type
|
||||
panic("non-zero import mode")
|
||||
}
|
||||
|
||||
// determine package path (do vendor resolution)
|
||||
var bp *build.Package
|
||||
var err error
|
||||
switch {
|
||||
default:
|
||||
if abs, err := p.absPath(srcDir); err == nil { // see issue #14282
|
||||
srcDir = abs
|
||||
}
|
||||
bp, err = p.ctxt.Import(path, srcDir, build.FindOnly)
|
||||
|
||||
case build.IsLocalImport(path):
|
||||
// "./x" -> "srcDir/x"
|
||||
bp, err = p.ctxt.ImportDir(filepath.Join(srcDir, path), build.FindOnly)
|
||||
|
||||
case p.isAbsPath(path):
|
||||
return nil, fmt.Errorf("invalid absolute import path %q", path)
|
||||
if abs, err := p.absPath(srcDir); err == nil { // see issue #14282
|
||||
srcDir = abs
|
||||
}
|
||||
bp, err := p.ctxt.Import(path, srcDir, 0)
|
||||
if err != nil {
|
||||
return nil, err // err may be *build.NoGoError - return as is
|
||||
}
|
||||
@@ -113,11 +100,6 @@ func (p *Importer) ImportFrom(path, srcDir string, mode types.ImportMode) (*type
|
||||
}
|
||||
}()
|
||||
|
||||
// collect package files
|
||||
bp, err = p.ctxt.ImportDir(bp.Dir, 0)
|
||||
if err != nil {
|
||||
return nil, err // err may be *build.NoGoError - return as is
|
||||
}
|
||||
var filenames []string
|
||||
filenames = append(filenames, bp.GoFiles...)
|
||||
filenames = append(filenames, bp.CgoFiles...)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"go/types"
|
||||
"internal/testenv"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
@@ -162,3 +163,34 @@ func TestIssue20855(t *testing.T) {
|
||||
t.Error("got no package despite no hard errors")
|
||||
}
|
||||
}
|
||||
|
||||
func testImportPath(t *testing.T, pkgPath string) {
|
||||
if !testenv.HasSrc() {
|
||||
t.Skip("no source code available")
|
||||
}
|
||||
|
||||
pkgName := path.Base(pkgPath)
|
||||
|
||||
pkg, err := importer.Import(pkgPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if pkg.Name() != pkgName {
|
||||
t.Errorf("got %q; want %q", pkg.Name(), pkgName)
|
||||
}
|
||||
|
||||
if pkg.Path() != pkgPath {
|
||||
t.Errorf("got %q; want %q", pkg.Path(), pkgPath)
|
||||
}
|
||||
}
|
||||
|
||||
// TestIssue23092 tests relative imports.
|
||||
func TestIssue23092(t *testing.T) {
|
||||
testImportPath(t, "./testdata/issue23092")
|
||||
}
|
||||
|
||||
// TestIssue24392 tests imports against a path containing 'testdata'.
|
||||
func TestIssue24392(t *testing.T) {
|
||||
testImportPath(t, "go/internal/srcimporter/testdata/issue24392")
|
||||
}
|
||||
|
||||
5
src/go/internal/srcimporter/testdata/issue23092/issue23092.go
vendored
Normal file
5
src/go/internal/srcimporter/testdata/issue23092/issue23092.go
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package issue23092
|
||||
5
src/go/internal/srcimporter/testdata/issue24392/issue24392.go
vendored
Normal file
5
src/go/internal/srcimporter/testdata/issue24392/issue24392.go
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package issue24392
|
||||
@@ -103,11 +103,21 @@ func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) {
|
||||
g.mu.Unlock()
|
||||
}
|
||||
|
||||
// Forget tells the singleflight to forget about a key. Future calls
|
||||
// to Do for this key will call the function rather than waiting for
|
||||
// an earlier call to complete.
|
||||
func (g *Group) Forget(key string) {
|
||||
// ForgetUnshared tells the singleflight to forget about a key if it is not
|
||||
// shared with any other goroutines. Future calls to Do for a forgotten key
|
||||
// will call the function rather than waiting for an earlier call to complete.
|
||||
// Returns whether the key was forgotten or unknown--that is, whether no
|
||||
// other goroutines are waiting for the result.
|
||||
func (g *Group) ForgetUnshared(key string) bool {
|
||||
g.mu.Lock()
|
||||
delete(g.m, key)
|
||||
g.mu.Unlock()
|
||||
defer g.mu.Unlock()
|
||||
c, ok := g.m[key]
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
if c.dups == 0 {
|
||||
delete(g.m, key)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ func init() {
|
||||
// command line, with arguments separated by NUL bytes.
|
||||
// The package initialization registers it as /debug/pprof/cmdline.
|
||||
func Cmdline(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
|
||||
}
|
||||
@@ -100,33 +101,36 @@ func durationExceedsWriteTimeout(r *http.Request, seconds float64) bool {
|
||||
return ok && srv.WriteTimeout != 0 && seconds >= srv.WriteTimeout.Seconds()
|
||||
}
|
||||
|
||||
func serveError(w http.ResponseWriter, status int, txt string) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Go-Pprof", "1")
|
||||
w.Header().Del("Content-Disposition")
|
||||
w.WriteHeader(status)
|
||||
fmt.Fprintln(w, txt)
|
||||
}
|
||||
|
||||
// Profile responds with the pprof-formatted cpu profile.
|
||||
// The package initialization registers it as /debug/pprof/profile.
|
||||
func Profile(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64)
|
||||
if sec == 0 {
|
||||
sec = 30
|
||||
}
|
||||
|
||||
if durationExceedsWriteTimeout(r, float64(sec)) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Go-Pprof", "1")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
fmt.Fprintln(w, "profile duration exceeds server's WriteTimeout")
|
||||
serveError(w, http.StatusBadRequest, "profile duration exceeds server's WriteTimeout")
|
||||
return
|
||||
}
|
||||
|
||||
// Set Content Type assuming StartCPUProfile will work,
|
||||
// because if it does it starts writing.
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.Header().Set("Content-Disposition", `attachment; filename="profile"`)
|
||||
if err := pprof.StartCPUProfile(w); err != nil {
|
||||
// StartCPUProfile failed, so no writes yet.
|
||||
// Can change header back to text content
|
||||
// and send error code.
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Go-Pprof", "1")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
|
||||
serveError(w, http.StatusInternalServerError,
|
||||
fmt.Sprintf("Could not enable CPU profiling: %s", err))
|
||||
return
|
||||
}
|
||||
sleep(w, time.Duration(sec)*time.Second)
|
||||
@@ -137,29 +141,25 @@ func Profile(w http.ResponseWriter, r *http.Request) {
|
||||
// Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified.
|
||||
// The package initialization registers it as /debug/pprof/trace.
|
||||
func Trace(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
sec, err := strconv.ParseFloat(r.FormValue("seconds"), 64)
|
||||
if sec <= 0 || err != nil {
|
||||
sec = 1
|
||||
}
|
||||
|
||||
if durationExceedsWriteTimeout(r, sec) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Go-Pprof", "1")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
fmt.Fprintln(w, "profile duration exceeds server's WriteTimeout")
|
||||
serveError(w, http.StatusBadRequest, "profile duration exceeds server's WriteTimeout")
|
||||
return
|
||||
}
|
||||
|
||||
// Set Content Type assuming trace.Start will work,
|
||||
// because if it does it starts writing.
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.Header().Set("Content-Disposition", `attachment; filename="trace"`)
|
||||
if err := trace.Start(w); err != nil {
|
||||
// trace.Start failed, so no writes yet.
|
||||
// Can change header back to text content and send error code.
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Go-Pprof", "1")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
fmt.Fprintf(w, "Could not enable tracing: %s\n", err)
|
||||
serveError(w, http.StatusInternalServerError,
|
||||
fmt.Sprintf("Could not enable tracing: %s", err))
|
||||
return
|
||||
}
|
||||
sleep(w, time.Duration(sec*float64(time.Second)))
|
||||
@@ -170,6 +170,7 @@ func Trace(w http.ResponseWriter, r *http.Request) {
|
||||
// responding with a table mapping program counters to function names.
|
||||
// The package initialization registers it as /debug/pprof/symbol.
|
||||
func Symbol(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
|
||||
// We have to read the whole POST body before
|
||||
@@ -222,18 +223,23 @@ func Handler(name string) http.Handler {
|
||||
type handler string
|
||||
|
||||
func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
debug, _ := strconv.Atoi(r.FormValue("debug"))
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
p := pprof.Lookup(string(name))
|
||||
if p == nil {
|
||||
w.WriteHeader(404)
|
||||
fmt.Fprintf(w, "Unknown profile: %s\n", name)
|
||||
serveError(w, http.StatusNotFound, "Unknown profile")
|
||||
return
|
||||
}
|
||||
gc, _ := strconv.Atoi(r.FormValue("gc"))
|
||||
if name == "heap" && gc > 0 {
|
||||
runtime.GC()
|
||||
}
|
||||
debug, _ := strconv.Atoi(r.FormValue("debug"))
|
||||
if debug != 0 {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name))
|
||||
}
|
||||
p.WriteTo(w, debug)
|
||||
}
|
||||
|
||||
|
||||
69
src/net/http/pprof/pprof_test.go
Normal file
69
src/net/http/pprof/pprof_test.go
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package pprof
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHandlers(t *testing.T) {
|
||||
testCases := []struct {
|
||||
path string
|
||||
handler http.HandlerFunc
|
||||
statusCode int
|
||||
contentType string
|
||||
contentDisposition string
|
||||
resp []byte
|
||||
}{
|
||||
{"/debug/pprof/<script>scripty<script>", Index, http.StatusNotFound, "text/plain; charset=utf-8", "", []byte("Unknown profile\n")},
|
||||
{"/debug/pprof/heap", Index, http.StatusOK, "application/octet-stream", `attachment; filename="heap"`, nil},
|
||||
{"/debug/pprof/heap?debug=1", Index, http.StatusOK, "text/plain; charset=utf-8", "", nil},
|
||||
{"/debug/pprof/cmdline", Cmdline, http.StatusOK, "text/plain; charset=utf-8", "", nil},
|
||||
{"/debug/pprof/profile?seconds=1", Profile, http.StatusOK, "application/octet-stream", `attachment; filename="profile"`, nil},
|
||||
{"/debug/pprof/symbol", Symbol, http.StatusOK, "text/plain; charset=utf-8", "", nil},
|
||||
{"/debug/pprof/trace", Trace, http.StatusOK, "application/octet-stream", `attachment; filename="trace"`, nil},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.path, func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "http://example.com"+tc.path, nil)
|
||||
w := httptest.NewRecorder()
|
||||
tc.handler(w, req)
|
||||
|
||||
resp := w.Result()
|
||||
if got, want := resp.StatusCode, tc.statusCode; got != want {
|
||||
t.Errorf("status code: got %d; want %d", got, want)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Errorf("when reading response body, expected non-nil err; got %v", err)
|
||||
}
|
||||
if got, want := resp.Header.Get("X-Content-Type-Options"), "nosniff"; got != want {
|
||||
t.Errorf("X-Content-Type-Options: got %q; want %q", got, want)
|
||||
}
|
||||
if got, want := resp.Header.Get("Content-Type"), tc.contentType; got != want {
|
||||
t.Errorf("Content-Type: got %q; want %q", got, want)
|
||||
}
|
||||
if got, want := resp.Header.Get("Content-Disposition"), tc.contentDisposition; got != want {
|
||||
t.Errorf("Content-Disposition: got %q; want %q", got, want)
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
return
|
||||
}
|
||||
if got, want := resp.Header.Get("X-Go-Pprof"), "1"; got != want {
|
||||
t.Errorf("X-Go-Pprof: got %q; want %q", got, want)
|
||||
}
|
||||
if !bytes.Equal(body, tc.resp) {
|
||||
t.Errorf("response: got %q; want %q", body, tc.resp)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -194,10 +194,16 @@ func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, err
|
||||
resolverFunc = alt
|
||||
}
|
||||
|
||||
// We don't want a cancelation of ctx to affect the
|
||||
// lookupGroup operation. Otherwise if our context gets
|
||||
// canceled it might cause an error to be returned to a lookup
|
||||
// using a completely different context.
|
||||
lookupGroupCtx, lookupGroupCancel := context.WithCancel(context.Background())
|
||||
|
||||
dnsWaitGroup.Add(1)
|
||||
ch, called := lookupGroup.DoChan(host, func() (interface{}, error) {
|
||||
defer dnsWaitGroup.Done()
|
||||
return testHookLookupIP(ctx, resolverFunc, host)
|
||||
return testHookLookupIP(lookupGroupCtx, resolverFunc, host)
|
||||
})
|
||||
if !called {
|
||||
dnsWaitGroup.Done()
|
||||
@@ -205,20 +211,28 @@ func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, err
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// If the DNS lookup timed out for some reason, force
|
||||
// future requests to start the DNS lookup again
|
||||
// rather than waiting for the current lookup to
|
||||
// complete. See issue 8602.
|
||||
ctxErr := ctx.Err()
|
||||
if ctxErr == context.DeadlineExceeded {
|
||||
lookupGroup.Forget(host)
|
||||
// Our context was canceled. If we are the only
|
||||
// goroutine looking up this key, then drop the key
|
||||
// from the lookupGroup and cancel the lookup.
|
||||
// If there are other goroutines looking up this key,
|
||||
// let the lookup continue uncanceled, and let later
|
||||
// lookups with the same key share the result.
|
||||
// See issues 8602, 20703, 22724.
|
||||
if lookupGroup.ForgetUnshared(host) {
|
||||
lookupGroupCancel()
|
||||
} else {
|
||||
go func() {
|
||||
<-ch
|
||||
lookupGroupCancel()
|
||||
}()
|
||||
}
|
||||
err := mapErr(ctxErr)
|
||||
err := mapErr(ctx.Err())
|
||||
if trace != nil && trace.DNSDone != nil {
|
||||
trace.DNSDone(nil, false, err)
|
||||
}
|
||||
return nil, err
|
||||
case r := <-ch:
|
||||
lookupGroupCancel()
|
||||
if trace != nil && trace.DNSDone != nil {
|
||||
addrs, _ := r.Val.([]IPAddr)
|
||||
trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err)
|
||||
|
||||
@@ -791,3 +791,28 @@ func TestLookupNonLDH(t *testing.T) {
|
||||
t.Fatalf("lookup error = %v, want %v", err, errNoSuchHost)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLookupContextCancel(t *testing.T) {
|
||||
if testenv.Builder() == "" {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
}
|
||||
if runtime.GOOS == "nacl" {
|
||||
t.Skip("skip on nacl")
|
||||
}
|
||||
|
||||
defer dnsWaitGroup.Wait()
|
||||
|
||||
ctx, ctxCancel := context.WithCancel(context.Background())
|
||||
ctxCancel()
|
||||
_, err := DefaultResolver.LookupIPAddr(ctx, "google.com")
|
||||
if err != errCanceled {
|
||||
testenv.SkipFlakyNet(t)
|
||||
t.Fatal(err)
|
||||
}
|
||||
ctx = context.Background()
|
||||
_, err = DefaultResolver.LookupIPAddr(ctx, "google.com")
|
||||
if err != nil {
|
||||
testenv.SkipFlakyNet(t)
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@ func TestTCPSpuriousConnSetupCompletionWithCancel(t *testing.T) {
|
||||
if testenv.Builder() == "" {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
}
|
||||
defer dnsWaitGroup.Wait()
|
||||
t.Parallel()
|
||||
const tries = 10000
|
||||
var wg sync.WaitGroup
|
||||
|
||||
@@ -73,14 +73,12 @@ func typestring(x interface{}) string {
|
||||
}
|
||||
|
||||
// printany prints an argument passed to panic.
|
||||
// If panic is called with a value that has a String or Error method,
|
||||
// it has already been converted into a string by preprintpanics.
|
||||
func printany(i interface{}) {
|
||||
switch v := i.(type) {
|
||||
case nil:
|
||||
print("nil")
|
||||
case stringer:
|
||||
print(v.String())
|
||||
case error:
|
||||
print(v.Error())
|
||||
case bool:
|
||||
print(v)
|
||||
case int:
|
||||
|
||||
@@ -113,6 +113,14 @@ func (t *itabTableType) find(inter *interfacetype, typ *_type) *itab {
|
||||
// itabAdd adds the given itab to the itab hash table.
|
||||
// itabLock must be held.
|
||||
func itabAdd(m *itab) {
|
||||
// Bugs can lead to calling this while mallocing is set,
|
||||
// typically because this is called while panicing.
|
||||
// Crash reliably, rather than only when we need to grow
|
||||
// the hash table.
|
||||
if getg().m.mallocing != 0 {
|
||||
throw("malloc deadlock")
|
||||
}
|
||||
|
||||
t := itabTable
|
||||
if t.count >= 3*(t.size/4) { // 75% load factor
|
||||
// Grow hash table.
|
||||
|
||||
@@ -304,8 +304,6 @@ func osinit() {
|
||||
|
||||
disableWER()
|
||||
|
||||
externalthreadhandlerp = funcPC(externalthreadhandler)
|
||||
|
||||
initExceptionHandler()
|
||||
|
||||
stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
|
||||
|
||||
@@ -389,7 +389,6 @@ func Goexit() {
|
||||
|
||||
// Call all Error and String methods before freezing the world.
|
||||
// Used when crashing with panicking.
|
||||
// This must match types handled by printany.
|
||||
func preprintpanics(p *_panic) {
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
@@ -415,8 +414,6 @@ func printpanics(p *_panic) {
|
||||
print("\t")
|
||||
}
|
||||
print("panic: ")
|
||||
// Because of preprintpanics, p.arg cannot be an error or
|
||||
// stringer, so this won't call into user code.
|
||||
printany(p.arg)
|
||||
if p.recovered {
|
||||
print(" [recovered]")
|
||||
|
||||
@@ -393,6 +393,11 @@ func releaseSudog(s *sudog) {
|
||||
|
||||
// funcPC returns the entry PC of the function f.
|
||||
// It assumes that f is a func value. Otherwise the behavior is undefined.
|
||||
// CAREFUL: In programs with plugins, funcPC can return different values
|
||||
// for the same function (because there are actually multiple copies of
|
||||
// the same function in the address space). To be safe, don't use the
|
||||
// results of this function in any == expression. It is only safe to
|
||||
// use the result as an address at which to start executing code.
|
||||
//go:nosplit
|
||||
func funcPC(f interface{}) uintptr {
|
||||
return **(**uintptr)(add(unsafe.Pointer(&f), sys.PtrSize))
|
||||
@@ -3798,8 +3803,8 @@ func setsSP(pc uintptr) bool {
|
||||
// so assume the worst and stop traceback
|
||||
return true
|
||||
}
|
||||
switch f.entry {
|
||||
case gogoPC, systemstackPC, mcallPC, morestackPC:
|
||||
switch f.funcID {
|
||||
case funcID_gogo, funcID_systemstack, funcID_mcall, funcID_morestack:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -635,8 +635,8 @@ type _func struct {
|
||||
entry uintptr // start pc
|
||||
nameoff int32 // function name
|
||||
|
||||
args int32 // in/out args size
|
||||
_ int32 // previously legacy frame size; kept for layout compatibility
|
||||
args int32 // in/out args size
|
||||
funcID funcID // set for certain special runtime functions
|
||||
|
||||
pcsp int32
|
||||
pcfile int32
|
||||
|
||||
@@ -619,7 +619,7 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
|
||||
if stackDebug >= 2 {
|
||||
print(" adjusting ", funcname(f), " frame=[", hex(frame.sp), ",", hex(frame.fp), "] pc=", hex(frame.pc), " continpc=", hex(frame.continpc), "\n")
|
||||
}
|
||||
if f.entry == systemstack_switchPC {
|
||||
if f.funcID == funcID_systemstack_switch {
|
||||
// A special routine at the bottom of stack of a goroutine that does an systemstack call.
|
||||
// We will allow it to be copied even though we don't
|
||||
// have full GC info for it (because it is written in asm).
|
||||
@@ -1110,7 +1110,8 @@ func shrinkstack(gp *g) {
|
||||
if debug.gcshrinkstackoff > 0 {
|
||||
return
|
||||
}
|
||||
if gp.startpc == gcBgMarkWorkerPC {
|
||||
f := findfunc(gp.startpc)
|
||||
if f.valid() && f.funcID == funcID_gcBgMarkWorker {
|
||||
// We're not allowed to shrink the gcBgMarkWorker
|
||||
// stack (see gcBgMarkWorker for explanation).
|
||||
return
|
||||
|
||||
@@ -133,7 +133,7 @@ again:
|
||||
}
|
||||
se.pcExpander.init(ncallers[0], se.wasPanic)
|
||||
ncallers = ncallers[1:]
|
||||
se.wasPanic = se.pcExpander.funcInfo.valid() && se.pcExpander.funcInfo.entry == sigpanicPC
|
||||
se.wasPanic = se.pcExpander.funcInfo.valid() && se.pcExpander.funcInfo.funcID == funcID_sigpanic
|
||||
if se.skip > 0 {
|
||||
for ; se.skip > 0; se.skip-- {
|
||||
se.pcExpander.next()
|
||||
@@ -349,6 +349,35 @@ const (
|
||||
_ArgsSizeUnknown = -0x80000000
|
||||
)
|
||||
|
||||
// A FuncID identifies particular functions that need to be treated
|
||||
// specially by the runtime.
|
||||
// Note that in some situations involving plugins, there may be multiple
|
||||
// copies of a particular special runtime function.
|
||||
// Note: this list must match the list in cmd/internal/objabi/funcid.go.
|
||||
type funcID uint32
|
||||
|
||||
const (
|
||||
funcID_normal funcID = iota // not a special function
|
||||
funcID_goexit
|
||||
funcID_jmpdefer
|
||||
funcID_mcall
|
||||
funcID_morestack
|
||||
funcID_mstart
|
||||
funcID_rt0_go
|
||||
funcID_asmcgocall
|
||||
funcID_sigpanic
|
||||
funcID_runfinq
|
||||
funcID_bgsweep
|
||||
funcID_forcegchelper
|
||||
funcID_timerproc
|
||||
funcID_gcBgMarkWorker
|
||||
funcID_systemstack_switch
|
||||
funcID_systemstack
|
||||
funcID_cgocallback_gofunc
|
||||
funcID_gogo
|
||||
funcID_externalthreadhandler
|
||||
)
|
||||
|
||||
// moduledata records information about the layout of the executable
|
||||
// image. It is written by the linker. Any changes here must be
|
||||
// matched changes to the code in cmd/internal/ld/symtab.go:symtab.
|
||||
@@ -648,7 +677,6 @@ func findfunc(pc uintptr) funcInfo {
|
||||
idx = uint32(len(datap.ftab) - 1)
|
||||
}
|
||||
if pc < datap.ftab[idx].entry {
|
||||
|
||||
// With multiple text sections, the idx might reference a function address that
|
||||
// is higher than the pc being searched, so search backward until the matching address is found.
|
||||
|
||||
@@ -659,7 +687,6 @@ func findfunc(pc uintptr) funcInfo {
|
||||
throw("findfunc: bad findfunctab entry idx")
|
||||
}
|
||||
} else {
|
||||
|
||||
// linear search to find func with pc >= entry.
|
||||
for datap.ftab[idx+1].entry <= pc {
|
||||
idx++
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
#include "go_tls.h"
|
||||
#include "textflag.h"
|
||||
|
||||
#define AT_FDCWD -100
|
||||
|
||||
#define SYS_read 0
|
||||
#define SYS_write 1
|
||||
#define SYS_open 2
|
||||
#define SYS_close 3
|
||||
#define SYS_mmap 9
|
||||
#define SYS_munmap 11
|
||||
@@ -20,7 +21,6 @@
|
||||
#define SYS_rt_sigaction 13
|
||||
#define SYS_rt_sigprocmask 14
|
||||
#define SYS_rt_sigreturn 15
|
||||
#define SYS_access 21
|
||||
#define SYS_sched_yield 24
|
||||
#define SYS_mincore 27
|
||||
#define SYS_madvise 28
|
||||
@@ -41,9 +41,11 @@
|
||||
#define SYS_sched_getaffinity 204
|
||||
#define SYS_epoll_create 213
|
||||
#define SYS_exit_group 231
|
||||
#define SYS_epoll_wait 232
|
||||
#define SYS_epoll_ctl 233
|
||||
#define SYS_openat 257
|
||||
#define SYS_faccessat 269
|
||||
#define SYS_pselect6 270
|
||||
#define SYS_epoll_pwait 281
|
||||
#define SYS_epoll_create1 291
|
||||
|
||||
TEXT runtime·exit(SB),NOSPLIT,$0-4
|
||||
@@ -65,10 +67,12 @@ TEXT runtime·exitThread(SB),NOSPLIT,$0-8
|
||||
JMP 0(PC)
|
||||
|
||||
TEXT runtime·open(SB),NOSPLIT,$0-20
|
||||
MOVQ name+0(FP), DI
|
||||
MOVL mode+8(FP), SI
|
||||
MOVL perm+12(FP), DX
|
||||
MOVL $SYS_open, AX
|
||||
// This uses openat instead of open, because Android O blocks open.
|
||||
MOVL $AT_FDCWD, DI // AT_FDCWD, so this acts like open
|
||||
MOVQ name+0(FP), SI
|
||||
MOVL mode+8(FP), DX
|
||||
MOVL perm+12(FP), R10
|
||||
MOVL $SYS_openat, AX
|
||||
SYSCALL
|
||||
CMPQ AX, $0xfffffffffffff001
|
||||
JLS 2(PC)
|
||||
@@ -599,7 +603,7 @@ TEXT runtime·settls(SB),NOSPLIT,$32
|
||||
// Same as in sys_darwin_386.s:/ugliness, different constant.
|
||||
// DI currently holds m->tls, which must be fs:0x1d0.
|
||||
// See cgo/gcc_android_amd64.c for the derivation of the constant.
|
||||
SUBQ $0x1d0, DI // In android, the tls base
|
||||
SUBQ $0x1d0, DI // In android, the tls base
|
||||
#else
|
||||
ADDQ $8, DI // ELF wants to use -8(FS)
|
||||
#endif
|
||||
@@ -655,11 +659,13 @@ TEXT runtime·epollctl(SB),NOSPLIT,$0
|
||||
|
||||
// int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout);
|
||||
TEXT runtime·epollwait(SB),NOSPLIT,$0
|
||||
// This uses pwait instead of wait, because Android O blocks wait.
|
||||
MOVL epfd+0(FP), DI
|
||||
MOVQ ev+8(FP), SI
|
||||
MOVL nev+16(FP), DX
|
||||
MOVL timeout+20(FP), R10
|
||||
MOVL $SYS_epoll_wait, AX
|
||||
MOVQ $0, R8
|
||||
MOVL $SYS_epoll_pwait, AX
|
||||
SYSCALL
|
||||
MOVL AX, ret+24(FP)
|
||||
RET
|
||||
@@ -676,9 +682,12 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$0
|
||||
|
||||
// int access(const char *name, int mode)
|
||||
TEXT runtime·access(SB),NOSPLIT,$0
|
||||
MOVQ name+0(FP), DI
|
||||
MOVL mode+8(FP), SI
|
||||
MOVL $SYS_access, AX
|
||||
// This uses faccessat instead of access, because Android O blocks access.
|
||||
MOVL $AT_FDCWD, DI // AT_FDCWD, so this acts like access
|
||||
MOVQ name+0(FP), SI
|
||||
MOVL mode+8(FP), DX
|
||||
MOVL $0, R10
|
||||
MOVL $SYS_faccessat, AX
|
||||
SYSCALL
|
||||
MOVL AX, ret+16(FP)
|
||||
RET
|
||||
|
||||
@@ -13,10 +13,11 @@
|
||||
#include "go_tls.h"
|
||||
#include "textflag.h"
|
||||
|
||||
#define AT_FDCWD -100
|
||||
|
||||
#define SYS_exit 5058
|
||||
#define SYS_read 5000
|
||||
#define SYS_write 5001
|
||||
#define SYS_open 5002
|
||||
#define SYS_close 5003
|
||||
#define SYS_getpid 5038
|
||||
#define SYS_kill 5060
|
||||
@@ -42,7 +43,8 @@
|
||||
#define SYS_exit_group 5205
|
||||
#define SYS_epoll_create 5207
|
||||
#define SYS_epoll_ctl 5208
|
||||
#define SYS_epoll_wait 5209
|
||||
#define SYS_openat 5247
|
||||
#define SYS_epoll_pwait 5272
|
||||
#define SYS_clock_gettime 5222
|
||||
#define SYS_epoll_create1 5285
|
||||
#define SYS_brk 5012
|
||||
@@ -66,11 +68,13 @@ TEXT runtime·exitThread(SB),NOSPLIT,$-8-8
|
||||
SYSCALL
|
||||
JMP 0(PC)
|
||||
|
||||
TEXT runtime·open(SB),NOSPLIT,$-8-20
|
||||
MOVV name+0(FP), R4
|
||||
MOVW mode+8(FP), R5
|
||||
MOVW perm+12(FP), R6
|
||||
MOVV $SYS_open, R2
|
||||
TEXT runtime·open(SB),NOSPLIT|NOFRAME,$0-20
|
||||
// This uses openat instead of open, because Android O blocks open.
|
||||
MOVW $AT_FDCWD, R4 // AT_FDCWD, so this acts like open
|
||||
MOVV name+0(FP), R5
|
||||
MOVW mode+8(FP), R6
|
||||
MOVW perm+12(FP), R7
|
||||
MOVV $SYS_openat, R2
|
||||
SYSCALL
|
||||
BEQ R7, 2(PC)
|
||||
MOVW $-1, R2
|
||||
@@ -422,12 +426,14 @@ TEXT runtime·epollctl(SB),NOSPLIT,$-8
|
||||
RET
|
||||
|
||||
// int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout);
|
||||
TEXT runtime·epollwait(SB),NOSPLIT,$-8
|
||||
TEXT runtime·epollwait(SB),NOSPLIT|NOFRAME,$0
|
||||
// This uses pwait instead of wait, because Android O blocks wait.
|
||||
MOVW epfd+0(FP), R4
|
||||
MOVV ev+8(FP), R5
|
||||
MOVW nev+16(FP), R6
|
||||
MOVW timeout+20(FP), R7
|
||||
MOVV $SYS_epoll_wait, R2
|
||||
MOVV $0, R8
|
||||
MOVV $SYS_epoll_pwait, R2
|
||||
SYSCALL
|
||||
MOVW R2, ret+24(FP)
|
||||
RET
|
||||
|
||||
@@ -35,56 +35,14 @@ import (
|
||||
|
||||
const usesLR = sys.MinFrameSize > 0
|
||||
|
||||
var (
|
||||
// initialized in tracebackinit
|
||||
goexitPC uintptr
|
||||
jmpdeferPC uintptr
|
||||
mcallPC uintptr
|
||||
morestackPC uintptr
|
||||
mstartPC uintptr
|
||||
rt0_goPC uintptr
|
||||
asmcgocallPC uintptr
|
||||
sigpanicPC uintptr
|
||||
runfinqPC uintptr
|
||||
bgsweepPC uintptr
|
||||
forcegchelperPC uintptr
|
||||
timerprocPC uintptr
|
||||
gcBgMarkWorkerPC uintptr
|
||||
systemstack_switchPC uintptr
|
||||
systemstackPC uintptr
|
||||
cgocallback_gofuncPC uintptr
|
||||
skipPC uintptr
|
||||
|
||||
gogoPC uintptr
|
||||
|
||||
externalthreadhandlerp uintptr // initialized elsewhere
|
||||
)
|
||||
var skipPC uintptr
|
||||
|
||||
func tracebackinit() {
|
||||
// Go variable initialization happens late during runtime startup.
|
||||
// Instead of initializing the variables above in the declarations,
|
||||
// schedinit calls this function so that the variables are
|
||||
// initialized and available earlier in the startup sequence.
|
||||
goexitPC = funcPC(goexit)
|
||||
jmpdeferPC = funcPC(jmpdefer)
|
||||
mcallPC = funcPC(mcall)
|
||||
morestackPC = funcPC(morestack)
|
||||
mstartPC = funcPC(mstart)
|
||||
rt0_goPC = funcPC(rt0_go)
|
||||
asmcgocallPC = funcPC(asmcgocall)
|
||||
sigpanicPC = funcPC(sigpanic)
|
||||
runfinqPC = funcPC(runfinq)
|
||||
bgsweepPC = funcPC(bgsweep)
|
||||
forcegchelperPC = funcPC(forcegchelper)
|
||||
timerprocPC = funcPC(timerproc)
|
||||
gcBgMarkWorkerPC = funcPC(gcBgMarkWorker)
|
||||
systemstack_switchPC = funcPC(systemstack_switch)
|
||||
systemstackPC = funcPC(systemstack)
|
||||
cgocallback_gofuncPC = funcPC(cgocallback_gofunc)
|
||||
skipPC = funcPC(skipPleaseUseCallersFrames)
|
||||
|
||||
// used by sigprof handler
|
||||
gogoPC = funcPC(gogo)
|
||||
}
|
||||
|
||||
// Traceback over the deferred function calls.
|
||||
@@ -137,9 +95,6 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
if skip > 0 && callback != nil {
|
||||
throw("gentraceback callback cannot be used with non-zero skip")
|
||||
}
|
||||
if goexitPC == 0 {
|
||||
throw("gentraceback before goexitPC initialization")
|
||||
}
|
||||
g := getg()
|
||||
if g == gp && g == g.m.curg {
|
||||
// The starting sp has been passed in as a uintptr, and the caller may
|
||||
@@ -241,7 +196,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
// g0, this systemstack is at the top of the stack.
|
||||
// if we're not on g0 or there's a no curg, then this is a regular call.
|
||||
sp := frame.sp
|
||||
if flags&_TraceJumpStack != 0 && f.entry == systemstackPC && gp == g.m.g0 && gp.m.curg != nil {
|
||||
if flags&_TraceJumpStack != 0 && f.funcID == funcID_systemstack && gp == g.m.g0 && gp.m.curg != nil {
|
||||
sp = gp.m.curg.sched.sp
|
||||
frame.sp = sp
|
||||
cgoCtxt = gp.m.curg.cgoCtxt
|
||||
@@ -256,7 +211,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
if topofstack(f, gp.m != nil && gp == gp.m.g0) {
|
||||
frame.lr = 0
|
||||
flr = funcInfo{}
|
||||
} else if usesLR && f.entry == jmpdeferPC {
|
||||
} else if usesLR && f.funcID == funcID_jmpdefer {
|
||||
// jmpdefer modifies SP/LR/PC non-atomically.
|
||||
// If a profiling interrupt arrives during jmpdefer,
|
||||
// the stack unwind may see a mismatched register set
|
||||
@@ -287,7 +242,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
// But if callback is set, we're doing a garbage collection and must
|
||||
// get everything, so crash loudly.
|
||||
doPrint := printing
|
||||
if doPrint && gp.m.incgo {
|
||||
if doPrint && gp.m.incgo && f.funcID == funcID_sigpanic {
|
||||
// We can inject sigpanic
|
||||
// calls directly into C code,
|
||||
// in which case we'll see a C
|
||||
@@ -396,8 +351,8 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
// if there's room, pcbuf[1] is a skip PC that encodes the number of skipped frames in pcbuf[0]
|
||||
if n+1 < max {
|
||||
n++
|
||||
skipPC := funcPC(skipPleaseUseCallersFrames) + uintptr(logicalSkipped)
|
||||
(*[1 << 20]uintptr)(unsafe.Pointer(pcbuf))[n] = skipPC
|
||||
pc := skipPC + uintptr(logicalSkipped)
|
||||
(*[1 << 20]uintptr)(unsafe.Pointer(pcbuf))[n] = pc
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -466,7 +421,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
n++
|
||||
|
||||
skipped:
|
||||
if f.entry == cgocallback_gofuncPC && len(cgoCtxt) > 0 {
|
||||
if f.funcID == funcID_cgocallback_gofunc && len(cgoCtxt) > 0 {
|
||||
ctxt := cgoCtxt[len(cgoCtxt)-1]
|
||||
cgoCtxt = cgoCtxt[:len(cgoCtxt)-1]
|
||||
|
||||
@@ -478,7 +433,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||
}
|
||||
}
|
||||
|
||||
waspanic = f.entry == sigpanicPC
|
||||
waspanic = f.funcID == funcID_sigpanic
|
||||
|
||||
// Do not unwind past the bottom of the stack.
|
||||
if !flr.valid() {
|
||||
@@ -931,30 +886,32 @@ func tracebackHexdump(stk stack, frame *stkframe, bad uintptr) {
|
||||
|
||||
// Does f mark the top of a goroutine stack?
|
||||
func topofstack(f funcInfo, g0 bool) bool {
|
||||
pc := f.entry
|
||||
return pc == goexitPC ||
|
||||
pc == mstartPC ||
|
||||
pc == mcallPC ||
|
||||
pc == morestackPC ||
|
||||
pc == rt0_goPC ||
|
||||
externalthreadhandlerp != 0 && pc == externalthreadhandlerp ||
|
||||
return f.funcID == funcID_goexit ||
|
||||
f.funcID == funcID_mstart ||
|
||||
f.funcID == funcID_mcall ||
|
||||
f.funcID == funcID_morestack ||
|
||||
f.funcID == funcID_rt0_go ||
|
||||
f.funcID == funcID_externalthreadhandler ||
|
||||
// asmcgocall is TOS on the system stack because it
|
||||
// switches to the system stack, but in this case we
|
||||
// can come back to the regular stack and still want
|
||||
// to be able to unwind through the call that appeared
|
||||
// on the regular stack.
|
||||
(g0 && pc == asmcgocallPC)
|
||||
(g0 && f.funcID == funcID_asmcgocall)
|
||||
}
|
||||
|
||||
// isSystemGoroutine reports whether the goroutine g must be omitted in
|
||||
// stack dumps and deadlock detector.
|
||||
func isSystemGoroutine(gp *g) bool {
|
||||
pc := gp.startpc
|
||||
return pc == runfinqPC && !fingRunning ||
|
||||
pc == bgsweepPC ||
|
||||
pc == forcegchelperPC ||
|
||||
pc == timerprocPC ||
|
||||
pc == gcBgMarkWorkerPC
|
||||
f := findfunc(gp.startpc)
|
||||
if !f.valid() {
|
||||
return false
|
||||
}
|
||||
return f.funcID == funcID_runfinq && !fingRunning ||
|
||||
f.funcID == funcID_bgsweep ||
|
||||
f.funcID == funcID_forcegchelper ||
|
||||
f.funcID == funcID_timerproc ||
|
||||
f.funcID == funcID_gcBgMarkWorker
|
||||
}
|
||||
|
||||
// SetCgoTraceback records three C functions to use to gather
|
||||
|
||||
@@ -474,7 +474,7 @@ func Map(mapping func(rune) rune, s string) string {
|
||||
b = make([]byte, len(s)+utf8.UTFMax)
|
||||
nbytes = copy(b, s[:i])
|
||||
if r >= 0 {
|
||||
if r <= utf8.RuneSelf {
|
||||
if r < utf8.RuneSelf {
|
||||
b[nbytes] = byte(r)
|
||||
nbytes++
|
||||
} else {
|
||||
@@ -504,7 +504,7 @@ func Map(mapping func(rune) rune, s string) string {
|
||||
r := mapping(c)
|
||||
|
||||
// common case
|
||||
if (0 <= r && r <= utf8.RuneSelf) && nbytes < len(b) {
|
||||
if (0 <= r && r < utf8.RuneSelf) && nbytes < len(b) {
|
||||
b[nbytes] = byte(r)
|
||||
nbytes++
|
||||
continue
|
||||
|
||||
@@ -528,6 +528,7 @@ var upperTests = []StringTest{
|
||||
{"longStrinGwitHmixofsmaLLandcAps", "LONGSTRINGWITHMIXOFSMALLANDCAPS"},
|
||||
{"long\u0250string\u0250with\u0250nonascii\u2C6Fchars", "LONG\u2C6FSTRING\u2C6FWITH\u2C6FNONASCII\u2C6FCHARS"},
|
||||
{"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char
|
||||
{"a\u0080\U0010FFFF", "A\u0080\U0010FFFF"}, // test utf8.RuneSelf and utf8.MaxRune
|
||||
}
|
||||
|
||||
var lowerTests = []StringTest{
|
||||
@@ -538,6 +539,7 @@ var lowerTests = []StringTest{
|
||||
{"longStrinGwitHmixofsmaLLandcAps", "longstringwithmixofsmallandcaps"},
|
||||
{"LONG\u2C6FSTRING\u2C6FWITH\u2C6FNONASCII\u2C6FCHARS", "long\u0250string\u0250with\u0250nonascii\u0250chars"},
|
||||
{"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char
|
||||
{"A\u0080\U0010FFFF", "a\u0080\U0010FFFF"}, // test utf8.RuneSelf and utf8.MaxRune
|
||||
}
|
||||
|
||||
const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000"
|
||||
@@ -650,6 +652,27 @@ func TestMap(t *testing.T) {
|
||||
if m != expect {
|
||||
t.Errorf("replace invalid sequence: expected %q got %q", expect, m)
|
||||
}
|
||||
|
||||
// 8. Check utf8.RuneSelf and utf8.MaxRune encoding
|
||||
encode := func(r rune) rune {
|
||||
switch r {
|
||||
case utf8.RuneSelf:
|
||||
return unicode.MaxRune
|
||||
case unicode.MaxRune:
|
||||
return utf8.RuneSelf
|
||||
}
|
||||
return r
|
||||
}
|
||||
s := string(utf8.RuneSelf) + string(utf8.MaxRune)
|
||||
r := string(utf8.MaxRune) + string(utf8.RuneSelf) // reverse of s
|
||||
m = Map(encode, s)
|
||||
if m != r {
|
||||
t.Errorf("encoding not handled correctly: expected %q got %q", r, m)
|
||||
}
|
||||
m = Map(encode, r)
|
||||
if m != s {
|
||||
t.Errorf("encoding not handled correctly: expected %q got %q", s, m)
|
||||
}
|
||||
}
|
||||
|
||||
func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) }
|
||||
|
||||
@@ -39,7 +39,6 @@ const (
|
||||
//sysnb Setreuid(ruid int, euid int) (err error)
|
||||
//sys Shutdown(fd int, how int) (err error)
|
||||
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
||||
//sys Stat(path string, stat *Stat_t) (err error)
|
||||
//sys Statfs(path string, buf *Statfs_t) (err error)
|
||||
//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
|
||||
//sys Truncate(path string, length int64) (err error)
|
||||
@@ -47,6 +46,7 @@ const (
|
||||
//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
|
||||
//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
|
||||
//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
|
||||
//sys fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_NEWFSTATAT
|
||||
//sysnb getgroups(n int, list *_Gid_t) (nn int, err error)
|
||||
//sysnb setgroups(n int, list *_Gid_t) (err error)
|
||||
//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
|
||||
@@ -61,6 +61,10 @@ const (
|
||||
//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
|
||||
//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
|
||||
|
||||
func Stat(path string, stat *Stat_t) (err error) {
|
||||
return fstatat(_AT_FDCWD, path, stat, 0)
|
||||
}
|
||||
|
||||
//go:noescape
|
||||
func gettimeofday(tv *Timeval) (err Errno)
|
||||
|
||||
|
||||
@@ -1476,21 +1476,6 @@ func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n i
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Stat(path string, stat *Stat_t) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Statfs(path string, buf *Statfs_t) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
@@ -1573,6 +1558,21 @@ func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func fstatat(fd int, path string, stat *Stat_t, flags int) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, _, e1 := Syscall6(SYS_NEWFSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func getgroups(n int, list *_Gid_t) (nn int, err error) {
|
||||
r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
|
||||
nn = int(r0)
|
||||
|
||||
34
test/fixedbugs/issue23812.go
Normal file
34
test/fixedbugs/issue23812.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// run
|
||||
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
want := int32(0x3edae8)
|
||||
got := foo(1)
|
||||
if want != got {
|
||||
panic(fmt.Sprintf("want %x, got %x", want, got))
|
||||
}
|
||||
}
|
||||
|
||||
func foo(a int32) int32 {
|
||||
return shr1(int32(shr2(int64(0x14ff6e2207db5d1f), int(a))), 4)
|
||||
}
|
||||
|
||||
func shr1(n int32, m int) int32 { return n >> uint(m) }
|
||||
|
||||
func shr2(n int64, m int) int64 {
|
||||
if m < 0 {
|
||||
m = -m
|
||||
}
|
||||
if m >= 64 {
|
||||
return n
|
||||
}
|
||||
|
||||
return n >> uint(m)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user