diff --git a/src/lib/core/TLVUpdater.cpp b/src/lib/core/TLVUpdater.cpp index c1793919bc7258..7df01cbad7b4a6 100644 --- a/src/lib/core/TLVUpdater.cpp +++ b/src/lib/core/TLVUpdater.cpp @@ -98,6 +98,8 @@ CHIP_ERROR TLVUpdater::Init(TLVReader & aReader, uint32_t freeLen) mUpdaterReader.ImplicitProfileId = aReader.ImplicitProfileId; mUpdaterReader.AppData = aReader.AppData; + // TODO(#30825): Need to ensure we use TLVWriter public API rather than touch the innards. + // Initialize the internal writer object mUpdaterWriter.mBackingStore = nullptr; mUpdaterWriter.mBufStart = buf - readDataLen; @@ -109,7 +111,8 @@ CHIP_ERROR TLVUpdater::Init(TLVReader & aReader, uint32_t freeLen) mUpdaterWriter.SetContainerOpen(false); mUpdaterWriter.SetCloseContainerReserved(false); - mUpdaterWriter.ImplicitProfileId = aReader.ImplicitProfileId; + mUpdaterWriter.ImplicitProfileId = aReader.ImplicitProfileId; + mUpdaterWriter.mInitializationCookie = TLVWriter::kExpectedInitializationCookie; // Cache element start address for internal use mElementStartAddr = buf + freeLen; @@ -142,6 +145,8 @@ CHIP_ERROR TLVUpdater::Next() CHIP_ERROR TLVUpdater::Move() { + VerifyOrReturnError(mUpdaterWriter.IsInitialized(), CHIP_ERROR_INCORRECT_STATE); + const uint8_t * elementEnd; uint32_t copyLen; @@ -171,6 +176,8 @@ CHIP_ERROR TLVUpdater::Move() void TLVUpdater::MoveUntilEnd() { + VerifyOrDie(mUpdaterWriter.IsInitialized()); + const uint8_t * buffEnd = mUpdaterReader.GetReadPoint() + mUpdaterReader.GetRemainingLength(); uint32_t copyLen = static_cast(buffEnd - mElementStartAddr); @@ -178,6 +185,7 @@ void TLVUpdater::MoveUntilEnd() // Move all elements till end to output TLV memmove(mUpdaterWriter.mWritePoint, mElementStartAddr, copyLen); + // TODO(#30825): Need to ensure public API is used rather than touching the innards. // Adjust the updater state mElementStartAddr += copyLen; mUpdaterWriter.mWritePoint += copyLen; @@ -197,6 +205,8 @@ void TLVUpdater::MoveUntilEnd() CHIP_ERROR TLVUpdater::EnterContainer(TLVType & outerContainerType) { + VerifyOrReturnError(mUpdaterWriter.IsInitialized(), CHIP_ERROR_INCORRECT_STATE); + TLVType containerType; VerifyOrReturnError(TLVTypeIsContainer(static_cast(mUpdaterReader.mControlByte & kTLVTypeMask)), @@ -232,6 +242,8 @@ CHIP_ERROR TLVUpdater::ExitContainer(TLVType outerContainerType) */ void TLVUpdater::AdjustInternalWriterFreeSpace() { + VerifyOrDie(mUpdaterWriter.IsInitialized()); + const uint8_t * nextElementStart = mUpdaterReader.mReadPoint; if (nextElementStart != mElementStartAddr) diff --git a/src/lib/core/TLVWriter.cpp b/src/lib/core/TLVWriter.cpp index eb93e781524677..1ac6433d1761fe 100644 --- a/src/lib/core/TLVWriter.cpp +++ b/src/lib/core/TLVWriter.cpp @@ -44,30 +44,56 @@ #define NO_INLINE __attribute__((noinline)) #endif // DOXYGEN +// You can enable this block manually to abort on usage of uninitialized writers in +// your codebase. There are no such usages in the SDK (outside of tests). +#if 0 +#define ABORT_ON_UNINITIALIZED_IF_ENABLED() VerifyOrDie(IsInitialized() == true) +#else +#define ABORT_ON_UNINITIALIZED_IF_ENABLED() \ + do \ + { \ + } while (0) +#endif + namespace chip { namespace TLV { using namespace chip::Encoding; +TLVWriter::TLVWriter() : + ImplicitProfileId(kProfileIdNotSpecified), AppData(nullptr), mBackingStore(nullptr), mBufStart(nullptr), mWritePoint(nullptr), + mRemainingLen(0), mLenWritten(0), mMaxLen(0), mReservedSize(0), mContainerType(kTLVType_NotSpecified), mInitializationCookie(0), + mContainerOpen(false), mCloseContainerReserved(true) +{} + NO_INLINE void TLVWriter::Init(uint8_t * buf, size_t maxLen) { // TODO: Maybe we can just make mMaxLen, mLenWritten, mRemainingLen size_t instead? uint32_t actualMaxLen = maxLen > UINT32_MAX ? UINT32_MAX : static_cast(maxLen); + + // TODO(#30825): Need to ensure a single init path for this complex data. + mInitializationCookie = 0; mBackingStore = nullptr; - mBufStart = mWritePoint = buf; - mRemainingLen = actualMaxLen; - mLenWritten = 0; - mMaxLen = actualMaxLen; - mContainerType = kTLVType_NotSpecified; - mReservedSize = 0; + mBufStart = buf; + mWritePoint = buf; + mRemainingLen = actualMaxLen; + mLenWritten = 0; + mMaxLen = actualMaxLen; + mContainerType = kTLVType_NotSpecified; + mReservedSize = 0; SetContainerOpen(false); SetCloseContainerReserved(true); - ImplicitProfileId = kProfileIdNotSpecified; + ImplicitProfileId = kProfileIdNotSpecified; + mInitializationCookie = kExpectedInitializationCookie; } -CHIP_ERROR TLVWriter::Init(TLVBackingStore & backingStore, uint32_t maxLen) +CHIP_ERROR TLVWriter::Init(TLVBackingStore & backingStore, uint32_t maxLen /* = UINT32_MAX */) { + // TODO(#30825): Need to ensure a single init path for this complex data. + Init(nullptr, maxLen); + mInitializationCookie = 0; + mBackingStore = &backingStore; mBufStart = nullptr; mRemainingLen = 0; @@ -75,25 +101,30 @@ CHIP_ERROR TLVWriter::Init(TLVBackingStore & backingStore, uint32_t maxLen) if (err != CHIP_NO_ERROR) return err; - mWritePoint = mBufStart; - mLenWritten = 0; - mMaxLen = maxLen; - mContainerType = kTLVType_NotSpecified; - mReservedSize = 0; - SetContainerOpen(false); - SetCloseContainerReserved(true); - - ImplicitProfileId = kProfileIdNotSpecified; + mWritePoint = mBufStart; + mInitializationCookie = kExpectedInitializationCookie; return CHIP_NO_ERROR; } CHIP_ERROR TLVWriter::Finalize() { + ABORT_ON_UNINITIALIZED_IF_ENABLED(); + + VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE); + CHIP_ERROR err = CHIP_NO_ERROR; if (IsContainerOpen()) return CHIP_ERROR_TLV_CONTAINER_OPEN; if (mBackingStore != nullptr) err = mBackingStore->FinalizeBuffer(*this, mBufStart, static_cast(mWritePoint - mBufStart)); + + // TODO(#30825) The following should be safe, but in some cases (without mBackingStore), there are incremental writes that + // start failing. +#if 0 + if (err == CHIP_NO_ERROR) + mInitializationCookie = 0; +#endif + return err; } @@ -463,6 +494,9 @@ CHIP_ERROR TLVWriter::CopyElement(Tag tag, TLVReader & reader) CHIP_ERROR TLVWriter::OpenContainer(Tag tag, TLVType containerType, TLVWriter & containerWriter) { + ABORT_ON_UNINITIALIZED_IF_ENABLED(); + + VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE); CHIP_ERROR err = CHIP_NO_ERROR; VerifyOrReturnError(TLVTypeIsContainer(containerType), CHIP_ERROR_WRONG_TLV_TYPE); @@ -483,6 +517,7 @@ CHIP_ERROR TLVWriter::OpenContainer(Tag tag, TLVType containerType, TLVWriter & return err; } + // TODO(#30825): Clean-up this separate init path path. containerWriter.mBackingStore = mBackingStore; containerWriter.mBufStart = mBufStart; containerWriter.mWritePoint = mWritePoint; @@ -492,7 +527,8 @@ CHIP_ERROR TLVWriter::OpenContainer(Tag tag, TLVType containerType, TLVWriter & containerWriter.mContainerType = containerType; containerWriter.SetContainerOpen(false); containerWriter.SetCloseContainerReserved(IsCloseContainerReserved()); - containerWriter.ImplicitProfileId = ImplicitProfileId; + containerWriter.ImplicitProfileId = ImplicitProfileId; + containerWriter.mInitializationCookie = kExpectedInitializationCookie; SetContainerOpen(true); @@ -501,6 +537,10 @@ CHIP_ERROR TLVWriter::OpenContainer(Tag tag, TLVType containerType, TLVWriter & CHIP_ERROR TLVWriter::CloseContainer(TLVWriter & containerWriter) { + ABORT_ON_UNINITIALIZED_IF_ENABLED(); + + VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE); + if (!TLVTypeIsContainer(containerWriter.mContainerType)) return CHIP_ERROR_INCORRECT_STATE; @@ -526,6 +566,9 @@ CHIP_ERROR TLVWriter::CloseContainer(TLVWriter & containerWriter) CHIP_ERROR TLVWriter::StartContainer(Tag tag, TLVType containerType, TLVType & outerContainerType) { + ABORT_ON_UNINITIALIZED_IF_ENABLED(); + + VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE); CHIP_ERROR err = CHIP_NO_ERROR; VerifyOrReturnError(TLVTypeIsContainer(containerType), CHIP_ERROR_WRONG_TLV_TYPE); @@ -555,6 +598,10 @@ CHIP_ERROR TLVWriter::StartContainer(Tag tag, TLVType containerType, TLVType & o CHIP_ERROR TLVWriter::EndContainer(TLVType outerContainerType) { + ABORT_ON_UNINITIALIZED_IF_ENABLED(); + + VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE); + if (!TLVTypeIsContainer(mContainerType)) return CHIP_ERROR_INCORRECT_STATE; @@ -585,6 +632,10 @@ CHIP_ERROR TLVWriter::CopyContainer(TLVReader & container) CHIP_ERROR TLVWriter::CopyContainer(Tag tag, TLVReader & container) { + ABORT_ON_UNINITIALIZED_IF_ENABLED(); + + VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE); + // NOTE: This function MUST be used with a TVLReader that is reading from a contiguous buffer. if (container.mBackingStore != nullptr) return CHIP_ERROR_INVALID_ARGUMENT; @@ -611,6 +662,8 @@ CHIP_ERROR TLVWriter::CopyContainer(Tag tag, TLVReader & container) CHIP_ERROR TLVWriter::CopyContainer(Tag tag, const uint8_t * encodedContainer, uint16_t encodedContainerLen) { + VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE); + TLVReader reader; reader.Init(encodedContainer, encodedContainerLen); @@ -624,6 +677,9 @@ CHIP_ERROR TLVWriter::CopyContainer(Tag tag, const uint8_t * encodedContainer, u CHIP_ERROR TLVWriter::WriteElementHead(TLVElementType elemType, Tag tag, uint64_t lenOrVal) { + ABORT_ON_UNINITIALIZED_IF_ENABLED(); + + VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE); uint8_t * p; uint8_t stagingBuf[17]; // 17 = 1 control byte + 8 tag bytes + 8 length/value bytes @@ -742,6 +798,9 @@ CHIP_ERROR TLVWriter::WriteElementHead(TLVElementType elemType, Tag tag, uint64_ CHIP_ERROR TLVWriter::WriteElementWithData(TLVType type, Tag tag, const uint8_t * data, uint32_t dataLen) { + ABORT_ON_UNINITIALIZED_IF_ENABLED(); + + VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE); if (static_cast(type) & kTLVTypeSizeMask) { // We won't be able to recover this type properly! @@ -767,6 +826,9 @@ CHIP_ERROR TLVWriter::WriteElementWithData(TLVType type, Tag tag, const uint8_t CHIP_ERROR TLVWriter::WriteData(const uint8_t * p, uint32_t len) { + ABORT_ON_UNINITIALIZED_IF_ENABLED(); + + VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError((mLenWritten + len) <= mMaxLen, CHIP_ERROR_BUFFER_TOO_SMALL); while (len > 0) diff --git a/src/lib/core/TLVWriter.h b/src/lib/core/TLVWriter.h index 59478f15e7123c..eb38d5a28d9932 100644 --- a/src/lib/core/TLVWriter.h +++ b/src/lib/core/TLVWriter.h @@ -27,6 +27,8 @@ #pragma once +#include + #include "TLVCommon.h" #include "TLVBackingStore.h" @@ -61,6 +63,18 @@ class DLL_EXPORT TLVWriter friend class TLVUpdater; public: + TLVWriter(); + + // TODO(#30825): We do not cleanly handle copies for all backing stores, but we don't disallow copy... +#if 0 + // Disable copy (and move) semantics. + TLVWriter(const TLVWriter&) = delete; + TLVWriter& operator=(const TLVWriter&) = delete; +#endif + + // Initialization cookie that is set when properly initialized. Randomly-picked 16 bit value. + static constexpr uint16_t kExpectedInitializationCookie = 0x52b1; + /** * Initializes a TLVWriter object to write into a single output buffer. * @@ -115,6 +129,7 @@ class DLL_EXPORT TLVWriter * (See @p OpenContainer()). * * @retval #CHIP_NO_ERROR If the encoding was finalized successfully. + * @retval #CHIP_ERROR_INCORRECT_STATE If the TLVWriter was not initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If a container writer has been opened on the current writer and not * yet closed. @@ -127,10 +142,12 @@ class DLL_EXPORT TLVWriter * Reserve some buffer for encoding future fields. * * @retval #CHIP_NO_ERROR Successfully reserved required buffer size. + * @retval #CHIP_ERROR_INCORRECT_STATE If the TLVWriter was not initialized. * @retval #CHIP_ERROR_NO_MEMORY The reserved buffer size cannot fits into the remaining buffer size. */ CHIP_ERROR ReserveBuffer(uint32_t aBufferSize) { + VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(mRemainingLen >= aBufferSize, CHIP_ERROR_NO_MEMORY); mReservedSize += aBufferSize; mRemainingLen -= aBufferSize; @@ -141,10 +158,12 @@ class DLL_EXPORT TLVWriter * Release previously reserved buffer. * * @retval #CHIP_NO_ERROR Successfully released reserved buffer size. + * @retval #CHIP_ERROR_INCORRECT_STATE If the TLVWriter was not initialized. * @retval #CHIP_ERROR_NO_MEMORY The released buffer is larger than previously reserved buffer size. */ CHIP_ERROR UnreserveBuffer(uint32_t aBufferSize) { + VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(mReservedSize >= aBufferSize, CHIP_ERROR_NO_MEMORY); mReservedSize -= aBufferSize; mRemainingLen += aBufferSize; @@ -161,6 +180,7 @@ class DLL_EXPORT TLVWriter * @param[in] v The value to be encoded. * * @retval #CHIP_NO_ERROR If the method succeeded. + * @retval #CHIP_ERROR_INCORRECT_STATE If the TLVWriter was not initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If a container writer has been opened on the current writer and not * yet closed. @@ -193,6 +213,7 @@ class DLL_EXPORT TLVWriter * are strongly encouraged to set this parameter to false. * * @retval #CHIP_NO_ERROR If the method succeeded. + * @retval #CHIP_ERROR_INCORRECT_STATE If the TLVWriter was not initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If a container writer has been opened on the current writer and not * yet closed. @@ -251,6 +272,7 @@ class DLL_EXPORT TLVWriter * @param[in] v The value to be encoded. * * @retval #CHIP_NO_ERROR If the method succeeded. + * @retval #CHIP_ERROR_INCORRECT_STATE If the TLVWriter was not initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If a container writer has been opened on the current writer and not * yet closed. @@ -341,6 +363,7 @@ class DLL_EXPORT TLVWriter * @param[in] v The value to be encoded. * * @retval #CHIP_NO_ERROR If the method succeeded. + * @retval #CHIP_ERROR_INCORRECT_STATE If the TLVWriter was not initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If a container writer has been opened on the current writer and not * yet closed. @@ -374,6 +397,7 @@ class DLL_EXPORT TLVWriter * @param[in] data A ByteSpan object containing the bytes string to be encoded. * * @retval #CHIP_NO_ERROR If the method succeeded. + * @retval #CHIP_ERROR_INCORRECT_STATE If the TLVWriter was not initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If a container writer has been opened on the current writer and not * yet closed. @@ -431,6 +455,7 @@ class DLL_EXPORT TLVWriter * @param[in] v The value to be encoded. * * @retval #CHIP_NO_ERROR If the method succeeded. + * @retval #CHIP_ERROR_INCORRECT_STATE If the TLVWriter was not initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If a container writer has been opened on the current writer and not * yet closed. @@ -472,6 +497,7 @@ class DLL_EXPORT TLVWriter * @param[in] len The number of bytes to be encoded. * * @retval #CHIP_NO_ERROR If the method succeeded. + * @retval #CHIP_ERROR_INCORRECT_STATE If the TLVWriter was not initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If a container writer has been opened on the current writer and not * yet closed. @@ -500,6 +526,7 @@ class DLL_EXPORT TLVWriter * @param[in] buf A pointer to the null-terminated UTF-8 string to be encoded. * * @retval #CHIP_NO_ERROR If the method succeeded. + * @retval #CHIP_ERROR_INCORRECT_STATE If the TLVWriter was not initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If a container writer has been opened on the current writer and not * yet closed. @@ -529,6 +556,7 @@ class DLL_EXPORT TLVWriter * @param[in] len The length (in bytes) of the string to be encoded. * * @retval #CHIP_NO_ERROR If the method succeeded. + * @retval #CHIP_ERROR_INCORRECT_STATE If the TLVWriter was not initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If a container writer has been opened on the current writer and not * yet closed. @@ -557,6 +585,7 @@ class DLL_EXPORT TLVWriter * @param[in] str A Span containing a pointer and a length of the string to be encoded. * * @retval #CHIP_NO_ERROR If the method succeeded. + * @retval #CHIP_ERROR_INCORRECT_STATE If the TLVWriter was not initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If a container writer has been opened on the current writer and not * yet closed. @@ -680,6 +709,7 @@ class DLL_EXPORT TLVWriter * ContextTag() or CommonTag(). * * @retval #CHIP_NO_ERROR If the method succeeded. + * @retval #CHIP_ERROR_INCORRECT_STATE If the TLVWriter was not initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If a container writer has been opened on the current writer and not * yet closed. @@ -716,7 +746,7 @@ class DLL_EXPORT TLVWriter * * @retval #CHIP_NO_ERROR If the method succeeded. * @retval #CHIP_ERROR_INCORRECT_STATE - * If the supplied reader is not positioned on an element. + * If the supplied reader is not positioned on an element or if the writer is not initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If a container writer has been opened on the current writer and not * yet closed. @@ -765,7 +795,7 @@ class DLL_EXPORT TLVWriter * * @retval #CHIP_NO_ERROR If the method succeeded. * @retval #CHIP_ERROR_INCORRECT_STATE - * If the supplied reader is not positioned on an element. + * If the supplied reader is not positioned on an element or if the writer is not initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If a container writer has been opened on the current writer and not * yet closed. @@ -815,6 +845,7 @@ class DLL_EXPORT TLVWriter * writer. * * @retval #CHIP_NO_ERROR If the method succeeded. + * @retval #CHIP_ERROR_INCORRECT_STATE If the TLVWriter was not initialized. * @retval #CHIP_ERROR_WRONG_TLV_TYPE * If the value specified for containerType is incorrect. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN @@ -855,7 +886,7 @@ class DLL_EXPORT TLVWriter * * @retval #CHIP_NO_ERROR If the method succeeded. * @retval #CHIP_ERROR_INCORRECT_STATE - * If a corresponding StartContainer() call was not made. + * If a corresponding StartContainer() call was not made or if the TLVWriter is not initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If a container writer has been opened on the current writer and not * yet closed. @@ -903,6 +934,7 @@ class DLL_EXPORT TLVWriter * associated with the supplied object is overwritten. * * @retval #CHIP_NO_ERROR If the method succeeded. + * @retval #CHIP_ERROR_INCORRECT_STATE If the TLVWriter was not initialized. * @retval #CHIP_ERROR_WRONG_TLV_TYPE * If the value specified for containerType is incorrect. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN @@ -940,7 +972,8 @@ class DLL_EXPORT TLVWriter * * @retval #CHIP_NO_ERROR If the method succeeded. * @retval #CHIP_ERROR_INCORRECT_STATE - * If the supplied container writer is not in the correct state. + * If the supplied container writer is not in the correct state or if the TLVWriter is not + * initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If another container writer has been opened on the supplied * container writer and not yet closed. @@ -979,6 +1012,7 @@ class DLL_EXPORT TLVWriter * @param[in] dataLen The number of bytes in the @p data buffer. * * @retval #CHIP_NO_ERROR If the method succeeded. + * @retval #CHIP_ERROR_INCORRECT_STATE If the TLVWriter was not initialized. * @retval #CHIP_ERROR_WRONG_TLV_TYPE * If the value specified for containerType is incorrect. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN @@ -1018,7 +1052,8 @@ class DLL_EXPORT TLVWriter * @retval #CHIP_ERROR_INVALID_ARGUMENT * If the supplied reader uses a TLVBackingStore rather than a simple buffer. * @retval #CHIP_ERROR_INCORRECT_STATE - * If the supplied reader is not positioned on a container element. + * If the supplied reader is not positioned on a container element or if the TLVWriter was not + * initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If a container writer has been opened on the current writer and not * yet closed. @@ -1070,7 +1105,8 @@ class DLL_EXPORT TLVWriter * @retval #CHIP_ERROR_INVALID_ARGUMENT * If the supplied reader uses a TLVBackingStore rather than a simple buffer. * @retval #CHIP_ERROR_INCORRECT_STATE - * If the supplied reader is not positioned on a container element. + * If the supplied reader is not positioned on a container element or of the TLVWriter was not + * initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If a container writer has been opened on the current writer and not * yet closed. @@ -1117,6 +1153,7 @@ class DLL_EXPORT TLVWriter * @param[in] encodedContainerLen The length in bytes of the pre-encoded container. * * @retval #CHIP_NO_ERROR If the method succeeded. + * @retval #CHIP_ERROR_INCORRECT_STATE If the TLVWriter was not initialized. * @retval #CHIP_ERROR_TLV_CONTAINER_OPEN * If a container writer has been opened on the current writer and not * yet closed. @@ -1165,6 +1202,12 @@ class DLL_EXPORT TLVWriter * @return the total remaining number of bytes. */ uint32_t GetRemainingFreeLength() const { return mRemainingLen; } + + /** + * @brief Returns true if this TLVWriter was properly initialized. + */ + bool IsInitialized() const { return mInitializationCookie == kExpectedInitializationCookie; } + /** * The profile id of tags that should be encoded in implicit form. * @@ -1197,6 +1240,7 @@ class DLL_EXPORT TLVWriter uint32_t mMaxLen; uint32_t mReservedSize; TLVType mContainerType; + uint16_t mInitializationCookie; private: bool mContainerOpen; diff --git a/src/lib/core/tests/TestTLV.cpp b/src/lib/core/tests/TestTLV.cpp index 9478a9186e6ce2..fce0a5d17ae484 100644 --- a/src/lib/core/tests/TestTLV.cpp +++ b/src/lib/core/tests/TestTLV.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -4646,6 +4647,281 @@ static void CheckTLVScopedBuffer(nlTestSuite * inSuite, void * inContext) } } +static void TestUninitializedWriter(nlTestSuite * inSuite, void * inContext) +{ + { + TLVWriter writer; + NL_TEST_ASSERT(inSuite, !writer.IsInitialized()); + } + + { + TLVWriter writer; + NL_TEST_ASSERT(inSuite, writer.Finalize() == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + NL_TEST_ASSERT(inSuite, writer.ReserveBuffer(123) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + NL_TEST_ASSERT(inSuite, writer.UnreserveBuffer(123) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + uint8_t v = 3; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + int8_t v = 3; + bool preserveSize = true; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v, preserveSize) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + int16_t v = 3; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + int16_t v = 3; + bool preserveSize = true; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v, preserveSize) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + int32_t v = 3; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + int32_t v = 3; + bool preserveSize = true; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v, preserveSize) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + int64_t v = 3; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + int64_t v = 3; + bool preserveSize = true; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v, preserveSize) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + uint8_t v = 3; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + uint8_t v = 3; + bool preserveSize = true; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v, preserveSize) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + uint16_t v = 3; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + uint16_t v = 3; + bool preserveSize = true; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v, preserveSize) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + uint32_t v = 3; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + uint32_t v = 3; + bool preserveSize = true; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v, preserveSize) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + uint64_t v = 3; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + uint64_t v = 3; + bool preserveSize = true; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v, preserveSize) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + double v = 1.23; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + float v = 1.23f; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + bool v = true; + NL_TEST_ASSERT(inSuite, writer.PutBoolean(ContextTag(1), v) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + bool v = true; + NL_TEST_ASSERT(inSuite, writer.Put(ContextTag(1), v) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + const uint8_t buf[] = { 1, 2, 3 }; + NL_TEST_ASSERT(inSuite, + writer.PutBytes(ContextTag(1), buf, static_cast(sizeof(buf))) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + const char * buf = "abc"; + NL_TEST_ASSERT(inSuite, writer.PutString(ContextTag(1), buf) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + const char * buf = "abc"; + NL_TEST_ASSERT(inSuite, + writer.PutString(ContextTag(1), buf, static_cast(strlen(buf))) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + CharSpan str = "abc"_span; + NL_TEST_ASSERT(inSuite, writer.PutString(ContextTag(1), str) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + NL_TEST_ASSERT(inSuite, writer.PutStringF(ContextTag(1), "%d", 1) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + NL_TEST_ASSERT(inSuite, writer.PutNull(ContextTag(1)) == CHIP_ERROR_INCORRECT_STATE); + } + + { + const uint8_t buf[]{ 0, 0, 0 }; + TLVReader reader; + reader.Init(buf); + + TLVWriter writer; + NL_TEST_ASSERT(inSuite, writer.CopyElement(reader) == CHIP_ERROR_INCORRECT_STATE); + } + + { + const uint8_t buf[]{ 0, 0, 0 }; + TLVReader reader; + reader.Init(buf); + + TLVWriter writer; + NL_TEST_ASSERT(inSuite, writer.CopyElement(ContextTag(1), reader) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + TLVType outerContainerType; + + NL_TEST_ASSERT(inSuite, + writer.StartContainer(ContextTag(1), TLVType::kTLVType_Structure, outerContainerType) == + CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter writer; + TLVType outerContainerType = TLVType::kTLVType_Structure; + NL_TEST_ASSERT(inSuite, writer.EndContainer(outerContainerType) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter innerWriter; + uint8_t buf[]{ 0, 0, 0 }; + innerWriter.Init(buf); + NL_TEST_ASSERT(inSuite, innerWriter.IsInitialized()); + + TLVWriter writer; + NL_TEST_ASSERT(inSuite, + writer.OpenContainer(ContextTag(1), TLVType::kTLVType_Structure, innerWriter) == CHIP_ERROR_INCORRECT_STATE); + } + + { + TLVWriter innerWriter; + uint8_t buf[]{ 0, 0, 0 }; + innerWriter.Init(buf); + NL_TEST_ASSERT(inSuite, innerWriter.IsInitialized()); + + TLVWriter writer; + NL_TEST_ASSERT(inSuite, writer.CloseContainer(innerWriter) == CHIP_ERROR_INCORRECT_STATE); + } + + { + uint8_t buf[]{ 0, 0, 0 }; + TLVWriter writer; + NL_TEST_ASSERT(inSuite, + writer.PutPreEncodedContainer(ContextTag(1), TLVType::kTLVType_Structure, buf, + static_cast(sizeof(buf))) == CHIP_ERROR_INCORRECT_STATE); + } + + { + const uint8_t buf[]{ 0, 0, 0 }; + TLVReader reader; + reader.Init(buf); + + TLVWriter writer; + NL_TEST_ASSERT(inSuite, writer.CopyContainer(reader) == CHIP_ERROR_INCORRECT_STATE); + } + + { + const uint8_t buf[]{ 0, 0, 0 }; + TLVReader reader; + reader.Init(buf); + + TLVWriter writer; + NL_TEST_ASSERT(inSuite, writer.CopyContainer(ContextTag(1), reader) == CHIP_ERROR_INCORRECT_STATE); + } + + { + uint8_t buf[]{ 0, 0, 0 }; + + TLVWriter writer; + NL_TEST_ASSERT(inSuite, + writer.CopyContainer(ContextTag(1), buf, static_cast(sizeof(buf))) == CHIP_ERROR_INCORRECT_STATE); + } +} + // Test Suite /** @@ -4684,6 +4960,7 @@ static const nlTest sTests[] = NL_TEST_DEF("CHIP TLV GetStringView Test", CheckGetStringView), NL_TEST_DEF("CHIP TLV GetByteView Test", CheckGetByteView), NL_TEST_DEF("Int Min/Max Test", TestIntMinMax), + NL_TEST_DEF("Uninitialized Writer Test", TestUninitializedWriter), NL_TEST_SENTINEL() };