diff options
| author | Cherry Mui <cherryyz@google.com> | 2026-03-17 21:59:52 -0400 |
|---|---|---|
| committer | Cherry Mui <cherryyz@google.com> | 2026-03-24 12:43:58 -0700 |
| commit | e20a1b603579fc36148530048c76de6938347019 (patch) | |
| tree | e20fc02f9420f4860a689ca97d3b9ef50a9c6d03 /src | |
| parent | 3390ec59af33d3c9ab431ff88a245b710b7c9e40 (diff) | |
| download | go-e20a1b603579fc36148530048c76de6938347019.tar.xz | |
cmd/compile: handle string literals in FIPS mode consistently
There are different code paths for compiling a composite literal,
e.g. small vs. large, fully static vs. partially static. Following
CL 755600, we need to apply the condition for string literals in
FIPS mode consistently in all places.
Enhance the test to check that not only does the code compile, the
same code inside and outside of FIPS mode produce the same result.
If the condition is not consistent in the compiler, it may compile
the code, but not all the fields are actually assigned.
Fixes #78173.
Change-Id: Icaf673bd4798d4312d86c39b147d7fd33b9dae2c
Reviewed-on: https://go-review.googlesource.com/c/go/+/756260
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/cmd/compile/internal/walk/complit.go | 30 | ||||
| -rw-r--r-- | src/crypto/internal/fips140/compile_test.go | 53 | ||||
| -rw-r--r-- | src/crypto/internal/fips140/export_test.go | 49 |
3 files changed, 109 insertions, 23 deletions
diff --git a/src/cmd/compile/internal/walk/complit.go b/src/cmd/compile/internal/walk/complit.go index 053b124a91..e0ffca86ce 100644 --- a/src/cmd/compile/internal/walk/complit.go +++ b/src/cmd/compile/internal/walk/complit.go @@ -85,9 +85,7 @@ const ( func getdyn(n ir.Node, top bool) initGenType { switch n.Op() { default: - // Handle constants in linker, except that linker cannot do - // the relocations necessary for string constants in FIPS packages. - if ir.IsConstNode(n) && (!n.Type().IsString() || !base.Ctxt.IsFIPS()) { + if isStaticLiteral(n) { return initConst } return initDynamic @@ -127,8 +125,17 @@ func getdyn(n ir.Node, top bool) initGenType { return mode } -// isStaticCompositeLiteral reports whether n is a compile-time constant, -// which can be represented in the read-only data section. +// isStaticLiteral reports whether n is a compile-time (non-composite) +// constant, which can be represented in the read-only data section. +func isStaticLiteral(n ir.Node) bool { + // A string reference requires a relocation, not allowed + // in static data in FIPS mode. + return ir.IsConstNode(n) && !(base.Ctxt.IsFIPS() && n.Type().IsString()) +} + +// isStaticCompositeLiteral reports whether a composite literal n +// is a compile-time constant, which can be represented in the +// read-only data section. func isStaticCompositeLiteral(n ir.Node) bool { switch n.Op() { case ir.OSLICELIT: @@ -153,13 +160,10 @@ func isStaticCompositeLiteral(n ir.Node) bool { } } return true - case ir.OLITERAL, ir.ONIL: - if base.Ctxt.IsFIPS() && n.Type().IsString() { - // A string reference requires a relocation, not allowed - // in static data in FIPS mode. - return false - } + case ir.ONIL: return true + case ir.OLITERAL: + return isStaticLiteral(n) case ir.OCONVIFACE: // See staticinit.Schedule.StaticAssign's OCONVIFACE case for comments. if base.Ctxt.IsFIPS() && base.Ctxt.Flag_shared { @@ -264,7 +268,7 @@ func fixedlit(ctxt initContext, kind initKind, n *ir.CompLitExpr, var_ ir.Node, continue } - islit := ir.IsConstNode(value) + islit := isStaticLiteral(value) if (kind == initKindStatic && !islit) || (kind == initKindDynamic && islit) { continue } @@ -404,7 +408,7 @@ func slicelit(ctxt initContext, n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes) continue } - if vstat != nil && ir.IsConstNode(value) { // already set by copy from static value + if vstat != nil && isStaticLiteral(value) { // already set by copy from static value continue } diff --git a/src/crypto/internal/fips140/compile_test.go b/src/crypto/internal/fips140/compile_test.go index 97434b9a0b..4832dd1ac1 100644 --- a/src/crypto/internal/fips140/compile_test.go +++ b/src/crypto/internal/fips140/compile_test.go @@ -2,23 +2,56 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package fips140 +package fips140_test -import "testing" +import ( + "crypto/internal/fips140" + "slices" + "testing" +) // This test checks that we can compile and link specific // code patterns in a FIPS package, where there are restrictions // on what relocations are allowed to use. +// Also checks that the code inside and outside of FIPS mode +// produce same result. The code in fips140.Literals and +// wantLiterals are the same. Keep them in sync. -type testType struct { - A, B, C string -} - -func TestCompile(t *testing.T) { - var a []testType - a = append(a, testType{ - A: "", +func wantLiterals() (a []fips140.TestType, b []fips140.TestType2) { + a = append(a, fips140.TestType{ + A: "a", B: "", C: "", }) + a = append(a, fips140.TestType{ + A: "a", + B: fips140.DynamicString(), + C: "", + }) + b = append(b, fips140.TestType2{ + A: "a", + B: "", + C: "", + D: "", + E: "", + }) + b = append(b, fips140.TestType2{ + A: "a", + B: fips140.DynamicString(), + C: "", + D: "d", + E: fips140.DynamicString(), + }) + return a, b +} + +func TestCompile(t *testing.T) { + wantA, wantB := wantLiterals() + gotA, gotB := fips140.Literals() + if !slices.Equal(gotA, wantA) { + t.Errorf("FIPS and non-FIPS mode produce different results: want %q, got %q", wantA, gotA) + } + if !slices.Equal(gotB, wantB) { + t.Errorf("FIPS and non-FIPS mode produce different results: want %q, got %q", wantB, gotB) + } } diff --git a/src/crypto/internal/fips140/export_test.go b/src/crypto/internal/fips140/export_test.go new file mode 100644 index 0000000000..65478ea904 --- /dev/null +++ b/src/crypto/internal/fips140/export_test.go @@ -0,0 +1,49 @@ +// Copyright 2026 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 fips140 + +type TestType struct { + A, B, C string +} + +type TestType2 struct { + A, B, C, D, E string +} + +//go:noinline +func DynamicString() string { return "dyn" } + +// This code is in the fips140 package, so it is compiled in +// FIPS mode. In the external test compile_test.go, wantLiterals +// is the same code. Keep them in sync. See TestCompile. + +//go:noinline +func Literals() (a []TestType, b []TestType2) { + a = append(a, TestType{ + A: "a", + B: "", + C: "", + }) + a = append(a, TestType{ + A: "a", + B: DynamicString(), + C: "", + }) + b = append(b, TestType2{ + A: "a", + B: "", + C: "", + D: "", + E: "", + }) + b = append(b, TestType2{ + A: "a", + B: DynamicString(), + C: "", + D: "d", + E: DynamicString(), + }) + return a, b +} |
