tlv: avoid misaligned memory access

They cause unit test crashing on ARM platform.

refs: #4609

Change-Id: Ifdb0401529de48b5c08ebcf6938d80ba87ff883d
diff --git a/src/tlv/coordinate-lsa.cpp b/src/tlv/coordinate-lsa.cpp
index dc6919e..fc74241 100644
--- a/src/tlv/coordinate-lsa.cpp
+++ b/src/tlv/coordinate-lsa.cpp
@@ -50,21 +50,12 @@
 CoordinateLsa::wireEncode(ndn::EncodingImpl<TAG>& block) const
 {
   size_t totalLength = 0;
-  size_t doubleLength = 10;
 
-  const uint8_t* doubleBytes1;
   for (auto it = m_hyperbolicAngle.rbegin(); it != m_hyperbolicAngle.rend(); ++it) {
-    doubleBytes1 = reinterpret_cast<const uint8_t*>(&*it);
-
-    totalLength += block.prependByteArrayBlock(ndn::tlv::nlsr::Double, doubleBytes1, 8);
-    totalLength += block.prependVarNumber(doubleLength);
-    totalLength += block.prependVarNumber(ndn::tlv::nlsr::HyperbolicAngle);
+    totalLength += prependDouble(block, ndn::tlv::nlsr::HyperbolicAngle, *it);
   }
 
-  const uint8_t* doubleBytes2 = reinterpret_cast<const uint8_t*>(&m_hyperbolicRadius);
-  totalLength += block.prependByteArrayBlock(ndn::tlv::nlsr::Double, doubleBytes2, 8);
-  totalLength += block.prependVarNumber(doubleLength);
-  totalLength += block.prependVarNumber(ndn::tlv::nlsr::HyperbolicRadius);
+  totalLength += prependDouble(block, ndn::tlv::nlsr::HyperbolicRadius, m_hyperbolicRadius);
 
   totalLength += m_lsaInfo.wireEncode(block);
 
@@ -123,17 +114,8 @@
   }
 
   if (val != m_wire.elements_end() && val->type() == ndn::tlv::nlsr::HyperbolicRadius) {
-    val->parse();
-    ndn::Block::element_const_iterator it = val->elements_begin();
-    if (it != val->elements_end() && it->type() == ndn::tlv::nlsr::Double) {
-      m_hyperbolicRadius = *reinterpret_cast<const double*>(it->value());
-
-      ++val;
-    }
-    else {
-      std::cout << "HyperbolicRadius: Missing required Double field" << std::endl;
-      BOOST_THROW_EXCEPTION(Error("HyperbolicRadius: Missing required Double field"));
-    }
+    m_hyperbolicRadius = ndn::tlv::nlsr::readDouble(*val);
+    ++val;
   }
   else {
     std::cout << "Missing required HyperbolicRadius field" << std::endl;
@@ -142,17 +124,7 @@
 
   for (; val != m_wire.elements_end(); ++val) {
     if (val->type() == ndn::tlv::nlsr::HyperbolicAngle) {
-      val->parse();
-
-      for (auto it = val->elements_begin(); it != val->elements_end(); ++it) {
-        if (it->type() == ndn::tlv::nlsr::Double) {
-          m_hyperbolicAngle.push_back(*reinterpret_cast<const double*>(it->value()));
-        }
-        else {
-          std::cout << "HyperbolicAngle: Missing required Double field" << std::endl;
-          BOOST_THROW_EXCEPTION(Error("HyperbolicAngle: Missing required Double field"));
-        }
-      }
+      m_hyperbolicAngle.push_back(ndn::tlv::nlsr::readDouble(*val));
     }
   }
 }
diff --git a/src/tlv/nexthop.cpp b/src/tlv/nexthop.cpp
index 342a02e..2db9c3c 100644
--- a/src/tlv/nexthop.cpp
+++ b/src/tlv/nexthop.cpp
@@ -21,6 +21,7 @@
 
 #include "nexthop.hpp"
 #include "tlv-nlsr.hpp"
+#include "coordinate-lsa.hpp"
 
 #include <ndn-cxx/util/concepts.hpp>
 #include <ndn-cxx/encoding/block-helpers.hpp>
