summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2022-07-12 16:30:42 +0200
committerLuboš Luňák <l.lunak@collabora.com>2022-07-12 18:46:24 +0200
commit385dac7edebeb391df740aa94752f14834827f8d (patch)
tree005a80baadfd8e1cce8264ecde7dae701d74c096
parentc331438be97f95313ec0c21de5bc5989f2c3e03d (diff)
use a read-only stream when reading graphic data
EmbeddedObjectRef::GetGraphicStream() creates a writable SvMemoryStream, read the graphics data into it and then returns the stream, which will be afterwards used to decode the graphics. But if the data is broken, incorrect seeking may cause a seek way past the buffer, and since the stream is writable, it would be done and cause problems such as running out of memory. The VersionCompatRead class is one such place that reads size from the stream and then seeks based on the read data. Add SvMemoryStream::MakeReadOnly() that will change the stream to be read-only after the initial read of the data into it. Change-Id: I1d44aabaf73071a691adafa489e65e4f5e3f021d
-rw-r--r--include/tools/stream.hxx4
-rw-r--r--svtools/source/misc/embedhlp.cxx3
-rw-r--r--tools/CppunitTest_tools_test.mk1
-rw-r--r--tools/qa/cppunit/test_stream.cxx33
-rw-r--r--tools/source/stream/stream.cxx8
5 files changed, 48 insertions, 1 deletions
diff --git a/include/tools/stream.hxx b/include/tools/stream.hxx
index 4cbe1a3e930c..99d7fa13b2b5 100644
--- a/include/tools/stream.hxx
+++ b/include/tools/stream.hxx
@@ -661,6 +661,10 @@ public:
void SetBuffer( void* pBuf, std::size_t nSize, std::size_t nEOF );
void ObjectOwnsMemory( bool bOwn ) { bOwnsData = bOwn; }
+ /// Makes the stream read-only after it was (possibly) initially writable,
+ /// without having to copy the data or change buffers.
+ /// @since LibreOffice 7.5
+ void MakeReadOnly();
void SetResizeOffset( std::size_t nNewResize ) { nResize = nNewResize; }
virtual sal_uInt64 TellEnd() override { FlushBuffer(); return nEndOfData; }
};
diff --git a/svtools/source/misc/embedhlp.cxx b/svtools/source/misc/embedhlp.cxx
index 62fe453c0fd3..e329ccd9d14b 100644
--- a/svtools/source/misc/embedhlp.cxx
+++ b/svtools/source/misc/embedhlp.cxx
@@ -599,7 +599,7 @@ std::unique_ptr<SvStream> EmbeddedObjectRef::GetGraphicStream( bool bUpdate ) co
if ( xStream.is() )
{
const sal_Int32 nConstBufferSize = 32000;
- std::unique_ptr<SvStream> pStream(new SvMemoryStream( 32000, 32000 ));
+ std::unique_ptr<SvMemoryStream> pStream(new SvMemoryStream( 32000, 32000 ));
try
{
sal_Int32 nRead=0;
@@ -611,6 +611,7 @@ std::unique_ptr<SvStream> EmbeddedObjectRef::GetGraphicStream( bool bUpdate ) co
}
while ( nRead == nConstBufferSize );
pStream->Seek(0);
+ pStream->MakeReadOnly();
return pStream;
}
catch (const uno::Exception&)
diff --git a/tools/CppunitTest_tools_test.mk b/tools/CppunitTest_tools_test.mk
index 5672be53353f..f9e5886723c0 100644
--- a/tools/CppunitTest_tools_test.mk
+++ b/tools/CppunitTest_tools_test.mk
@@ -41,6 +41,7 @@ $(eval $(call gb_CppunitTest_use_libraries,tools_test, \
tl \
test \
unotest \
+ vcl \
))
$(eval $(call gb_CppunitTest_use_static_libraries,tools_test, \
diff --git a/tools/qa/cppunit/test_stream.cxx b/tools/qa/cppunit/test_stream.cxx
index d8e4d1ef71e1..0e025b9a533f 100644
--- a/tools/qa/cppunit/test_stream.cxx
+++ b/tools/qa/cppunit/test_stream.cxx
@@ -27,6 +27,7 @@ namespace
void test_read_cstring();
void test_read_pstring();
void test_readline();
+ void test_makereadonly();
CPPUNIT_TEST_SUITE(Test);
CPPUNIT_TEST(test_stdstream);
@@ -34,6 +35,7 @@ namespace
CPPUNIT_TEST(test_read_cstring);
CPPUNIT_TEST(test_read_pstring);
CPPUNIT_TEST(test_readline);
+ CPPUNIT_TEST(test_makereadonly);
CPPUNIT_TEST_SUITE_END();
};
@@ -271,6 +273,37 @@ namespace
CPPUNIT_ASSERT(issB.eof()); //<-- diff A
}
+ void Test::test_makereadonly()
+ {
+ SvMemoryStream aMemStream;
+ CPPUNIT_ASSERT(aMemStream.IsWritable());
+ CPPUNIT_ASSERT_EQUAL(sal_uInt64(0), aMemStream.GetSize());
+ aMemStream.WriteInt64(21);
+ CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, aMemStream.GetError());
+ CPPUNIT_ASSERT_EQUAL(sal_uInt64(8), aMemStream.GetSize());
+
+ aMemStream.MakeReadOnly();
+ CPPUNIT_ASSERT(!aMemStream.IsWritable());
+ CPPUNIT_ASSERT_EQUAL(sal_uInt64(8), aMemStream.GetSize());
+ aMemStream.WriteInt64(42);
+ CPPUNIT_ASSERT_EQUAL(ERRCODE_IO_CANTWRITE, aMemStream.GetError());
+ CPPUNIT_ASSERT_EQUAL(sal_uInt64(8), aMemStream.GetSize());
+
+ aMemStream.ResetError();
+ // Check that seeking past the end doesn't resize a read-only stream.
+ // This apparently doesn't set an error, but at least it shouldn't
+ // change the size.
+ aMemStream.Seek(1024LL*1024*1024*3);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt64(8), aMemStream.GetSize());
+
+ aMemStream.ResetError();
+ aMemStream.Seek(0);
+ sal_Int64 res;
+ aMemStream.ReadInt64(res);
+ CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, aMemStream.GetError());
+ CPPUNIT_ASSERT_EQUAL(sal_Int64(21), res);
+ }
+
CPPUNIT_TEST_SUITE_REGISTRATION(Test);
}
diff --git a/tools/source/stream/stream.cxx b/tools/source/stream/stream.cxx
index 404b9eb67537..f0fd3a9de7ec 100644
--- a/tools/source/stream/stream.cxx
+++ b/tools/source/stream/stream.cxx
@@ -1903,6 +1903,14 @@ void SvMemoryStream::SetSize(sal_uInt64 const nNewSize)
ReAllocateMemory( nDiff );
}
+void SvMemoryStream::MakeReadOnly()
+{
+ FlushBuffer();
+ m_isWritable = false;
+ nResize = 0;
+ SetBufferSize( 0 );
+}
+
//Create an OString of nLen bytes from rStream
OString read_uInt8s_ToOString(SvStream& rStrm, std::size_t nLen)
{