-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfuzz_test.go
More file actions
82 lines (78 loc) · 2.56 KB
/
Copy pathfuzz_test.go
File metadata and controls
82 lines (78 loc) · 2.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package ifc_test
import (
"io"
"os"
"path/filepath"
"testing"
ifc "github.com/blox-eng/goifc"
"github.com/blox-eng/goifc/step"
)
// FuzzAssemble drives the WHOLE untrusted-input path — parse, semantic extract,
// tessellate, derive quantities, write GLB — because that is the path a
// third-party IFC file actually takes through a consumer. The geometry stage is
// where the hand-reasoned recursion guards live (maxMapDepth, maxWalkDepth,
// maxApproxLadder), and their own comments say the failure they prevent is a
// stack overflow that recover() cannot catch and that takes down the worker
// process. A guard nobody exercises adversarially is a guard nobody has tested.
//
// The contract asserted is deliberately weak — no panic, no hang, no unbounded
// recursion, and an error rather than a half-built result. Garbage in may
// legitimately yield an empty scene; it must never yield a crash.
func FuzzAssemble(f *testing.F) {
for _, g := range []string{
"testdata/*.ifc",
"geometry/testdata/synthetic/*.ifc",
"model/testdata/synthetic/*.ifc",
"step/testdata/*.ifc",
} {
paths, err := filepath.Glob(g)
if err != nil {
f.Fatalf("glob %s: %v", g, err)
}
for _, p := range paths {
b, err := os.ReadFile(p)
if err != nil {
f.Fatalf("read %s: %v", p, err)
}
f.Add(b)
}
}
f.Fuzz(func(t *testing.T, src []byte) {
file, err := step.ParseBytes(src)
if err != nil {
return
}
a, err := ifc.Assemble(file)
if err != nil {
if a != nil {
t.Fatalf("Assemble returned both a result and an error: %v", err)
}
return
}
if a.Result == nil || a.Scene == nil {
t.Fatal("Assemble returned a nil Result or Scene without an error")
}
// An element carrying a mesh must carry a well-formed one: Tris index
// Verts by vertex triple, so an out-of-range index is a corrupt mesh
// that would fault whatever renders or measures it downstream.
for _, e := range a.Scene.Elements {
// Check the triple-alignment first: len/3 truncates, so a Verts
// slice of length 3n+1 passes the range check below while being
// structurally malformed.
if len(e.Verts)%3 != 0 {
t.Fatalf("element %s (%s): %d floats in Verts, not a whole number of XYZ triples",
e.GlobalID, e.Source, len(e.Verts))
}
nv := uint32(len(e.Verts) / 3)
for _, idx := range e.Tris {
if idx >= nv {
t.Fatalf("element %s (%s): triangle index %d out of range for %d vertices",
e.GlobalID, e.Source, idx, nv)
}
}
}
if err := a.Scene.WriteGLB(io.Discard); err != nil {
t.Fatalf("WriteGLB on an assembled scene: %v", err)
}
})
}