}()
atomic.AddInt32(nilptr, 1)
}
+
+func TestNoRaceDeferAtomicStore(t *testing.T) {
+ // Test that when an atomic function is deferred directly, the
+ // GC scans it correctly. See issue 42599.
+ type foo struct {
+ bar int64
+ }
+
+ var doFork func(f *foo, depth int)
+ doFork = func(f *foo, depth int) {
+ atomic.StoreInt64(&f.bar, 1)
+ defer atomic.StoreInt64(&f.bar, 0)
+ if depth > 0 {
+ for i := 0; i < 2; i++ {
+ f2 := &foo{}
+ go doFork(f2, depth-1)
+ }
+ }
+ runtime.GC()
+ }
+
+ f := &foo{}
+ doFork(f, 11)
+}
// Atomic operations for sync/atomic package.
// Load
-TEXT sync∕atomic·LoadInt32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·LoadInt32(SB), NOSPLIT, $0-12
+ GO_ARGS
MOVQ $__tsan_go_atomic32_load(SB), AX
CALL racecallatomic<>(SB)
RET
-TEXT sync∕atomic·LoadInt64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·LoadInt64(SB), NOSPLIT, $0-16
+ GO_ARGS
MOVQ $__tsan_go_atomic64_load(SB), AX
CALL racecallatomic<>(SB)
RET
-TEXT sync∕atomic·LoadUint32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·LoadUint32(SB), NOSPLIT, $0-12
+ GO_ARGS
JMP sync∕atomic·LoadInt32(SB)
-TEXT sync∕atomic·LoadUint64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·LoadUint64(SB), NOSPLIT, $0-16
+ GO_ARGS
JMP sync∕atomic·LoadInt64(SB)
-TEXT sync∕atomic·LoadUintptr(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·LoadUintptr(SB), NOSPLIT, $0-16
+ GO_ARGS
JMP sync∕atomic·LoadInt64(SB)
-TEXT sync∕atomic·LoadPointer(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·LoadPointer(SB), NOSPLIT, $0-16
+ GO_ARGS
JMP sync∕atomic·LoadInt64(SB)
// Store
-TEXT sync∕atomic·StoreInt32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·StoreInt32(SB), NOSPLIT, $0-12
+ GO_ARGS
MOVQ $__tsan_go_atomic32_store(SB), AX
CALL racecallatomic<>(SB)
RET
-TEXT sync∕atomic·StoreInt64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·StoreInt64(SB), NOSPLIT, $0-16
+ GO_ARGS
MOVQ $__tsan_go_atomic64_store(SB), AX
CALL racecallatomic<>(SB)
RET
-TEXT sync∕atomic·StoreUint32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·StoreUint32(SB), NOSPLIT, $0-12
+ GO_ARGS
JMP sync∕atomic·StoreInt32(SB)
-TEXT sync∕atomic·StoreUint64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·StoreUint64(SB), NOSPLIT, $0-16
+ GO_ARGS
JMP sync∕atomic·StoreInt64(SB)
-TEXT sync∕atomic·StoreUintptr(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·StoreUintptr(SB), NOSPLIT, $0-16
+ GO_ARGS
JMP sync∕atomic·StoreInt64(SB)
// Swap
-TEXT sync∕atomic·SwapInt32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·SwapInt32(SB), NOSPLIT, $0-20
+ GO_ARGS
MOVQ $__tsan_go_atomic32_exchange(SB), AX
CALL racecallatomic<>(SB)
RET
-TEXT sync∕atomic·SwapInt64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·SwapInt64(SB), NOSPLIT, $0-24
+ GO_ARGS
MOVQ $__tsan_go_atomic64_exchange(SB), AX
CALL racecallatomic<>(SB)
RET
-TEXT sync∕atomic·SwapUint32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·SwapUint32(SB), NOSPLIT, $0-20
+ GO_ARGS
JMP sync∕atomic·SwapInt32(SB)
-TEXT sync∕atomic·SwapUint64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·SwapUint64(SB), NOSPLIT, $0-24
+ GO_ARGS
JMP sync∕atomic·SwapInt64(SB)
-TEXT sync∕atomic·SwapUintptr(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·SwapUintptr(SB), NOSPLIT, $0-24
+ GO_ARGS
JMP sync∕atomic·SwapInt64(SB)
// Add
-TEXT sync∕atomic·AddInt32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·AddInt32(SB), NOSPLIT, $0-20
+ GO_ARGS
MOVQ $__tsan_go_atomic32_fetch_add(SB), AX
CALL racecallatomic<>(SB)
MOVL add+8(FP), AX // convert fetch_add to add_fetch
ADDL AX, ret+16(FP)
RET
-TEXT sync∕atomic·AddInt64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·AddInt64(SB), NOSPLIT, $0-24
+ GO_ARGS
MOVQ $__tsan_go_atomic64_fetch_add(SB), AX
CALL racecallatomic<>(SB)
MOVQ add+8(FP), AX // convert fetch_add to add_fetch
ADDQ AX, ret+16(FP)
RET
-TEXT sync∕atomic·AddUint32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·AddUint32(SB), NOSPLIT, $0-20
+ GO_ARGS
JMP sync∕atomic·AddInt32(SB)
-TEXT sync∕atomic·AddUint64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·AddUint64(SB), NOSPLIT, $0-24
+ GO_ARGS
JMP sync∕atomic·AddInt64(SB)
-TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24
+ GO_ARGS
JMP sync∕atomic·AddInt64(SB)
// CompareAndSwap
-TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17
+ GO_ARGS
MOVQ $__tsan_go_atomic32_compare_exchange(SB), AX
CALL racecallatomic<>(SB)
RET
-TEXT sync∕atomic·CompareAndSwapInt64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·CompareAndSwapInt64(SB), NOSPLIT, $0-25
+ GO_ARGS
MOVQ $__tsan_go_atomic64_compare_exchange(SB), AX
CALL racecallatomic<>(SB)
RET
-TEXT sync∕atomic·CompareAndSwapUint32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·CompareAndSwapUint32(SB), NOSPLIT, $0-17
+ GO_ARGS
JMP sync∕atomic·CompareAndSwapInt32(SB)
-TEXT sync∕atomic·CompareAndSwapUint64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·CompareAndSwapUint64(SB), NOSPLIT, $0-25
+ GO_ARGS
JMP sync∕atomic·CompareAndSwapInt64(SB)
-TEXT sync∕atomic·CompareAndSwapUintptr(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·CompareAndSwapUintptr(SB), NOSPLIT, $0-25
+ GO_ARGS
JMP sync∕atomic·CompareAndSwapInt64(SB)
// Generic atomic operation implementation.
// R0, R1, R2 set in racecallatomic
// Load
-TEXT sync∕atomic·LoadInt32(SB), NOSPLIT, $0
+TEXT sync∕atomic·LoadInt32(SB), NOSPLIT, $0-12
GO_ARGS
MOVD $__tsan_go_atomic32_load(SB), R9
BL racecallatomic<>(SB)
RET
-TEXT sync∕atomic·LoadInt64(SB), NOSPLIT, $0
+TEXT sync∕atomic·LoadInt64(SB), NOSPLIT, $0-16
GO_ARGS
MOVD $__tsan_go_atomic64_load(SB), R9
BL racecallatomic<>(SB)
RET
-TEXT sync∕atomic·LoadUint32(SB), NOSPLIT, $0
+TEXT sync∕atomic·LoadUint32(SB), NOSPLIT, $0-12
GO_ARGS
JMP sync∕atomic·LoadInt32(SB)
-TEXT sync∕atomic·LoadUint64(SB), NOSPLIT, $0
+TEXT sync∕atomic·LoadUint64(SB), NOSPLIT, $0-16
GO_ARGS
JMP sync∕atomic·LoadInt64(SB)
-TEXT sync∕atomic·LoadUintptr(SB), NOSPLIT, $0
+TEXT sync∕atomic·LoadUintptr(SB), NOSPLIT, $0-16
GO_ARGS
JMP sync∕atomic·LoadInt64(SB)
-TEXT sync∕atomic·LoadPointer(SB), NOSPLIT, $0
+TEXT sync∕atomic·LoadPointer(SB), NOSPLIT, $0-16
GO_ARGS
JMP sync∕atomic·LoadInt64(SB)
// Store
-TEXT sync∕atomic·StoreInt32(SB), NOSPLIT, $0
+TEXT sync∕atomic·StoreInt32(SB), NOSPLIT, $0-12
GO_ARGS
MOVD $__tsan_go_atomic32_store(SB), R9
BL racecallatomic<>(SB)
RET
-TEXT sync∕atomic·StoreInt64(SB), NOSPLIT, $0
+TEXT sync∕atomic·StoreInt64(SB), NOSPLIT, $0-16
GO_ARGS
MOVD $__tsan_go_atomic64_store(SB), R9
BL racecallatomic<>(SB)
RET
-TEXT sync∕atomic·StoreUint32(SB), NOSPLIT, $0
+TEXT sync∕atomic·StoreUint32(SB), NOSPLIT, $0-12
GO_ARGS
JMP sync∕atomic·StoreInt32(SB)
-TEXT sync∕atomic·StoreUint64(SB), NOSPLIT, $0
+TEXT sync∕atomic·StoreUint64(SB), NOSPLIT, $0-16
GO_ARGS
JMP sync∕atomic·StoreInt64(SB)
-TEXT sync∕atomic·StoreUintptr(SB), NOSPLIT, $0
+TEXT sync∕atomic·StoreUintptr(SB), NOSPLIT, $0-16
GO_ARGS
JMP sync∕atomic·StoreInt64(SB)
// Swap
-TEXT sync∕atomic·SwapInt32(SB), NOSPLIT, $0
+TEXT sync∕atomic·SwapInt32(SB), NOSPLIT, $0-20
GO_ARGS
MOVD $__tsan_go_atomic32_exchange(SB), R9
BL racecallatomic<>(SB)
RET
-TEXT sync∕atomic·SwapInt64(SB), NOSPLIT, $0
+TEXT sync∕atomic·SwapInt64(SB), NOSPLIT, $0-24
GO_ARGS
MOVD $__tsan_go_atomic64_exchange(SB), R9
BL racecallatomic<>(SB)
RET
-TEXT sync∕atomic·SwapUint32(SB), NOSPLIT, $0
+TEXT sync∕atomic·SwapUint32(SB), NOSPLIT, $0-20
GO_ARGS
JMP sync∕atomic·SwapInt32(SB)
-TEXT sync∕atomic·SwapUint64(SB), NOSPLIT, $0
+TEXT sync∕atomic·SwapUint64(SB), NOSPLIT, $0-24
GO_ARGS
JMP sync∕atomic·SwapInt64(SB)
-TEXT sync∕atomic·SwapUintptr(SB), NOSPLIT, $0
+TEXT sync∕atomic·SwapUintptr(SB), NOSPLIT, $0-24
GO_ARGS
JMP sync∕atomic·SwapInt64(SB)
// Add
-TEXT sync∕atomic·AddInt32(SB), NOSPLIT, $0
+TEXT sync∕atomic·AddInt32(SB), NOSPLIT, $0-20
GO_ARGS
MOVD $__tsan_go_atomic32_fetch_add(SB), R9
BL racecallatomic<>(SB)
MOVW R0, ret+16(FP)
RET
-TEXT sync∕atomic·AddInt64(SB), NOSPLIT, $0
+TEXT sync∕atomic·AddInt64(SB), NOSPLIT, $0-24
GO_ARGS
MOVD $__tsan_go_atomic64_fetch_add(SB), R9
BL racecallatomic<>(SB)
MOVD R0, ret+16(FP)
RET
-TEXT sync∕atomic·AddUint32(SB), NOSPLIT, $0
+TEXT sync∕atomic·AddUint32(SB), NOSPLIT, $0-20
GO_ARGS
JMP sync∕atomic·AddInt32(SB)
-TEXT sync∕atomic·AddUint64(SB), NOSPLIT, $0
+TEXT sync∕atomic·AddUint64(SB), NOSPLIT, $0-24
GO_ARGS
JMP sync∕atomic·AddInt64(SB)
-TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0
+TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24
GO_ARGS
JMP sync∕atomic·AddInt64(SB)
// CompareAndSwap
-TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0
+TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17
GO_ARGS
MOVD $__tsan_go_atomic32_compare_exchange(SB), R9
BL racecallatomic<>(SB)
RET
-TEXT sync∕atomic·CompareAndSwapInt64(SB), NOSPLIT, $0
+TEXT sync∕atomic·CompareAndSwapInt64(SB), NOSPLIT, $0-25
GO_ARGS
MOVD $__tsan_go_atomic64_compare_exchange(SB), R9
BL racecallatomic<>(SB)
RET
-TEXT sync∕atomic·CompareAndSwapUint32(SB), NOSPLIT, $0
+TEXT sync∕atomic·CompareAndSwapUint32(SB), NOSPLIT, $0-17
GO_ARGS
JMP sync∕atomic·CompareAndSwapInt32(SB)
-TEXT sync∕atomic·CompareAndSwapUint64(SB), NOSPLIT, $0
+TEXT sync∕atomic·CompareAndSwapUint64(SB), NOSPLIT, $0-25
GO_ARGS
JMP sync∕atomic·CompareAndSwapInt64(SB)
-TEXT sync∕atomic·CompareAndSwapUintptr(SB), NOSPLIT, $0
+TEXT sync∕atomic·CompareAndSwapUintptr(SB), NOSPLIT, $0-25
GO_ARGS
JMP sync∕atomic·CompareAndSwapInt64(SB)
// R3, R4, R5 set in racecallatomic
// Load atomic in tsan
-TEXT sync∕atomic·LoadInt32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·LoadInt32(SB), NOSPLIT, $0-12
+ GO_ARGS
// void __tsan_go_atomic32_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
MOVD $__tsan_go_atomic32_load(SB), R8
ADD $32, R1, R6 // addr of caller's 1st arg
BR racecallatomic<>(SB)
RET
-TEXT sync∕atomic·LoadInt64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·LoadInt64(SB), NOSPLIT, $0-16
+ GO_ARGS
// void __tsan_go_atomic64_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
MOVD $__tsan_go_atomic64_load(SB), R8
ADD $32, R1, R6 // addr of caller's 1st arg
BR racecallatomic<>(SB)
RET
-TEXT sync∕atomic·LoadUint32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·LoadUint32(SB), NOSPLIT, $0-12
+ GO_ARGS
BR sync∕atomic·LoadInt32(SB)
-TEXT sync∕atomic·LoadUint64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·LoadUint64(SB), NOSPLIT, $0-16
+ GO_ARGS
BR sync∕atomic·LoadInt64(SB)
-TEXT sync∕atomic·LoadUintptr(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·LoadUintptr(SB), NOSPLIT, $0-16
+ GO_ARGS
BR sync∕atomic·LoadInt64(SB)
-TEXT sync∕atomic·LoadPointer(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·LoadPointer(SB), NOSPLIT, $0-16
+ GO_ARGS
BR sync∕atomic·LoadInt64(SB)
// Store atomic in tsan
-TEXT sync∕atomic·StoreInt32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·StoreInt32(SB), NOSPLIT, $0-12
+ GO_ARGS
// void __tsan_go_atomic32_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
MOVD $__tsan_go_atomic32_store(SB), R8
ADD $32, R1, R6 // addr of caller's 1st arg
BR racecallatomic<>(SB)
-TEXT sync∕atomic·StoreInt64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·StoreInt64(SB), NOSPLIT, $0-16
+ GO_ARGS
// void __tsan_go_atomic64_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
MOVD $__tsan_go_atomic64_store(SB), R8
ADD $32, R1, R6 // addr of caller's 1st arg
BR racecallatomic<>(SB)
-TEXT sync∕atomic·StoreUint32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·StoreUint32(SB), NOSPLIT, $0-12
+ GO_ARGS
BR sync∕atomic·StoreInt32(SB)
-TEXT sync∕atomic·StoreUint64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·StoreUint64(SB), NOSPLIT, $0-16
+ GO_ARGS
BR sync∕atomic·StoreInt64(SB)
-TEXT sync∕atomic·StoreUintptr(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·StoreUintptr(SB), NOSPLIT, $0-16
+ GO_ARGS
BR sync∕atomic·StoreInt64(SB)
// Swap in tsan
-TEXT sync∕atomic·SwapInt32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·SwapInt32(SB), NOSPLIT, $0-20
+ GO_ARGS
// void __tsan_go_atomic32_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
MOVD $__tsan_go_atomic32_exchange(SB), R8
ADD $32, R1, R6 // addr of caller's 1st arg
BR racecallatomic<>(SB)
-TEXT sync∕atomic·SwapInt64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·SwapInt64(SB), NOSPLIT, $0-24
+ GO_ARGS
// void __tsan_go_atomic64_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a)
MOVD $__tsan_go_atomic64_exchange(SB), R8
ADD $32, R1, R6 // addr of caller's 1st arg
BR racecallatomic<>(SB)
-TEXT sync∕atomic·SwapUint32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·SwapUint32(SB), NOSPLIT, $0-20
+ GO_ARGS
BR sync∕atomic·SwapInt32(SB)
-TEXT sync∕atomic·SwapUint64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·SwapUint64(SB), NOSPLIT, $0-24
+ GO_ARGS
BR sync∕atomic·SwapInt64(SB)
-TEXT sync∕atomic·SwapUintptr(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·SwapUintptr(SB), NOSPLIT, $0-24
+ GO_ARGS
BR sync∕atomic·SwapInt64(SB)
// Add atomic in tsan
-TEXT sync∕atomic·AddInt32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·AddInt32(SB), NOSPLIT, $0-20
+ GO_ARGS
// void __tsan_go_atomic32_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
MOVD $__tsan_go_atomic32_fetch_add(SB), R8
ADD $64, R1, R6 // addr of caller's 1st arg
MOVW R3, ret+16(FP)
RET
-TEXT sync∕atomic·AddInt64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·AddInt64(SB), NOSPLIT, $0-24
+ GO_ARGS
// void __tsan_go_atomic64_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
MOVD $__tsan_go_atomic64_fetch_add(SB), R8
ADD $64, R1, R6 // addr of caller's 1st arg
MOVD R3, ret+16(FP)
RET
-TEXT sync∕atomic·AddUint32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·AddUint32(SB), NOSPLIT, $0-20
+ GO_ARGS
BR sync∕atomic·AddInt32(SB)
-TEXT sync∕atomic·AddUint64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·AddUint64(SB), NOSPLIT, $0-24
+ GO_ARGS
BR sync∕atomic·AddInt64(SB)
-TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24
+ GO_ARGS
BR sync∕atomic·AddInt64(SB)
// CompareAndSwap in tsan
-TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17
+ GO_ARGS
// void __tsan_go_atomic32_compare_exchange(
// ThreadState *thr, uptr cpc, uptr pc, u8 *a)
MOVD $__tsan_go_atomic32_compare_exchange(SB), R8
ADD $32, R1, R6 // addr of caller's 1st arg
BR racecallatomic<>(SB)
-TEXT sync∕atomic·CompareAndSwapInt64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·CompareAndSwapInt64(SB), NOSPLIT, $0-25
+ GO_ARGS
// void __tsan_go_atomic32_compare_exchange(
// ThreadState *thr, uptr cpc, uptr pc, u8 *a)
MOVD $__tsan_go_atomic64_compare_exchange(SB), R8
ADD $32, R1, R6 // addr of caller's 1st arg
BR racecallatomic<>(SB)
-TEXT sync∕atomic·CompareAndSwapUint32(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·CompareAndSwapUint32(SB), NOSPLIT, $0-17
+ GO_ARGS
BR sync∕atomic·CompareAndSwapInt32(SB)
-TEXT sync∕atomic·CompareAndSwapUint64(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·CompareAndSwapUint64(SB), NOSPLIT, $0-25
+ GO_ARGS
BR sync∕atomic·CompareAndSwapInt64(SB)
-TEXT sync∕atomic·CompareAndSwapUintptr(SB), NOSPLIT, $0-0
+TEXT sync∕atomic·CompareAndSwapUintptr(SB), NOSPLIT, $0-25
+ GO_ARGS
BR sync∕atomic·CompareAndSwapInt64(SB)
// Common function used to call tsan's atomic functions