From f67cc657eb5ab41c2f904ecd56573e496ef19262 Mon Sep 17 00:00:00 2001 From: "Brandon McGinty (chatgpt)" Date: Sun, 9 Aug 2026 14:20:50 -0400 Subject: [PATCH] Initialize context actions with their client --- fix.txt | 2 +- gumble/gumble/client.go | 9 ++-- .../gumble/contextaction_regression_test.go | 52 +++++++++++++++++++ gumble/gumble/contextactions.go | 5 +- gumble/gumble/handlers.go | 2 +- 5 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 gumble/gumble/contextaction_regression_test.go diff --git a/fix.txt b/fix.txt index 744e363..d139e61 100644 --- a/fix.txt +++ b/fix.txt @@ -28,7 +28,7 @@ Priority 0: security and crashers ensure channel close/send are serialized. Do not rely on the TCP read routine being serialized with UDP. -3. Context actions panic on receipt and on trigger +[x] 3. Context actions panic on receipt and on trigger Files: gumble/gumble/client.go, gumble/gumble/handlers.go, gumble/gumble/contextaction.go Client.ContextActions is never initialized, so the first diff --git a/gumble/gumble/client.go b/gumble/gumble/client.go index d4444c8..f400f49 100644 --- a/gumble/gumble/client.go +++ b/gumble/gumble/client.go @@ -118,10 +118,11 @@ func DialWithDialer(dialer *net.Dialer, config *Config, tlsConfig *tls.Config) ( } client := &Client{ - Conn: NewConn(conn), - Config: config, - Users: make(Users), - Channels: make(Channels), + Conn: NewConn(conn), + Config: config, + Users: make(Users), + Channels: make(Channels), + ContextActions: make(ContextActions), permissions: make(map[uint32]*Permission), diff --git a/gumble/gumble/contextaction_regression_test.go b/gumble/gumble/contextaction_regression_test.go new file mode 100644 index 0000000..021a39c --- /dev/null +++ b/gumble/gumble/contextaction_regression_test.go @@ -0,0 +1,52 @@ +package gumble + +import ( + "net" + "testing" + + "git.stormux.org/storm/barnard/gumble/gumble/MumbleProto" + "google.golang.org/protobuf/proto" +) + +// Regression: server context-action adds wrote to a nil map and the resulting +// action had no owning client, so Trigger panicked. +func TestContextActionAddAndTrigger(t *testing.T) { + clientConn, serverConn := net.Pipe() + defer serverConn.Close() + c := &Client{Config: NewConfig(), Users: make(Users), Channels: make(Channels), ContextActions: make(ContextActions)} + c.Conn = NewConn(clientConn) + action, operation := "test", MumbleProto.ContextActionModify_Add + data, err := proto.Marshal(&MumbleProto.ContextActionModify{Action: &action, Operation: &operation}) + if err != nil { + t.Fatal(err) + } + if err := c.handleContextActionModify(data); err != nil { + t.Fatal(err) + } + added := c.ContextActions[action] + if added == nil || added.client != c { + t.Fatal("action was not initialized with its client") + } + written := make(chan error, 1) + go func() { _, _, err := NewConn(serverConn).ReadPacket(); written <- err }() + added.Trigger() + if err := <-written; err != nil { + t.Fatalf("trigger did not write: %v", err) + } + remove := MumbleProto.ContextActionModify_Remove + data, _ = proto.Marshal(&MumbleProto.ContextActionModify{Action: &action, Operation: &remove}) + if err := c.handleContextActionModify(data); err != nil { + t.Fatal(err) + } + if c.ContextActions[action] != nil { + t.Fatal("action was not removed") + } +} + +// Regression: the documented bit layout disagreed with SemanticVersion. +func TestSemanticVersionKnownLayout(t *testing.T) { + major, minor, patch := (&Version{Version: 1<<16 | 5<<8 | 2}).SemanticVersion() + if major != 1 || minor != 5 || patch != 2 { + t.Fatalf("got %d.%d.%d", major, minor, patch) + } +} diff --git a/gumble/gumble/contextactions.go b/gumble/gumble/contextactions.go index 6dd0c16..ee58bfd 100644 --- a/gumble/gumble/contextactions.go +++ b/gumble/gumble/contextactions.go @@ -3,9 +3,10 @@ package gumble // ContextActions is a map of ContextActions. type ContextActions map[string]*ContextAction -func (c ContextActions) create(action string) *ContextAction { +func (c ContextActions) create(client *Client, action string) *ContextAction { contextAction := &ContextAction{ - Name: action, + Name: action, + client: client, } c[action] = contextAction return contextAction diff --git a/gumble/gumble/handlers.go b/gumble/gumble/handlers.go index b1d9f0a..0cc859f 100644 --- a/gumble/gumble/handlers.go +++ b/gumble/gumble/handlers.go @@ -1029,7 +1029,7 @@ func (c *Client) handleContextActionModify(buffer []byte) error { return nil } event.Type = ContextActionAdd - contextAction := c.ContextActions.create(*packet.Action) + contextAction := c.ContextActions.create(c, *packet.Action) if packet.Text != nil { contextAction.Label = *packet.Text }