fix 64-bit aligment for 32-bit platforms

sync/atomic must be used with 64-bit aligned fields, and that alignment is difficult to
ensure unless the field is the first one in the struct.

https://golang.org/pkg/sync/atomic/#pkg-note-BUG.
This commit is contained in:
Daniel Nephin 2021-06-28 18:19:44 -04:00
parent 902bd80989
commit e226733b26
3 changed files with 16 additions and 7 deletions

3
.changelog/10515.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:bug
agent: fix a panic on 32-bit platforms caused by misaligned struct fields used with sync/atomic.
```

View File

@ -52,8 +52,11 @@ var defaultMetrics = metrics.Default
// statsHandler is a grpc/stats.StatsHandler which emits connection and // statsHandler is a grpc/stats.StatsHandler which emits connection and
// request metrics to go-metrics. // request metrics to go-metrics.
type statsHandler struct { type statsHandler struct {
// activeConns is used with sync/atomic and MUST be 64-bit aligned. To ensure
// alignment on 32-bit platforms this field must remain the first field in
// the struct. See https://golang.org/pkg/sync/atomic/#pkg-note-BUG.
activeConns uint64
metrics *metrics.Metrics metrics *metrics.Metrics
activeConns uint64 // must be 8-byte aligned for atomic access
} }
func newStatsHandler(m *metrics.Metrics) *statsHandler { func newStatsHandler(m *metrics.Metrics) *statsHandler {
@ -103,10 +106,11 @@ func (c *statsHandler) HandleConn(_ context.Context, s stats.ConnStats) {
} }
type activeStreamCounter struct { type activeStreamCounter struct {
metrics *metrics.Metrics // count is used with sync/atomic and MUST be 64-bit aligned. To ensure
// count of the number of open streaming RPCs on a server. It is accessed // alignment on 32-bit platforms this field must remain the first field in
// atomically. // the struct. See https://golang.org/pkg/sync/atomic/#pkg-note-BUG.
count uint64 count uint64
metrics *metrics.Metrics
} }
// GRPCCountingStreamInterceptor is a grpc.ServerStreamInterceptor that emits a // GRPCCountingStreamInterceptor is a grpc.ServerStreamInterceptor that emits a

View File

@ -175,6 +175,11 @@ type manual struct {
// Configurator receives an initial TLS configuration from agent configuration, // Configurator receives an initial TLS configuration from agent configuration,
// and receives updates from config reloads, auto-encrypt, and auto-config. // and receives updates from config reloads, auto-encrypt, and auto-config.
type Configurator struct { type Configurator struct {
// version is increased each time the Configurator is updated. Must be accessed
// using sync/atomic. Also MUST be the first field in this struct to ensure
// 64-bit alignment. See https://golang.org/pkg/sync/atomic/#pkg-note-BUG.
version uint64
// lock synchronizes access to all fields on this struct except for logger and version. // lock synchronizes access to all fields on this struct except for logger and version.
lock sync.RWMutex lock sync.RWMutex
base *Config base *Config
@ -188,9 +193,6 @@ type Configurator struct {
// logger is not protected by a lock. It must never be changed after // logger is not protected by a lock. It must never be changed after
// Configurator is created. // Configurator is created.
logger hclog.Logger logger hclog.Logger
// version is increased each time the Configurator is updated. Must be accessed
// using sync/atomic.
version uint64
} }
// NewConfigurator creates a new Configurator and sets the provided // NewConfigurator creates a new Configurator and sets the provided