Cap PixelBuffer.from_bytes dimensions at 64k x 64k

Following review feedback, the reader now rejects a header claiming a
width or height beyond 65536, guarding against malformed byte streams
that would otherwise trigger an unreasonable allocation. The writer
stays full 32-bit ('unlimited'), and native little-endian order and the
transparency mask are kept as-is. Adds Ruby and Python tests for the
oversized-header rejection.

Ref: https://github.com/KLayout/klayout/pull/2387#issuecomment-4984941409
This commit is contained in:
Kirill Osipov 2026-07-16 19:03:34 +02:00
parent 2fa7b24345
commit 9a606ec4e9
3 changed files with 21 additions and 1 deletions

View File

@ -146,6 +146,12 @@ static tl::PixelBuffer pixel_buffer_from_bytes (const std::vector<char> &data)
memcpy (&w, data.data (), 4);
memcpy (&h, data.data () + 4, 4);
}
// sanity guard against malformed headers: reader caps dimensions at 64k x 64k
// (generous for finely-resolved drawings), writer stays full 32-bit
const uint32_t max_dim = 65536;
if (w > max_dim || h > max_dim) {
throw tl::Exception (tl::to_string (tr ("Invalid PixelBuffer byte stream: width or height exceeds the 65536 x 65536 limit")));
}
if (data.size () != 8 + (size_t) w * (size_t) h * 4) {
throw tl::Exception (tl::to_string (tr ("Invalid PixelBuffer byte stream: length does not match the width and height in the header")));
}
@ -229,7 +235,8 @@ Class<tl::PixelBuffer> decl_PixelBuffer ("lay", "PixelBuffer",
gsi::method ("from_bytes", &pixel_buffer_from_bytes, gsi::arg ("data"),
"@brief Reconstructs a pixel buffer from a byte stream produced by \\to_bytes\n"
"\n"
"The width and height are taken from the header and the stream length is checked against them.\n"
"The width and height are taken from the header and the stream length is checked against them. "
"The dimensions are capped at 65536 x 65536; a header exceeding this limit raises an error.\n"
"\n"
"This method has been added in version 0.30.10."
) +

View File

@ -78,6 +78,10 @@ class LAYPixelBufferTests(unittest.TestCase):
with self.assertRaises(Exception):
pya.PixelBuffer.from_bytes(data[:-4])
# a header beyond the 64k x 64k limit is rejected
with self.assertRaises(Exception):
pya.PixelBuffer.from_bytes(struct.pack("=II", 65537, 1))
# run unit tests
if __name__ == '__main__':

View File

@ -176,6 +176,15 @@ class LAYPixelBuffer_TestClass < TestBase
end
assert_equal(error, true)
# a header beyond the 64k x 64k limit is rejected
error = false
begin
RBA::PixelBuffer.from_bytes([ 65537, 1 ].pack("VV"))
rescue
error = true
end
assert_equal(error, true)
end
def test_11