internal/impl: fix data race in atomicNilMessage

The problem is that atomicNilMessage.m.mi is accessed both by atomic and
non-atomic operations. (Init uses an atomic read to verify that m.mi is
non-nil, but then returns a non-atomic m.)

Race condition is demonstrated by this test with
"go test -race -count=1000":

	func TestPointer(t *testing.T) {
		var m atomicNilMessage
		var mi MessageInfo
		ch := make(chan *MessageInfo)
		for i := 0; i < 20; i++ {
			go func() {
				r := m.Init(&mi)
				if &mi != r.mi {
					// This conditional exists just
					// ensure r.mi is touched.
					t.Error("mismatch")
				}
				ch <- r.mi
			}()
		}
		for i := 0; i < 20; i++ {
			<-ch
		}
	}

I chose not to add the test since it seems a bit overfit to the specific
situation.

Change-Id: Id4664ef3cd5b29515ed310851b9aeb7561be30d0
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/188337
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/internal/impl/pointer_unsafe.go b/internal/impl/pointer_unsafe.go
index 5cebd5c..3f53cbc 100644
--- a/internal/impl/pointer_unsafe.go
+++ b/internal/impl/pointer_unsafe.go
@@ -154,11 +154,13 @@
 	atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&ms.mi)), unsafe.Pointer(mi))
 }
 
-type atomicNilMessage struct{ m messageReflectWrapper }
+type atomicNilMessage struct{ p unsafe.Pointer } // p is a *messageReflectWrapper
 
 func (m *atomicNilMessage) Init(mi *MessageInfo) *messageReflectWrapper {
-	if (*messageReflectWrapper)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&m.m.mi)))) == nil {
-		atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&m.m.mi)), unsafe.Pointer(mi))
+	if p := atomic.LoadPointer(&m.p); p != nil {
+		return (*messageReflectWrapper)(p)
 	}
-	return &m.m
+	w := &messageReflectWrapper{mi: mi}
+	atomic.CompareAndSwapPointer(&m.p, nil, (unsafe.Pointer)(w))
+	return (*messageReflectWrapper)(atomic.LoadPointer(&m.p))
 }