Skip to content

fix: stop leaking a temp file on every image send#330

Merged
asternic merged 3 commits into
asternic:mainfrom
ThiagoBauken:fix/sendimage-temp-leak
Jun 5, 2026
Merged

fix: stop leaking a temp file on every image send#330
asternic merged 3 commits into
asternic:mainfrom
ThiagoBauken:fix/sendimage-temp-leak

Conversation

@ThiagoBauken

Copy link
Copy Markdown
Contributor

What & why

SendImage created a temp file (os.CreateTemp) to hold the resized thumbnail, read it back, and only deferred Close() — never Remove(). So every image send left a file behind in TMPDIR, eventually exhausting disk on busy servers.

Change

The thumbnail is now resized and JPEG-encoded entirely in memory via a small jpegThumbnail helper — no temp file, and two fewer filesystem operations. Behavior is otherwise identical.

Testing

  • TestJpegThumbnail — returns a decodable JPEG bounded by the requested size; fails on the un-resized path (red→green).
  • go build ./... · go vet ./... · go test ./... — pass on host.
  • GOOS=linux GOARCH=amd64 go build . + go test ./... / go test -race ./... — pass on linux/amd64 (Docker golang:1.25).

No API change — internal fix.

SendImage created a temp file (os.CreateTemp) to hold the resized thumbnail,
read it back, and only deferred Close() — never Remove() — so every image send
left a file behind in TMPDIR, eventually exhausting disk on busy servers.

The thumbnail is now resized and JPEG-encoded entirely in memory via the new
jpegThumbnail helper (no temp file, two fewer filesystem ops). Test:
TestJpegThumbnail (red->green). go build/vet/test pass on host and cross-compile
for linux/amd64.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the thumbnail generation in SendImage by introducing an in-memory helper function jpegThumbnail and an accompanying unit test, successfully eliminating the use of temporary files and preventing potential file leaks. The review feedback correctly points out that the img parameter in jpegThumbnail could be nil, which would lead to a runtime panic, and suggests adding a defensive nil check.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread handlers.go
Comment on lines +1215 to +1222
func jpegThumbnail(img image.Image, width, height uint) ([]byte, error) {
thumb := resize.Thumbnail(width, height, img, resize.Lanczos3)
var buf bytes.Buffer
if err := jpeg.Encode(&buf, thumb, nil); err != nil {
return nil, err
}
return buf.Bytes(), nil
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The img parameter is of interface type image.Image, which can be nil. If a nil image is passed to resize.Thumbnail, it will cause a runtime panic because resize.Thumbnail attempts to access the image's bounds. To ensure robust and defensive programming, add a nil check at the beginning of the function.

func jpegThumbnail(img image.Image, width, height uint) ([]byte, error) {
	if img == nil {
		return nil, errors.New("cannot create thumbnail from nil image")
	}
	thumb := resize.Thumbnail(width, height, img, resize.Lanczos3)
	var buf bytes.Buffer
	if err := jpeg.Encode(&buf, thumb, nil); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks — addressed in 7d57cfd: jpegThumbnail now returns an error on a nil image before it ever reaches resize.Thumbnail, and TestJpegThumbnailNil covers it. (c3ade4f additionally proves, on a real 1536x1024 image, that the in-memory output is byte-identical to the previous temp-file path.)

Addresses Gemini review: resize.Thumbnail dereferences the image bounds, so a
nil image would panic. jpegThumbnail now returns an error for nil instead.
Test: TestJpegThumbnailNil (fails — panics — without the guard, passes with it).
@ThiagoBauken

Copy link
Copy Markdown
Contributor Author

Thanks — added the nil guard. jpegThumbnail now returns an error for a nil image instead of letting resize.Thumbnail dereference its bounds and panic. Covered by TestJpegThumbnailNil, which fails (panics) without the guard and passes with it. go build/vet/test pass on host and it cross-compiles for linux/amd64.

… path

Adds TestJpegThumbnailRealImage: decodes the real static/images/background_image.png
(1536x1024) exactly like SendImage does, runs jpegThumbnail, and asserts the output
is byte-for-byte identical to the previous resize+encode (so the temp-file removal
changed nothing but the mechanism) and is a valid, bounded JPEG.
@asternic asternic merged commit 689d4b9 into asternic:main Jun 5, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants