github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/unsafekit/byte_string_test.go (about) 1 // Copyright 2020 Insolar Network Ltd. 2 // All rights reserved. 3 // This material is licensed under the Insolar License version 1.0, 4 // available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md. 5 6 package unsafekit 7 8 import ( 9 "reflect" 10 "runtime" 11 "sync/atomic" 12 "testing" 13 "time" 14 "unsafe" 15 16 "github.com/stretchr/testify/require" 17 ) 18 19 // In accordance with unsafe Rule (6) this behavior is NOT guaranteed. Yet it is valid for gc compiler. 20 // So one should be careful with Wrap/Unwrap operations. 21 //go:nocheckptr 22 func TestRetentionByByteString(t *testing.T) { 23 type testPtr [8912]byte // enforce off-stack allocation 24 b := make([]byte, 2048) 25 26 b[0] = 'A' 27 b[1] = 'B' 28 29 finMark := uint32(0) 30 31 shd := unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&b)).Data) 32 runtime.SetFinalizer((*testPtr)(shd), func(_ *testPtr) { 33 atomic.StoreUint32(&finMark, 1) 34 }) 35 36 w := WrapBytes(b) 37 runtime.KeepAlive(b) 38 b = nil 39 40 runtime.GC() 41 time.Sleep(100 * time.Millisecond) 42 runtime.GC() 43 44 // Here, the original content of (b) is retained by 45 // an internal Data reference of ByteString/string 46 47 require.Equal(t, uint32(0), finMark) 48 tp := (*testPtr)(shd) 49 require.Equal(t, byte('A'), tp[0]) 50 require.Equal(t, byte('B'), tp[1]) 51 tp = nil 52 require.Equal(t, byte('A'), w[0]) 53 require.Equal(t, byte('B'), w[1]) 54 w = "" 55 56 runtime.GC() 57 time.Sleep(100 * time.Millisecond) 58 runtime.GC() 59 fm := atomic.LoadUint32(&finMark) 60 require.Equal(t, uint32(1), fm) 61 } 62 63 // In accordance with unsafe Rule (6) this behavior is NOT guaranteed. Yet it is valid for gc compiler. 64 // So one should be careful with Wrap/Unwrap operations. 65 func TestRetentionBySlice(t *testing.T) { 66 type testPtr [8912]byte // enforce off-stack allocation 67 68 bb := &testPtr{'A', 'B'} 69 finMark := uint32(0) 70 runtime.SetFinalizer(bb, func(_ *testPtr) { 71 atomic.StoreUint32(&finMark, 1) 72 }) 73 74 var b []byte 75 76 sh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) 77 sh.Data = uintptr(unsafe.Pointer(bb)) 78 sh.Len = len(*bb) 79 sh.Cap = len(*bb) 80 sh = nil 81 bb = nil 82 83 runtime.GC() 84 time.Sleep(100 * time.Millisecond) 85 runtime.GC() 86 87 // Here, the original content of (bb) is retained by 88 // an internal Data reference of slice 89 90 require.Equal(t, uint32(0), finMark) 91 require.Equal(t, byte('A'), b[0]) 92 require.Equal(t, byte('B'), b[1]) 93 b = nil 94 95 runtime.GC() 96 time.Sleep(100 * time.Millisecond) 97 runtime.GC() 98 fm := atomic.LoadUint32(&finMark) 99 require.Equal(t, uint32(1), fm) 100 }