package main import "io" // B.0.4 test: chan element type with []byte slice field. // Before Codec invocation, raw memcpy across the spawn boundary sent // only the slice header (ptr/len/cap), causing the receiver to // dereference a parent-only address — SIGSEGV. // // With Codec, EncodeTo writes the byte payload as length-prefixed // data; DecodeFrom allocates a fresh slice in the receiver's heap. type Blob struct { Size int32 Data []byte } func (b Blob) EncodeTo(w io.Writer) error { var sz [4]byte sz[0] = byte(b.Size) sz[1] = byte(b.Size >> 8) sz[2] = byte(b.Size >> 16) sz[3] = byte(b.Size >> 24) if _, err := w.Write(sz[:]); err != nil { return err } _, err := w.Write(b.Data) return err } func (b *Blob) DecodeFrom(r io.Reader) error { var sz [4]byte if _, err := io.ReadFull(r, sz[:]); err != nil { return err } b.Size = int32(sz[0]) | int32(sz[1])<<8 | int32(sz[2])<<16 | int32(sz[3])<<24 b.Data = make([]byte, b.Size) _, err := io.ReadFull(r, b.Data) return err } func echo(in chan Blob, out chan Blob) { b := <-in bad := int32(-1) for i := int32(0); i < b.Size; i++ { if b.Data[i] != byte(i) { bad = i break } } if bad != -1 { out <- Blob{Size: bad, Data: nil} return } out <- Blob{Size: b.Size, Data: b.Data} } func main() { const N = int32(100000) // 100 KB — exceeds kernel pipe buffer to exercise partial syscalls in := make(chan Blob) out := make(chan Blob) spawn(echo, in, out) data := make([]byte, N) for i := int32(0); i < N; i++ { data[i] = byte(i) } in <- Blob{Size: N, Data: data} got := <-out if got.Size != N { println("FAIL:slice", "size", got.Size, "want", N) return } for i := int32(0); i < N; i++ { if got.Data[i] != byte(i) { println("FAIL:slice", "byte mismatch at", i) return } } println("PASS:slice-codec") }