mirror of
https://github.com/golang/go.git
synced 2026-01-29 15:12:08 +03:00
Compare commits
107 Commits
dev.boring
...
go1.10.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0cb374daf | ||
|
|
ed3af1d472 | ||
|
|
d4cad3c4b1 | ||
|
|
d5f2dc6a5c | ||
|
|
f5ff72d623 | ||
|
|
9a66eedd42 | ||
|
|
a9ccbe0a69 | ||
|
|
d74e69c755 | ||
|
|
25bee965c6 | ||
|
|
f40c04941a | ||
|
|
25ca8f49c3 | ||
|
|
f1a7c2aae8 | ||
|
|
9a80067643 | ||
|
|
aaa5f47754 | ||
|
|
7ef6ee2c57 | ||
|
|
90d609ba61 | ||
|
|
0a4a37f1f0 | ||
|
|
1ae739797e | ||
|
|
aaccedc781 | ||
|
|
ce842c532a | ||
|
|
13a2f533e0 | ||
|
|
edd28f1e6d | ||
|
|
fba2c4d76b | ||
|
|
7495cdaf3d | ||
|
|
4f4cf6abd7 | ||
|
|
30ccc6284a | ||
|
|
15c6cc7c67 | ||
|
|
e97b7d68f1 | ||
|
|
1f8a5b8cc8 | ||
|
|
95b56b3879 | ||
|
|
2191fce26a | ||
|
|
713120eab6 | ||
|
|
305b0de625 | ||
|
|
ba5e308ea9 | ||
|
|
4d6ae73dfc | ||
|
|
dea961ebd9 | ||
|
|
b8ae3569c8 | ||
|
|
097d642de5 | ||
|
|
0fae49df57 | ||
|
|
0f1c9decc9 | ||
|
|
2b07564d19 | ||
|
|
1dea6c5269 | ||
|
|
61e4c11693 | ||
|
|
424f4ea0bd | ||
|
|
48016b89d9 | ||
|
|
815e0f9755 | ||
|
|
4c77cb3087 | ||
|
|
0931e9fef3 | ||
|
|
b5375d70d1 | ||
|
|
3d59583836 | ||
|
|
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,82 @@ 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>
|
||||
|
||||
<p>
|
||||
go1.10.4 (released 2018/08/24) includes fixes to the go command, linker, and the
|
||||
<code>net/http</code>, <code>mime/multipart</code>, <code>ld/macho</code>,
|
||||
<code>bytes</code>, and <code>strings</code> packages.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.4">Go
|
||||
1.10.4 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.10.5 (released 2018/11/02) includes fixes to the go command, linker, runtime
|
||||
and the <code>database/sql</code> package.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.5">Go
|
||||
1.10.5 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.10.6 (released 2018/12/12) includes three security fixes to "go get" and
|
||||
the <code>crypto/x509</code> package.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.6">Go
|
||||
1.10.6 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.10.7 (released 2018/12/14) includes a fix to a bug introduced in Go 1.10.6
|
||||
that broke <code>go</code> <code>get</code> for import path patterns containing
|
||||
"<code>...</code>".
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.7+label%3ACherryPickApproved">
|
||||
Go 1.10.7 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.10.8 (released 2019/01/23) includes a security fix to the
|
||||
<code>crypto/elliptic</code> package.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.8+label%3ACherryPickApproved">Go
|
||||
1.10.8 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.9">go1.9 (released 2017/08/24)</h2>
|
||||
@@ -63,6 +134,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 +208,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}}
|
||||
|
||||
31
misc/cgo/test/issue24161_darwin_test.go
Normal file
31
misc/cgo/test/issue24161_darwin_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// 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 cgotest
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"./issue24161arg"
|
||||
"./issue24161e0"
|
||||
"./issue24161e1"
|
||||
"./issue24161e2"
|
||||
"./issue24161res"
|
||||
)
|
||||
|
||||
func Test24161Arg(t *testing.T) {
|
||||
issue24161arg.Test(t)
|
||||
}
|
||||
func Test24161Res(t *testing.T) {
|
||||
issue24161res.Test(t)
|
||||
}
|
||||
func Test24161Example0(t *testing.T) {
|
||||
issue24161e0.Test(t)
|
||||
}
|
||||
func Test24161Example1(t *testing.T) {
|
||||
issue24161e1.Test(t)
|
||||
}
|
||||
func Test24161Example2(t *testing.T) {
|
||||
issue24161e2.Test(t)
|
||||
}
|
||||
17
misc/cgo/test/issue24161arg/def.go
Normal file
17
misc/cgo/test/issue24161arg/def.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// 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.
|
||||
|
||||
// +build darwin
|
||||
|
||||
package issue24161arg
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -framework CoreFoundation
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func test24161array() C.CFArrayRef {
|
||||
return C.CFArrayCreate(0, nil, 0, nil)
|
||||
}
|
||||
19
misc/cgo/test/issue24161arg/use.go
Normal file
19
misc/cgo/test/issue24161arg/use.go
Normal file
@@ -0,0 +1,19 @@
|
||||
// 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.
|
||||
|
||||
// +build darwin
|
||||
|
||||
package issue24161arg
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -framework CoreFoundation
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
*/
|
||||
import "C"
|
||||
import "testing"
|
||||
|
||||
func Test(t *testing.T) {
|
||||
a := test24161array()
|
||||
C.CFArrayCreateCopy(0, a)
|
||||
}
|
||||
29
misc/cgo/test/issue24161e0/main.go
Normal file
29
misc/cgo/test/issue24161e0/main.go
Normal file
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// +build darwin
|
||||
|
||||
package issue24161e0
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -x objective-c
|
||||
#cgo LDFLAGS: -framework CoreFoundation -framework Security
|
||||
#include <TargetConditionals.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <Security/Security.h>
|
||||
#if TARGET_OS_IPHONE == 0 && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101200
|
||||
typedef CFStringRef SecKeyAlgorithm;
|
||||
static CFDataRef SecKeyCreateSignature(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef dataToSign, CFErrorRef *error){return NULL;}
|
||||
#define kSecKeyAlgorithmECDSASignatureDigestX962SHA1 foo()
|
||||
static SecKeyAlgorithm foo(void){return NULL;}
|
||||
#endif
|
||||
*/
|
||||
import "C"
|
||||
import "testing"
|
||||
|
||||
func f1() {
|
||||
C.SecKeyCreateSignature(0, C.kSecKeyAlgorithmECDSASignatureDigestX962SHA1, 0, nil)
|
||||
}
|
||||
|
||||
func Test(t *testing.T) {}
|
||||
38
misc/cgo/test/issue24161e1/main.go
Normal file
38
misc/cgo/test/issue24161e1/main.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// 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.
|
||||
|
||||
// +build darwin
|
||||
|
||||
package issue24161e1
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -x objective-c
|
||||
#cgo LDFLAGS: -framework CoreFoundation -framework Security
|
||||
#include <TargetConditionals.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <Security/Security.h>
|
||||
#if TARGET_OS_IPHONE == 0 && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101200
|
||||
typedef CFStringRef SecKeyAlgorithm;
|
||||
static CFDataRef SecKeyCreateSignature(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef dataToSign, CFErrorRef *error){return NULL;}
|
||||
#define kSecKeyAlgorithmECDSASignatureDigestX962SHA1 foo()
|
||||
static SecKeyAlgorithm foo(void){return NULL;}
|
||||
#endif
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func f1() {
|
||||
C.SecKeyCreateSignature(0, C.kSecKeyAlgorithmECDSASignatureDigestX962SHA1, 0, nil)
|
||||
}
|
||||
|
||||
func f2(e C.CFErrorRef) {
|
||||
if desc := C.CFErrorCopyDescription(e); desc != 0 {
|
||||
fmt.Println(desc)
|
||||
}
|
||||
}
|
||||
|
||||
func Test(t *testing.T) {}
|
||||
40
misc/cgo/test/issue24161e2/main.go
Normal file
40
misc/cgo/test/issue24161e2/main.go
Normal file
@@ -0,0 +1,40 @@
|
||||
// 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.
|
||||
|
||||
// +build darwin
|
||||
|
||||
package issue24161e2
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -x objective-c
|
||||
#cgo LDFLAGS: -framework CoreFoundation -framework Security
|
||||
#include <TargetConditionals.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <Security/Security.h>
|
||||
#if TARGET_OS_IPHONE == 0 && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101200
|
||||
typedef CFStringRef SecKeyAlgorithm;
|
||||
static CFDataRef SecKeyCreateSignature(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef dataToSign, CFErrorRef *error){return NULL;}
|
||||
#define kSecKeyAlgorithmECDSASignatureDigestX962SHA1 foo()
|
||||
static SecKeyAlgorithm foo(void){return NULL;}
|
||||
#endif
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var _ C.CFStringRef
|
||||
|
||||
func f1() {
|
||||
C.SecKeyCreateSignature(0, C.kSecKeyAlgorithmECDSASignatureDigestX962SHA1, 0, nil)
|
||||
}
|
||||
|
||||
func f2(e C.CFErrorRef) {
|
||||
if desc := C.CFErrorCopyDescription(e); desc != 0 {
|
||||
fmt.Println(desc)
|
||||
}
|
||||
}
|
||||
|
||||
func Test(t *testing.T) {}
|
||||
23
misc/cgo/test/issue24161res/restype.go
Normal file
23
misc/cgo/test/issue24161res/restype.go
Normal file
@@ -0,0 +1,23 @@
|
||||
// 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.
|
||||
|
||||
// +build darwin
|
||||
|
||||
package issue24161res
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -framework CoreFoundation
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
if k := reflect.TypeOf(C.CFArrayCreate(0, nil, 0, nil)).Kind(); k != reflect.Uintptr {
|
||||
t.Fatalf("bad kind %s\n", k)
|
||||
}
|
||||
}
|
||||
10
misc/cgo/test/issue26430.go
Normal file
10
misc/cgo/test/issue26430.go
Normal file
@@ -0,0 +1,10 @@
|
||||
// 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.
|
||||
|
||||
// Issue 26430: incomplete typedef leads to inconsistent typedefs error.
|
||||
// No runtime test; just make sure it compiles.
|
||||
|
||||
package cgotest
|
||||
|
||||
import _ "./issue26430"
|
||||
13
misc/cgo/test/issue26430/a.go
Normal file
13
misc/cgo/test/issue26430/a.go
Normal file
@@ -0,0 +1,13 @@
|
||||
// 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 a
|
||||
|
||||
// typedef struct S ST;
|
||||
// static ST* F() { return 0; }
|
||||
import "C"
|
||||
|
||||
func F1() {
|
||||
C.F()
|
||||
}
|
||||
13
misc/cgo/test/issue26430/b.go
Normal file
13
misc/cgo/test/issue26430/b.go
Normal file
@@ -0,0 +1,13 @@
|
||||
// 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 a
|
||||
|
||||
// typedef struct S ST;
|
||||
// struct S { int f; };
|
||||
import "C"
|
||||
|
||||
func F2(p *C.ST) {
|
||||
p.f = 1
|
||||
}
|
||||
23
misc/cgo/test/issue26517.go
Normal file
23
misc/cgo/test/issue26517.go
Normal file
@@ -0,0 +1,23 @@
|
||||
// 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 cgotest
|
||||
|
||||
// Introduce two pointer types which are distinct, but have the same
|
||||
// base type. Make sure that both of those pointer types get resolved
|
||||
// correctly. Before the fix for 26517 if one of these pointer types
|
||||
// was resolved before the other one was processed, the second one
|
||||
// would never be resolved.
|
||||
// Before this issue was fixed this test failed on Windows,
|
||||
// where va_list expands to a named char* type.
|
||||
|
||||
/*
|
||||
#include <stdarg.h>
|
||||
typedef va_list TypeOne;
|
||||
typedef char *TypeTwo;
|
||||
*/
|
||||
import "C"
|
||||
|
||||
var a C.TypeOne
|
||||
var b C.TypeTwo
|
||||
10
misc/cgo/test/issue26743.go
Normal file
10
misc/cgo/test/issue26743.go
Normal file
@@ -0,0 +1,10 @@
|
||||
// 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.
|
||||
|
||||
// Issue 26743: typedef of uint leads to inconsistent typedefs error.
|
||||
// No runtime test; just make sure it compiles.
|
||||
|
||||
package cgotest
|
||||
|
||||
import _ "./issue26743"
|
||||
11
misc/cgo/test/issue26743/a.go
Normal file
11
misc/cgo/test/issue26743/a.go
Normal file
@@ -0,0 +1,11 @@
|
||||
// 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 issue26743
|
||||
|
||||
// typedef unsigned int uint;
|
||||
// int C1(uint x) { return x; }
|
||||
import "C"
|
||||
|
||||
var V1 = C.C1(0)
|
||||
9
misc/cgo/test/issue26743/b.go
Normal file
9
misc/cgo/test/issue26743/b.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// 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 issue26743
|
||||
|
||||
import "C"
|
||||
|
||||
var V2 C.uint
|
||||
@@ -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() {
|
||||
|
||||
18
misc/cgo/testgodefs/fieldtypedef.go
Normal file
18
misc/cgo/testgodefs/fieldtypedef.go
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserve d.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
/*
|
||||
struct S1 { int f1; };
|
||||
struct S2 { struct S1 s1; };
|
||||
typedef struct S1 S1Type;
|
||||
typedef struct S2 S2Type;
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type S1 C.S1Type
|
||||
type S2 C.S2Type
|
||||
@@ -7,7 +7,7 @@
|
||||
# We are testing cgo -godefs, which translates Go files that use
|
||||
# import "C" into Go files with Go definitions of types defined in the
|
||||
# import "C" block. Add more tests here.
|
||||
FILE_PREFIXES="anonunion issue8478"
|
||||
FILE_PREFIXES="anonunion issue8478 fieldtypedef"
|
||||
|
||||
RM=
|
||||
for FP in $FILE_PREFIXES
|
||||
|
||||
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,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -6,6 +6,7 @@ package bytes_test
|
||||
|
||||
import (
|
||||
. "bytes"
|
||||
"internal/testenv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -58,10 +59,20 @@ func TestCompareIdenticalSlice(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCompareBytes(t *testing.T) {
|
||||
n := 128
|
||||
lengths := make([]int, 0) // lengths to test in ascending order
|
||||
for i := 0; i <= 128; i++ {
|
||||
lengths = append(lengths, i)
|
||||
}
|
||||
lengths = append(lengths, 256, 512, 1024, 1333, 4095, 4096, 4097)
|
||||
|
||||
if !testing.Short() || testenv.Builder() != "" {
|
||||
lengths = append(lengths, 65535, 65536, 65537, 99999)
|
||||
}
|
||||
|
||||
n := lengths[len(lengths)-1]
|
||||
a := make([]byte, n+1)
|
||||
b := make([]byte, n+1)
|
||||
for len := 0; len < 128; len++ {
|
||||
for _, len := range lengths {
|
||||
// randomish but deterministic data. No 0 or 255.
|
||||
for i := 0; i < len; i++ {
|
||||
a[i] = byte(1 + 31*i%254)
|
||||
|
||||
@@ -164,9 +164,29 @@ func (p *Package) Translate(f *File) {
|
||||
cref.Name.C = cname(cref.Name.Go)
|
||||
}
|
||||
p.loadDefines(f)
|
||||
needType := p.guessKinds(f)
|
||||
if len(needType) > 0 {
|
||||
p.loadDWARF(f, needType)
|
||||
p.typedefs = map[string]bool{}
|
||||
p.typedefList = nil
|
||||
numTypedefs := -1
|
||||
for len(p.typedefs) > numTypedefs {
|
||||
numTypedefs = len(p.typedefs)
|
||||
// Also ask about any typedefs we've seen so far.
|
||||
for _, a := range p.typedefList {
|
||||
f.Name[a] = &Name{
|
||||
Go: a,
|
||||
C: a,
|
||||
}
|
||||
}
|
||||
needType := p.guessKinds(f)
|
||||
if len(needType) > 0 {
|
||||
p.loadDWARF(f, needType)
|
||||
}
|
||||
|
||||
// In godefs mode we're OK with the typedefs, which
|
||||
// will presumably also be defined in the file, we
|
||||
// don't want to resolve them to their base types.
|
||||
if *godefs {
|
||||
break
|
||||
}
|
||||
}
|
||||
if p.rewriteCalls(f) {
|
||||
// Add `import _cgo_unsafe "unsafe"` after the package statement.
|
||||
@@ -551,6 +571,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
|
||||
fatalf("malformed __cgo__ name: %s", name)
|
||||
}
|
||||
types[i] = t.Type
|
||||
p.recordTypedefs(t.Type)
|
||||
}
|
||||
if e.Tag != dwarf.TagCompileUnit {
|
||||
r.SkipChildren()
|
||||
@@ -599,6 +620,47 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
|
||||
}
|
||||
}
|
||||
|
||||
// recordTypedefs remembers in p.typedefs all the typedefs used in dtypes and its children.
|
||||
func (p *Package) recordTypedefs(dtype dwarf.Type) {
|
||||
p.recordTypedefs1(dtype, map[dwarf.Type]bool{})
|
||||
}
|
||||
func (p *Package) recordTypedefs1(dtype dwarf.Type, visited map[dwarf.Type]bool) {
|
||||
if dtype == nil {
|
||||
return
|
||||
}
|
||||
if visited[dtype] {
|
||||
return
|
||||
}
|
||||
visited[dtype] = true
|
||||
switch dt := dtype.(type) {
|
||||
case *dwarf.TypedefType:
|
||||
if strings.HasPrefix(dt.Name, "__builtin") {
|
||||
// Don't look inside builtin types. There be dragons.
|
||||
return
|
||||
}
|
||||
if !p.typedefs[dt.Name] {
|
||||
p.typedefs[dt.Name] = true
|
||||
p.typedefList = append(p.typedefList, dt.Name)
|
||||
p.recordTypedefs1(dt.Type, visited)
|
||||
}
|
||||
case *dwarf.PtrType:
|
||||
p.recordTypedefs1(dt.Type, visited)
|
||||
case *dwarf.ArrayType:
|
||||
p.recordTypedefs1(dt.Type, visited)
|
||||
case *dwarf.QualType:
|
||||
p.recordTypedefs1(dt.Type, visited)
|
||||
case *dwarf.FuncType:
|
||||
p.recordTypedefs1(dt.ReturnType, visited)
|
||||
for _, a := range dt.ParamType {
|
||||
p.recordTypedefs1(a, visited)
|
||||
}
|
||||
case *dwarf.StructType:
|
||||
for _, f := range dt.Field {
|
||||
p.recordTypedefs1(f.Type, visited)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mangleName does name mangling to translate names
|
||||
// from the original Go source files to the names
|
||||
// used in the final Go files generated by cgo.
|
||||
@@ -1659,6 +1721,7 @@ type typeConv struct {
|
||||
// Map from types to incomplete pointers to those types.
|
||||
ptrs map[dwarf.Type][]*Type
|
||||
// Keys of ptrs in insertion order (deterministic worklist)
|
||||
// ptrKeys contains exactly the keys in ptrs.
|
||||
ptrKeys []dwarf.Type
|
||||
|
||||
// Type names X for which there exists an XGetTypeID function with type func() CFTypeID.
|
||||
@@ -1801,14 +1864,15 @@ func (c *typeConv) FinishType(pos token.Pos) {
|
||||
for len(c.ptrKeys) > 0 {
|
||||
dtype := c.ptrKeys[0]
|
||||
c.ptrKeys = c.ptrKeys[1:]
|
||||
ptrs := c.ptrs[dtype]
|
||||
delete(c.ptrs, dtype)
|
||||
|
||||
// Note Type might invalidate c.ptrs[dtype].
|
||||
t := c.Type(dtype, pos)
|
||||
for _, ptr := range c.ptrs[dtype] {
|
||||
for _, ptr := range ptrs {
|
||||
ptr.Go.(*ast.StarExpr).X = t.Go
|
||||
ptr.C.Set("%s*", t.C)
|
||||
}
|
||||
c.ptrs[dtype] = nil // retain the map key
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2085,6 +2149,10 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
||||
s := *sub
|
||||
s.Go = c.uintptr
|
||||
sub = &s
|
||||
// Make sure we update any previously computed type.
|
||||
if oldType := typedef[name.Name]; oldType != nil {
|
||||
oldType.Go = sub.Go
|
||||
}
|
||||
}
|
||||
t.Go = name
|
||||
if unionWithPointer[sub.Go] {
|
||||
@@ -2246,7 +2314,7 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
|
||||
}
|
||||
// ...or the typedef is one in which we expect bad pointers.
|
||||
// It will be a uintptr instead of *X.
|
||||
if c.badPointerTypedef(dt) {
|
||||
if c.baseBadPointerTypedef(dt) {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -2598,6 +2666,19 @@ func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// baseBadPointerTypedef reports whether the base of a chain of typedefs is a bad typedef
|
||||
// as badPointerTypedef reports.
|
||||
func (c *typeConv) baseBadPointerTypedef(dt *dwarf.TypedefType) bool {
|
||||
for {
|
||||
if t, ok := dt.Type.(*dwarf.TypedefType); ok {
|
||||
dt = t
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
return c.badPointerTypedef(dt)
|
||||
}
|
||||
|
||||
func (c *typeConv) badCFType(dt *dwarf.TypedefType) bool {
|
||||
// The real bad types are CFNumberRef and CFDateRef.
|
||||
// Sometimes non-pointers are stored in these types.
|
||||
|
||||
@@ -42,9 +42,11 @@ type Package struct {
|
||||
Name map[string]*Name // accumulated Name from Files
|
||||
ExpFunc []*ExpFunc // accumulated ExpFunc from Files
|
||||
Decl []ast.Decl
|
||||
GoFiles []string // list of Go files
|
||||
GccFiles []string // list of gcc output files
|
||||
Preamble string // collected preamble for _cgo_export.h
|
||||
GoFiles []string // list of Go files
|
||||
GccFiles []string // list of gcc output files
|
||||
Preamble string // collected preamble for _cgo_export.h
|
||||
typedefs map[string]bool // type names that appear in the types of the objects we're interested in
|
||||
typedefList []string
|
||||
}
|
||||
|
||||
// A File collects information about a single Go input file.
|
||||
@@ -388,6 +390,14 @@ func (p *Package) Record(f *File) {
|
||||
for k, v := range f.Name {
|
||||
if p.Name[k] == nil {
|
||||
p.Name[k] = v
|
||||
} else if p.incompleteTypedef(p.Name[k].Type) {
|
||||
p.Name[k] = v
|
||||
} else if p.incompleteTypedef(v.Type) {
|
||||
// Nothing to do.
|
||||
} else if _, ok := nameToC[k]; ok {
|
||||
// Names we predefine may appear inconsistent
|
||||
// if some files typedef them and some don't.
|
||||
// Issue 26743.
|
||||
} else if !reflect.DeepEqual(p.Name[k], v) {
|
||||
error_(token.NoPos, "inconsistent definitions for C.%s", fixGo(k))
|
||||
}
|
||||
@@ -400,3 +410,9 @@ func (p *Package) Record(f *File) {
|
||||
}
|
||||
p.Decl = append(p.Decl, f.AST.Decls...)
|
||||
}
|
||||
|
||||
// incompleteTypedef reports whether t appears to be an incomplete
|
||||
// typedef definition.
|
||||
func (p *Package) incompleteTypedef(t *Type) bool {
|
||||
return t == nil || (t.Size == 0 && t.Align == -1)
|
||||
}
|
||||
|
||||
@@ -122,6 +122,17 @@ func (n *Node) Int64() int64 {
|
||||
return n.Val().U.(*Mpint).Int64()
|
||||
}
|
||||
|
||||
// CanInt64 reports whether it is safe to call Int64() on n.
|
||||
func (n *Node) CanInt64() bool {
|
||||
if !Isconst(n, CTINT) {
|
||||
return false
|
||||
}
|
||||
|
||||
// if the value inside n cannot be represented as an int64, the
|
||||
// return value of Int64 is undefined
|
||||
return n.Val().U.(*Mpint).CmpInt64(n.Int64()) == 0
|
||||
}
|
||||
|
||||
// Bool returns n as a bool.
|
||||
// n must be a boolean constant.
|
||||
func (n *Node) Bool() bool {
|
||||
|
||||
@@ -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.
|
||||
@@ -3554,6 +3561,12 @@ func walkinrange(n *Node, init *Nodes) *Node {
|
||||
return n
|
||||
}
|
||||
|
||||
// Ensure that Int64() does not overflow on a and c (it'll happen
|
||||
// for any const above 2**63; see issue #27143).
|
||||
if !a.CanInt64() || !c.CanInt64() {
|
||||
return n
|
||||
}
|
||||
|
||||
if opl == OLT {
|
||||
// We have a < b && ...
|
||||
// We need a ≤ b && ... to safely use unsigned comparison tricks.
|
||||
|
||||
@@ -102,7 +102,7 @@ func checkFunc(f *Func) {
|
||||
f.Fatalf("plain/dead block %s has a control value", b)
|
||||
}
|
||||
}
|
||||
if len(b.Succs) > 2 && b.Likely != BranchUnknown {
|
||||
if len(b.Succs) != 2 && b.Likely != BranchUnknown {
|
||||
f.Fatalf("likeliness prediction %d for block %s with %d successors", b.Likely, b, len(b.Succs))
|
||||
}
|
||||
|
||||
|
||||
@@ -92,6 +92,7 @@ func fuseBlockIf(b *Block) bool {
|
||||
b.removeEdge(1)
|
||||
}
|
||||
b.Kind = BlockPlain
|
||||
b.Likely = BranchUnknown
|
||||
b.SetControl(nil)
|
||||
|
||||
// Trash the empty blocks s0 & s1.
|
||||
|
||||
@@ -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])
|
||||
@@ -2658,7 +2658,7 @@
|
||||
|
||||
// Load args directly into the register class where it will be used.
|
||||
// We do this by just modifying the type of the Arg.
|
||||
(MOVQf2i <t> (Arg [off] {sym})) -> @b.Func.Entry (Arg <t> [off] {sym})
|
||||
(MOVLf2i <t> (Arg [off] {sym})) -> @b.Func.Entry (Arg <t> [off] {sym})
|
||||
(MOVQi2f <t> (Arg [off] {sym})) -> @b.Func.Entry (Arg <t> [off] {sym})
|
||||
(MOVLi2f <t> (Arg [off] {sym})) -> @b.Func.Entry (Arg <t> [off] {sym})
|
||||
(MOVQf2i <t> (Arg <u> [off] {sym})) && t.Size() == u.Size() -> @b.Func.Entry (Arg <t> [off] {sym})
|
||||
(MOVLf2i <t> (Arg <u> [off] {sym})) && t.Size() == u.Size() -> @b.Func.Entry (Arg <t> [off] {sym})
|
||||
(MOVQi2f <t> (Arg <u> [off] {sym})) && t.Size() == u.Size() -> @b.Func.Entry (Arg <t> [off] {sym})
|
||||
(MOVLi2f <t> (Arg <u> [off] {sym})) && t.Size() == u.Size() -> @b.Func.Entry (Arg <t> [off] {sym})
|
||||
|
||||
@@ -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.
|
||||
@@ -407,7 +407,7 @@ func init() {
|
||||
{name: "MOVQi2f", argLength: 1, reg: gpfp, typ: "Float64"}, // move 64 bits from int to float reg
|
||||
{name: "MOVQf2i", argLength: 1, reg: fpgp, typ: "UInt64"}, // move 64 bits from float to int reg
|
||||
{name: "MOVLi2f", argLength: 1, reg: gpfp, typ: "Float32"}, // move 32 bits from int to float reg
|
||||
{name: "MOVLf2i", argLength: 1, reg: fpgp, typ: "UInt32"}, // move 32 bits from float to int reg
|
||||
{name: "MOVLf2i", argLength: 1, reg: fpgp, typ: "UInt32"}, // move 32 bits from float to int reg, zero extend
|
||||
|
||||
{name: "PXOR", argLength: 2, reg: fp21, asm: "PXOR", commutative: true, resultInArg0: true}, // exclusive or, applied to X regs for float negation.
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -7428,8 +7428,8 @@ func rewriteValueAMD64_OpAMD64MOVLatomicload_0(v *Value) bool {
|
||||
func rewriteValueAMD64_OpAMD64MOVLf2i_0(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVLf2i <t> (Arg [off] {sym}))
|
||||
// cond:
|
||||
// match: (MOVLf2i <t> (Arg <u> [off] {sym}))
|
||||
// cond: t.Size() == u.Size()
|
||||
// result: @b.Func.Entry (Arg <t> [off] {sym})
|
||||
for {
|
||||
t := v.Type
|
||||
@@ -7437,8 +7437,12 @@ func rewriteValueAMD64_OpAMD64MOVLf2i_0(v *Value) bool {
|
||||
if v_0.Op != OpArg {
|
||||
break
|
||||
}
|
||||
u := v_0.Type
|
||||
off := v_0.AuxInt
|
||||
sym := v_0.Aux
|
||||
if !(t.Size() == u.Size()) {
|
||||
break
|
||||
}
|
||||
b = b.Func.Entry
|
||||
v0 := b.NewValue0(v.Pos, OpArg, t)
|
||||
v.reset(OpCopy)
|
||||
@@ -7452,8 +7456,8 @@ func rewriteValueAMD64_OpAMD64MOVLf2i_0(v *Value) bool {
|
||||
func rewriteValueAMD64_OpAMD64MOVLi2f_0(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVLi2f <t> (Arg [off] {sym}))
|
||||
// cond:
|
||||
// match: (MOVLi2f <t> (Arg <u> [off] {sym}))
|
||||
// cond: t.Size() == u.Size()
|
||||
// result: @b.Func.Entry (Arg <t> [off] {sym})
|
||||
for {
|
||||
t := v.Type
|
||||
@@ -7461,8 +7465,12 @@ func rewriteValueAMD64_OpAMD64MOVLi2f_0(v *Value) bool {
|
||||
if v_0.Op != OpArg {
|
||||
break
|
||||
}
|
||||
u := v_0.Type
|
||||
off := v_0.AuxInt
|
||||
sym := v_0.Aux
|
||||
if !(t.Size() == u.Size()) {
|
||||
break
|
||||
}
|
||||
b = b.Func.Entry
|
||||
v0 := b.NewValue0(v.Pos, OpArg, t)
|
||||
v.reset(OpCopy)
|
||||
@@ -9631,8 +9639,8 @@ func rewriteValueAMD64_OpAMD64MOVQatomicload_0(v *Value) bool {
|
||||
func rewriteValueAMD64_OpAMD64MOVQf2i_0(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVQf2i <t> (Arg [off] {sym}))
|
||||
// cond:
|
||||
// match: (MOVQf2i <t> (Arg <u> [off] {sym}))
|
||||
// cond: t.Size() == u.Size()
|
||||
// result: @b.Func.Entry (Arg <t> [off] {sym})
|
||||
for {
|
||||
t := v.Type
|
||||
@@ -9640,8 +9648,12 @@ func rewriteValueAMD64_OpAMD64MOVQf2i_0(v *Value) bool {
|
||||
if v_0.Op != OpArg {
|
||||
break
|
||||
}
|
||||
u := v_0.Type
|
||||
off := v_0.AuxInt
|
||||
sym := v_0.Aux
|
||||
if !(t.Size() == u.Size()) {
|
||||
break
|
||||
}
|
||||
b = b.Func.Entry
|
||||
v0 := b.NewValue0(v.Pos, OpArg, t)
|
||||
v.reset(OpCopy)
|
||||
@@ -9655,8 +9667,8 @@ func rewriteValueAMD64_OpAMD64MOVQf2i_0(v *Value) bool {
|
||||
func rewriteValueAMD64_OpAMD64MOVQi2f_0(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVQi2f <t> (Arg [off] {sym}))
|
||||
// cond:
|
||||
// match: (MOVQi2f <t> (Arg <u> [off] {sym}))
|
||||
// cond: t.Size() == u.Size()
|
||||
// result: @b.Func.Entry (Arg <t> [off] {sym})
|
||||
for {
|
||||
t := v.Type
|
||||
@@ -9664,8 +9676,12 @@ func rewriteValueAMD64_OpAMD64MOVQi2f_0(v *Value) bool {
|
||||
if v_0.Op != OpArg {
|
||||
break
|
||||
}
|
||||
u := v_0.Type
|
||||
off := v_0.AuxInt
|
||||
sym := v_0.Aux
|
||||
if !(t.Size() == u.Size()) {
|
||||
break
|
||||
}
|
||||
b = b.Func.Entry
|
||||
v0 := b.NewValue0(v.Pos, OpArg, t)
|
||||
v.reset(OpCopy)
|
||||
@@ -34892,7 +34908,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 +34917,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 +35163,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 +35172,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 +35483,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 +35492,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],
|
||||
|
||||
@@ -207,9 +207,9 @@ var downloadCache = map[string]bool{}
|
||||
var downloadRootCache = map[string]bool{}
|
||||
|
||||
// download runs the download half of the get command
|
||||
// for the package named by the argument.
|
||||
// for the package or pattern 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)
|
||||
}
|
||||
@@ -376,6 +376,23 @@ func downloadPackage(p *load.Package) error {
|
||||
security = web.Insecure
|
||||
}
|
||||
|
||||
// p can be either a real package, or a pseudo-package whose “import path” is
|
||||
// actually a wildcard pattern.
|
||||
// Trim the path at the element containing the first wildcard,
|
||||
// and hope that it applies to the wildcarded parts too.
|
||||
// This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH.
|
||||
importPrefix := p.ImportPath
|
||||
if i := strings.Index(importPrefix, "..."); i >= 0 {
|
||||
slash := strings.LastIndexByte(importPrefix[:i], '/')
|
||||
if slash < 0 {
|
||||
return fmt.Errorf("cannot expand ... in %q", p.ImportPath)
|
||||
}
|
||||
importPrefix = importPrefix[:slash]
|
||||
}
|
||||
if err := CheckImportPath(importPrefix); err != nil {
|
||||
return fmt.Errorf("%s: invalid import path: %v", p.ImportPath, err)
|
||||
}
|
||||
|
||||
if p.Internal.Build.SrcRoot != "" {
|
||||
// Directory exists. Look for checkout along path to src.
|
||||
vcs, rootPath, err = vcsFromDir(p.Dir, p.Internal.Build.SrcRoot)
|
||||
@@ -393,7 +410,7 @@ func downloadPackage(p *load.Package) error {
|
||||
}
|
||||
repo = remote
|
||||
if !*getF {
|
||||
if rr, err := repoRootForImportPath(p.ImportPath, security); err == nil {
|
||||
if rr, err := repoRootForImportPath(importPrefix, security); err == nil {
|
||||
repo := rr.repo
|
||||
if rr.vcs.resolveRepo != nil {
|
||||
resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
|
||||
@@ -410,7 +427,7 @@ func downloadPackage(p *load.Package) error {
|
||||
} else {
|
||||
// Analyze the import path to determine the version control system,
|
||||
// repository, and the import path for the root of the repository.
|
||||
rr, err := repoRootForImportPath(p.ImportPath, security)
|
||||
rr, err := repoRootForImportPath(importPrefix, security)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
192
src/cmd/go/internal/get/path.go
Normal file
192
src/cmd/go/internal/get/path.go
Normal file
@@ -0,0 +1,192 @@
|
||||
// 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 get
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// The following functions are copied verbatim from cmd/go/internal/module/module.go,
|
||||
// with a change to additionally reject Windows short-names,
|
||||
// and one to accept arbitrary letters (golang.org/issue/29101).
|
||||
//
|
||||
// TODO(bcmills): After the call site for this function is backported,
|
||||
// consolidate this back down to a single copy.
|
||||
//
|
||||
// NOTE: DO NOT MERGE THESE UNTIL WE DECIDE ABOUT ARBITRARY LETTERS IN MODULE MODE.
|
||||
|
||||
// CheckImportPath checks that an import path is valid.
|
||||
func CheckImportPath(path string) error {
|
||||
if err := checkPath(path, false); err != nil {
|
||||
return fmt.Errorf("malformed import path %q: %v", path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkPath checks that a general path is valid.
|
||||
// It returns an error describing why but not mentioning path.
|
||||
// Because these checks apply to both module paths and import paths,
|
||||
// the caller is expected to add the "malformed ___ path %q: " prefix.
|
||||
// fileName indicates whether the final element of the path is a file name
|
||||
// (as opposed to a directory name).
|
||||
func checkPath(path string, fileName bool) error {
|
||||
if !utf8.ValidString(path) {
|
||||
return fmt.Errorf("invalid UTF-8")
|
||||
}
|
||||
if path == "" {
|
||||
return fmt.Errorf("empty string")
|
||||
}
|
||||
if strings.Contains(path, "..") {
|
||||
return fmt.Errorf("double dot")
|
||||
}
|
||||
if strings.Contains(path, "//") {
|
||||
return fmt.Errorf("double slash")
|
||||
}
|
||||
if path[len(path)-1] == '/' {
|
||||
return fmt.Errorf("trailing slash")
|
||||
}
|
||||
elemStart := 0
|
||||
for i, r := range path {
|
||||
if r == '/' {
|
||||
if err := checkElem(path[elemStart:i], fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
elemStart = i + 1
|
||||
}
|
||||
}
|
||||
if err := checkElem(path[elemStart:], fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkElem checks whether an individual path element is valid.
|
||||
// fileName indicates whether the element is a file name (not a directory name).
|
||||
func checkElem(elem string, fileName bool) error {
|
||||
if elem == "" {
|
||||
return fmt.Errorf("empty path element")
|
||||
}
|
||||
if strings.Count(elem, ".") == len(elem) {
|
||||
return fmt.Errorf("invalid path element %q", elem)
|
||||
}
|
||||
if elem[0] == '.' && !fileName {
|
||||
return fmt.Errorf("leading dot in path element")
|
||||
}
|
||||
if elem[len(elem)-1] == '.' {
|
||||
return fmt.Errorf("trailing dot in path element")
|
||||
}
|
||||
|
||||
charOK := pathOK
|
||||
if fileName {
|
||||
charOK = fileNameOK
|
||||
}
|
||||
for _, r := range elem {
|
||||
if !charOK(r) {
|
||||
return fmt.Errorf("invalid char %q", r)
|
||||
}
|
||||
}
|
||||
|
||||
// Windows disallows a bunch of path elements, sadly.
|
||||
// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
|
||||
short := elem
|
||||
if i := strings.Index(short, "."); i >= 0 {
|
||||
short = short[:i]
|
||||
}
|
||||
for _, bad := range badWindowsNames {
|
||||
if strings.EqualFold(bad, short) {
|
||||
return fmt.Errorf("disallowed path element %q", elem)
|
||||
}
|
||||
}
|
||||
|
||||
// Reject path components that look like Windows short-names.
|
||||
// Those usually end in a tilde followed by one or more ASCII digits.
|
||||
if tilde := strings.LastIndexByte(short, '~'); tilde >= 0 && tilde < len(short)-1 {
|
||||
suffix := short[tilde+1:]
|
||||
suffixIsDigits := true
|
||||
for _, r := range suffix {
|
||||
if r < '0' || r > '9' {
|
||||
suffixIsDigits = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if suffixIsDigits {
|
||||
return fmt.Errorf("trailing tilde and digits in path element")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// pathOK reports whether r can appear in an import path element.
|
||||
//
|
||||
// NOTE: This function DIVERGES from module mode pathOK by accepting Unicode letters.
|
||||
func pathOK(r rune) bool {
|
||||
if r < utf8.RuneSelf {
|
||||
return r == '+' || r == '-' || r == '.' || r == '_' || r == '~' ||
|
||||
'0' <= r && r <= '9' ||
|
||||
'A' <= r && r <= 'Z' ||
|
||||
'a' <= r && r <= 'z'
|
||||
}
|
||||
return unicode.IsLetter(r)
|
||||
}
|
||||
|
||||
// fileNameOK reports whether r can appear in a file name.
|
||||
// For now we allow all Unicode letters but otherwise limit to pathOK plus a few more punctuation characters.
|
||||
// If we expand the set of allowed characters here, we have to
|
||||
// work harder at detecting potential case-folding and normalization collisions.
|
||||
// See note about "safe encoding" below.
|
||||
func fileNameOK(r rune) bool {
|
||||
if r < utf8.RuneSelf {
|
||||
// Entire set of ASCII punctuation, from which we remove characters:
|
||||
// ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~
|
||||
// We disallow some shell special characters: " ' * < > ? ` |
|
||||
// (Note that some of those are disallowed by the Windows file system as well.)
|
||||
// We also disallow path separators / : and \ (fileNameOK is only called on path element characters).
|
||||
// We allow spaces (U+0020) in file names.
|
||||
const allowed = "!#$%&()+,-.=@[]^_{}~ "
|
||||
if '0' <= r && r <= '9' || 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' {
|
||||
return true
|
||||
}
|
||||
for i := 0; i < len(allowed); i++ {
|
||||
if rune(allowed[i]) == r {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
// It may be OK to add more ASCII punctuation here, but only carefully.
|
||||
// For example Windows disallows < > \, and macOS disallows :, so we must not allow those.
|
||||
return unicode.IsLetter(r)
|
||||
}
|
||||
|
||||
// badWindowsNames are the reserved file path elements on Windows.
|
||||
// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
|
||||
var badWindowsNames = []string{
|
||||
"CON",
|
||||
"PRN",
|
||||
"AUX",
|
||||
"NUL",
|
||||
"COM1",
|
||||
"COM2",
|
||||
"COM3",
|
||||
"COM4",
|
||||
"COM5",
|
||||
"COM6",
|
||||
"COM7",
|
||||
"COM8",
|
||||
"COM9",
|
||||
"LPT1",
|
||||
"LPT2",
|
||||
"LPT3",
|
||||
"LPT4",
|
||||
"LPT5",
|
||||
"LPT6",
|
||||
"LPT7",
|
||||
"LPT8",
|
||||
"LPT9",
|
||||
}
|
||||
@@ -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">
|
||||
|
||||
@@ -647,14 +647,7 @@ var httpPrefixRE = regexp.MustCompile(`^https?:`)
|
||||
func repoRootForImportPath(importPath string, security web.SecurityMode) (*repoRoot, error) {
|
||||
rr, err := repoRootFromVCSPaths(importPath, "", security, vcsPaths)
|
||||
if err == errUnknownSite {
|
||||
// If there are wildcards, look up the thing before the wildcard,
|
||||
// hoping it applies to the wildcarded parts too.
|
||||
// This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH.
|
||||
lookup := strings.TrimSuffix(importPath, "/...")
|
||||
if i := strings.Index(lookup, "/.../"); i >= 0 {
|
||||
lookup = lookup[:i]
|
||||
}
|
||||
rr, err = repoRootForImportDynamic(lookup, security)
|
||||
rr, err = repoRootForImportDynamic(importPath, security)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unrecognized import path %q (%v)", importPath, err)
|
||||
}
|
||||
@@ -667,6 +660,7 @@ func repoRootForImportPath(importPath string, security web.SecurityMode) (*repoR
|
||||
}
|
||||
}
|
||||
|
||||
// Should have been taken care of above, but make sure.
|
||||
if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.root, "...") {
|
||||
// Do not allow wildcards in the repo root.
|
||||
rr = nil
|
||||
@@ -809,8 +803,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 +818,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
|
||||
@@ -940,10 +964,14 @@ func matchGoImport(imports []metaImport, importPath string) (metaImport, error)
|
||||
|
||||
// expand rewrites s to replace {k} with match[k] for each key k in match.
|
||||
func expand(match map[string]string, s string) string {
|
||||
// We want to replace each match exactly once, and the result of expansion
|
||||
// must not depend on the iteration order through the map.
|
||||
// A strings.Replacer has exactly the properties we're looking for.
|
||||
oldNew := make([]string, 0, 2*len(match))
|
||||
for k, v := range match {
|
||||
s = strings.Replace(s, "{"+k+"}", v, -1)
|
||||
oldNew = append(oldNew, "{"+k+"}", v)
|
||||
}
|
||||
return s
|
||||
return strings.NewReplacer(oldNew...).Replace(s)
|
||||
}
|
||||
|
||||
// vcsPaths defines the meaning of import paths referring to
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -220,7 +220,9 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
|
||||
if len(p.SFiles) > 0 {
|
||||
fmt.Fprintf(h, "asm %q %q %q\n", b.toolID("asm"), forcedAsmflags, p.Internal.Asmflags)
|
||||
}
|
||||
fmt.Fprintf(h, "GO$GOARCH=%s\n", os.Getenv("GO"+strings.ToUpper(cfg.BuildContext.GOARCH))) // GO386, GOARM, etc
|
||||
// GO386, GOARM, GOMIPS, etc.
|
||||
baseArch := strings.TrimSuffix(cfg.BuildContext.GOARCH, "le")
|
||||
fmt.Fprintf(h, "GO$GOARCH=%s\n", os.Getenv("GO"+strings.ToUpper(baseArch)))
|
||||
|
||||
// TODO(rsc): Convince compiler team not to add more magic environment variables,
|
||||
// or perhaps restrict the environment variables passed to subprocesses.
|
||||
@@ -934,16 +936,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 +968,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 +1095,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,77 @@ 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,--(no-)?export-dynamic`),
|
||||
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 +252,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])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -696,9 +696,16 @@ func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
|
||||
o = c.oplook(p)
|
||||
|
||||
/* very large branches */
|
||||
if (o.type_ == 7 || o.type_ == 39) && p.Pcond != nil { // 7: BEQ and like, 39: CBZ and like
|
||||
if (o.type_ == 7 || o.type_ == 39 || o.type_ == 40) && p.Pcond != nil { // 7: BEQ and like, 39: CBZ and like, 40: TBZ and like
|
||||
otxt := p.Pcond.Pc - pc
|
||||
if otxt <= -(1<<18)+10 || otxt >= (1<<18)-10 {
|
||||
var toofar bool
|
||||
switch o.type_ {
|
||||
case 7, 39: // branch instruction encodes 19 bits
|
||||
toofar = otxt <= -(1<<20)+10 || otxt >= (1<<20)-10
|
||||
case 40: // branch instruction encodes 14 bits
|
||||
toofar = otxt <= -(1<<15)+10 || otxt >= (1<<15)-10
|
||||
}
|
||||
if toofar {
|
||||
q := c.newprog()
|
||||
q.Link = p.Link
|
||||
p.Link = q
|
||||
|
||||
@@ -52,6 +52,7 @@ func TestLarge(t *testing.T) {
|
||||
// gen generates a very large program, with a very far conditional branch.
|
||||
func gen(buf *bytes.Buffer) {
|
||||
fmt.Fprintln(buf, "TEXT f(SB),0,$0-0")
|
||||
fmt.Fprintln(buf, "TBZ $5, R0, label")
|
||||
fmt.Fprintln(buf, "CBZ R0, label")
|
||||
fmt.Fprintln(buf, "BEQ label")
|
||||
for i := 0; i < 1<<19; i++ {
|
||||
|
||||
@@ -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
|
||||
@@ -461,14 +461,14 @@ func (ctxt *Link) loadlib() {
|
||||
// recording the value of GOARM.
|
||||
if ctxt.Arch.Family == sys.ARM {
|
||||
s := ctxt.Syms.Lookup("runtime.goarm", 0)
|
||||
s.Type = sym.SRODATA
|
||||
s.Type = sym.SDATA
|
||||
s.Size = 0
|
||||
s.AddUint8(uint8(objabi.GOARM))
|
||||
}
|
||||
|
||||
if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) {
|
||||
s := ctxt.Syms.Lookup("runtime.framepointer_enabled", 0)
|
||||
s.Type = sym.SRODATA
|
||||
s.Type = sym.SDATA
|
||||
s.Size = 0
|
||||
s.AddUint8(1)
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -103,32 +103,57 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
LC_SEGMENT = 0x1
|
||||
LC_SYMTAB = 0x2
|
||||
LC_UNIXTHREAD = 0x5
|
||||
LC_DYSYMTAB = 0xb
|
||||
LC_LOAD_DYLIB = 0xc
|
||||
LC_ID_DYLIB = 0xd
|
||||
LC_LOAD_DYLINKER = 0xe
|
||||
LC_PREBOUND_DYLIB = 0x10
|
||||
LC_LOAD_WEAK_DYLIB = 0x18
|
||||
LC_SEGMENT_64 = 0x19
|
||||
LC_UUID = 0x1b
|
||||
LC_RPATH = 0x8000001c
|
||||
LC_CODE_SIGNATURE = 0x1d
|
||||
LC_SEGMENT_SPLIT_INFO = 0x1e
|
||||
LC_REEXPORT_DYLIB = 0x8000001f
|
||||
LC_ENCRYPTION_INFO = 0x21
|
||||
LC_DYLD_INFO = 0x22
|
||||
LC_DYLD_INFO_ONLY = 0x80000022
|
||||
LC_VERSION_MIN_MACOSX = 0x24
|
||||
LC_VERSION_MIN_IPHONEOS = 0x25
|
||||
LC_FUNCTION_STARTS = 0x26
|
||||
LC_MAIN = 0x80000028
|
||||
LC_DATA_IN_CODE = 0x29
|
||||
LC_SOURCE_VERSION = 0x2A
|
||||
LC_DYLIB_CODE_SIGN_DRS = 0x2B
|
||||
LC_ENCRYPTION_INFO_64 = 0x2C
|
||||
LC_SEGMENT = 0x1
|
||||
LC_SYMTAB = 0x2
|
||||
LC_SYMSEG = 0x3
|
||||
LC_THREAD = 0x4
|
||||
LC_UNIXTHREAD = 0x5
|
||||
LC_LOADFVMLIB = 0x6
|
||||
LC_IDFVMLIB = 0x7
|
||||
LC_IDENT = 0x8
|
||||
LC_FVMFILE = 0x9
|
||||
LC_PREPAGE = 0xa
|
||||
LC_DYSYMTAB = 0xb
|
||||
LC_LOAD_DYLIB = 0xc
|
||||
LC_ID_DYLIB = 0xd
|
||||
LC_LOAD_DYLINKER = 0xe
|
||||
LC_ID_DYLINKER = 0xf
|
||||
LC_PREBOUND_DYLIB = 0x10
|
||||
LC_ROUTINES = 0x11
|
||||
LC_SUB_FRAMEWORK = 0x12
|
||||
LC_SUB_UMBRELLA = 0x13
|
||||
LC_SUB_CLIENT = 0x14
|
||||
LC_SUB_LIBRARY = 0x15
|
||||
LC_TWOLEVEL_HINTS = 0x16
|
||||
LC_PREBIND_CKSUM = 0x17
|
||||
LC_LOAD_WEAK_DYLIB = 0x18
|
||||
LC_SEGMENT_64 = 0x19
|
||||
LC_ROUTINES_64 = 0x1a
|
||||
LC_UUID = 0x1b
|
||||
LC_RPATH = 0x8000001c
|
||||
LC_CODE_SIGNATURE = 0x1d
|
||||
LC_SEGMENT_SPLIT_INFO = 0x1e
|
||||
LC_REEXPORT_DYLIB = 0x8000001f
|
||||
LC_LAZY_LOAD_DYLIB = 0x20
|
||||
LC_ENCRYPTION_INFO = 0x21
|
||||
LC_DYLD_INFO = 0x22
|
||||
LC_DYLD_INFO_ONLY = 0x80000022
|
||||
LC_LOAD_UPWARD_DYLIB = 0x80000023
|
||||
LC_VERSION_MIN_MACOSX = 0x24
|
||||
LC_VERSION_MIN_IPHONEOS = 0x25
|
||||
LC_FUNCTION_STARTS = 0x26
|
||||
LC_DYLD_ENVIRONMENT = 0x27
|
||||
LC_MAIN = 0x80000028
|
||||
LC_DATA_IN_CODE = 0x29
|
||||
LC_SOURCE_VERSION = 0x2A
|
||||
LC_DYLIB_CODE_SIGN_DRS = 0x2B
|
||||
LC_ENCRYPTION_INFO_64 = 0x2C
|
||||
LC_LINKER_OPTION = 0x2D
|
||||
LC_LINKER_OPTIMIZATION_HINT = 0x2E
|
||||
LC_VERSION_MIN_TVOS = 0x2F
|
||||
LC_VERSION_MIN_WATCHOS = 0x30
|
||||
LC_VERSION_NOTE = 0x31
|
||||
LC_BUILD_VERSION = 0x32
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -221,7 +221,7 @@ func machoCombineDwarf(inexe, dsym, outexe string, buildmode BuildMode) error {
|
||||
err = machoUpdateLoadCommand(reader, &linkEditDataCmd{}, "DataOff")
|
||||
case LC_ENCRYPTION_INFO, LC_ENCRYPTION_INFO_64:
|
||||
err = machoUpdateLoadCommand(reader, &encryptionInfoCmd{}, "CryptOff")
|
||||
case macho.LoadCmdDylib, macho.LoadCmdThread, macho.LoadCmdUnixThread, LC_PREBOUND_DYLIB, LC_UUID, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_SOURCE_VERSION, LC_MAIN, LC_LOAD_DYLINKER, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_RPATH, LC_ID_DYLIB:
|
||||
case macho.LoadCmdDylib, macho.LoadCmdThread, macho.LoadCmdUnixThread, LC_PREBOUND_DYLIB, LC_UUID, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_SOURCE_VERSION, LC_MAIN, LC_LOAD_DYLINKER, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_RPATH, LC_ID_DYLIB, LC_SYMSEG, LC_LOADFVMLIB, LC_IDFVMLIB, LC_IDENT, LC_FVMFILE, LC_PREPAGE, LC_ID_DYLINKER, LC_ROUTINES, LC_SUB_FRAMEWORK, LC_SUB_UMBRELLA, LC_SUB_CLIENT, LC_SUB_LIBRARY, LC_TWOLEVEL_HINTS, LC_PREBIND_CKSUM, LC_ROUTINES_64, LC_LAZY_LOAD_DYLIB, LC_LOAD_UPWARD_DYLIB, LC_DYLD_ENVIRONMENT, LC_LINKER_OPTION, LC_LINKER_OPTIMIZATION_HINT, LC_VERSION_MIN_TVOS, LC_VERSION_MIN_WATCHOS, LC_VERSION_NOTE, LC_BUILD_VERSION:
|
||||
// Nothing to update
|
||||
default:
|
||||
err = fmt.Errorf("Unknown load command 0x%x (%s)\n", int(cmd.Cmd), cmd.Cmd)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// iteration over encoded pcdata tables.
|
||||
@@ -162,13 +163,15 @@ func renumberfiles(ctxt *Link, files []*sym.Symbol, d *sym.Pcdata) {
|
||||
*d = out
|
||||
}
|
||||
|
||||
// onlycsymbol reports whether this is a cgo symbol provided by the
|
||||
// runtime and only used from C code.
|
||||
// onlycsymbol reports whether this is a symbol that is referenced by C code.
|
||||
func onlycsymbol(s *sym.Symbol) bool {
|
||||
switch s.Name {
|
||||
case "_cgo_topofstack", "_cgo_panic", "crosscall2":
|
||||
return true
|
||||
}
|
||||
if strings.HasPrefix(s.Name, "_cgoexp_") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -312,12 +315,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)
|
||||
|
||||
@@ -210,8 +210,9 @@ func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int,
|
||||
|
||||
x3 := new(big.Int).Mul(alpha, alpha)
|
||||
beta8 := new(big.Int).Lsh(beta, 3)
|
||||
beta8.Mod(beta8, curve.P)
|
||||
x3.Sub(x3, beta8)
|
||||
for x3.Sign() == -1 {
|
||||
if x3.Sign() == -1 {
|
||||
x3.Add(x3, curve.P)
|
||||
}
|
||||
x3.Mod(x3, curve.P)
|
||||
|
||||
@@ -38,32 +38,16 @@ func SystemCertPool() (*CertPool, error) {
|
||||
return loadSystemRoots()
|
||||
}
|
||||
|
||||
// findVerifiedParents attempts to find certificates in s which have signed the
|
||||
// given certificate. If any candidates were rejected then errCert will be set
|
||||
// to one of them, arbitrarily, and err will contain the reason that it was
|
||||
// rejected.
|
||||
func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCert *Certificate, err error) {
|
||||
// findPotentialParents returns the indexes of certificates in s which might
|
||||
// have signed cert. The caller must not modify the returned slice.
|
||||
func (s *CertPool) findPotentialParents(cert *Certificate) []int {
|
||||
if s == nil {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
var candidates []int
|
||||
|
||||
if len(cert.AuthorityKeyId) > 0 {
|
||||
candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
|
||||
return s.bySubjectKeyId[string(cert.AuthorityKeyId)]
|
||||
}
|
||||
if len(candidates) == 0 {
|
||||
candidates = s.byName[string(cert.RawIssuer)]
|
||||
}
|
||||
|
||||
for _, c := range candidates {
|
||||
if err = cert.CheckSignatureFrom(s.certs[c]); err == nil {
|
||||
parents = append(parents, c)
|
||||
} else {
|
||||
errCert = s.certs[c]
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
return s.byName[string(cert.RawIssuer)]
|
||||
}
|
||||
|
||||
func (s *CertPool) contains(cert *Certificate) bool {
|
||||
|
||||
@@ -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,46 +761,38 @@ 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})
|
||||
} else {
|
||||
if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil {
|
||||
if candidateChains, err = c.buildChains(nil, []*Certificate{c}, nil, &opts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -879,58 +802,74 @@ func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate
|
||||
return n
|
||||
}
|
||||
|
||||
func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
|
||||
possibleRoots, failedRoot, rootErr := opts.Roots.findVerifiedParents(c)
|
||||
nextRoot:
|
||||
for _, rootNum := range possibleRoots {
|
||||
root := opts.Roots.certs[rootNum]
|
||||
// maxChainSignatureChecks is the maximum number of CheckSignatureFrom calls
|
||||
// that an invocation of buildChains will (tranistively) make. Most chains are
|
||||
// less than 15 certificates long, so this leaves space for multiple chains and
|
||||
// for failed checks due to different intermediates having the same Subject.
|
||||
const maxChainSignatureChecks = 100
|
||||
|
||||
func (c *Certificate) buildChains(cache map[*Certificate][][]*Certificate, currentChain []*Certificate, sigChecks *int, opts *VerifyOptions) (chains [][]*Certificate, err error) {
|
||||
var (
|
||||
hintErr error
|
||||
hintCert *Certificate
|
||||
)
|
||||
|
||||
considerCandidate := func(certType int, candidate *Certificate) {
|
||||
for _, cert := range currentChain {
|
||||
if cert.Equal(root) {
|
||||
continue nextRoot
|
||||
if cert.Equal(candidate) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = root.isValid(rootCertificate, currentChain, opts)
|
||||
if err != nil {
|
||||
continue
|
||||
if sigChecks == nil {
|
||||
sigChecks = new(int)
|
||||
}
|
||||
*sigChecks++
|
||||
if *sigChecks > maxChainSignatureChecks {
|
||||
err = errors.New("x509: signature check attempts limit reached while verifying certificate chain")
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.CheckSignatureFrom(candidate); err != nil {
|
||||
if hintErr == nil {
|
||||
hintErr = err
|
||||
hintCert = candidate
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
err = candidate.isValid(certType, currentChain, opts)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch certType {
|
||||
case rootCertificate:
|
||||
chains = append(chains, appendToFreshChain(currentChain, candidate))
|
||||
case intermediateCertificate:
|
||||
if cache == nil {
|
||||
cache = make(map[*Certificate][][]*Certificate)
|
||||
}
|
||||
childChains, ok := cache[candidate]
|
||||
if !ok {
|
||||
childChains, err = candidate.buildChains(cache, appendToFreshChain(currentChain, candidate), sigChecks, opts)
|
||||
cache[candidate] = childChains
|
||||
}
|
||||
chains = append(chains, childChains...)
|
||||
}
|
||||
chains = append(chains, appendToFreshChain(currentChain, root))
|
||||
}
|
||||
|
||||
possibleIntermediates, failedIntermediate, intermediateErr := opts.Intermediates.findVerifiedParents(c)
|
||||
nextIntermediate:
|
||||
for _, intermediateNum := range possibleIntermediates {
|
||||
intermediate := opts.Intermediates.certs[intermediateNum]
|
||||
for _, cert := range currentChain {
|
||||
if cert.Equal(intermediate) {
|
||||
continue nextIntermediate
|
||||
}
|
||||
}
|
||||
err = intermediate.isValid(intermediateCertificate, currentChain, opts)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
var childChains [][]*Certificate
|
||||
childChains, ok := cache[intermediateNum]
|
||||
if !ok {
|
||||
childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts)
|
||||
cache[intermediateNum] = childChains
|
||||
}
|
||||
chains = append(chains, childChains...)
|
||||
for _, rootNum := range opts.Roots.findPotentialParents(c) {
|
||||
considerCandidate(rootCertificate, opts.Roots.certs[rootNum])
|
||||
}
|
||||
for _, intermediateNum := range opts.Intermediates.findPotentialParents(c) {
|
||||
considerCandidate(intermediateCertificate, opts.Intermediates.certs[intermediateNum])
|
||||
}
|
||||
|
||||
if len(chains) > 0 {
|
||||
err = nil
|
||||
}
|
||||
|
||||
if len(chains) == 0 && err == nil {
|
||||
hintErr := rootErr
|
||||
hintCert := failedRoot
|
||||
if hintErr == nil {
|
||||
hintErr = intermediateErr
|
||||
hintCert = failedIntermediate
|
||||
}
|
||||
err = UnknownAuthorityError{c, hintErr, hintCert}
|
||||
}
|
||||
|
||||
@@ -1030,3 +969,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
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user