@@ -49,8 +50,7 @@
 {
   size_t totalLength = 0;
 
-  const uint8_t* doubleBytes = reinterpret_cast<const uint8_t*>(&m_cost);
-  totalLength += block.prependByteArrayBlock(ndn::tlv::nlsr::Double, doubleBytes, 8);
+  totalLength += prependDouble(block, ndn::tlv::nlsr::Double, m_cost);
 
   totalLength += block.prependByteArrayBlock(
     ndn::tlv::nlsr::Uri, reinterpret_cast<const uint8_t*>(m_uri.c_str()), m_uri.size());
@@ -108,13 +108,7 @@
     BOOST_THROW_EXCEPTION(Error("Missing required Uri field"));
   }
 
-  if (val != val->elements_end() && val->type() == ndn::tlv::nlsr::Double) {
-    m_cost = *reinterpret_cast<const double*>(val->value());
-    ++val;
-  }
-  else {
-    BOOST_THROW_EXCEPTION(Error("HyperbolicCost: Missing required Double field"));
-  }
+  m_cost = ndn::tlv::nlsr::readDouble(*val);
 }
 
 std::ostream&
diff --git a/src/tlv/tlv-nlsr.hpp b/src/tlv/tlv-nlsr.hpp
index 3960eb0..0e400ea 100644
--- a/src/tlv/tlv-nlsr.hpp
+++ b/src/tlv/tlv-nlsr.hpp
@@ -23,6 +23,7 @@
 #define NLSR_TLV_NLSR_HPP
 
 #include <ndn-cxx/encoding/tlv.hpp>
+#include <ndn-cxx/encoding/block-helpers.hpp>
 
 namespace ndn {
 namespace tlv {
@@ -54,6 +55,45 @@
   RouteTableEntry  = 145
 };
 
+/*! \brief Read a double from a TLV element
+ *  \param block the TLV element
+ *  \throw ndn::tlv::Error block does not contain a double
+ *  \sa prependDouble
+ */
+inline double
+readDouble(const ndn::Block& block)
+{
+  block.parse();
+  auto it = block.elements_begin();
+
+  double doubleFromBlock = 0.0;
+  if (it == it->elements_end() || it->type() != ndn::tlv::nlsr::Double ||
+      it->value_size() != sizeof(doubleFromBlock)) {
+    BOOST_THROW_EXCEPTION(ndn::tlv::Error("Block does not contain a double"));
+  }
+  memcpy(&doubleFromBlock, it->value(), sizeof(doubleFromBlock));
+  return doubleFromBlock;
+}
+
+/*! \brief Prepend a TLV element containing a double.
+ *  \param encoder an EncodingBuffer or EncodingEstimator
+ *  \param type TLV-TYPE number
+ *  \param value double value
+ */
+template<ndn::encoding::Tag TAG>
+inline size_t
+prependDouble(ndn::EncodingImpl<TAG>& encoder, uint32_t type, double value)
+{
+  size_t totalLength = 0;
+
+  const uint8_t* doubleBytes = reinterpret_cast<const uint8_t*>(&value);
+  totalLength = encoder.prependByteArrayBlock(ndn::tlv::nlsr::Double, doubleBytes, 8);
+  totalLength += encoder.prependVarNumber(totalLength);
+  totalLength += encoder.prependVarNumber(type);
+
+  return totalLength;
+}
+
 } // namespace nlsr
 } // namespace tlv
 } // namespace ndn
diff --git a/tests/tlv/test-nexthops.cpp b/tests/tlv/test-nexthops.cpp
index a0472e8..9e8158f 100644
--- a/tests/tlv/test-nexthops.cpp
+++ b/tests/tlv/test-nexthops.cpp
@@ -32,11 +32,11 @@
 const uint8_t NexthopData[] =
 {
   // Header
-  0x8f, 0x1d,
+  0x8f, 0x1f,
   // Uri
   0x8d, 0x11, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x6e, 0x65, 0x78, 0x74, 0x68, 0x6f, 0x70, 0x2f, 0x74, 0x6c, 0x76,
   // Cost
-  0x86, 0x08, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfa, 0x3f
+  0x86, 0x0a, 0x86, 0x08, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfa, 0x3f
 };
 
 BOOST_AUTO_TEST_CASE(NexthopEncode)
