Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

clang_test.gno

3.75 Kb · 110 lines
  1package riscv
  2
  3import (
  4	"testing"
  5
  6	"gno.land/p/nym-moultest123/x/vm/vmkit/v0"
  7	"gno.land/p/nt/uassert/v0"
  8)
  9
 10// A guest compiled by a real compiler, which is the only test here that was
 11// not written by the same person who wrote the emulator.
 12//
 13// The image is guests.gno's, built from tools/riscv-guests/fnv by clang. It
 14// exercises what hand-written tests do not: a real function prologue spilling
 15// ra and s0 to a stack the host set up, .bss addressed far above a read-only
 16// text segment, LLVM's constant materialization through lui/addi pairs, and
 17// MUL in an inner loop.
 18
 19// The expected hashes come from an independent FNV-1a, not from this VM.
 20func TestClangCompiledGuest(t *testing.T) {
 21	cases := []struct {
 22		in   string
 23		want string
 24	}{
 25		{"", "811c9dc5"},
 26		{"a", "e40c292c"},
 27		{"Hello", "f55c314b"},
 28		{"gno.land", "fb7ffba0"},
 29	}
 30	for _, c := range cases {
 31		m, err := NewMachine(GuestFNV(), entry)
 32		uassert.NoError(t, err)
 33		if m == nil {
 34			continue
 35		}
 36		h := vmkit.NewTestHost().WithInput([]byte(c.in))
 37		_, status := m.Step(h, vmkit.Unmetered)
 38		uassert.Equal(t, "halted", status.String(), "input "+c.in+": "+m.Trap())
 39		uassert.Equal(t, c.want, string(h.Out()), "fnv1a of "+c.in)
 40	}
 41}
 42
 43// Compiled code pauses and resumes like anything else. This is the property a
 44// realm depends on, run against output a compiler produced rather than against
 45// a loop written to be sliceable.
 46func TestClangGuestSurvivesSlicing(t *testing.T) {
 47	image := GuestFNV()
 48	h := vmkit.NewTestHost().WithInput([]byte("gno.land"))
 49
 50	sliced, err := NewMachine(image, entry)
 51	uassert.NoError(t, err)
 52	status := vmkit.Running
 53	slices := 0
 54	for i := 0; i < 500 && status == vmkit.Running; i++ {
 55		var fresh Machine
 56		uassert.NoError(t, fresh.Restore(sliced.Snapshot()))
 57		_, status = fresh.Step(h, 3)
 58		sliced = &fresh
 59		slices++
 60	}
 61	uassert.Equal(t, "halted", status.String())
 62	uassert.True(t, slices > 10, "a sliced run must actually have been sliced")
 63	uassert.Equal(t, "fb7ffba0", string(h.Out()))
 64}
 65
 66// The guest writes its globals at 0x40000, which the linker script put well
 67// above the text segment on purpose. If it had put them adjacent, W xor X
 68// would trap on the first store, so this is the test that the memory layout
 69// the toolchain was told to use is the one the host actually provides.
 70func TestClangGuestWritesAboveItsText(t *testing.T) {
 71	m, err := NewMachine(GuestFNV(), entry)
 72	uassert.NoError(t, err)
 73	h := vmkit.NewTestHost().WithInput([]byte("gno.land"))
 74	_, status := m.Step(h, vmkit.Unmetered)
 75	uassert.Equal(t, "halted", status.String())
 76
 77	// The text pages, the .bss page at 0x40000, and the stack page at the top.
 78	uassert.True(t, m.Memory().DirtyPages() >= 3,
 79		"the guest must have written outside its text segment")
 80	uassert.True(t, m.Memory().DirtyPages() <= 8,
 81		"a 196-byte program must not have dirtied the address space")
 82}
 83
 84// Image is what every caller uses to turn words into a program, so a byte
 85// order mistake here would look like a decoder bug everywhere else.
 86func TestImageIsLittleEndian(t *testing.T) {
 87	b := Image([]uint32{0x04030201, 0xFF000000})
 88	uassert.Equal(t, 8, len(b))
 89	uassert.Equal(t, uint64(0x01), uint64(b[0]))
 90	uassert.Equal(t, uint64(0x04), uint64(b[3]))
 91	uassert.Equal(t, uint64(0x00), uint64(b[4]))
 92	uassert.Equal(t, uint64(0xFF), uint64(b[7]))
 93
 94	// And it agrees with the assembler the other tests use.
 95	words := []uint32{addi(5, 0, 1), ecall()}
 96	a, i := asm(words), Image(words)
 97	uassert.Equal(t, len(a), len(i))
 98	for k := range a {
 99		uassert.Equal(t, uint64(a[k]), uint64(i[k]))
100	}
101}
102
103// GuestFNV must not hand out a slice a caller can scribble on, because the
104// next caller gets the same program.
105func TestGuestFNVIsACopy(t *testing.T) {
106	a := GuestFNV()
107	a[0] = 0xFF
108	b := GuestFNV()
109	uassert.False(t, b[0] == 0xFF, "GuestFNV must return a fresh image each call")
110}