pass_chan_slice.go raw

   1  package main
   2  
   3  import "io"
   4  
   5  // B.0.4 test: chan element type with []byte slice field.
   6  // Before Codec invocation, raw memcpy across the spawn boundary sent
   7  // only the slice header (ptr/len/cap), causing the receiver to
   8  // dereference a parent-only address - SIGSEGV.
   9  //
  10  // With Codec, EncodeTo writes the byte payload as length-prefixed
  11  // data; DecodeFrom allocates a fresh slice in the receiver's heap.
  12  
  13  type Blob struct {
  14  	Size int32
  15  	Data []byte
  16  }
  17  
  18  func (b *Blob) EncodeTo(w io.Writer) (encErr error) {
  19  	var sz [4]byte
  20  	sz[0] = byte(b.Size)
  21  	sz[1] = byte(b.Size >> 8)
  22  	sz[2] = byte(b.Size >> 16)
  23  	sz[3] = byte(b.Size >> 24)
  24  	_, encErr = w.Write(sz[:])
  25  	if encErr != nil {
  26  		return encErr
  27  	}
  28  	_, encErr = w.Write(b.Data)
  29  	return encErr
  30  }
  31  
  32  func (b *Blob) DecodeFrom(r io.Reader) (decErr error) {
  33  	var sz [4]byte
  34  	_, decErr = io.ReadFull(r, sz[:])
  35  	if decErr != nil {
  36  		return decErr
  37  	}
  38  	b.Size = int32(sz[0]) | int32(sz[1])<<8 | int32(sz[2])<<16 | int32(sz[3])<<24
  39  	b.Data = make([]byte, b.Size)
  40  	_, decErr = io.ReadFull(r, b.Data)
  41  	return decErr
  42  }
  43  
  44  func echo(in chan Blob, out chan Blob) {
  45  	b := <-in
  46  	bad := int32(-1)
  47  	for i := int32(0); i < b.Size; i++ {
  48  		if b.Data[i] != byte(i) {
  49  			bad = i
  50  			break
  51  		}
  52  	}
  53  	if bad != -1 {
  54  		out <- Blob{Size: bad, Data: nil}
  55  		return
  56  	}
  57  	out <- Blob{Size: b.Size, Data: b.Data}
  58  }
  59  
  60  func main() {
  61  	const N = int32(100000) // 100 KB - exceeds kernel pipe buffer to exercise partial syscalls
  62  	in := make(chan Blob)
  63  	out := make(chan Blob)
  64  	spawn(echo, in, out)
  65  
  66  	data := make([]byte, N)
  67  	for i := int32(0); i < N; i++ {
  68  		data[i] = byte(i)
  69  	}
  70  	in <- Blob{Size: N, Data: data}
  71  
  72  	got := <-out
  73  	if got.Size != N {
  74  		println("FAIL:slice", "size", got.Size, "want", N)
  75  		return
  76  	}
  77  	for i := int32(0); i < N; i++ {
  78  		if got.Data[i] != byte(i) {
  79  			println("FAIL:slice", "byte mismatch at", i)
  80  			return
  81  		}
  82  	}
  83  	println("PASS:slice-codec")
  84  }
  85