bound the configured audio buffer count
Buffers had a lower bound but no upper one, and it is allocated per speaking user twice over: as a queue of decoded frames and as OpenAL playback buffers. Each buffer holds up to one maximum sized frame, so a large value multiplied by a populated channel is a substantial amount of memory. Cap it, and reject the flag up front so the failure names the flag rather than surfacing later as a dial error. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
0d62f745ca
commit
ef9bd19fc9
@@ -38,6 +38,12 @@ type Config struct {
|
||||
Buffers int
|
||||
}
|
||||
|
||||
// MaximumBuffers caps Config.Buffers. Each buffer holds up to one maximum
|
||||
// sized audio frame and is allocated per speaking user, so a large value
|
||||
// multiplied by a populated channel is a substantial amount of memory. A few
|
||||
// seconds of buffering is already far more than playback needs.
|
||||
const MaximumBuffers = 1024
|
||||
|
||||
// NewConfig returns a new Config struct with default values set.
|
||||
func NewConfig() *Config {
|
||||
return &Config{
|
||||
@@ -64,6 +70,12 @@ func (c *Config) Validate() error {
|
||||
if c.Buffers <= 0 {
|
||||
return fmt.Errorf("gumble: Buffers must be positive")
|
||||
}
|
||||
// Buffers is allocated per speaking user, both as a queue of decoded
|
||||
// frames and as OpenAL playback buffers, so an unbounded value multiplies
|
||||
// straight into memory use as a channel fills up.
|
||||
if c.Buffers > MaximumBuffers {
|
||||
return fmt.Errorf("gumble: Buffers must be at most %d", MaximumBuffers)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package gumble
|
||||
|
||||
import "testing"
|
||||
|
||||
// Regression: Buffers had no upper bound, but it is allocated per speaking
|
||||
// user both as a decoded-frame queue and as OpenAL playback buffers.
|
||||
func TestConfigRejectsOversizedBuffers(t *testing.T) {
|
||||
config := NewConfig()
|
||||
config.Buffers = MaximumBuffers + 1
|
||||
if err := config.Validate(); err == nil {
|
||||
t.Fatal("expected Buffers above the maximum to be rejected")
|
||||
}
|
||||
config.Buffers = MaximumBuffers
|
||||
if err := config.Validate(); err != nil {
|
||||
t.Fatalf("Buffers at the maximum should be accepted: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -105,6 +105,10 @@ func main() {
|
||||
if err != nil {
|
||||
handle_raw_error(err)
|
||||
}
|
||||
if *buffers <= 0 || *buffers > gumble.MaximumBuffers {
|
||||
handle_raw_error(fmt.Errorf("buffers must be between 1 and %d, got %d",
|
||||
gumble.MaximumBuffers, *buffers))
|
||||
}
|
||||
|
||||
// Set up logging
|
||||
var level barnlog.Level
|
||||
|
||||
Reference in New Issue
Block a user