diff --git a/tests/tlv/test-nlsr.cpp b/tests/tlv/test-nlsr.cpp
new file mode 100644
index 0000000..43d1487
--- /dev/null
+++ b/tests/tlv/test-nlsr.cpp
@@ -0,0 +1,57 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2018,  The University of Memphis,
+ *                           Regents of the University of California,
+ *                           Arizona Board of Regents.
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "tlv/tlv-nlsr.hpp"
+
+#include "../boost-test.hpp"
+
+#include <ndn-cxx/encoding/estimator.hpp>
+#include <ndn-cxx/encoding/encoding-buffer.hpp>
+#include <ndn-cxx/encoding/block-helpers.hpp>
+
+namespace nlsr {
+namespace tlv {
+namespace test {
+
+BOOST_AUTO_TEST_SUITE(TlvTestNlsr)
+
+BOOST_AUTO_TEST_CASE(TestDouble)
+{
+  ndn::Block block = ndn::encoding::makeNonNegativeIntegerBlock(0x01, 1);
+  BOOST_CHECK_THROW(ndn::tlv::nlsr::readDouble(block), ndn::tlv::Error);
+
+  double value = 1.65;
+  uint32_t type = 0x251;
+
+  ndn::encoding::EncodingEstimator estimator;
+  size_t totalLength = ndn::tlv::nlsr::prependDouble(estimator, type, value);
+
+  ndn::encoding::EncodingBuffer encoder(totalLength, 0);
+  ndn::tlv::nlsr::prependDouble(encoder, type, value);
+
+  BOOST_CHECK_CLOSE(value, ndn::tlv::nlsr::readDouble(encoder.block()), 0.001);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace test
+} // namespace tlv
+} // namespace nlsr
diff --git a/tests/tlv/test-routing-table-entry.cpp b/tests/tlv/test-routing-table-entry.cpp
index a58918e..deaad1c 100644
--- a/tests/tlv/test-routing-table-entry.cpp
+++ b/tests/tlv/test-routing-table-entry.cpp
@@ -32,15 +32,15 @@
 const uint8_t RoutingTableEntryWithNexthopsData[] =
 {
   // Header
-  0x91, 0x37,
+  0x91, 0x3b,
   // Destination
   0x8e, 0x09, 0x07, 0x07, 0x08, 0x05, 0x64, 0x65, 0x73, 0x74, 0x31,
   // Nexthop
-  0x8f, 0x14, 0x8d, 0x08, 0x6e, 0x65, 0x78, 0x74, 0x68, 0x6f, 0x70,
-  0x31, 0x86, 0x08, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfa, 0x3f,
+  0x8f, 0x16, 0x8d, 0x08, 0x6e, 0x65, 0x78, 0x74, 0x68, 0x6f, 0x70,
+  0x31, 0x86, 0x0a, 0x86, 0x08, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfa, 0x3f,
   // Nexthop
-  0x8f, 0x14, 0x8d, 0x08, 0x6e, 0x65, 0x78, 0x74, 0x68, 0x6f, 0x70,
-  0x32, 0x86, 0x08, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfa, 0x3f
+  0x8f, 0x16, 0x8d, 0x08, 0x6e, 0x65, 0x78, 0x74, 0x68, 0x6f, 0x70,
+  0x32, 0x86, 0x0a, 0x86, 0x08, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfa, 0x3f
 };
 
 const uint8_t RoutingTableEntryWithoutNexthopsData[] =
diff --git a/tests/tlv/test-routing-table.cpp b/tests/tlv/test-routing-table.cpp
index c7af5ae..85a9850 100644
--- a/tests/tlv/test-routing-table.cpp
+++ b/tests/tlv/test-routing-table.cpp
@@ -32,13 +32,14 @@
 const uint8_t RoutingTableData1[] =
 {
   // Header
-  0x90, 0x22,
+  0x90, 0x24,
   // Routing table entry
-  0x91, 0x20,
+  0x91, 0x22,
     // Destination
     0x8e, 0x09, 0x07, 0x07, 0x08, 0x05, 0x64, 0x65, 0x73, 0x74, 0x31,
     // Nexthop
-    0x8f, 0x13, 0x8d, 0x07, 0x6e, 0x65, 0x78, 0x74, 0x68, 0x6f, 0x70, 0x86, 0x08, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfa, 0x3f
+    0x8f, 0x15, 0x8d, 0x07, 0x6e, 0x65, 0x78, 0x74, 0x68, 0x6f, 0x70,
+    0x86, 0x0a, 0x86, 0x08, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfa, 0x3f
 };
 
 const uint8_t RoutingTableData2[] =