Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc fixes #560

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions pipelines/_steps/url_preview/upload_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,16 @@ func UploadImage(ctx rcontext.RequestContext, image *m.PreviewImage, onHost stri
defer image.Data.Close()
pr, pw := io.Pipe()
tee := io.TeeReader(image.Data, pw)
mediaChan := make(chan *database.DbMedia)
defer close(mediaChan)
mediaChan := make(chan *database.DbMedia, 1)
go func() {
media, err := pipeline_upload.Execute(ctx, onHost, "", io.NopCloser(tee), image.ContentType, image.Filename, userId, datastores.LocalMediaKind)
if err != nil {
_ = pw.CloseWithError(err)
} else {
_ = pw.Close()
}
go func() {
defer func() {
recover() // consume write-to-closed-channel errors
}()
mediaChan <- media
}()
mediaChan <- media
close(mediaChan)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's a bit uncomfortable to me to have the close in the goroutine when the channel is created externally - please restore the defer close(mediaChan) to avoid potential resource leaks.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this is a bug. Recovering from a panic does not remedy unclear channel ownership. The go routine for writing is no longer necessary since this is a buffered channel now. And the channel can just be closed afterwards. A simple look at the possible code paths confirms that there is no way the channel could remain unclosed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The panic recovery is indeed a bug, though the defer close(mediaChan) needs to be moved up near the channel creation please. The remainder of the change is fine, I think.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. This is a concurrency bug. The channel closing can be deferred in the writing function, but never outside of it. Otherwise, you end with a potential write on a closed channel. And since uploading likely takes a few milliseconds more than thumbnailing (at least on reasonably fast hardware), this will happen more often than not. So the best I could do is:

go func(){
    defer close(mediachan)
    // upload and stuff

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be blocking on a read from the channel before the defer would fire - if we're not, then the concurrency is broken for sure. I'm not really comfortable using a different close style in a single section of the code, and would rather go out of the way to make defer close() immediately after creation work reliably.

}()

w := 0
Expand Down