mirror of
https://github.com/golang/go.git
synced 2026-01-31 08:02:06 +03:00
Compare commits
132 Commits
dev.corety
...
go1.24rc2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a4c24f9bb | ||
|
|
3de5aca7d0 | ||
|
|
8336dfde70 | ||
|
|
6b60550504 | ||
|
|
468fad45a2 | ||
|
|
e06b6fc58d | ||
|
|
e966a2773c | ||
|
|
b3799ba634 | ||
|
|
9a44df6675 | ||
|
|
f025d19e7b | ||
|
|
1e9835f5b1 | ||
|
|
39f2032c17 | ||
|
|
b50ccef67a | ||
|
|
b2aa18b96c | ||
|
|
d93b549f05 | ||
|
|
d62154db83 | ||
|
|
9d0772b23e | ||
|
|
1d20bce981 | ||
|
|
a9bd6239a4 | ||
|
|
850b276a67 | ||
|
|
27c5164374 | ||
|
|
d8ad4af78b | ||
|
|
a76cc5a4ec | ||
|
|
3f002abb60 | ||
|
|
7a2e88e911 | ||
|
|
c112c0af13 | ||
|
|
705b5a569a | ||
|
|
f966695cce | ||
|
|
5da026354c | ||
|
|
31cabcf084 | ||
|
|
eb0c2b2f96 | ||
|
|
f0a9b6df45 | ||
|
|
5d626c49ec | ||
|
|
81566aff3a | ||
|
|
e7a8bd5d8b | ||
|
|
4b652e9f5f | ||
|
|
0afd7e85e5 | ||
|
|
3c8e5b13df | ||
|
|
20da34c6d2 | ||
|
|
858a0e9dfd | ||
|
|
a63aee4955 | ||
|
|
847c357bbb | ||
|
|
d1d9312950 | ||
|
|
94f15810e6 | ||
|
|
856a7bc8e9 | ||
|
|
5efb4239c6 | ||
|
|
0d8aa8cce6 | ||
|
|
8857a5a33f | ||
|
|
3c4102bfd4 | ||
|
|
b702a26cf8 | ||
|
|
15f232456a | ||
|
|
ba1deb1cee | ||
|
|
fd5e0d26d9 | ||
|
|
a785d11ac4 | ||
|
|
2b794ed86c | ||
|
|
e3cd55e9d2 | ||
|
|
39794819aa | ||
|
|
7c03fe70b8 | ||
|
|
d7c3e93c16 | ||
|
|
cce75da30b | ||
|
|
772f024c61 | ||
|
|
b9955f0ad9 | ||
|
|
eef35e3bd9 | ||
|
|
9f6c80a76a | ||
|
|
05d8984781 | ||
|
|
500675a7c8 | ||
|
|
06b191e11f | ||
|
|
110ab1aaf4 | ||
|
|
669d87a935 | ||
|
|
45f49139f5 | ||
|
|
e63eb98e98 | ||
|
|
7b6c94dd03 | ||
|
|
cb72406c36 | ||
|
|
4f0561f9d3 | ||
|
|
87dbfb9fa7 | ||
|
|
f4e3ec3dbe | ||
|
|
6aa46eb750 | ||
|
|
10ca5ba4ff | ||
|
|
8ff4cee564 | ||
|
|
971448ddf8 | ||
|
|
95b433eed4 | ||
|
|
b2c0168893 | ||
|
|
b9e2ffdcd2 | ||
|
|
8790372a8d | ||
|
|
b057b8872d | ||
|
|
e977b83b32 | ||
|
|
4ac8f552e9 | ||
|
|
236a0b4ffb | ||
|
|
9f806bb76c | ||
|
|
0cd833d198 | ||
|
|
31e50af5f3 | ||
|
|
b47ce8b0e9 | ||
|
|
dd7a7ba38f | ||
|
|
427a2401af | ||
|
|
75736cc169 | ||
|
|
1218566fe5 | ||
|
|
d92c34a387 | ||
|
|
3bd08b9792 | ||
|
|
18b5435fc8 | ||
|
|
c1f2542c8b | ||
|
|
6bd56fcaeb | ||
|
|
090748d6c7 | ||
|
|
e39e965e0e | ||
|
|
08770a5b94 | ||
|
|
c4f356dd86 | ||
|
|
08725f9de2 | ||
|
|
1cbfe8c482 | ||
|
|
16afa6a740 | ||
|
|
8391579ece | ||
|
|
80a2982a80 | ||
|
|
38e9a671d7 | ||
|
|
6f7a4540b1 | ||
|
|
14e5093ee5 | ||
|
|
fb764cdad0 | ||
|
|
817d7bdc0a | ||
|
|
9118060040 | ||
|
|
077d51909d | ||
|
|
fafd4477f3 | ||
|
|
14bb1e11b9 | ||
|
|
0ca521f9c1 | ||
|
|
2297c34cdf | ||
|
|
c93477b5e5 | ||
|
|
3104b6adbb | ||
|
|
5424f2e200 | ||
|
|
d5c1333eb4 | ||
|
|
a7c4cadce0 | ||
|
|
979c1cfbe8 | ||
|
|
e424d78c3d | ||
|
|
6c25cf1c5f | ||
|
|
e0c76d95ab | ||
|
|
a9922d096f | ||
|
|
26682773ca |
@@ -106,33 +106,26 @@ pkg debug/elf, const VER_FLG_INFO = 4 #63952
|
||||
pkg debug/elf, const VER_FLG_INFO DynamicVersionFlag #63952
|
||||
pkg debug/elf, const VER_FLG_WEAK = 2 #63952
|
||||
pkg debug/elf, const VER_FLG_WEAK DynamicVersionFlag #63952
|
||||
pkg debug/elf, const VerFlagGlobal = 2 #63952
|
||||
pkg debug/elf, const VerFlagGlobal SymbolVersionFlag #63952
|
||||
pkg debug/elf, const VerFlagHidden = 4 #63952
|
||||
pkg debug/elf, const VerFlagHidden SymbolVersionFlag #63952
|
||||
pkg debug/elf, const VerFlagLocal = 1 #63952
|
||||
pkg debug/elf, const VerFlagLocal SymbolVersionFlag #63952
|
||||
pkg debug/elf, const VerFlagNone = 0 #63952
|
||||
pkg debug/elf, const VerFlagNone SymbolVersionFlag #63952
|
||||
pkg debug/elf, method (*File) DynamicVersionNeeds() ([]DynamicVersionNeed, error) #63952
|
||||
pkg debug/elf, method (*File) DynamicVersions() ([]DynamicVersion, error) #63952
|
||||
pkg debug/elf, type DynamicVersion struct #63952
|
||||
pkg debug/elf, type DynamicVersion struct, Deps []string #63952
|
||||
pkg debug/elf, type DynamicVersion struct, Flags DynamicVersionFlag #63952
|
||||
pkg debug/elf, type DynamicVersion struct, Name string #63952
|
||||
pkg debug/elf, type DynamicVersion struct, Index uint16 #63952
|
||||
pkg debug/elf, type DynamicVersion struct, Version uint16 #63952
|
||||
pkg debug/elf, type DynamicVersionDep struct #63952
|
||||
pkg debug/elf, type DynamicVersionDep struct, Dep string #63952
|
||||
pkg debug/elf, type DynamicVersionDep struct, Flags DynamicVersionFlag #63952
|
||||
pkg debug/elf, type DynamicVersionDep struct, Other uint16 #63952
|
||||
pkg debug/elf, type DynamicVersionDep struct, Index uint16 #63952
|
||||
pkg debug/elf, type DynamicVersionFlag uint16 #63952
|
||||
pkg debug/elf, type DynamicVersionNeed struct #63952
|
||||
pkg debug/elf, type DynamicVersionNeed struct, Name string #63952
|
||||
pkg debug/elf, type DynamicVersionNeed struct, Needs []DynamicVersionDep #63952
|
||||
pkg debug/elf, type DynamicVersionNeed struct, Version uint16 #63952
|
||||
pkg debug/elf, type Symbol struct, VersionFlags SymbolVersionFlag #63952
|
||||
pkg debug/elf, type Symbol struct, VersionIndex int16 #63952
|
||||
pkg debug/elf, type SymbolVersionFlag uint8 #63952
|
||||
pkg debug/elf, type Symbol struct, HasVersion bool #63952
|
||||
pkg debug/elf, type Symbol struct, VersionIndex VersionIndex #63952
|
||||
pkg debug/elf, method (VersionIndex) Index() uint16 #63952
|
||||
pkg debug/elf, method (VersionIndex) IsHidden() bool #63952
|
||||
pkg debug/elf, type VersionIndex uint16 #63952
|
||||
pkg encoding, type BinaryAppender interface { AppendBinary } #62384
|
||||
pkg encoding, type BinaryAppender interface, AppendBinary([]uint8) ([]uint8, error) #62384
|
||||
pkg encoding, type TextAppender interface { AppendText } #62384
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
branch: master
|
||||
branch: release-branch.go1.24
|
||||
parent-branch: master
|
||||
|
||||
243
doc/go_spec.html
243
doc/go_spec.html
@@ -1,6 +1,6 @@
|
||||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Language version go1.24 (Nov 20, 2024)",
|
||||
"Subtitle": "Language version go1.24 (Dec 30, 2024)",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
@@ -798,7 +798,6 @@ If a variable has not yet been assigned a value, its value is the
|
||||
<a href="#The_zero_value">zero value</a> for its type.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="Types">Types</h2>
|
||||
|
||||
<p>
|
||||
@@ -810,12 +809,12 @@ from existing types.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
Type = TypeName [ TypeArgs ] | TypeLit | "(" Type ")" .
|
||||
TypeName = identifier | QualifiedIdent .
|
||||
TypeArgs = "[" TypeList [ "," ] "]" .
|
||||
TypeList = Type { "," Type } .
|
||||
TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
|
||||
SliceType | MapType | ChannelType .
|
||||
Type = TypeName [ TypeArgs ] | TypeLit | "(" Type ")" .
|
||||
TypeName = identifier | QualifiedIdent .
|
||||
TypeArgs = "[" TypeList [ "," ] "]" .
|
||||
TypeList = Type { "," Type } .
|
||||
TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
|
||||
SliceType | MapType | ChannelType .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -1200,7 +1199,7 @@ type (
|
||||
<p>
|
||||
A pointer type denotes the set of all pointers to <a href="#Variables">variables</a> of a given
|
||||
type, called the <i>base type</i> of the pointer.
|
||||
The value of an uninitialized pointer is <code>nil</code>.
|
||||
The <a href="#Representation_of_values">value</a> of an uninitialized pointer is <code>nil</code>.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
@@ -1216,18 +1215,18 @@ BaseType = Type .
|
||||
<h3 id="Function_types">Function types</h3>
|
||||
|
||||
<p>
|
||||
A function type denotes the set of all functions with the same parameter
|
||||
and result types. The value of an uninitialized variable of function type
|
||||
is <code>nil</code>.
|
||||
A function type denotes the set of all functions with the same parameter and result types.
|
||||
The <a href="#Representation_of_values">value</a> of an uninitialized variable of function
|
||||
type is <code>nil</code>.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
FunctionType = "func" Signature .
|
||||
Signature = Parameters [ Result ] .
|
||||
Result = Parameters | Type .
|
||||
Parameters = "(" [ ParameterList [ "," ] ] ")" .
|
||||
ParameterList = ParameterDecl { "," ParameterDecl } .
|
||||
ParameterDecl = [ IdentifierList ] [ "..." ] Type .
|
||||
FunctionType = "func" Signature .
|
||||
Signature = Parameters [ Result ] .
|
||||
Result = Parameters | Type .
|
||||
Parameters = "(" [ ParameterList [ "," ] ] ")" .
|
||||
ParameterList = ParameterDecl { "," ParameterDecl } .
|
||||
ParameterDecl = [ IdentifierList ] [ "..." ] Type .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -1267,7 +1266,8 @@ An interface type defines a <i>type set</i>.
|
||||
A variable of interface type can store a value of any type that is in the type
|
||||
set of the interface. Such a type is said to
|
||||
<a href="#Implementing_an_interface">implement the interface</a>.
|
||||
The value of an uninitialized variable of interface type is <code>nil</code>.
|
||||
The <a href="#Representation_of_values">value</a> of an uninitialized variable of
|
||||
interface type is <code>nil</code>.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
@@ -1630,12 +1630,12 @@ implements the interface.
|
||||
A map is an unordered group of elements of one type, called the
|
||||
element type, indexed by a set of unique <i>keys</i> of another type,
|
||||
called the key type.
|
||||
The value of an uninitialized map is <code>nil</code>.
|
||||
The <a href="#Representation_of_values">value</a> of an uninitialized map is <code>nil</code>.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
MapType = "map" "[" KeyType "]" ElementType .
|
||||
KeyType = Type .
|
||||
MapType = "map" "[" KeyType "]" ElementType .
|
||||
KeyType = Type .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -1693,7 +1693,7 @@ to communicate by
|
||||
<a href="#Send_statements">sending</a> and
|
||||
<a href="#Receive_operator">receiving</a>
|
||||
values of a specified element type.
|
||||
The value of an uninitialized channel is <code>nil</code>.
|
||||
The <a href="#Representation_of_values">value</a> of an uninitialized channel is <code>nil</code>.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
@@ -1772,6 +1772,57 @@ received in the order sent.
|
||||
|
||||
<h2 id="Properties_of_types_and_values">Properties of types and values</h2>
|
||||
|
||||
<h3 id="Representation_of_values">Representation of values</h3>
|
||||
|
||||
<p>
|
||||
Values of predeclared types (see below for the interfaces <code>any</code>
|
||||
and <code>error</code>), arrays, and structs are self-contained:
|
||||
Each such value contains a complete copy of all its data,
|
||||
and <a href="#Variables">variables</a> of such types store the entire value.
|
||||
For instance, an array variable provides the storage (the variables)
|
||||
for all elements of the array.
|
||||
The respective <a href="#The_zero_value">zero values</a> are specific to the
|
||||
value's types; they are never <code>nil</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Non-nil pointer, function, slice, map, and channel values contain references
|
||||
to underlying data which may be shared by multiple values:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
A pointer value is a reference to the variable holding
|
||||
the pointer base type value.
|
||||
</li>
|
||||
<li>
|
||||
A function value contains references to the (possibly
|
||||
<a href="#Function_literals">anonymous</a>) function
|
||||
and enclosed variables.
|
||||
</li>
|
||||
<li>
|
||||
A slice value contains the slice length, capacity, and
|
||||
a reference to its <a href="#Slice_types">underlying array</a>.
|
||||
</li>
|
||||
<li>
|
||||
A map or channel value is a reference to the implementation-specific
|
||||
data structure of the map or channel.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
An interface value may be self-contained or contain references to underlying data
|
||||
depending on the interface's <a href="#Variables">dynamic type</a>.
|
||||
The predeclared identifier <code>nil</code> is the zero value for types whose values
|
||||
can contain references.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When multiple values share underlying data, changing one value may change another.
|
||||
For instance, changing an element of a <a href="#Slice_types">slice</a> will change
|
||||
that element in the underlying array for all slices that share the array.
|
||||
</p>
|
||||
|
||||
<h3 id="Underlying_types">Underlying types</h3>
|
||||
|
||||
<p>
|
||||
@@ -2176,7 +2227,7 @@ within matching brace brackets.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
Block = "{" StatementList "}" .
|
||||
Block = "{" StatementList "}" .
|
||||
StatementList = { Statement ";" } .
|
||||
</pre>
|
||||
|
||||
@@ -2233,8 +2284,8 @@ and like the blank identifier it does not introduce a new binding.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
Declaration = ConstDecl | TypeDecl | VarDecl .
|
||||
TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
|
||||
Declaration = ConstDecl | TypeDecl | VarDecl .
|
||||
TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -2679,9 +2730,9 @@ in square brackets rather than parentheses
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
TypeParameters = "[" TypeParamList [ "," ] "]" .
|
||||
TypeParamList = TypeParamDecl { "," TypeParamDecl } .
|
||||
TypeParamDecl = IdentifierList TypeConstraint .
|
||||
TypeParameters = "[" TypeParamList [ "," ] "]" .
|
||||
TypeParamList = TypeParamDecl { "," TypeParamDecl } .
|
||||
TypeParamDecl = IdentifierList TypeConstraint .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -2819,7 +2870,7 @@ values or variables, or components of other, non-interface types.
|
||||
|
||||
<p>
|
||||
A type argument <code>T</code><i> satisfies</i> a type constraint <code>C</code>
|
||||
if <code>T</code> is an element of the type set defined by <code>C</code>; i.e.,
|
||||
if <code>T</code> is an element of the type set defined by <code>C</code>; in other words,
|
||||
if <code>T</code> <a href="#Implementing_an_interface">implements</a> <code>C</code>.
|
||||
As an exception, a <a href="#Comparison_operators">strictly comparable</a>
|
||||
type constraint may also be satisfied by a <a href="#Comparison_operators">comparable</a>
|
||||
@@ -2869,8 +2920,8 @@ binds corresponding identifiers to them, and gives each a type and an initial va
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
|
||||
VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
|
||||
VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
|
||||
VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
@@ -2899,7 +2950,7 @@ initialization value in the assignment.
|
||||
If that value is an untyped constant, it is first implicitly
|
||||
<a href="#Conversions">converted</a> to its <a href="#Constants">default type</a>;
|
||||
if it is an untyped boolean value, it is first implicitly converted to type <code>bool</code>.
|
||||
The predeclared value <code>nil</code> cannot be used to initialize a variable
|
||||
The predeclared identifier <code>nil</code> cannot be used to initialize a variable
|
||||
with no explicit type.
|
||||
</p>
|
||||
|
||||
@@ -3210,15 +3261,15 @@ Each element may optionally be preceded by a corresponding key.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
CompositeLit = LiteralType LiteralValue .
|
||||
LiteralType = StructType | ArrayType | "[" "..." "]" ElementType |
|
||||
SliceType | MapType | TypeName [ TypeArgs ] .
|
||||
LiteralValue = "{" [ ElementList [ "," ] ] "}" .
|
||||
ElementList = KeyedElement { "," KeyedElement } .
|
||||
KeyedElement = [ Key ":" ] Element .
|
||||
Key = FieldName | Expression | LiteralValue .
|
||||
FieldName = identifier .
|
||||
Element = Expression | LiteralValue .
|
||||
CompositeLit = LiteralType LiteralValue .
|
||||
LiteralType = StructType | ArrayType | "[" "..." "]" ElementType |
|
||||
SliceType | MapType | TypeName [ TypeArgs ] .
|
||||
LiteralValue = "{" [ ElementList [ "," ] ] "}" .
|
||||
ElementList = KeyedElement { "," KeyedElement } .
|
||||
KeyedElement = [ Key ":" ] Element .
|
||||
Key = FieldName | Expression | LiteralValue .
|
||||
FieldName = identifier .
|
||||
Element = Expression | LiteralValue .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -3450,22 +3501,21 @@ Primary expressions are the operands for unary and binary expressions.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
PrimaryExpr =
|
||||
Operand |
|
||||
Conversion |
|
||||
MethodExpr |
|
||||
PrimaryExpr Selector |
|
||||
PrimaryExpr Index |
|
||||
PrimaryExpr Slice |
|
||||
PrimaryExpr TypeAssertion |
|
||||
PrimaryExpr Arguments .
|
||||
PrimaryExpr = Operand |
|
||||
Conversion |
|
||||
MethodExpr |
|
||||
PrimaryExpr Selector |
|
||||
PrimaryExpr Index |
|
||||
PrimaryExpr Slice |
|
||||
PrimaryExpr TypeAssertion |
|
||||
PrimaryExpr Arguments .
|
||||
|
||||
Selector = "." identifier .
|
||||
Index = "[" Expression [ "," ] "]" .
|
||||
Slice = "[" [ Expression ] ":" [ Expression ] "]" |
|
||||
"[" [ Expression ] ":" Expression ":" Expression "]" .
|
||||
TypeAssertion = "." "(" Type ")" .
|
||||
Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
|
||||
Selector = "." identifier .
|
||||
Index = "[" Expression [ "," ] "]" .
|
||||
Slice = "[" [ Expression ] ":" [ Expression ] "]" |
|
||||
"[" [ Expression ] ":" Expression ":" Expression "]" .
|
||||
TypeAssertion = "." "(" Type ")" .
|
||||
Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
|
||||
</pre>
|
||||
|
||||
|
||||
@@ -3638,8 +3688,8 @@ argument that is the receiver of the method.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
MethodExpr = ReceiverType "." MethodName .
|
||||
ReceiverType = Type .
|
||||
MethodExpr = ReceiverType "." MethodName .
|
||||
ReceiverType = Type .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -4230,8 +4280,7 @@ calls <code>f</code> with arguments <code>a1, a2, … an</code>.
|
||||
Except for one special case, arguments must be single-valued expressions
|
||||
<a href="#Assignability">assignable</a> to the parameter types of
|
||||
<code>F</code> and are evaluated before the function is called.
|
||||
The type of the expression is the result type
|
||||
of <code>F</code>.
|
||||
The type of the expression is the result type of <code>F</code>.
|
||||
A method invocation is similar but the method itself
|
||||
is specified as a selector upon a value of the receiver type for
|
||||
the method.
|
||||
@@ -4252,9 +4301,14 @@ or used as a function value.
|
||||
<p>
|
||||
In a function call, the function value and arguments are evaluated in
|
||||
<a href="#Order_of_evaluation">the usual order</a>.
|
||||
After they are evaluated, the parameters of the call are passed by value to the function
|
||||
After they are evaluated, new storage is allocated for the function's
|
||||
<a href="#Variables">variables</a>, which includes its parameters
|
||||
and results.
|
||||
Then, the arguments of the call are <i>passed</i> to the function,
|
||||
which means that they are <a href="#Assignment_statements">assigned</a>
|
||||
to their corresponding function parameters,
|
||||
and the called function begins execution.
|
||||
The return parameters of the function are passed by value
|
||||
The return parameters of the function are passed
|
||||
back to the caller when the function returns.
|
||||
</p>
|
||||
|
||||
@@ -4268,9 +4322,9 @@ As a special case, if the return values of a function or method
|
||||
<code>g</code> are equal in number and individually
|
||||
assignable to the parameters of another function or method
|
||||
<code>f</code>, then the call <code>f(g(<i>parameters_of_g</i>))</code>
|
||||
will invoke <code>f</code> after binding the return values of
|
||||
<code>g</code> to the parameters of <code>f</code> in order. The call
|
||||
of <code>f</code> must contain no parameters other than the call of <code>g</code>,
|
||||
will invoke <code>f</code> after passing the return values of
|
||||
<code>g</code> to the parameters of <code>f</code> in order.
|
||||
The call of <code>f</code> must contain no parameters other than the call of <code>g</code>,
|
||||
and <code>g</code> must have at least one return value.
|
||||
If <code>f</code> has a final <code>...</code> parameter, it is
|
||||
assigned the return values of <code>g</code> that remain after
|
||||
@@ -4316,7 +4370,7 @@ If <code>f</code> is <a href="#Function_types">variadic</a> with a final
|
||||
parameter <code>p</code> of type <code>...T</code>, then within <code>f</code>
|
||||
the type of <code>p</code> is equivalent to type <code>[]T</code>.
|
||||
If <code>f</code> is invoked with no actual arguments for <code>p</code>,
|
||||
the value passed to <code>p</code> is <code>nil</code>.
|
||||
the value <a href="#Calls">passed</a> to <code>p</code> is <code>nil</code>.
|
||||
Otherwise, the value passed is a new slice
|
||||
of type <code>[]T</code> with a new underlying array whose successive elements
|
||||
are the actual arguments, which all must be <a href="#Assignability">assignable</a>
|
||||
@@ -5632,6 +5686,8 @@ myString([]myRune{0x1f30e}) // "\U0001f30e" == "🌎"
|
||||
<li>
|
||||
Converting a value of a string type to a slice of bytes type
|
||||
yields a non-nil slice whose successive elements are the bytes of the string.
|
||||
The <a href="#Length_and_capacity">capacity</a> of the resulting slice is
|
||||
implementation-specific and may be larger than the slice length.
|
||||
|
||||
<pre>
|
||||
[]byte("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
|
||||
@@ -5647,6 +5703,8 @@ bytes("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
|
||||
<li>
|
||||
Converting a value of a string type to a slice of runes type
|
||||
yields a slice containing the individual Unicode code points of the string.
|
||||
The <a href="#Length_and_capacity">capacity</a> of the resulting slice is
|
||||
implementation-specific and may be larger than the slice length.
|
||||
|
||||
<pre>
|
||||
[]rune(myString("白鵬翔")) // []rune{0x767d, 0x9d6c, 0x7fd4}
|
||||
@@ -5848,7 +5906,7 @@ Otherwise, when evaluating the <a href="#Operands">operands</a> of an
|
||||
expression, assignment, or
|
||||
<a href="#Return_statements">return statement</a>,
|
||||
all function calls, method calls,
|
||||
<a href="#Receive operator">receive operations</a>,
|
||||
<a href="#Receive_operator">receive operations</a>,
|
||||
and <a href="#Logical_operators">binary logical operations</a>
|
||||
are evaluated in lexical left-to-right order.
|
||||
</p>
|
||||
@@ -5916,11 +5974,10 @@ Statements control execution.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
Statement =
|
||||
Declaration | LabeledStmt | SimpleStmt |
|
||||
GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
|
||||
FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt |
|
||||
DeferStmt .
|
||||
Statement = Declaration | LabeledStmt | SimpleStmt |
|
||||
GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
|
||||
FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt |
|
||||
DeferStmt .
|
||||
|
||||
SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl .
|
||||
</pre>
|
||||
@@ -6132,7 +6189,7 @@ matching number of variables.
|
||||
<pre class="ebnf">
|
||||
Assignment = ExpressionList assign_op ExpressionList .
|
||||
|
||||
assign_op = [ add_op | mul_op ] "=" .
|
||||
assign_op = [ add_op | mul_op ] "=" .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -6261,6 +6318,26 @@ to the type of the operand to which it is assigned, with the following special c
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
When a value is assigned to a variable, only the data that is stored in the variable
|
||||
is replaced. If the value contains a <a href="#Representation_of_values">reference</a>,
|
||||
the assignment copies the reference but does not make a copy of the referenced data
|
||||
(such as the underlying array of a slice).
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var s1 = []int{1, 2, 3}
|
||||
var s2 = s1 // s2 stores the slice descriptor of s1
|
||||
s1 = s1[:1] // s1's length is 1 but it still shares its underlying array with s2
|
||||
s2[0] = 42 // setting s2[0] changes s1[0] as well
|
||||
fmt.Println(s1, s2) // prints [42] [42 2 3]
|
||||
|
||||
var m1 = make(map[string]int)
|
||||
var m2 = m1 // m2 stores the map descriptor of m1
|
||||
m1["foo"] = 42 // setting m1["foo"] changes m2["foo"] as well
|
||||
fmt.Println(m2["foo"]) // prints 42
|
||||
</pre>
|
||||
|
||||
<h3 id="If_statements">If statements</h3>
|
||||
|
||||
<p>
|
||||
@@ -6548,7 +6625,7 @@ The iteration may be controlled by a single condition, a "for" clause, or a "ran
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
|
||||
ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
|
||||
Condition = Expression .
|
||||
</pre>
|
||||
|
||||
@@ -6580,8 +6657,8 @@ an increment or decrement statement. The init statement may be a
|
||||
|
||||
<pre class="ebnf">
|
||||
ForClause = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] .
|
||||
InitStmt = SimpleStmt .
|
||||
PostStmt = SimpleStmt .
|
||||
InitStmt = SimpleStmt .
|
||||
PostStmt = SimpleStmt .
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
@@ -7909,7 +7986,7 @@ types, variables, and constants.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
|
||||
SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
|
||||
</pre>
|
||||
|
||||
<h3 id="Package_clause">Package clause</h3>
|
||||
@@ -7920,8 +7997,8 @@ to which the file belongs.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
PackageClause = "package" PackageName .
|
||||
PackageName = identifier .
|
||||
PackageClause = "package" PackageName .
|
||||
PackageName = identifier .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -7950,9 +8027,9 @@ that specifies the package to be imported.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
|
||||
ImportSpec = [ "." | PackageName ] ImportPath .
|
||||
ImportPath = string_lit .
|
||||
ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
|
||||
ImportSpec = [ "." | PackageName ] ImportPath .
|
||||
ImportPath = string_lit .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
<!--
|
||||
NOTE: In this document and others in this directory, the convention is to
|
||||
set fixed-width phrases with non-fixed-width spaces, as in
|
||||
`hello` `world`.
|
||||
-->
|
||||
|
||||
<style>
|
||||
main ul li { margin: 0.5em 0; }
|
||||
</style>
|
||||
|
||||
@@ -162,12 +162,12 @@ func delete(m map[Type]Type1, key Type)
|
||||
|
||||
// The len built-in function returns the length of v, according to its type:
|
||||
//
|
||||
// Array: the number of elements in v.
|
||||
// Pointer to array: the number of elements in *v (even if v is nil).
|
||||
// Slice, or map: the number of elements in v; if v is nil, len(v) is zero.
|
||||
// String: the number of bytes in v.
|
||||
// Channel: the number of elements queued (unread) in the channel buffer;
|
||||
// if v is nil, len(v) is zero.
|
||||
// - Array: the number of elements in v.
|
||||
// - Pointer to array: the number of elements in *v (even if v is nil).
|
||||
// - Slice, or map: the number of elements in v; if v is nil, len(v) is zero.
|
||||
// - String: the number of bytes in v.
|
||||
// - Channel: the number of elements queued (unread) in the channel buffer;
|
||||
// if v is nil, len(v) is zero.
|
||||
//
|
||||
// For some arguments, such as a string literal or a simple array expression, the
|
||||
// result can be a constant. See the Go language specification's "Length and
|
||||
@@ -176,12 +176,12 @@ func len(v Type) int
|
||||
|
||||
// The cap built-in function returns the capacity of v, according to its type:
|
||||
//
|
||||
// Array: the number of elements in v (same as len(v)).
|
||||
// Pointer to array: the number of elements in *v (same as len(v)).
|
||||
// Slice: the maximum length the slice can reach when resliced;
|
||||
// if v is nil, cap(v) is zero.
|
||||
// Channel: the channel buffer capacity, in units of elements;
|
||||
// if v is nil, cap(v) is zero.
|
||||
// - Array: the number of elements in v (same as len(v)).
|
||||
// - Pointer to array: the number of elements in *v (same as len(v)).
|
||||
// - Slice: the maximum length the slice can reach when resliced;
|
||||
// if v is nil, cap(v) is zero.
|
||||
// - Channel: the channel buffer capacity, in units of elements;
|
||||
// if v is nil, cap(v) is zero.
|
||||
//
|
||||
// For some arguments, such as a simple array expression, the result can be a
|
||||
// constant. See the Go language specification's "Length and capacity" section for
|
||||
@@ -194,18 +194,18 @@ func cap(v Type) int
|
||||
// argument, not a pointer to it. The specification of the result depends on
|
||||
// the type:
|
||||
//
|
||||
// Slice: The size specifies the length. The capacity of the slice is
|
||||
// equal to its length. A second integer argument may be provided to
|
||||
// specify a different capacity; it must be no smaller than the
|
||||
// length. For example, make([]int, 0, 10) allocates an underlying array
|
||||
// of size 10 and returns a slice of length 0 and capacity 10 that is
|
||||
// backed by this underlying array.
|
||||
// Map: An empty map is allocated with enough space to hold the
|
||||
// specified number of elements. The size may be omitted, in which case
|
||||
// a small starting size is allocated.
|
||||
// Channel: The channel's buffer is initialized with the specified
|
||||
// buffer capacity. If zero, or the size is omitted, the channel is
|
||||
// unbuffered.
|
||||
// - Slice: The size specifies the length. The capacity of the slice is
|
||||
// equal to its length. A second integer argument may be provided to
|
||||
// specify a different capacity; it must be no smaller than the
|
||||
// length. For example, make([]int, 0, 10) allocates an underlying array
|
||||
// of size 10 and returns a slice of length 0 and capacity 10 that is
|
||||
// backed by this underlying array.
|
||||
// - Map: An empty map is allocated with enough space to hold the
|
||||
// specified number of elements. The size may be omitted, in which case
|
||||
// a small starting size is allocated.
|
||||
// - Channel: The channel's buffer is initialized with the specified
|
||||
// buffer capacity. If zero, or the size is omitted, the channel is
|
||||
// unbuffered.
|
||||
func make(t Type, size ...IntegerType) Type
|
||||
|
||||
// The max built-in function returns the largest value of a fixed number of
|
||||
@@ -247,7 +247,7 @@ func imag(c ComplexType) FloatType
|
||||
// to the zero value of the respective element type. If the argument
|
||||
// type is a type parameter, the type parameter's type set must
|
||||
// contain only map or slice types, and clear performs the operation
|
||||
// implied by the type argument.
|
||||
// implied by the type argument. If t is nil, clear is a no-op.
|
||||
func clear[T ~[]Type | ~map[Type]Type1](t T)
|
||||
|
||||
// The close built-in function closes a channel, which must be either
|
||||
|
||||
@@ -68,7 +68,7 @@ func splitSeq(s, sep []byte, sepSave int) iter.Seq[[]byte] {
|
||||
}
|
||||
|
||||
// SplitSeq returns an iterator over all substrings of s separated by sep.
|
||||
// The iterator yields the same strings that would be returned by Split(s, sep),
|
||||
// The iterator yields the same strings that would be returned by [Split](s, sep),
|
||||
// but without constructing the slice.
|
||||
// It returns a single-use iterator.
|
||||
func SplitSeq(s, sep []byte) iter.Seq[[]byte] {
|
||||
@@ -76,7 +76,7 @@ func SplitSeq(s, sep []byte) iter.Seq[[]byte] {
|
||||
}
|
||||
|
||||
// SplitAfterSeq returns an iterator over substrings of s split after each instance of sep.
|
||||
// The iterator yields the same strings that would be returned by SplitAfter(s, sep),
|
||||
// The iterator yields the same strings that would be returned by [SplitAfter](s, sep),
|
||||
// but without constructing the slice.
|
||||
// It returns a single-use iterator.
|
||||
func SplitAfterSeq(s, sep []byte) iter.Seq[[]byte] {
|
||||
@@ -84,8 +84,8 @@ func SplitAfterSeq(s, sep []byte) iter.Seq[[]byte] {
|
||||
}
|
||||
|
||||
// FieldsSeq returns an iterator over substrings of s split around runs of
|
||||
// whitespace characters, as defined by unicode.IsSpace.
|
||||
// The iterator yields the same strings that would be returned by Fields(s),
|
||||
// whitespace characters, as defined by [unicode.IsSpace].
|
||||
// The iterator yields the same strings that would be returned by [Fields](s),
|
||||
// but without constructing the slice.
|
||||
func FieldsSeq(s []byte) iter.Seq[[]byte] {
|
||||
return func(yield func([]byte) bool) {
|
||||
@@ -118,7 +118,7 @@ func FieldsSeq(s []byte) iter.Seq[[]byte] {
|
||||
|
||||
// FieldsFuncSeq returns an iterator over substrings of s split around runs of
|
||||
// Unicode code points satisfying f(c).
|
||||
// The iterator yields the same strings that would be returned by FieldsFunc(s),
|
||||
// The iterator yields the same strings that would be returned by [FieldsFunc](s),
|
||||
// but without constructing the slice.
|
||||
func FieldsFuncSeq(s []byte, f func(rune) bool) iter.Seq[[]byte] {
|
||||
return func(yield func([]byte) bool) {
|
||||
|
||||
@@ -796,7 +796,7 @@ Instead, the build process generates an object file using dynamic
|
||||
linkage to the desired libraries. The main function is provided by
|
||||
_cgo_main.c:
|
||||
|
||||
int main() { return 0; }
|
||||
int main(int argc, char **argv) { return 0; }
|
||||
void crosscall2(void(*fn)(void*), void *a, int c, uintptr_t ctxt) { }
|
||||
uintptr_t _cgo_wait_runtime_init_done(void) { return 0; }
|
||||
void _cgo_release_context(uintptr_t ctxt) { }
|
||||
|
||||
@@ -59,7 +59,7 @@ func (p *Package) writeDefs() {
|
||||
|
||||
// Write C main file for using gcc to resolve imports.
|
||||
fmt.Fprintf(fm, "#include <stddef.h>\n") // For size_t below.
|
||||
fmt.Fprintf(fm, "int main() { return 0; }\n")
|
||||
fmt.Fprintf(fm, "int main(int argc __attribute__((unused)), char **argv __attribute__((unused))) { return 0; }\n")
|
||||
if *importRuntimeCgo {
|
||||
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*) __attribute__((unused)), void *a __attribute__((unused)), int c __attribute__((unused)), size_t ctxt __attribute__((unused))) { }\n")
|
||||
fmt.Fprintf(fm, "size_t _cgo_wait_runtime_init_done(void) { return 0; }\n")
|
||||
|
||||
@@ -15,7 +15,7 @@ the package and about types used by symbols imported by the package from
|
||||
other packages. It is therefore not necessary when compiling client C of
|
||||
package P to read the files of P's dependencies, only the compiled output of P.
|
||||
|
||||
Command Line
|
||||
# Command Line
|
||||
|
||||
Usage:
|
||||
|
||||
@@ -150,14 +150,21 @@ Flags to debug the compiler itself:
|
||||
-w
|
||||
Debug type checking.
|
||||
|
||||
Compiler Directives
|
||||
# Compiler Directives
|
||||
|
||||
The compiler accepts directives in the form of comments.
|
||||
To distinguish them from non-directive comments, directives
|
||||
require no space between the comment opening and the name of the directive. However, since
|
||||
they are comments, tools unaware of the directive convention or of a particular
|
||||
Each directive must be placed its own line, with only leading spaces and tabs
|
||||
allowed before the comment, and there must be no space between the comment
|
||||
opening and the name of the directive, to distinguish it from a regular comment.
|
||||
Tools unaware of the directive convention or of a particular
|
||||
directive can skip over a directive like any other comment.
|
||||
|
||||
Other than the line directive, which is a historical special case;
|
||||
all other compiler directives are of the form
|
||||
//go:name, indicating that they are defined by the Go toolchain.
|
||||
*/
|
||||
// # Line Directives
|
||||
//
|
||||
// Line directives come in several forms:
|
||||
//
|
||||
// //line :line
|
||||
@@ -197,12 +204,9 @@ directive can skip over a directive like any other comment.
|
||||
// Line directives typically appear in machine-generated code, so that compilers and debuggers
|
||||
// will report positions in the original input to the generator.
|
||||
/*
|
||||
The line directive is a historical special case; all other directives are of the form
|
||||
//go:name, indicating that they are defined by the Go toolchain.
|
||||
Each directive must be placed its own line, with only leading spaces and tabs
|
||||
allowed before the comment.
|
||||
Each directive applies to the Go code that immediately follows it,
|
||||
which typically must be a declaration.
|
||||
# Function Directives
|
||||
|
||||
A function directive applies to the Go function that immediately follows it.
|
||||
|
||||
//go:noescape
|
||||
|
||||
@@ -245,6 +249,8 @@ It specifies that the function must omit its usual stack overflow check.
|
||||
This is most commonly used by low-level runtime code invoked
|
||||
at times when it is unsafe for the calling goroutine to be preempted.
|
||||
|
||||
# Linkname Directive
|
||||
|
||||
//go:linkname localname [importpath.name]
|
||||
|
||||
The //go:linkname directive conventionally precedes the var or func
|
||||
@@ -295,17 +301,34 @@ The declaration of lower.f may also have a linkname directive with a
|
||||
single argument, f. This is optional, but helps alert the reader that
|
||||
the function is accessed from outside the package.
|
||||
|
||||
# WebAssembly Directives
|
||||
|
||||
//go:wasmimport importmodule importname
|
||||
|
||||
The //go:wasmimport directive is wasm-only and must be followed by a
|
||||
function declaration.
|
||||
function declaration with no body.
|
||||
It specifies that the function is provided by a wasm module identified
|
||||
by ``importmodule`` and ``importname``.
|
||||
by ``importmodule'' and ``importname''. For example,
|
||||
|
||||
//go:wasmimport a_module f
|
||||
func g()
|
||||
|
||||
The types of parameters and return values to the Go function are translated to
|
||||
causes g to refer to the WebAssembly function f from module a_module.
|
||||
|
||||
//go:wasmexport exportname
|
||||
|
||||
The //go:wasmexport directive is wasm-only and must be followed by a
|
||||
function definition.
|
||||
It specifies that the function is exported to the wasm host as ``exportname''.
|
||||
For example,
|
||||
|
||||
//go:wasmexport h
|
||||
func hWasm() { ... }
|
||||
|
||||
make Go function hWasm available outside this WebAssembly module as h.
|
||||
|
||||
For both go:wasmimport and go:wasmexport,
|
||||
the types of parameters and return values to the Go function are translated to
|
||||
Wasm according to the following table:
|
||||
|
||||
Go types Wasm types
|
||||
@@ -318,24 +341,12 @@ Wasm according to the following table:
|
||||
pointer i32 (more restrictions below)
|
||||
string (i32, i32) (only permitted as a parameters, not a result)
|
||||
|
||||
Any other parameter types are disallowed by the compiler.
|
||||
|
||||
For a pointer type, its element type must be a bool, int8, uint8, int16, uint16,
|
||||
int32, uint32, int64, uint64, float32, float64, an array whose element type is
|
||||
a permitted pointer element type, or a struct, which, if non-empty, embeds
|
||||
structs.HostLayout, and contains only fields whose types are permitted pointer
|
||||
[structs.HostLayout], and contains only fields whose types are permitted pointer
|
||||
element types.
|
||||
|
||||
Any other parameter types are disallowed by the compiler.
|
||||
|
||||
//go:wasmexport exportname
|
||||
|
||||
The //go:wasmexport directive is wasm-only and must be followed by a
|
||||
function definition.
|
||||
It specifies that the function is exported to the wasm host as ``exportname``.
|
||||
|
||||
//go:wasmexport f
|
||||
func g()
|
||||
|
||||
The types of parameters and return values to the Go function are permitted and
|
||||
translated to Wasm in the same way as //go:wasmimport functions.
|
||||
*/
|
||||
package main
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
// This program generates Go code that applies rewrite rules to a Value.
|
||||
// The generated code implements a function of type func (v *Value) bool
|
||||
// which reports whether if did something.
|
||||
// Ideas stolen from Swift: http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-2000-2.html
|
||||
// Ideas stolen from the Swift Java compiler:
|
||||
// https://bitsavers.org/pdf/dec/tech_reports/WRL-2000-2.pdf
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -5452,12 +5452,15 @@ func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value {
|
||||
if n.X.Type().IsChan() && n.Op() == ir.OCAP {
|
||||
s.Fatalf("cannot inline cap(chan)") // must use runtime.chancap now
|
||||
}
|
||||
if n.X.Type().IsMap() && n.Op() == ir.OCAP {
|
||||
s.Fatalf("cannot inline cap(map)") // cap(map) does not exist
|
||||
}
|
||||
// if n == nil {
|
||||
// return 0
|
||||
// } else {
|
||||
// // len
|
||||
// return *((*int)n)
|
||||
// // cap
|
||||
// // len, the actual loadType depends
|
||||
// return int(*((*loadType)n))
|
||||
// // cap (chan only, not used for now)
|
||||
// return *(((*int)n)+1)
|
||||
// }
|
||||
lenType := n.Type()
|
||||
@@ -5485,7 +5488,9 @@ func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value {
|
||||
case ir.OLEN:
|
||||
if buildcfg.Experiment.SwissMap && n.X.Type().IsMap() {
|
||||
// length is stored in the first word.
|
||||
s.vars[n] = s.load(lenType, x)
|
||||
loadType := reflectdata.SwissMapType().Field(0).Type // uint64
|
||||
load := s.load(loadType, x)
|
||||
s.vars[n] = s.conv(nil, load, loadType, lenType) // integer conversion doesn't need Node
|
||||
} else {
|
||||
// length is stored in the first word for map/chan
|
||||
s.vars[n] = s.load(lenType, x)
|
||||
|
||||
17
src/cmd/compile/internal/syntax/testdata/issue70974.go
vendored
Normal file
17
src/cmd/compile/internal/syntax/testdata/issue70974.go
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2025 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 p
|
||||
|
||||
func _() {
|
||||
M:
|
||||
L:
|
||||
for range 0 {
|
||||
break L
|
||||
break /* ERROR invalid break label M */ M
|
||||
}
|
||||
for range 0 {
|
||||
break /* ERROR invalid break label L */ L
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@ The tests are in:
|
||||
Tests are .go files annotated with `/* ERROR "msg" */` or `/* ERRORx "msg" */`
|
||||
comments (or the respective line comment form).
|
||||
For each such error comment, typechecking the respective file is expected to
|
||||
report an error at the position of the syntactic token _immediately preceeding_
|
||||
report an error at the position of the syntactic token _immediately preceding_
|
||||
the comment.
|
||||
For `ERROR`, the `"msg"` string must be a substring of the error message
|
||||
reported by the typechecker;
|
||||
|
||||
@@ -208,11 +208,19 @@ type Info struct {
|
||||
//
|
||||
// The Types map does not record the type of every identifier,
|
||||
// only those that appear where an arbitrary expression is
|
||||
// permitted. For instance, the identifier f in a selector
|
||||
// expression x.f is found only in the Selections map, the
|
||||
// identifier z in a variable declaration 'var z int' is found
|
||||
// only in the Defs map, and identifiers denoting packages in
|
||||
// qualified identifiers are collected in the Uses map.
|
||||
// permitted. For instance:
|
||||
// - an identifier f in a selector expression x.f is found
|
||||
// only in the Selections map;
|
||||
// - an identifier z in a variable declaration 'var z int'
|
||||
// is found only in the Defs map;
|
||||
// - an identifier p denoting a package in a qualified
|
||||
// identifier p.X is found only in the Uses map.
|
||||
//
|
||||
// Similarly, no type is recorded for the (synthetic) FuncType
|
||||
// node in a FuncDecl.Type field, since there is no corresponding
|
||||
// syntactic function type expression in the source in this case
|
||||
// Instead, the function type is found in the Defs.map entry for
|
||||
// the corresponding function declaration.
|
||||
Types map[syntax.Expr]TypeAndValue
|
||||
|
||||
// If StoreTypesInSyntax is set, type information identical to
|
||||
|
||||
@@ -174,7 +174,7 @@ func (check *Checker) collectRecv(rparam *syntax.Field, scopePos syntax.Pos) (*V
|
||||
} else {
|
||||
// If there are type parameters, rbase must denote a generic base type.
|
||||
// Important: rbase must be resolved before declaring any receiver type
|
||||
// parameters (wich may have the same name, see below).
|
||||
// parameters (which may have the same name, see below).
|
||||
var baseType *Named // nil if not valid
|
||||
var cause string
|
||||
if t := check.genericType(rbase, &cause); isValid(t) {
|
||||
|
||||
25
src/cmd/dist/test.go
vendored
25
src/cmd/dist/test.go
vendored
@@ -876,16 +876,18 @@ func (t *tester) registerTests() {
|
||||
}
|
||||
|
||||
if t.extLink() && !t.compileOnly {
|
||||
t.registerTest("external linking, -buildmode=exe",
|
||||
&goTest{
|
||||
variant: "exe_external",
|
||||
timeout: 60 * time.Second,
|
||||
buildmode: "exe",
|
||||
ldflags: "-linkmode=external",
|
||||
env: []string{"CGO_ENABLED=1"},
|
||||
pkg: "crypto/internal/fips140test",
|
||||
runTests: "TestFIPSCheck",
|
||||
})
|
||||
if goos != "android" { // Android does not support non-PIE linking
|
||||
t.registerTest("external linking, -buildmode=exe",
|
||||
&goTest{
|
||||
variant: "exe_external",
|
||||
timeout: 60 * time.Second,
|
||||
buildmode: "exe",
|
||||
ldflags: "-linkmode=external",
|
||||
env: []string{"CGO_ENABLED=1"},
|
||||
pkg: "crypto/internal/fips140test",
|
||||
runTests: "TestFIPSCheck",
|
||||
})
|
||||
}
|
||||
if t.externalLinkPIE() && !disablePIE {
|
||||
t.registerTest("external linking, -buildmode=pie",
|
||||
&goTest{
|
||||
@@ -1795,6 +1797,8 @@ func isEnvSet(evar string) bool {
|
||||
}
|
||||
|
||||
func (t *tester) fipsSupported() bool {
|
||||
// Keep this in sync with [crypto/internal/fips140.Supported].
|
||||
|
||||
// Use GOFIPS140 or GOEXPERIMENT=boringcrypto, but not both.
|
||||
if strings.Contains(goexperiment, "boringcrypto") {
|
||||
return false
|
||||
@@ -1808,6 +1812,7 @@ func (t *tester) fipsSupported() bool {
|
||||
case goarch == "wasm",
|
||||
goos == "windows" && goarch == "386",
|
||||
goos == "windows" && goarch == "arm",
|
||||
goos == "openbsd",
|
||||
goos == "aix":
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -739,11 +739,6 @@
|
||||
//
|
||||
// For more about specifying packages, see 'go help packages'.
|
||||
//
|
||||
// This text describes the behavior of get using modules to manage source
|
||||
// code and dependencies. If instead the go command is running in GOPATH
|
||||
// mode, the details of get's flags and effects change, as does 'go help get'.
|
||||
// See 'go help gopath-get'.
|
||||
//
|
||||
// See also: go build, go install, go clean, go mod.
|
||||
//
|
||||
// # Compile and install packages and dependencies
|
||||
@@ -2186,7 +2181,7 @@
|
||||
// fields of all events to reconstruct the text format output, as it would
|
||||
// have appeared from go build without the -json flag.
|
||||
//
|
||||
// Note that there may also be non-JSON error text on stdnard error, even
|
||||
// Note that there may also be non-JSON error text on standard error, even
|
||||
// with the -json flag. Typically, this indicates an early, serious error.
|
||||
// Consumers should be robust to this.
|
||||
//
|
||||
@@ -2250,7 +2245,7 @@
|
||||
//
|
||||
// The second is the SWIG program, which is a general tool for
|
||||
// interfacing between languages. For information on SWIG see
|
||||
// http://swig.org/. When running go build, any file with a .swig
|
||||
// https://swig.org/. When running go build, any file with a .swig
|
||||
// extension will be passed to SWIG. Any file with a .swigcxx extension
|
||||
// will be passed to SWIG with the -c++ option.
|
||||
//
|
||||
@@ -2338,6 +2333,10 @@
|
||||
// GOCACHE
|
||||
// The directory where the go command will store cached
|
||||
// information for reuse in future builds.
|
||||
// GOCACHEPROG
|
||||
// A command (with optional space-separated flags) that implements an
|
||||
// external go command build cache.
|
||||
// See 'go doc cmd/go/internal/cacheprog'.
|
||||
// GODEBUG
|
||||
// Enable various debugging facilities. See https://go.dev/doc/godebug
|
||||
// for details.
|
||||
@@ -2448,6 +2447,11 @@
|
||||
// GOARM
|
||||
// For GOARCH=arm, the ARM architecture for which to compile.
|
||||
// Valid values are 5, 6, 7.
|
||||
// When the Go tools are built on an arm system,
|
||||
// the default value is set based on what the build system supports.
|
||||
// When the Go tools are not built on an arm system
|
||||
// (that is, when building a cross-compiler),
|
||||
// the default value is 7.
|
||||
// The value can be followed by an option specifying how to implement floating point instructions.
|
||||
// Valid options are ,softfloat (default for 5) and ,hardfloat (default for 6 and 7).
|
||||
// GOARM64
|
||||
@@ -2612,7 +2616,7 @@
|
||||
// Example: Data
|
||||
//
|
||||
// If the server responds with any 4xx code, the go command will write the
|
||||
// following to the programs' stdin:
|
||||
// following to the program's stdin:
|
||||
// Response = StatusLine { HeaderLine } BlankLine .
|
||||
// StatusLine = Protocol Space Status '\n' .
|
||||
// Protocol = /* HTTP protocol */ .
|
||||
@@ -2969,11 +2973,7 @@
|
||||
// same meta tag and then git clone https://code.org/r/p/exproj into
|
||||
// GOPATH/src/example.org.
|
||||
//
|
||||
// When using GOPATH, downloaded packages are written to the first directory
|
||||
// listed in the GOPATH environment variable.
|
||||
// (See 'go help gopath-get' and 'go help gopath'.)
|
||||
//
|
||||
// When using modules, downloaded packages are stored in the module cache.
|
||||
// Downloaded packages are stored in the module cache.
|
||||
// See https://golang.org/ref/mod#module-cache.
|
||||
//
|
||||
// When using modules, an additional variant of the go-import meta tag is
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
@@ -73,7 +72,12 @@ func runGoAuth(client *http.Client, res *http.Response, url string) {
|
||||
if err != nil {
|
||||
base.Fatalf("go: could not parse netrc (GOAUTH=%s): %v", cfg.GOAUTH, err)
|
||||
}
|
||||
for _, l := range lines {
|
||||
// Process lines in reverse so that if the same machine is listed
|
||||
// multiple times, we end up saving the earlier one
|
||||
// (overwriting later ones). This matches the way the go command
|
||||
// worked before GOAUTH.
|
||||
for i := len(lines) - 1; i >= 0; i-- {
|
||||
l := lines[i]
|
||||
r := http.Request{Header: make(http.Header)}
|
||||
r.SetBasicAuth(l.login, l.password)
|
||||
storeCredential(l.machine, r.Header)
|
||||
@@ -137,11 +141,13 @@ func runGoAuth(client *http.Client, res *http.Response, url string) {
|
||||
func loadCredential(req *http.Request, url string) bool {
|
||||
currentPrefix := strings.TrimPrefix(url, "https://")
|
||||
// Iteratively try prefixes, moving up the path hierarchy.
|
||||
for currentPrefix != "/" && currentPrefix != "." && currentPrefix != "" {
|
||||
for {
|
||||
headers, ok := credentialCache.Load(currentPrefix)
|
||||
if !ok {
|
||||
// Move to the parent directory.
|
||||
currentPrefix = path.Dir(currentPrefix)
|
||||
currentPrefix, _, ok = strings.Cut(currentPrefix, "/")
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
continue
|
||||
}
|
||||
for key, values := range headers.(http.Header) {
|
||||
@@ -151,7 +157,6 @@ func loadCredential(req *http.Request, url string) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// storeCredential caches or removes credentials (represented by HTTP headers)
|
||||
|
||||
@@ -25,7 +25,29 @@ func TestCredentialCache(t *testing.T) {
|
||||
got := &http.Request{Header: make(http.Header)}
|
||||
ok := loadCredential(got, tc.machine)
|
||||
if !ok || !reflect.DeepEqual(got.Header, want.Header) {
|
||||
t.Errorf("loadCredential:\nhave %q\nwant %q", got.Header, want.Header)
|
||||
t.Errorf("loadCredential(%q):\nhave %q\nwant %q", tc.machine, got.Header, want.Header)
|
||||
}
|
||||
}
|
||||
|
||||
// Having stored those credentials, we should be able to look up longer URLs too.
|
||||
extraCases := []netrcLine{
|
||||
{"https://api.github.com/foo", "user", "pwd"},
|
||||
{"https://api.github.com/foo/bar/baz", "user", "pwd"},
|
||||
{"https://example.com/abc", "", ""},
|
||||
{"https://example.com/?/../api.github.com/", "", ""},
|
||||
{"https://example.com/?/../api.github.com", "", ""},
|
||||
{"https://example.com/../api.github.com/", "", ""},
|
||||
{"https://example.com/../api.github.com", "", ""},
|
||||
}
|
||||
for _, tc := range extraCases {
|
||||
want := http.Request{Header: make(http.Header)}
|
||||
if tc.login != "" {
|
||||
want.SetBasicAuth(tc.login, tc.password)
|
||||
}
|
||||
got := &http.Request{Header: make(http.Header)}
|
||||
loadCredential(got, tc.machine)
|
||||
if !reflect.DeepEqual(got.Header, want.Header) {
|
||||
t.Errorf("loadCredential(%q):\nhave %q\nwant %q", tc.machine, got.Header, want.Header)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
24
src/cmd/go/internal/cache/cache.go
vendored
24
src/cmd/go/internal/cache/cache.go
vendored
@@ -38,8 +38,8 @@ type Cache interface {
|
||||
// Get returns the cache entry for the provided ActionID.
|
||||
// On miss, the error type should be of type *entryNotFoundError.
|
||||
//
|
||||
// After a success call to Get, OutputFile(Entry.OutputID) must
|
||||
// exist on disk for until Close is called (at the end of the process).
|
||||
// After a successful call to Get, OutputFile(Entry.OutputID) must
|
||||
// exist on disk until Close is called (at the end of the process).
|
||||
Get(ActionID) (Entry, error)
|
||||
|
||||
// Put adds an item to the cache.
|
||||
@@ -50,14 +50,14 @@ type Cache interface {
|
||||
// As a special case, if the ReadSeeker is of type noVerifyReadSeeker,
|
||||
// the verification from GODEBUG=goverifycache=1 is skipped.
|
||||
//
|
||||
// After a success call to Get, OutputFile(Entry.OutputID) must
|
||||
// exist on disk for until Close is called (at the end of the process).
|
||||
// After a successful call to Put, OutputFile(OutputID) must
|
||||
// exist on disk until Close is called (at the end of the process).
|
||||
Put(ActionID, io.ReadSeeker) (_ OutputID, size int64, _ error)
|
||||
|
||||
// Close is called at the end of the go process. Implementations can do
|
||||
// cache cleanup work at this phase, or wait for and report any errors from
|
||||
// background cleanup work started earlier. Any cache trimming should in one
|
||||
// process should not violate cause the invariants of this interface to be
|
||||
// background cleanup work started earlier. Any cache trimming in one
|
||||
// process should not cause the invariants of this interface to be
|
||||
// violated in another process. Namely, a cache trim from one process should
|
||||
// not delete an ObjectID from disk that was recently Get or Put from
|
||||
// another process. As a rule of thumb, don't trim things used in the last
|
||||
@@ -296,19 +296,19 @@ func GetBytes(c Cache, id ActionID) ([]byte, Entry, error) {
|
||||
// GetMmap looks up the action ID in the cache and returns
|
||||
// the corresponding output bytes.
|
||||
// GetMmap should only be used for data that can be expected to fit in memory.
|
||||
func GetMmap(c Cache, id ActionID) ([]byte, Entry, error) {
|
||||
func GetMmap(c Cache, id ActionID) ([]byte, Entry, bool, error) {
|
||||
entry, err := c.Get(id)
|
||||
if err != nil {
|
||||
return nil, entry, err
|
||||
return nil, entry, false, err
|
||||
}
|
||||
md, err := mmap.Mmap(c.OutputFile(entry.OutputID))
|
||||
md, opened, err := mmap.Mmap(c.OutputFile(entry.OutputID))
|
||||
if err != nil {
|
||||
return nil, Entry{}, err
|
||||
return nil, Entry{}, opened, err
|
||||
}
|
||||
if int64(len(md.Data)) != entry.Size {
|
||||
return nil, Entry{}, &entryNotFoundError{Err: errors.New("file incomplete")}
|
||||
return nil, Entry{}, true, &entryNotFoundError{Err: errors.New("file incomplete")}
|
||||
}
|
||||
return md.Data, entry, nil
|
||||
return md.Data, entry, true, nil
|
||||
}
|
||||
|
||||
// OutputFile returns the name of the cache file storing output with the given OutputID.
|
||||
|
||||
4
src/cmd/go/internal/cache/default.go
vendored
4
src/cmd/go/internal/cache/default.go
vendored
@@ -54,8 +54,8 @@ func initDefaultCache() Cache {
|
||||
base.Fatalf("failed to initialize build cache at %s: %s\n", dir, err)
|
||||
}
|
||||
|
||||
if v := cfg.Getenv("GOCACHEPROG"); v != "" {
|
||||
return startCacheProg(v, diskCache)
|
||||
if cfg.GOCACHEPROG != "" {
|
||||
return startCacheProg(cfg.GOCACHEPROG, diskCache)
|
||||
}
|
||||
|
||||
return diskCache
|
||||
|
||||
150
src/cmd/go/internal/cache/prog.go
vendored
150
src/cmd/go/internal/cache/prog.go
vendored
@@ -7,6 +7,7 @@ package cache
|
||||
import (
|
||||
"bufio"
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cacheprog"
|
||||
"cmd/internal/quoted"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
@@ -38,7 +39,7 @@ type ProgCache struct {
|
||||
|
||||
// can are the commands that the child process declared that it supports.
|
||||
// This is effectively the versioning mechanism.
|
||||
can map[ProgCmd]bool
|
||||
can map[cacheprog.Cmd]bool
|
||||
|
||||
// fuzzDirCache is another Cache implementation to use for the FuzzDir
|
||||
// method. In practice this is the default GOCACHE disk-based
|
||||
@@ -55,7 +56,7 @@ type ProgCache struct {
|
||||
|
||||
mu sync.Mutex // guards following fields
|
||||
nextID int64
|
||||
inFlight map[int64]chan<- *ProgResponse
|
||||
inFlight map[int64]chan<- *cacheprog.Response
|
||||
outputFile map[OutputID]string // object => abs path on disk
|
||||
|
||||
// writeMu serializes writing to the child process.
|
||||
@@ -63,95 +64,6 @@ type ProgCache struct {
|
||||
writeMu sync.Mutex
|
||||
}
|
||||
|
||||
// ProgCmd is a command that can be issued to a child process.
|
||||
//
|
||||
// If the interface needs to grow, we can add new commands or new versioned
|
||||
// commands like "get2".
|
||||
type ProgCmd string
|
||||
|
||||
const (
|
||||
cmdGet = ProgCmd("get")
|
||||
cmdPut = ProgCmd("put")
|
||||
cmdClose = ProgCmd("close")
|
||||
)
|
||||
|
||||
// ProgRequest is the JSON-encoded message that's sent from cmd/go to
|
||||
// the GOCACHEPROG child process over stdin. Each JSON object is on its
|
||||
// own line. A ProgRequest of Type "put" with BodySize > 0 will be followed
|
||||
// by a line containing a base64-encoded JSON string literal of the body.
|
||||
type ProgRequest struct {
|
||||
// ID is a unique number per process across all requests.
|
||||
// It must be echoed in the ProgResponse from the child.
|
||||
ID int64
|
||||
|
||||
// Command is the type of request.
|
||||
// The cmd/go tool will only send commands that were declared
|
||||
// as supported by the child.
|
||||
Command ProgCmd
|
||||
|
||||
// ActionID is non-nil for get and puts.
|
||||
ActionID []byte `json:",omitempty"` // or nil if not used
|
||||
|
||||
// OutputID is set for Type "put".
|
||||
//
|
||||
// Prior to Go 1.24, when GOCACHEPROG was still an experiment, this was
|
||||
// accidentally named ObjectID. It was renamed to OutputID in Go 1.24.
|
||||
OutputID []byte `json:",omitempty"` // or nil if not used
|
||||
|
||||
// Body is the body for "put" requests. It's sent after the JSON object
|
||||
// as a base64-encoded JSON string when BodySize is non-zero.
|
||||
// It's sent as a separate JSON value instead of being a struct field
|
||||
// send in this JSON object so large values can be streamed in both directions.
|
||||
// The base64 string body of a ProgRequest will always be written
|
||||
// immediately after the JSON object and a newline.
|
||||
Body io.Reader `json:"-"`
|
||||
|
||||
// BodySize is the number of bytes of Body. If zero, the body isn't written.
|
||||
BodySize int64 `json:",omitempty"`
|
||||
|
||||
// ObjectID is the accidental spelling of OutputID that was used prior to Go
|
||||
// 1.24.
|
||||
//
|
||||
// Deprecated: use OutputID. This field is only populated temporarily for
|
||||
// backwards compatibility with Go 1.23 and earlier when
|
||||
// GOEXPERIMENT=gocacheprog is set. It will be removed in Go 1.25.
|
||||
ObjectID []byte `json:",omitempty"`
|
||||
}
|
||||
|
||||
// ProgResponse is the JSON response from the child process to cmd/go.
|
||||
//
|
||||
// With the exception of the first protocol message that the child writes to its
|
||||
// stdout with ID==0 and KnownCommands populated, these are only sent in
|
||||
// response to a ProgRequest from cmd/go.
|
||||
//
|
||||
// ProgResponses can be sent in any order. The ID must match the request they're
|
||||
// replying to.
|
||||
type ProgResponse struct {
|
||||
ID int64 // that corresponds to ProgRequest; they can be answered out of order
|
||||
Err string `json:",omitempty"` // if non-empty, the error
|
||||
|
||||
// KnownCommands is included in the first message that cache helper program
|
||||
// writes to stdout on startup (with ID==0). It includes the
|
||||
// ProgRequest.Command types that are supported by the program.
|
||||
//
|
||||
// This lets us extend the protocol gracefully over time (adding "get2",
|
||||
// etc), or fail gracefully when needed. It also lets us verify the program
|
||||
// wants to be a cache helper.
|
||||
KnownCommands []ProgCmd `json:",omitempty"`
|
||||
|
||||
// For Get requests.
|
||||
|
||||
Miss bool `json:",omitempty"` // cache miss
|
||||
OutputID []byte `json:",omitempty"`
|
||||
Size int64 `json:",omitempty"` // in bytes
|
||||
Time *time.Time `json:",omitempty"` // an Entry.Time; when the object was added to the docs
|
||||
|
||||
// DiskPath is the absolute path on disk of the ObjectID corresponding
|
||||
// a "get" request's ActionID (on cache hit) or a "put" request's
|
||||
// provided ObjectID.
|
||||
DiskPath string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// startCacheProg starts the prog binary (with optional space-separated flags)
|
||||
// and returns a Cache implementation that talks to it.
|
||||
//
|
||||
@@ -183,6 +95,8 @@ func startCacheProg(progAndArgs string, fuzzDirCache Cache) Cache {
|
||||
base.Fatalf("StdinPipe to GOCACHEPROG: %v", err)
|
||||
}
|
||||
cmd.Stderr = os.Stderr
|
||||
// On close, we cancel the context. Rather than killing the helper,
|
||||
// close its stdin.
|
||||
cmd.Cancel = in.Close
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
@@ -197,14 +111,14 @@ func startCacheProg(progAndArgs string, fuzzDirCache Cache) Cache {
|
||||
stdout: out,
|
||||
stdin: in,
|
||||
bw: bufio.NewWriter(in),
|
||||
inFlight: make(map[int64]chan<- *ProgResponse),
|
||||
inFlight: make(map[int64]chan<- *cacheprog.Response),
|
||||
outputFile: make(map[OutputID]string),
|
||||
readLoopDone: make(chan struct{}),
|
||||
}
|
||||
|
||||
// Register our interest in the initial protocol message from the child to
|
||||
// us, saying what it can do.
|
||||
capResc := make(chan *ProgResponse, 1)
|
||||
capResc := make(chan *cacheprog.Response, 1)
|
||||
pc.inFlight[0] = capResc
|
||||
|
||||
pc.jenc = json.NewEncoder(pc.bw)
|
||||
@@ -219,7 +133,7 @@ func startCacheProg(progAndArgs string, fuzzDirCache Cache) Cache {
|
||||
case <-timer.C:
|
||||
log.Printf("# still waiting for GOCACHEPROG %v ...", prog)
|
||||
case capRes := <-capResc:
|
||||
can := map[ProgCmd]bool{}
|
||||
can := map[cacheprog.Cmd]bool{}
|
||||
for _, cmd := range capRes.KnownCommands {
|
||||
can[cmd] = true
|
||||
}
|
||||
@@ -236,9 +150,15 @@ func (c *ProgCache) readLoop(readLoopDone chan<- struct{}) {
|
||||
defer close(readLoopDone)
|
||||
jd := json.NewDecoder(c.stdout)
|
||||
for {
|
||||
res := new(ProgResponse)
|
||||
res := new(cacheprog.Response)
|
||||
if err := jd.Decode(res); err != nil {
|
||||
if c.closing.Load() {
|
||||
c.mu.Lock()
|
||||
for _, ch := range c.inFlight {
|
||||
close(ch)
|
||||
}
|
||||
c.inFlight = nil
|
||||
c.mu.Unlock()
|
||||
return // quietly
|
||||
}
|
||||
if err == io.EOF {
|
||||
@@ -261,13 +181,18 @@ func (c *ProgCache) readLoop(readLoopDone chan<- struct{}) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ProgCache) send(ctx context.Context, req *ProgRequest) (*ProgResponse, error) {
|
||||
resc := make(chan *ProgResponse, 1)
|
||||
var errCacheprogClosed = errors.New("GOCACHEPROG program closed unexpectedly")
|
||||
|
||||
func (c *ProgCache) send(ctx context.Context, req *cacheprog.Request) (*cacheprog.Response, error) {
|
||||
resc := make(chan *cacheprog.Response, 1)
|
||||
if err := c.writeToChild(req, resc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
select {
|
||||
case res := <-resc:
|
||||
if res == nil {
|
||||
return nil, errCacheprogClosed
|
||||
}
|
||||
if res.Err != "" {
|
||||
return nil, errors.New(res.Err)
|
||||
}
|
||||
@@ -277,8 +202,11 @@ func (c *ProgCache) send(ctx context.Context, req *ProgRequest) (*ProgResponse,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ProgCache) writeToChild(req *ProgRequest, resc chan<- *ProgResponse) (err error) {
|
||||
func (c *ProgCache) writeToChild(req *cacheprog.Request, resc chan<- *cacheprog.Response) (err error) {
|
||||
c.mu.Lock()
|
||||
if c.inFlight == nil {
|
||||
return errCacheprogClosed
|
||||
}
|
||||
c.nextID++
|
||||
req.ID = c.nextID
|
||||
c.inFlight[req.ID] = resc
|
||||
@@ -287,7 +215,9 @@ func (c *ProgCache) writeToChild(req *ProgRequest, resc chan<- *ProgResponse) (e
|
||||
defer func() {
|
||||
if err != nil {
|
||||
c.mu.Lock()
|
||||
delete(c.inFlight, req.ID)
|
||||
if c.inFlight != nil {
|
||||
delete(c.inFlight, req.ID)
|
||||
}
|
||||
c.mu.Unlock()
|
||||
}
|
||||
}()
|
||||
@@ -328,7 +258,7 @@ func (c *ProgCache) writeToChild(req *ProgRequest, resc chan<- *ProgResponse) (e
|
||||
}
|
||||
|
||||
func (c *ProgCache) Get(a ActionID) (Entry, error) {
|
||||
if !c.can[cmdGet] {
|
||||
if !c.can[cacheprog.CmdGet] {
|
||||
// They can't do a "get". Maybe they're a write-only cache.
|
||||
//
|
||||
// TODO(bradfitz,bcmills): figure out the proper error type here. Maybe
|
||||
@@ -338,8 +268,8 @@ func (c *ProgCache) Get(a ActionID) (Entry, error) {
|
||||
// error types on the Cache interface.
|
||||
return Entry{}, &entryNotFoundError{}
|
||||
}
|
||||
res, err := c.send(c.ctx, &ProgRequest{
|
||||
Command: cmdGet,
|
||||
res, err := c.send(c.ctx, &cacheprog.Request{
|
||||
Command: cacheprog.CmdGet,
|
||||
ActionID: a[:],
|
||||
})
|
||||
if err != nil {
|
||||
@@ -395,7 +325,7 @@ func (c *ProgCache) Put(a ActionID, file io.ReadSeeker) (_ OutputID, size int64,
|
||||
return OutputID{}, 0, err
|
||||
}
|
||||
|
||||
if !c.can[cmdPut] {
|
||||
if !c.can[cacheprog.CmdPut] {
|
||||
// Child is a read-only cache. Do nothing.
|
||||
return out, size, nil
|
||||
}
|
||||
@@ -407,8 +337,8 @@ func (c *ProgCache) Put(a ActionID, file io.ReadSeeker) (_ OutputID, size int64,
|
||||
deprecatedValue = out[:]
|
||||
}
|
||||
|
||||
res, err := c.send(c.ctx, &ProgRequest{
|
||||
Command: cmdPut,
|
||||
res, err := c.send(c.ctx, &cacheprog.Request{
|
||||
Command: cacheprog.CmdPut,
|
||||
ActionID: a[:],
|
||||
OutputID: out[:],
|
||||
ObjectID: deprecatedValue, // TODO(bradfitz): remove in Go 1.25
|
||||
@@ -432,10 +362,16 @@ func (c *ProgCache) Close() error {
|
||||
// First write a "close" message to the child so it can exit nicely
|
||||
// and clean up if it wants. Only after that exchange do we cancel
|
||||
// the context that kills the process.
|
||||
if c.can[cmdClose] {
|
||||
_, err = c.send(c.ctx, &ProgRequest{Command: cmdClose})
|
||||
if c.can[cacheprog.CmdClose] {
|
||||
_, err = c.send(c.ctx, &cacheprog.Request{Command: cacheprog.CmdClose})
|
||||
if errors.Is(err, errCacheprogClosed) {
|
||||
// Allow the child to quit without responding to close.
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
// Cancel the context, which will close the helper's stdin.
|
||||
c.ctxCancel()
|
||||
// Wait until the helper closes its stdout.
|
||||
<-c.readLoopDone
|
||||
return err
|
||||
}
|
||||
|
||||
137
src/cmd/go/internal/cacheprog/cacheprog.go
Normal file
137
src/cmd/go/internal/cacheprog/cacheprog.go
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright 2024 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 cacheprog defines the protocol for a GOCACHEPROG program.
|
||||
//
|
||||
// By default, the go command manages a build cache stored in the file system
|
||||
// itself. GOCACHEPROG can be set to the name of a command (with optional
|
||||
// space-separated flags) that implements the go command build cache externally.
|
||||
// This permits defining a different cache policy.
|
||||
//
|
||||
// The go command will start the GOCACHEPROG as a subprocess and communicate
|
||||
// with it via JSON messages over stdin/stdout. The subprocess's stderr will be
|
||||
// connected to the go command's stderr.
|
||||
//
|
||||
// The subprocess should immediately send a [Response] with its capabilities.
|
||||
// After that, the go command will send a stream of [Request] messages and the
|
||||
// subprocess should reply to each [Request] with a [Response] message.
|
||||
package cacheprog
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Cmd is a command that can be issued to a child process.
|
||||
//
|
||||
// If the interface needs to grow, the go command can add new commands or new
|
||||
// versioned commands like "get2" in the future. The initial [Response] from
|
||||
// the child process indicates which commands it supports.
|
||||
type Cmd string
|
||||
|
||||
const (
|
||||
// CmdPut tells the cache program to store an object in the cache.
|
||||
//
|
||||
// [Request.ActionID] is the cache key of this object. The cache should
|
||||
// store [Request.OutputID] and [Request.Body] under this key for a
|
||||
// later "get" request. It must also store the Body in a file in the local
|
||||
// file system and return the path to that file in [Response.DiskPath],
|
||||
// which must exist at least until a "close" request.
|
||||
CmdPut = Cmd("put")
|
||||
|
||||
// CmdGet tells the cache program to retrieve an object from the cache.
|
||||
//
|
||||
// [Request.ActionID] specifies the key of the object to get. If the
|
||||
// cache does not contain this object, it should set [Response.Miss] to
|
||||
// true. Otherwise, it should populate the fields of [Response],
|
||||
// including setting [Response.OutputID] to the OutputID of the original
|
||||
// "put" request and [Response.DiskPath] to the path of a local file
|
||||
// containing the Body of the original "put" request. That file must
|
||||
// continue to exist at least until a "close" request.
|
||||
CmdGet = Cmd("get")
|
||||
|
||||
// CmdClose requests that the cache program exit gracefully.
|
||||
//
|
||||
// The cache program should reply to this request and then exit
|
||||
// (thus closing its stdout).
|
||||
CmdClose = Cmd("close")
|
||||
)
|
||||
|
||||
// Request is the JSON-encoded message that's sent from the go command to
|
||||
// the GOCACHEPROG child process over stdin. Each JSON object is on its own
|
||||
// line. A ProgRequest of Type "put" with BodySize > 0 will be followed by a
|
||||
// line containing a base64-encoded JSON string literal of the body.
|
||||
type Request struct {
|
||||
// ID is a unique number per process across all requests.
|
||||
// It must be echoed in the Response from the child.
|
||||
ID int64
|
||||
|
||||
// Command is the type of request.
|
||||
// The go command will only send commands that were declared
|
||||
// as supported by the child.
|
||||
Command Cmd
|
||||
|
||||
// ActionID is the cache key for "put" and "get" requests.
|
||||
ActionID []byte `json:",omitempty"` // or nil if not used
|
||||
|
||||
// OutputID is stored with the body for "put" requests.
|
||||
//
|
||||
// Prior to Go 1.24, when GOCACHEPROG was still an experiment, this was
|
||||
// accidentally named ObjectID. It was renamed to OutputID in Go 1.24.
|
||||
OutputID []byte `json:",omitempty"` // or nil if not used
|
||||
|
||||
// Body is the body for "put" requests. It's sent after the JSON object
|
||||
// as a base64-encoded JSON string when BodySize is non-zero.
|
||||
// It's sent as a separate JSON value instead of being a struct field
|
||||
// send in this JSON object so large values can be streamed in both directions.
|
||||
// The base64 string body of a Request will always be written
|
||||
// immediately after the JSON object and a newline.
|
||||
Body io.Reader `json:"-"`
|
||||
|
||||
// BodySize is the number of bytes of Body. If zero, the body isn't written.
|
||||
BodySize int64 `json:",omitempty"`
|
||||
|
||||
// ObjectID is the accidental spelling of OutputID that was used prior to Go
|
||||
// 1.24.
|
||||
//
|
||||
// Deprecated: use OutputID. This field is only populated temporarily for
|
||||
// backwards compatibility with Go 1.23 and earlier when
|
||||
// GOEXPERIMENT=gocacheprog is set. It will be removed in Go 1.25.
|
||||
ObjectID []byte `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Response is the JSON response from the child process to the go command.
|
||||
//
|
||||
// With the exception of the first protocol message that the child writes to its
|
||||
// stdout with ID==0 and KnownCommands populated, these are only sent in
|
||||
// response to a Request from the go command.
|
||||
//
|
||||
// Responses can be sent in any order. The ID must match the request they're
|
||||
// replying to.
|
||||
type Response struct {
|
||||
ID int64 // that corresponds to Request; they can be answered out of order
|
||||
Err string `json:",omitempty"` // if non-empty, the error
|
||||
|
||||
// KnownCommands is included in the first message that cache helper program
|
||||
// writes to stdout on startup (with ID==0). It includes the
|
||||
// Request.Command types that are supported by the program.
|
||||
//
|
||||
// This lets the go command extend the protocol gracefully over time (adding
|
||||
// "get2", etc), or fail gracefully when needed. It also lets the go command
|
||||
// verify the program wants to be a cache helper.
|
||||
KnownCommands []Cmd `json:",omitempty"`
|
||||
|
||||
// For "get" requests.
|
||||
|
||||
Miss bool `json:",omitempty"` // cache miss
|
||||
OutputID []byte `json:",omitempty"` // the ObjectID stored with the body
|
||||
Size int64 `json:",omitempty"` // body size in bytes
|
||||
Time *time.Time `json:",omitempty"` // when the object was put in the cache (optional; used for cache expiration)
|
||||
|
||||
// For "get" and "put" requests.
|
||||
|
||||
// DiskPath is the absolute path on disk of the body corresponding to a
|
||||
// "get" (on cache hit) or "put" request's ActionID.
|
||||
DiskPath string `json:",omitempty"`
|
||||
}
|
||||
@@ -425,8 +425,9 @@ var (
|
||||
GOROOTpkg string
|
||||
GOROOTsrc string
|
||||
|
||||
GOBIN = Getenv("GOBIN")
|
||||
GOMODCACHE, GOMODCACHEChanged = EnvOrAndChanged("GOMODCACHE", gopathDir("pkg/mod"))
|
||||
GOBIN = Getenv("GOBIN")
|
||||
GOCACHEPROG, GOCACHEPROGChanged = EnvOrAndChanged("GOCACHEPROG", "")
|
||||
GOMODCACHE, GOMODCACHEChanged = EnvOrAndChanged("GOMODCACHE", gopathDir("pkg/mod"))
|
||||
|
||||
// Used in envcmd.MkEnv and build ID computations.
|
||||
GOARM64, goARM64Changed = EnvOrAndChanged("GOARM64", buildcfg.DefaultGOARM64)
|
||||
|
||||
@@ -85,6 +85,7 @@ func MkEnv() []cfg.EnvVar {
|
||||
{Name: "GOAUTH", Value: cfg.GOAUTH, Changed: cfg.GOAUTHChanged},
|
||||
{Name: "GOBIN", Value: cfg.GOBIN},
|
||||
{Name: "GOCACHE"},
|
||||
{Name: "GOCACHEPROG", Value: cfg.GOCACHEPROG, Changed: cfg.GOCACHEPROGChanged},
|
||||
{Name: "GODEBUG", Value: os.Getenv("GODEBUG")},
|
||||
{Name: "GOENV", Value: envFile, Changed: envFileChanged},
|
||||
{Name: "GOEXE", Value: cfg.ExeSuffix},
|
||||
|
||||
@@ -40,14 +40,8 @@
|
||||
//
|
||||
// GOFIPS140=latest go build -work my/binary
|
||||
//
|
||||
// will leave fips.o behind in $WORK/b001. Auditors like to be able to
|
||||
// see that file. Accordingly, when [Enabled] returns true,
|
||||
// [cmd/go/internal/work.Builder.useCache] arranges never to cache linker
|
||||
// output, so that the link step always runs, and fips.o is always left
|
||||
// behind in the link step. If this proves too slow, we could always
|
||||
// cache fips.o as an extra link output and then restore it when -work is
|
||||
// set, but we went a very long time never caching link steps at all, so
|
||||
// not caching them in FIPS mode seems perfectly fine.
|
||||
// will leave fips.o behind in $WORK/b001
|
||||
// (unless the build result is cached, of course).
|
||||
//
|
||||
// When GOFIPS140 is set to something besides off and latest, [Snapshot]
|
||||
// returns true, indicating that the build should replace the latest copy
|
||||
@@ -119,6 +113,10 @@ func Init() {
|
||||
if Snapshot() {
|
||||
fsys.Bind(Dir(), filepath.Join(cfg.GOROOT, "src/crypto/internal/fips140"))
|
||||
}
|
||||
|
||||
if cfg.Experiment.BoringCrypto && Enabled() {
|
||||
base.Fatalf("go: cannot use GOFIPS140 with GOEXPERIMENT=boringcrypto")
|
||||
}
|
||||
}
|
||||
|
||||
var initDone bool
|
||||
|
||||
@@ -17,7 +17,7 @@ information on how to use it see the cgo documentation (go doc cmd/cgo).
|
||||
|
||||
The second is the SWIG program, which is a general tool for
|
||||
interfacing between languages. For information on SWIG see
|
||||
http://swig.org/. When running go build, any file with a .swig
|
||||
https://swig.org/. When running go build, any file with a .swig
|
||||
extension will be passed to SWIG. Any file with a .swigcxx extension
|
||||
will be passed to SWIG with the -c++ option.
|
||||
|
||||
@@ -270,11 +270,7 @@ the go tool will verify that https://example.org/?go-get=1 contains the
|
||||
same meta tag and then git clone https://code.org/r/p/exproj into
|
||||
GOPATH/src/example.org.
|
||||
|
||||
When using GOPATH, downloaded packages are written to the first directory
|
||||
listed in the GOPATH environment variable.
|
||||
(See 'go help gopath-get' and 'go help gopath'.)
|
||||
|
||||
When using modules, downloaded packages are stored in the module cache.
|
||||
Downloaded packages are stored in the module cache.
|
||||
See https://golang.org/ref/mod#module-cache.
|
||||
|
||||
When using modules, an additional variant of the go-import meta tag is
|
||||
@@ -510,6 +506,10 @@ General-purpose environment variables:
|
||||
GOCACHE
|
||||
The directory where the go command will store cached
|
||||
information for reuse in future builds.
|
||||
GOCACHEPROG
|
||||
A command (with optional space-separated flags) that implements an
|
||||
external go command build cache.
|
||||
See 'go doc cmd/go/internal/cacheprog'.
|
||||
GODEBUG
|
||||
Enable various debugging facilities. See https://go.dev/doc/godebug
|
||||
for details.
|
||||
@@ -620,6 +620,11 @@ Architecture-specific environment variables:
|
||||
GOARM
|
||||
For GOARCH=arm, the ARM architecture for which to compile.
|
||||
Valid values are 5, 6, 7.
|
||||
When the Go tools are built on an arm system,
|
||||
the default value is set based on what the build system supports.
|
||||
When the Go tools are not built on an arm system
|
||||
(that is, when building a cross-compiler),
|
||||
the default value is 7.
|
||||
The value can be followed by an option specifying how to implement floating point instructions.
|
||||
Valid options are ,softfloat (default for 5) and ,hardfloat (default for 6 and 7).
|
||||
GOARM64
|
||||
@@ -1029,7 +1034,7 @@ command
|
||||
Example: Data
|
||||
|
||||
If the server responds with any 4xx code, the go command will write the
|
||||
following to the programs' stdin:
|
||||
following to the program's stdin:
|
||||
Response = StatusLine { HeaderLine } BlankLine .
|
||||
StatusLine = Protocol Space Status '\n' .
|
||||
Protocol = /* HTTP protocol */ .
|
||||
@@ -1097,7 +1102,7 @@ Furthermore, as with TestEvent, parsers can simply concatenate the Output
|
||||
fields of all events to reconstruct the text format output, as it would
|
||||
have appeared from go build without the -json flag.
|
||||
|
||||
Note that there may also be non-JSON error text on stdnard error, even
|
||||
Note that there may also be non-JSON error text on standard error, even
|
||||
with the -json flag. Typically, this indicates an early, serious error.
|
||||
Consumers should be robust to this.
|
||||
`,
|
||||
|
||||
@@ -3068,7 +3068,15 @@ func setPGOProfilePath(pkgs []*Package) {
|
||||
// CheckPackageErrors prints errors encountered loading pkgs and their
|
||||
// dependencies, then exits with a non-zero status if any errors were found.
|
||||
func CheckPackageErrors(pkgs []*Package) {
|
||||
var anyIncomplete bool
|
||||
PackageErrors(pkgs, func(p *Package) {
|
||||
DefaultPrinter().Errorf(p, "%v", p.Error)
|
||||
})
|
||||
base.ExitIfErrors()
|
||||
}
|
||||
|
||||
// PackageErrors calls report for errors encountered loading pkgs and their dependencies.
|
||||
func PackageErrors(pkgs []*Package, report func(*Package)) {
|
||||
var anyIncomplete, anyErrors bool
|
||||
for _, pkg := range pkgs {
|
||||
if pkg.Incomplete {
|
||||
anyIncomplete = true
|
||||
@@ -3078,11 +3086,14 @@ func CheckPackageErrors(pkgs []*Package) {
|
||||
all := PackageList(pkgs)
|
||||
for _, p := range all {
|
||||
if p.Error != nil {
|
||||
DefaultPrinter().Errorf(p, "%v", p.Error)
|
||||
report(p)
|
||||
anyErrors = true
|
||||
}
|
||||
}
|
||||
}
|
||||
base.ExitIfErrors()
|
||||
if anyErrors {
|
||||
return
|
||||
}
|
||||
|
||||
// Check for duplicate loads of the same package.
|
||||
// That should be impossible, but if it does happen then
|
||||
@@ -3105,7 +3116,9 @@ func CheckPackageErrors(pkgs []*Package) {
|
||||
}
|
||||
seen[key] = true
|
||||
}
|
||||
base.ExitIfErrors()
|
||||
if len(reported) > 0 {
|
||||
base.ExitIfErrors()
|
||||
}
|
||||
}
|
||||
|
||||
// mainPackagesOnly filters out non-main packages matched only by arguments
|
||||
|
||||
@@ -22,10 +22,11 @@ type Data struct {
|
||||
}
|
||||
|
||||
// Mmap maps the given file into memory.
|
||||
func Mmap(file string) (Data, error) {
|
||||
func Mmap(file string) (Data, bool, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return Data{}, err
|
||||
return Data{}, false, err
|
||||
}
|
||||
return mmapFile(f)
|
||||
data, err := mmapFile(f)
|
||||
return data, true, err
|
||||
}
|
||||
|
||||
@@ -125,11 +125,6 @@ suggested Go toolchain, see https://go.dev/doc/toolchain.
|
||||
|
||||
For more about specifying packages, see 'go help packages'.
|
||||
|
||||
This text describes the behavior of get using modules to manage source
|
||||
code and dependencies. If instead the go command is running in GOPATH
|
||||
mode, the details of get's flags and effects change, as does 'go help get'.
|
||||
See 'go help gopath-get'.
|
||||
|
||||
See also: go build, go install, go clean, go mod.
|
||||
`,
|
||||
}
|
||||
|
||||
@@ -183,16 +183,21 @@ func openIndexModule(modroot string, ismodcache bool) (*Module, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, _, err := cache.GetMmap(cache.Default(), id)
|
||||
data, _, opened, err := cache.GetMmap(cache.Default(), id)
|
||||
if err != nil {
|
||||
// Couldn't read from modindex. Assume we couldn't read from
|
||||
// the index because the module hasn't been indexed yet.
|
||||
// But double check on Windows that we haven't opened the file yet,
|
||||
// because once mmap opens the file, we can't close it, and
|
||||
// Windows won't let us open an already opened file.
|
||||
data, err = indexModule(modroot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = cache.PutBytes(cache.Default(), id, data); err != nil {
|
||||
return nil, err
|
||||
if runtime.GOOS != "windows" || !opened {
|
||||
if err = cache.PutBytes(cache.Default(), id, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
mi, err := fromBytes(modroot, data)
|
||||
@@ -212,13 +217,18 @@ func openIndexPackage(modroot, pkgdir string) (*IndexPackage, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, _, err := cache.GetMmap(cache.Default(), id)
|
||||
data, _, opened, err := cache.GetMmap(cache.Default(), id)
|
||||
if err != nil {
|
||||
// Couldn't read from index. Assume we couldn't read from
|
||||
// the index because the package hasn't been indexed yet.
|
||||
// But double check on Windows that we haven't opened the file yet,
|
||||
// because once mmap opens the file, we can't close it, and
|
||||
// Windows won't let us open an already opened file.
|
||||
data = indexPackage(modroot, pkgdir)
|
||||
if err = cache.PutBytes(cache.Default(), id, data); err != nil {
|
||||
return nil, err
|
||||
if runtime.GOOS != "windows" || !opened {
|
||||
if err = cache.PutBytes(cache.Default(), id, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
pkg, err := packageFromBytes(modroot, data)
|
||||
|
||||
@@ -994,14 +994,15 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) {
|
||||
|
||||
// Prepare build + run + print actions for all packages being tested.
|
||||
for _, p := range pkgs {
|
||||
buildTest, runTest, printTest, perr, err := builderTest(b, ctx, pkgOpts, p, allImports[p], writeCoverMetaAct)
|
||||
if err != nil {
|
||||
reportErr := func(perr *load.Package, err error) {
|
||||
str := err.Error()
|
||||
if p.ImportPath != "" {
|
||||
load.DefaultPrinter().Errorf(perr, "# %s\n%s", p.ImportPath, str)
|
||||
} else {
|
||||
load.DefaultPrinter().Errorf(perr, "%s", str)
|
||||
}
|
||||
}
|
||||
reportSetupFailed := func(perr *load.Package, err error) {
|
||||
var stdout io.Writer = os.Stdout
|
||||
if testJSON {
|
||||
json := test2json.NewConverter(stdout, p.ImportPath, test2json.Timestamp)
|
||||
@@ -1009,11 +1010,34 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) {
|
||||
json.Exited(err)
|
||||
json.Close()
|
||||
}()
|
||||
json.SetFailedBuild(perr.Desc())
|
||||
if gotestjsonbuildtext.Value() == "1" {
|
||||
// While this flag is about go build -json, the other effect
|
||||
// of that change was to include "FailedBuild" in the test JSON.
|
||||
gotestjsonbuildtext.IncNonDefault()
|
||||
} else {
|
||||
json.SetFailedBuild(perr.Desc())
|
||||
}
|
||||
stdout = json
|
||||
}
|
||||
fmt.Fprintf(stdout, "FAIL\t%s [setup failed]\n", p.ImportPath)
|
||||
base.SetExitStatus(1)
|
||||
}
|
||||
|
||||
var firstErrPkg *load.Package // arbitrarily report setup failed error for first error pkg reached in DFS
|
||||
load.PackageErrors([]*load.Package{p}, func(p *load.Package) {
|
||||
reportErr(p, p.Error)
|
||||
if firstErrPkg == nil {
|
||||
firstErrPkg = p
|
||||
}
|
||||
})
|
||||
if firstErrPkg != nil {
|
||||
reportSetupFailed(firstErrPkg, firstErrPkg.Error)
|
||||
continue
|
||||
}
|
||||
buildTest, runTest, printTest, perr, err := builderTest(b, ctx, pkgOpts, p, allImports[p], writeCoverMetaAct)
|
||||
if err != nil {
|
||||
reportErr(perr, err)
|
||||
reportSetupFailed(perr, err)
|
||||
continue
|
||||
}
|
||||
builds = append(builds, buildTest)
|
||||
@@ -1437,7 +1461,11 @@ func (r *runTestActor) Act(b *work.Builder, ctx context.Context, a *work.Action)
|
||||
if a.Failed != nil {
|
||||
// We were unable to build the binary.
|
||||
if json != nil && a.Failed.Package != nil {
|
||||
json.SetFailedBuild(a.Failed.Package.Desc())
|
||||
if gotestjsonbuildtext.Value() == "1" {
|
||||
gotestjsonbuildtext.IncNonDefault()
|
||||
} else {
|
||||
json.SetFailedBuild(a.Failed.Package.Desc())
|
||||
}
|
||||
}
|
||||
a.Failed = nil
|
||||
fmt.Fprintf(stdout, "FAIL\t%s [build failed]\n", a.Package.ImportPath)
|
||||
|
||||
@@ -169,7 +169,7 @@ func Select() {
|
||||
}
|
||||
|
||||
gotoolchain = minToolchain
|
||||
if (mode == "auto" || mode == "path") && !goInstallVersion() {
|
||||
if (mode == "auto" || mode == "path") && !goInstallVersion(minVers) {
|
||||
// Read go.mod to find new minimum and suggested toolchain.
|
||||
file, goVers, toolchain := modGoToolchain()
|
||||
gover.Startup.AutoFile = file
|
||||
@@ -549,7 +549,7 @@ func modGoToolchain() (file, goVers, toolchain string) {
|
||||
|
||||
// goInstallVersion reports whether the command line is go install m@v or go run m@v.
|
||||
// If so, Select must not read the go.mod or go.work file in "auto" or "path" mode.
|
||||
func goInstallVersion() bool {
|
||||
func goInstallVersion(minVers string) bool {
|
||||
// Note: We assume there are no flags between 'go' and 'install' or 'run'.
|
||||
// During testing there are some debugging flags that are accepted
|
||||
// in that position, but in production go binaries there are not.
|
||||
@@ -708,7 +708,11 @@ func goInstallVersion() bool {
|
||||
if errors.Is(err, gover.ErrTooNew) {
|
||||
// Run early switch, same one go install or go run would eventually do,
|
||||
// if it understood all the command-line flags.
|
||||
SwitchOrFatal(ctx, err)
|
||||
var s Switcher
|
||||
s.Error(err)
|
||||
if s.TooNew != nil && gover.Compare(s.TooNew.GoVersion, minVers) > 0 {
|
||||
SwitchOrFatal(ctx, err)
|
||||
}
|
||||
}
|
||||
|
||||
return true // pkg@version found
|
||||
|
||||
@@ -63,6 +63,7 @@ func (h *authHandler) Handler(dir string, env []string, logger *log.Logger) (htt
|
||||
var err error
|
||||
accessFile, err = fs.Open(path.Join(accessDir, ".access"))
|
||||
if err == nil {
|
||||
defer accessFile.Close()
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cache"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/fips140"
|
||||
"cmd/go/internal/fsys"
|
||||
"cmd/go/internal/str"
|
||||
"cmd/internal/buildid"
|
||||
@@ -447,19 +446,6 @@ func (b *Builder) useCache(a *Action, actionHash cache.ActionID, target string,
|
||||
a.buildID = actionID + buildIDSeparator + mainpkg.buildID + buildIDSeparator + contentID
|
||||
}
|
||||
|
||||
// In FIPS mode, we disable any link caching,
|
||||
// so that we always leave fips.o in $WORK/b001.
|
||||
// This makes sure that labs validating the FIPS
|
||||
// implementation can always run 'go build -work'
|
||||
// and then find fips.o in $WORK/b001/fips.o.
|
||||
// We could instead also save the fips.o and restore it
|
||||
// to $WORK/b001 from the cache,
|
||||
// but we went years without caching binaries anyway,
|
||||
// so not caching them for FIPS will be fine, at least to start.
|
||||
if a.Mode == "link" && fips140.Enabled() && a.Package != nil && !strings.HasSuffix(a.Package.ImportPath, ".test") {
|
||||
return false
|
||||
}
|
||||
|
||||
// If user requested -a, we force a rebuild, so don't use the cache.
|
||||
if cfg.BuildA {
|
||||
if p := a.Package; p != nil && !p.Stale {
|
||||
@@ -519,7 +505,7 @@ func (b *Builder) useCache(a *Action, actionHash cache.ActionID, target string,
|
||||
oldBuildID := a.buildID
|
||||
a.buildID = id[1] + buildIDSeparator + id[2]
|
||||
linkID := buildid.HashToString(b.linkActionID(a.triggers[0]))
|
||||
if id[0] == linkID && !fips140.Enabled() {
|
||||
if id[0] == linkID {
|
||||
// Best effort attempt to display output from the compile and link steps.
|
||||
// If it doesn't work, it doesn't work: reusing the cached binary is more
|
||||
// important than reprinting diagnostic information.
|
||||
|
||||
@@ -1374,6 +1374,7 @@ func (b *Builder) linkActionID(a *Action) cache.ActionID {
|
||||
fmt.Fprintf(h, "buildmode %s goos %s goarch %s\n", cfg.BuildBuildmode, cfg.Goos, cfg.Goarch)
|
||||
fmt.Fprintf(h, "import %q\n", p.ImportPath)
|
||||
fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix)
|
||||
fmt.Fprintf(h, "defaultgodebug %q\n", p.DefaultGODEBUG)
|
||||
if cfg.BuildTrimpath {
|
||||
fmt.Fprintln(h, "trimpath")
|
||||
}
|
||||
|
||||
@@ -201,23 +201,23 @@ var validLinkerFlags = []*lazyregexp.Regexp{
|
||||
re(`-Wl,--end-group`),
|
||||
re(`-Wl,--(no-)?export-dynamic`),
|
||||
re(`-Wl,-E`),
|
||||
re(`-Wl,-framework,[^,@\-][^,]+`),
|
||||
re(`-Wl,-framework,[^,@\-][^,]*`),
|
||||
re(`-Wl,--hash-style=(sysv|gnu|both)`),
|
||||
re(`-Wl,-headerpad_max_install_names`),
|
||||
re(`-Wl,--no-undefined`),
|
||||
re(`-Wl,--pop-state`),
|
||||
re(`-Wl,--push-state`),
|
||||
re(`-Wl,-R,?([^@\-,][^,@]*$)`),
|
||||
re(`-Wl,--just-symbols[=,]([^,@\-][^,@]+)`),
|
||||
re(`-Wl,-rpath(-link)?[=,]([^,@\-][^,]+)`),
|
||||
re(`-Wl,--just-symbols[=,]([^,@\-][^,@]*)`),
|
||||
re(`-Wl,-rpath(-link)?[=,]([^,@\-][^,]*)`),
|
||||
re(`-Wl,-s`),
|
||||
re(`-Wl,-search_paths_first`),
|
||||
re(`-Wl,-sectcreate,([^,@\-][^,]+),([^,@\-][^,]+),([^,@\-][^,]+)`),
|
||||
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,-syslibroot[=,]([^,@\-][^,]*)`),
|
||||
re(`-Wl,-undefined[=,]([^,@\-][^,]*)`),
|
||||
re(`-Wl,-?-unresolved-symbols=[^,]+`),
|
||||
re(`-Wl,--(no-)?warn-([^,]+)`),
|
||||
re(`-Wl,-?-wrap[=,][^,@\-][^,]*`),
|
||||
@@ -227,6 +227,21 @@ var validLinkerFlags = []*lazyregexp.Regexp{
|
||||
re(`\./.*\.(a|o|obj|dll|dylib|so|tbd)`),
|
||||
}
|
||||
|
||||
var validLinkerFlagsOnDarwin = []*lazyregexp.Regexp{
|
||||
// The GNU linker interprets `@file` as "read command-line options from
|
||||
// file". Thus, we forbid values starting with `@` on linker flags.
|
||||
// However, this causes a problem when targeting Darwin.
|
||||
// `@executable_path`, `@loader_path`, and `@rpath` are special values
|
||||
// used in Mach-O to change the library search path and can be used in
|
||||
// conjunction with the `-install_name` and `-rpath` linker flags.
|
||||
// Since the GNU linker does not support Mach-O, targeting Darwin
|
||||
// implies not using the GNU linker. Therefore, we allow @ in the linker
|
||||
// flags if and only if cfg.Goos == "darwin" || cfg.Goos == "ios".
|
||||
re(`-Wl,-dylib_install_name,@rpath(/[^,]*)?`),
|
||||
re(`-Wl,-install_name,@rpath(/[^,]*)?`),
|
||||
re(`-Wl,-rpath,@(executable_path|loader_path)(/[^,]*)?`),
|
||||
}
|
||||
|
||||
var validLinkerFlagsWithNextArg = []string{
|
||||
"-arch",
|
||||
"-F",
|
||||
@@ -249,8 +264,13 @@ func checkCompilerFlags(name, source string, list []string) error {
|
||||
}
|
||||
|
||||
func checkLinkerFlags(name, source string, list []string) error {
|
||||
validLinkerFlagsForPlatform := validLinkerFlags
|
||||
if cfg.Goos == "darwin" || cfg.Goos == "ios" {
|
||||
validLinkerFlagsForPlatform = append(validLinkerFlags, validLinkerFlagsOnDarwin...)
|
||||
}
|
||||
|
||||
checkOverrides := true
|
||||
return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides)
|
||||
return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlagsForPlatform, validLinkerFlagsWithNextArg, checkOverrides)
|
||||
}
|
||||
|
||||
// checkCompilerFlagsForInternalLink returns an error if 'list'
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"cmd/go/internal/cfg"
|
||||
)
|
||||
|
||||
var goodCompilerFlags = [][]string{
|
||||
@@ -182,6 +184,13 @@ var goodLinkerFlags = [][]string{
|
||||
{"-Wl,--pop-state"},
|
||||
{"-Wl,--push-state,--as-needed"},
|
||||
{"-Wl,--push-state,--no-as-needed,-Bstatic"},
|
||||
{"-Wl,--just-symbols,."},
|
||||
{"-Wl,-framework,."},
|
||||
{"-Wl,-rpath,."},
|
||||
{"-Wl,-rpath-link,."},
|
||||
{"-Wl,-sectcreate,.,.,."},
|
||||
{"-Wl,-syslibroot,."},
|
||||
{"-Wl,-undefined,."},
|
||||
}
|
||||
|
||||
var badLinkerFlags = [][]string{
|
||||
@@ -238,6 +247,8 @@ var badLinkerFlags = [][]string{
|
||||
{"-Wl,--hash-style=foo"},
|
||||
{"-x", "--c"},
|
||||
{"-x", "@obj"},
|
||||
{"-Wl,-dylib_install_name,@foo"},
|
||||
{"-Wl,-install_name,@foo"},
|
||||
{"-Wl,-rpath,@foo"},
|
||||
{"-Wl,-R,foo,bar"},
|
||||
{"-Wl,-R,@foo"},
|
||||
@@ -254,6 +265,21 @@ var badLinkerFlags = [][]string{
|
||||
{"./-Wl,--push-state,-R.c"},
|
||||
}
|
||||
|
||||
var goodLinkerFlagsOnDarwin = [][]string{
|
||||
{"-Wl,-dylib_install_name,@rpath"},
|
||||
{"-Wl,-dylib_install_name,@rpath/"},
|
||||
{"-Wl,-dylib_install_name,@rpath/foo"},
|
||||
{"-Wl,-install_name,@rpath"},
|
||||
{"-Wl,-install_name,@rpath/"},
|
||||
{"-Wl,-install_name,@rpath/foo"},
|
||||
{"-Wl,-rpath,@executable_path"},
|
||||
{"-Wl,-rpath,@executable_path/"},
|
||||
{"-Wl,-rpath,@executable_path/foo"},
|
||||
{"-Wl,-rpath,@loader_path"},
|
||||
{"-Wl,-rpath,@loader_path/"},
|
||||
{"-Wl,-rpath,@loader_path/foo"},
|
||||
}
|
||||
|
||||
func TestCheckLinkerFlags(t *testing.T) {
|
||||
for _, f := range goodLinkerFlags {
|
||||
if err := checkLinkerFlags("test", "test", f); err != nil {
|
||||
@@ -265,6 +291,31 @@ func TestCheckLinkerFlags(t *testing.T) {
|
||||
t.Errorf("missing error for %q", f)
|
||||
}
|
||||
}
|
||||
|
||||
goos := cfg.Goos
|
||||
|
||||
cfg.Goos = "darwin"
|
||||
for _, f := range goodLinkerFlagsOnDarwin {
|
||||
if err := checkLinkerFlags("test", "test", f); err != nil {
|
||||
t.Errorf("unexpected error for %q: %v", f, err)
|
||||
}
|
||||
}
|
||||
|
||||
cfg.Goos = "ios"
|
||||
for _, f := range goodLinkerFlagsOnDarwin {
|
||||
if err := checkLinkerFlags("test", "test", f); err != nil {
|
||||
t.Errorf("unexpected error for %q: %v", f, err)
|
||||
}
|
||||
}
|
||||
|
||||
cfg.Goos = "linux"
|
||||
for _, f := range goodLinkerFlagsOnDarwin {
|
||||
if err := checkLinkerFlags("test", "test", f); err == nil {
|
||||
t.Errorf("missing error for %q", f)
|
||||
}
|
||||
}
|
||||
|
||||
cfg.Goos = goos
|
||||
}
|
||||
|
||||
func TestCheckFlagAllowDisallow(t *testing.T) {
|
||||
|
||||
27
src/cmd/go/testdata/script/build_cacheprog_issue70848.txt
vendored
Normal file
27
src/cmd/go/testdata/script/build_cacheprog_issue70848.txt
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
[short] skip 'builds go programs'
|
||||
|
||||
go build -o cacheprog$GOEXE cacheprog.go
|
||||
env GOCACHEPROG=$GOPATH/src/cacheprog$GOEXE
|
||||
|
||||
# This should not deadlock
|
||||
go build simple.go
|
||||
! stderr 'cacheprog closed'
|
||||
|
||||
-- simple.go --
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
-- cacheprog.go --
|
||||
// This is a minimal GOCACHEPROG program that doesn't respond to close.
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
json.NewEncoder(os.Stdout).Encode(map[string][]string{"KnownCommands": {"close"}})
|
||||
var res struct{}
|
||||
json.NewDecoder(os.Stdin).Decode(&res)
|
||||
}
|
||||
@@ -51,7 +51,7 @@ go version -m example$GOEXE
|
||||
stdout '\s+mod\s+example\s+v1.0.1\s+'
|
||||
rm example$GOEXE
|
||||
|
||||
# Use tag+dirty when there are uncomitted changes present.
|
||||
# Use tag+dirty when there are uncommitted changes present.
|
||||
cp $WORK/copy/README $WORK/repo/README
|
||||
go build
|
||||
go version -m example$GOEXE
|
||||
@@ -82,7 +82,7 @@ go version -m example$GOEXE
|
||||
stdout '\s+mod\s+example\s+v1.0.3-0.20220719150702-deaeab06f7fe\s+'
|
||||
rm example$GOEXE
|
||||
|
||||
# Use pseudo+dirty when uncomitted changes are present.
|
||||
# Use pseudo+dirty when uncommitted changes are present.
|
||||
mv README2 README3
|
||||
go build
|
||||
go version -m example$GOEXE
|
||||
|
||||
3
src/cmd/go/testdata/script/env_changed.txt
vendored
3
src/cmd/go/testdata/script/env_changed.txt
vendored
@@ -1,5 +1,8 @@
|
||||
# Test query for non-defaults in the env
|
||||
|
||||
# Go+BoringCrypto conflicts with GOFIPS140.
|
||||
[GOEXPERIMENT:boringcrypto] skip
|
||||
|
||||
env GOROOT=./a
|
||||
env GOTOOLCHAIN=local
|
||||
env GOSUMDB=nodefault
|
||||
|
||||
42
src/cmd/go/testdata/script/env_gocacheprog.txt
vendored
Normal file
42
src/cmd/go/testdata/script/env_gocacheprog.txt
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
# GOCACHEPROG unset
|
||||
env GOCACHEPROG=
|
||||
|
||||
go env
|
||||
stdout 'GOCACHEPROG=''?''?'
|
||||
|
||||
go env -changed
|
||||
! stdout 'GOCACHEPROG'
|
||||
|
||||
go env -changed -json
|
||||
! stdout 'GOCACHEPROG'
|
||||
|
||||
# GOCACHEPROG set
|
||||
[short] skip 'compiles and runs a go program'
|
||||
|
||||
go build -o cacheprog$GOEXE cacheprog.go
|
||||
|
||||
env GOCACHEPROG=$GOPATH/src/cacheprog$GOEXE
|
||||
|
||||
go env
|
||||
stdout 'GOCACHEPROG=''?'$GOCACHEPROG'''?'
|
||||
|
||||
go env -changed
|
||||
stdout 'GOCACHEPROG=''?'$GOCACHEPROG'''?'
|
||||
|
||||
go env -changed -json
|
||||
stdout '"GOCACHEPROG": ".*cacheprog'$GOEXE'"'
|
||||
|
||||
-- cacheprog.go --
|
||||
// This is a minimal GOCACHEPROG program that can't actually do anything but exit.
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
json.NewEncoder(os.Stdout).Encode(map[string][]string{"KnownCommands": {"close"}})
|
||||
var res struct{}
|
||||
json.NewDecoder(os.Stdin).Decode(&res)
|
||||
}
|
||||
9
src/cmd/go/testdata/script/fips.txt
vendored
9
src/cmd/go/testdata/script/fips.txt
vendored
@@ -1,3 +1,6 @@
|
||||
# Go+BoringCrypto conflicts with GOFIPS140.
|
||||
[GOEXPERIMENT:boringcrypto] skip
|
||||
|
||||
# list with GOFIPS140=off
|
||||
env GOFIPS140=off
|
||||
go list -f '{{.DefaultGODEBUG}}'
|
||||
@@ -17,12 +20,12 @@ go build -x -o x.exe
|
||||
go build -x -o x.exe
|
||||
! stderr link
|
||||
|
||||
# build with GOFIPS140=latest is NOT cached (need fipso)
|
||||
# build with GOFIPS140=latest is cached too
|
||||
env GOFIPS140=latest
|
||||
go build -x -o x.exe
|
||||
stderr link.*-fipso
|
||||
go build -x -o x.exe
|
||||
stderr link.*-fipso
|
||||
! stderr link.*-fipso
|
||||
|
||||
# build test with GOFIPS140=off is cached
|
||||
env GOFIPS140=off
|
||||
@@ -38,8 +41,6 @@ stderr link.*-fipso
|
||||
go test -x -c
|
||||
! stderr link
|
||||
|
||||
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
-- x.go --
|
||||
|
||||
7
src/cmd/go/testdata/script/fipssnap.txt
vendored
7
src/cmd/go/testdata/script/fipssnap.txt
vendored
@@ -7,6 +7,9 @@ env alias=inprocess
|
||||
skip 'no snapshots yet'
|
||||
env GOFIPS140=$snap
|
||||
|
||||
# Go+BoringCrypto conflicts with GOFIPS140.
|
||||
[GOEXPERIMENT:boringcrypto] skip
|
||||
|
||||
# default GODEBUG includes fips140=on
|
||||
go list -f '{{.DefaultGODEBUG}}'
|
||||
stdout fips140=on
|
||||
@@ -44,11 +47,11 @@ stdout crypto/internal/fips140/$snap/sha256
|
||||
|
||||
[short] skip
|
||||
|
||||
# build with GOFIPS140=snap is NOT cached (need fipso)
|
||||
# build with GOFIPS140=snap is cached
|
||||
go build -x -o x.exe
|
||||
stderr link.*-fipso
|
||||
go build -x -o x.exe
|
||||
stderr link.*-fipso
|
||||
! stderr link.*-fipso
|
||||
|
||||
# build test with GOFIPS140=snap is cached
|
||||
go test -x -c
|
||||
|
||||
7
src/cmd/go/testdata/script/goauth_netrc.txt
vendored
7
src/cmd/go/testdata/script/goauth_netrc.txt
vendored
@@ -2,8 +2,6 @@
|
||||
# credentials passed in HTTPS requests to VCS servers.
|
||||
# See golang.org/issue/26232
|
||||
|
||||
[short] skip
|
||||
|
||||
env GOPROXY=direct
|
||||
env GOSUMDB=off
|
||||
|
||||
@@ -55,7 +53,6 @@ go get vcs-test.golang.org/auth/or401
|
||||
env NETRC=$WORK/missing
|
||||
! go get vcs-test.golang.org/auth/or401
|
||||
stderr '^\tserver response: ACCESS DENIED, buddy$'
|
||||
|
||||
-- go.mod --
|
||||
module private.example.com
|
||||
-- $WORK/empty --
|
||||
@@ -63,3 +60,7 @@ module private.example.com
|
||||
machine vcs-test.golang.org
|
||||
login aladdin
|
||||
password opensesame
|
||||
# first one should override this one
|
||||
machine vcs-test.golang.org
|
||||
login aladdin
|
||||
password ignored
|
||||
|
||||
94
src/cmd/go/testdata/script/goauth_userauth.txt
vendored
94
src/cmd/go/testdata/script/goauth_userauth.txt
vendored
@@ -3,13 +3,8 @@
|
||||
|
||||
env GOPROXY=direct
|
||||
env GOSUMDB=off
|
||||
|
||||
# Use a custom authenticator to provide custom credentials
|
||||
mkdir $WORK/bin
|
||||
env PATH=$WORK/bin${:}$PATH
|
||||
cd auth
|
||||
go build -o $WORK/bin/my-auth$GOEXE .
|
||||
cd ..
|
||||
|
||||
# Without credentials, downloading a module from a path that requires HTTPS
|
||||
# basic auth should fail.
|
||||
@@ -21,8 +16,10 @@ stderr '^\tserver response: ACCESS DENIED, buddy$'
|
||||
! go mod tidy
|
||||
stderr '^\tserver response: ACCESS DENIED, buddy$'
|
||||
|
||||
# With credentials from the my-auth binary, it should succeed.
|
||||
env GOAUTH='my-auth'$GOEXE' --arg1 "value with spaces"'
|
||||
# Initial invocation of authenticator is successful.
|
||||
go build -o $WORK/bin/basic$GOEXE scripts/basic.go
|
||||
# With credentials from the binary, it should succeed.
|
||||
env GOAUTH='basic'$GOEXE
|
||||
cp go.mod.orig go.mod
|
||||
go get vcs-test.golang.org/auth/or401
|
||||
# go imports should resolve correctly as well.
|
||||
@@ -30,7 +27,54 @@ go mod tidy
|
||||
go list all
|
||||
stdout vcs-test.golang.org/auth/or401
|
||||
|
||||
-- auth/main.go --
|
||||
# Second invocation of authenticator is successful.
|
||||
go build -o $WORK/bin/reinvocation$GOEXE scripts/reinvocation.go
|
||||
# With credentials from the binary, it should succeed.
|
||||
env GOAUTH='reinvocation'$GOEXE
|
||||
cp go.mod.orig go.mod
|
||||
go get vcs-test.golang.org/auth/or401
|
||||
# go imports should resolve correctly as well.
|
||||
go mod tidy
|
||||
go list all
|
||||
stdout vcs-test.golang.org/auth/or401
|
||||
|
||||
# Authenticator can parse arguments correctly.
|
||||
go build -o $WORK/bin/arguments$GOEXE scripts/arguments.go
|
||||
# With credentials from the binary, it should succeed.
|
||||
env GOAUTH='arguments'$GOEXE' --arg1 "value with spaces"'
|
||||
cp go.mod.orig go.mod
|
||||
go get vcs-test.golang.org/auth/or401
|
||||
# go imports should resolve correctly as well.
|
||||
go mod tidy
|
||||
go list all
|
||||
stdout vcs-test.golang.org/auth/or401
|
||||
|
||||
# Authenticator provides bad credentials.
|
||||
go build -o $WORK/bin/invalid$GOEXE scripts/invalid.go
|
||||
# With credentials from the binary, it should fail.
|
||||
env GOAUTH='invalid'$GOEXE
|
||||
cp go.mod.orig go.mod
|
||||
! go get vcs-test.golang.org/auth/or401
|
||||
stderr '^\tserver response: ACCESS DENIED, buddy$'
|
||||
# go imports should fail as well.
|
||||
! go mod tidy
|
||||
stderr '^\tserver response: ACCESS DENIED, buddy$'
|
||||
|
||||
-- go.mod.orig --
|
||||
module private.example.com
|
||||
-- main.go --
|
||||
package useprivate
|
||||
|
||||
import "vcs-test.golang.org/auth/or401"
|
||||
-- scripts/basic.go --
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Printf("https://vcs-test.golang.org\n\nAuthorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l\n\n")
|
||||
}
|
||||
-- scripts/reinvocation.go --
|
||||
package main
|
||||
|
||||
import(
|
||||
@@ -45,11 +89,7 @@ import(
|
||||
)
|
||||
|
||||
func main() {
|
||||
arg1 := flag.String("arg1", "", "")
|
||||
flag.Parse()
|
||||
if *arg1 != "value with spaces" {
|
||||
log.Fatal("argument with spaces does not work")
|
||||
}
|
||||
// wait for re-invocation
|
||||
if !strings.HasPrefix(flag.Arg(0), "https://vcs-test.golang.org") {
|
||||
return
|
||||
@@ -68,12 +108,28 @@ func main() {
|
||||
}
|
||||
fmt.Printf("https://vcs-test.golang.org\n\nAuthorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l\n\n")
|
||||
}
|
||||
-- scripts/arguments.go --
|
||||
package main
|
||||
|
||||
-- auth/go.mod --
|
||||
module my-auth
|
||||
-- go.mod.orig --
|
||||
module private.example.com
|
||||
-- main.go --
|
||||
package useprivate
|
||||
import(
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
import "vcs-test.golang.org/auth/or401"
|
||||
func main() {
|
||||
arg1 := flag.String("arg1", "", "")
|
||||
flag.Parse()
|
||||
if *arg1 != "value with spaces" {
|
||||
log.Fatal("argument with spaces does not work")
|
||||
}
|
||||
fmt.Printf("https://vcs-test.golang.org\n\nAuthorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l\n\n")
|
||||
}
|
||||
-- scripts/invalid.go --
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Printf("https://vcs-test.golang.org\n\nAuthorization: Basic invalid\n\n")
|
||||
}
|
||||
11
src/cmd/go/testdata/script/gotoolchain_local.txt
vendored
11
src/cmd/go/testdata/script/gotoolchain_local.txt
vendored
@@ -197,6 +197,17 @@ go mod edit -go=1.501 -toolchain=none
|
||||
go version
|
||||
stdout go1.501
|
||||
|
||||
# avoid two-step switch, first from install target requirement, then from GOTOOLCHAIN min
|
||||
# instead, just jump directly to GOTOOLCHAIN min
|
||||
env TESTGO_VERSION=go1.2.3
|
||||
env GODEBUG=toolchaintrace=1
|
||||
env GOTOOLCHAIN=go1.23.0+auto
|
||||
! go install rsc.io/fortune/nonexist@v0.0.1
|
||||
! stderr 'switching to go1.22.9'
|
||||
stderr 'using go1.23.0'
|
||||
env GODEBUG=
|
||||
env GOTOOLCHAIN=auto
|
||||
|
||||
# go install m@v and go run m@v should ignore go.mod and use m@v
|
||||
env TESTGO_VERSION=go1.2.3
|
||||
go mod edit -go=1.999 -toolchain=go1.998
|
||||
|
||||
2
src/cmd/go/testdata/script/mod_help.txt
vendored
2
src/cmd/go/testdata/script/mod_help.txt
vendored
@@ -3,4 +3,4 @@ env GO111MODULE=on
|
||||
# go help get shows usage for get
|
||||
go help get
|
||||
stdout 'usage: go get'
|
||||
stdout 'get using modules to manage source'
|
||||
stdout 'updates go.mod to require those versions'
|
||||
|
||||
4
src/cmd/go/testdata/script/test_flags.txt
vendored
4
src/cmd/go/testdata/script/test_flags.txt
vendored
@@ -15,8 +15,8 @@ stdout '\Aok\s+example.com/x\s+[0-9.s]+\n\z'
|
||||
# Even though ./x looks like a package path, the real package should be
|
||||
# the implicit '.'.
|
||||
! go test --answer=42 ./x
|
||||
stdout '^FAIL\t. \[build failed\]'
|
||||
stderr '^\.: no Go files in '$PWD'$'
|
||||
stdout '^FAIL\t. \[setup failed\]'
|
||||
stderr '^# \.\nno Go files in '$PWD'$'
|
||||
|
||||
# However, *flags* that appear after unrecognized flags should still be
|
||||
# interpreted as flags, under the (possibly-erroneous) assumption that
|
||||
|
||||
47
src/cmd/go/testdata/script/test_fuzz_context.txt
vendored
Normal file
47
src/cmd/go/testdata/script/test_fuzz_context.txt
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
[!fuzz] skip
|
||||
[short] skip
|
||||
env GOCACHE=$WORK/cache
|
||||
|
||||
# Test fuzz.Context.
|
||||
go test -vet=off context_fuzz_test.go
|
||||
stdout ^ok
|
||||
! stdout FAIL
|
||||
|
||||
go test -vet=off -fuzz=Fuzz -fuzztime=1x context_fuzz_test.go
|
||||
stdout ok
|
||||
! stdout FAIL
|
||||
|
||||
-- context_fuzz_test.go --
|
||||
package context_fuzz
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Fuzz(f *testing.F) {
|
||||
ctx := f.Context()
|
||||
if err := ctx.Err(); err != nil {
|
||||
f.Fatalf("expected non-canceled context, got %v", err)
|
||||
}
|
||||
|
||||
f.Fuzz(func(t *testing.T, data []byte) {
|
||||
innerCtx := t.Context()
|
||||
if err := innerCtx.Err(); err != nil {
|
||||
t.Fatalf("expected inner test to not inherit canceled context, got %v", err)
|
||||
}
|
||||
|
||||
t.Cleanup(func() {
|
||||
if !errors.Is(innerCtx.Err(), context.Canceled) {
|
||||
t.Fatal("expected context of inner test to be canceled after its fuzz function finished")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
f.Cleanup(func() {
|
||||
if !errors.Is(ctx.Err(), context.Canceled) {
|
||||
f.Fatal("expected context canceled before cleanup")
|
||||
}
|
||||
})
|
||||
}
|
||||
27
src/cmd/go/testdata/script/test_json_build.txt
vendored
27
src/cmd/go/testdata/script/test_json_build.txt
vendored
@@ -40,6 +40,18 @@ stdout '"Action":"output","Package":"m/loaderror","Output":"FAIL\\tm/loaderror \
|
||||
stdout '"Action":"fail","Package":"m/loaderror","Elapsed":.*,"FailedBuild":"x"'
|
||||
! stderr '.'
|
||||
|
||||
# Test an import cycle loading error in a non test file. (#70820)
|
||||
! go test -json -o=$devnull ./cycle/p
|
||||
stdout '"ImportPath":"m/cycle/q","Action":"build-output","Output":"# m/cycle/p\\n"'
|
||||
stdout '"ImportPath":"m/cycle/q","Action":"build-output","Output":"package m/cycle/p\\n"'
|
||||
stdout '"ImportPath":"m/cycle/q","Action":"build-output","Output":"\\timports m/cycle/q from p.go\\n"'
|
||||
stdout '"ImportPath":"m/cycle/q","Action":"build-output","Output":"\\timports m/cycle/q from q.go: import cycle not allowed\\n"'
|
||||
stdout '"ImportPath":"m/cycle/q","Action":"build-fail"'
|
||||
stdout '"Action":"start","Package":"m/cycle/p"'
|
||||
stdout '"Action":"output","Package":"m/cycle/p","Output":"FAIL\\tm/cycle/p \[setup failed\]\\n"'
|
||||
stdout '"Action":"fail","Package":"m/cycle/p","Elapsed":.*,"FailedBuild":"m/cycle/q"'
|
||||
! stderr '.'
|
||||
|
||||
# Test a vet error
|
||||
! go test -json -o=$devnull ./veterror
|
||||
stdout '"ImportPath":"m/veterror \[m/veterror.test\]","Action":"build-output","Output":"# m/veterror\\n"'
|
||||
@@ -58,8 +70,9 @@ stderr '# m/builderror \[m/builderror.test\]\n'
|
||||
stderr 'builderror'${/}'main_test.go:3:11: undefined: y\n'
|
||||
stdout '"Action":"start","Package":"m/builderror"'
|
||||
stdout '"Action":"output","Package":"m/builderror","Output":"FAIL\\tm/builderror \[build failed\]\\n"'
|
||||
stdout '"Action":"fail","Package":"m/builderror","Elapsed":.*,"FailedBuild":"m/builderror \[m/builderror\.test\]"'
|
||||
|
||||
stdout '"Action":"fail","Package":"m/builderror","Elapsed":[0-9.]+\}'
|
||||
# FailedBuild should NOT appear in the output in this mode.
|
||||
! stdout '"FailedBuild"'
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
@@ -98,3 +111,13 @@ import (
|
||||
func TestVetError(t *testing.T) {
|
||||
fmt.Printf("%s")
|
||||
}
|
||||
-- cycle/p/p.go --
|
||||
package p
|
||||
|
||||
import "m/cycle/q"
|
||||
-- cycle/q/q.go --
|
||||
package q
|
||||
|
||||
import (
|
||||
"m/cycle/q"
|
||||
)
|
||||
|
||||
30
src/cmd/go/testdata/script/test_setup_error.txt
vendored
30
src/cmd/go/testdata/script/test_setup_error.txt
vendored
@@ -33,10 +33,23 @@ stderr '# m/t2/p\n.*package x is not in std'
|
||||
stdout 'FAIL m/t2/p \[setup failed\]'
|
||||
stdout 'ok m/t'
|
||||
|
||||
# Finally, this one is a build error, but produced by cmd/go directly
|
||||
# Test that an import cycle error is reported. Test for #70820
|
||||
! go test -o=$devnull ./cycle/p ./t
|
||||
stderr '# m/cycle/p\n.*package m/cycle/p\n\timports m/cycle/p from p\.go: import cycle not allowed'
|
||||
stdout 'FAIL m/cycle/p \[setup failed\]'
|
||||
stdout 'ok m/t'
|
||||
|
||||
# Test that multiple errors for the same package under test are reported.
|
||||
! go test -o=$devnull ./cycle/q ./t
|
||||
stderr '# m/cycle/q\n.*package m/cycle/q\n\timports m/cycle/p from q\.go\n\timports m/cycle/p from p\.go: import cycle not allowed'
|
||||
stdout 'FAIL m/cycle/q \[setup failed\]'
|
||||
stdout 'ok m/t'
|
||||
|
||||
# Finally, this one is a non-import-cycle load error that
|
||||
# is produced for the package under test.
|
||||
! go test -o=$devnull . ./t
|
||||
stderr '^\.: no Go files in '$PWD'$'
|
||||
stdout 'FAIL . \[build failed\]'
|
||||
stderr '# \.\n.*no Go files in '$PWD'$'
|
||||
stdout 'FAIL . \[setup failed\]'
|
||||
stdout 'ok m/t'
|
||||
|
||||
-- go.mod --
|
||||
@@ -68,6 +81,17 @@ package p
|
||||
package p
|
||||
|
||||
import "m/bad"
|
||||
-- cycle/p/p.go --
|
||||
package p
|
||||
|
||||
import "m/cycle/p"
|
||||
-- cycle/q/q.go --
|
||||
package q
|
||||
|
||||
import (
|
||||
"m/bad"
|
||||
"m/cycle/p"
|
||||
)
|
||||
-- bad/bad.go --
|
||||
package bad
|
||||
|
||||
|
||||
@@ -2,13 +2,16 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package objfile
|
||||
// Package disasm provides disassembly routines.
|
||||
//
|
||||
// It is broken out from cmd/internal/objfile so tools that don't need
|
||||
// disassembling don't need to depend on x/arch disassembler code.
|
||||
package disasm
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"container/list"
|
||||
"debug/gosym"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -19,6 +22,7 @@ import (
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"cmd/internal/objfile"
|
||||
"cmd/internal/src"
|
||||
|
||||
"golang.org/x/arch/arm/armasm"
|
||||
@@ -32,8 +36,8 @@ import (
|
||||
|
||||
// Disasm is a disassembler for a given File.
|
||||
type Disasm struct {
|
||||
syms []Sym //symbols in file, sorted by address
|
||||
pcln Liner // pcln table
|
||||
syms []objfile.Sym // symbols in file, sorted by address
|
||||
pcln objfile.Liner // pcln table
|
||||
text []byte // bytes of text segment (actual instructions)
|
||||
textStart uint64 // start PC of text
|
||||
textEnd uint64 // end PC of text
|
||||
@@ -42,8 +46,12 @@ type Disasm struct {
|
||||
byteOrder binary.ByteOrder // byte order for goarch
|
||||
}
|
||||
|
||||
// Disasm returns a disassembler for the file f.
|
||||
func (e *Entry) Disasm() (*Disasm, error) {
|
||||
// DisasmForFile returns a disassembler for the file f.
|
||||
func DisasmForFile(f *objfile.File) (*Disasm, error) {
|
||||
return disasmForEntry(f.Entries()[0])
|
||||
}
|
||||
|
||||
func disasmForEntry(e *objfile.Entry) (*Disasm, error) {
|
||||
syms, err := e.Symbols()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -269,7 +277,7 @@ func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, pr
|
||||
}
|
||||
|
||||
// Decode disassembles the text segment range [start, end), calling f for each instruction.
|
||||
func (d *Disasm) Decode(start, end uint64, relocs []Reloc, gnuAsm bool, f func(pc, size uint64, file string, line int, text string)) {
|
||||
func (d *Disasm) Decode(start, end uint64, relocs []objfile.Reloc, gnuAsm bool, f func(pc, size uint64, file string, line int, text string)) {
|
||||
if start < d.textStart {
|
||||
start = d.textStart
|
||||
}
|
||||
@@ -402,14 +410,16 @@ func disasm_ppc64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.By
|
||||
func disasm_riscv64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder, gnuAsm bool) (string, int) {
|
||||
inst, err := riscv64asm.Decode(code)
|
||||
var text string
|
||||
size := inst.Len
|
||||
if err != nil || inst.Op == 0 {
|
||||
size = 2
|
||||
text = "?"
|
||||
} else if gnuAsm {
|
||||
text = fmt.Sprintf("%-36s // %s", riscv64asm.GoSyntax(inst, pc, lookup, textReader{code, pc}), riscv64asm.GNUSyntax(inst))
|
||||
} else {
|
||||
text = riscv64asm.GoSyntax(inst, pc, lookup, textReader{code, pc})
|
||||
}
|
||||
return text, 4
|
||||
return text, size
|
||||
}
|
||||
|
||||
func disasm_s390x(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) {
|
||||
@@ -452,9 +462,3 @@ var byteOrders = map[string]binary.ByteOrder{
|
||||
"riscv64": binary.LittleEndian,
|
||||
"s390x": binary.BigEndian,
|
||||
}
|
||||
|
||||
type Liner interface {
|
||||
// Given a pc, returns the corresponding file, line, and function data.
|
||||
// If unknown, returns "",0,nil.
|
||||
PCToLine(uint64) (string, int, *gosym.Func)
|
||||
}
|
||||
@@ -5,22 +5,33 @@
|
||||
// Package hash implements hash functions used in the compiler toolchain.
|
||||
package hash
|
||||
|
||||
// TODO(rsc): Delete the 16 and 20 forms and use 32 at all call sites.
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"hash"
|
||||
)
|
||||
|
||||
const (
|
||||
// Size32 is the size of 32 bytes hash checksum.
|
||||
Size32 = sha256.Size
|
||||
// Size20 is the size of 20 bytes hash checksum.
|
||||
Size20 = sha1.Size
|
||||
// Size16 is the size of 16 bytes hash checksum.
|
||||
Size16 = md5.Size
|
||||
// Size32 is the size of the 32-byte hash checksum.
|
||||
Size32 = 32
|
||||
// Size20 is the size of the 20-byte hash checksum.
|
||||
Size20 = 20
|
||||
// Size16 is the size of the 16-byte hash checksum.
|
||||
Size16 = 16
|
||||
)
|
||||
|
||||
type shortHash struct {
|
||||
hash.Hash
|
||||
n int
|
||||
}
|
||||
|
||||
func (h *shortHash) Sum(b []byte) []byte {
|
||||
old := b
|
||||
sum := h.Hash.Sum(b)
|
||||
return sum[:len(old)+h.n]
|
||||
}
|
||||
|
||||
// New32 returns a new [hash.Hash] computing the 32 bytes hash checksum.
|
||||
func New32() hash.Hash {
|
||||
h := sha256.New()
|
||||
@@ -30,12 +41,12 @@ func New32() hash.Hash {
|
||||
|
||||
// New20 returns a new [hash.Hash] computing the 20 bytes hash checksum.
|
||||
func New20() hash.Hash {
|
||||
return sha1.New()
|
||||
return &shortHash{New32(), 20}
|
||||
}
|
||||
|
||||
// New16 returns a new [hash.Hash] computing the 16 bytes hash checksum.
|
||||
func New16() hash.Hash {
|
||||
return md5.New()
|
||||
return &shortHash{New32(), 16}
|
||||
}
|
||||
|
||||
// Sum32 returns the 32 bytes checksum of the data.
|
||||
@@ -47,10 +58,16 @@ func Sum32(data []byte) [Size32]byte {
|
||||
|
||||
// Sum20 returns the 20 bytes checksum of the data.
|
||||
func Sum20(data []byte) [Size20]byte {
|
||||
return sha1.Sum(data)
|
||||
sum := Sum32(data)
|
||||
var short [Size20]byte
|
||||
copy(short[:], sum[4:])
|
||||
return short
|
||||
}
|
||||
|
||||
// Sum16 returns the 16 bytes checksum of the data.
|
||||
func Sum16(data []byte) [Size16]byte {
|
||||
return md5.Sum(data)
|
||||
sum := Sum32(data)
|
||||
var short [Size16]byte
|
||||
copy(short[:], sum[8:])
|
||||
return short
|
||||
}
|
||||
|
||||
@@ -320,7 +320,7 @@ func (ctxt *Link) NumberSyms() {
|
||||
// Assign special index for builtin symbols.
|
||||
// Don't do it when linking against shared libraries, as the runtime
|
||||
// may be in a different library.
|
||||
if i := goobj.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 {
|
||||
if i := goobj.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 && !rs.IsLinkname() {
|
||||
rs.PkgIdx = goobj.PkgIdxBuiltin
|
||||
rs.SymIdx = int32(i)
|
||||
rs.Set(AttrIndexed, true)
|
||||
|
||||
@@ -119,10 +119,6 @@ func (f *File) DWARF() (*dwarf.Data, error) {
|
||||
return f.entries[0].DWARF()
|
||||
}
|
||||
|
||||
func (f *File) Disasm() (*Disasm, error) {
|
||||
return f.entries[0].Disasm()
|
||||
}
|
||||
|
||||
func (e *Entry) Name() string {
|
||||
return e.name
|
||||
}
|
||||
@@ -181,3 +177,9 @@ func (e *Entry) LoadAddress() (uint64, error) {
|
||||
func (e *Entry) DWARF() (*dwarf.Data, error) {
|
||||
return e.raw.dwarf()
|
||||
}
|
||||
|
||||
type Liner interface {
|
||||
// Given a pc, returns the corresponding file, line, and function data.
|
||||
// If unknown, returns "",0,nil.
|
||||
PCToLine(uint64) (string, int, *gosym.Func)
|
||||
}
|
||||
|
||||
@@ -118,6 +118,7 @@ Flags:
|
||||
Link with race detection libraries.
|
||||
-s
|
||||
Omit the symbol table and debug information.
|
||||
Implies the -w flag, which can be negated with -w=0.
|
||||
-tmpdir dir
|
||||
Write temporary files to dir.
|
||||
Temporary files are only used in external linking mode.
|
||||
|
||||
@@ -55,17 +55,31 @@ import (
|
||||
)
|
||||
|
||||
// isRuntimeDepPkg reports whether pkg is the runtime package or its dependency.
|
||||
// TODO: just compute from the runtime package, and remove this hardcoded list.
|
||||
func isRuntimeDepPkg(pkg string) bool {
|
||||
switch pkg {
|
||||
case "runtime",
|
||||
"sync/atomic", // runtime may call to sync/atomic, due to go:linkname
|
||||
"internal/abi", // used by reflectcall (and maybe more)
|
||||
"internal/bytealg", // for IndexByte
|
||||
"sync/atomic", // runtime may call to sync/atomic, due to go:linkname // TODO: this is not true?
|
||||
"internal/abi", // used by reflectcall (and maybe more)
|
||||
"internal/asan",
|
||||
"internal/bytealg", // for IndexByte
|
||||
"internal/byteorder",
|
||||
"internal/chacha8rand", // for rand
|
||||
"internal/cpu": // for cpu features
|
||||
"internal/coverage/rtcov",
|
||||
"internal/cpu", // for cpu features
|
||||
"internal/goarch",
|
||||
"internal/godebugs",
|
||||
"internal/goexperiment",
|
||||
"internal/goos",
|
||||
"internal/msan",
|
||||
"internal/profilerecord",
|
||||
"internal/race",
|
||||
"internal/stringslite",
|
||||
"unsafe":
|
||||
return true
|
||||
}
|
||||
return strings.HasPrefix(pkg, "runtime/internal/") && !strings.HasSuffix(pkg, "_test")
|
||||
return (strings.HasPrefix(pkg, "runtime/internal/") || strings.HasPrefix(pkg, "internal/runtime/")) &&
|
||||
!strings.HasSuffix(pkg, "_test")
|
||||
}
|
||||
|
||||
// Estimate the max size needed to hold any new trampolines created for this function. This
|
||||
@@ -410,6 +424,9 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
|
||||
// FIXME: It should be forbidden to have R_ADDR from a
|
||||
// symbol which isn't in .data. However, as .text has the
|
||||
// same address once loaded, this is possible.
|
||||
// TODO: .text (including rodata) to .data relocation
|
||||
// doesn't work correctly, so we should really disallow it.
|
||||
// See also aixStaticDataBase in symtab.go and in runtime.
|
||||
if ldr.SymSect(s).Seg == &Segdata {
|
||||
Xcoffadddynrel(target, ldr, syms, s, r, ri)
|
||||
}
|
||||
|
||||
@@ -520,7 +520,7 @@ func (d *dwctxt) defgotype(gotype loader.Sym) loader.Sym {
|
||||
d.linkctxt.Errorf(gotype, "dwarf: type name doesn't start with \"type:\"")
|
||||
return d.mustFind("<unspecified>")
|
||||
}
|
||||
name := sn[5:] // could also decode from Type.string
|
||||
name := sn[len("type:"):] // could also decode from Type.string
|
||||
|
||||
sdie := d.find(name)
|
||||
if sdie != 0 {
|
||||
@@ -534,7 +534,7 @@ func (d *dwctxt) defgotype(gotype loader.Sym) loader.Sym {
|
||||
|
||||
func (d *dwctxt) newtype(gotype loader.Sym) *dwarf.DWDie {
|
||||
sn := d.ldr.SymName(gotype)
|
||||
name := sn[5:] // could also decode from Type.string
|
||||
name := sn[len("type:"):] // could also decode from Type.string
|
||||
tdata := d.ldr.Data(gotype)
|
||||
if len(tdata) == 0 {
|
||||
d.linkctxt.Errorf(gotype, "missing type")
|
||||
|
||||
@@ -707,6 +707,17 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind {
|
||||
// except go:buildid which is generated late and not used by the program.
|
||||
addRef("go:buildid")
|
||||
}
|
||||
if ctxt.IsAIX() {
|
||||
// On AIX, an R_ADDR relocation from an RODATA symbol to a DATA symbol
|
||||
// does not work. See data.go:relocsym, case R_ADDR.
|
||||
// Here we record the unrelocated address in aixStaticDataBase (it is
|
||||
// unrelocated as it is in RODATA) so we can compute the delta at
|
||||
// run time.
|
||||
sb := ldr.CreateSymForUpdate("runtime.aixStaticDataBase", 0)
|
||||
sb.SetSize(0)
|
||||
sb.AddAddr(ctxt.Arch, ldr.Lookup("runtime.data", 0))
|
||||
sb.SetType(sym.SRODATA)
|
||||
}
|
||||
|
||||
// text section information
|
||||
slice(textsectionmapSym, uint64(nsections))
|
||||
|
||||
@@ -2338,6 +2338,45 @@ var blockedLinknames = map[string][]string{
|
||||
"runtime.newcoro": {"iter"},
|
||||
// fips info
|
||||
"go:fipsinfo": {"crypto/internal/fips140/check"},
|
||||
// New internal linknames in Go 1.24
|
||||
// Pushed from runtime
|
||||
"crypto/internal/fips140.fatal": {"crypto/internal/fips140"},
|
||||
"crypto/internal/fips140.getIndicator": {"crypto/internal/fips140"},
|
||||
"crypto/internal/fips140.setIndicator": {"crypto/internal/fips140"},
|
||||
"crypto/internal/sysrand.fatal": {"crypto/internal/sysrand"},
|
||||
"crypto/rand.fatal": {"crypto/rand"},
|
||||
"internal/runtime/maps.errNilAssign": {"internal/runtime/maps"},
|
||||
"internal/runtime/maps.fatal": {"internal/runtime/maps"},
|
||||
"internal/runtime/maps.mapKeyError": {"internal/runtime/maps"},
|
||||
"internal/runtime/maps.newarray": {"internal/runtime/maps"},
|
||||
"internal/runtime/maps.newobject": {"internal/runtime/maps"},
|
||||
"internal/runtime/maps.typedmemclr": {"internal/runtime/maps"},
|
||||
"internal/runtime/maps.typedmemmove": {"internal/runtime/maps"},
|
||||
"internal/sync.fatal": {"internal/sync"},
|
||||
"internal/sync.runtime_canSpin": {"internal/sync"},
|
||||
"internal/sync.runtime_doSpin": {"internal/sync"},
|
||||
"internal/sync.runtime_nanotime": {"internal/sync"},
|
||||
"internal/sync.runtime_Semrelease": {"internal/sync"},
|
||||
"internal/sync.runtime_SemacquireMutex": {"internal/sync"},
|
||||
"internal/sync.throw": {"internal/sync"},
|
||||
"internal/synctest.Run": {"internal/synctest"},
|
||||
"internal/synctest.Wait": {"internal/synctest"},
|
||||
"internal/synctest.acquire": {"internal/synctest"},
|
||||
"internal/synctest.release": {"internal/synctest"},
|
||||
"internal/synctest.inBubble": {"internal/synctest"},
|
||||
"runtime.getStaticuint64s": {"reflect"},
|
||||
"sync.runtime_SemacquireWaitGroup": {"sync"},
|
||||
"time.runtimeNow": {"time"},
|
||||
"time.runtimeNano": {"time"},
|
||||
// Pushed to runtime from internal/runtime/maps
|
||||
// (other map functions are already linknamed in Go 1.23)
|
||||
"runtime.mapaccess1": {"runtime"},
|
||||
"runtime.mapaccess1_fast32": {"runtime"},
|
||||
"runtime.mapaccess1_fast64": {"runtime"},
|
||||
"runtime.mapaccess1_faststr": {"runtime"},
|
||||
"runtime.mapdelete_fast32": {"runtime"},
|
||||
"runtime.mapdelete_fast64": {"runtime"},
|
||||
"runtime.mapdelete_faststr": {"runtime"},
|
||||
}
|
||||
|
||||
// check if a linkname reference to symbol s from pkg is allowed
|
||||
|
||||
@@ -1518,6 +1518,8 @@ func TestCheckLinkname(t *testing.T) {
|
||||
{"coro_asm", false},
|
||||
// pull-only linkname is not ok
|
||||
{"coro2.go", false},
|
||||
// pull linkname of a builtin symbol is not ok
|
||||
{"builtin.go", false},
|
||||
// legacy bad linkname is ok, for now
|
||||
{"fastrand.go", true},
|
||||
{"badlinkname.go", true},
|
||||
|
||||
17
src/cmd/link/testdata/linkname/builtin.go
vendored
Normal file
17
src/cmd/link/testdata/linkname/builtin.go
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
// Linkname builtin symbols (that is not already linknamed,
|
||||
// e.g. mapaccess1) is not allowed.
|
||||
|
||||
package main
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func main() {
|
||||
mapaccess1(nil, nil, nil)
|
||||
}
|
||||
|
||||
//go:linkname mapaccess1 runtime.mapaccess1
|
||||
func mapaccess1(t, m, k unsafe.Pointer) unsafe.Pointer
|
||||
@@ -40,6 +40,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"cmd/internal/disasm"
|
||||
"cmd/internal/objfile"
|
||||
"cmd/internal/telemetry/counter"
|
||||
)
|
||||
@@ -82,7 +83,7 @@ func main() {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
dis, err := f.Disasm()
|
||||
dis, err := disasm.DisasmForFile(f)
|
||||
if err != nil {
|
||||
log.Fatalf("disassemble %s: %v", flag.Arg(0), err)
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"cmd/internal/disasm"
|
||||
"cmd/internal/objfile"
|
||||
"cmd/internal/telemetry/counter"
|
||||
|
||||
@@ -162,7 +163,7 @@ func adjustURL(source string, duration, timeout time.Duration) (string, time.Dur
|
||||
// (instead of invoking GNU binutils).
|
||||
type objTool struct {
|
||||
mu sync.Mutex
|
||||
disasmCache map[string]*objfile.Disasm
|
||||
disasmCache map[string]*disasm.Disasm
|
||||
}
|
||||
|
||||
func (*objTool) Open(name string, start, limit, offset uint64, relocationSymbol string) (driver.ObjFile, error) {
|
||||
@@ -202,11 +203,11 @@ func (t *objTool) Disasm(file string, start, end uint64, intelSyntax bool) ([]dr
|
||||
return asm, nil
|
||||
}
|
||||
|
||||
func (t *objTool) cachedDisasm(file string) (*objfile.Disasm, error) {
|
||||
func (t *objTool) cachedDisasm(file string) (*disasm.Disasm, error) {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
if t.disasmCache == nil {
|
||||
t.disasmCache = make(map[string]*objfile.Disasm)
|
||||
t.disasmCache = make(map[string]*disasm.Disasm)
|
||||
}
|
||||
d := t.disasmCache[file]
|
||||
if d != nil {
|
||||
@@ -216,7 +217,7 @@ func (t *objTool) cachedDisasm(file string) (*objfile.Disasm, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d, err = f.Disasm()
|
||||
d, err = disasm.DisasmForFile(f)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -108,7 +108,7 @@ func TestVet(t *testing.T) {
|
||||
// is a no-op for files whose version >= go1.22, so we use a
|
||||
// go.mod file in the rangeloop directory to "downgrade".
|
||||
//
|
||||
// TOOD(adonovan): delete when go1.21 goes away.
|
||||
// TODO(adonovan): delete when go1.21 goes away.
|
||||
t.Run("loopclosure", func(t *testing.T) {
|
||||
cmd := testenv.Command(t, testenv.GoToolPath(t), "vet", "-vettool="+vetPath(t), ".")
|
||||
cmd.Env = append(os.Environ(), "GOWORK=off")
|
||||
|
||||
@@ -10,23 +10,25 @@
|
||||
// calls to servers should accept a Context. The chain of function
|
||||
// calls between them must propagate the Context, optionally replacing
|
||||
// it with a derived Context created using [WithCancel], [WithDeadline],
|
||||
// [WithTimeout], or [WithValue]. When a Context is canceled, all
|
||||
// Contexts derived from it are also canceled.
|
||||
// [WithTimeout], or [WithValue].
|
||||
//
|
||||
// A Context may be canceled to indicate that work done on its behalf should stop.
|
||||
// A Context with a deadline is canceled after the deadline passes.
|
||||
// When a Context is canceled, all Contexts derived from it are also canceled.
|
||||
//
|
||||
// The [WithCancel], [WithDeadline], and [WithTimeout] functions take a
|
||||
// Context (the parent) and return a derived Context (the child) and a
|
||||
// [CancelFunc]. Calling the CancelFunc cancels the child and its
|
||||
// [CancelFunc]. Calling the CancelFunc directly cancels the child and its
|
||||
// children, removes the parent's reference to the child, and stops
|
||||
// any associated timers. Failing to call the CancelFunc leaks the
|
||||
// child and its children until the parent is canceled or the timer
|
||||
// fires. The go vet tool checks that CancelFuncs are used on all
|
||||
// control-flow paths.
|
||||
// child and its children until the parent is canceled. The go vet tool
|
||||
// checks that CancelFuncs are used on all control-flow paths.
|
||||
//
|
||||
// The [WithCancelCause] function returns a [CancelCauseFunc], which
|
||||
// takes an error and records it as the cancellation cause. Calling
|
||||
// [Cause] on the canceled context or any of its children retrieves
|
||||
// the cause. If no cause is specified, Cause(ctx) returns the same
|
||||
// value as ctx.Err().
|
||||
// The [WithCancelCause], [WithDeadlineCause], and [WithTimeoutCause] functions
|
||||
// return a [CancelCauseFunc], which takes an error and records it as
|
||||
// the cancellation cause. Calling [Cause] on the canceled context
|
||||
// or any of its children retrieves the cause. If no cause is specified,
|
||||
// Cause(ctx) returns the same value as ctx.Err().
|
||||
//
|
||||
// Programs that use Contexts should follow these rules to keep interfaces
|
||||
// consistent across packages and enable static analysis tools to check context
|
||||
@@ -107,8 +109,8 @@ type Context interface {
|
||||
|
||||
// If Done is not yet closed, Err returns nil.
|
||||
// If Done is closed, Err returns a non-nil error explaining why:
|
||||
// Canceled if the context was canceled
|
||||
// or DeadlineExceeded if the context's deadline passed.
|
||||
// DeadlineExceeded if the context's deadline passed,
|
||||
// or Canceled if the context was canceled for some other reason.
|
||||
// After Err returns a non-nil error, successive calls to Err return the same error.
|
||||
Err() error
|
||||
|
||||
@@ -160,11 +162,12 @@ type Context interface {
|
||||
Value(key any) any
|
||||
}
|
||||
|
||||
// Canceled is the error returned by [Context.Err] when the context is canceled.
|
||||
// Canceled is the error returned by [Context.Err] when the context is canceled
|
||||
// for some reason other than its deadline passing.
|
||||
var Canceled = errors.New("context canceled")
|
||||
|
||||
// DeadlineExceeded is the error returned by [Context.Err] when the context's
|
||||
// deadline passes.
|
||||
// DeadlineExceeded is the error returned by [Context.Err] when the context is canceled
|
||||
// due to its deadline passing.
|
||||
var DeadlineExceeded error = deadlineExceededError{}
|
||||
|
||||
type deadlineExceededError struct{}
|
||||
@@ -296,9 +299,8 @@ func Cause(c Context) error {
|
||||
return c.Err()
|
||||
}
|
||||
|
||||
// AfterFunc arranges to call f in its own goroutine after ctx is done
|
||||
// (canceled or timed out).
|
||||
// If ctx is already done, AfterFunc calls f immediately in its own goroutine.
|
||||
// AfterFunc arranges to call f in its own goroutine after ctx is canceled.
|
||||
// If ctx is already canceled, AfterFunc calls f immediately in its own goroutine.
|
||||
//
|
||||
// Multiple calls to AfterFunc on a context operate independently;
|
||||
// one does not replace another.
|
||||
@@ -306,7 +308,7 @@ func Cause(c Context) error {
|
||||
// Calling the returned stop function stops the association of ctx with f.
|
||||
// It returns true if the call stopped f from being run.
|
||||
// If stop returns false,
|
||||
// either the context is done and f has been started in its own goroutine;
|
||||
// either the context is canceled and f has been started in its own goroutine;
|
||||
// or f was already stopped.
|
||||
// The stop function does not wait for f to complete before returning.
|
||||
// If the caller needs to know whether f is completed,
|
||||
|
||||
@@ -146,8 +146,8 @@ func ExampleAfterFunc_cond() {
|
||||
defer stopf()
|
||||
|
||||
// Since the wakeups are using Broadcast instead of Signal, this call to
|
||||
// Wait may unblock due to some other goroutine's context becoming done,
|
||||
// so to be sure that ctx is actually done we need to check it in a loop.
|
||||
// Wait may unblock due to some other goroutine's context being canceled,
|
||||
// so to be sure that ctx is actually canceled we need to check it in a loop.
|
||||
for !conditionMet() {
|
||||
cond.Wait()
|
||||
if ctx.Err() != nil {
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"bytes"
|
||||
"crypto/internal/fips140/aes"
|
||||
"crypto/internal/fips140/alias"
|
||||
"crypto/internal/fips140only"
|
||||
"crypto/subtle"
|
||||
)
|
||||
|
||||
@@ -53,6 +54,9 @@ func NewCBCEncrypter(b Block, iv []byte) BlockMode {
|
||||
if b, ok := b.(*aes.Block); ok {
|
||||
return aes.NewCBCEncrypter(b, [16]byte(iv))
|
||||
}
|
||||
if fips140only.Enabled {
|
||||
panic("crypto/cipher: use of CBC with non-AES ciphers is not allowed in FIPS 140-only mode")
|
||||
}
|
||||
if cbc, ok := b.(cbcEncAble); ok {
|
||||
return cbc.NewCBCEncrypter(iv)
|
||||
}
|
||||
@@ -129,6 +133,9 @@ func NewCBCDecrypter(b Block, iv []byte) BlockMode {
|
||||
if b, ok := b.(*aes.Block); ok {
|
||||
return aes.NewCBCDecrypter(b, [16]byte(iv))
|
||||
}
|
||||
if fips140only.Enabled {
|
||||
panic("crypto/cipher: use of CBC with non-AES ciphers is not allowed in FIPS 140-only mode")
|
||||
}
|
||||
if cbc, ok := b.(cbcDecAble); ok {
|
||||
return cbc.NewCBCDecrypter(iv)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"bytes"
|
||||
"crypto/internal/fips140/aes"
|
||||
"crypto/internal/fips140/alias"
|
||||
"crypto/internal/fips140only"
|
||||
"crypto/subtle"
|
||||
)
|
||||
|
||||
@@ -41,6 +42,9 @@ func NewCTR(block Block, iv []byte) Stream {
|
||||
if block, ok := block.(*aes.Block); ok {
|
||||
return aesCtrWrapper{aes.NewCTR(block, iv)}
|
||||
}
|
||||
if fips140only.Enabled {
|
||||
panic("crypto/cipher: use of CTR with non-AES ciphers is not allowed in FIPS 140-only mode")
|
||||
}
|
||||
if ctr, ok := block.(ctrAble); ok {
|
||||
return ctr.NewCTR(iv)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"bytes"
|
||||
"crypto/internal/boring"
|
||||
"crypto/internal/fips140/ecdh"
|
||||
"crypto/internal/fips140only"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
@@ -43,6 +44,10 @@ func (c *nistCurve) GenerateKey(rand io.Reader) (*PrivateKey, error) {
|
||||
return k, nil
|
||||
}
|
||||
|
||||
if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) {
|
||||
return nil, errors.New("crypto/ecdh: only crypto/rand.Reader is allowed in FIPS 140-only mode")
|
||||
}
|
||||
|
||||
privateKey, err := c.generate(rand)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package ecdsa implements the Elliptic Curve Digital Signature Algorithm, as
|
||||
// defined in FIPS 186-5 and SEC 1, Version 2.0.
|
||||
// defined in [FIPS 186-5].
|
||||
//
|
||||
// Signatures generated by this package are not deterministic, but entropy is
|
||||
// mixed with the private key and the message, achieving the same level of
|
||||
@@ -12,6 +12,8 @@
|
||||
// Operations involving private keys are implemented using constant-time
|
||||
// algorithms, as long as an [elliptic.Curve] returned by [elliptic.P224],
|
||||
// [elliptic.P256], [elliptic.P384], or [elliptic.P521] is used.
|
||||
//
|
||||
// [FIPS 186-5]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf
|
||||
package ecdsa
|
||||
|
||||
import (
|
||||
@@ -21,6 +23,7 @@ import (
|
||||
"crypto/internal/boring"
|
||||
"crypto/internal/boring/bbig"
|
||||
"crypto/internal/fips140/ecdsa"
|
||||
"crypto/internal/fips140only"
|
||||
"crypto/internal/randutil"
|
||||
"crypto/sha512"
|
||||
"crypto/subtle"
|
||||
@@ -182,6 +185,9 @@ func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
|
||||
}
|
||||
|
||||
func generateFIPS[P ecdsa.Point[P]](curve elliptic.Curve, c *ecdsa.Curve[P], rand io.Reader) (*PrivateKey, error) {
|
||||
if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) {
|
||||
return nil, errors.New("crypto/ecdsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
|
||||
}
|
||||
privateKey, err := ecdsa.GenerateKey(c, rand)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -228,6 +234,9 @@ func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
func signFIPS[P ecdsa.Point[P]](c *ecdsa.Curve[P], priv *PrivateKey, rand io.Reader, hash []byte) ([]byte, error) {
|
||||
if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) {
|
||||
return nil, errors.New("crypto/ecdsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
|
||||
}
|
||||
// privateKeyToFIPS is very slow in FIPS mode because it performs a
|
||||
// Sign+Verify cycle per FIPS 140-3 IG 10.3.A. We should find a way to cache
|
||||
// it or attach it to the PrivateKey.
|
||||
|
||||
@@ -26,7 +26,7 @@ func Enabled() bool {
|
||||
if currentlyEnabled != fips140.Enabled {
|
||||
panic("crypto/fips140: GODEBUG setting changed after program start")
|
||||
}
|
||||
if fips140.Enabled && !check.Enabled() {
|
||||
if fips140.Enabled && !check.Verified {
|
||||
panic("crypto/fips140: FIPS 140-3 mode enabled, but integrity check didn't pass")
|
||||
}
|
||||
return fips140.Enabled
|
||||
|
||||
@@ -16,6 +16,7 @@ import "C"
|
||||
import (
|
||||
"crypto/internal/boring/sig"
|
||||
_ "crypto/internal/boring/syso"
|
||||
"crypto/internal/fips140"
|
||||
"internal/stringslite"
|
||||
"math/bits"
|
||||
"unsafe"
|
||||
@@ -31,6 +32,12 @@ func init() {
|
||||
sig.BoringCrypto()
|
||||
}
|
||||
|
||||
func init() {
|
||||
if fips140.Enabled {
|
||||
panic("boringcrypto: cannot use GODEBUG=fips140 with GOEXPERIMENT=boringcrypto")
|
||||
}
|
||||
}
|
||||
|
||||
// Unreachable marks code that should be unreachable
|
||||
// when BoringCrypto is in use. It panics.
|
||||
func Unreachable() {
|
||||
|
||||
@@ -32,6 +32,12 @@ func SkipTestAllocations(t *testing.T) {
|
||||
t.Skip("skipping allocations test on plan9")
|
||||
}
|
||||
|
||||
// s390x deviates from other assembly implementations and is very hard to
|
||||
// test due to the lack of LUCI builders. See #67307.
|
||||
if runtime.GOARCH == "s390x" {
|
||||
t.Skip("skipping allocations test on s390x")
|
||||
}
|
||||
|
||||
// Some APIs rely on inliner and devirtualization to allocate on the stack.
|
||||
testenv.SkipIfOptimizationOff(t)
|
||||
}
|
||||
|
||||
@@ -94,6 +94,8 @@ func newBlockExpanded(c *blockExpanded, key []byte) {
|
||||
func (c *Block) BlockSize() int { return BlockSize }
|
||||
|
||||
func (c *Block) Encrypt(dst, src []byte) {
|
||||
// AES-ECB is not approved in FIPS 140-3 mode.
|
||||
fips140.RecordNonApproved()
|
||||
if len(src) < BlockSize {
|
||||
panic("crypto/aes: input not full block")
|
||||
}
|
||||
@@ -103,11 +105,12 @@ func (c *Block) Encrypt(dst, src []byte) {
|
||||
if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
|
||||
panic("crypto/aes: invalid buffer overlap")
|
||||
}
|
||||
fips140.RecordApproved()
|
||||
encryptBlock(c, dst, src)
|
||||
}
|
||||
|
||||
func (c *Block) Decrypt(dst, src []byte) {
|
||||
// AES-ECB is not approved in FIPS 140-3 mode.
|
||||
fips140.RecordNonApproved()
|
||||
if len(src) < BlockSize {
|
||||
panic("crypto/aes: input not full block")
|
||||
}
|
||||
@@ -117,6 +120,12 @@ func (c *Block) Decrypt(dst, src []byte) {
|
||||
if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
|
||||
panic("crypto/aes: invalid buffer overlap")
|
||||
}
|
||||
fips140.RecordApproved()
|
||||
decryptBlock(c, dst, src)
|
||||
}
|
||||
|
||||
// EncryptBlockInternal applies the AES encryption function to one block.
|
||||
//
|
||||
// It is an internal function meant only for the gcm package.
|
||||
func EncryptBlockInternal(c *Block, dst, src []byte) {
|
||||
encryptBlock(c, dst, src)
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ func cryptBlocksEncGeneric(b *Block, civ *[BlockSize]byte, dst, src []byte) {
|
||||
for len(src) > 0 {
|
||||
// Write the xor to dst, then encrypt in place.
|
||||
subtle.XORBytes(dst[:BlockSize], src[:BlockSize], iv)
|
||||
b.Encrypt(dst[:BlockSize], dst[:BlockSize])
|
||||
encryptBlock(b, dst[:BlockSize], dst[:BlockSize])
|
||||
|
||||
// Move to the next block with this block as the next iv.
|
||||
iv = dst[:BlockSize]
|
||||
@@ -111,7 +111,7 @@ func cryptBlocksDecGeneric(b *Block, civ *[BlockSize]byte, dst, src []byte) {
|
||||
copy(civ[:], src[start:end])
|
||||
|
||||
for start >= 0 {
|
||||
b.Decrypt(dst[start:end], src[start:end])
|
||||
decryptBlock(b, dst[start:end], src[start:end])
|
||||
|
||||
if start > 0 {
|
||||
subtle.XORBytes(dst[start:end], dst[start:end], src[prev:start])
|
||||
|
||||
@@ -132,7 +132,7 @@ func ctrBlocks(b *Block, dst, src []byte, ivlo, ivhi uint64) {
|
||||
byteorder.BEPutUint64(buf[i:], ivhi)
|
||||
byteorder.BEPutUint64(buf[i+8:], ivlo)
|
||||
ivlo, ivhi = add128(ivlo, ivhi, 1)
|
||||
b.Encrypt(buf[i:], buf[i:])
|
||||
encryptBlock(b, buf[i:], buf[i:])
|
||||
}
|
||||
// XOR into buf first, in case src and dst overlap (see above).
|
||||
subtle.XORBytes(buf, src, buf)
|
||||
|
||||
@@ -28,7 +28,7 @@ func NewCMAC(b *aes.Block) *CMAC {
|
||||
}
|
||||
|
||||
func (c *CMAC) deriveSubkeys() {
|
||||
c.b.Encrypt(c.k1[:], c.k1[:])
|
||||
aes.EncryptBlockInternal(&c.b, c.k1[:], c.k1[:])
|
||||
msb := shiftLeft(&c.k1)
|
||||
c.k1[len(c.k1)-1] ^= msb * 0b10000111
|
||||
|
||||
@@ -45,7 +45,7 @@ func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte {
|
||||
// Special-cased as a single empty partial final block.
|
||||
x = c.k2
|
||||
x[len(m)] ^= 0b10000000
|
||||
c.b.Encrypt(x[:], x[:])
|
||||
aes.EncryptBlockInternal(&c.b, x[:], x[:])
|
||||
return x
|
||||
}
|
||||
for len(m) >= aes.BlockSize {
|
||||
@@ -54,7 +54,7 @@ func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte {
|
||||
// Final complete block.
|
||||
subtle.XORBytes(x[:], c.k1[:], x[:])
|
||||
}
|
||||
c.b.Encrypt(x[:], x[:])
|
||||
aes.EncryptBlockInternal(&c.b, x[:], x[:])
|
||||
m = m[aes.BlockSize:]
|
||||
}
|
||||
if len(m) > 0 {
|
||||
@@ -62,7 +62,7 @@ func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte {
|
||||
subtle.XORBytes(x[:], m, x[:])
|
||||
subtle.XORBytes(x[:], c.k2[:], x[:])
|
||||
x[len(m)] ^= 0b10000000
|
||||
c.b.Encrypt(x[:], x[:])
|
||||
aes.EncryptBlockInternal(&c.b, x[:], x[:])
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ func seal(out []byte, g *GCM, nonce, plaintext, data []byte) {
|
||||
gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
|
||||
}
|
||||
|
||||
g.cipher.Encrypt(tagMask[:], counter[:])
|
||||
aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:])
|
||||
|
||||
var tagOut [gcmTagSize]byte
|
||||
gcmAesData(&g.productTable, data, &tagOut)
|
||||
@@ -114,7 +114,7 @@ func open(out []byte, g *GCM, nonce, ciphertext, data []byte) error {
|
||||
gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
|
||||
}
|
||||
|
||||
g.cipher.Encrypt(tagMask[:], counter[:])
|
||||
aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:])
|
||||
|
||||
var expectedTag [gcmTagSize]byte
|
||||
gcmAesData(&g.productTable, data, &expectedTag)
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
func sealGeneric(out []byte, g *GCM, nonce, plaintext, additionalData []byte) {
|
||||
var H, counter, tagMask [gcmBlockSize]byte
|
||||
g.cipher.Encrypt(H[:], H[:])
|
||||
aes.EncryptBlockInternal(&g.cipher, H[:], H[:])
|
||||
deriveCounterGeneric(&H, &counter, nonce)
|
||||
gcmCounterCryptGeneric(&g.cipher, tagMask[:], tagMask[:], &counter)
|
||||
|
||||
@@ -25,7 +25,7 @@ func sealGeneric(out []byte, g *GCM, nonce, plaintext, additionalData []byte) {
|
||||
|
||||
func openGeneric(out []byte, g *GCM, nonce, ciphertext, additionalData []byte) error {
|
||||
var H, counter, tagMask [gcmBlockSize]byte
|
||||
g.cipher.Encrypt(H[:], H[:])
|
||||
aes.EncryptBlockInternal(&g.cipher, H[:], H[:])
|
||||
deriveCounterGeneric(&H, &counter, nonce)
|
||||
gcmCounterCryptGeneric(&g.cipher, tagMask[:], tagMask[:], &counter)
|
||||
|
||||
@@ -70,7 +70,7 @@ func gcmCounterCryptGeneric(b *aes.Block, out, src []byte, counter *[gcmBlockSiz
|
||||
var mask [gcmBlockSize]byte
|
||||
|
||||
for len(src) >= gcmBlockSize {
|
||||
b.Encrypt(mask[:], counter[:])
|
||||
aes.EncryptBlockInternal(b, mask[:], counter[:])
|
||||
gcmInc32(counter)
|
||||
|
||||
subtle.XORBytes(out, src, mask[:])
|
||||
@@ -79,7 +79,7 @@ func gcmCounterCryptGeneric(b *aes.Block, out, src []byte, counter *[gcmBlockSiz
|
||||
}
|
||||
|
||||
if len(src) > 0 {
|
||||
b.Encrypt(mask[:], counter[:])
|
||||
aes.EncryptBlockInternal(b, mask[:], counter[:])
|
||||
gcmInc32(counter)
|
||||
subtle.XORBytes(out, src, mask[:])
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func initGCM(g *GCM) {
|
||||
}
|
||||
|
||||
hle := make([]byte, gcmBlockSize)
|
||||
g.cipher.Encrypt(hle, hle)
|
||||
aes.EncryptBlockInternal(&g.cipher, hle, hle)
|
||||
|
||||
// Reverse the bytes in each 8 byte chunk
|
||||
// Load little endian, store big endian
|
||||
@@ -133,7 +133,7 @@ func seal(out []byte, g *GCM, nonce, plaintext, data []byte) {
|
||||
var counter, tagMask [gcmBlockSize]byte
|
||||
deriveCounter(&counter, nonce, &g.productTable)
|
||||
|
||||
g.cipher.Encrypt(tagMask[:], counter[:])
|
||||
aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:])
|
||||
gcmInc32(&counter)
|
||||
|
||||
counterCrypt(&g.cipher, out, plaintext, &counter)
|
||||
@@ -151,7 +151,7 @@ func open(out []byte, g *GCM, nonce, ciphertext, data []byte) error {
|
||||
var counter, tagMask [gcmBlockSize]byte
|
||||
deriveCounter(&counter, nonce, &g.productTable)
|
||||
|
||||
g.cipher.Encrypt(tagMask[:], counter[:])
|
||||
aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:])
|
||||
gcmInc32(&counter)
|
||||
|
||||
var expectedTag [gcmTagSize]byte
|
||||
|
||||
@@ -55,7 +55,7 @@ func initGCM(g *GCM) {
|
||||
return
|
||||
}
|
||||
// Note that hashKey is also used in the KMA codepath to hash large nonces.
|
||||
g.cipher.Encrypt(g.hashKey[:], g.hashKey[:])
|
||||
aes.EncryptBlockInternal(&g.cipher, g.hashKey[:], g.hashKey[:])
|
||||
}
|
||||
|
||||
// ghashAsm uses the GHASH algorithm to hash data with the given key. The initial
|
||||
@@ -115,7 +115,7 @@ func counterCrypt(g *GCM, dst, src []byte, cnt *[gcmBlockSize]byte) {
|
||||
}
|
||||
if len(src) > 0 {
|
||||
var x [16]byte
|
||||
g.cipher.Encrypt(x[:], cnt[:])
|
||||
aes.EncryptBlockInternal(&g.cipher, x[:], cnt[:])
|
||||
for i := range src {
|
||||
dst[i] = src[i] ^ x[i]
|
||||
}
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
|
||||
//go:build asan
|
||||
|
||||
package check
|
||||
package fips140
|
||||
|
||||
const asanEnabled = true
|
||||
@@ -134,6 +134,13 @@ func (x *Nat) set(y *Nat) *Nat {
|
||||
return x
|
||||
}
|
||||
|
||||
// Bits returns x as a little-endian slice of uint. The length of the slice
|
||||
// matches the announced length of x. The result and x share the same underlying
|
||||
// array.
|
||||
func (x *Nat) Bits() []uint {
|
||||
return x.limbs
|
||||
}
|
||||
|
||||
// Bytes returns x as a zero-extended big-endian byte slice. The size of the
|
||||
// slice will match the size of m.
|
||||
//
|
||||
@@ -1058,6 +1065,34 @@ func (out *Nat) ExpShortVarTime(x *Nat, e uint, m *Modulus) *Nat {
|
||||
//
|
||||
//go:norace
|
||||
func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) {
|
||||
u, A, err := extendedGCD(a, m.nat)
|
||||
if err != nil {
|
||||
return x, false
|
||||
}
|
||||
if u.IsOne() == no {
|
||||
return x, false
|
||||
}
|
||||
return x.set(A), true
|
||||
}
|
||||
|
||||
// GCDVarTime calculates x = GCD(a, b) where at least one of a or b is odd, and
|
||||
// both are non-zero. If GCDVarTime returns an error, x is not modified.
|
||||
//
|
||||
// The output will be resized to the size of the larger of a and b.
|
||||
func (x *Nat) GCDVarTime(a, b *Nat) (*Nat, error) {
|
||||
u, _, err := extendedGCD(a, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return x.set(u), nil
|
||||
}
|
||||
|
||||
// extendedGCD computes u and A such that a = GCD(a, m) and u = A*a - B*m.
|
||||
//
|
||||
// u will have the size of the larger of a and m, and A will have the size of m.
|
||||
//
|
||||
// It is an error if either a or m is zero, or if they are both even.
|
||||
func extendedGCD(a, m *Nat) (u, A *Nat, err error) {
|
||||
// This is the extended binary GCD algorithm described in the Handbook of
|
||||
// Applied Cryptography, Algorithm 14.61, adapted by BoringSSL to bound
|
||||
// coefficients and avoid negative numbers. For more details and proof of
|
||||
@@ -1068,7 +1103,7 @@ func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) {
|
||||
// 1. Negate [B] and [C] so they are positive. The invariant now involves a
|
||||
// subtraction.
|
||||
// 2. If step 2 (both [x] and [y] are even) runs, abort immediately. This
|
||||
// algorithm only cares about [x] and [y] relatively prime.
|
||||
// case needs to be handled by the caller.
|
||||
// 3. Subtract copies of [x] and [y] as needed in step 6 (both [u] and [v]
|
||||
// are odd) so coefficients stay in bounds.
|
||||
// 4. Replace the [u >= v] check with [u > v]. This changes the end
|
||||
@@ -1082,21 +1117,21 @@ func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) {
|
||||
//
|
||||
// Note this algorithm does not handle either input being zero.
|
||||
|
||||
if a.IsZero() == yes {
|
||||
return x, false
|
||||
if a.IsZero() == yes || m.IsZero() == yes {
|
||||
return nil, nil, errors.New("extendedGCD: a or m is zero")
|
||||
}
|
||||
if a.IsOdd() == no && !m.odd {
|
||||
// a and m are not coprime, as they are both even.
|
||||
return x, false
|
||||
if a.IsOdd() == no && m.IsOdd() == no {
|
||||
return nil, nil, errors.New("extendedGCD: both a and m are even")
|
||||
}
|
||||
|
||||
u := NewNat().set(a).ExpandFor(m)
|
||||
v := m.Nat()
|
||||
size := max(len(a.limbs), len(m.limbs))
|
||||
u = NewNat().set(a).expand(size)
|
||||
v := NewNat().set(m).expand(size)
|
||||
|
||||
A := NewNat().reset(len(m.nat.limbs))
|
||||
A = NewNat().reset(len(m.limbs))
|
||||
A.limbs[0] = 1
|
||||
B := NewNat().reset(len(a.limbs))
|
||||
C := NewNat().reset(len(m.nat.limbs))
|
||||
C := NewNat().reset(len(m.limbs))
|
||||
D := NewNat().reset(len(a.limbs))
|
||||
D.limbs[0] = 1
|
||||
|
||||
@@ -1119,11 +1154,11 @@ func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) {
|
||||
if u.IsOdd() == yes && v.IsOdd() == yes {
|
||||
if v.cmpGeq(u) == no {
|
||||
u.sub(v)
|
||||
A.Add(C, m)
|
||||
A.Add(C, &Modulus{nat: m})
|
||||
B.Add(D, &Modulus{nat: a})
|
||||
} else {
|
||||
v.sub(u)
|
||||
C.Add(A, m)
|
||||
C.Add(A, &Modulus{nat: m})
|
||||
D.Add(B, &Modulus{nat: a})
|
||||
}
|
||||
}
|
||||
@@ -1137,7 +1172,7 @@ func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) {
|
||||
if u.IsOdd() == no {
|
||||
rshift1(u, 0)
|
||||
if A.IsOdd() == yes || B.IsOdd() == yes {
|
||||
rshift1(A, A.add(m.nat))
|
||||
rshift1(A, A.add(m))
|
||||
rshift1(B, B.add(a))
|
||||
} else {
|
||||
rshift1(A, 0)
|
||||
@@ -1146,7 +1181,7 @@ func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) {
|
||||
} else { // v.IsOdd() == no
|
||||
rshift1(v, 0)
|
||||
if C.IsOdd() == yes || D.IsOdd() == yes {
|
||||
rshift1(C, C.add(m.nat))
|
||||
rshift1(C, C.add(m))
|
||||
rshift1(D, D.add(a))
|
||||
} else {
|
||||
rshift1(C, 0)
|
||||
@@ -1155,10 +1190,7 @@ func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) {
|
||||
}
|
||||
|
||||
if v.IsZero() == yes {
|
||||
if u.IsOne() == no {
|
||||
return x, false
|
||||
}
|
||||
return x.set(A), true
|
||||
return u, A, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1177,3 +1209,20 @@ func rshift1(a *Nat, carry uint) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DivShortVarTime calculates x = x / y and returns the remainder.
|
||||
//
|
||||
// It panics if y is zero.
|
||||
//
|
||||
//go:norace
|
||||
func (x *Nat) DivShortVarTime(y uint) uint {
|
||||
if y == 0 {
|
||||
panic("bigmod: division by zero")
|
||||
}
|
||||
|
||||
var r uint
|
||||
for i := len(x.limbs) - 1; i >= 0; i-- {
|
||||
x.limbs[i], r = bits.Div(r, x.limbs[i], y)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
10
src/crypto/internal/fips140/boring.go
Normal file
10
src/crypto/internal/fips140/boring.go
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
// Keep in sync with notboring.go and crypto/internal/boring/boring.go.
|
||||
//go:build boringcrypto && linux && (amd64 || arm64) && !android && !msan && cgo
|
||||
|
||||
package fips140
|
||||
|
||||
const boringEnabled = true
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package check implements the FIPS-140 load-time code+data verification.
|
||||
// Package check implements the FIPS 140 load-time code+data verification.
|
||||
// Every FIPS package providing cryptographic functionality except hmac and sha256
|
||||
// must import crypto/internal/fips140/check, so that the verification happens
|
||||
// before initialization of package global variables.
|
||||
@@ -13,37 +13,18 @@
|
||||
package check
|
||||
|
||||
import (
|
||||
"crypto/internal/fips140"
|
||||
"crypto/internal/fips140/hmac"
|
||||
"crypto/internal/fips140/sha256"
|
||||
"crypto/internal/fips140deps/byteorder"
|
||||
"crypto/internal/fips140deps/godebug"
|
||||
"io"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Enabled reports whether verification was enabled.
|
||||
// If Enabled returns true, then verification succeeded,
|
||||
// because if it failed the binary would have panicked at init time.
|
||||
func Enabled() bool {
|
||||
return enabled
|
||||
}
|
||||
|
||||
var enabled bool // set when verification is enabled
|
||||
var Verified bool // set when verification succeeds, for testing
|
||||
|
||||
// Supported reports whether the current GOOS/GOARCH is Supported at all.
|
||||
func Supported() bool {
|
||||
// See cmd/internal/obj/fips.go's EnableFIPS for commentary.
|
||||
switch {
|
||||
case runtime.GOARCH == "wasm",
|
||||
runtime.GOOS == "windows" && runtime.GOARCH == "386",
|
||||
runtime.GOOS == "windows" && runtime.GOARCH == "arm",
|
||||
runtime.GOOS == "aix":
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
// Verified is set when verification succeeded. It can be expected to always be
|
||||
// true when [fips140.Enabled] is true, or init would have panicked.
|
||||
var Verified bool
|
||||
|
||||
// Linkinfo holds the go:fipsinfo symbol prepared by the linker.
|
||||
// See cmd/link/internal/ld/fips.go for details.
|
||||
@@ -71,32 +52,12 @@ const fipsMagic = " Go fipsinfo \xff\x00"
|
||||
var zeroSum [32]byte
|
||||
|
||||
func init() {
|
||||
v := godebug.Value("#fips140")
|
||||
enabled = v != "" && v != "off"
|
||||
if !enabled {
|
||||
if !fips140.Enabled {
|
||||
return
|
||||
}
|
||||
|
||||
if asanEnabled {
|
||||
// ASAN disapproves of reading swaths of global memory below.
|
||||
// One option would be to expose runtime.asanunpoison through
|
||||
// crypto/internal/fips140deps and then call it to unpoison the range
|
||||
// before reading it, but it is unclear whether that would then cause
|
||||
// false negatives. For now, FIPS+ASAN doesn't need to work.
|
||||
// If this is made to work, also re-enable the test in check_test.go
|
||||
// and in cmd/dist/test.go.
|
||||
panic("fips140: cannot verify in asan mode")
|
||||
}
|
||||
|
||||
switch v {
|
||||
case "on", "only", "debug":
|
||||
// ok
|
||||
default:
|
||||
panic("fips140: unknown GODEBUG setting fips140=" + v)
|
||||
}
|
||||
|
||||
if !Supported() {
|
||||
panic("fips140: unavailable on " + runtime.GOOS + "-" + runtime.GOARCH)
|
||||
if err := fips140.Supported(); err != nil {
|
||||
panic("fips140: " + err.Error())
|
||||
}
|
||||
|
||||
if Linkinfo.Magic[0] != 0xff || string(Linkinfo.Magic[1:]) != fipsMagic || Linkinfo.Sum == zeroSum {
|
||||
@@ -132,7 +93,14 @@ func init() {
|
||||
panic("fips140: verification mismatch")
|
||||
}
|
||||
|
||||
if v == "debug" {
|
||||
// "The temporary value(s) generated during the integrity test of the
|
||||
// module’s software or firmware shall [05.10] be zeroised from the module
|
||||
// upon completion of the integrity test"
|
||||
clear(sum)
|
||||
clear(nbuf[:])
|
||||
h.Reset()
|
||||
|
||||
if godebug.Value("#fips140") == "debug" {
|
||||
println("fips140: verified code+data")
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,21 @@ package drbg
|
||||
import (
|
||||
"crypto/internal/entropy"
|
||||
"crypto/internal/fips140"
|
||||
"crypto/internal/randutil"
|
||||
"crypto/internal/sysrand"
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var mu sync.Mutex
|
||||
var drbg *Counter
|
||||
var drbgs = sync.Pool{
|
||||
New: func() any {
|
||||
var c *Counter
|
||||
entropy.Depleted(func(seed *[48]byte) {
|
||||
c = NewCounter(seed)
|
||||
})
|
||||
return c
|
||||
},
|
||||
}
|
||||
|
||||
// Read fills b with cryptographically secure random bytes. In FIPS mode, it
|
||||
// uses an SP 800-90A Rev. 1 Deterministic Random Bit Generator (DRBG).
|
||||
@@ -31,14 +40,8 @@ func Read(b []byte) {
|
||||
additionalInput := new([SeedSize]byte)
|
||||
sysrand.Read(additionalInput[:16])
|
||||
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
if drbg == nil {
|
||||
entropy.Depleted(func(seed *[48]byte) {
|
||||
drbg = NewCounter(seed)
|
||||
})
|
||||
}
|
||||
drbg := drbgs.Get().(*Counter)
|
||||
defer drbgs.Put(drbg)
|
||||
|
||||
for len(b) > 0 {
|
||||
size := min(len(b), maxRequestSize)
|
||||
@@ -56,3 +59,38 @@ func Read(b []byte) {
|
||||
b = b[size:]
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultReader is a sentinel type, embedded in the default
|
||||
// [crypto/rand.Reader], used to recognize it when passed to
|
||||
// APIs that accept a rand io.Reader.
|
||||
type DefaultReader interface{ defaultReader() }
|
||||
|
||||
// ReadWithReader uses Reader to fill b with cryptographically secure random
|
||||
// bytes. It is intended for use in APIs that expose a rand io.Reader.
|
||||
//
|
||||
// If Reader is not the default Reader from crypto/rand,
|
||||
// [randutil.MaybeReadByte] and [fips140.RecordNonApproved] are called.
|
||||
func ReadWithReader(r io.Reader, b []byte) error {
|
||||
if _, ok := r.(DefaultReader); ok {
|
||||
Read(b)
|
||||
return nil
|
||||
}
|
||||
|
||||
fips140.RecordNonApproved()
|
||||
randutil.MaybeReadByte(r)
|
||||
_, err := io.ReadFull(r, b)
|
||||
return err
|
||||
}
|
||||
|
||||
// ReadWithReaderDeterministic is like ReadWithReader, but it doesn't call
|
||||
// [randutil.MaybeReadByte] on non-default Readers.
|
||||
func ReadWithReaderDeterministic(r io.Reader, b []byte) error {
|
||||
if _, ok := r.(DefaultReader); ok {
|
||||
Read(b)
|
||||
return nil
|
||||
}
|
||||
|
||||
fips140.RecordNonApproved()
|
||||
_, err := io.ReadFull(r, b)
|
||||
return err
|
||||
}
|
||||
|
||||
27
src/crypto/internal/fips140/drbg/rand_test.go
Normal file
27
src/crypto/internal/fips140/drbg/rand_test.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2025 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 drbg
|
||||
|
||||
import (
|
||||
"crypto/internal/fips140"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkDBRG(b *testing.B) {
|
||||
old := fips140.Enabled
|
||||
defer func() {
|
||||
fips140.Enabled = old
|
||||
}()
|
||||
fips140.Enabled = true
|
||||
|
||||
const N = 64
|
||||
b.SetBytes(N)
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
buf := make([]byte, N)
|
||||
for pb.Next() {
|
||||
Read(buf)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"crypto/internal/fips140/drbg"
|
||||
"crypto/internal/fips140/nistec"
|
||||
"crypto/internal/fips140deps/byteorder"
|
||||
"crypto/internal/randutil"
|
||||
"errors"
|
||||
"io"
|
||||
"math/bits"
|
||||
@@ -137,8 +136,6 @@ var p521Order = []byte{0x01, 0xff,
|
||||
}
|
||||
|
||||
// GenerateKey generates a new ECDSA private key pair for the specified curve.
|
||||
//
|
||||
// In FIPS mode, rand is ignored.
|
||||
func GenerateKey[P Point[P]](c *Curve[P], rand io.Reader) (*PrivateKey, error) {
|
||||
fips140.RecordApproved()
|
||||
// This procedure is equivalent to Key Pair Generation by Testing
|
||||
@@ -146,18 +143,13 @@ func GenerateKey[P Point[P]](c *Curve[P], rand io.Reader) (*PrivateKey, error) {
|
||||
|
||||
for {
|
||||
key := make([]byte, len(c.N))
|
||||
if fips140.Enabled {
|
||||
drbg.Read(key)
|
||||
} else {
|
||||
randutil.MaybeReadByte(rand)
|
||||
if _, err := io.ReadFull(rand, key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// In tests, rand will return all zeros and NewPrivateKey will reject
|
||||
// the zero key as it generates the identity as a public key. This also
|
||||
// makes this function consistent with crypto/elliptic.GenerateKey.
|
||||
key[1] ^= 0x42
|
||||
if err := drbg.ReadWithReader(rand, key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// In tests, rand will return all zeros and NewPrivateKey will reject
|
||||
// the zero key as it generates the identity as a public key. This also
|
||||
// makes this function consistent with crypto/elliptic.GenerateKey.
|
||||
key[1] ^= 0x42
|
||||
|
||||
// Mask off any excess bits if the size of the underlying field is not a
|
||||
// whole number of bytes, which is only the case for P-521.
|
||||
|
||||
@@ -54,7 +54,8 @@ func testHash() []byte {
|
||||
func fipsPCT[P Point[P]](c *Curve[P], k *PrivateKey) error {
|
||||
return fips140.PCT("ECDSA PCT", func() error {
|
||||
hash := testHash()
|
||||
sig, err := Sign(c, sha512.New, k, nil, hash)
|
||||
drbg := newDRBG(sha512.New, k.d, bits2octets(P256(), hash), nil)
|
||||
sig, err := sign(c, k, drbg, hash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"crypto/internal/fips140/bigmod"
|
||||
"crypto/internal/fips140/drbg"
|
||||
"crypto/internal/fips140/nistec"
|
||||
"crypto/internal/randutil"
|
||||
"errors"
|
||||
"io"
|
||||
"sync"
|
||||
@@ -22,7 +21,7 @@ import (
|
||||
|
||||
type PrivateKey struct {
|
||||
pub PublicKey
|
||||
d []byte // bigmod.(*Nat).Bytes output (fixed length)
|
||||
d []byte // bigmod.(*Nat).Bytes output (same length as the curve order)
|
||||
}
|
||||
|
||||
func (priv *PrivateKey) Bytes() []byte {
|
||||
@@ -187,20 +186,11 @@ func NewPublicKey[P Point[P]](c *Curve[P], Q []byte) (*PublicKey, error) {
|
||||
}
|
||||
|
||||
// GenerateKey generates a new ECDSA private key pair for the specified curve.
|
||||
//
|
||||
// In FIPS mode, rand is ignored.
|
||||
func GenerateKey[P Point[P]](c *Curve[P], rand io.Reader) (*PrivateKey, error) {
|
||||
fips140.RecordApproved()
|
||||
|
||||
k, Q, err := randomPoint(c, func(b []byte) error {
|
||||
if fips140.Enabled {
|
||||
drbg.Read(b)
|
||||
return nil
|
||||
} else {
|
||||
randutil.MaybeReadByte(rand)
|
||||
_, err := io.ReadFull(rand, b)
|
||||
return err
|
||||
}
|
||||
return drbg.ReadWithReader(rand, b)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -272,7 +262,7 @@ func randomPoint[P Point[P]](c *Curve[P], generate func([]byte) error) (k *bigmo
|
||||
var testingOnlyRejectionSamplingLooped func()
|
||||
|
||||
// Signature is an ECDSA signature, where r and s are represented as big-endian
|
||||
// fixed-length byte slices.
|
||||
// byte slices of the same length as the curve order.
|
||||
type Signature struct {
|
||||
R, S []byte
|
||||
}
|
||||
@@ -281,8 +271,6 @@ type Signature struct {
|
||||
// the hash function H) using the private key, priv. If the hash is longer than
|
||||
// the bit-length of the private key's curve order, the hash will be truncated
|
||||
// to that length.
|
||||
//
|
||||
// The signature is randomized. If FIPS mode is enabled, rand is ignored.
|
||||
func Sign[P Point[P], H fips140.Hash](c *Curve[P], h func() H, priv *PrivateKey, rand io.Reader, hash []byte) (*Signature, error) {
|
||||
if priv.pub.curve != c.curve {
|
||||
return nil, errors.New("ecdsa: private key does not match curve")
|
||||
@@ -296,13 +284,8 @@ func Sign[P Point[P], H fips140.Hash](c *Curve[P], h func() H, priv *PrivateKey,
|
||||
// advantage of closely resembling Deterministic ECDSA.
|
||||
|
||||
Z := make([]byte, len(priv.d))
|
||||
if fips140.Enabled {
|
||||
drbg.Read(Z)
|
||||
} else {
|
||||
randutil.MaybeReadByte(rand)
|
||||
if _, err := io.ReadFull(rand, Z); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := drbg.ReadWithReader(rand, Z); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// See https://github.com/cfrg/draft-irtf-cfrg-det-sigs-with-noise/issues/6
|
||||
|
||||
@@ -47,15 +47,34 @@ func canUseKDSA(c curveID) (functionCode uint64, blockSize int, ok bool) {
|
||||
case p384:
|
||||
return 2, 48, true
|
||||
case p521:
|
||||
// Note that the block size doesn't match the field size for P-521.
|
||||
return 3, 80, true
|
||||
}
|
||||
return 0, 0, false // A mismatch
|
||||
}
|
||||
|
||||
func hashToBytes[P Point[P]](c *Curve[P], dst, hash []byte) {
|
||||
func hashToBytes[P Point[P]](c *Curve[P], hash []byte) []byte {
|
||||
e := bigmod.NewNat()
|
||||
hashToNat(c, e, hash)
|
||||
copy(dst, e.Bytes(c.N))
|
||||
return e.Bytes(c.N)
|
||||
}
|
||||
|
||||
func appendBlock(p []byte, blocksize int, b []byte) []byte {
|
||||
if len(b) > blocksize {
|
||||
panic("ecdsa: internal error: appendBlock input larger than block")
|
||||
}
|
||||
padding := blocksize - len(b)
|
||||
p = append(p, make([]byte, padding)...)
|
||||
return append(p, b...)
|
||||
}
|
||||
|
||||
func trimBlock(p []byte, size int) ([]byte, error) {
|
||||
for _, b := range p[:len(p)-size] {
|
||||
if b != 0 {
|
||||
return nil, errors.New("ecdsa: internal error: KDSA produced invalid signature")
|
||||
}
|
||||
}
|
||||
return p[len(p)-size:], nil
|
||||
}
|
||||
|
||||
func sign[P Point[P]](c *Curve[P], priv *PrivateKey, drbg *hmacDRBG, hash []byte) (*Signature, error) {
|
||||
@@ -95,17 +114,27 @@ func sign[P Point[P]](c *Curve[P], priv *PrivateKey, drbg *hmacDRBG, hash []byte
|
||||
|
||||
// Copy content into the parameter block. In the sign case,
|
||||
// we copy hashed message, private key and random number into
|
||||
// the parameter block.
|
||||
hashToBytes(c, params[2*blockSize:3*blockSize], hash)
|
||||
copy(params[3*blockSize+blockSize-len(priv.d):], priv.d)
|
||||
copy(params[4*blockSize:5*blockSize], k.Bytes(c.N))
|
||||
// the parameter block. We skip the signature slots.
|
||||
p := params[:2*blockSize]
|
||||
p = appendBlock(p, blockSize, hashToBytes(c, hash))
|
||||
p = appendBlock(p, blockSize, priv.d)
|
||||
p = appendBlock(p, blockSize, k.Bytes(c.N))
|
||||
// Convert verify function code into a sign function code by adding 8.
|
||||
// We also need to set the 'deterministic' bit in the function code, by
|
||||
// adding 128, in order to stop the instruction using its own random number
|
||||
// generator in addition to the random number we supply.
|
||||
switch kdsa(functionCode+136, ¶ms) {
|
||||
case 0: // success
|
||||
return &Signature{R: params[:blockSize], S: params[blockSize : 2*blockSize]}, nil
|
||||
elementSize := (c.N.BitLen() + 7) / 8
|
||||
r, err := trimBlock(params[:blockSize], elementSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s, err := trimBlock(params[blockSize:2*blockSize], elementSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Signature{R: r, S: s}, nil
|
||||
case 1: // error
|
||||
return nil, errors.New("zero parameter")
|
||||
case 2: // retry
|
||||
@@ -149,10 +178,12 @@ func verify[P Point[P]](c *Curve[P], pub *PublicKey, hash []byte, sig *Signature
|
||||
// Copy content into the parameter block. In the verify case,
|
||||
// we copy signature (r), signature(s), hashed message, public key x component,
|
||||
// and public key y component into the parameter block.
|
||||
copy(params[0*blockSize+blockSize-len(r):], r)
|
||||
copy(params[1*blockSize+blockSize-len(s):], s)
|
||||
hashToBytes(c, params[2*blockSize:3*blockSize], hash)
|
||||
copy(params[3*blockSize:5*blockSize], pub.q[1:]) // strip 0x04 prefix
|
||||
p := params[:0]
|
||||
p = appendBlock(p, blockSize, r)
|
||||
p = appendBlock(p, blockSize, s)
|
||||
p = appendBlock(p, blockSize, hashToBytes(c, hash))
|
||||
p = appendBlock(p, blockSize, pub.q[1:1+len(pub.q)/2])
|
||||
p = appendBlock(p, blockSize, pub.q[1+len(pub.q)/2:])
|
||||
if kdsa(functionCode, ¶ms) != 0 {
|
||||
return errors.New("invalid signature")
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"crypto/internal/fips140/edwards25519"
|
||||
"crypto/internal/fips140/sha512"
|
||||
"errors"
|
||||
"io"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@@ -61,24 +60,14 @@ func (pub *PublicKey) Bytes() []byte {
|
||||
}
|
||||
|
||||
// GenerateKey generates a new Ed25519 private key pair.
|
||||
//
|
||||
// In FIPS mode, rand is ignored. Otherwise, the output of this function is
|
||||
// deterministic, and equivalent to reading 32 bytes from rand, and passing them
|
||||
// to [NewKeyFromSeed].
|
||||
func GenerateKey(rand io.Reader) (*PrivateKey, error) {
|
||||
func GenerateKey() (*PrivateKey, error) {
|
||||
priv := &PrivateKey{}
|
||||
return generateKey(priv, rand)
|
||||
return generateKey(priv)
|
||||
}
|
||||
|
||||
func generateKey(priv *PrivateKey, rand io.Reader) (*PrivateKey, error) {
|
||||
func generateKey(priv *PrivateKey) (*PrivateKey, error) {
|
||||
fips140.RecordApproved()
|
||||
if fips140.Enabled {
|
||||
drbg.Read(priv.seed[:])
|
||||
} else {
|
||||
if _, err := io.ReadFull(rand, priv.seed[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
drbg.Read(priv.seed[:])
|
||||
precomputePrivateKey(priv)
|
||||
if err := fipsPCT(priv); err != nil {
|
||||
// This clearly can't happen, but FIPS 140-3 requires that we check.
|
||||
|
||||
@@ -4,18 +4,64 @@
|
||||
|
||||
package fips140
|
||||
|
||||
import "crypto/internal/fips140deps/godebug"
|
||||
import (
|
||||
"crypto/internal/fips140deps/godebug"
|
||||
"errors"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var Enabled bool
|
||||
|
||||
var debug bool
|
||||
|
||||
func init() {
|
||||
switch godebug.Value("#fips140") {
|
||||
v := godebug.Value("#fips140")
|
||||
switch v {
|
||||
case "on", "only":
|
||||
Enabled = true
|
||||
case "debug":
|
||||
Enabled = true
|
||||
debug = true
|
||||
case "off", "":
|
||||
default:
|
||||
panic("fips140: unknown GODEBUG setting fips140=" + v)
|
||||
}
|
||||
}
|
||||
|
||||
// Supported returns an error if FIPS 140-3 mode can't be enabled.
|
||||
func Supported() error {
|
||||
// Keep this in sync with fipsSupported in cmd/dist/test.go.
|
||||
|
||||
// ASAN disapproves of reading swaths of global memory in fips140/check.
|
||||
// One option would be to expose runtime.asanunpoison through
|
||||
// crypto/internal/fips140deps and then call it to unpoison the range
|
||||
// before reading it, but it is unclear whether that would then cause
|
||||
// false negatives. For now, FIPS+ASAN doesn't need to work.
|
||||
if asanEnabled {
|
||||
return errors.New("FIPS 140-3 mode is incompatible with ASAN")
|
||||
}
|
||||
|
||||
// See EnableFIPS in cmd/internal/obj/fips.go for commentary.
|
||||
switch {
|
||||
case runtime.GOARCH == "wasm",
|
||||
runtime.GOOS == "windows" && runtime.GOARCH == "386",
|
||||
runtime.GOOS == "windows" && runtime.GOARCH == "arm",
|
||||
runtime.GOOS == "openbsd", // due to -fexecute-only, see #70880
|
||||
runtime.GOOS == "aix":
|
||||
return errors.New("FIPS 140-3 mode is not supported on " + runtime.GOOS + "-" + runtime.GOARCH)
|
||||
}
|
||||
|
||||
if boringEnabled {
|
||||
return errors.New("FIPS 140-3 mode is incompatible with GOEXPERIMENT=boringcrypto")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Name() string {
|
||||
return "Go Cryptographic Module"
|
||||
}
|
||||
|
||||
func Version() string {
|
||||
return "v1.0"
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ func init() {
|
||||
dk := &DecapsulationKey768{}
|
||||
kemKeyGen(dk, d, z)
|
||||
ek := dk.EncapsulationKey()
|
||||
c, Ke := ek.EncapsulateInternal(m)
|
||||
Ke, c := ek.EncapsulateInternal(m)
|
||||
Kd, err := dk.Decapsulate(c)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -189,7 +189,7 @@ func kemKeyGen1024(dk *DecapsulationKey1024, d, z *[32]byte) {
|
||||
// the first operational use (if not exported before the first use)."
|
||||
func kemPCT1024(dk *DecapsulationKey1024) error {
|
||||
ek := dk.EncapsulationKey()
|
||||
c, K := ek.Encapsulate()
|
||||
K, c := ek.Encapsulate()
|
||||
K1, err := dk.Decapsulate(c)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -204,13 +204,13 @@ func kemPCT1024(dk *DecapsulationKey1024) error {
|
||||
// encapsulation key, drawing random bytes from a DRBG.
|
||||
//
|
||||
// The shared key must be kept secret.
|
||||
func (ek *EncapsulationKey1024) Encapsulate() (ciphertext, sharedKey []byte) {
|
||||
func (ek *EncapsulationKey1024) Encapsulate() (sharedKey, ciphertext []byte) {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
var cc [CiphertextSize1024]byte
|
||||
return ek.encapsulate(&cc)
|
||||
}
|
||||
|
||||
func (ek *EncapsulationKey1024) encapsulate(cc *[CiphertextSize1024]byte) (ciphertext, sharedKey []byte) {
|
||||
func (ek *EncapsulationKey1024) encapsulate(cc *[CiphertextSize1024]byte) (sharedKey, ciphertext []byte) {
|
||||
var m [messageSize]byte
|
||||
drbg.Read(m[:])
|
||||
// Note that the modulus check (step 2 of the encapsulation key check from
|
||||
@@ -221,7 +221,7 @@ func (ek *EncapsulationKey1024) encapsulate(cc *[CiphertextSize1024]byte) (ciphe
|
||||
|
||||
// EncapsulateInternal is a derandomized version of Encapsulate, exclusively for
|
||||
// use in tests.
|
||||
func (ek *EncapsulationKey1024) EncapsulateInternal(m *[32]byte) (ciphertext, sharedKey []byte) {
|
||||
func (ek *EncapsulationKey1024) EncapsulateInternal(m *[32]byte) (sharedKey, ciphertext []byte) {
|
||||
cc := &[CiphertextSize1024]byte{}
|
||||
return kemEncaps1024(cc, ek, m)
|
||||
}
|
||||
@@ -229,14 +229,14 @@ func (ek *EncapsulationKey1024) EncapsulateInternal(m *[32]byte) (ciphertext, sh
|
||||
// kemEncaps1024 generates a shared key and an associated ciphertext.
|
||||
//
|
||||
// It implements ML-KEM.Encaps_internal according to FIPS 203, Algorithm 17.
|
||||
func kemEncaps1024(cc *[CiphertextSize1024]byte, ek *EncapsulationKey1024, m *[messageSize]byte) (c, K []byte) {
|
||||
func kemEncaps1024(cc *[CiphertextSize1024]byte, ek *EncapsulationKey1024, m *[messageSize]byte) (K, c []byte) {
|
||||
g := sha3.New512()
|
||||
g.Write(m[:])
|
||||
g.Write(ek.h[:])
|
||||
G := g.Sum(nil)
|
||||
K, r := G[:SharedKeySize], G[SharedKeySize:]
|
||||
c = pkeEncrypt1024(cc, &ek.encryptionKey1024, m, r)
|
||||
return c, K
|
||||
return K, c
|
||||
}
|
||||
|
||||
// NewEncapsulationKey1024 parses an encapsulation key from its encoded form.
|
||||
|
||||
@@ -246,7 +246,7 @@ func kemKeyGen(dk *DecapsulationKey768, d, z *[32]byte) {
|
||||
// the first operational use (if not exported before the first use)."
|
||||
func kemPCT(dk *DecapsulationKey768) error {
|
||||
ek := dk.EncapsulationKey()
|
||||
c, K := ek.Encapsulate()
|
||||
K, c := ek.Encapsulate()
|
||||
K1, err := dk.Decapsulate(c)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -261,13 +261,13 @@ func kemPCT(dk *DecapsulationKey768) error {
|
||||
// encapsulation key, drawing random bytes from a DRBG.
|
||||
//
|
||||
// The shared key must be kept secret.
|
||||
func (ek *EncapsulationKey768) Encapsulate() (ciphertext, sharedKey []byte) {
|
||||
func (ek *EncapsulationKey768) Encapsulate() (sharedKey, ciphertext []byte) {
|
||||
// The actual logic is in a separate function to outline this allocation.
|
||||
var cc [CiphertextSize768]byte
|
||||
return ek.encapsulate(&cc)
|
||||
}
|
||||
|
||||
func (ek *EncapsulationKey768) encapsulate(cc *[CiphertextSize768]byte) (ciphertext, sharedKey []byte) {
|
||||
func (ek *EncapsulationKey768) encapsulate(cc *[CiphertextSize768]byte) (sharedKey, ciphertext []byte) {
|
||||
var m [messageSize]byte
|
||||
drbg.Read(m[:])
|
||||
// Note that the modulus check (step 2 of the encapsulation key check from
|
||||
@@ -278,7 +278,7 @@ func (ek *EncapsulationKey768) encapsulate(cc *[CiphertextSize768]byte) (ciphert
|
||||
|
||||
// EncapsulateInternal is a derandomized version of Encapsulate, exclusively for
|
||||
// use in tests.
|
||||
func (ek *EncapsulationKey768) EncapsulateInternal(m *[32]byte) (ciphertext, sharedKey []byte) {
|
||||
func (ek *EncapsulationKey768) EncapsulateInternal(m *[32]byte) (sharedKey, ciphertext []byte) {
|
||||
cc := &[CiphertextSize768]byte{}
|
||||
return kemEncaps(cc, ek, m)
|
||||
}
|
||||
@@ -286,14 +286,14 @@ func (ek *EncapsulationKey768) EncapsulateInternal(m *[32]byte) (ciphertext, sha
|
||||
// kemEncaps generates a shared key and an associated ciphertext.
|
||||
//
|
||||
// It implements ML-KEM.Encaps_internal according to FIPS 203, Algorithm 17.
|
||||
func kemEncaps(cc *[CiphertextSize768]byte, ek *EncapsulationKey768, m *[messageSize]byte) (c, K []byte) {
|
||||
func kemEncaps(cc *[CiphertextSize768]byte, ek *EncapsulationKey768, m *[messageSize]byte) (K, c []byte) {
|
||||
g := sha3.New512()
|
||||
g.Write(m[:])
|
||||
g.Write(ek.h[:])
|
||||
G := g.Sum(nil)
|
||||
K, r := G[:SharedKeySize], G[SharedKeySize:]
|
||||
c = pkeEncrypt(cc, &ek.encryptionKey, m, r)
|
||||
return c, K
|
||||
return K, c
|
||||
}
|
||||
|
||||
// NewEncapsulationKey768 parses an encapsulation key from its encoded form.
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
|
||||
//go:build !asan
|
||||
|
||||
package check
|
||||
package fips140
|
||||
|
||||
const asanEnabled = false
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user