Skip to content

Commit

Permalink
read_f{4,8}{be,le}(): fix violations of strict aliasing rules
Browse files Browse the repository at this point in the history
  • Loading branch information
generalmimon committed May 4, 2024
1 parent 1de8362 commit c01f530
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 4 deletions.
55 changes: 51 additions & 4 deletions kaitai/kaitaistream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,57 @@
#include <byteswap.h>
#endif

#include <cstring> // std::memcpy
#include <iostream>
#include <vector>
#include <stdexcept>

#ifdef KAITAI_STREAM_H_CPP11_SUPPORT
#include <type_traits> // std::enable_if, std::is_trivially_copyable, std::is_trivially_constructible

// Taken from https://en.cppreference.com/w/cpp/numeric/bit_cast#Possible_implementation
// (only adjusted for C++11 compatibility)
template<class To, class From>
typename std::enable_if<
sizeof(To) == sizeof(From) &&
std::is_trivially_copyable<From>::value &&
std::is_trivially_copyable<To>::value,
To
>::type
// constexpr support needs compiler magic
static bit_cast(const From &src) noexcept
{
static_assert(std::is_trivially_constructible<To>::value,
"This implementation additionally requires "
"destination type to be trivially constructible");

To dst;
std::memcpy(&dst, &src, sizeof(To));
return dst;
}
#else
// The following implementation of `StaticAssert` was inspired by https://stackoverflow.com/a/6765840

// empty default template
template <bool b>
struct StaticAssert;

// template specialized on true
template <>
struct StaticAssert<true> {};

template<class To, class From>
To
static bit_cast(const From &src)
{
StaticAssert<sizeof(To) == sizeof(From)>();

To dst;
std::memcpy(&dst, &src, sizeof(To));
return dst;
}
#endif

kaitai::kstream::kstream(std::istream *io) {
m_io = io;
init();
Expand Down Expand Up @@ -263,7 +310,7 @@ float kaitai::kstream::read_f4be() {
#if __BYTE_ORDER == __LITTLE_ENDIAN
t = bswap_32(t);
#endif
return reinterpret_cast<float &>(t);
return bit_cast<float>(t);
}

double kaitai::kstream::read_f8be() {
Expand All @@ -272,7 +319,7 @@ double kaitai::kstream::read_f8be() {
#if __BYTE_ORDER == __LITTLE_ENDIAN
t = bswap_64(t);
#endif
return reinterpret_cast<double &>(t);
return bit_cast<double>(t);
}

// ........................................................................
Expand All @@ -285,7 +332,7 @@ float kaitai::kstream::read_f4le() {
#if __BYTE_ORDER == __BIG_ENDIAN
t = bswap_32(t);
#endif
return reinterpret_cast<float &>(t);
return bit_cast<float>(t);
}

double kaitai::kstream::read_f8le() {
Expand All @@ -294,7 +341,7 @@ double kaitai::kstream::read_f8le() {
#if __BYTE_ORDER == __BIG_ENDIAN
t = bswap_64(t);
#endif
return reinterpret_cast<double &>(t);
return bit_cast<double>(t);
}

// ========================================================================
Expand Down
5 changes: 5 additions & 0 deletions kaitai/kaitaistream.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
// Kaitai Struct runtime API version: x.y.z = 'xxxyyyzzz' decimal
#define KAITAI_STRUCT_VERSION 11000L

// check for C++11 support - https://stackoverflow.com/a/40512515
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
#define KAITAI_STREAM_H_CPP11_SUPPORT
#endif

#include <istream>
#include <sstream>
#include <stdint.h>
Expand Down

0 comments on commit c01f530

Please sign in to comment.