table: prevent integer overflow in pit::FaceRecord
refs #4979
Change-Id: Iacd5abdfc8ae4530364e3fa590778a234140b7ed
diff --git a/daemon/table/pit-face-record.cpp b/daemon/table/pit-face-record.cpp
index d58ec96..3b358bd 100644
--- a/daemon/table/pit-face-record.cpp
+++ b/daemon/table/pit-face-record.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2014-2019, Regents of the University of California,
+ * Copyright (c) 2014-2020, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,6 +28,10 @@
namespace nfd {
namespace pit {
+// Impose a maximum lifetime to prevent integer overflow when calculating m_expiry.
+// This limit is 49.7 days, which should be enough everywhere.
+static const time::milliseconds MAX_LIFETIME(std::numeric_limits<uint32_t>::max());
+
void
FaceRecord::update(const Interest& interest)
{
@@ -35,10 +39,7 @@
m_lastRenewed = time::steady_clock::now();
auto lifetime = interest.getInterestLifetime();
- if (lifetime < 0_ms) {
- lifetime = ndn::DEFAULT_INTEREST_LIFETIME;
- }
- m_expiry = m_lastRenewed + lifetime;
+ m_expiry = m_lastRenewed + std::min(lifetime, MAX_LIFETIME);
}
} // namespace pit
diff --git a/tests/daemon/table/pit-entry.t.cpp b/tests/daemon/table/pit-entry.t.cpp
index 8bdb5fe..ab65ca8 100644
--- a/tests/daemon/table/pit-entry.t.cpp
+++ b/tests/daemon/table/pit-entry.t.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2014-2019, Regents of the University of California,
+ * Copyright (c) 2014-2020, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -29,6 +29,10 @@
#include "tests/daemon/global-io-fixture.hpp"
#include "tests/daemon/face/dummy-face.hpp"
+#include <boost/test/data/test_case.hpp>
+
+namespace bdata = boost::unit_test::data;
+
namespace nfd {
namespace pit {
namespace tests {
@@ -166,17 +170,33 @@
BOOST_CHECK(entry.getOutRecord(*face2) == entry.out_end());
}
-BOOST_AUTO_TEST_CASE(Lifetime)
+const time::milliseconds lifetimes[] = {
+ 0_ms,
+ 1_ms,
+ ndn::DEFAULT_INTEREST_LIFETIME,
+ 8624_ms,
+ 86400_s,
+ time::milliseconds(std::numeric_limits<time::milliseconds::rep>::max()),
+};
+
+BOOST_DATA_TEST_CASE(Lifetime, bdata::make(lifetimes), lifetime)
{
auto interest = makeInterest("/7oIEurbgy6");
+ if (lifetime != ndn::DEFAULT_INTEREST_LIFETIME) {
+ interest->setInterestLifetime(lifetime);
+ }
auto face = make_shared<DummyFace>();
Entry entry(*interest);
auto inIt = entry.insertOrUpdateInRecord(*face, *interest);
- BOOST_CHECK_GT(inIt->getExpiry(), time::steady_clock::now());
+ auto expirySinceNow = inIt->getExpiry() - time::steady_clock::now();
+ BOOST_CHECK_GT(expirySinceNow, 0_ms);
+ BOOST_CHECK_LT(std::abs(time::duration_cast<time::milliseconds>(expirySinceNow - lifetime).count()), 100);
auto outIt = entry.insertOrUpdateOutRecord(*face, *interest);
- BOOST_CHECK_GT(outIt->getExpiry(), time::steady_clock::now());
+ expirySinceNow = outIt->getExpiry() - time::steady_clock::now();
+ BOOST_CHECK_GT(expirySinceNow, 0_ms);
+ BOOST_CHECK_LT(std::abs(time::duration_cast<time::milliseconds>(expirySinceNow - lifetime).count()), 100);
}
BOOST_AUTO_TEST_CASE(OutRecordNack)