Skip to content

Commit 43193cd

Browse files
committed
trace: fix race condition
Found with `go test -race -run=TestPatchConflicts ./test/integration/apiserver` in Kubernetes. writeTraceSteps gets called while the mutex of t is locked, so iterating over t.traceItems is fine. But then it calls stepOrTrace.time = Trace.time of another instance. Retrieving that time is done without locking the mutex of that other instance and thus races with setting the end time of that trace in End. WARNING: DATA RACE Write at 0x00c009fed898 by goroutine 124291: k8s.io/kubernetes/vendor/k8s.io/utils/trace.(*Trace).Log() /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/k8s.io/utils/trace/trace.go:175 +0xc4 k8s.io/kubernetes/vendor/k8s.io/utils/trace.(*Trace).LogIfLong() /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/k8s.io/utils/trace/trace.go:194 +0xc4 k8s.io/kubernetes/vendor/k8s.io/component-base/tracing.(*Span).End() /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/k8s.io/component-base/tracing/tracing.go:67 +0x8f k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/storage/etcd3.(*store).GuaranteedUpdate.func2() /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/storage/etcd3/store.go:384 +0x3e runtime.deferreturn() /home/prow/go/src/k8s.io/kubernetes/_output/local/.gimme/versions/go1.20.2.linux.amd64/src/runtime/panic.go:476 +0x32 k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/storage/cacher.(*Cacher).GuaranteedUpdate() /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/storage/cacher/cacher.go:839 +0x1cc k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/registry/generic/registry.(*DryRunnableStorage).GuaranteedUpdate() /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/registry/generic/registry/dryrun.go:93 +0x321 k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/registry/generic/registry.(*Store).Update() /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/registry/generic/registry/store.go:559 +0x858 k8s.io/kubernetes/pkg/registry/core/secret/storage.(*REST).Update() <autogenerated>:1 +0xfe k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/endpoints/handlers.(*patcher).patchResource.func2() /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/endpoints/handlers/patch.go:666 +0x1f1 k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/endpoints/handlers.(*patcher).patchResource.func3() /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/endpoints/handlers/patch.go:672 +0x57 k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/endpoints/handlers/finisher.finishRequest.func1() /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/endpoints/handlers/finisher/finisher.go:117 +0xfa Previous read at 0x00c009fed898 by goroutine 124286: k8s.io/kubernetes/vendor/k8s.io/utils/trace.(*Trace).time() /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/k8s.io/utils/trace/trace.go:110 +0x3e k8s.io/kubernetes/vendor/k8s.io/utils/trace.(*Trace).writeTraceSteps() /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/k8s.io/utils/trace/trace.go:235 +0x17a k8s.io/kubernetes/vendor/k8s.io/utils/trace.(*Trace).logTrace() /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/k8s.io/utils/trace/trace.go:216 +0x4c7 k8s.io/kubernetes/vendor/k8s.io/utils/trace.(*Trace).Log() /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/k8s.io/utils/trace/trace.go:179 +0x118 k8s.io/kubernetes/vendor/k8s.io/utils/trace.(*Trace).LogIfLong() /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/k8s.io/utils/trace/trace.go:194 +0xc4 k8s.io/kubernetes/vendor/k8s.io/component-base/tracing.(*Span).End() /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/k8s.io/component-base/tracing/tracing.go:67 +0x8f k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/endpoints/handlers.PatchResource.func1.1() /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/endpoints/handlers/patch.go:69 +0x3e ...
1 parent 38a27ef commit 43193cd

File tree

1 file changed

+19
-0
lines changed

1 file changed

+19
-0
lines changed

trace/trace.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ func durationToMilliseconds(timeDuration time.Duration) int64 {
6565
}
6666

6767
type traceItem interface {
68+
// rLock must be called before invoking time or writeItem.
69+
rLock()
70+
// rUnlock must be called after processing the item is complete.
71+
rUnlock()
72+
6873
// time returns when the trace was recorded as completed.
6974
time() time.Time
7075
// writeItem outputs the traceItem to the buffer. If stepThreshold is non-nil, only output the
@@ -79,6 +84,10 @@ type traceStep struct {
7984
fields []Field
8085
}
8186

87+
// rLock doesn't need to do anything because traceStep instances are immutable.
88+
func (s traceStep) rLock() {}
89+
func (s traceStep) rUnlock() {}
90+
8291
func (s traceStep) time() time.Time {
8392
return s.stepTime
8493
}
@@ -106,6 +115,14 @@ type Trace struct {
106115
traceItems []traceItem
107116
}
108117

118+
func (t *Trace) rLock() {
119+
t.lock.RLock()
120+
}
121+
122+
func (t *Trace) rUnlock() {
123+
t.lock.RUnlock()
124+
}
125+
109126
func (t *Trace) time() time.Time {
110127
if t.endTime != nil {
111128
return *t.endTime
@@ -231,8 +248,10 @@ func (t *Trace) logTrace() {
231248
func (t *Trace) writeTraceSteps(b *bytes.Buffer, formatter string, stepThreshold *time.Duration) {
232249
lastStepTime := t.startTime
233250
for _, stepOrTrace := range t.traceItems {
251+
stepOrTrace.rLock()
234252
stepOrTrace.writeItem(b, formatter, lastStepTime, stepThreshold)
235253
lastStepTime = stepOrTrace.time()
254+
stepOrTrace.rUnlock()
236255
}
237256
}
238257

0 commit comments

Comments
 (0)