From e616b656276c18e4c859245a1cb3f367da69e123 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 11 Aug 2024 19:44:53 +0200 Subject: [PATCH] More tests for PB, some bug fixes --- src/tl/tl/tlProtocolBuffer.cc | 22 ++- src/tl/unit_tests/tlProtocolBufferTests.cc | 210 ++++++++++++++++++--- testdata/pb/struct1.pb | Bin 0 -> 149 bytes testdata/pb/struct2_invalid_header.pb | Bin 0 -> 147 bytes testdata/pb/struct3_invalid_header.pb | Bin 0 -> 149 bytes testdata/pb/struct4_deviations.pb | Bin 0 -> 184 bytes testdata/pb/struct5_overflow.pb | 2 + testdata/pb/struct6_invalid_type.pb | Bin 0 -> 20 bytes testdata/pb/struct7_invalid_type.pb | Bin 0 -> 16 bytes testdata/pb/struct8_invalid_type.pb | 2 + 10 files changed, 199 insertions(+), 37 deletions(-) create mode 100644 testdata/pb/struct1.pb create mode 100644 testdata/pb/struct2_invalid_header.pb create mode 100644 testdata/pb/struct3_invalid_header.pb create mode 100644 testdata/pb/struct4_deviations.pb create mode 100644 testdata/pb/struct5_overflow.pb create mode 100644 testdata/pb/struct6_invalid_type.pb create mode 100644 testdata/pb/struct7_invalid_type.pb create mode 100644 testdata/pb/struct8_invalid_type.pb diff --git a/src/tl/tl/tlProtocolBuffer.cc b/src/tl/tl/tlProtocolBuffer.cc index b12b8f761..126b0ffdf 100644 --- a/src/tl/tl/tlProtocolBuffer.cc +++ b/src/tl/tl/tlProtocolBuffer.cc @@ -63,8 +63,7 @@ ProtocolBufferReader::skip () } else if (m_type == PB_LEN) { - size_t value = 0; - read (value); + size_t value = read_varint (); skip_bytes (value); } @@ -93,8 +92,7 @@ ProtocolBufferReader::read (std::string &s) error (tl::to_string (tr ("Expected a LEN wire type for a string"))); } - size_t value = 0; - read (value); + size_t value = read_varint (); s = std::string (); s.reserve (value); @@ -110,7 +108,7 @@ ProtocolBufferReader::read (std::string &s) void ProtocolBufferReader::read (uint32_t &ui32) { - if (m_type == PB_VARINT || m_type == PB_LEN) { + if (m_type == PB_VARINT) { pb_varint ui64 = read_varint (); if (ui64 > std::numeric_limits::max ()) { @@ -153,7 +151,7 @@ ProtocolBufferReader::read (int32_t &i32) void ProtocolBufferReader::read (uint64_t &ui64) { - if (m_type == PB_VARINT || m_type == PB_LEN) { + if (m_type == PB_VARINT) { ui64 = read_varint (); @@ -203,8 +201,7 @@ ProtocolBufferReader::open () error (tl::to_string (tr ("Expected a LEN wire type for a submessage"))); } - size_t value = 0; - read (value); + size_t value = read_varint (); if (! m_seq_counts.empty ()) { // take out the following bytes from the current sequence m_seq_counts.back () -= value; @@ -284,6 +281,15 @@ ProtocolBufferReader::read_varint () void ProtocolBufferReader::skip_bytes (size_t n) { + m_pos_before = m_pos; + m_pos += n; + if (! m_seq_counts.empty ()) { + if (m_seq_counts.back () < n) { + error (tl::to_string (tr ("sequence underflow"))); + } + m_seq_counts.back () -= n; + } + const size_t chunk_size = 1024; while (n > 0) { size_t l = std::min (chunk_size, n); diff --git a/src/tl/unit_tests/tlProtocolBufferTests.cc b/src/tl/unit_tests/tlProtocolBufferTests.cc index cf413878e..68ea64f06 100644 --- a/src/tl/unit_tests/tlProtocolBufferTests.cc +++ b/src/tl/unit_tests/tlProtocolBufferTests.cc @@ -205,28 +205,26 @@ struct Root { const Child &get_child () const { return m_child; } }; -TEST (100_BasicStruct) +static tl::PBElementList child_struct = + tl::pb_make_member (&Child::txt, 1) + + tl::pb_make_member (&Child::d, 2) + + tl::pb_make_element (&Child::begin_children, &Child::end_children, &Child::add_child, 3, &child_struct); + +static tl::PBStruct structure ("pbtest-struct", 88888888, + tl::pb_make_member (&Root::begin_subs, &Root::end_subs, &Root::add_sub, 1) + + tl::pb_make_member (&Root::begin_isubs, &Root::end_isubs, &Root::add_isub, 2) + + tl::pb_make_element (&Root::begin_children, &Root::end_children, &Root::add_child, 3, &child_struct) + + tl::pb_make_element (&Root::get_child, &Root::set_child, 4, + tl::pb_make_member (&Child::txt, 1) + + tl::pb_make_member (&Child::d, 2) + ) + + tl::pb_make_member (&Root::m, 5) + + tl::pb_make_member (&Root::get_mi, &Root::set_mi, 6) + + tl::pb_make_member (&Root::b, 7) +); + +static void build_struct (Root &root) { - Root root; - - tl::PBElementList child_struct = - tl::pb_make_member (&Child::txt, 1) + - tl::pb_make_member (&Child::d, 2) + - tl::pb_make_element (&Child::begin_children, &Child::end_children, &Child::add_child, 3, &child_struct); - - tl::PBStruct structure ("pbtest-struct", 88888888, - tl::pb_make_member (&Root::begin_subs, &Root::end_subs, &Root::add_sub, 1) + - tl::pb_make_member (&Root::begin_isubs, &Root::end_isubs, &Root::add_isub, 2) + - tl::pb_make_element (&Root::begin_children, &Root::end_children, &Root::add_child, 3, &child_struct) + - tl::pb_make_element (&Root::get_child, &Root::set_child, 4, - tl::pb_make_member (&Child::txt, 1) + - tl::pb_make_member (&Child::d, 2) - ) + - tl::pb_make_member (&Root::m, 5) + - tl::pb_make_member (&Root::get_mi, &Root::set_mi, 6) + - tl::pb_make_member (&Root::b, 7) - ); - root.add_sub (0.5); root.add_sub (7.5); root.add_isub (420000000); @@ -264,6 +262,12 @@ TEST (100_BasicStruct) sc.txt = "single"; sc.d = 4.2e6; root.set_child (sc); +} + +TEST (100_BasicStruct) +{ + Root root; + build_struct (root); std::string fn = tl::combine_path (tl::testtmp (), "pb_test.pb"); @@ -405,21 +409,21 @@ struct TestClassEnumConverter } }; +tl::PBStruct tc_structure ("pbtest-tc", 1, + tl::pb_make_member (&TestClass::e, 2, TestClassEnumConverter ()) +); + TEST (101_Converter) { TestClass tc; - tl::PBStruct structure ("pbtest-tc", 1, - tl::pb_make_member (&TestClass::e, 2, TestClassEnumConverter ()) - ); - tc.e = TestClass::A; std::string fn = tl::combine_path (tl::testtmp (), "pb_101a.pb"); { tl::OutputStream os (fn); tl::ProtocolBufferWriter writer (os); - structure.write (writer, tc); + tc_structure.write (writer, tc); } tc = TestClass (); @@ -428,7 +432,7 @@ TEST (101_Converter) try { tl::InputStream is (fn); tl::ProtocolBufferReader reader (is); - structure.parse (reader, tc); + tc_structure.parse (reader, tc); } catch (tl::Exception &ex) { error = ex.msg (); } @@ -442,7 +446,7 @@ TEST (101_Converter) { tl::OutputStream os (fn); tl::ProtocolBufferWriter writer (os); - structure.write (writer, tc); + tc_structure.write (writer, tc); } tc = TestClass (); @@ -451,7 +455,7 @@ TEST (101_Converter) try { tl::InputStream is (fn); tl::ProtocolBufferReader reader (is); - structure.parse (reader, tc); + tc_structure.parse (reader, tc); } catch (tl::Exception &ex) { error = ex.msg (); } @@ -459,3 +463,151 @@ TEST (101_Converter) EXPECT_EQ (tc.e, TestClass::B); } +TEST (101_ExternalFiles) +{ + Root root_au; + build_struct (root_au); + + std::string fn = tl::combine_path (tl::testsrc (), "testdata/pb/struct1.pb"); + + Root root; + std::string error; + try { + tl::InputStream is (fn); + tl::ProtocolBufferReader reader (is); + structure.parse (reader, root); + } catch (tl::Exception &ex) { + error = ex.msg (); + } + + EXPECT_EQ (error, ""); + EXPECT_EQ (root == root_au, true); +} + +TEST (102_InvalidHeader) +{ + std::string fn = tl::combine_path (tl::testsrc (), "testdata/pb/struct2_invalid_header.pb"); + + Root root; + std::string error; + try { + tl::InputStream is (fn); + tl::ProtocolBufferReader reader (is); + structure.parse (reader, root); + } catch (tl::Exception &ex) { + error = ex.msg (); + } + + EXPECT_EQ (std::string (error, 0, 49), "Expected header field with ID 88888888 (got 4444)"); +} + +TEST (103_InvalidHeader) +{ + std::string fn = tl::combine_path (tl::testsrc (), "testdata/pb/struct3_invalid_header.pb"); + + Root root; + std::string error; + try { + tl::InputStream is (fn); + tl::ProtocolBufferReader reader (is); + structure.parse (reader, root); + } catch (tl::Exception &ex) { + error = ex.msg (); + } + + EXPECT_EQ (std::string (error, 0, 71), "Expected header field with string 'pbtest-struct' (got 'xxxxxxxxxxxxx')"); +} + +// "last one wins", unknown IDs are skipped +TEST (104_Deviations) +{ + Root root_au; + build_struct (root_au); + + std::string fn = tl::combine_path (tl::testsrc (), "testdata/pb/struct4_deviations.pb"); + + Root root; + std::string error; + try { + tl::InputStream is (fn); + tl::ProtocolBufferReader reader (is); + structure.parse (reader, root); + } catch (tl::Exception &ex) { + error = ex.msg (); + } + + EXPECT_EQ (error, ""); + EXPECT_EQ (root == root_au, true); +} + +TEST (105_Int32Overflow) +{ + std::string fn = tl::combine_path (tl::testsrc (), "testdata/pb/struct5_overflow.pb"); + + TestClass tc; + std::string error; + try { + tl::InputStream is (fn); + tl::ProtocolBufferReader reader (is); + tc_structure.parse (reader, tc); + } catch (tl::Exception &ex) { + error = ex.msg (); + } + + EXPECT_EQ (std::string (error, 0, 21), "32 bit value overflow"); +} + +TEST (106_InvalidType) +{ + std::string fn = tl::combine_path (tl::testsrc (), "testdata/pb/struct6_invalid_type.pb"); + + TestClass tc; + std::string error; + try { + tl::InputStream is (fn); + tl::ProtocolBufferReader reader (is); + tc_structure.parse (reader, tc); + } catch (tl::Exception &ex) { + error = ex.msg (); + } + + EXPECT_EQ (std::string (error, 0, 34), "Expected a VARINT or I32 wire type"); +} + +TEST (107_InvalidType) +{ + // uses I32 to represent enum - works too, not just VARINT + std::string fn = tl::combine_path (tl::testsrc (), "testdata/pb/struct7_invalid_type.pb"); + + TestClass tc; + tc.e = TestClass::B; + std::string error; + try { + tl::InputStream is (fn); + tl::ProtocolBufferReader reader (is); + tc_structure.parse (reader, tc); + } catch (tl::Exception &ex) { + error = ex.msg (); + } + + EXPECT_EQ (error, ""); + EXPECT_EQ (tc.e, TestClass::A); +} + +TEST (108_InvalidType) +{ + std::string fn = tl::combine_path (tl::testsrc (), "testdata/pb/struct8_invalid_type.pb"); + + TestClass tc; + std::string error; + try { + tl::InputStream is (fn); + tl::ProtocolBufferReader reader (is); + tc_structure.parse (reader, tc); + } catch (tl::Exception &ex) { + error = ex.msg (); + } + + EXPECT_EQ (std::string (error, 0, 34), "Expected a VARINT or I32 wire type"); +} + diff --git a/testdata/pb/struct1.pb b/testdata/pb/struct1.pb new file mode 100644 index 0000000000000000000000000000000000000000..b786e0d3c39520f2d2cd9743fd9be9eeb1539cfc GIT binary patch literal 149 zcmX@~xa%?#Z$VN?YH^8faY<2WatS8`7(B3tGUOZt8jc*Dz%0ef#guF)2$B6@FJ%kl z8bP@X4pMwv%*jTEf@jZw0E}-WIBO;dFhb>x1=GNQ$w5hwi>){_FFhv}Y{UfC07s4e Mht4w^Xjw1<04G5uw*UYD literal 0 HcmV?d00001 diff --git a/testdata/pb/struct2_invalid_header.pb b/testdata/pb/struct2_invalid_header.pb new file mode 100644 index 0000000000000000000000000000000000000000..8fb9360701e0a1903020878cb0e53c658ad34f56 GIT binary patch literal 147 zcmaDfm5H|?sU)?yM7Ox4s5H5RlK~7K*h3j|4gw8Fj!s~f;^ksWHWY-&ez2Fa1#*p` zTm}azJ}%~DBSXQnXFvePHxisR69gEc^2UN`V8G;{B*?{9oSB!NlL|Is0&9Sy#{NU+ J84a{77y&{yBrE^` literal 0 HcmV?d00001 diff --git a/testdata/pb/struct3_invalid_header.pb b/testdata/pb/struct3_invalid_header.pb new file mode 100644 index 0000000000000000000000000000000000000000..0c1e687ef262e19505bd862e439445fcaa9aa12d GIT binary patch literal 149 zcmX@~xa%?#Zv`^oWB`K)_E3hLgFwTPqZ62=c)6I84Fw^xAMB-Ufm|afm%%}bkBd3k z$WZX?84!T+jRa@S1OY~|p1`9?2Nj)z6 literal 0 HcmV?d00001 diff --git a/testdata/pb/struct5_overflow.pb b/testdata/pb/struct5_overflow.pb new file mode 100644 index 000000000..14e328697 --- /dev/null +++ b/testdata/pb/struct5_overflow.pb @@ -0,0 +1,2 @@ + + pbtest-tcԝ? \ No newline at end of file diff --git a/testdata/pb/struct6_invalid_type.pb b/testdata/pb/struct6_invalid_type.pb new file mode 100644 index 0000000000000000000000000000000000000000..4331c5da28dc17b38e01771552863cf6cfdb40b9 GIT binary patch literal 20 Wcmd<$EJ!LzEiTb5Nfs1jfB*nBSp&=f literal 0 HcmV?d00001 diff --git a/testdata/pb/struct7_invalid_type.pb b/testdata/pb/struct7_invalid_type.pb new file mode 100644 index 0000000000000000000000000000000000000000..bec039f513e8e736d303a4267e6c7563cd115c13 GIT binary patch literal 16 Xcmd<$EJ!LzEiTb5Nfs4kU|;|MCOret literal 0 HcmV?d00001 diff --git a/testdata/pb/struct8_invalid_type.pb b/testdata/pb/struct8_invalid_type.pb new file mode 100644 index 000000000..02d42f890 --- /dev/null +++ b/testdata/pb/struct8_invalid_type.pb @@ -0,0 +1,2 @@ + + pbtest-tcabc \ No newline at end of file