Corrupt PNG throws uncatchable error

Đang mở
#1,747 2 bình luận 3 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

  • #1788 của @afonsojanu — đã đóng, không merge

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
55/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Ít trao đổi
Công nghệ
javascript, node.js
Lĩnh vực
backend

Hướng nghiên cứu

Bắt đầu tại điểm vào doc.image và lần theo đường đi của tính trong suốt PNG đến png-js decodePixels, nơi lỗi zlib bất đồng bộ được ném lại. Tái hiện trường hợp PNG bị hỏng được nêu trong issue và xác minh rằng lỗi có thể được bên gọi bắt lại hoặc được phát qua đường dẫn lỗi của tài liệu mà không làm tiến trình bị crash.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Bug Report

Description

When embedding a PNG which IDAT data is corrupted or truncated, pdfkit crashes the process with an uncaught exception. The error cannot be caught by the caller: wrapping inside try/catch does not work, and no error event is emitted on the document.

The root cause is in the png-js dependency. In decodePixels, it calls zlib.inflate and re-throws the error from inside the asynchronous callback:

decodePixels(fn) {
  return zlib.inflate(this.imgData, (err, data) => {
    if (err) {
      throw err;
    }
    ...

This happens specifically when pdfkit needs to access the raw pixels, for example for PNGs with transparency.

How to reproduce

Create a script as follows:

const PDFDocument = require('pdfkit');
const fs = require('fs');
const zlib = require('zlib');

// Construct a PNG which IDAT payload is not a valid zlib stream
function chunk(type, data) {
  const len = Buffer.alloc(4);
  len.writeUInt32BE(data.length);
  const body = Buffer.concat([Buffer.from(type, 'ascii'), data]);
  const crc = Buffer.alloc(4);
  crc.writeUInt32BE(zlib.crc32 ? zlib.crc32(body) : 0);
  return Buffer.concat([len, body, crc]);
}

const ihdr = Buffer.alloc(13);
ihdr.writeUInt32BE(1, 0); // width
ihdr.writeUInt32BE(1, 4); // height
ihdr[8] = 8; // bit depth
ihdr[9] = 6; // color type: RGBA (forces pdfkit to decode pixels)
const corruptPng = Buffer.concat([
  Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]),
  chunk('IHDR', ihdr),
  chunk('IDAT', Buffer.from([0xde, 0xad, 0xbe, 0xef])), // garbage deflate data
  chunk('IEND', Buffer.alloc(0)),
]);

const doc = new PDFDocument();
doc.pipe(fs.createWriteStream('/dev/null'));

try {
  doc.image(corruptPng, 0, 0);
  doc.end();
} catch (err) {
  console.log('Caught:', err.message); // never reached
}

Result: despite the try-catch, the Node process crashes.

Environment: pdfkit 0.19.1, png-js 1.1.0, Node.js 22

Suggested fix

The cleanest option is probably to replace png-js with a maintained decoder such as fast-png, which decodes synchronously, throws normal catchable errors, and seems to be more actively maintained.

Alternatively, fixing png-js itself would be fine too, of course, and I think that the fix would be small. However, this exact problem has already been reported in that repo many years ago (foliojs/png.js#14) and the repository shows little activity, so a fix on the pdfkit side seems more realistic.

Ngôn ngữ chính
JavaScript
Star
10.7k
Fork
1.2k
Merge trung bình
21 giờ 41 phút
Pull request đã merge (30 ngày)
27

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của foliojs/pdfkit

Tất cả issue của foliojs/pdfkit

Issue tương tự

Thêm issue về JavaScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.