github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/internal/errors_test.go (about) 1 package internal 2 3 import ( 4 "errors" 5 "os" 6 "testing" 7 8 "github.com/go-quicktest/qt" 9 10 "github.com/cilium/ebpf/internal/unix" 11 ) 12 13 func TestVerifierErrorWhitespace(t *testing.T) { 14 b := []byte("unreachable insn 28") 15 b = append(b, 16 0xa, // \n 17 0xd, // \r 18 0x9, // \t 19 0x20, // space 20 0, 0, // trailing NUL bytes 21 ) 22 23 err := ErrorWithLog("frob", errors.New("test"), b, false) 24 qt.Assert(t, qt.Equals(err.Error(), "frob: test: unreachable insn 28")) 25 26 for _, log := range [][]byte{ 27 nil, 28 []byte("\x00"), 29 []byte(" "), 30 } { 31 err = ErrorWithLog("frob", errors.New("test"), log, false) 32 qt.Assert(t, qt.Equals(err.Error(), "frob: test"), qt.Commentf("empty log %q has incorrect format", log)) 33 } 34 } 35 36 func TestVerifierErrorWrapping(t *testing.T) { 37 ve := ErrorWithLog("frob", unix.ENOENT, nil, false) 38 qt.Assert(t, qt.ErrorIs(ve, unix.ENOENT), qt.Commentf("should wrap provided error")) 39 qt.Assert(t, qt.IsFalse(ve.Truncated), qt.Commentf("verifier log should not be marked as truncated")) 40 41 ve = ErrorWithLog("frob", unix.EINVAL, nil, true) 42 qt.Assert(t, qt.ErrorIs(ve, unix.EINVAL), qt.Commentf("should wrap provided error")) 43 qt.Assert(t, qt.IsTrue(ve.Truncated), qt.Commentf("verifier log should be marked as truncated")) 44 45 ve = ErrorWithLog("frob", unix.EINVAL, []byte("foo"), false) 46 qt.Assert(t, qt.ErrorIs(ve, unix.EINVAL), qt.Commentf("should wrap provided error")) 47 qt.Assert(t, qt.StringContains(ve.Error(), "foo"), qt.Commentf("verifier log should appear in error string")) 48 49 ve = ErrorWithLog("frob", unix.ENOSPC, []byte("foo"), true) 50 qt.Assert(t, qt.ErrorIs(ve, unix.ENOSPC), qt.Commentf("should wrap provided error")) 51 qt.Assert(t, qt.StringContains(ve.Error(), "foo"), qt.Commentf("verifier log should appear in error string")) 52 qt.Assert(t, qt.IsTrue(ve.Truncated), qt.Commentf("verifier log should be marked truncated")) 53 } 54 55 func TestVerifierErrorSummary(t *testing.T) { 56 // Suppress the last line containing 'processed ... insns'. 57 errno524 := readErrorFromFile(t, "testdata/errno524.log") 58 qt.Assert(t, qt.StringContains(errno524.Error(), "JIT doesn't support bpf-to-bpf calls")) 59 qt.Assert(t, qt.Not(qt.StringContains(errno524.Error(), "processed 39 insns"))) 60 61 // Include the previous line if the current one starts with a tab. 62 invalidMember := readErrorFromFile(t, "testdata/invalid-member.log") 63 qt.Assert(t, qt.StringContains(invalidMember.Error(), "STRUCT task_struct size=7744 vlen=218: cpus_mask type_id=109 bitfield_size=0 bits_offset=7744 Invalid member")) 64 65 // Only include the last line. 66 issue43 := readErrorFromFile(t, "testdata/issue-43.log") 67 qt.Assert(t, qt.StringContains(issue43.Error(), "[11] FUNC helper_func2 type_id=10 vlen != 0")) 68 qt.Assert(t, qt.Not(qt.StringContains(issue43.Error(), "[10] FUNC_PROTO (anon) return=3 args=(3 arg)"))) 69 70 // Include instruction that caused invalid register access. 71 invalidR0 := readErrorFromFile(t, "testdata/invalid-R0.log") 72 qt.Assert(t, qt.StringContains(invalidR0.Error(), "0: (95) exit: R0 !read_ok")) 73 74 // Include symbol that doesn't match context type. 75 invalidCtx := readErrorFromFile(t, "testdata/invalid-ctx-access.log") 76 qt.Assert(t, qt.StringContains(invalidCtx.Error(), "func '__x64_sys_recvfrom' arg0 type FWD is not a struct: invalid bpf_context access off=0 size=8")) 77 } 78 79 func readErrorFromFile(tb testing.TB, file string) *VerifierError { 80 tb.Helper() 81 82 contents, err := os.ReadFile(file) 83 if err != nil { 84 tb.Fatal("Read file:", err) 85 } 86 87 return ErrorWithLog("file", unix.EINVAL, contents, false) 88 }