imagemin / imagemin-pngquant

Imagemin plugin for `pngquant`
MIT License
316 stars 81 forks source link

Write EPIPE errors for certain png images #69

Closed geraldke closed 4 years ago

geraldke commented 4 years ago

I'm getting the following error for certain png images:

at WriteWrap.onWriteComplete [as oncomplete] (internal/stream_base_commons.js:87:16)
(node:4546) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)

This seems to be happening only on linux machines. I can't replicate this on a Mac because it uses a different binary.

I've also tried identifying the problematic image with ImageMagick, I'm not seeing anything odd on the output: https://gist.github.com/geraldke/68f2e5f6480fdf18472286b73c01dfc3

Here's a test repo that can reproduce the error. Steps are on the readme, problematic image included. https://github.com/geraldke/imagemin-pngquant-issue

It's odd that running the binary directly succeeds:

./node_modules/pngquant-bin/vendor/pngquant -- images/test.png

might be related to: https://github.com/imagemin/imagemin-pngquant/issues/68

Juddling commented 4 years ago

Reproduced on an Ubuntu 18.04 system, when ran with strace we can see:

write(18, "\211PNG\r\n\32\n\0\0\0\rIHDR\0\0\4\0\0\0\3\0\10\0\0\0\0\237\321J"..., 470854) = 255808
write(18, " \342\326\353+\254\250b\2578|8\327\247\f\357\37\364B\251\302\240\"\4\216\244\314Q\310\320\277\371"..., 215046) = -1 EAGAIN (Resource temporarily unavailable)
write(18, " \342\326\353+\254\250b\2578|8\327\247\f\357\37\364B\251\302\240\"\4\216\244\314Q\310\320\277\371"..., 215046) = 182720
write(18, "7\237\370S\372\256\334\237\336\373\311\237\372\21\273\274\365a\363C\364\357\376\310/\376}\370\324\337\375\341"..., 32326) = -1 EPIPE (Broken pipe)

Which shows a partially successful write, EAGAIN, another partial write, and then EPIPE

Juddling commented 4 years ago

Turns out the png image is invalid šŸ¤¦ No fixes are required for this package.

# pngcheck test.png
test.png  additional data after IEND chunk
ERROR: test.png

For anyone interested in what's going on under the hood: the image is piped to the stdin of the child process running pngquant, when this pipe is created, a flag is set:

socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, [18, 19]) = 0

SOCK_CLOEXEC this closes the pipe as soon as the child process has executed.

The order of events is:

geraldke commented 4 years ago

@Juddling That makes perfect sense! Closing this off then, thanks!