1//go:build linux
2
3package protocol_test
4
5import (
6 "errors"
7 "github.com/bnema/wlturbo"
8 "github.com/bnema/wlturbo/protocol/linuxdmabuf"
9 "golang.org/x/sys/unix"
10 "io"
11 "os"
12 "testing"
13)
14
15// Exercise format_table through generated event dispatch so the received FD
16// has real transport ownership; verify closing by inspecting the taken FD.
17func TestMalformedFormatTables(t *testing.T) {
18 for _, tc := range []struct {
19 name string
20 contents []byte
21 size uint32
22 wantErr bool
23 }{
24 {"unaligned", make([]byte, 16), 17, true},
25 {"truncated", make([]byte, 16), 32, true},
26 {"zero", nil, 0, false},
27 {"oversize", nil, (16 << 20) + 16, true},
28 } {
29 t.Run(tc.name, func(t *testing.T) {
30 c, p := pair(t)
31 d, e := wlturbo.ConnectFromConn(c)
32 noerr(t, e)
33 defer d.Close()
34 request(t, p)
35 fb := linuxdmabuf.NewLinuxDmabufFeedback(d.Context())
36 fb.SetID(d.AllocateID())
37 d.Context().Register(fb)
38 file, e := os.CreateTemp(t.TempDir(), "table")
39 noerr(t, e)
40 defer file.Close()
41 _, e = file.Write(tc.contents)
42 noerr(t, e)
43 called := false
44 fb.OnFormatTable(func(fd *wlturbo.OwnedFD, size uint32) {
45 called = true
46 entries, err := linuxdmabuf.ReadFormatTable(fd, size)
47 if (err != nil) != tc.wantErr {
48 t.Fatalf("size=%d entries=%v err=%v", size, entries, err)
49 }
50 if tc.name == "truncated" && !errors.Is(err, io.ErrUnexpectedEOF) {
51 t.Fatalf("short read: %v", err)
52 }
53 // Take/Close must be idempotent, including after a failed size check.
54 if _, err = fd.Take(); err == nil {
55 t.Fatal("already consumed fd still takeable")
56 }
57 noerr(t, fd.Close())
58 noerr(t, fd.Close())
59 })
60 send(t, p, msg(fb.ID(), 1, tc.size), int(file.Fd()))
61 noerr(t, d.Dispatch())
62 if !called {
63 t.Fatal("no callback")
64 }
65 // The transport FD was a duplicate: caller's descriptor is still open.
66 if _, e = unix.FcntlInt(file.Fd(), unix.F_GETFD, 0); e != nil {
67 t.Fatalf("sender fd closed: %v", e)
68 }
69 })
70 }
71}