foliojs / png.js

A (animated) PNG decoder in JavaScript for the HTML5 canvas element and Node.js
http://devongovett.github.com/png.js
MIT License
489 stars 92 forks source link

Impossible to catch error thrown from inside decodePixels' zlib.inflate's callback #74

Open nitram-work opened 1 year ago

nitram-work commented 1 year ago

When throwing an error from inside zlib.inflate's callback it goes right down to the event queue handlers, internal to node, and not to the user code. As this is uncaught it will crash the application even if only one image has a failure.

You can trap them with process.on('uncaughtException', ...) to avoid the hard crash, but then fn() never gets called and most use case programs will just keep waiting for a decode that never finishes, an unnecessary timeout.

Any error should either pass through to a callback function or be logged but never thrown from inside the decode coroutine. Maybe a secondary optional reject parameter: decodePixels(fn, reject) to avoid breaking the api?

Node v16.17.1

Lines: https://github.com/foliojs/png.js/blob/master/png-node.js#L185 https://github.com/foliojs/png.js/blob/master/png-node.js#L293

MWE

const { inflate } = require('zlib');

// Same with inflate, gunzip, unzip

process.on('uncaughtException', err => {
  console.error('Uncaught Error', err);
});

const buf = Buffer.alloc(1);
try {
  inflate(buf, (error, decompressed) => {
    throw new Error('See stack trace. Example usage: Found error / wrong data');
  });
  console.log('Continue');
}catch(e) {
  console.error('Catch!', e);
}

Stack trace for the throw:

    at Inflate.cb (/mwe.js:12:11)
    at Inflate.zlibBufferOnError (node:zlib:146:8)
    at Inflate.emit (node:events:513:28)
    at emitErrorNT (node:internal/streams/destroy:157:8)
    at emitErrorCloseNT (node:internal/streams/destroy:122:3)
    at processTicksAndRejections (node:internal/process/task_queues:83:21)