From 1d0143386de410b19a0e4adea497f7e246e89226 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Wed, 26 Nov 2025 18:50:09 +0900 Subject: [PATCH] internal/pipewire: optional final trailing garbage check Omitting the check is only useful for custom unmarshaler. Signed-off-by: Ophestra --- internal/pipewire/client.go | 10 ++-------- internal/pipewire/core.go | 31 +++++++------------------------ internal/pipewire/pod.go | 25 +++++++++++++++++-------- 3 files changed, 26 insertions(+), 40 deletions(-) diff --git a/internal/pipewire/client.go b/internal/pipewire/client.go index ce2b627..0dce269 100644 --- a/internal/pipewire/client.go +++ b/internal/pipewire/client.go @@ -50,10 +50,7 @@ type ClientInfo struct { func (c *ClientInfo) MarshalBinary() ([]byte, error) { return Marshal(c) } // UnmarshalBinary satisfies [encoding.BinaryUnmarshaler] via [Unmarshal]. -func (c *ClientInfo) UnmarshalBinary(data []byte) error { - _, err := Unmarshal(data, c) - return err -} +func (c *ClientInfo) UnmarshalBinary(data []byte) error { return Unmarshal(data, c) } // ClientUpdateProperties is used to update the properties of a client. type ClientUpdateProperties struct { @@ -65,7 +62,4 @@ type ClientUpdateProperties struct { func (c *ClientUpdateProperties) MarshalBinary() ([]byte, error) { return Marshal(c) } // UnmarshalBinary satisfies [encoding.BinaryUnmarshaler] via [Unmarshal]. -func (c *ClientUpdateProperties) UnmarshalBinary(data []byte) error { - _, err := Unmarshal(data, c) - return err -} +func (c *ClientUpdateProperties) UnmarshalBinary(data []byte) error { return Unmarshal(data, c) } diff --git a/internal/pipewire/core.go b/internal/pipewire/core.go index 75d2b76..05fd03b 100644 --- a/internal/pipewire/core.go +++ b/internal/pipewire/core.go @@ -106,10 +106,7 @@ type CoreInfo struct { func (c *CoreInfo) MarshalBinary() ([]byte, error) { return Marshal(c) } // UnmarshalBinary satisfies [encoding.BinaryUnmarshaler] via [Unmarshal]. -func (c *CoreInfo) UnmarshalBinary(data []byte) error { - _, err := Unmarshal(data, c) - return err -} +func (c *CoreInfo) UnmarshalBinary(data []byte) error { return Unmarshal(data, c) } // The CoreBoundProps event is emitted when a local object ID is bound to a global ID. // It is emitted before the global becomes visible in the registry. @@ -126,10 +123,7 @@ type CoreBoundProps struct { func (c *CoreBoundProps) MarshalBinary() ([]byte, error) { return Marshal(c) } // UnmarshalBinary satisfies [encoding.BinaryUnmarshaler] via [Unmarshal]. -func (c *CoreBoundProps) UnmarshalBinary(data []byte) error { - _, err := Unmarshal(data, c) - return err -} +func (c *CoreBoundProps) UnmarshalBinary(data []byte) error { return Unmarshal(data, c) } // CoreHello is the first message sent by a client. type CoreHello struct { @@ -143,10 +137,7 @@ func (c *CoreHello) MarshalBinary() ([]byte, error) { } // UnmarshalBinary satisfies [encoding.BinaryUnmarshaler] via [Unmarshal]. -func (c *CoreHello) UnmarshalBinary(data []byte) error { - _, err := Unmarshal(data, c) - return err -} +func (c *CoreHello) UnmarshalBinary(data []byte) error { return Unmarshal(data, c) } const ( // CoreSyncSequenceOffset is the offset to [Header.Sequence] to produce [CoreSync.Sequence]. @@ -157,11 +148,9 @@ const ( // When the Done event is received, the client can be sure that all // operations before the Sync method have been completed. type CoreSync struct { - // The id will be returned in the Done event, - // ends up as [Header.ID] in a future message. + // The id will be returned in the Done event. ID Int - // Usually generated automatically and will be - // returned in the Done event. + // Usually generated automatically and will be returned in the Done event. Sequence Int } @@ -171,10 +160,7 @@ func (c *CoreSync) MarshalBinary() ([]byte, error) { } // UnmarshalBinary satisfies [encoding.BinaryUnmarshaler] via [Unmarshal]. -func (c *CoreSync) UnmarshalBinary(data []byte) error { - _, err := Unmarshal(data, c) - return err -} +func (c *CoreSync) UnmarshalBinary(data []byte) error { return Unmarshal(data, c) } // CoreGetRegistry is sent when a client requests to bind to the // registry object and list the available objects on the server. @@ -197,7 +183,4 @@ func (c *CoreGetRegistry) MarshalBinary() ([]byte, error) { } // UnmarshalBinary satisfies [encoding.BinaryUnmarshaler] via [Unmarshal]. -func (c *CoreGetRegistry) UnmarshalBinary(data []byte) error { - _, err := Unmarshal(data, c) - return err -} +func (c *CoreGetRegistry) UnmarshalBinary(data []byte) error { return Unmarshal(data, c) } diff --git a/internal/pipewire/pod.go b/internal/pipewire/pod.go index 1c02bd9..d36afca 100644 --- a/internal/pipewire/pod.go +++ b/internal/pipewire/pod.go @@ -204,7 +204,19 @@ func (e *InvalidUnmarshalError) Error() string { // Unmarshal parses the PipeWire POD encoded data and stores the result // in the value pointed to by v. If v is nil or not a pointer, // Unmarshal returns an [InvalidUnmarshalError]. -func Unmarshal(data []byte, v any) (size Word, err error) { +func Unmarshal(data []byte, v any) error { + if n, err := UnmarshalNext(data, v); err != nil { + return err + } else if len(data) > int(n) { + return &TrailingGarbageError{data[int(n):]} + } + + return nil +} + +// UnmarshalNext implements [Unmarshal] but returns the size of message decoded +// and skips the final trailing garbage check. +func UnmarshalNext(data []byte, v any) (size Word, err error) { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Pointer || rv.IsNil() { return 0, &InvalidUnmarshalError{reflect.TypeOf(v)} @@ -399,10 +411,7 @@ type Footer[T any] struct { func (f *Footer[T]) MarshalBinary() ([]byte, error) { return Marshal(f) } // UnmarshalBinary satisfies [encoding.BinaryUnmarshaler] via [Unmarshal]. -func (f *Footer[T]) UnmarshalBinary(data []byte) error { - _, err := Unmarshal(data, f) - return err -} +func (f *Footer[T]) UnmarshalBinary(data []byte) error { return Unmarshal(data, f) } // SPADictItem is an encoding-compatible representation of spa_dict_item. type SPADictItem struct{ Key, Value string } @@ -445,7 +454,7 @@ func (d *SPADict) UnmarshalPOD(data []byte) (Word, error) { // bounds check completed in successful call to unmarshalCheckTypeBounds data = data[:wireSize] - if size, err := Unmarshal(data, &d.NItems); err != nil { + if size, err := UnmarshalNext(data, &d.NItems); err != nil { return wireSize, err } else { // bounds check completed in successful call to Unmarshal @@ -454,13 +463,13 @@ func (d *SPADict) UnmarshalPOD(data []byte) (Word, error) { d.Items = make([]SPADictItem, d.NItems) for i := range d.Items { - if size, err := Unmarshal(data, &d.Items[i].Key); err != nil { + if size, err := UnmarshalNext(data, &d.Items[i].Key); err != nil { return wireSize, err } else { // bounds check completed in successful call to Unmarshal data = data[size:] } - if size, err := Unmarshal(data, &d.Items[i].Value); err != nil { + if size, err := UnmarshalNext(data, &d.Items[i].Value); err != nil { return wireSize, err } else { // bounds check completed in successful call to Unmarshal