Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TLVReader: Add test for Expect() and handle corner case better #30188

Merged
merged 2 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions src/credentials/CertificationDeclaration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,15 +336,10 @@ CHIP_ERROR CertificationElementsDecoder::FindAndEnterArray(const ByteSpan & enco
ReturnErrorOnFailure(mReader.EnterContainer(outerContainerType1));

// position to arrayTag Array
CHIP_ERROR error = CHIP_NO_ERROR;
do
{
error = mReader.Next(kTLVType_Array, arrayTag);
// Return error code unless one of three things happened:
// 1. We found the right thing (CHIP_NO_ERROR returned).
// 2. The next tag is not the one we are looking for (CHIP_ERROR_UNEXPECTED_TLV_ELEMENT).
VerifyOrReturnError(error == CHIP_NO_ERROR || error == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT, error);
} while (error != CHIP_NO_ERROR);
ReturnErrorOnFailure(mReader.Next());
} while (mReader.Expect(kTLVType_Array, arrayTag) != CHIP_NO_ERROR);

ReturnErrorOnFailure(mReader.EnterContainer(outerContainerType2));

Expand Down
5 changes: 3 additions & 2 deletions src/lib/core/TLVReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,8 @@ CHIP_ERROR TLVReader::Next()

CHIP_ERROR TLVReader::Expect(Tag expectedTag)
{
VerifyOrReturnError(mElemTag == expectedTag, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
VerifyOrReturnError(GetType() != kTLVType_NotSpecified, CHIP_ERROR_WRONG_TLV_TYPE);
VerifyOrReturnError(GetTag() == expectedTag, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
return CHIP_NO_ERROR;
}

Expand All @@ -598,8 +599,8 @@ CHIP_ERROR TLVReader::Next(Tag expectedTag)

CHIP_ERROR TLVReader::Expect(TLVType expectedType, Tag expectedTag)
{
ReturnErrorOnFailure(Expect(expectedTag));
VerifyOrReturnError(GetType() == expectedType, CHIP_ERROR_WRONG_TLV_TYPE);
VerifyOrReturnError(GetTag() == expectedTag, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
return CHIP_NO_ERROR;
}

Expand Down
11 changes: 9 additions & 2 deletions src/lib/core/TLVReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,10 @@ class DLL_EXPORT TLVReader
* Advances the TLVReader object to the next TLV element to be read, asserting the tag of
* the new element.
*
* This is a convenience method that combines the behavior of Next() and Expect().
* This is a convenience method that combines the behavior of Next() and Expect(...).
*
* Note that if this method returns an error, the reader may or may not have been advanced already.
* In use cases where this is important, separate calls to Next() and Expect(...) should be made.
*
* @retval #CHIP_NO_ERROR If the reader was successfully positioned on a new element
* matching the expected parameters.
Expand All @@ -179,6 +182,7 @@ class DLL_EXPORT TLVReader
* Checks that the TLV reader is positioned at an element with the expected tag.
*
* @retval #CHIP_NO_ERROR If the reader is positioned on the expected element.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the reader is not positioned on an element.
* @retval #CHIP_ERROR_UNEXPECTED_TLV_ELEMENT
* If the tag associated with the new element does not match the
* value of the @p expectedTag argument.
Expand All @@ -189,7 +193,10 @@ class DLL_EXPORT TLVReader
* Advances the TLVReader object to the next TLV element to be read, asserting the type and tag of
* the new element.
*
* This is a convenience method that combines the behavior of Next() and Expect().
* This is a convenience method that combines the behavior of Next() and Expect(...).
*
* Note that if this method returns an error, the reader may or may not have been advanced already.
* In use cases where this is important, separate calls to Next() and Expect(...) should be made.
*
* @retval #CHIP_NO_ERROR If the reader was successfully positioned on a new element
* matching the expected parameters.
Expand Down
55 changes: 55 additions & 0 deletions src/lib/core/tests/TestTLV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3628,6 +3628,59 @@ void TestTLVReaderErrorHandling(nlTestSuite * inSuite)
chip::Platform::MemoryFree(const_cast<uint8_t *>(data));
}

void TestTLVReaderExpect(nlTestSuite * inSuite)
{
// Prepare some test data
uint8_t buffer[20];
TLVWriter writer;
writer.Init(buffer, sizeof(buffer));
TLVType outerContainer;
NL_TEST_ASSERT_SUCCESS(inSuite, writer.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainer));
NL_TEST_ASSERT_SUCCESS(inSuite, writer.PutBoolean(ContextTag(23), false));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest adding a test case for profile specific tags as well

NL_TEST_ASSERT_SUCCESS(inSuite, writer.EndContainer(outerContainer));

TLVReader reader;
reader.Init(buffer, writer.GetLengthWritten());

// Positioned before the first element
NL_TEST_ASSERT(inSuite, reader.GetType() == kTLVType_NotSpecified);

NL_TEST_ASSERT(inSuite, reader.Expect(AnonymousTag()) == CHIP_ERROR_WRONG_TLV_TYPE);
NL_TEST_ASSERT(inSuite, reader.Expect(ContextTag(23)) == CHIP_ERROR_WRONG_TLV_TYPE);
NL_TEST_ASSERT(inSuite, reader.Expect(kTLVType_Boolean, AnonymousTag()) == CHIP_ERROR_WRONG_TLV_TYPE);

// Positioned on kTLVType_Structure / AnonymousTag(),
NL_TEST_ASSERT_SUCCESS(inSuite, reader.Next());
NL_TEST_ASSERT(inSuite, reader.GetType() == kTLVType_Structure);
NL_TEST_ASSERT(inSuite, reader.GetTag() == AnonymousTag());

NL_TEST_ASSERT(inSuite, reader.Expect(ContextTag(23)) == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
NL_TEST_ASSERT_SUCCESS(inSuite, reader.Expect(AnonymousTag()));

NL_TEST_ASSERT(inSuite, reader.Expect(kTLVType_SignedInteger, AnonymousTag()) == CHIP_ERROR_WRONG_TLV_TYPE);
NL_TEST_ASSERT_SUCCESS(inSuite, reader.Expect(kTLVType_Structure, AnonymousTag()));

// Positioned before first struct element
NL_TEST_ASSERT_SUCCESS(inSuite, reader.EnterContainer(outerContainer));
NL_TEST_ASSERT(inSuite, reader.GetType() == kTLVType_NotSpecified);

NL_TEST_ASSERT(inSuite, reader.Expect(AnonymousTag()) == CHIP_ERROR_WRONG_TLV_TYPE);
NL_TEST_ASSERT(inSuite, reader.Expect(ContextTag(23)) == CHIP_ERROR_WRONG_TLV_TYPE);
NL_TEST_ASSERT(inSuite, reader.Expect(kTLVType_Boolean, AnonymousTag()) == CHIP_ERROR_WRONG_TLV_TYPE);

// Positioned on kTLVType_Boolean / ContextTag(23)
NL_TEST_ASSERT_SUCCESS(inSuite, reader.Next());
NL_TEST_ASSERT(inSuite, reader.GetType() == kTLVType_Boolean);
NL_TEST_ASSERT(inSuite, reader.GetTag() == ContextTag(23));

NL_TEST_ASSERT(inSuite, reader.Expect(AnonymousTag()) == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
NL_TEST_ASSERT(inSuite, reader.Expect(ContextTag(42)) == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
NL_TEST_ASSERT_SUCCESS(inSuite, reader.Expect(ContextTag(23)));

NL_TEST_ASSERT(inSuite, reader.Expect(kTLVType_SignedInteger, ContextTag(23)) == CHIP_ERROR_WRONG_TLV_TYPE);
NL_TEST_ASSERT_SUCCESS(inSuite, reader.Expect(kTLVType_Boolean, ContextTag(23)));
}

/**
* Test that CHIP TLV reader returns an error when a read is requested that
* would truncate the output.
Expand Down Expand Up @@ -3789,6 +3842,8 @@ void CheckTLVReader(nlTestSuite * inSuite, void * inContext)

TestTLVReaderErrorHandling(inSuite);

TestTLVReaderExpect(inSuite);

TestTLVReaderTruncatedReads(inSuite);

TestTLVReaderInPractice(inSuite);
Expand Down
Loading