fixup decode logic for fragmented IOBufs
authorWez Furlong <wez@fb.com>
Fri, 19 Jan 2018 02:39:48 +0000 (18:39 -0800)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Fri, 19 Jan 2018 03:09:44 +0000 (19:09 -0800)
Summary:
D6635325 exposed a long standing issue with the way
that we were consuming Cursor::length, so let's fix it up!

More details are in the new unit test for this!

Reviewed By: spalamarchuk

Differential Revision: D6755842

fbshipit-source-id: f8b20406c32682892791e7375be577d54d52e0ad

folly/experimental/bser/Load.cpp
folly/experimental/bser/test/BserTest.cpp

index a0a49c81709de08ee4a4b76bde810299fc36a7f0..ad390ee8a866f7405798ba076c0d50d430c62bae 100644 (file)
@@ -61,7 +61,10 @@ static std::string decodeString(Cursor& curs) {
   }
   str.reserve(size_t(len));
 
-  size_t available = curs.length();
+  // peekBytes will advance over any "empty" IOBuf elements until
+  // it reaches the next one with data, so do that to obtain the
+  // true remaining length.
+  size_t available = curs.peekBytes().size();
   while (available < (size_t)len) {
     if (available == 0) {
       // Saw this case when we decodeHeader was returning the incorrect length
@@ -74,7 +77,7 @@ static std::string decodeString(Cursor& curs) {
     str.append(reinterpret_cast<const char*>(curs.data()), available);
     curs.skipAtMost(available);
     len -= available;
-    available = curs.length();
+    available = curs.peekBytes().size();
   }
 
   str.append(reinterpret_cast<const char*>(curs.data()), size_t(len));
index 61f07f2b5193501e110ce53acb64f531dc431d05..97bf5c75dfadba6de334f8a6e4f9d5e9f11fccc2 100644 (file)
@@ -118,5 +118,32 @@ TEST(Bser, PduLength) {
   EXPECT_EQ(len, 44) << "PduLength should be 44, got " << len;
 }
 
+TEST(Bser, CursorLength) {
+  folly::bser::serialization_opts opts;
+  std::string inputStr("hello there please break");
+
+  // This test is exercising the decode logic for pathological
+  // fragmentation cases.  We try a few permutations with the
+  // BSER header being fragmented to tickle boundary conditions
+
+  auto longSerialized = folly::bser::toBser(inputStr, opts);
+  for (uint32_t i = 1; i < longSerialized.size(); ++i) {
+    folly::IOBufQueue q;
+
+    q.append(folly::IOBuf::wrapBuffer(longSerialized.data(), i));
+    uint32_t j = i;
+    while (j < longSerialized.size()) {
+      q.append(folly::IOBuf::wrapBuffer(&longSerialized[j], 1));
+      ++j;
+    }
+
+    auto pdu_len = folly::bser::decodePduLength(q.front());
+    auto buf = q.split(pdu_len);
+
+    auto hello = folly::bser::parseBser(buf.get());
+    EXPECT_EQ(inputStr, hello.asString());
+  }
+}
+
 /* vim:ts=2:sw=2:et:
  */