From be9ccf08d9072ebf6f2edddafc378604f47d7420 Mon Sep 17 00:00:00 2001 From: fraillt Date: Mon, 30 Oct 2017 08:55:27 +0200 Subject: [PATCH] added NotNull pointer to to pointer extensions --- include/bitsery/adapter_reader.h | 3 ++- include/bitsery/details/sessions.h | 9 ++++++--- include/bitsery/ext/pointer.h | 29 +++++++++++++++++++++++++---- tests/serialization_ext_pointer.cpp | 21 ++++++++++++++++++++- 4 files changed, 53 insertions(+), 9 deletions(-) diff --git a/include/bitsery/adapter_reader.h b/include/bitsery/adapter_reader.h index 1d22e21..a1b9aa8 100644 --- a/include/bitsery/adapter_reader.h +++ b/include/bitsery/adapter_reader.h @@ -99,7 +99,8 @@ namespace bitsery { } void setError(ReaderError error) { - return _inputAdapter.setError(error); + if (this->error() == ReaderError::NoError) + _inputAdapter.setError(error); } void beginSession() { diff --git a/include/bitsery/details/sessions.h b/include/bitsery/details/sessions.h index 1b86129..b4db60b 100644 --- a/include/bitsery/details/sessions.h +++ b/include/bitsery/details/sessions.h @@ -163,9 +163,12 @@ namespace bitsery { break; } } - _posItRef = _endItRef; - //restore end position - _endItRef = _sessionsStack.top(); + //modify pointers only if no error or buffer overflow + if (_reader.error() == ReaderError::NoError || _reader.error() == ReaderError::DataOverflow) { + _posItRef = _endItRef; + //restore end position + _endItRef = _sessionsStack.top(); + } _sessionsStack.pop(); } } diff --git a/include/bitsery/ext/pointer.h b/include/bitsery/ext/pointer.h index f2ba2d1..f63223f 100644 --- a/include/bitsery/ext/pointer.h +++ b/include/bitsery/ext/pointer.h @@ -34,6 +34,11 @@ namespace bitsery { //forward declare class PointerLinkingContext; + enum PointerType { + Nullable, + NotNull + }; + namespace details_pointer { enum class PointerOwnershipType:uint8_t { @@ -263,10 +268,13 @@ namespace bitsery { class PointerOwner { public: + explicit PointerOwner(PointerType ptrType = PointerType::Nullable):_ptrType{ptrType} {} + template void serialize(Ser &ser, Writer &w, const T &obj, Fnc &&) const { auto& ctx = details_pointer::getLinkingContext(ser); auto id = ctx.createId(obj, details_pointer::PointerOwnershipType::Owner); + assert(id || _ptrType == PointerType::Nullable); details::writeSize(w, id); if (id) ctx.serialize(ser, obj); @@ -282,18 +290,27 @@ namespace bitsery { ctx.deserialize(des, obj); ctx.processOwnerPtr(id, obj, details_pointer::PointerOwnershipType::Owner); } else { - details_pointer::destroyPointer(obj); + if (_ptrType == PointerType::Nullable) + details_pointer::destroyPointer(obj); + else + r.setError(ReaderError::InvalidPointer); } } + private: + PointerType _ptrType; }; class PointerObserver { public: + explicit PointerObserver(PointerType ptrType = PointerType::Nullable):_ptrType{ptrType} {} + template void serialize(Ser &ser, Writer &w, const T &obj, Fnc &&) const { auto& ctx = details_pointer::getLinkingContext(ser); - details::writeSize(w, ctx.createId(obj, details_pointer::PointerOwnershipType::Observer)); + auto id = ctx.createId(obj, details_pointer::PointerOwnershipType::Observer); + assert(id || _ptrType == PointerType::Nullable); + details::writeSize(w, id); } template @@ -304,10 +321,14 @@ namespace bitsery { auto& ctx = details_pointer::getLinkingContext(des); ctx.processObserverPtr(id, reinterpret_cast(obj)); } else { - obj = nullptr; + if (_ptrType == PointerType::Nullable) + obj = nullptr; + else + r.setError(ReaderError::InvalidPointer); } } - + private: + PointerType _ptrType; }; class ReferencedByPointer { diff --git a/tests/serialization_ext_pointer.cpp b/tests/serialization_ext_pointer.cpp index 35a8179..3810844 100644 --- a/tests/serialization_ext_pointer.cpp +++ b/tests/serialization_ext_pointer.cpp @@ -28,6 +28,7 @@ using bitsery::ext::PointerOwner; using bitsery::ext::PointerObserver; using bitsery::ext::ReferencedByPointer; using bitsery::ext::PointerLinkingContext; +using bitsery::ext::PointerType; using testing::Eq; @@ -145,6 +146,12 @@ TEST_F(SerializeExtensionPointerSerialization, WhenRererencedByPointerIsSameAsPo EXPECT_DEATH(ser1.ext2b(d1, ReferencedByPointer{}), ""); } +TEST_F(SerializeExtensionPointerSerialization, WhenNonNullPointerIsNullThenAssert) { + auto& ser1 = createSerializer(); + EXPECT_DEATH(ser1.ext2b(p1null, PointerOwner{PointerType::NotNull}), ""); + EXPECT_DEATH(ser1.ext2b(p1null, PointerObserver{PointerType::NotNull}), ""); +} + #endif TEST_F(SerializeExtensionPointerSerialization, WhenPointerObserverPointsToOwnerThenIsValid) { @@ -277,7 +284,7 @@ TEST_F(SerializeExtensionPointerDeserialization, ReferencedByPointer) { EXPECT_THAT(r3, Eq(d3)); } -TEST_F(SerializeExtensionPointerDeserialization, WhenReferencedByPointerReadsZeroPointerIdThenInvalidPointerError) { +TEST_F(SerializeExtensionPointerDeserialization, WhenReferencedByPointerReadsNullPointerThenInvalidPointerError) { auto& ser = createSerializer(); bitsery::details::writeSize(*sctx1.bw, 0u); ser.ext2b(d1, ReferencedByPointer{}); @@ -286,6 +293,18 @@ TEST_F(SerializeExtensionPointerDeserialization, WhenReferencedByPointerReadsZer EXPECT_THAT(sctx1.br->error(), Eq(bitsery::ReaderError::InvalidPointer)); } +TEST_F(SerializeExtensionPointerDeserialization, WhenNonNullPointerIsNullThenInvalidPointerError) { + createSerializer(); + bitsery::details::writeSize(*sctx1.bw, 0u); + auto& des1 = createDeserializer(); + des1.ext2b(p1null, PointerOwner{PointerType::NotNull}); + EXPECT_THAT(sctx1.br->error(), Eq(bitsery::ReaderError::InvalidPointer)); + + auto& des2 = createDeserializer(); + des2.ext2b(p1null, PointerObserver{PointerType::NotNull}); + EXPECT_THAT(sctx1.br->error(), Eq(bitsery::ReaderError::InvalidPointer)); +} + TEST_F(SerializeExtensionPointerDeserialization, PointerOwnerCreatesObjects) { auto& ser = createSerializer(); ser.ext2b(pd1, PointerOwner{});