Skip to content

Commit

Permalink
Remove error on reads over MemoryStream's size.
Browse files Browse the repository at this point in the history
This makes MemoryStream consistent with FileStream for reads beyond the maximum size. This is needed for the MemoryStream to be compatible with all image file formats. In particular, the JPEG library reads beyond the specified maximum buffer size. Previously, this meant that a JPEG could not easily be deserialized from a MemoryStream.
  • Loading branch information
dvicini committed Nov 15, 2023
1 parent c26b485 commit 3549783
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 7 deletions.
10 changes: 3 additions & 7 deletions src/core/mstream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,16 @@ void MemoryStream::read(void *p, size_t size) {
Throw("Attempted to read from a closed stream: %s", to_string());

if (m_pos + size > m_size) {
const auto old_pos = m_pos;
// Use signed difference since `m_pos` might be beyond `m_size`
int64_t size_read = m_size - static_cast<int64_t>(m_pos);
if (size_read > 0) {
memcpy(p, m_data + m_pos, static_cast<size_t>(size_read));
m_pos += static_cast<size_t>(size_read);
}
Log(Error, "Reading over the end of a memory stream!"
" (amount requested = %llu, amount actually read = %llu,"
" total size of the stream = %llu, previous position = %llu)",
size, size_read, m_size, old_pos);
} else {
memcpy(p, m_data + m_pos, size);
m_pos += size;
}
memcpy(p, m_data + m_pos, size);
m_pos += size;
}

void MemoryStream::write(const void *p, size_t size) {
Expand Down
28 changes: 28 additions & 0 deletions src/core/tests/test_bitmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,34 @@ def test_read_tga(variant_scalar_rgb):
assert b1 == b2


@pytest.mark.parametrize('file_format',
[mi.scalar_rgb.Bitmap.FileFormat.JPEG,
mi.scalar_rgb.Bitmap.FileFormat.PPM,
mi.scalar_rgb.Bitmap.FileFormat.PNG])
def test_read_write_memorystream_uint8(variant_scalar_rgb, np_rng, file_format):
ref = np.uint8(np_rng.random((10, 10, 3)) * 255)
b = mi.Bitmap(ref)
stream = mi.MemoryStream()
b.write(stream, file_format)
stream.seek(0)
b2 = mi.Bitmap(stream)
assert np.sum(np.abs(np.float32(np.array(b2))-ref)) / (3*10*10*255) < 0.2


@pytest.mark.parametrize('file_format',
[mi.scalar_rgb.Bitmap.FileFormat.OpenEXR,
mi.scalar_rgb.Bitmap.FileFormat.RGBE,
mi.scalar_rgb.Bitmap.FileFormat.PFM])
def test_read_write_memorystream_float32(variant_scalar_rgb, np_rng, file_format):
ref = np.float32(np_rng.random((10, 10, 3)))
b = mi.Bitmap(ref)
stream = mi.MemoryStream()
b.write(stream, file_format)
stream.seek(0)
b2 = mi.Bitmap(stream)
assert np.abs(np.mean(np.array(b2)-ref)) < 1e-2


def test_accumulate(variant_scalar_rgb):
# ----- Accumulate the whole bitmap
b1 = mi.Bitmap(mi.Bitmap.PixelFormat.RGB, mi.Struct.Type.UInt8, [10, 10])
Expand Down

0 comments on commit 3549783

Please sign in to comment.