parseBuffer ignores byteOffset - small PDFs read from the wrong memory
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 78/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả 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 trong pdfparser.js tại parseBuffer(), sau đó lần theo createParserStream() và đường đi của Buffer.concat. Chạy repro.mjs được cung cấp bằng Node 24 và xác nhận hành vi đối với các Buffers thuộc pool có byteOffset khác không. Được xem là hoàn tất khi tệp PDF nhỏ được phân tích thành công qua parseBuffer() và createParserStream(), trong khi loadPDF() không bị ảnh hưởng.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
I started seeing issues with Invalid XRef stream header while parsing PDF files. They are not loaded from the files but from S3 bucket.
All this happened when there was a rollout of node 24.18 which increased buffer size from 8kB to 64kB (by default).
After long investigation I was able to get full reproduction and understanding of the source of the issue. parseBuffer() assumes the Buffer it is given starts at offset 0 of its underlying ArrayBuffer. Node returns pooled Buffers (views into a shared 64 KB ArrayBuffer) for allocations under 32 KB, and that includes fs.readFileSync() of any file under 32 KB.
Environment
- pdf2json 4.0.3
- Node 24.19.0 (
Buffer.poolSizeis 65536)
Reproduction
npm i pdf2json
node repro.mjs
import fs from "node:fs";
import PDFParser from "pdf2json";
// Write a tiny valid PDF so this script is self-contained.
// Any PDF smaller than 32 KB reproduces it just as well.
const objs = [
"1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n",
"2 0 obj\n<< /Type /Pages /Kids [3 0 R] /Count 1 >>\nendobj\n",
"3 0 obj\n<< /Type /Page /Parent 2 0 R /MediaBox [0 0 200 200] /Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >>\nendobj\n",
"4 0 obj\n<< /Length 44 >>\nstream\nBT /F1 12 Tf 20 100 Td (hello pdf2json) Tj ET\nendstream\nendobj\n",
"5 0 obj\n<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>\nendobj\n",
];
let pdf = "%PDF-1.4\n";
const offsets = [];
for (const o of objs) { offsets.push(pdf.length); pdf += o; }
const xref = pdf.length;
pdf += `xref\n0 ${objs.length + 1}\n0000000000 65535 f \n`;
for (const o of offsets) pdf += `${String(o).padStart(10, "0")} 00000 n \n`;
pdf += `trailer\n<< /Size ${objs.length + 1} /Root 1 0 R >>\nstartxref\n${xref}\n%%EOF\n`;
fs.writeFileSync("tiny.pdf", Buffer.from(pdf, "latin1"));
// Uncomment this line and the script passes. It is the only change needed.
// Buffer.poolSize = 0;
// Read the file the ordinary way. No slicing, no views, no manual buffers.
const buffer = fs.readFileSync("tiny.pdf");
console.log("node :", process.version);
console.log("file size :", buffer.length);
console.log("buffer.byteOffset:", buffer.byteOffset);
console.log("buffer.buffer :", buffer.buffer.byteLength, "bytes");
const parser = new PDFParser(null, true);
parser.on("pdfParser_dataReady", () =>
console.log("\nparsed OK:", JSON.stringify(parser.getRawTextContent().split("\n")[0])));
parser.on("pdfParser_dataError", (e) =>
console.log("\nfailed:", String(e?.parserError ?? e)));
parser.parseBuffer(buffer);
Actual output:
node : v24.19.0
file size : 589
buffer.byteOffset: 2400
buffer.buffer : 65536 bytes
failed: Error: Error: Invalid XRef stream header
Uncommenting Buffer.poolSize = 0 is the only change needed to make the same file parse:
buffer.byteOffset: 0
buffer.buffer : 589 bytes
parsed OK: "hello pdf2json"
Probably this is the source of issues
pdfparser.js, in parseBuffer():
let pdfBufferParse = pdfBuffer;
if (pdfBufferParse.buffer.byteLength !== pdfBufferParse.length) {
pdfBufferParse = Buffer.from(pdfBufferParse.buffer, 0, pdfBufferParse.byteLength);
}
When the input is a view into a larger ArrayBuffer, this re-wraps it starting at offset 0 rather than at pdfBuffer.byteOffset, so the parser gets whatever else is in the pool at that position.
Also affects
createParserStream()
Piping the same tiny PDF into createParserStream() fails identically, since it calls parseBuffer(Buffer.concat(chunks)) and Buffer.concat returns a pooled buffer. loadPDF() with a file path is not affected.
- Ngôn ngữ chính
- Java
- Star
- 2.2k
- Fork
- 396
- Merge trung bình
- 9 ngày 19 giờ
- Pull request đã merge (30 ngày)
- 3
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- 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.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của modesty/pdf2json
-
getRawTextContent() returns the lines of every page in reverse order (bottom to top) since 4.0.3Đang mở
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 90/100
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 38/100
-
`getRawTextContent` does not returns words' pieces in proper coordinate orderCó thể đã có người làm Có pull request liên kết đang mở hoặc đã được merge. Đang mở
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 48/100
-
many warnings in version 4.0.0Đang mở
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 35/100
-
help-wanted: type3-font not-supported
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 42/100
Tất cả issue của modesty/pdf2json
Issue tương tự
-
hermes-queue
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 72/100
chrisalunlloyd2-sudo/mindpalace#349 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug priority: medium Review effort [1-5]: 2 status: needs-triage type: bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
carlos-emr/carlos#5818 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug good first issue help wanted tooling
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
appmonster007/kmip-adapter#100 ·
-
[Documentation]: Remove non-existent CHANGELOG reference from StateBackendProperties JavadocĐang mởaccepted good first issue java
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 88/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Marketplace time-zone issueĐang mởbug main ui
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
openhab/openhab-webui#4671 ·
Maintainer thường phản hồi trong vòng 1 ngày