main.mx raw

   1  // A reslice past the end of a slice must stay a well-formed view of its
   2  // parent: an empty slice, not a slice with a negative length.
   3  //
   4  // Moxie emits no slice bounds check - the programmer owns the indices - but
   5  // `s[1:]` on an empty slice produced len -1, so the tree's
   6  // `for ; len(r) > 0; r = r[1:]` loops left `r` with a negative length and the
   7  // `if len(r) == 0` guards that follow never fired. A truncated REQ filter
   8  // (`{"kinds":[1`) then read past the end and killed the relay.
   9  package main
  10  
  11  import (
  12  	"fmt"
  13  	"os"
  14  )
  15  
  16  func consume(s []byte) (n int32) {
  17  	for ; len(s) > 0; s = s[1:] {
  18  		if s[0] == 'x' {
  19  			return -1
  20  		}
  21  	}
  22  	return int32(len(s))
  23  }
  24  
  25  func main() {
  26  	fmt.Fprintf(os.Stderr, "ok\n")
  27  	empty := []byte{}
  28  	after := empty[1:]
  29  	if len(after) != 0 {
  30  		panic("reslicing past the end must produce an empty slice")
  31  	}
  32  	if consume([]byte("x")) != -1 {
  33  		panic("the loop body must still see its element")
  34  	}
  35  	if consume([]byte("xy")) != -1 {
  36  		panic("consume must stop at the matching element")
  37  	}
  38  	if consume(nil) != 0 {
  39  		panic("consume of nil must end immediately")
  40  	}
  41  	// Extending to capacity is a valid slice, not an out-of-range index.
  42  	buf := []byte{:0:8}
  43  	buf = push(buf, 'a', 'b')
  44  	grown := buf[:cap(buf)]
  45  	if len(grown) != 8 {
  46  		panic("reslicing to capacity must keep the capacity")
  47  	}
  48  	grown[7] = 'z'
  49  	if grown[7] != 'z' {
  50  		panic("the extended view must alias the parent buffer")
  51  	}
  52  	// An inverted range and a cursor past the end are both empty. The indices
  53  	// are variables because a constant inverted range is a frontend error.
  54  	var lo byte = 3
  55  	var hi byte = 1
  56  	inverted := buf[lo:hi]
  57  	if len(inverted) != 0 {
  58  		panic("an inverted range must be empty")
  59  	}
  60  	past := buf[99:]
  61  	if len(past) != 0 {
  62  		panic("a reslice starting past the end must be empty")
  63  	}
  64  	// A valid middle slice is unchanged.
  65  	mid := buf[2:5]
  66  	if len(mid) != 3 || mid[0] != 0 {
  67  		panic("a valid sub-slice must keep its bounds")
  68  	}
  69  	fmt.Fprintf(os.Stderr, "%d %d %d\n", int32(len(grown)), int32(len(inverted)), int32(len(past)))
  70  	fmt.Fprintf(os.Stderr, "done\n")
  71  }
  72