diff --git a/src/stream.c b/src/stream.c index 60e6aa384c..8ea90cf866 100644 --- a/src/stream.c +++ b/src/stream.c @@ -397,13 +397,12 @@ avifResult avifRWStreamWriteChars(avifRWStream * stream, const char * chars, siz avifResult avifRWStreamWriteFullBox(avifRWStream * stream, const char * type, size_t contentSize, int version, uint32_t flags, avifBoxMarker * marker) { assert(stream->numUsedBitsInPartialByte == 0); // Byte alignment is required. - if (marker) { - *marker = stream->offset; - } + avifBoxMarker oldOffset = stream->offset; size_t headerSize = sizeof(uint32_t) + 4 /* size of type */; if (version != -1) { headerSize += 4; } + AVIF_CHECKERR(contentSize <= UINT32_MAX - headerSize, AVIF_RESULT_INVALID_ARGUMENT); AVIF_CHECKRES(makeRoom(stream, headerSize)); memset(stream->raw->data + stream->offset, 0, headerSize); @@ -416,6 +415,9 @@ avifResult avifRWStreamWriteFullBox(avifRWStream * stream, const char * type, si stream->raw->data[stream->offset + 10] = (uint8_t)((flags >> 8) & 0xff); stream->raw->data[stream->offset + 11] = (uint8_t)((flags >> 0) & 0xff); } + if (marker) { + *marker = oldOffset; + } stream->offset += headerSize; return AVIF_RESULT_OK; diff --git a/tests/gtest/avifstreamtest.cc b/tests/gtest/avifstreamtest.cc index 199b8bef12..a493f336f0 100644 --- a/tests/gtest/avifstreamtest.cc +++ b/tests/gtest/avifstreamtest.cc @@ -202,6 +202,42 @@ TEST(StreamTest, WriteBitsLimit) { AVIF_RESULT_INVALID_ARGUMENT); } +TEST(StreamTest, WriteBoxSizeLimit) { + testutil::AvifRwData rw_data; + avifRWStream rw_stream; + avifRWStreamStart(&rw_stream, &rw_data); + const char box_type[] = "type"; + avifBoxMarker marker = 123; + + EXPECT_EQ( + avifRWStreamWriteBox( + &rw_stream, box_type, + std::numeric_limits::max() - sizeof(uint32_t) - 4, &marker), + AVIF_RESULT_OK); + EXPECT_EQ(marker, size_t{0}); + EXPECT_EQ(avifRWStreamOffset(&rw_stream), sizeof(uint32_t) + 4); + + EXPECT_EQ( + avifRWStreamWriteBox( + &rw_stream, box_type, + std::numeric_limits::max() - sizeof(uint32_t) - 3, &marker), + AVIF_RESULT_INVALID_ARGUMENT); + + EXPECT_EQ(avifRWStreamWriteFullBox( + &rw_stream, box_type, + std::numeric_limits::max() - sizeof(uint32_t) - 8, + /*version=*/0, /*flags=*/0, &marker), + AVIF_RESULT_OK); + EXPECT_EQ(marker, sizeof(uint32_t) + 4); + EXPECT_EQ(avifRWStreamOffset(&rw_stream), 2 * (sizeof(uint32_t) + 4) + 4); + + EXPECT_EQ(avifRWStreamWriteFullBox( + &rw_stream, box_type, + std::numeric_limits::max() - sizeof(uint32_t) - 7, + /*version=*/0, /*flags=*/0, &marker), + AVIF_RESULT_INVALID_ARGUMENT); +} + // Test the overflow checks in the makeRoom() function in src/stream.c. TEST(StreamTest, OverflowChecksInMakeRoom) { testutil::AvifRwData rw_data;