internal/pipewire: handle dangling files in roundtrip
All checks were successful
Test / Create distribution (push) Successful in 39s
Test / Sandbox (push) Successful in 2m40s
Test / Sandbox (race detector) (push) Successful in 4m47s
Test / Hakurei (push) Successful in 5m3s
Test / Hpkg (push) Successful in 5m5s
Test / Hakurei (race detector) (push) Successful in 6m50s
Test / Flake checks (push) Successful in 1m32s
All checks were successful
Test / Create distribution (push) Successful in 39s
Test / Sandbox (push) Successful in 2m40s
Test / Sandbox (race detector) (push) Successful in 4m47s
Test / Hakurei (push) Successful in 5m3s
Test / Hpkg (push) Successful in 5m5s
Test / Hakurei (race detector) (push) Successful in 6m50s
Test / Flake checks (push) Successful in 1m32s
This should not be handled on every receive as it could cause valid (though impossible in current upstream implementation) messages to be rejected and raise a protocol error. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
7cb3308a53
commit
5e7861bb00
@ -571,6 +571,36 @@ func (ctx *Context) roundtrip() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
var danglingFiles DanglingFilesError
|
||||
if len(ctx.receivedFiles) > 0 {
|
||||
// having multiple *os.File with the same fd causes serious problems
|
||||
slices.Sort(ctx.receivedFiles)
|
||||
ctx.receivedFiles = slices.Compact(ctx.receivedFiles)
|
||||
|
||||
danglingFiles = make(DanglingFilesError, 0, len(ctx.receivedFiles))
|
||||
for _, fd := range ctx.receivedFiles {
|
||||
// hold these as *os.File so they are closed if this error never reaches the caller,
|
||||
// or the caller discards or otherwise does not handle this error, to avoid leaking fds
|
||||
danglingFiles = append(danglingFiles, os.NewFile(uintptr(fd),
|
||||
"dangling fd "+strconv.Itoa(fd)+" received from PipeWire"))
|
||||
}
|
||||
ctx.receivedFiles = ctx.receivedFiles[:0]
|
||||
}
|
||||
|
||||
// populated early for finalizers, but does not overwrite existing errors
|
||||
if len(danglingFiles) > 0 && err == nil {
|
||||
err = &ProxyFatalError{Err: danglingFiles, ProxyErrs: ctx.cloneAsProxyErrors()}
|
||||
return
|
||||
}
|
||||
|
||||
// this check must happen after everything else passes
|
||||
if len(ctx.pendingIds) != 0 {
|
||||
err = &ProxyFatalError{Err: UnacknowledgedProxyError(slices.Collect(maps.Keys(ctx.pendingIds))), ProxyErrs: ctx.cloneAsProxyErrors()}
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
var remaining []byte
|
||||
for {
|
||||
remaining, err = ctx.consume(remaining)
|
||||
@ -595,22 +625,6 @@ func (ctx *Context) roundtrip() (err error) {
|
||||
// consume receives messages from the server and processes events.
|
||||
func (ctx *Context) consume(receiveRemaining []byte) (remaining []byte, err error) {
|
||||
defer func() {
|
||||
// anything before this has already been processed and must not be closed
|
||||
// here, as anything holding onto them will end up with a dangling fd that
|
||||
// can be reused and cause serious problems
|
||||
if len(ctx.receivedFiles) > 0 {
|
||||
ctx.closeReceivedFiles()
|
||||
|
||||
// this catches cases where Roundtrip somehow returns without processing
|
||||
// all received files or preparing an error for dangling files, this is
|
||||
// always overwritten by the fatal error being processed below or made
|
||||
// inaccessible due to repanicking, so if this ends up returned to the
|
||||
// caller it indicates something has gone seriously wrong in Roundtrip
|
||||
if err == nil {
|
||||
err = syscall.ENOTRECOVERABLE
|
||||
}
|
||||
}
|
||||
|
||||
r := recover()
|
||||
if r == nil {
|
||||
return
|
||||
@ -677,34 +691,6 @@ func (ctx *Context) consume(receiveRemaining []byte) (remaining []byte, err erro
|
||||
ctx.proxyErrors = append(ctx.proxyErrors, proxyErr)
|
||||
}
|
||||
}
|
||||
|
||||
// prepared here so finalizers are set up, but should not prevent proxyErrors
|
||||
// from reaching the caller as those describe the cause of these dangling fds
|
||||
var danglingFiles DanglingFilesError
|
||||
if len(ctx.receivedFiles) > 0 {
|
||||
// having multiple *os.File with the same fd causes serious problems
|
||||
slices.Sort(ctx.receivedFiles)
|
||||
ctx.receivedFiles = slices.Compact(ctx.receivedFiles)
|
||||
|
||||
danglingFiles = make(DanglingFilesError, 0, len(ctx.receivedFiles))
|
||||
for _, fd := range ctx.receivedFiles {
|
||||
// hold these as *os.File so they are closed if this error never reaches the caller,
|
||||
// or the caller discards or otherwise does not handle this error, to avoid leaking fds
|
||||
danglingFiles = append(danglingFiles, os.NewFile(uintptr(fd),
|
||||
"dangling fd "+strconv.Itoa(fd)+" received from PipeWire"))
|
||||
}
|
||||
ctx.receivedFiles = ctx.receivedFiles[:0]
|
||||
}
|
||||
|
||||
// populated early for finalizers
|
||||
if len(danglingFiles) > 0 {
|
||||
return remaining, danglingFiles
|
||||
}
|
||||
|
||||
// this check must happen after everything else passes
|
||||
if len(ctx.pendingIds) != 0 {
|
||||
return remaining, UnacknowledgedProxyError(slices.Collect(maps.Keys(ctx.pendingIds)))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user