main.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) 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  	if _, err := w.Write(sz[:]); err != nil {
  25  		return err
  26  	}
  27  	_, err := w.Write(b.Data)
  28  	return err
  29  }
  30  
  31  func (b *Blob) DecodeFrom(r io.Reader) error {
  32  	var sz [4]byte
  33  	if _, err := io.ReadFull(r, sz[:]); err != nil {
  34  		return err
  35  	}
  36  	b.Size = int32(sz[0]) | int32(sz[1])<<8 | int32(sz[2])<<16 | int32(sz[3])<<24
  37  	b.Data = make([]byte, b.Size)
  38  	_, err := io.ReadFull(r, b.Data)
  39  	return err
  40  }
  41  
  42  func echo(in chan Blob, out chan Blob) {
  43  	b := <-in
  44  	bad := int32(-1)
  45  	for i := int32(0); i < b.Size; i++ {
  46  		if b.Data[i] != byte(i) {
  47  			bad = i
  48  			break
  49  		}
  50  	}
  51  	if bad != -1 {
  52  		out <- Blob{Size: bad, Data: nil}
  53  		return
  54  	}
  55  	out <- Blob{Size: b.Size, Data: b.Data}
  56  }
  57  
  58  func main() {
  59  	const N = int32(4 * 1024 * 1024) // 100 KB — exceeds kernel pipe buffer to exercise partial syscalls
  60  	in := make(chan Blob)
  61  	out := make(chan Blob)
  62  	spawn(echo, in, out)
  63  
  64  	data := make([]byte, N)
  65  	for i := int32(0); i < N; i++ {
  66  		data[i] = byte(i)
  67  	}
  68  	in <- Blob{Size: N, Data: data}
  69  
  70  	got := <-out
  71  	if got.Size != N {
  72  		println("FAIL:slice", "size", got.Size, "want", N)
  73  		return
  74  	}
  75  	for i := int32(0); i < N; i++ {
  76  		if got.Data[i] != byte(i) {
  77  			println("FAIL:slice", "byte mismatch at", i)
  78  			return
  79  		}
  80  	}
  81  	println("PASS:slice-codec")
  82  }
  83