Skip to content

Commit 9b5bd30

Browse files
committed
runtime: document special memmove requirements
Unlike C's memmove, Go's memmove must be careful to do indivisible writes of pointer values because it may be racing with the garbage collector reading the heap. We've had various bugs related to this over the years (#36101, #13160, #12552). Indeed, memmove is a great target for optimization and it's easy to forget the special requirements of Go's memmove. The CL documents these (currently unwritten!) requirements. We're also adding a test that should hopefully keep everyone honest going forward, though it's hard to be sure we're hitting all cases of memmove. Change-Id: I2f59f8d8d6fb42d2f10006b55d605b5efd8ddc24 Reviewed-on: https://go-review.googlesource.com/c/go/+/213418 Reviewed-by: Cherry Zhang <[email protected]>
1 parent 895b7c8 commit 9b5bd30

13 files changed

+35
-1
lines changed

src/runtime/memmove_386.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include "go_asm.h"
2929
#include "textflag.h"
3030

31+
// See memmove Go doc for important implementation constraints.
32+
3133
// func memmove(to, from unsafe.Pointer, n uintptr)
3234
TEXT runtime·memmove(SB), NOSPLIT, $0-12
3335
MOVL to+0(FP), DI

src/runtime/memmove_amd64.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include "go_asm.h"
2929
#include "textflag.h"
3030

31+
// See memmove Go doc for important implementation constraints.
32+
3133
// func memmove(to, from unsafe.Pointer, n uintptr)
3234
TEXT runtime·memmove(SB), NOSPLIT, $0-24
3335

src/runtime/memmove_arm.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858
#define FW3 R4
5959
#define FR3 R8 /* shared with TE */
6060

61+
// See memmove Go doc for important implementation constraints.
62+
6163
// func memmove(to, from unsafe.Pointer, n uintptr)
6264
TEXT runtime·memmove(SB), NOSPLIT, $4-12
6365
_memmove:

src/runtime/memmove_arm64.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include "textflag.h"
66

7+
// See memmove Go doc for important implementation constraints.
8+
79
// func memmove(to, from unsafe.Pointer, n uintptr)
810
TEXT runtime·memmove(SB), NOSPLIT|NOFRAME, $0-24
911
MOVD to+0(FP), R3

src/runtime/memmove_mips64x.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
#include "textflag.h"
88

9+
// See memmove Go doc for important implementation constraints.
10+
911
// func memmove(to, from unsafe.Pointer, n uintptr)
1012
TEXT runtime·memmove(SB), NOSPLIT|NOFRAME, $0-24
1113
MOVV to+0(FP), R1

src/runtime/memmove_mipsx.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#define MOVWLO MOVWL
1515
#endif
1616

17+
// See memmove Go doc for important implementation constraints.
18+
1719
// func memmove(to, from unsafe.Pointer, n uintptr)
1820
TEXT runtime·memmove(SB),NOSPLIT,$-0-12
1921
MOVW n+8(FP), R3

src/runtime/memmove_plan9_386.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
#include "textflag.h"
2727

28+
// See memmove Go doc for important implementation constraints.
29+
2830
// func memmove(to, from unsafe.Pointer, n uintptr)
2931
TEXT runtime·memmove(SB), NOSPLIT, $0-12
3032
MOVL to+0(FP), DI

src/runtime/memmove_plan9_amd64.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
#include "textflag.h"
2727

28+
// See memmove Go doc for important implementation constraints.
29+
2830
// func memmove(to, from unsafe.Pointer, n uintptr)
2931
TEXT runtime·memmove(SB), NOSPLIT, $0-24
3032

src/runtime/memmove_ppc64x.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
#include "textflag.h"
88

9+
// See memmove Go doc for important implementation constraints.
10+
911
// func memmove(to, from unsafe.Pointer, n uintptr)
1012
TEXT runtime·memmove(SB), NOSPLIT|NOFRAME, $0-24
1113
MOVD to+0(FP), R3

src/runtime/memmove_riscv64.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include "textflag.h"
66

7+
// See memmove Go doc for important implementation constraints.
8+
79
// void runtime·memmove(void*, void*, uintptr)
810
TEXT runtime·memmove(SB),NOSPLIT,$-0-24
911
MOV to+0(FP), T0

src/runtime/memmove_s390x.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include "textflag.h"
66

7+
// See memmove Go doc for important implementation constraints.
8+
79
// func memmove(to, from unsafe.Pointer, n uintptr)
810
TEXT runtime·memmove(SB),NOSPLIT|NOFRAME,$0-24
911
MOVD to+0(FP), R6

src/runtime/memmove_wasm.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include "textflag.h"
66

7+
// See memmove Go doc for important implementation constraints.
8+
79
// func memmove(to, from unsafe.Pointer, n uintptr)
810
TEXT runtime·memmove(SB), NOSPLIT, $0-24
911
MOVD to+0(FP), R0

src/runtime/stubs.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,17 @@ func reflect_memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr) {
8383
}
8484

8585
// memmove copies n bytes from "from" to "to".
86-
// in memmove_*.s
86+
//
87+
// memmove ensures that any pointer in "from" is written to "to" with
88+
// an indivisible write, so that racy reads cannot observe a
89+
// half-written pointer. This is necessary to prevent the garbage
90+
// collector from observing invalid pointers, and differs from memmove
91+
// in unmanaged languages. However, memmove is only required to do
92+
// this if "from" and "to" may contain pointers, which can only be the
93+
// case if "from", "to", and "n" are all be word-aligned.
94+
//
95+
// Implementations are in memmove_*.s.
96+
//
8797
//go:noescape
8898
func memmove(to, from unsafe.Pointer, n uintptr)
8999

0 commit comments

Comments
 (0)