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  }