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

clamp_test.gno

2.71 Kb · 63 lines
 1package impl
 2
 3import (
 4	"strings"
 5	"testing"
 6
 7	"gno.land/p/nt/uassert/v0"
 8)
 9
10// Sanitizing costs ~11,310 gas/byte, and rendering is reachable unauthenticated
11// through vm/qrender under a 3,000,000,000 gas cap. ExecutorCreationRealm is
12// dispatched through the public dao.Executor interface, so a hostile executor
13// computes it per call and stores almost nothing: unclamped, a ~250KB value
14// costs over 3G gas in one render and bricks the proposal page for everyone.
15// Measured on the real render path: 2,839,117,770 gas unclamped versus
16// 18,749,984 clamped. About 265KB of input crosses the query cap entirely.
17func TestClampFieldBoundsSanitizerInput(t *testing.T) {
18	uassert.Equal(t, "short", clampField("short", maxRenderedRealm),
19		"a value within the bound must pass through untouched")
20
21	huge := strings.Repeat("a", 250000)
22	got := clampField(huge, maxRenderedRealm)
23	uassert.True(t, len(got) < maxRenderedRealm+32,
24		"the clamped value must be bounded by the limit, not by the input")
25	uassert.True(t, strings.HasSuffix(got, "… truncated"),
26		"a clamped value must say it was cut rather than look authored short")
27}
28
29// Cutting at a byte offset can land inside a multi-byte rune; the sanitizer
30// tolerates invalid UTF-8, but handing it a split rune is sloppy and would
31// render a replacement character mid-path.
32func TestClampFieldCutsOnRuneBoundary(t *testing.T) {
33	// 3-byte runes, so a 256-byte cut lands mid-rune (256 = 85*3 + 1).
34	got := clampField(strings.Repeat("世", 200), maxRenderedRealm)
35	body := strings.TrimSuffix(got, "… truncated")
36
37	uassert.True(t, len(body)%3 == 0,
38		"the cut must land on a rune boundary")
39	uassert.Equal(t, strings.Repeat("世", len(body)/3), body,
40		"every retained rune must be intact")
41}
42
43// Boundary and malformed input. clampField does byte arithmetic and backs off
44// over UTF-8 continuation bytes, so the interesting cases are the ones where
45// that loop has nowhere to back off to.
46func TestClampFieldBoundaries(t *testing.T) {
47	exact := strings.Repeat("a", maxRenderedRealm)
48	uassert.Equal(t, exact, clampField(exact, maxRenderedRealm),
49		"a value exactly at the bound must not be marked truncated")
50
51	over := strings.Repeat("a", maxRenderedRealm+1)
52	uassert.True(t, strings.HasSuffix(clampField(over, maxRenderedRealm), "… truncated"),
53		"one byte over the bound must be cut")
54
55	// Already-invalid UTF-8: every byte is a continuation, so the backoff
56	// walks to zero. Must degrade to the marker rather than panic or loop.
57	cont := strings.Repeat("\x80", maxRenderedRealm+10)
58	uassert.Equal(t, "… truncated", clampField(cont, maxRenderedRealm),
59		"an all-continuation string must degrade to just the marker")
60
61	uassert.Equal(t, "… truncated", clampField("abc", 0),
62		"a zero bound must still terminate")
63}