meta-info: prevent FreshnessPeriod overflow

refs #4997

Change-Id: I22ae27257fd79b539a8ac137f8b1871e1b988cf8
diff --git a/ndn-cxx/meta-info.cpp b/ndn-cxx/meta-info.cpp
index ce04687..3e4d6f1 100644
--- a/ndn-cxx/meta-info.cpp
+++ b/ndn-cxx/meta-info.cpp
@@ -42,14 +42,23 @@
   return *this;
 }
 
+time::milliseconds
+MetaInfo::getFreshnessPeriod() const
+{
+  if (m_freshnessPeriod > static_cast<uint64_t>(time::milliseconds::max().count())) {
+    return time::milliseconds::max();
+  }
+  return time::milliseconds(m_freshnessPeriod);
+}
+
 MetaInfo&
 MetaInfo::setFreshnessPeriod(time::milliseconds freshnessPeriod)
 {
-  if (freshnessPeriod < time::milliseconds::zero()) {
+  if (freshnessPeriod < 0_ms) {
     NDN_THROW(std::invalid_argument("FreshnessPeriod must be >= 0"));
   }
   m_wire.reset();
-  m_freshnessPeriod = freshnessPeriod;
+  m_freshnessPeriod = static_cast<uint64_t>(freshnessPeriod.count());
   return *this;
 }
 
@@ -135,9 +144,8 @@
   }
 
   // FreshnessPeriod
-  if (m_freshnessPeriod != DEFAULT_FRESHNESS_PERIOD) {
-    totalLength += prependNonNegativeIntegerBlock(encoder, tlv::FreshnessPeriod,
-                                                  static_cast<uint64_t>(m_freshnessPeriod.count()));
+  if (m_freshnessPeriod != static_cast<uint64_t>(DEFAULT_FRESHNESS_PERIOD.count())) {
+    totalLength += prependNonNegativeIntegerBlock(encoder, tlv::FreshnessPeriod, m_freshnessPeriod);
   }
 
   // ContentType
@@ -193,11 +201,11 @@
 
   // FreshnessPeriod
   if (val != m_wire.elements_end() && val->type() == tlv::FreshnessPeriod) {
-    m_freshnessPeriod = time::milliseconds(readNonNegativeInteger(*val));
+    m_freshnessPeriod = readNonNegativeInteger(*val);
     ++val;
   }
   else {
-    m_freshnessPeriod = DEFAULT_FRESHNESS_PERIOD;
+    m_freshnessPeriod = static_cast<uint64_t>(DEFAULT_FRESHNESS_PERIOD.count());
   }
 
   // FinalBlockId
diff --git a/ndn-cxx/meta-info.hpp b/ndn-cxx/meta-info.hpp
index 886e8a3..5f0df92 100644
--- a/ndn-cxx/meta-info.hpp
+++ b/ndn-cxx/meta-info.hpp
@@ -102,15 +102,15 @@
   MetaInfo&
   setType(uint32_t type);
 
-  /** @brief Return the value of `FreshnessPeriod`.
+  /**
+   * @brief Return the value of `FreshnessPeriod`.
    *
-   *  If the `FreshnessPeriod` element is not present, returns #DEFAULT_FRESHNESS_PERIOD.
+   * If the `FreshnessPeriod` element is not present, returns #DEFAULT_FRESHNESS_PERIOD.
+   * If the `FreshnessPeriod` value is not representable in the return type, it's clamped to
+   * the nearest representable value.
    */
   time::milliseconds
-  getFreshnessPeriod() const
-  {
-    return m_freshnessPeriod;
-  }
+  getFreshnessPeriod() const;
 
   /** @brief Set `FreshnessPeriod`.
    *  @throw std::invalid_argument specified FreshnessPeriod is negative
@@ -196,7 +196,7 @@
 
 private:
   uint32_t m_type = tlv::ContentType_Blob;
-  time::milliseconds m_freshnessPeriod = DEFAULT_FRESHNESS_PERIOD;
+  uint64_t m_freshnessPeriod = static_cast<uint64_t>(DEFAULT_FRESHNESS_PERIOD.count());
   std::optional<name::Component> m_finalBlockId;
   std::list<Block> m_appMetaInfo;
 
diff --git a/tests/unit/meta-info.t.cpp b/tests/unit/meta-info.t.cpp
index 2e37ea5..bd5aee4 100644
--- a/tests/unit/meta-info.t.cpp
+++ b/tests/unit/meta-info.t.cpp
@@ -78,6 +78,19 @@
   BOOST_CHECK_EQUAL(b.wireEncode(), wire3);
 }
 
+BOOST_AUTO_TEST_CASE(FreshnessPeriodOverflow)
+{
+  // Bug #4997
+  MetaInfo mi0("140A 19087FFFFFFFFFFFFFFF"_block);
+  BOOST_CHECK_EQUAL(mi0.getFreshnessPeriod(), 0x7FFFFFFFFFFFFFFF_ms);
+
+  MetaInfo mi1("140A 19088000000000000000"_block);
+  BOOST_CHECK_EQUAL(mi1.getFreshnessPeriod(), time::milliseconds::max());
+
+  MetaInfo mi2("140A 1908FFFFFFFFFFFFFFFF"_block);
+  BOOST_CHECK_EQUAL(mi2.getFreshnessPeriod(), time::milliseconds::max());
+}
+
 BOOST_AUTO_TEST_CASE(AppMetaInfo)
 {
   MetaInfo info1;