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