Fix infinite loop in Cursor::readTerminatedString
authorAlan Frindell <afrind@fb.com>
Thu, 22 Oct 2015 20:12:58 +0000 (13:12 -0700)
committerfacebook-github-bot-4 <folly-bot@fb.com>
Thu, 22 Oct 2015 21:20:20 +0000 (14:20 -0700)
Summary: readTerminatedString could infinite loop if the terminator does not appear in the contained IOBuf chain and maxLength > chain.computeChainLength.  I'm throwing out_of_range here because that more closely mirrors what the other read() functions do.

Reviewed By: siyengar

Differential Revision: D2571039

fb-gh-sync-id: 1db22089562d8767920d66a0a1b091b02de6571f

folly/io/Cursor.h
folly/io/test/IOBufCursorTest.cpp

index 5d12b6f89069ff183faa23a1351cd579944dbc93..d38d4dfbc472dd6148cb5c6e3cf57a1fd6a53e21 100644 (file)
@@ -212,7 +212,7 @@ class CursorBase {
       size_t maxLength = std::numeric_limits<size_t>::max()) {
     std::string str;
 
-    for (;;) {
+    while (!isAtEnd()) {
       const uint8_t* buf = data();
       size_t buflen = length();
 
@@ -235,6 +235,7 @@ class CursorBase {
 
       skip(i);
     }
+    throw std::out_of_range("terminator not found");
   }
 
   size_t skipAtMost(size_t len) {
index 86aad240f1466c82f42625f57efdd91c8e93b882..31801b8a14c25947e535147448f9ad5fb47eb55a 100644 (file)
@@ -683,6 +683,33 @@ TEST(IOBuf, StringOperations) {
     EXPECT_STREQ("hello", curs.readTerminatedString().c_str());
   }
 
+  // Test reading a null-terminated string from a chain that doesn't contain the
+  // terminator
+  {
+    std::unique_ptr<IOBuf> buf(IOBuf::create(8));
+    Appender app(buf.get(), 0);
+    app.push(reinterpret_cast<const uint8_t*>("hello"), 5);
+    std::unique_ptr<IOBuf> chain(IOBuf::create(8));
+    chain->prependChain(std::move(buf));
+
+    Cursor curs(chain.get());
+    EXPECT_THROW(curs.readTerminatedString(),
+                 std::out_of_range);
+  }
+
+  // Test reading a null-terminated string past the maximum length
+  {
+    std::unique_ptr<IOBuf> buf(IOBuf::create(8));
+    Appender app(buf.get(), 0);
+    app.push(reinterpret_cast<const uint8_t*>("hello\0"), 6);
+    std::unique_ptr<IOBuf> chain(IOBuf::create(8));
+    chain->prependChain(std::move(buf));
+
+    Cursor curs(chain.get());
+    EXPECT_THROW(curs.readTerminatedString('\0', 3),
+                 std::length_error);
+  }
+
   // Test reading a two fixed-length strings from a single buffer with an extra
   // uint8_t at the end
   {